Free Electron
var_char_buf.h
1 // Copyright (c) 2001 John Panzer
2 // Permission is granted to use this code without restriction as
3 // long as this copyright notice appears in all source files.
4 #ifndef VAR_CHAR_BUF_H_INCLUDED
5 #define VAR_CHAR_BUF_H_INCLUDED
6 
7 #include <string> // For char_traits
8 #include "xs_defs.h" // Utility macros
9 
10 XS_NAMESPACE(xstr)
11 
12 // Variable character buffer class which uses a
13 // small internal buffer along with a dynamic overflow
14 // buffer.
15 /// This class implements the minimal string interface
16 /// and is intended to be used as a base class for
17 /// xstring<>, which provides the full string interface.
18 template <size_t SIZE,
19  class CharT = char,
20  class Traits = std::char_traits<CharT>,
21  class Alloc = std::allocator<CharT> >
22 class var_char_buf {
23 public:
24  /// STL container interface typedefs:
25  // Listing: Replace next 12 lines with "...(typedefs same as those in fixed_char_buf)..."
26  typedef CharT value_type;
27  typedef value_type* pointer;
28  typedef const value_type* const_pointer;
29  typedef value_type& reference;
30  typedef const value_type& const_reference;
31  typedef size_t size_type;
32  typedef ptrdiff_t difference_type;
33  typedef const value_type* const_iterator;
34  typedef value_type* iterator;
35  typedef std::reverse_iterator<const_iterator>
36  const_reverse_iterator;
37  typedef std::reverse_iterator<iterator> reverse_iterator;
38  typedef Alloc allocator_type;
39 
40  /// String interface typedefs:
41  typedef Traits traits_type;
42  static const size_type npos;
43 
44  // Constructors:
45  var_char_buf(allocator_type const &a=allocator_type())
46  : _buffer(_internal_buf),
47  _end(_internal_buf),
48  _num_chars_allocated(0) {}
49 
50  var_char_buf(var_char_buf const &s)
51  : _buffer(_internal_buf),
52  _end(_internal_buf),
53  _num_chars_allocated(0) {
54  range_initialize(s.begin(), s.end());
55  }
56 
57  ~var_char_buf() {release_resources();}
58 
59  // Copy operator:
60  var_char_buf &operator=(var_char_buf const &s) {
61  range_initialize(s.begin(), s.end());
62  }
63 
64  // Insert:
65  template <class InputIter>
66  void insert(iterator pos, InputIter first, InputIter last) {
67  if (first!=last) {
68  size_type xtra = std::distance(first,last);
69  size_type newlen = _end-_buffer+xtra;
70  if (newlen >= capacity()) {
71  size_type ipos = pos-_buffer;
72  reserve(newlen);
73  pos = _buffer+ipos;
74  }
75  if (pos!=_end)
76  Traits::move(pos+xtra,pos,_end-pos);
77  std::copy(first,last,pos);
78  _end += xtra; // Expand end point
79  }
80  }
81 
82  // Erase:
83  iterator erase(iterator first, iterator last) {
84  if (first != last) {
85  Traits::move(first, last, (_end - last) + 1);
86  const iterator new_finish = _end - (last - first);
87  _end = new_finish;
88  }
89  return first;
90  }
91 
92  /// (Replace can be defined in terms of erase and insert,
93  /// so the minimal interface can skip it.)
94 
95  // STL container member function interface:
96  const allocator_type &get_allocator() const {
97  return _allocator;
98  }
99 
100  iterator begin() {return _buffer;}
101  const_iterator begin() const {return _buffer;}
102  iterator end() {return _end;}
103  const_iterator end() const {return _end;}
104 
105  void clear() {_end = _buffer;}
106 
107  /// Proper thing to do is probably to return
108  /// _allocator.max_size(), but this causes problems: My
109  /// default allocator returns 0xFFFFFFFF, and in fact
110  /// will allocate a block of that size, but the memory
111  /// returned is not actually accessible. This causes
112  /// problems for test code that wants to stress
113  /// test the string (it breaks std::string too).
114  /// Thus the following hack.
115  size_t max_size() const {
116  return std::min((size_t)0xFFFF,_allocator.max_size());
117  }
118  bool empty() const { return (_end == _buffer); }
119  size_type size() const {return _end - _buffer;}
120 
121  void swap(var_char_buf& s) {
122  int len = _end - _buffer;
123  if (_buffer == _internal_buf)
124  for(int i=0;i<SIZE;++i) {
125  std::swap(_buffer[i],s._buffer[i]);
126  }
127  else
128  std::swap(_buffer,s._buffer);
129  std::swap(_num_chars_allocated,s._num_chars_allocated);
130  _end = s.size()+_buffer;
131  s._end = len+s._buffer;
132  }
133 
134  // String interface member functions:
135  void reserve(size_type requested_chars= 0) {
136  if (requested_chars < SIZE && (_buffer==_internal_buf))
137  return;
138  if (requested_chars < _num_chars_allocated)
139  return;
140  if (requested_chars > max_size())
141  throw std::length_error("Max size exceeded");
142 
143  /// TODO: Smarter reallocation strategy
144  CharT *p = _allocator.allocate(requested_chars+1);
145 
146  /// Everything else should be nothrow:
147  size_type sz = size();
148  Traits::move(p,_buffer,sz);
149  release_resources();
150  _buffer = p;
151  _end = _buffer + sz;
152  _num_chars_allocated = requested_chars+1;
153  }
154 
155  size_type capacity() const {
156  return _num_chars_allocated ?
157  _num_chars_allocated : SIZE;
158  }
159 
160  const CharT* c_str() const {
161  *_end = CharT(); // Null terminate.
162  return _buffer;
163  }
164 
165  const CharT* data() const {
166  return _buffer;
167  }
168 
169 protected:
170  void release_resources() {
171  if (_buffer != _internal_buf) {
172  _allocator.deallocate(_buffer,
173  _num_chars_allocated);
174  }
175  }
176 
177  // Initializes with n copies of given element:
178  void element_initialize(size_type n, value_type c) {
179  reserve(n); // TODO: Can reserve throw?
180  std::uninitialized_fill_n(begin(), n, c);
181  _end = begin()+n;
182  }
183 
184  // Initializes with given range of elements:
185  template <class InputIter>
186  void range_initialize(InputIter first, InputIter last) {
187  size_type n = std::distance(first,last);
188  if (n >= SIZE)
189  reserve(n);
190  std::uninitialized_copy(first,last,_buffer);
191  _end = _buffer+n;
192  }
193 private:
194  /// A variable size buffer implementation:
195  CharT *_buffer; // Start of text in string
196  mutable CharT *_end ; // End of text in _buffer
197 
198  CharT _internal_buf[SIZE+1]; // Space for SIZE elems+null
199  size_type _num_chars_allocated; // Size of dynamic block
200  static allocator_type _allocator;
201 };
202 
203 // Listing: Replace next 11 lines with "...(size_type and _allocator same as in fixed_char_buf)..."
204 /// Definition of "npos" constant:
205 template <size_t SIZE, class CharT, class Traits, class Alloc>
206 const var_char_buf<SIZE,CharT,Traits,Alloc>::size_type
208  = (var_char_buf<SIZE,CharT,Traits,Alloc>::size_type) -1;
209 
210 /// Definition of _allocator instance, shared between
211 /// all strings of a given type:
212 template <size_t SIZE, class CharT, class Traits, class Alloc>
213 var_char_buf<SIZE,CharT,Traits,Alloc>::allocator_type
215 
216 XS_END_NAMESPACE
217 
218 #endif
CharT value_type
STL container interface typedefs:
Definition: var_char_buf.h:26
static const size_type npos
Definition of "npos" constant:
Definition: var_char_buf.h:42
static allocator_type _allocator
Definition of _allocator instance, shared between all strings of a given type:
Definition: var_char_buf.h:200
CharT * _buffer
A variable size buffer implementation:
Definition: var_char_buf.h:195
const allocator_type & get_allocator() const
(Replace can be defined in terms of erase and insert, so the minimal interface can skip it...
Definition: var_char_buf.h:96
This class implements the minimal string interface and is intended to be used as a base class for xst...
Definition: var_char_buf.h:22
void reserve(size_type requested_chars=0)
Definition: var_char_buf.h:135
Traits traits_type
String interface typedefs:
Definition: var_char_buf.h:41
size_t max_size() const
Proper thing to do is probably to return _allocator.max_size(), but this causes problems: My default ...
Definition: var_char_buf.h:115