GCS  0.2.3
gu_string.hpp
1 // Copyright (C) 2013 Codership Oy <info@codership.com>
2 
9 #ifndef _GU_STRING_HPP_
10 #define _GU_STRING_HPP_
11 
12 #include "gu_vector.hpp"
13 
14 #include <string>
15 #include <new> // std::bad_alloc
16 #include <limits>
17 #include <cstdlib> // realloc()
18 #include <cstring> // strlen(), strcmp()
19 #include <cstdio> // snprintf()
20 #include <iostream>
21 
22 #include "gu_macros.h" // gu_likely()
23 
24 namespace gu
25 {
26 
27 /* container for a printf()-like format */
28 struct Fmt
29 {
30  explicit Fmt(const char* f) : fmt_(f) {}
31  const char* const fmt_;
32 };
33 
34 
35 template <typename T = char>
37 {
38 public:
39 
40  typedef T value_type;
41  typedef T* pointer;
42  typedef const T* const_pointer;
43  typedef size_t size_type;
44 
45  size_type size() const { return size_; }
46  size_type length()const { return size(); }
47 
48  pointer c_str() { return str_; }
49  const_pointer c_str() const { return str_; }
50 
51  StringBase& operator<< (const Fmt& f)
52  {
53  fmt_ = f.fmt_;
54  return *this;
55  }
56 
57  StringBase& operator<< (const StringBase& s)
58  {
59  size_type const n(s.size());
60  append_string (s.c_str(), n);
61  return *this;
62  }
63 
64  StringBase& operator<< (const char* s)
65  {
66  size_type const n(::strlen(s));
67  append_string (s, n);
68  return *this;
69  }
70 
71  StringBase& operator<< (const std::string& s)
72  {
73  append_string (s.c_str(), s.length());
74  return *this;
75  }
76 
77  StringBase& operator<< (const bool& b)
78  {
79  // following std::boolalpha
80  if (b)
81  append_string ("true", 4);
82  else
83  append_string ("false", 5);
84 
85  return *this;
86  }
87 
88  StringBase& operator<< (const double& d)
89  {
90  convert ("%f", std::numeric_limits<double>::digits10, d);
91  return *this;
92  }
93 
94  StringBase& operator<< (const void* const ptr)
95  {
96  /* not using %p here seeing that it may be not universally supported */
97  static size_type const ptr_len(sizeof(ptr) == 4 ? 11 : 19 );
98  static const char* const fmt(sizeof(ptr) == 4 ? "0x%08lx":"0x%016lx");
99 
100  convert (fmt, ptr_len, reinterpret_cast<unsigned long>(ptr));
101  return *this;
102  }
103 
104  StringBase& operator<< (const long long &i)
105  {
106  convert ("%lld", 21, i);
107  return *this;
108  }
109 
110  StringBase& operator<< (const unsigned long long &i)
111  {
112  convert ("%llu", 20, i);
113  return *this;
114  }
115 
116  StringBase& operator<< (const int &i)
117  {
118  convert ("%d", 11, i);
119  return *this;
120  }
121 
122  StringBase& operator<< (const unsigned int &i)
123  {
124  convert ("%u", 10, i);
125  return *this;
126  }
127 
128  StringBase& operator<< (const short &i)
129  {
130  convert ("%hd", 6, i);
131  return *this;
132  }
133 
134  StringBase& operator<< (const unsigned short &i)
135  {
136  convert ("%hu", 5, i);
137  return *this;
138  }
139 
140  StringBase& operator<< (const char &c)
141  {
142  convert ("%c", 1, c);
143  return *this;
144  }
145 
146  StringBase& operator<< (const unsigned char &c)
147  {
148  convert ("%hhu", 3, c);
149  return *this;
150  }
151 
152  template <typename X>
153  StringBase& operator+= (const X& x) { return operator<<(x); }
154 
155  bool operator== (const StringBase& other)
156  {
157  return (size() == other.size() && !::strcmp(c_str(), other.c_str()));
158  }
159 
160  bool operator== (const std::string& other)
161  {
162  return (size() == other.size() && !::strcmp(c_str(), other.c_str()));
163  }
164 
165  bool operator== (const char* s)
166  {
167  size_type const s_size(::strlen(s));
168  return (size() == s_size && !::strcmp(c_str(), s));
169  }
170 
171  template <typename X>
172  bool operator!= (const X& x) { return !operator==(x); }
173 
174  void clear() { derived_clear(); };
175 
176  StringBase& operator= (const StringBase& other)
177  {
178  clear();
179  append_string (other.c_str(), other.size());
180  return *this;
181  }
182 
183  StringBase& operator= (const char* const other)
184  {
185  clear();
186  append_string (other, ::strlen(other));
187  return *this;
188  }
189 
190 protected:
191 
192  pointer str_; // points to an adequately sized memory area
193  const char* fmt_;
194  size_type size_;
195 
196  virtual void reserve (size_type n) = 0;
197  virtual void derived_clear() = 0; // real clear must happen in derived class
198 
199  void append_string (const_pointer const s, size_type const n)
200  {
201  reserve(size_ + n + 1);
202  std::copy(s, s + n, &str_[size_]);
203  size_ += n;
204  str_[size_] = 0;
205  }
206 
207  template <typename X>
208  void convert (const char* const format, size_type max_len, const X& x)
209  {
210  ++max_len; // add null termination
211  reserve(size_ + max_len);
212  int const n(snprintf(&str_[size_], max_len, fmt_ ? fmt_ : format, x));
213  assert(n > 0);
214  assert(size_type(n) < max_len);
215  if (gu_likely(n > 0)) size_ += n;
216  str_[size_] = 0; // null-terminate even if snprintf() failed.
217  fmt_ = NULL;
218  }
219 
220  StringBase(pointer init_buf) : str_(init_buf), fmt_(NULL), size_(0) {}
221 
222  virtual ~StringBase() {}
223 
224 private:
225 
226  StringBase(const StringBase&);
227 
228 }; /* class StringBase */
229 
230 template <typename T>
231 std::ostream& operator<< (std::ostream& os, const gu::StringBase<T>& s)
232 {
233  os << s.c_str();
234  return os;
235 }
236 
237 template <size_t capacity = 256, typename T = char>
238 class String : public StringBase<T>
239 {
240 public:
241 
242  typedef T value_type;
243  typedef T* pointer;
244  typedef const T* const_pointer;
245  typedef size_t size_type;
246 
247  String() : StringBase<T>(buf_), reserved_(capacity), buf_()
248  {
249  buf_[0] = 0;
250  }
251 
252  explicit
253  String(const StringBase<T>& s)
254  : StringBase<T>(buf_), reserved_(capacity), buf_()
255  {
256  append_string (s.c_str(), s.size());
257  }
258 
259  String(const T* s, size_type n)
260  : StringBase<T>(buf_), reserved_(capacity), buf_()
261  {
262  append_string (s, n);
263  }
264 
265  explicit
266  String(const char* s)
267  : StringBase<T>(buf_), reserved_(capacity), buf_()
268  {
269  size_type const n(strlen(s));
270  append_string (s, n);
271  }
272 
273  explicit
274  String(const std::string& s)
275  : StringBase<T>(buf_), reserved_(capacity), buf_()
276  {
277  append_string (s.c_str(), s.length());
278  }
279 
280 #if 0
281  String& operator= (String other)
282  {
283  using namespace std;
284  swap(other);
285  return *this;
286  }
287 #endif
288 
289  template <typename X>
290  String& operator= (const X& x)
291  {
292  base::operator=(x);
293  return *this;
294  }
295 
296  ~String()
297  {
298  if (base::str_ != buf_) ::free(base::str_);
299  }
300 
301 private:
302 
303  size_type reserved_;
304  value_type buf_[capacity];
305 
307 
308  void reserve (size_type const n)
309  {
310  if (n <= reserved_) return;
311 
312  assert (n > capacity);
313 
314  bool const overflow(buf_ == base::str_);
315 
316  pointer const tmp
317  (static_cast<pointer>
318  (::realloc(overflow ? NULL : base::str_, n * sizeof(value_type))));
319 
320  if (NULL == tmp) throw std::bad_alloc();
321 
322  if (overflow) std::copy(buf_, buf_ + base::size_, tmp);
323 
324  base::str_ = tmp;
325  reserved_ = n;
326  }
327 
328  void derived_clear()
329  {
330  if (base::str_ != buf_) ::free(base::str_);
331 
332  base::str_ = buf_;
333  base::size_ = 0;
334  buf_[0] = 0;
335  reserved_ = capacity;
336  }
337 
338  void append_string (const_pointer s, size_type n)
339  {
340  base::append_string(s, n);
341  }
342 
343 }; /* class String */
344 
345 } /* namespace gu */
346 
347 #endif /* _GU_STRING_HPP_ */
Definition: gu_string.hpp:36
Definition: gu_string.hpp:28
Definition: gu_string.hpp:238