Chris@16
|
1 /*=============================================================================
|
Chris@16
|
2 Boost.Wave: A Standard compliant C++ preprocessor library
|
Chris@16
|
3 http://www.boost.org/
|
Chris@16
|
4
|
Chris@16
|
5 Copyright (c) 2001 by Andrei Alexandrescu. Distributed under the Boost
|
Chris@16
|
6 Software License, Version 1.0. (See accompanying file
|
Chris@16
|
7 LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
8 =============================================================================*/
|
Chris@16
|
9
|
Chris@16
|
10 // This code is taken from:
|
Chris@16
|
11 // Andrei Alexandrescu, Generic<Programming>: A Policy-Based basic_string
|
Chris@16
|
12 // Implementation. http://www.cuj.com/documents/s=7994/cujcexp1906alexandr/
|
Chris@16
|
13 //
|
Chris@16
|
14 // #HK030306:
|
Chris@16
|
15 // - Moved into the namespace boost::wave::util
|
Chris@16
|
16 // - Added a bunch of missing typename(s)
|
Chris@16
|
17 // - Integrated with boost config
|
Chris@16
|
18 // - Added a missing header include
|
Chris@16
|
19 // - Added special constructors and operator= to allow CowString to be
|
Chris@16
|
20 // a real COW-string (removed unnecessary data copying)
|
Chris@16
|
21 // - Fixed a string terminating bug in append
|
Chris@16
|
22 //
|
Chris@16
|
23 // #HK040109:
|
Chris@16
|
24 // - Incorporated the changes from Andrei's latest version of this class
|
Chris@16
|
25 //
|
Chris@16
|
26 // #HK070307:
|
Chris@16
|
27 // - Once again incorporated the changes from Andrei's latest version of
|
Chris@16
|
28 // this class
|
Chris@16
|
29 //
|
Chris@16
|
30 // #HK090523:
|
Chris@16
|
31 // - Incorporated the changes from latest version of flex_string as
|
Chris@16
|
32 // maintained in Loki
|
Chris@16
|
33 //
|
Chris@16
|
34 // #HK130910:
|
Chris@16
|
35 // - Removed the getline implementation which was borrowed from the SGI
|
Chris@16
|
36 // STL as the license for this code is not compatible with Boost.
|
Chris@16
|
37
|
Chris@16
|
38 #ifndef FLEX_STRING_INC_
|
Chris@16
|
39 #define FLEX_STRING_INC_
|
Chris@16
|
40
|
Chris@16
|
41 /*
|
Chris@16
|
42 ////////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
43 template <typename E, class A = @>
|
Chris@16
|
44 class StoragePolicy
|
Chris@16
|
45 {
|
Chris@16
|
46 typedef E value_type;
|
Chris@16
|
47 typedef @ iterator;
|
Chris@16
|
48 typedef @ const_iterator;
|
Chris@16
|
49 typedef A allocator_type;
|
Chris@16
|
50 typedef @ size_type;
|
Chris@16
|
51
|
Chris@16
|
52 StoragePolicy(const StoragePolicy& s);
|
Chris@16
|
53 StoragePolicy(const A&);
|
Chris@16
|
54 StoragePolicy(const E* s, size_type len, const A&);
|
Chris@16
|
55 StoragePolicy(size_type len, E c, const A&);
|
Chris@16
|
56 ~StoragePolicy();
|
Chris@16
|
57
|
Chris@16
|
58 iterator begin();
|
Chris@16
|
59 const_iterator begin() const;
|
Chris@16
|
60 iterator end();
|
Chris@16
|
61 const_iterator end() const;
|
Chris@16
|
62
|
Chris@16
|
63 size_type size() const;
|
Chris@16
|
64 size_type max_size() const;
|
Chris@16
|
65 size_type capacity() const;
|
Chris@16
|
66
|
Chris@16
|
67 void reserve(size_type res_arg);
|
Chris@16
|
68
|
Chris@16
|
69 void append(const E* s, size_type sz);
|
Chris@16
|
70
|
Chris@16
|
71 template <class InputIterator>
|
Chris@16
|
72 void append(InputIterator b, InputIterator e);
|
Chris@16
|
73
|
Chris@16
|
74 void resize(size_type newSize, E fill);
|
Chris@16
|
75
|
Chris@16
|
76 void swap(StoragePolicy& rhs);
|
Chris@16
|
77
|
Chris@16
|
78 const E* c_str() const;
|
Chris@16
|
79 const E* data() const;
|
Chris@16
|
80
|
Chris@16
|
81 A get_allocator() const;
|
Chris@16
|
82 };
|
Chris@16
|
83 ////////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
84 */
|
Chris@16
|
85
|
Chris@16
|
86 #include <boost/config.hpp>
|
Chris@16
|
87 #include <boost/assert.hpp>
|
Chris@16
|
88 #include <boost/throw_exception.hpp>
|
Chris@16
|
89
|
Chris@16
|
90 #include <boost/iterator/reverse_iterator.hpp>
|
Chris@16
|
91
|
Chris@16
|
92 #include <boost/wave/wave_config.hpp>
|
Chris@16
|
93 #if BOOST_WAVE_SERIALIZATION != 0
|
Chris@16
|
94 #include <boost/serialization/serialization.hpp>
|
Chris@16
|
95 #include <boost/serialization/split_free.hpp>
|
Chris@16
|
96 #include <boost/serialization/collections_save_imp.hpp>
|
Chris@16
|
97 #include <boost/serialization/collections_load_imp.hpp>
|
Chris@16
|
98 #define BOOST_WAVE_FLEX_STRING_SERIALIZATION_HACK 1
|
Chris@16
|
99 #endif
|
Chris@16
|
100
|
Chris@16
|
101 #include <memory>
|
Chris@16
|
102 #include <new>
|
Chris@16
|
103 #include <string>
|
Chris@16
|
104 #include <vector>
|
Chris@16
|
105 #include <algorithm>
|
Chris@16
|
106 #include <functional>
|
Chris@16
|
107 #include <limits>
|
Chris@16
|
108 #include <stdexcept>
|
Chris@16
|
109 #include <ios>
|
Chris@16
|
110
|
Chris@16
|
111 #include <cstddef>
|
Chris@16
|
112 #include <cstring>
|
Chris@16
|
113 #include <cstdlib>
|
Chris@16
|
114
|
Chris@16
|
115 // this must occur after all of the includes and before any code appears
|
Chris@16
|
116 #ifdef BOOST_HAS_ABI_HEADERS
|
Chris@16
|
117 #include BOOST_ABI_PREFIX
|
Chris@16
|
118 #endif
|
Chris@16
|
119
|
Chris@16
|
120 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
121 namespace boost {
|
Chris@16
|
122 namespace wave {
|
Chris@16
|
123 namespace util {
|
Chris@16
|
124
|
Chris@16
|
125 namespace flex_string_details
|
Chris@16
|
126 {
|
Chris@16
|
127 template <class InIt, class OutIt>
|
Chris@16
|
128 OutIt copy_n(InIt b,
|
Chris@16
|
129 typename std::iterator_traits<InIt>::difference_type n, OutIt d)
|
Chris@16
|
130 {
|
Chris@16
|
131 for (/**/; n != 0; --n, ++b, ++d)
|
Chris@16
|
132 {
|
Chris@16
|
133 *d = *b;
|
Chris@16
|
134 }
|
Chris@16
|
135 return d;
|
Chris@16
|
136 }
|
Chris@16
|
137
|
Chris@16
|
138 template <class Pod, class T>
|
Chris@16
|
139 inline void pod_fill(Pod* b, Pod* e, T c)
|
Chris@16
|
140 {
|
Chris@16
|
141 switch ((e - b) & 7)
|
Chris@16
|
142 {
|
Chris@16
|
143 case 0:
|
Chris@16
|
144 while (b != e)
|
Chris@16
|
145 {
|
Chris@16
|
146 *b = c; ++b; BOOST_FALLTHROUGH;
|
Chris@16
|
147 case 7: *b = c; ++b; BOOST_FALLTHROUGH;
|
Chris@16
|
148 case 6: *b = c; ++b; BOOST_FALLTHROUGH;
|
Chris@16
|
149 case 5: *b = c; ++b; BOOST_FALLTHROUGH;
|
Chris@16
|
150 case 4: *b = c; ++b; BOOST_FALLTHROUGH;
|
Chris@16
|
151 case 3: *b = c; ++b; BOOST_FALLTHROUGH;
|
Chris@16
|
152 case 2: *b = c; ++b; BOOST_FALLTHROUGH;
|
Chris@16
|
153 case 1: *b = c; ++b;
|
Chris@16
|
154 }
|
Chris@16
|
155 }
|
Chris@16
|
156 }
|
Chris@16
|
157
|
Chris@16
|
158 template <class Pod>
|
Chris@16
|
159 inline void pod_move(const Pod* b, const Pod* e, Pod* d)
|
Chris@16
|
160 {
|
Chris@16
|
161 using namespace std;
|
Chris@16
|
162 memmove(d, b, (e - b) * sizeof(*b));
|
Chris@16
|
163 }
|
Chris@16
|
164
|
Chris@16
|
165 template <class Pod>
|
Chris@16
|
166 inline Pod* pod_copy(const Pod* b, const Pod* e, Pod* d)
|
Chris@16
|
167 {
|
Chris@16
|
168 const std::size_t s = e - b;
|
Chris@16
|
169 using namespace std;
|
Chris@16
|
170 memcpy(d, b, s * sizeof(*b));
|
Chris@16
|
171 return d + s;
|
Chris@16
|
172 }
|
Chris@16
|
173
|
Chris@16
|
174 template <typename T> struct get_unsigned
|
Chris@16
|
175 {
|
Chris@16
|
176 typedef T result;
|
Chris@16
|
177 };
|
Chris@16
|
178
|
Chris@16
|
179 template <> struct get_unsigned<char>
|
Chris@16
|
180 {
|
Chris@16
|
181 typedef unsigned char result;
|
Chris@16
|
182 };
|
Chris@16
|
183
|
Chris@16
|
184 template <> struct get_unsigned<signed char>
|
Chris@16
|
185 {
|
Chris@16
|
186 typedef unsigned char result;
|
Chris@16
|
187 };
|
Chris@16
|
188
|
Chris@16
|
189 template <> struct get_unsigned<short int>
|
Chris@16
|
190 {
|
Chris@16
|
191 typedef unsigned short int result;
|
Chris@16
|
192 };
|
Chris@16
|
193
|
Chris@16
|
194 template <> struct get_unsigned<int>
|
Chris@16
|
195 {
|
Chris@16
|
196 typedef unsigned int result;
|
Chris@16
|
197 };
|
Chris@16
|
198
|
Chris@16
|
199 template <> struct get_unsigned<long int>
|
Chris@16
|
200 {
|
Chris@16
|
201 typedef unsigned long int result;
|
Chris@16
|
202 };
|
Chris@16
|
203
|
Chris@16
|
204 enum Shallow {};
|
Chris@16
|
205 }
|
Chris@16
|
206
|
Chris@16
|
207 template <class T> class mallocator
|
Chris@16
|
208 {
|
Chris@16
|
209 public:
|
Chris@16
|
210 typedef T value_type;
|
Chris@16
|
211 typedef value_type* pointer;
|
Chris@16
|
212 typedef const value_type* const_pointer;
|
Chris@16
|
213 typedef value_type& reference;
|
Chris@16
|
214 typedef const value_type& const_reference;
|
Chris@16
|
215 typedef std::size_t size_type;
|
Chris@16
|
216 //typedef unsigned int size_type;
|
Chris@16
|
217 //typedef std::ptrdiff_t difference_type;
|
Chris@16
|
218 typedef int difference_type;
|
Chris@16
|
219
|
Chris@16
|
220 template <class U>
|
Chris@16
|
221 struct rebind { typedef mallocator<U> other; };
|
Chris@16
|
222
|
Chris@16
|
223 mallocator() {}
|
Chris@16
|
224 mallocator(const mallocator&) {}
|
Chris@16
|
225 //template <class U>
|
Chris@16
|
226 //mallocator(const mallocator<U>&) {}
|
Chris@16
|
227 ~mallocator() {}
|
Chris@16
|
228
|
Chris@16
|
229 pointer address(reference x) const { return &x; }
|
Chris@16
|
230 const_pointer address(const_reference x) const
|
Chris@16
|
231 {
|
Chris@16
|
232 return x;
|
Chris@16
|
233 }
|
Chris@16
|
234
|
Chris@16
|
235 pointer allocate(size_type n, const_pointer = 0)
|
Chris@16
|
236 {
|
Chris@16
|
237 using namespace std;
|
Chris@16
|
238 void* p = malloc(n * sizeof(T));
|
Chris@16
|
239 if (!p) boost::throw_exception(std::bad_alloc());
|
Chris@16
|
240 return static_cast<pointer>(p);
|
Chris@16
|
241 }
|
Chris@16
|
242
|
Chris@16
|
243 void deallocate(pointer p, size_type)
|
Chris@16
|
244 {
|
Chris@16
|
245 using namespace std;
|
Chris@16
|
246 free(p);
|
Chris@16
|
247 }
|
Chris@16
|
248
|
Chris@16
|
249 size_type max_size() const
|
Chris@16
|
250 {
|
Chris@16
|
251 return static_cast<size_type>(-1) / sizeof(T);
|
Chris@16
|
252 }
|
Chris@16
|
253
|
Chris@16
|
254 void construct(pointer p, const value_type& x)
|
Chris@16
|
255 {
|
Chris@16
|
256 new(p) value_type(x);
|
Chris@16
|
257 }
|
Chris@16
|
258
|
Chris@16
|
259 void destroy(pointer p)
|
Chris@16
|
260 {
|
Chris@16
|
261 p->~value_type();
|
Chris@16
|
262 }
|
Chris@16
|
263
|
Chris@16
|
264 private:
|
Chris@16
|
265 void operator=(const mallocator&);
|
Chris@16
|
266 };
|
Chris@16
|
267
|
Chris@16
|
268 template<> class mallocator<void>
|
Chris@16
|
269 {
|
Chris@16
|
270 typedef void value_type;
|
Chris@16
|
271 typedef void* pointer;
|
Chris@16
|
272 typedef const void* const_pointer;
|
Chris@16
|
273
|
Chris@16
|
274 template <class U>
|
Chris@16
|
275 struct rebind { typedef mallocator<U> other; };
|
Chris@16
|
276 };
|
Chris@16
|
277
|
Chris@16
|
278 template <class T>
|
Chris@16
|
279 inline bool operator==(const mallocator<T>&,
|
Chris@16
|
280 const mallocator<T>&) {
|
Chris@16
|
281 return true;
|
Chris@16
|
282 }
|
Chris@16
|
283
|
Chris@16
|
284 template <class T>
|
Chris@16
|
285 inline bool operator!=(const mallocator<T>&,
|
Chris@16
|
286 const mallocator<T>&) {
|
Chris@16
|
287 return false;
|
Chris@16
|
288 }
|
Chris@16
|
289
|
Chris@16
|
290 template <class Allocator>
|
Chris@16
|
291 typename Allocator::pointer Reallocate(
|
Chris@16
|
292 Allocator& alloc,
|
Chris@16
|
293 typename Allocator::pointer p,
|
Chris@16
|
294 typename Allocator::size_type oldObjCount,
|
Chris@16
|
295 typename Allocator::size_type newObjCount,
|
Chris@16
|
296 void*)
|
Chris@16
|
297 {
|
Chris@16
|
298 // @@@ not implemented
|
Chris@16
|
299 return NULL;
|
Chris@16
|
300 }
|
Chris@16
|
301
|
Chris@16
|
302 template <class Allocator>
|
Chris@16
|
303 typename Allocator::pointer Reallocate(
|
Chris@16
|
304 Allocator& alloc,
|
Chris@16
|
305 typename Allocator::pointer p,
|
Chris@16
|
306 typename Allocator::size_type oldObjCount,
|
Chris@16
|
307 typename Allocator::size_type newObjCount,
|
Chris@16
|
308 mallocator<void>*)
|
Chris@16
|
309 {
|
Chris@16
|
310 // @@@ not implemented
|
Chris@16
|
311 return NULL;
|
Chris@16
|
312 }
|
Chris@16
|
313
|
Chris@16
|
314 ////////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
315 // class template SimpleStringStorage
|
Chris@16
|
316 // Allocates memory with malloc
|
Chris@16
|
317 ////////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
318
|
Chris@16
|
319 template <typename E, class A = std::allocator<E> >
|
Chris@16
|
320 class SimpleStringStorage
|
Chris@16
|
321 {
|
Chris@16
|
322 // The "public" below exists because MSVC can't do template typedefs
|
Chris@16
|
323 public:
|
Chris@16
|
324 struct Data
|
Chris@16
|
325 {
|
Chris@16
|
326 Data() : pEnd_(buffer_), pEndOfMem_(buffer_) { buffer_[0] = E(0); }
|
Chris@16
|
327
|
Chris@16
|
328 E* pEnd_;
|
Chris@16
|
329 E* pEndOfMem_;
|
Chris@16
|
330 E buffer_[1];
|
Chris@16
|
331 };
|
Chris@16
|
332 static const Data emptyString_;
|
Chris@16
|
333
|
Chris@16
|
334 typedef typename A::size_type size_type;
|
Chris@16
|
335
|
Chris@16
|
336 private:
|
Chris@16
|
337 Data* pData_;
|
Chris@16
|
338
|
Chris@16
|
339 void Init(size_type size, size_type capacity)
|
Chris@16
|
340 {
|
Chris@16
|
341 BOOST_ASSERT(size <= capacity);
|
Chris@16
|
342 if (capacity == 0)
|
Chris@16
|
343 {
|
Chris@16
|
344 pData_ = const_cast<Data*>(&emptyString_);
|
Chris@16
|
345 }
|
Chris@16
|
346 else
|
Chris@16
|
347 {
|
Chris@16
|
348 // 11-17-2000: comment added:
|
Chris@16
|
349 // No need to allocate (capacity + 1) to
|
Chris@16
|
350 // accommodate the terminating 0, because Data already
|
Chris@16
|
351 // has one character in there
|
Chris@16
|
352 pData_ = static_cast<Data*>(
|
Chris@16
|
353 malloc(sizeof(Data) + capacity * sizeof(E)));
|
Chris@16
|
354 if (!pData_) boost::throw_exception(std::bad_alloc());
|
Chris@16
|
355 pData_->pEnd_ = pData_->buffer_ + size;
|
Chris@16
|
356 pData_->pEndOfMem_ = pData_->buffer_ + capacity;
|
Chris@16
|
357 }
|
Chris@16
|
358 }
|
Chris@16
|
359
|
Chris@16
|
360 private:
|
Chris@16
|
361 // Warning - this doesn't initialize pData_. Used in reserve()
|
Chris@16
|
362 SimpleStringStorage()
|
Chris@16
|
363 { }
|
Chris@16
|
364
|
Chris@16
|
365 public:
|
Chris@16
|
366 typedef E value_type;
|
Chris@16
|
367 typedef E* iterator;
|
Chris@16
|
368 typedef const E* const_iterator;
|
Chris@16
|
369 typedef A allocator_type;
|
Chris@16
|
370
|
Chris@16
|
371 SimpleStringStorage(const SimpleStringStorage& rhs)
|
Chris@16
|
372 {
|
Chris@16
|
373 const size_type sz = rhs.size();
|
Chris@16
|
374 Init(sz, sz);
|
Chris@16
|
375 if (sz) flex_string_details::pod_copy(rhs.begin(), rhs.end(), begin());
|
Chris@16
|
376 }
|
Chris@16
|
377
|
Chris@16
|
378 SimpleStringStorage(const SimpleStringStorage& s,
|
Chris@16
|
379 flex_string_details::Shallow)
|
Chris@16
|
380 : pData_(s.pData_)
|
Chris@16
|
381 {
|
Chris@16
|
382 }
|
Chris@16
|
383
|
Chris@16
|
384 SimpleStringStorage(const A&)
|
Chris@16
|
385 { pData_ = const_cast<Data*>(&emptyString_); }
|
Chris@16
|
386
|
Chris@16
|
387 SimpleStringStorage(const E* s, size_type len, const A&)
|
Chris@16
|
388 {
|
Chris@16
|
389 Init(len, len);
|
Chris@16
|
390 flex_string_details::pod_copy(s, s + len, begin());
|
Chris@16
|
391 }
|
Chris@16
|
392
|
Chris@16
|
393 SimpleStringStorage(size_type len, E c, const A&)
|
Chris@16
|
394 {
|
Chris@16
|
395 Init(len, len);
|
Chris@16
|
396 flex_string_details::pod_fill(begin(), end(), c);
|
Chris@16
|
397 }
|
Chris@16
|
398
|
Chris@16
|
399 SimpleStringStorage& operator=(const SimpleStringStorage& rhs)
|
Chris@16
|
400 {
|
Chris@16
|
401 const size_type sz = rhs.size();
|
Chris@16
|
402 reserve(sz);
|
Chris@16
|
403 flex_string_details::pod_copy(&*rhs.begin(), &*rhs.end(), begin());
|
Chris@16
|
404 pData_->pEnd_ = &*begin() + sz;
|
Chris@16
|
405 return *this;
|
Chris@16
|
406 }
|
Chris@16
|
407
|
Chris@16
|
408 ~SimpleStringStorage()
|
Chris@16
|
409 {
|
Chris@16
|
410 BOOST_ASSERT(begin() <= end());
|
Chris@16
|
411 if (pData_ != &emptyString_) free(pData_);
|
Chris@16
|
412 }
|
Chris@16
|
413
|
Chris@16
|
414 iterator begin()
|
Chris@16
|
415 { return pData_->buffer_; }
|
Chris@16
|
416
|
Chris@16
|
417 const_iterator begin() const
|
Chris@16
|
418 { return pData_->buffer_; }
|
Chris@16
|
419
|
Chris@16
|
420 iterator end()
|
Chris@16
|
421 { return pData_->pEnd_; }
|
Chris@16
|
422
|
Chris@16
|
423 const_iterator end() const
|
Chris@16
|
424 { return pData_->pEnd_; }
|
Chris@16
|
425
|
Chris@16
|
426 size_type size() const
|
Chris@16
|
427 { return pData_->pEnd_ - pData_->buffer_; }
|
Chris@16
|
428
|
Chris@16
|
429 size_type max_size() const
|
Chris@16
|
430 { return std::size_t(-1) / sizeof(E) - sizeof(Data) - 1; }
|
Chris@16
|
431
|
Chris@16
|
432 size_type capacity() const
|
Chris@16
|
433 { return pData_->pEndOfMem_ - pData_->buffer_; }
|
Chris@16
|
434
|
Chris@16
|
435 void reserve(size_type res_arg)
|
Chris@16
|
436 {
|
Chris@16
|
437 if (res_arg <= capacity())
|
Chris@16
|
438 {
|
Chris@16
|
439 // @@@ insert shrinkage here if you wish
|
Chris@16
|
440 return;
|
Chris@16
|
441 }
|
Chris@16
|
442
|
Chris@16
|
443 if (pData_ == &emptyString_)
|
Chris@16
|
444 {
|
Chris@16
|
445 Init(0, res_arg);
|
Chris@16
|
446 }
|
Chris@16
|
447 else
|
Chris@16
|
448 {
|
Chris@16
|
449 const size_type sz = size();
|
Chris@16
|
450
|
Chris@16
|
451 void* p = realloc(pData_,
|
Chris@16
|
452 sizeof(Data) + res_arg * sizeof(E));
|
Chris@16
|
453 if (!p) boost::throw_exception(std::bad_alloc());
|
Chris@16
|
454
|
Chris@16
|
455 if (p != pData_)
|
Chris@16
|
456 {
|
Chris@16
|
457 pData_ = static_cast<Data*>(p);
|
Chris@16
|
458 pData_->pEnd_ = pData_->buffer_ + sz;
|
Chris@16
|
459 }
|
Chris@16
|
460 pData_->pEndOfMem_ = pData_->buffer_ + res_arg;
|
Chris@16
|
461 }
|
Chris@16
|
462 }
|
Chris@16
|
463
|
Chris@16
|
464 void append(const E* s, size_type sz)
|
Chris@16
|
465 {
|
Chris@16
|
466 const size_type neededCapacity = size() + sz;
|
Chris@16
|
467
|
Chris@16
|
468 if (capacity() < neededCapacity)
|
Chris@16
|
469 {
|
Chris@16
|
470 const iterator b = begin();
|
Chris@16
|
471 static std::less_equal<const E*> le;
|
Chris@16
|
472 if (le(b, s) && le(s, end()))
|
Chris@16
|
473 {
|
Chris@16
|
474 // aliased
|
Chris@16
|
475 const size_type offset = s - b;
|
Chris@16
|
476 reserve(neededCapacity);
|
Chris@16
|
477 s = begin() + offset;
|
Chris@16
|
478 }
|
Chris@16
|
479 else
|
Chris@16
|
480 {
|
Chris@16
|
481 reserve(neededCapacity);
|
Chris@16
|
482 }
|
Chris@16
|
483 }
|
Chris@16
|
484 flex_string_details::pod_copy(s, s + sz, end());
|
Chris@16
|
485 pData_->pEnd_ += sz;
|
Chris@16
|
486 }
|
Chris@16
|
487
|
Chris@16
|
488 template <class InputIterator>
|
Chris@16
|
489 void append(InputIterator b, InputIterator e)
|
Chris@16
|
490 {
|
Chris@16
|
491 // @@@ todo: optimize this depending on iterator type
|
Chris@16
|
492 for (; b != e; ++b)
|
Chris@16
|
493 {
|
Chris@16
|
494 *this += *b;
|
Chris@16
|
495 }
|
Chris@16
|
496 }
|
Chris@16
|
497
|
Chris@16
|
498 void resize(size_type newSize, E fill)
|
Chris@16
|
499 {
|
Chris@16
|
500 const int delta = int(newSize - size());
|
Chris@16
|
501 if (delta == 0) return;
|
Chris@16
|
502
|
Chris@16
|
503 if (delta > 0)
|
Chris@16
|
504 {
|
Chris@16
|
505 if (newSize > capacity())
|
Chris@16
|
506 {
|
Chris@16
|
507 reserve(newSize);
|
Chris@16
|
508 }
|
Chris@16
|
509 E* e = &*end();
|
Chris@16
|
510 flex_string_details::pod_fill(e, e + delta, fill);
|
Chris@16
|
511 }
|
Chris@16
|
512 pData_->pEnd_ = pData_->buffer_ + newSize;
|
Chris@16
|
513 }
|
Chris@16
|
514
|
Chris@16
|
515 void swap(SimpleStringStorage& rhs)
|
Chris@16
|
516 {
|
Chris@16
|
517 std::swap(pData_, rhs.pData_);
|
Chris@16
|
518 }
|
Chris@16
|
519
|
Chris@16
|
520 const E* c_str() const
|
Chris@16
|
521 {
|
Chris@16
|
522 if (pData_ != &emptyString_) *pData_->pEnd_ = E();
|
Chris@16
|
523 return pData_->buffer_;
|
Chris@16
|
524 }
|
Chris@16
|
525
|
Chris@16
|
526 const E* data() const
|
Chris@16
|
527 { return pData_->buffer_; }
|
Chris@16
|
528
|
Chris@16
|
529 A get_allocator() const
|
Chris@16
|
530 { return A(); }
|
Chris@16
|
531 };
|
Chris@16
|
532
|
Chris@16
|
533 template <typename E, class A>
|
Chris@16
|
534 const typename SimpleStringStorage<E, A>::Data
|
Chris@16
|
535 SimpleStringStorage<E, A>::emptyString_ =
|
Chris@16
|
536 typename SimpleStringStorage<E, A>::Data();
|
Chris@16
|
537
|
Chris@16
|
538 ////////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
539 // class template AllocatorStringStorage
|
Chris@16
|
540 // Allocates with your allocator
|
Chris@16
|
541 // Takes advantage of the Empty Base Optimization if available
|
Chris@16
|
542 ////////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
543
|
Chris@16
|
544 template <typename E, class A = std::allocator<E> >
|
Chris@16
|
545 class AllocatorStringStorage : public A
|
Chris@16
|
546 {
|
Chris@16
|
547 typedef typename A::size_type size_type;
|
Chris@16
|
548 typedef typename SimpleStringStorage<E, A>::Data Data;
|
Chris@16
|
549
|
Chris@16
|
550 void* Alloc(size_type sz, const void* p = 0)
|
Chris@16
|
551 {
|
Chris@16
|
552 return A::allocate(1 + (sz - 1) / sizeof(E),
|
Chris@16
|
553 static_cast<const char*>(p));
|
Chris@16
|
554 }
|
Chris@16
|
555
|
Chris@16
|
556 void* Realloc(void* p, size_type oldSz, size_type newSz)
|
Chris@16
|
557 {
|
Chris@16
|
558 void* r = Alloc(newSz);
|
Chris@16
|
559 flex_string_details::pod_copy(p, p + Min(oldSz, newSz), r);
|
Chris@16
|
560 Free(p, oldSz);
|
Chris@16
|
561 return r;
|
Chris@16
|
562 }
|
Chris@16
|
563
|
Chris@16
|
564 void Free(void* p, size_type sz)
|
Chris@16
|
565 {
|
Chris@16
|
566 A::deallocate(static_cast<E*>(p), sz);
|
Chris@16
|
567 }
|
Chris@16
|
568
|
Chris@16
|
569 Data* pData_;
|
Chris@16
|
570
|
Chris@16
|
571 void Init(size_type size, size_type cap)
|
Chris@16
|
572 {
|
Chris@16
|
573 BOOST_ASSERT(size <= cap);
|
Chris@16
|
574
|
Chris@16
|
575 if (cap == 0)
|
Chris@16
|
576 {
|
Chris@16
|
577 pData_ = const_cast<Data*>(
|
Chris@16
|
578 &SimpleStringStorage<E, A>::emptyString_);
|
Chris@16
|
579 }
|
Chris@16
|
580 else
|
Chris@16
|
581 {
|
Chris@16
|
582 pData_ = static_cast<Data*>(Alloc(
|
Chris@16
|
583 cap * sizeof(E) + sizeof(Data)));
|
Chris@16
|
584 pData_->pEnd_ = pData_->buffer_ + size;
|
Chris@16
|
585 pData_->pEndOfMem_ = pData_->buffer_ + cap;
|
Chris@16
|
586 }
|
Chris@16
|
587 }
|
Chris@16
|
588
|
Chris@16
|
589 public:
|
Chris@16
|
590 typedef E value_type;
|
Chris@16
|
591 typedef E* iterator;
|
Chris@16
|
592 typedef const E* const_iterator;
|
Chris@16
|
593 typedef A allocator_type;
|
Chris@16
|
594
|
Chris@16
|
595 AllocatorStringStorage()
|
Chris@16
|
596 : A(), pData_(0)
|
Chris@16
|
597 {
|
Chris@16
|
598 }
|
Chris@16
|
599
|
Chris@16
|
600 AllocatorStringStorage(const AllocatorStringStorage& rhs)
|
Chris@16
|
601 : A(rhs.get_allocator())
|
Chris@16
|
602 {
|
Chris@16
|
603 const size_type sz = rhs.size();
|
Chris@16
|
604 Init(sz, sz);
|
Chris@16
|
605 if (sz) flex_string_details::pod_copy(rhs.begin(), rhs.end(), begin());
|
Chris@16
|
606 }
|
Chris@16
|
607
|
Chris@16
|
608 AllocatorStringStorage(const AllocatorStringStorage& s,
|
Chris@16
|
609 flex_string_details::Shallow)
|
Chris@16
|
610 : A(s.get_allocator())
|
Chris@16
|
611 {
|
Chris@16
|
612 pData_ = s.pData_;
|
Chris@16
|
613 }
|
Chris@16
|
614
|
Chris@16
|
615 AllocatorStringStorage(const A& a) : A(a)
|
Chris@16
|
616 {
|
Chris@16
|
617 pData_ = const_cast<Data*>(
|
Chris@16
|
618 &SimpleStringStorage<E, A>::emptyString_);
|
Chris@16
|
619 }
|
Chris@16
|
620
|
Chris@16
|
621 AllocatorStringStorage(const E* s, size_type len, const A& a)
|
Chris@16
|
622 : A(a)
|
Chris@16
|
623 {
|
Chris@16
|
624 Init(len, len);
|
Chris@16
|
625 flex_string_details::pod_copy(s, s + len, begin());
|
Chris@16
|
626 }
|
Chris@16
|
627
|
Chris@16
|
628 AllocatorStringStorage(size_type len, E c, const A& a)
|
Chris@16
|
629 : A(a)
|
Chris@16
|
630 {
|
Chris@16
|
631 Init(len, len);
|
Chris@16
|
632 flex_string_details::pod_fill(&*begin(), &*end(), c);
|
Chris@16
|
633 }
|
Chris@16
|
634
|
Chris@16
|
635 AllocatorStringStorage& operator=(const AllocatorStringStorage& rhs)
|
Chris@16
|
636 {
|
Chris@16
|
637 const size_type sz = rhs.size();
|
Chris@16
|
638 reserve(sz);
|
Chris@16
|
639 flex_string_details::pod_copy(&*rhs.begin(), &*rhs.end(), begin());
|
Chris@16
|
640 pData_->pEnd_ = &*begin() + rhs.size();
|
Chris@16
|
641 return *this;
|
Chris@16
|
642 }
|
Chris@16
|
643
|
Chris@16
|
644 ~AllocatorStringStorage()
|
Chris@16
|
645 {
|
Chris@16
|
646 if (capacity())
|
Chris@16
|
647 {
|
Chris@16
|
648 Free(pData_,
|
Chris@16
|
649 sizeof(Data) + capacity() * sizeof(E));
|
Chris@16
|
650 }
|
Chris@16
|
651 }
|
Chris@16
|
652
|
Chris@16
|
653 iterator begin()
|
Chris@16
|
654 { return pData_->buffer_; }
|
Chris@16
|
655
|
Chris@16
|
656 const_iterator begin() const
|
Chris@16
|
657 { return pData_->buffer_; }
|
Chris@16
|
658
|
Chris@16
|
659 iterator end()
|
Chris@16
|
660 { return pData_->pEnd_; }
|
Chris@16
|
661
|
Chris@16
|
662 const_iterator end() const
|
Chris@16
|
663 { return pData_->pEnd_; }
|
Chris@16
|
664
|
Chris@16
|
665 size_type size() const
|
Chris@16
|
666 { return size_type(end() - begin()); }
|
Chris@16
|
667
|
Chris@16
|
668 size_type max_size() const
|
Chris@16
|
669 { return A::max_size(); }
|
Chris@16
|
670
|
Chris@16
|
671 size_type capacity() const
|
Chris@16
|
672 { return size_type(pData_->pEndOfMem_ - pData_->buffer_); }
|
Chris@16
|
673
|
Chris@16
|
674 void resize(size_type n, E c)
|
Chris@16
|
675 {
|
Chris@16
|
676 reserve(n);
|
Chris@16
|
677 iterator newEnd = begin() + n;
|
Chris@16
|
678 iterator oldEnd = end();
|
Chris@16
|
679 if (newEnd > oldEnd)
|
Chris@16
|
680 {
|
Chris@16
|
681 // Copy the characters
|
Chris@16
|
682 flex_string_details::pod_fill(oldEnd, newEnd, c);
|
Chris@16
|
683 }
|
Chris@16
|
684 if (capacity()) pData_->pEnd_ = newEnd;
|
Chris@16
|
685 }
|
Chris@16
|
686
|
Chris@16
|
687 void reserve(size_type res_arg)
|
Chris@16
|
688 {
|
Chris@16
|
689 if (res_arg <= capacity())
|
Chris@16
|
690 {
|
Chris@16
|
691 // @@@ shrink to fit here
|
Chris@16
|
692 return;
|
Chris@16
|
693 }
|
Chris@16
|
694
|
Chris@16
|
695 A& myAlloc = *this;
|
Chris@16
|
696 AllocatorStringStorage newStr(myAlloc);
|
Chris@16
|
697 newStr.Init(size(), res_arg);
|
Chris@16
|
698
|
Chris@16
|
699 flex_string_details::pod_copy(begin(), end(), newStr.begin());
|
Chris@16
|
700
|
Chris@16
|
701 swap(newStr);
|
Chris@16
|
702 }
|
Chris@16
|
703
|
Chris@16
|
704 template <class ForwardIterator>
|
Chris@16
|
705 void append(ForwardIterator b, ForwardIterator e)
|
Chris@16
|
706 {
|
Chris@16
|
707 const size_type
|
Chris@16
|
708 sz = std::distance(b, e),
|
Chris@16
|
709 neededCapacity = size() + sz;
|
Chris@16
|
710
|
Chris@16
|
711 if (capacity() < neededCapacity)
|
Chris@16
|
712 {
|
Chris@16
|
713 // typedef std::less_equal<const E*> le_type;
|
Chris@16
|
714 // BOOST_ASSERT(!(le_type()(begin(), &*b) && le_type()(&*b, end())));
|
Chris@16
|
715 reserve(neededCapacity);
|
Chris@16
|
716 }
|
Chris@16
|
717 std::copy(b, e, end());
|
Chris@16
|
718 pData_->pEnd_ += sz;
|
Chris@16
|
719 }
|
Chris@16
|
720
|
Chris@16
|
721 void swap(AllocatorStringStorage& rhs)
|
Chris@16
|
722 {
|
Chris@16
|
723 // @@@ The following line is commented due to a bug in MSVC
|
Chris@16
|
724 //std::swap(lhsAlloc, rhsAlloc);
|
Chris@16
|
725 std::swap(pData_, rhs.pData_);
|
Chris@16
|
726 }
|
Chris@16
|
727
|
Chris@16
|
728 const E* c_str() const
|
Chris@16
|
729 {
|
Chris@16
|
730 if (pData_ != &SimpleStringStorage<E, A>::emptyString_)
|
Chris@16
|
731 {
|
Chris@16
|
732 *pData_->pEnd_ = E();
|
Chris@16
|
733 }
|
Chris@16
|
734 return &*begin();
|
Chris@16
|
735 }
|
Chris@16
|
736
|
Chris@16
|
737 const E* data() const
|
Chris@16
|
738 { return &*begin(); }
|
Chris@16
|
739
|
Chris@16
|
740 A get_allocator() const
|
Chris@16
|
741 { return *this; }
|
Chris@16
|
742 };
|
Chris@16
|
743
|
Chris@16
|
744 ////////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
745 // class template VectorStringStorage
|
Chris@16
|
746 // Uses std::vector
|
Chris@16
|
747 // Takes advantage of the Empty Base Optimization if available
|
Chris@16
|
748 ////////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
749
|
Chris@16
|
750 template <typename E, class A = std::allocator<E> >
|
Chris@16
|
751 class VectorStringStorage : protected std::vector<E, A>
|
Chris@16
|
752 {
|
Chris@16
|
753 typedef std::vector<E, A> base;
|
Chris@16
|
754
|
Chris@16
|
755 public: // protected:
|
Chris@16
|
756 typedef E value_type;
|
Chris@16
|
757 typedef typename base::iterator iterator;
|
Chris@16
|
758 typedef typename base::const_iterator const_iterator;
|
Chris@16
|
759 typedef A allocator_type;
|
Chris@16
|
760 typedef typename A::size_type size_type;
|
Chris@16
|
761
|
Chris@16
|
762 VectorStringStorage(const VectorStringStorage& s) : base(s)
|
Chris@16
|
763 { }
|
Chris@16
|
764
|
Chris@16
|
765 VectorStringStorage(const A& a) : base(1, E(), a)
|
Chris@16
|
766 { }
|
Chris@16
|
767
|
Chris@16
|
768 VectorStringStorage(const E* s, size_type len, const A& a)
|
Chris@16
|
769 : base(a)
|
Chris@16
|
770 {
|
Chris@16
|
771 base::reserve(len + 1);
|
Chris@16
|
772 base::insert(base::end(), s, s + len);
|
Chris@16
|
773 // Terminating zero
|
Chris@16
|
774 base::insert(base::end(), E());
|
Chris@16
|
775 }
|
Chris@16
|
776
|
Chris@16
|
777 VectorStringStorage(size_type len, E c, const A& a)
|
Chris@16
|
778 : base(len + 1, c, a)
|
Chris@16
|
779 {
|
Chris@16
|
780 // Terminating zero
|
Chris@16
|
781 base::back() = E();
|
Chris@16
|
782 }
|
Chris@16
|
783
|
Chris@16
|
784 VectorStringStorage& operator=(const VectorStringStorage& rhs)
|
Chris@16
|
785 {
|
Chris@16
|
786 base& v = *this;
|
Chris@16
|
787 v = rhs;
|
Chris@16
|
788 return *this;
|
Chris@16
|
789 }
|
Chris@16
|
790
|
Chris@16
|
791 iterator begin()
|
Chris@16
|
792 { return base::begin(); }
|
Chris@16
|
793
|
Chris@16
|
794 const_iterator begin() const
|
Chris@16
|
795 { return base::begin(); }
|
Chris@16
|
796
|
Chris@16
|
797 iterator end()
|
Chris@16
|
798 { return base::end() - 1; }
|
Chris@16
|
799
|
Chris@16
|
800 const_iterator end() const
|
Chris@16
|
801 { return base::end() - 1; }
|
Chris@16
|
802
|
Chris@16
|
803 size_type size() const
|
Chris@16
|
804 { return base::size() - 1; }
|
Chris@16
|
805
|
Chris@16
|
806 size_type max_size() const
|
Chris@16
|
807 { return base::max_size() - 1; }
|
Chris@16
|
808
|
Chris@16
|
809 size_type capacity() const
|
Chris@16
|
810 { return base::capacity() - 1; }
|
Chris@16
|
811
|
Chris@16
|
812 void reserve(size_type res_arg)
|
Chris@16
|
813 {
|
Chris@16
|
814 BOOST_ASSERT(res_arg < max_size());
|
Chris@16
|
815 base::reserve(res_arg + 1);
|
Chris@16
|
816 }
|
Chris@16
|
817
|
Chris@16
|
818 void append(const E* s, size_type sz)
|
Chris@16
|
819 {
|
Chris@16
|
820 // Check for aliasing because std::vector doesn't do it.
|
Chris@16
|
821 static std::less_equal<const E*> le;
|
Chris@16
|
822 if (!base::empty())
|
Chris@16
|
823 {
|
Chris@16
|
824 const E* start = &base::front();
|
Chris@16
|
825 if (le(start, s) && le(s, start + size()))
|
Chris@16
|
826 {
|
Chris@16
|
827 // aliased
|
Chris@16
|
828 const size_type offset = s - start;
|
Chris@16
|
829 reserve(size() + sz);
|
Chris@16
|
830 s = &base::front() + offset;
|
Chris@16
|
831 }
|
Chris@16
|
832 }
|
Chris@16
|
833 base::insert(end(), s, s + sz);
|
Chris@16
|
834 }
|
Chris@16
|
835
|
Chris@16
|
836 template <class InputIterator>
|
Chris@16
|
837 void append(InputIterator b, InputIterator e)
|
Chris@16
|
838 {
|
Chris@16
|
839 base::insert(end(), b, e);
|
Chris@16
|
840 }
|
Chris@16
|
841
|
Chris@16
|
842 void resize(size_type n, E c)
|
Chris@16
|
843 {
|
Chris@16
|
844 base::reserve(n + 1);
|
Chris@16
|
845 base::back() = c;
|
Chris@16
|
846 base::resize(n + 1, c);
|
Chris@16
|
847 base::back() = E();
|
Chris@16
|
848 }
|
Chris@16
|
849
|
Chris@16
|
850 void swap(VectorStringStorage& rhs)
|
Chris@16
|
851 { base::swap(rhs); }
|
Chris@16
|
852
|
Chris@16
|
853 const E* c_str() const
|
Chris@16
|
854 { return &*begin(); }
|
Chris@16
|
855
|
Chris@16
|
856 const E* data() const
|
Chris@16
|
857 { return &*begin(); }
|
Chris@16
|
858
|
Chris@16
|
859 A get_allocator() const
|
Chris@16
|
860 { return base::get_allocator(); }
|
Chris@16
|
861 };
|
Chris@16
|
862
|
Chris@16
|
863 ////////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
864 // class template SmallStringOpt
|
Chris@16
|
865 // Builds the small string optimization over any other storage
|
Chris@16
|
866 ////////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
867
|
Chris@16
|
868 template <class Storage, unsigned int threshold,
|
Chris@16
|
869 typename Align = typename Storage::value_type*>
|
Chris@16
|
870 class SmallStringOpt
|
Chris@16
|
871 {
|
Chris@16
|
872 public:
|
Chris@16
|
873 typedef typename Storage::value_type value_type;
|
Chris@16
|
874 typedef value_type* iterator;
|
Chris@16
|
875 typedef const value_type* const_iterator;
|
Chris@16
|
876 typedef typename Storage::allocator_type allocator_type;
|
Chris@16
|
877 typedef typename allocator_type::size_type size_type;
|
Chris@16
|
878
|
Chris@16
|
879 private:
|
Chris@16
|
880 enum { temp1 = threshold * sizeof(value_type) > sizeof(Storage)
|
Chris@16
|
881 ? threshold * sizeof(value_type)
|
Chris@16
|
882 : sizeof(Storage) };
|
Chris@16
|
883
|
Chris@16
|
884 enum { temp2 = temp1 > sizeof(Align) ? temp1 : sizeof(Align) };
|
Chris@16
|
885
|
Chris@16
|
886 public:
|
Chris@16
|
887 enum { maxSmallString =
|
Chris@16
|
888 (temp2 + sizeof(value_type) - 1) / sizeof(value_type) };
|
Chris@16
|
889
|
Chris@16
|
890 private:
|
Chris@16
|
891 enum { magic = maxSmallString + 1 };
|
Chris@16
|
892
|
Chris@16
|
893 union
|
Chris@16
|
894 {
|
Chris@16
|
895 mutable value_type buf_[maxSmallString + 1];
|
Chris@16
|
896 Align align_;
|
Chris@16
|
897 };
|
Chris@16
|
898
|
Chris@16
|
899 Storage& GetStorage()
|
Chris@16
|
900 {
|
Chris@16
|
901 BOOST_ASSERT(buf_[maxSmallString] == magic);
|
Chris@16
|
902 Storage* p = reinterpret_cast<Storage*>(&buf_[0]);
|
Chris@16
|
903 return *p;
|
Chris@16
|
904 }
|
Chris@16
|
905
|
Chris@16
|
906 const Storage& GetStorage() const
|
Chris@16
|
907 {
|
Chris@16
|
908 BOOST_ASSERT(buf_[maxSmallString] == magic);
|
Chris@16
|
909 const Storage *p = reinterpret_cast<const Storage*>(&buf_[0]);
|
Chris@16
|
910 return *p;
|
Chris@16
|
911 }
|
Chris@16
|
912
|
Chris@16
|
913 bool Small() const
|
Chris@16
|
914 {
|
Chris@16
|
915 return buf_[maxSmallString] != magic;
|
Chris@16
|
916 }
|
Chris@16
|
917
|
Chris@16
|
918 public:
|
Chris@16
|
919 SmallStringOpt(const SmallStringOpt& s)
|
Chris@16
|
920 {
|
Chris@16
|
921 if (s.Small())
|
Chris@16
|
922 {
|
Chris@16
|
923 flex_string_details::pod_copy(
|
Chris@16
|
924 s.buf_,
|
Chris@16
|
925 s.buf_ + s.size(),
|
Chris@16
|
926 buf_);
|
Chris@16
|
927 }
|
Chris@16
|
928 else
|
Chris@16
|
929 {
|
Chris@16
|
930 new(buf_) Storage(s.GetStorage());
|
Chris@16
|
931 }
|
Chris@16
|
932 buf_[maxSmallString] = s.buf_[maxSmallString];
|
Chris@16
|
933 }
|
Chris@16
|
934
|
Chris@16
|
935 SmallStringOpt(const allocator_type&)
|
Chris@16
|
936 {
|
Chris@16
|
937 buf_[maxSmallString] = maxSmallString;
|
Chris@16
|
938 }
|
Chris@16
|
939
|
Chris@16
|
940 SmallStringOpt(const value_type* s, size_type len, const allocator_type& a)
|
Chris@16
|
941 {
|
Chris@16
|
942 if (len <= maxSmallString)
|
Chris@16
|
943 {
|
Chris@16
|
944 flex_string_details::pod_copy(s, s + len, buf_);
|
Chris@16
|
945 buf_[maxSmallString] = value_type(maxSmallString - len);
|
Chris@16
|
946 }
|
Chris@16
|
947 else
|
Chris@16
|
948 {
|
Chris@16
|
949 new(buf_) Storage(s, len, a);
|
Chris@16
|
950 buf_[maxSmallString] = magic;
|
Chris@16
|
951 }
|
Chris@16
|
952 }
|
Chris@16
|
953
|
Chris@16
|
954 SmallStringOpt(size_type len, value_type c, const allocator_type& a)
|
Chris@16
|
955 {
|
Chris@16
|
956 if (len <= maxSmallString)
|
Chris@16
|
957 {
|
Chris@16
|
958 flex_string_details::pod_fill(buf_, buf_ + len, c);
|
Chris@16
|
959 buf_[maxSmallString] = value_type(maxSmallString - len);
|
Chris@16
|
960 }
|
Chris@16
|
961 else
|
Chris@16
|
962 {
|
Chris@16
|
963 new(buf_) Storage(len, c, a);
|
Chris@16
|
964 buf_[maxSmallString] = magic;
|
Chris@16
|
965 }
|
Chris@16
|
966 }
|
Chris@16
|
967
|
Chris@16
|
968 SmallStringOpt& operator=(const SmallStringOpt& rhs)
|
Chris@16
|
969 {
|
Chris@16
|
970 reserve(rhs.size());
|
Chris@16
|
971 resize(0, 0);
|
Chris@16
|
972 append(rhs.data(), rhs.size());
|
Chris@16
|
973 return *this;
|
Chris@16
|
974 }
|
Chris@16
|
975
|
Chris@16
|
976 ~SmallStringOpt()
|
Chris@16
|
977 {
|
Chris@16
|
978 if (!Small()) GetStorage().~Storage();
|
Chris@16
|
979 }
|
Chris@16
|
980
|
Chris@16
|
981 iterator begin()
|
Chris@16
|
982 {
|
Chris@16
|
983 if (Small()) return buf_;
|
Chris@16
|
984 return &*GetStorage().begin();
|
Chris@16
|
985 }
|
Chris@16
|
986
|
Chris@16
|
987 const_iterator begin() const
|
Chris@16
|
988 {
|
Chris@16
|
989 if (Small()) return buf_;
|
Chris@16
|
990 return &*GetStorage().begin();
|
Chris@16
|
991 }
|
Chris@16
|
992
|
Chris@16
|
993 iterator end()
|
Chris@16
|
994 {
|
Chris@16
|
995 if (Small()) return buf_ + maxSmallString - buf_[maxSmallString];
|
Chris@16
|
996 return &*GetStorage().end();
|
Chris@16
|
997 }
|
Chris@16
|
998
|
Chris@16
|
999 const_iterator end() const
|
Chris@16
|
1000 {
|
Chris@16
|
1001 if (Small()) return buf_ + maxSmallString - buf_[maxSmallString];
|
Chris@16
|
1002 return &*GetStorage().end();
|
Chris@16
|
1003 }
|
Chris@16
|
1004
|
Chris@16
|
1005 size_type size() const
|
Chris@16
|
1006 {
|
Chris@16
|
1007 BOOST_ASSERT(!Small() || maxSmallString >= buf_[maxSmallString]);
|
Chris@16
|
1008 return Small()
|
Chris@16
|
1009 ? maxSmallString - buf_[maxSmallString]
|
Chris@16
|
1010 : GetStorage().size();
|
Chris@16
|
1011 }
|
Chris@16
|
1012
|
Chris@16
|
1013 size_type max_size() const
|
Chris@16
|
1014 { return get_allocator().max_size(); }
|
Chris@16
|
1015
|
Chris@16
|
1016 size_type capacity() const
|
Chris@16
|
1017 { return Small() ? maxSmallString : GetStorage().capacity(); }
|
Chris@16
|
1018
|
Chris@16
|
1019 void reserve(size_type res_arg)
|
Chris@16
|
1020 {
|
Chris@16
|
1021 if (Small())
|
Chris@16
|
1022 {
|
Chris@16
|
1023 if (res_arg <= maxSmallString) return;
|
Chris@16
|
1024 SmallStringOpt temp(*this);
|
Chris@16
|
1025 this->~SmallStringOpt();
|
Chris@16
|
1026 new(buf_) Storage(temp.data(), temp.size(),
|
Chris@16
|
1027 temp.get_allocator());
|
Chris@16
|
1028 buf_[maxSmallString] = magic;
|
Chris@16
|
1029 GetStorage().reserve(res_arg);
|
Chris@16
|
1030 }
|
Chris@16
|
1031 else
|
Chris@16
|
1032 {
|
Chris@16
|
1033 GetStorage().reserve(res_arg);
|
Chris@16
|
1034 }
|
Chris@16
|
1035 BOOST_ASSERT(capacity() >= res_arg);
|
Chris@16
|
1036 }
|
Chris@16
|
1037
|
Chris@16
|
1038 void append(const value_type* s, size_type sz)
|
Chris@16
|
1039 {
|
Chris@16
|
1040 if (!Small())
|
Chris@16
|
1041 {
|
Chris@16
|
1042 GetStorage().append(s, sz);
|
Chris@16
|
1043 }
|
Chris@16
|
1044 else
|
Chris@16
|
1045 {
|
Chris@16
|
1046 // append to a small string
|
Chris@16
|
1047 const size_type neededCapacity =
|
Chris@16
|
1048 maxSmallString - buf_[maxSmallString] + sz;
|
Chris@16
|
1049
|
Chris@16
|
1050 if (maxSmallString < neededCapacity)
|
Chris@16
|
1051 {
|
Chris@16
|
1052 // need to change storage strategy
|
Chris@16
|
1053 allocator_type alloc;
|
Chris@16
|
1054 Storage temp(alloc);
|
Chris@16
|
1055 temp.reserve(neededCapacity);
|
Chris@16
|
1056 temp.append(buf_, maxSmallString - buf_[maxSmallString]);
|
Chris@16
|
1057 temp.append(s, sz);
|
Chris@16
|
1058 buf_[maxSmallString] = magic;
|
Chris@16
|
1059 new(buf_) Storage(temp.get_allocator());
|
Chris@16
|
1060 GetStorage().swap(temp);
|
Chris@16
|
1061 }
|
Chris@16
|
1062 else
|
Chris@16
|
1063 {
|
Chris@16
|
1064 flex_string_details::pod_move(s, s + sz,
|
Chris@16
|
1065 buf_ + maxSmallString - buf_[maxSmallString]);
|
Chris@16
|
1066 buf_[maxSmallString] -= value_type(sz);
|
Chris@16
|
1067 }
|
Chris@16
|
1068 }
|
Chris@16
|
1069 }
|
Chris@16
|
1070
|
Chris@16
|
1071 template <class InputIterator>
|
Chris@16
|
1072 void append(InputIterator b, InputIterator e)
|
Chris@16
|
1073 {
|
Chris@16
|
1074 // @@@ todo: optimize this depending on iterator type
|
Chris@16
|
1075 for (; b != e; ++b)
|
Chris@16
|
1076 {
|
Chris@16
|
1077 *this += *b;
|
Chris@16
|
1078 }
|
Chris@16
|
1079 }
|
Chris@16
|
1080
|
Chris@16
|
1081 void resize(size_type n, value_type c)
|
Chris@16
|
1082 {
|
Chris@16
|
1083 if (Small())
|
Chris@16
|
1084 {
|
Chris@16
|
1085 if (n > maxSmallString)
|
Chris@16
|
1086 {
|
Chris@16
|
1087 // Small string resized to big string
|
Chris@16
|
1088 SmallStringOpt temp(*this); // can't throw
|
Chris@16
|
1089 // 11-17-2001: correct exception safety bug
|
Chris@16
|
1090 Storage newString(temp.data(), temp.size(),
|
Chris@16
|
1091 temp.get_allocator());
|
Chris@16
|
1092 newString.resize(n, c);
|
Chris@16
|
1093 // We make the reasonable assumption that an empty Storage
|
Chris@16
|
1094 // constructor won't throw
|
Chris@16
|
1095 this->~SmallStringOpt();
|
Chris@16
|
1096 new(&buf_[0]) Storage(temp.get_allocator());
|
Chris@16
|
1097 buf_[maxSmallString] = value_type(magic);
|
Chris@16
|
1098 GetStorage().swap(newString);
|
Chris@16
|
1099 }
|
Chris@16
|
1100 else
|
Chris@16
|
1101 {
|
Chris@16
|
1102 // Small string resized to small string
|
Chris@16
|
1103 // 11-17-2001: bug fix: terminating zero not copied
|
Chris@16
|
1104 size_type toFill = n > size() ? n - size() : 0;
|
Chris@16
|
1105 flex_string_details::pod_fill(end(), end() + toFill, c);
|
Chris@16
|
1106 buf_[maxSmallString] = value_type(maxSmallString - n);
|
Chris@16
|
1107 }
|
Chris@16
|
1108 }
|
Chris@16
|
1109 else
|
Chris@16
|
1110 {
|
Chris@16
|
1111 if (n > maxSmallString)
|
Chris@16
|
1112 {
|
Chris@16
|
1113 // Big string resized to big string
|
Chris@16
|
1114 GetStorage().resize(n, c);
|
Chris@16
|
1115 }
|
Chris@16
|
1116 else
|
Chris@16
|
1117 {
|
Chris@16
|
1118 // Big string resized to small string
|
Chris@16
|
1119 // 11-17=2001: bug fix in the BOOST_ASSERTion below
|
Chris@16
|
1120 BOOST_ASSERT(capacity() > n);
|
Chris@16
|
1121 SmallStringOpt newObj(data(), n, get_allocator());
|
Chris@16
|
1122 newObj.swap(*this);
|
Chris@16
|
1123 }
|
Chris@16
|
1124 }
|
Chris@16
|
1125 }
|
Chris@16
|
1126
|
Chris@16
|
1127 void swap(SmallStringOpt& rhs)
|
Chris@16
|
1128 {
|
Chris@16
|
1129 if (Small())
|
Chris@16
|
1130 {
|
Chris@16
|
1131 if (rhs.Small())
|
Chris@16
|
1132 {
|
Chris@16
|
1133 // Small swapped with small
|
Chris@16
|
1134 std::swap_ranges(buf_, buf_ + maxSmallString + 1,
|
Chris@16
|
1135 rhs.buf_);
|
Chris@16
|
1136 }
|
Chris@16
|
1137 else
|
Chris@16
|
1138 {
|
Chris@16
|
1139 // Small swapped with big
|
Chris@16
|
1140 // Make a copy of myself - can't throw
|
Chris@16
|
1141 SmallStringOpt temp(*this);
|
Chris@16
|
1142 // Nuke myself
|
Chris@16
|
1143 this->~SmallStringOpt();
|
Chris@16
|
1144 // Make an empty storage for myself (likely won't throw)
|
Chris@16
|
1145 new(buf_) Storage(0, value_type(), rhs.get_allocator());
|
Chris@16
|
1146 buf_[maxSmallString] = magic;
|
Chris@16
|
1147 // Recurse to this same function
|
Chris@16
|
1148 swap(rhs);
|
Chris@16
|
1149 // Nuke rhs
|
Chris@16
|
1150 rhs.~SmallStringOpt();
|
Chris@16
|
1151 // Build the new small string into rhs
|
Chris@16
|
1152 new(&rhs) SmallStringOpt(temp);
|
Chris@16
|
1153 }
|
Chris@16
|
1154 }
|
Chris@16
|
1155 else
|
Chris@16
|
1156 {
|
Chris@16
|
1157 if (rhs.Small())
|
Chris@16
|
1158 {
|
Chris@16
|
1159 // Big swapped with small
|
Chris@16
|
1160 // Already implemented, recurse with reversed args
|
Chris@16
|
1161 rhs.swap(*this);
|
Chris@16
|
1162 }
|
Chris@16
|
1163 else
|
Chris@16
|
1164 {
|
Chris@16
|
1165 // Big swapped with big
|
Chris@16
|
1166 GetStorage().swap(rhs.GetStorage());
|
Chris@16
|
1167 }
|
Chris@16
|
1168 }
|
Chris@16
|
1169 }
|
Chris@16
|
1170
|
Chris@16
|
1171 const value_type* c_str() const
|
Chris@16
|
1172 {
|
Chris@16
|
1173 if (!Small()) return GetStorage().c_str();
|
Chris@16
|
1174 buf_[maxSmallString - buf_[maxSmallString]] = value_type();
|
Chris@16
|
1175 return buf_;
|
Chris@16
|
1176 }
|
Chris@16
|
1177
|
Chris@16
|
1178 const value_type* data() const
|
Chris@16
|
1179 { return Small() ? buf_ : GetStorage().data(); }
|
Chris@16
|
1180
|
Chris@16
|
1181 allocator_type get_allocator() const
|
Chris@16
|
1182 { return allocator_type(); }
|
Chris@16
|
1183 };
|
Chris@16
|
1184
|
Chris@16
|
1185 ////////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
1186 // class template CowString
|
Chris@16
|
1187 // Implements Copy on Write over any storage
|
Chris@16
|
1188 ////////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
1189
|
Chris@16
|
1190 template <
|
Chris@16
|
1191 typename Storage,
|
Chris@16
|
1192 typename Align = BOOST_DEDUCED_TYPENAME Storage::value_type*
|
Chris@16
|
1193 >
|
Chris@16
|
1194 class CowString
|
Chris@16
|
1195 {
|
Chris@16
|
1196 typedef typename Storage::value_type E;
|
Chris@16
|
1197 typedef typename flex_string_details::get_unsigned<E>::result RefCountType;
|
Chris@16
|
1198
|
Chris@16
|
1199 public:
|
Chris@16
|
1200 typedef E value_type;
|
Chris@16
|
1201 typedef typename Storage::iterator iterator;
|
Chris@16
|
1202 typedef typename Storage::const_iterator const_iterator;
|
Chris@16
|
1203 typedef typename Storage::allocator_type allocator_type;
|
Chris@16
|
1204 typedef typename allocator_type::size_type size_type;
|
Chris@16
|
1205 typedef typename Storage::reference reference;
|
Chris@16
|
1206
|
Chris@16
|
1207 private:
|
Chris@16
|
1208 union
|
Chris@16
|
1209 {
|
Chris@16
|
1210 mutable char buf_[sizeof(Storage)];
|
Chris@16
|
1211 Align align_;
|
Chris@16
|
1212 };
|
Chris@16
|
1213
|
Chris@16
|
1214 Storage& Data() const
|
Chris@16
|
1215 {
|
Chris@16
|
1216 Storage* p = reinterpret_cast<Storage*>(&buf_[0]);
|
Chris@16
|
1217 return *p;
|
Chris@16
|
1218 }
|
Chris@16
|
1219
|
Chris@16
|
1220 RefCountType GetRefs() const
|
Chris@16
|
1221 {
|
Chris@16
|
1222 const Storage& d = Data();
|
Chris@16
|
1223 BOOST_ASSERT(d.size() > 0);
|
Chris@16
|
1224 BOOST_ASSERT(static_cast<RefCountType>(*d.begin()) != 0);
|
Chris@16
|
1225 return *d.begin();
|
Chris@16
|
1226 }
|
Chris@16
|
1227
|
Chris@16
|
1228 RefCountType& Refs()
|
Chris@16
|
1229 {
|
Chris@16
|
1230 Storage& d = Data();
|
Chris@16
|
1231 BOOST_ASSERT(d.size() > 0);
|
Chris@16
|
1232 return reinterpret_cast<RefCountType&>(*d.begin());
|
Chris@16
|
1233 }
|
Chris@16
|
1234
|
Chris@16
|
1235 void MakeUnique() const
|
Chris@16
|
1236 {
|
Chris@16
|
1237 BOOST_ASSERT(GetRefs() >= 1);
|
Chris@16
|
1238 if (GetRefs() == 1) return;
|
Chris@16
|
1239
|
Chris@16
|
1240 union
|
Chris@16
|
1241 {
|
Chris@16
|
1242 char buf_[sizeof(Storage)];
|
Chris@16
|
1243 Align align_;
|
Chris@16
|
1244 } temp;
|
Chris@16
|
1245
|
Chris@16
|
1246 --(*Data().begin()); // decrement the use count of the remaining object
|
Chris@16
|
1247
|
Chris@16
|
1248 Storage* p = reinterpret_cast<Storage*>(&temp.buf_[0]);
|
Chris@16
|
1249 new(buf_) Storage(
|
Chris@16
|
1250 *new(p) Storage(Data()),
|
Chris@16
|
1251 flex_string_details::Shallow());
|
Chris@16
|
1252 *Data().begin() = 1;
|
Chris@16
|
1253 }
|
Chris@16
|
1254
|
Chris@16
|
1255 public:
|
Chris@16
|
1256 CowString(const CowString& s)
|
Chris@16
|
1257 {
|
Chris@16
|
1258 if (s.GetRefs() == (std::numeric_limits<RefCountType>::max)())
|
Chris@16
|
1259 {
|
Chris@16
|
1260 // must make a brand new copy
|
Chris@16
|
1261 new(buf_) Storage(s.Data()); // non shallow
|
Chris@16
|
1262 Refs() = 1;
|
Chris@16
|
1263 }
|
Chris@16
|
1264 else
|
Chris@16
|
1265 {
|
Chris@16
|
1266 new(buf_) Storage(s.Data(), flex_string_details::Shallow());
|
Chris@16
|
1267 ++Refs();
|
Chris@16
|
1268 }
|
Chris@16
|
1269 BOOST_ASSERT(Data().size() > 0);
|
Chris@16
|
1270 }
|
Chris@16
|
1271
|
Chris@16
|
1272 CowString(const allocator_type& a)
|
Chris@16
|
1273 {
|
Chris@16
|
1274 new(buf_) Storage(1, 1, a);
|
Chris@16
|
1275 }
|
Chris@16
|
1276
|
Chris@16
|
1277 CowString(const E* s, size_type len, const allocator_type& a)
|
Chris@16
|
1278 {
|
Chris@16
|
1279 // Warning - MSVC's debugger has trouble tracing through the code below.
|
Chris@16
|
1280 // It seems to be a const-correctness issue
|
Chris@16
|
1281 //
|
Chris@16
|
1282 new(buf_) Storage(a);
|
Chris@16
|
1283 Data().reserve(len + 1);
|
Chris@16
|
1284 Data().resize(1, 1);
|
Chris@16
|
1285 Data().append(s, s + len);
|
Chris@16
|
1286 }
|
Chris@16
|
1287
|
Chris@16
|
1288 CowString(size_type len, E c, const allocator_type& a)
|
Chris@16
|
1289 {
|
Chris@16
|
1290 new(buf_) Storage(len + 1, c, a);
|
Chris@16
|
1291 Refs() = 1;
|
Chris@16
|
1292 }
|
Chris@16
|
1293
|
Chris@16
|
1294 CowString& operator=(const CowString& rhs)
|
Chris@16
|
1295 {
|
Chris@16
|
1296 // CowString(rhs).swap(*this);
|
Chris@16
|
1297 if (--Refs() == 0)
|
Chris@16
|
1298 Data().~Storage();
|
Chris@16
|
1299 if (rhs.GetRefs() == (std::numeric_limits<RefCountType>::max)())
|
Chris@16
|
1300 {
|
Chris@16
|
1301 // must make a brand new copy
|
Chris@16
|
1302 new(buf_) Storage(rhs.Data()); // non shallow
|
Chris@16
|
1303 Refs() = 1;
|
Chris@16
|
1304 }
|
Chris@16
|
1305 else
|
Chris@16
|
1306 {
|
Chris@16
|
1307 new(buf_) Storage(rhs.Data(), flex_string_details::Shallow());
|
Chris@16
|
1308 ++Refs();
|
Chris@16
|
1309 }
|
Chris@16
|
1310 BOOST_ASSERT(Data().size() > 0);
|
Chris@16
|
1311 return *this;
|
Chris@16
|
1312 }
|
Chris@16
|
1313
|
Chris@16
|
1314 ~CowString()
|
Chris@16
|
1315 {
|
Chris@16
|
1316 BOOST_ASSERT(Data().size() > 0);
|
Chris@16
|
1317 if (--Refs() == 0)
|
Chris@16
|
1318 Data().~Storage();
|
Chris@16
|
1319 }
|
Chris@16
|
1320
|
Chris@16
|
1321 iterator begin()
|
Chris@16
|
1322 {
|
Chris@16
|
1323 BOOST_ASSERT(Data().size() > 0);
|
Chris@16
|
1324 MakeUnique();
|
Chris@16
|
1325 return Data().begin() + 1;
|
Chris@16
|
1326 }
|
Chris@16
|
1327
|
Chris@16
|
1328 const_iterator begin() const
|
Chris@16
|
1329 {
|
Chris@16
|
1330 BOOST_ASSERT(Data().size() > 0);
|
Chris@16
|
1331 return Data().begin() + 1;
|
Chris@16
|
1332 }
|
Chris@16
|
1333
|
Chris@16
|
1334 iterator end()
|
Chris@16
|
1335 {
|
Chris@16
|
1336 MakeUnique();
|
Chris@16
|
1337 return Data().end();
|
Chris@16
|
1338 }
|
Chris@16
|
1339
|
Chris@16
|
1340 const_iterator end() const
|
Chris@16
|
1341 {
|
Chris@16
|
1342 return Data().end();
|
Chris@16
|
1343 }
|
Chris@16
|
1344
|
Chris@16
|
1345 size_type size() const
|
Chris@16
|
1346 {
|
Chris@16
|
1347 BOOST_ASSERT(Data().size() > 0);
|
Chris@16
|
1348 return Data().size() - 1;
|
Chris@16
|
1349 }
|
Chris@16
|
1350
|
Chris@16
|
1351 size_type max_size() const
|
Chris@16
|
1352 {
|
Chris@16
|
1353 BOOST_ASSERT(Data().max_size() > 0);
|
Chris@16
|
1354 return Data().max_size() - 1;
|
Chris@16
|
1355 }
|
Chris@16
|
1356
|
Chris@16
|
1357 size_type capacity() const
|
Chris@16
|
1358 {
|
Chris@16
|
1359 BOOST_ASSERT(Data().capacity() > 0);
|
Chris@16
|
1360 return Data().capacity() - 1;
|
Chris@16
|
1361 }
|
Chris@16
|
1362
|
Chris@16
|
1363 void resize(size_type n, E c)
|
Chris@16
|
1364 {
|
Chris@16
|
1365 BOOST_ASSERT(Data().size() > 0);
|
Chris@16
|
1366 MakeUnique();
|
Chris@16
|
1367 Data().resize(n + 1, c);
|
Chris@16
|
1368 }
|
Chris@16
|
1369
|
Chris@16
|
1370 template <class FwdIterator>
|
Chris@16
|
1371 void append(FwdIterator b, FwdIterator e)
|
Chris@16
|
1372 {
|
Chris@16
|
1373 MakeUnique();
|
Chris@16
|
1374 Data().append(b, e);
|
Chris@16
|
1375 }
|
Chris@16
|
1376
|
Chris@16
|
1377 void reserve(size_type res_arg)
|
Chris@16
|
1378 {
|
Chris@16
|
1379 if (capacity() > res_arg) return;
|
Chris@16
|
1380 MakeUnique();
|
Chris@16
|
1381 Data().reserve(res_arg + 1);
|
Chris@16
|
1382 }
|
Chris@16
|
1383
|
Chris@16
|
1384 void swap(CowString& rhs)
|
Chris@16
|
1385 {
|
Chris@16
|
1386 Data().swap(rhs.Data());
|
Chris@16
|
1387 }
|
Chris@16
|
1388
|
Chris@16
|
1389 const E* c_str() const
|
Chris@16
|
1390 {
|
Chris@16
|
1391 BOOST_ASSERT(Data().size() > 0);
|
Chris@16
|
1392 return Data().c_str() + 1;
|
Chris@16
|
1393 }
|
Chris@16
|
1394
|
Chris@16
|
1395 const E* data() const
|
Chris@16
|
1396 {
|
Chris@16
|
1397 BOOST_ASSERT(Data().size() > 0);
|
Chris@16
|
1398 return Data().data() + 1;
|
Chris@16
|
1399 }
|
Chris@16
|
1400
|
Chris@16
|
1401 allocator_type get_allocator() const
|
Chris@16
|
1402 {
|
Chris@16
|
1403 return Data().get_allocator();
|
Chris@16
|
1404 }
|
Chris@16
|
1405 };
|
Chris@16
|
1406
|
Chris@16
|
1407 ////////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
1408 // class template flex_string
|
Chris@16
|
1409 // a std::basic_string compatible implementation
|
Chris@16
|
1410 // Uses a Storage policy
|
Chris@16
|
1411 ////////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
1412
|
Chris@16
|
1413 template <typename E,
|
Chris@16
|
1414 class T = std::char_traits<E>,
|
Chris@16
|
1415 class A = std::allocator<E>,
|
Chris@16
|
1416 class Storage = AllocatorStringStorage<E, A> >
|
Chris@16
|
1417 class flex_string : private Storage
|
Chris@16
|
1418 {
|
Chris@16
|
1419 #if defined(BOOST_WAVE_FLEXSTRING_THROW_ON_ENFORCE)
|
Chris@16
|
1420 template <typename Exception>
|
Chris@16
|
1421 static void Enforce(bool condition, Exception*, const char* msg)
|
Chris@16
|
1422 { if (!condition) boost::throw_exception(Exception(msg)); }
|
Chris@16
|
1423 #else
|
Chris@16
|
1424 template <typename Exception>
|
Chris@16
|
1425 static inline void Enforce(bool condition, Exception*, const char* msg)
|
Chris@16
|
1426 { BOOST_ASSERT(condition && msg); }
|
Chris@16
|
1427 #endif // defined(BOOST_WAVE_FLEXSTRING_THROW_ON_ENFORCE)
|
Chris@16
|
1428
|
Chris@16
|
1429 #ifndef NDEBUG
|
Chris@16
|
1430 bool Sane() const
|
Chris@16
|
1431 {
|
Chris@16
|
1432 return
|
Chris@16
|
1433 begin() <= end() &&
|
Chris@16
|
1434 empty() == (size() == 0) &&
|
Chris@16
|
1435 empty() == (begin() == end()) &&
|
Chris@16
|
1436 size() <= max_size() &&
|
Chris@16
|
1437 capacity() <= max_size() &&
|
Chris@16
|
1438 size() <= capacity();
|
Chris@16
|
1439 }
|
Chris@16
|
1440
|
Chris@16
|
1441 struct Invariant;
|
Chris@16
|
1442 friend struct Invariant;
|
Chris@16
|
1443 struct Invariant
|
Chris@16
|
1444 {
|
Chris@16
|
1445 Invariant(const flex_string& s) : s_(s)
|
Chris@16
|
1446 {
|
Chris@16
|
1447 BOOST_ASSERT(s_.Sane());
|
Chris@16
|
1448 }
|
Chris@16
|
1449 ~Invariant()
|
Chris@16
|
1450 {
|
Chris@16
|
1451 BOOST_ASSERT(s_.Sane());
|
Chris@16
|
1452 }
|
Chris@16
|
1453 private:
|
Chris@16
|
1454 const flex_string& s_;
|
Chris@16
|
1455 Invariant& operator=(const Invariant&);
|
Chris@16
|
1456 };
|
Chris@16
|
1457 #endif
|
Chris@16
|
1458
|
Chris@16
|
1459 public:
|
Chris@16
|
1460 // types
|
Chris@16
|
1461 typedef T traits_type;
|
Chris@16
|
1462 typedef typename traits_type::char_type value_type;
|
Chris@16
|
1463 typedef A allocator_type;
|
Chris@16
|
1464 typedef typename A::size_type size_type;
|
Chris@16
|
1465 typedef typename A::difference_type difference_type;
|
Chris@16
|
1466
|
Chris@16
|
1467 typedef typename A::reference reference;
|
Chris@16
|
1468 typedef typename A::const_reference const_reference;
|
Chris@16
|
1469 typedef typename A::pointer pointer;
|
Chris@16
|
1470 typedef typename A::const_pointer const_pointer;
|
Chris@16
|
1471
|
Chris@16
|
1472 typedef typename Storage::iterator iterator;
|
Chris@16
|
1473 typedef typename Storage::const_iterator const_iterator;
|
Chris@16
|
1474
|
Chris@16
|
1475 typedef boost::reverse_iterator<iterator> reverse_iterator;
|
Chris@16
|
1476 typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
|
Chris@16
|
1477
|
Chris@16
|
1478 static const size_type npos; // = size_type(-1)
|
Chris@16
|
1479
|
Chris@16
|
1480 private:
|
Chris@16
|
1481 static size_type Min(size_type lhs, size_type rhs)
|
Chris@16
|
1482 { return lhs < rhs ? lhs : rhs; }
|
Chris@16
|
1483 static void Procust(size_type& n, size_type nmax)
|
Chris@16
|
1484 { if (n > nmax) n = nmax; }
|
Chris@16
|
1485
|
Chris@16
|
1486 public:
|
Chris@16
|
1487 // 21.3.1 construct/copy/destroy
|
Chris@16
|
1488 explicit flex_string(const A& a = A())
|
Chris@16
|
1489 : Storage(a)
|
Chris@16
|
1490 {}
|
Chris@16
|
1491
|
Chris@16
|
1492 flex_string(const flex_string& str)
|
Chris@16
|
1493 : Storage(str)
|
Chris@16
|
1494 {
|
Chris@16
|
1495 }
|
Chris@16
|
1496
|
Chris@16
|
1497 flex_string(const flex_string& str, size_type pos,
|
Chris@16
|
1498 size_type n = npos, const A& a = A())
|
Chris@16
|
1499 : Storage(a)
|
Chris@16
|
1500 {
|
Chris@16
|
1501 Enforce(pos <= str.size(), (std::out_of_range*)0, "");
|
Chris@16
|
1502 assign(str, pos, n);
|
Chris@16
|
1503 }
|
Chris@16
|
1504
|
Chris@16
|
1505 flex_string(const value_type* s, const A& a = A())
|
Chris@16
|
1506 : Storage(s, traits_type::length(s), a)
|
Chris@16
|
1507 {}
|
Chris@16
|
1508
|
Chris@16
|
1509 flex_string(const value_type* s, size_type n, const A& a = A())
|
Chris@16
|
1510 : Storage(s, n, a)
|
Chris@16
|
1511 {}
|
Chris@16
|
1512
|
Chris@16
|
1513 flex_string(size_type n, value_type c, const A& a = A())
|
Chris@16
|
1514 : Storage(n, c, a)
|
Chris@16
|
1515 {}
|
Chris@16
|
1516
|
Chris@16
|
1517 template <class InputIterator>
|
Chris@16
|
1518 flex_string(InputIterator begin, InputIterator end, const A& a = A())
|
Chris@16
|
1519 : Storage(a)
|
Chris@16
|
1520 {
|
Chris@16
|
1521 assign(begin, end);
|
Chris@16
|
1522 }
|
Chris@16
|
1523
|
Chris@16
|
1524 ~flex_string()
|
Chris@16
|
1525 {}
|
Chris@16
|
1526
|
Chris@16
|
1527 flex_string& operator=(const flex_string& str)
|
Chris@16
|
1528 {
|
Chris@16
|
1529 if (this != &str) {
|
Chris@16
|
1530 Storage& s = *this;
|
Chris@16
|
1531 s = str;
|
Chris@16
|
1532 }
|
Chris@16
|
1533 return *this;
|
Chris@16
|
1534 }
|
Chris@16
|
1535
|
Chris@16
|
1536 flex_string& operator=(const value_type* s)
|
Chris@16
|
1537 {
|
Chris@16
|
1538 assign(s);
|
Chris@16
|
1539 return *this;
|
Chris@16
|
1540 }
|
Chris@16
|
1541
|
Chris@16
|
1542 flex_string& operator=(value_type c)
|
Chris@16
|
1543 {
|
Chris@16
|
1544 assign(1, c);
|
Chris@16
|
1545 return *this;
|
Chris@16
|
1546 }
|
Chris@16
|
1547
|
Chris@16
|
1548 // 21.3.2 iterators:
|
Chris@16
|
1549 iterator begin()
|
Chris@16
|
1550 { return Storage::begin(); }
|
Chris@16
|
1551
|
Chris@16
|
1552 const_iterator begin() const
|
Chris@16
|
1553 { return Storage::begin(); }
|
Chris@16
|
1554
|
Chris@16
|
1555 iterator end()
|
Chris@16
|
1556 { return Storage::end(); }
|
Chris@16
|
1557
|
Chris@16
|
1558 const_iterator end() const
|
Chris@16
|
1559 { return Storage::end(); }
|
Chris@16
|
1560
|
Chris@16
|
1561 reverse_iterator rbegin()
|
Chris@16
|
1562 { return reverse_iterator(end()); }
|
Chris@16
|
1563
|
Chris@16
|
1564 const_reverse_iterator rbegin() const
|
Chris@16
|
1565 { return const_reverse_iterator(end()); }
|
Chris@16
|
1566
|
Chris@16
|
1567 reverse_iterator rend()
|
Chris@16
|
1568 { return reverse_iterator(begin()); }
|
Chris@16
|
1569
|
Chris@16
|
1570 const_reverse_iterator rend() const
|
Chris@16
|
1571 { return const_reverse_iterator(begin()); }
|
Chris@16
|
1572
|
Chris@16
|
1573 #if BOOST_WAVE_FLEX_STRING_SERIALIZATION_HACK != 0
|
Chris@16
|
1574 // temporary hack to make it easier to serialize flex_string's using
|
Chris@16
|
1575 // the Boost.Serialization library
|
Chris@16
|
1576 value_type & back() { return *(begin()+size()-1); }
|
Chris@16
|
1577 value_type const& back() const { return *(begin()+size()-1); }
|
Chris@16
|
1578 #endif
|
Chris@16
|
1579
|
Chris@16
|
1580 // 21.3.3 capacity:
|
Chris@16
|
1581 size_type size() const
|
Chris@16
|
1582 { return Storage::size(); }
|
Chris@16
|
1583
|
Chris@16
|
1584 size_type length() const
|
Chris@16
|
1585 { return size(); }
|
Chris@16
|
1586
|
Chris@16
|
1587 size_type max_size() const
|
Chris@16
|
1588 { return Storage::max_size(); }
|
Chris@16
|
1589
|
Chris@16
|
1590 void resize(size_type n, value_type c)
|
Chris@16
|
1591 { Storage::resize(n, c); }
|
Chris@16
|
1592
|
Chris@16
|
1593 void resize(size_type n)
|
Chris@16
|
1594 { resize(n, value_type()); }
|
Chris@16
|
1595
|
Chris@16
|
1596 size_type capacity() const
|
Chris@16
|
1597 { return Storage::capacity(); }
|
Chris@16
|
1598
|
Chris@16
|
1599 void reserve(size_type res_arg = 0)
|
Chris@16
|
1600 {
|
Chris@16
|
1601 Enforce(res_arg <= max_size(), (std::length_error*)0, "");
|
Chris@16
|
1602 Storage::reserve(res_arg);
|
Chris@16
|
1603 }
|
Chris@16
|
1604
|
Chris@16
|
1605 void clear()
|
Chris@16
|
1606 { resize(0); }
|
Chris@16
|
1607
|
Chris@16
|
1608 bool empty() const
|
Chris@16
|
1609 { return size() == 0; }
|
Chris@16
|
1610
|
Chris@16
|
1611 // 21.3.4 element access:
|
Chris@16
|
1612 const_reference operator[](size_type pos) const
|
Chris@16
|
1613 { return *(begin() + pos); }
|
Chris@16
|
1614
|
Chris@16
|
1615 reference operator[](size_type pos)
|
Chris@16
|
1616 { return *(begin() + pos); }
|
Chris@16
|
1617
|
Chris@16
|
1618 const_reference at(size_type n) const
|
Chris@16
|
1619 {
|
Chris@16
|
1620 Enforce(n < size(), (std::out_of_range*)0, "");
|
Chris@16
|
1621 return (*this)[n];
|
Chris@16
|
1622 }
|
Chris@16
|
1623
|
Chris@16
|
1624 reference at(size_type n)
|
Chris@16
|
1625 {
|
Chris@16
|
1626 Enforce(n < size(), (std::out_of_range*)0, "");
|
Chris@16
|
1627 return (*this)[n];
|
Chris@16
|
1628 }
|
Chris@16
|
1629
|
Chris@16
|
1630 // 21.3.5 modifiers:
|
Chris@16
|
1631 flex_string& operator+=(const flex_string& str)
|
Chris@16
|
1632 { return append(str); }
|
Chris@16
|
1633
|
Chris@16
|
1634 flex_string& operator+=(const value_type* s)
|
Chris@16
|
1635 { return append(s); }
|
Chris@16
|
1636
|
Chris@16
|
1637 flex_string& operator+=(value_type c)
|
Chris@16
|
1638 {
|
Chris@16
|
1639 push_back(c);
|
Chris@16
|
1640 return *this;
|
Chris@16
|
1641 }
|
Chris@16
|
1642
|
Chris@16
|
1643 flex_string& append(const flex_string& str)
|
Chris@16
|
1644 { return append(str, 0, npos); }
|
Chris@16
|
1645
|
Chris@16
|
1646 flex_string& append(const flex_string& str, const size_type pos,
|
Chris@16
|
1647 size_type n)
|
Chris@16
|
1648 {
|
Chris@16
|
1649 const size_type sz = str.size();
|
Chris@16
|
1650 Enforce(pos <= sz, (std::out_of_range*)0, "");
|
Chris@16
|
1651 Procust(n, sz - pos);
|
Chris@16
|
1652 return append(str.c_str() + pos, n);
|
Chris@16
|
1653 }
|
Chris@16
|
1654
|
Chris@16
|
1655 flex_string& append(const value_type* s, const size_type n)
|
Chris@16
|
1656 {
|
Chris@16
|
1657 #ifndef NDEBUG
|
Chris@16
|
1658 Invariant checker(*this);
|
Chris@16
|
1659 #endif
|
Chris@16
|
1660 if (IsAliasedRange(s, s + n))
|
Chris@16
|
1661 {
|
Chris@16
|
1662 const size_type offset = s - &*begin();
|
Chris@16
|
1663 Storage::reserve(size() + n);
|
Chris@16
|
1664 s = &*begin() + offset;
|
Chris@16
|
1665 }
|
Chris@16
|
1666 Storage::append(s, s+ n);
|
Chris@16
|
1667 return *this;
|
Chris@16
|
1668 }
|
Chris@16
|
1669
|
Chris@16
|
1670 flex_string& append(const value_type* s)
|
Chris@16
|
1671 { return append(s, traits_type::length(s)); }
|
Chris@16
|
1672
|
Chris@16
|
1673 flex_string& append(size_type n, value_type c)
|
Chris@16
|
1674 {
|
Chris@16
|
1675 resize(size() + n, c);
|
Chris@16
|
1676 return *this;
|
Chris@16
|
1677 }
|
Chris@16
|
1678
|
Chris@16
|
1679 template<class InputIterator>
|
Chris@16
|
1680 flex_string& append(InputIterator first, InputIterator last)
|
Chris@16
|
1681 {
|
Chris@16
|
1682 insert(end(), first, last);
|
Chris@16
|
1683 return *this;
|
Chris@16
|
1684 }
|
Chris@16
|
1685
|
Chris@16
|
1686 void push_back(value_type c)
|
Chris@16
|
1687 {
|
Chris@16
|
1688 const size_type cap = capacity();
|
Chris@16
|
1689 if (size() == cap)
|
Chris@16
|
1690 {
|
Chris@16
|
1691 reserve(cap << 1u);
|
Chris@16
|
1692 }
|
Chris@16
|
1693 Storage::append(&c, &c + 1);
|
Chris@16
|
1694 }
|
Chris@16
|
1695
|
Chris@16
|
1696 flex_string& assign(const flex_string& str)
|
Chris@16
|
1697 {
|
Chris@16
|
1698 if (&str == this) return *this;
|
Chris@16
|
1699 return assign(str.data(), str.size());
|
Chris@16
|
1700 }
|
Chris@16
|
1701
|
Chris@16
|
1702 flex_string& assign(const flex_string& str, size_type pos,
|
Chris@16
|
1703 size_type n)
|
Chris@16
|
1704 {
|
Chris@16
|
1705 const size_type sz = str.size();
|
Chris@16
|
1706 Enforce(pos <= str.size(), (std::out_of_range*)0, "");
|
Chris@16
|
1707 Procust(n, sz - pos);
|
Chris@16
|
1708 return assign(str.data() + pos, n);
|
Chris@16
|
1709 }
|
Chris@16
|
1710
|
Chris@16
|
1711 flex_string& assign(const value_type* s, size_type n)
|
Chris@16
|
1712 {
|
Chris@16
|
1713 #ifndef NDEBUG
|
Chris@16
|
1714 Invariant checker(*this);
|
Chris@16
|
1715 #endif
|
Chris@16
|
1716 if (size() >= n)
|
Chris@16
|
1717 {
|
Chris@16
|
1718 std::copy(s, s + n, begin());
|
Chris@16
|
1719 resize(n);
|
Chris@16
|
1720 }
|
Chris@16
|
1721 else
|
Chris@16
|
1722 {
|
Chris@16
|
1723 const value_type *const s2 = s + size();
|
Chris@16
|
1724 std::copy(s, s2, begin());
|
Chris@16
|
1725 append(s2, n - size());
|
Chris@16
|
1726 }
|
Chris@16
|
1727 return *this;
|
Chris@16
|
1728 }
|
Chris@16
|
1729
|
Chris@16
|
1730 flex_string& assign(const value_type* s)
|
Chris@16
|
1731 { return assign(s, traits_type::length(s)); }
|
Chris@16
|
1732
|
Chris@16
|
1733 template <class ItOrLength, class ItOrChar>
|
Chris@16
|
1734 flex_string& assign(ItOrLength first_or_n, ItOrChar last_or_c)
|
Chris@16
|
1735 { return replace(begin(), end(), first_or_n, last_or_c); }
|
Chris@16
|
1736
|
Chris@16
|
1737 flex_string& insert(size_type pos1, const flex_string& str)
|
Chris@16
|
1738 { return insert(pos1, str.data(), str.size()); }
|
Chris@16
|
1739
|
Chris@16
|
1740 flex_string& insert(size_type pos1, const flex_string& str,
|
Chris@16
|
1741 size_type pos2, size_type n)
|
Chris@16
|
1742 {
|
Chris@16
|
1743 Enforce(pos2 <= str.length(), (std::out_of_range*)0, "");
|
Chris@16
|
1744 Procust(n, str.length() - pos2);
|
Chris@16
|
1745 return insert(pos1, str.data() + pos2, n);
|
Chris@16
|
1746 }
|
Chris@16
|
1747
|
Chris@16
|
1748 flex_string& insert(size_type pos, const value_type* s, size_type n)
|
Chris@16
|
1749 {
|
Chris@16
|
1750 Enforce(pos <= length(), (std::out_of_range*)0, "");
|
Chris@16
|
1751 insert(begin() + pos, s, s + n);
|
Chris@16
|
1752 return *this;
|
Chris@16
|
1753 }
|
Chris@16
|
1754
|
Chris@16
|
1755 flex_string& insert(size_type pos, const value_type* s)
|
Chris@16
|
1756 { return insert(pos, s, traits_type::length(s)); }
|
Chris@16
|
1757
|
Chris@16
|
1758 flex_string& insert(size_type pos, size_type n, value_type c)
|
Chris@16
|
1759 {
|
Chris@16
|
1760 Enforce(pos <= length(), (std::out_of_range*)0, "");
|
Chris@16
|
1761 insert(begin() + pos, n, c);
|
Chris@16
|
1762 return *this;
|
Chris@16
|
1763 }
|
Chris@16
|
1764
|
Chris@16
|
1765 iterator insert(iterator p, value_type c = value_type())
|
Chris@16
|
1766 {
|
Chris@16
|
1767 const size_type pos = p - begin();
|
Chris@16
|
1768 insert(pos, &c, 1);
|
Chris@16
|
1769 return begin() + pos;
|
Chris@16
|
1770 }
|
Chris@16
|
1771
|
Chris@16
|
1772 private:
|
Chris@16
|
1773 // Care must be taken when dereferencing some iterator types.
|
Chris@16
|
1774 //
|
Chris@16
|
1775 // Users can implement this function in their namespace if their storage
|
Chris@16
|
1776 // uses a special iterator type, the function will be found through ADL.
|
Chris@16
|
1777 template<class Iterator>
|
Chris@16
|
1778 const typename std::iterator_traits<Iterator>::value_type*
|
Chris@16
|
1779 DereferenceValidIterator(Iterator it) const
|
Chris@16
|
1780 {
|
Chris@16
|
1781 return &*it;
|
Chris@16
|
1782 }
|
Chris@16
|
1783
|
Chris@16
|
1784 // Care must be taken when dereferencing a reverse iterators, hence this
|
Chris@16
|
1785 // special case. This isn't in the std namespace so as not to pollute it or
|
Chris@16
|
1786 // create name clashes.
|
Chris@16
|
1787 template<typename Iterator>
|
Chris@16
|
1788 const typename std::iterator_traits<Iterator>::value_type*
|
Chris@16
|
1789 DereferenceValidIterator(std::reverse_iterator<Iterator> it) const
|
Chris@16
|
1790 {
|
Chris@16
|
1791 return &*--it;
|
Chris@16
|
1792 }
|
Chris@16
|
1793
|
Chris@16
|
1794 // Determine if the range aliases the current string.
|
Chris@16
|
1795 //
|
Chris@16
|
1796 // This method cannot be const because calling begin/end on copy-on-write
|
Chris@16
|
1797 // implementations must have side effects.
|
Chris@16
|
1798 // A const version wouldn't make the string unique through this call.
|
Chris@16
|
1799 template<class Iterator>
|
Chris@16
|
1800 bool IsAliasedRange(Iterator beginIterator, Iterator endIterator)
|
Chris@16
|
1801 {
|
Chris@16
|
1802 if(!empty() && beginIterator != endIterator)
|
Chris@16
|
1803 {
|
Chris@16
|
1804 typedef const typename std::iterator_traits<Iterator>::value_type *
|
Chris@16
|
1805 pointer;
|
Chris@16
|
1806
|
Chris@16
|
1807 pointer myBegin(&*begin());
|
Chris@16
|
1808 pointer myEnd(&*begin() + size());
|
Chris@16
|
1809 pointer rangeBegin(DereferenceValidIterator(beginIterator));
|
Chris@16
|
1810
|
Chris@16
|
1811 const std::less_equal<pointer> less_equal = std::less_equal<pointer>();
|
Chris@16
|
1812 if(less_equal(myBegin, rangeBegin) && less_equal(rangeBegin, myEnd))
|
Chris@16
|
1813 return true;
|
Chris@16
|
1814 }
|
Chris@16
|
1815 return false;
|
Chris@16
|
1816 }
|
Chris@16
|
1817
|
Chris@16
|
1818 template <int i> class Selector {};
|
Chris@16
|
1819
|
Chris@16
|
1820 flex_string& InsertImplDiscr(iterator p,
|
Chris@16
|
1821 size_type n, value_type c, Selector<1>)
|
Chris@16
|
1822 {
|
Chris@16
|
1823 #ifndef NDEBUG
|
Chris@16
|
1824 Invariant checker(*this);
|
Chris@16
|
1825 #endif
|
Chris@16
|
1826 BOOST_ASSERT(begin() <= p && p <= end());
|
Chris@16
|
1827 const size_type insertOffset(p - begin());
|
Chris@16
|
1828 const size_type originalSize(size());
|
Chris@16
|
1829 if(n < originalSize - insertOffset)
|
Chris@16
|
1830 {
|
Chris@16
|
1831 // The new characters fit within the original string.
|
Chris@16
|
1832 // The characters that are pushed back need to be moved because
|
Chris@16
|
1833 // they're aliased.
|
Chris@16
|
1834 // The appended characters will all be overwritten by the move.
|
Chris@16
|
1835 append(n, value_type(0));
|
Chris@16
|
1836 value_type* begin(&*begin());
|
Chris@16
|
1837 flex_string_details::pod_move(begin + insertOffset,
|
Chris@16
|
1838 begin + originalSize, begin + insertOffset + n);
|
Chris@16
|
1839 std::fill(begin + insertOffset, begin + insertOffset + n, c);
|
Chris@16
|
1840 }
|
Chris@16
|
1841 else
|
Chris@16
|
1842 {
|
Chris@16
|
1843 // The new characters exceed the original string.
|
Chris@16
|
1844 // The characters that are pushed back can simply be copied since
|
Chris@16
|
1845 // they aren't aliased.
|
Chris@16
|
1846 // The appended characters will partly be overwritten by the copy.
|
Chris@16
|
1847 append(n, c);
|
Chris@16
|
1848 value_type* begin(&*begin());
|
Chris@16
|
1849 flex_string_details::pod_copy(begin + insertOffset,
|
Chris@16
|
1850 begin + originalSize, begin + insertOffset + n);
|
Chris@16
|
1851 std::fill(begin + insertOffset, begin + originalSize, c);
|
Chris@16
|
1852 }
|
Chris@16
|
1853 return *this;
|
Chris@16
|
1854 }
|
Chris@16
|
1855
|
Chris@16
|
1856 template<class InputIterator>
|
Chris@16
|
1857 flex_string& InsertImplDiscr(iterator i,
|
Chris@16
|
1858 InputIterator b, InputIterator e, Selector<0>)
|
Chris@16
|
1859 {
|
Chris@16
|
1860 InsertImpl(i, b, e,
|
Chris@16
|
1861 typename std::iterator_traits<InputIterator>::iterator_category());
|
Chris@16
|
1862 return *this;
|
Chris@16
|
1863 }
|
Chris@16
|
1864
|
Chris@16
|
1865 template <class FwdIterator>
|
Chris@16
|
1866 void InsertImpl(iterator i,
|
Chris@16
|
1867 FwdIterator s1, FwdIterator s2, std::forward_iterator_tag)
|
Chris@16
|
1868 {
|
Chris@16
|
1869 if(s1 == s2)
|
Chris@16
|
1870 {
|
Chris@16
|
1871 // Insert an empty range.
|
Chris@16
|
1872 return;
|
Chris@16
|
1873 }
|
Chris@16
|
1874
|
Chris@16
|
1875 if(IsAliasedRange(s1, s2))
|
Chris@16
|
1876 {
|
Chris@16
|
1877 // The source range is contained in the current string, copy it
|
Chris@16
|
1878 // and recurse.
|
Chris@16
|
1879 const flex_string temporary(s1, s2);
|
Chris@16
|
1880 InsertImpl(i, temporary.begin(), temporary.end(),
|
Chris@16
|
1881 typename std::iterator_traits<FwdIterator>::iterator_category());
|
Chris@16
|
1882 return;
|
Chris@16
|
1883 }
|
Chris@16
|
1884
|
Chris@16
|
1885 #ifndef NDEBUG
|
Chris@16
|
1886 Invariant checker(*this);
|
Chris@16
|
1887 #endif
|
Chris@16
|
1888 const size_type pos = i - begin();
|
Chris@16
|
1889 const typename std::iterator_traits<FwdIterator>::difference_type n2 =
|
Chris@16
|
1890 std::distance(s1, s2);
|
Chris@16
|
1891
|
Chris@16
|
1892 BOOST_ASSERT(n2 >= 0);
|
Chris@16
|
1893 using namespace flex_string_details;
|
Chris@16
|
1894 BOOST_ASSERT(pos <= size());
|
Chris@16
|
1895
|
Chris@16
|
1896 const typename std::iterator_traits<FwdIterator>::difference_type maxn2 =
|
Chris@16
|
1897 capacity() - size();
|
Chris@16
|
1898 if (maxn2 < n2)
|
Chris@16
|
1899 {
|
Chris@16
|
1900 // Reallocate the string.
|
Chris@16
|
1901 BOOST_ASSERT(!IsAliasedRange(s1, s2));
|
Chris@16
|
1902 reserve(size() + n2);
|
Chris@16
|
1903 i = begin() + pos;
|
Chris@16
|
1904 }
|
Chris@16
|
1905 if (pos + n2 <= size())
|
Chris@16
|
1906 {
|
Chris@16
|
1907 const iterator tailBegin = end() - n2;
|
Chris@16
|
1908 Storage::append(tailBegin, tailBegin + n2);
|
Chris@16
|
1909 std::copy(reverse_iterator(tailBegin), reverse_iterator(i),
|
Chris@16
|
1910 reverse_iterator(tailBegin + n2));
|
Chris@16
|
1911 std::copy(s1, s2, i);
|
Chris@16
|
1912 }
|
Chris@16
|
1913 else
|
Chris@16
|
1914 {
|
Chris@16
|
1915 FwdIterator t = s1;
|
Chris@16
|
1916 const size_type old_size = size();
|
Chris@16
|
1917 std::advance(t, old_size - pos);
|
Chris@16
|
1918 BOOST_ASSERT(std::distance(t, s2) >= 0);
|
Chris@16
|
1919 Storage::append(t, s2);
|
Chris@16
|
1920 Storage::append(data() + pos, data() + old_size);
|
Chris@16
|
1921 std::copy(s1, t, i);
|
Chris@16
|
1922 }
|
Chris@16
|
1923 }
|
Chris@16
|
1924
|
Chris@16
|
1925 template <class InputIterator>
|
Chris@16
|
1926 void InsertImpl(iterator insertPosition,
|
Chris@16
|
1927 InputIterator inputBegin, InputIterator inputEnd,
|
Chris@16
|
1928 std::input_iterator_tag)
|
Chris@16
|
1929 {
|
Chris@16
|
1930 flex_string temporary(begin(), insertPosition);
|
Chris@16
|
1931 for (; inputBegin != inputEnd; ++inputBegin)
|
Chris@16
|
1932 {
|
Chris@16
|
1933 temporary.push_back(*inputBegin);
|
Chris@16
|
1934 }
|
Chris@16
|
1935 temporary.append(insertPosition, end());
|
Chris@16
|
1936 swap(temporary);
|
Chris@16
|
1937 }
|
Chris@16
|
1938
|
Chris@16
|
1939 public:
|
Chris@16
|
1940 template <class ItOrLength, class ItOrChar>
|
Chris@16
|
1941 void insert(iterator p, ItOrLength first_or_n, ItOrChar last_or_c)
|
Chris@16
|
1942 {
|
Chris@16
|
1943 Selector<std::numeric_limits<ItOrLength>::is_specialized> sel;
|
Chris@16
|
1944 InsertImplDiscr(p, first_or_n, last_or_c, sel);
|
Chris@16
|
1945 }
|
Chris@16
|
1946
|
Chris@16
|
1947 flex_string& erase(size_type pos = 0, size_type n = npos)
|
Chris@16
|
1948 {
|
Chris@16
|
1949 #ifndef NDEBUG
|
Chris@16
|
1950 Invariant checker(*this);
|
Chris@16
|
1951 #endif
|
Chris@16
|
1952 Enforce(pos <= length(), (std::out_of_range*)0, "");
|
Chris@16
|
1953 Procust(n, length() - pos);
|
Chris@16
|
1954 std::copy(begin() + pos + n, end(), begin() + pos);
|
Chris@16
|
1955 resize(length() - n);
|
Chris@16
|
1956 return *this;
|
Chris@16
|
1957 }
|
Chris@16
|
1958
|
Chris@16
|
1959 iterator erase(iterator position)
|
Chris@16
|
1960 {
|
Chris@16
|
1961 const size_type pos(position - begin());
|
Chris@16
|
1962 erase(pos, 1);
|
Chris@16
|
1963 return begin() + pos;
|
Chris@16
|
1964 }
|
Chris@16
|
1965
|
Chris@16
|
1966 iterator erase(iterator first, iterator last)
|
Chris@16
|
1967 {
|
Chris@16
|
1968 const size_type pos(first - begin());
|
Chris@16
|
1969 erase(pos, last - first);
|
Chris@16
|
1970 return begin() + pos;
|
Chris@16
|
1971 }
|
Chris@16
|
1972
|
Chris@16
|
1973 // Replaces at most n1 chars of *this, starting with pos1 with the content of str
|
Chris@16
|
1974 flex_string& replace(size_type pos1, size_type n1, const flex_string& str)
|
Chris@16
|
1975 { return replace(pos1, n1, str, 0, npos); }
|
Chris@16
|
1976
|
Chris@16
|
1977 // Replaces at most n1 chars of *this, starting with pos1,
|
Chris@16
|
1978 // with at most n2 chars of str starting with pos2
|
Chris@16
|
1979 flex_string& replace(size_type pos1, size_type n1, const flex_string& str,
|
Chris@16
|
1980 size_type pos2, size_type n2)
|
Chris@16
|
1981 {
|
Chris@16
|
1982 Enforce(pos2 <= str.length(), (std::out_of_range*)0, "");
|
Chris@16
|
1983 return replace(pos1, n1, str.data() + pos2,
|
Chris@16
|
1984 Min(n2, str.size() - pos2));
|
Chris@16
|
1985 }
|
Chris@16
|
1986
|
Chris@16
|
1987 // Replaces at most n1 chars of *this, starting with pos, with chars from s
|
Chris@16
|
1988 flex_string& replace(size_type pos, size_type n1, const value_type* s)
|
Chris@16
|
1989 { return replace(pos, n1, s, traits_type::length(s)); }
|
Chris@16
|
1990
|
Chris@16
|
1991 // Replaces at most n1 chars of *this, starting with pos, with n2 occurences of c
|
Chris@16
|
1992 // consolidated with
|
Chris@16
|
1993 // Replaces at most n1 chars of *this, starting with pos,
|
Chris@16
|
1994 // with at most n2 chars of str.
|
Chris@16
|
1995 // str must have at least n2 chars.
|
Chris@16
|
1996 template <class StrOrLength, class NumOrChar>
|
Chris@16
|
1997 flex_string& replace(size_type pos, size_type n1,
|
Chris@16
|
1998 StrOrLength s_or_n2, NumOrChar n_or_c)
|
Chris@16
|
1999 {
|
Chris@16
|
2000 #ifndef NDEBUG
|
Chris@16
|
2001 Invariant checker(*this);
|
Chris@16
|
2002 #endif
|
Chris@16
|
2003 Enforce(pos <= size(), (std::out_of_range*)0, "");
|
Chris@16
|
2004 Procust(n1, length() - pos);
|
Chris@16
|
2005 const iterator b = begin() + pos;
|
Chris@16
|
2006 return replace(b, b + n1, s_or_n2, n_or_c);
|
Chris@16
|
2007 }
|
Chris@16
|
2008
|
Chris@16
|
2009 flex_string& replace(iterator i1, iterator i2, const flex_string& str)
|
Chris@16
|
2010 { return replace(i1, i2, str.c_str(), str.length()); }
|
Chris@16
|
2011
|
Chris@16
|
2012 flex_string& replace(iterator i1, iterator i2, const value_type* s)
|
Chris@16
|
2013 { return replace(i1, i2, s, traits_type::length(s)); }
|
Chris@16
|
2014
|
Chris@16
|
2015 private:
|
Chris@16
|
2016 flex_string& ReplaceImplDiscr(iterator i1, iterator i2,
|
Chris@16
|
2017 const value_type* s, size_type n, Selector<2>)
|
Chris@16
|
2018 {
|
Chris@16
|
2019 BOOST_ASSERT(i1 <= i2);
|
Chris@16
|
2020 BOOST_ASSERT(begin() <= i1 && i1 <= end());
|
Chris@16
|
2021 BOOST_ASSERT(begin() <= i2 && i2 <= end());
|
Chris@16
|
2022 return replace(i1, i2, s, s + n);
|
Chris@16
|
2023 }
|
Chris@16
|
2024
|
Chris@16
|
2025 flex_string& ReplaceImplDiscr(iterator i1, iterator i2,
|
Chris@16
|
2026 size_type n2, value_type c, Selector<1>)
|
Chris@16
|
2027 {
|
Chris@16
|
2028 const size_type n1 = i2 - i1;
|
Chris@16
|
2029 if (n1 > n2)
|
Chris@16
|
2030 {
|
Chris@16
|
2031 std::fill(i1, i1 + n2, c);
|
Chris@16
|
2032 erase(i1 + n2, i2);
|
Chris@16
|
2033 }
|
Chris@16
|
2034 else
|
Chris@16
|
2035 {
|
Chris@16
|
2036 std::fill(i1, i2, c);
|
Chris@16
|
2037 insert(i2, n2 - n1, c);
|
Chris@16
|
2038 }
|
Chris@16
|
2039 return *this;
|
Chris@16
|
2040 }
|
Chris@16
|
2041
|
Chris@16
|
2042 template <class InputIterator>
|
Chris@16
|
2043 flex_string& ReplaceImplDiscr(iterator i1, iterator i2,
|
Chris@16
|
2044 InputIterator b, InputIterator e, Selector<0>)
|
Chris@16
|
2045 {
|
Chris@16
|
2046 ReplaceImpl(i1, i2, b, e,
|
Chris@16
|
2047 typename std::iterator_traits<InputIterator>::iterator_category());
|
Chris@16
|
2048 return *this;
|
Chris@16
|
2049 }
|
Chris@16
|
2050
|
Chris@16
|
2051 template <class FwdIterator>
|
Chris@16
|
2052 void ReplaceImpl(iterator i1, iterator i2,
|
Chris@16
|
2053 FwdIterator s1, FwdIterator s2, std::forward_iterator_tag)
|
Chris@16
|
2054 {
|
Chris@16
|
2055 #ifndef NDEBUG
|
Chris@16
|
2056 Invariant checker(*this);
|
Chris@16
|
2057 #endif
|
Chris@16
|
2058 const typename std::iterator_traits<iterator>::difference_type n1 =
|
Chris@16
|
2059 i2 - i1;
|
Chris@16
|
2060 BOOST_ASSERT(n1 >= 0);
|
Chris@16
|
2061 const typename std::iterator_traits<FwdIterator>::difference_type n2 =
|
Chris@16
|
2062 std::distance(s1, s2);
|
Chris@16
|
2063 BOOST_ASSERT(n2 >= 0);
|
Chris@16
|
2064
|
Chris@16
|
2065 if (IsAliasedRange(s1, s2))
|
Chris@16
|
2066 {
|
Chris@16
|
2067 // Aliased replace, copy to new string.
|
Chris@16
|
2068 flex_string temporary;
|
Chris@16
|
2069 temporary.reserve(size() - n1 + n2);
|
Chris@16
|
2070 temporary.append(begin(), i1).append(s1, s2).append(i2, end());
|
Chris@16
|
2071 swap(temporary);
|
Chris@16
|
2072 return;
|
Chris@16
|
2073 }
|
Chris@16
|
2074
|
Chris@16
|
2075 if (n1 > n2)
|
Chris@16
|
2076 {
|
Chris@16
|
2077 // Shrinks
|
Chris@16
|
2078 std::copy(s1, s2, i1);
|
Chris@16
|
2079 erase(i1 + n2, i2);
|
Chris@16
|
2080 }
|
Chris@16
|
2081 else
|
Chris@16
|
2082 {
|
Chris@16
|
2083 // Grows
|
Chris@16
|
2084 flex_string_details::copy_n(s1, n1, i1);
|
Chris@16
|
2085 std::advance(s1, n1);
|
Chris@16
|
2086 insert(i2, s1, s2);
|
Chris@16
|
2087 }
|
Chris@16
|
2088 }
|
Chris@16
|
2089
|
Chris@16
|
2090 template <class InputIterator>
|
Chris@16
|
2091 void ReplaceImpl(iterator i1, iterator i2,
|
Chris@16
|
2092 InputIterator b, InputIterator e, std::input_iterator_tag)
|
Chris@16
|
2093 {
|
Chris@16
|
2094 flex_string temp(begin(), i1);
|
Chris@16
|
2095 temp.append(b, e).append(i2, end());
|
Chris@16
|
2096 swap(temp);
|
Chris@16
|
2097 }
|
Chris@16
|
2098
|
Chris@16
|
2099 public:
|
Chris@16
|
2100 template <class T1, class T2>
|
Chris@16
|
2101 flex_string& replace(iterator i1, iterator i2,
|
Chris@16
|
2102 T1 first_or_n_or_s, T2 last_or_c_or_n)
|
Chris@16
|
2103 {
|
Chris@16
|
2104 const bool
|
Chris@16
|
2105 num1 = std::numeric_limits<T1>::is_specialized,
|
Chris@16
|
2106 num2 = std::numeric_limits<T2>::is_specialized;
|
Chris@16
|
2107 return ReplaceImplDiscr(i1, i2, first_or_n_or_s, last_or_c_or_n,
|
Chris@16
|
2108 Selector<num1 ? (num2 ? 1 : -1) : (num2 ? 2 : 0)>());
|
Chris@16
|
2109 }
|
Chris@16
|
2110
|
Chris@16
|
2111 size_type copy(value_type* s, size_type n, size_type pos = 0) const
|
Chris@16
|
2112 {
|
Chris@16
|
2113 Enforce(pos <= size(), (std::out_of_range*)0, "");
|
Chris@16
|
2114 n = Min(n, size() - pos);
|
Chris@16
|
2115
|
Chris@16
|
2116 flex_string_details::pod_copy(
|
Chris@16
|
2117 &*begin() + pos,
|
Chris@16
|
2118 &*begin() + pos + n,
|
Chris@16
|
2119 s);
|
Chris@16
|
2120 return n;
|
Chris@16
|
2121 }
|
Chris@16
|
2122
|
Chris@16
|
2123 void swap(flex_string& rhs)
|
Chris@16
|
2124 {
|
Chris@16
|
2125 Storage& srhs = rhs;
|
Chris@16
|
2126 this->Storage::swap(srhs);
|
Chris@16
|
2127 }
|
Chris@16
|
2128
|
Chris@16
|
2129 // 21.3.6 string operations:
|
Chris@16
|
2130 const value_type* c_str() const
|
Chris@16
|
2131 { return Storage::c_str(); }
|
Chris@16
|
2132
|
Chris@16
|
2133 const value_type* data() const
|
Chris@16
|
2134 { return Storage::data(); }
|
Chris@16
|
2135
|
Chris@16
|
2136 allocator_type get_allocator() const
|
Chris@16
|
2137 { return Storage::get_allocator(); }
|
Chris@16
|
2138
|
Chris@16
|
2139 size_type find(const flex_string& str, size_type pos = 0) const
|
Chris@16
|
2140 { return find(str.data(), pos, str.length()); }
|
Chris@16
|
2141
|
Chris@16
|
2142 size_type find (const value_type* s, size_type pos, size_type n) const
|
Chris@16
|
2143 {
|
Chris@16
|
2144 const size_type size_(size());
|
Chris@16
|
2145 if (n + pos > size_)
|
Chris@16
|
2146 return npos;
|
Chris@16
|
2147 for (; pos < size_; ++pos)
|
Chris@16
|
2148 {
|
Chris@16
|
2149 if (traits_type::compare(&*begin() + pos, s, n) == 0)
|
Chris@16
|
2150 {
|
Chris@16
|
2151 return pos;
|
Chris@16
|
2152 }
|
Chris@16
|
2153 }
|
Chris@16
|
2154 return npos;
|
Chris@16
|
2155 }
|
Chris@16
|
2156
|
Chris@16
|
2157 size_type find (const value_type* s, size_type pos = 0) const
|
Chris@16
|
2158 { return find(s, pos, traits_type::length(s)); }
|
Chris@16
|
2159
|
Chris@16
|
2160 size_type find (value_type c, size_type pos = 0) const
|
Chris@16
|
2161 { return find(&c, pos, 1); }
|
Chris@16
|
2162
|
Chris@16
|
2163 size_type rfind(const flex_string& str, size_type pos = npos) const
|
Chris@16
|
2164 { return rfind(str.c_str(), pos, str.length()); }
|
Chris@16
|
2165
|
Chris@16
|
2166 size_type rfind(const value_type* s, size_type pos, size_type n) const
|
Chris@16
|
2167 {
|
Chris@16
|
2168 if (n > length()) return npos;
|
Chris@16
|
2169 pos = Min(pos, length() - n);
|
Chris@16
|
2170 if (n == 0) return pos;
|
Chris@16
|
2171
|
Chris@16
|
2172 const_iterator i(begin() + pos);
|
Chris@16
|
2173 for (; ; --i)
|
Chris@16
|
2174 {
|
Chris@16
|
2175 if (traits_type::eq(*i, *s)
|
Chris@16
|
2176 && traits_type::compare(&*i, s, n) == 0)
|
Chris@16
|
2177 {
|
Chris@16
|
2178 return i - begin();
|
Chris@16
|
2179 }
|
Chris@16
|
2180 if (i == begin()) break;
|
Chris@16
|
2181 }
|
Chris@16
|
2182 return npos;
|
Chris@16
|
2183 }
|
Chris@16
|
2184
|
Chris@16
|
2185 size_type rfind(const value_type* s, size_type pos = npos) const
|
Chris@16
|
2186 { return rfind(s, pos, traits_type::length(s)); }
|
Chris@16
|
2187
|
Chris@16
|
2188 size_type rfind(value_type c, size_type pos = npos) const
|
Chris@16
|
2189 { return rfind(&c, pos, 1); }
|
Chris@16
|
2190
|
Chris@16
|
2191 size_type find_first_of(const flex_string& str, size_type pos = 0) const
|
Chris@16
|
2192 { return find_first_of(str.c_str(), pos, str.length()); }
|
Chris@16
|
2193
|
Chris@16
|
2194 size_type find_first_of(const value_type* s,
|
Chris@16
|
2195 size_type pos, size_type n) const
|
Chris@16
|
2196 {
|
Chris@16
|
2197 if (pos > length() || n == 0) return npos;
|
Chris@16
|
2198 const_iterator i(begin() + pos),
|
Chris@16
|
2199 finish(end());
|
Chris@16
|
2200 for (; i != finish; ++i)
|
Chris@16
|
2201 {
|
Chris@16
|
2202 if (traits_type::find(s, n, *i) != 0)
|
Chris@16
|
2203 {
|
Chris@16
|
2204 return i - begin();
|
Chris@16
|
2205 }
|
Chris@16
|
2206 }
|
Chris@16
|
2207 return npos;
|
Chris@16
|
2208 }
|
Chris@16
|
2209
|
Chris@16
|
2210 size_type find_first_of(const value_type* s, size_type pos = 0) const
|
Chris@16
|
2211 { return find_first_of(s, pos, traits_type::length(s)); }
|
Chris@16
|
2212
|
Chris@16
|
2213 size_type find_first_of(value_type c, size_type pos = 0) const
|
Chris@16
|
2214 { return find_first_of(&c, pos, 1); }
|
Chris@16
|
2215
|
Chris@16
|
2216 size_type find_last_of (const flex_string& str,
|
Chris@16
|
2217 size_type pos = npos) const
|
Chris@16
|
2218 { return find_last_of(str.c_str(), pos, str.length()); }
|
Chris@16
|
2219
|
Chris@16
|
2220 size_type find_last_of (const value_type* s, size_type pos,
|
Chris@16
|
2221 size_type n) const
|
Chris@16
|
2222 {
|
Chris@16
|
2223 if (!empty() && n > 0)
|
Chris@16
|
2224 {
|
Chris@16
|
2225 pos = Min(pos, length() - 1);
|
Chris@16
|
2226 const_iterator i(begin() + pos);
|
Chris@16
|
2227 for (;; --i)
|
Chris@16
|
2228 {
|
Chris@16
|
2229 if (traits_type::find(s, n, *i) != 0)
|
Chris@16
|
2230 {
|
Chris@16
|
2231 return i - begin();
|
Chris@16
|
2232 }
|
Chris@16
|
2233 if (i == begin()) break;
|
Chris@16
|
2234 }
|
Chris@16
|
2235 }
|
Chris@16
|
2236 return npos;
|
Chris@16
|
2237 }
|
Chris@16
|
2238
|
Chris@16
|
2239 size_type find_last_of (const value_type* s,
|
Chris@16
|
2240 size_type pos = npos) const
|
Chris@16
|
2241 { return find_last_of(s, pos, traits_type::length(s)); }
|
Chris@16
|
2242
|
Chris@16
|
2243 size_type find_last_of (value_type c, size_type pos = npos) const
|
Chris@16
|
2244 { return find_last_of(&c, pos, 1); }
|
Chris@16
|
2245
|
Chris@16
|
2246 size_type find_first_not_of(const flex_string& str,
|
Chris@16
|
2247 size_type pos = 0) const
|
Chris@16
|
2248 { return find_first_not_of(str.data(), pos, str.size()); }
|
Chris@16
|
2249
|
Chris@16
|
2250 size_type find_first_not_of(const value_type* s, size_type pos,
|
Chris@16
|
2251 size_type n) const
|
Chris@16
|
2252 {
|
Chris@16
|
2253 if (pos < length())
|
Chris@16
|
2254 {
|
Chris@16
|
2255 const_iterator
|
Chris@16
|
2256 i(begin() + pos),
|
Chris@16
|
2257 finish(end());
|
Chris@16
|
2258 for (; i != finish; ++i)
|
Chris@16
|
2259 {
|
Chris@16
|
2260 if (traits_type::find(s, n, *i) == 0)
|
Chris@16
|
2261 {
|
Chris@16
|
2262 return i - begin();
|
Chris@16
|
2263 }
|
Chris@16
|
2264 }
|
Chris@16
|
2265 }
|
Chris@16
|
2266 return npos;
|
Chris@16
|
2267 }
|
Chris@16
|
2268
|
Chris@16
|
2269 size_type find_first_not_of(const value_type* s,
|
Chris@16
|
2270 size_type pos = 0) const
|
Chris@16
|
2271 { return find_first_not_of(s, pos, traits_type::length(s)); }
|
Chris@16
|
2272
|
Chris@16
|
2273 size_type find_first_not_of(value_type c, size_type pos = 0) const
|
Chris@16
|
2274 { return find_first_not_of(&c, pos, 1); }
|
Chris@16
|
2275
|
Chris@16
|
2276 size_type find_last_not_of(const flex_string& str,
|
Chris@16
|
2277 size_type pos = npos) const
|
Chris@16
|
2278 { return find_last_not_of(str.c_str(), pos, str.length()); }
|
Chris@16
|
2279
|
Chris@16
|
2280 size_type find_last_not_of(const value_type* s, size_type pos,
|
Chris@16
|
2281 size_type n) const
|
Chris@16
|
2282 {
|
Chris@16
|
2283 if (!empty())
|
Chris@16
|
2284 {
|
Chris@16
|
2285 pos = Min(pos, size() - 1);
|
Chris@16
|
2286 const_iterator i(begin() + pos);
|
Chris@16
|
2287 for (;; --i)
|
Chris@16
|
2288 {
|
Chris@16
|
2289 if (traits_type::find(s, n, *i) == 0)
|
Chris@16
|
2290 {
|
Chris@16
|
2291 return i - begin();
|
Chris@16
|
2292 }
|
Chris@16
|
2293 if (i == begin()) break;
|
Chris@16
|
2294 }
|
Chris@16
|
2295 }
|
Chris@16
|
2296 return npos;
|
Chris@16
|
2297 }
|
Chris@16
|
2298
|
Chris@16
|
2299 size_type find_last_not_of(const value_type* s,
|
Chris@16
|
2300 size_type pos = npos) const
|
Chris@16
|
2301 { return find_last_not_of(s, pos, traits_type::length(s)); }
|
Chris@16
|
2302
|
Chris@16
|
2303 size_type find_last_not_of (value_type c, size_type pos = npos) const
|
Chris@16
|
2304 { return find_last_not_of(&c, pos, 1); }
|
Chris@16
|
2305
|
Chris@16
|
2306 flex_string substr(size_type pos = 0, size_type n = npos) const
|
Chris@16
|
2307 {
|
Chris@16
|
2308 Enforce(pos <= size(), (std::out_of_range*)0, "");
|
Chris@16
|
2309 return flex_string(data() + pos, Min(n, size() - pos));
|
Chris@16
|
2310 }
|
Chris@16
|
2311
|
Chris@16
|
2312 std::ptrdiff_t compare(const flex_string& str) const
|
Chris@16
|
2313 {
|
Chris@16
|
2314 // FIX due to Goncalo N M de Carvalho July 18, 2005
|
Chris@16
|
2315 return compare(0, size(), str);
|
Chris@16
|
2316 }
|
Chris@16
|
2317
|
Chris@16
|
2318 std::ptrdiff_t compare(size_type pos1, size_type n1,
|
Chris@16
|
2319 const flex_string& str) const
|
Chris@16
|
2320 { return compare(pos1, n1, str.data(), str.size()); }
|
Chris@16
|
2321
|
Chris@16
|
2322 // FIX to compare: added the TC
|
Chris@16
|
2323 // (http://www.comeaucomputing.com/iso/lwg-defects.html number 5)
|
Chris@16
|
2324 // Thanks to Caleb Epstein for the fix
|
Chris@16
|
2325 std::ptrdiff_t compare(size_type pos1, size_type n1,
|
Chris@16
|
2326 const value_type* s) const
|
Chris@16
|
2327 {
|
Chris@16
|
2328 return compare(pos1, n1, s, traits_type::length(s));
|
Chris@16
|
2329 }
|
Chris@16
|
2330
|
Chris@16
|
2331 std::ptrdiff_t compare(size_type pos1, size_type n1,
|
Chris@16
|
2332 const value_type* s, size_type n2) const
|
Chris@16
|
2333 {
|
Chris@16
|
2334 Enforce(pos1 <= size(), (std::out_of_range*)0, "");
|
Chris@16
|
2335 Procust(n1, size() - pos1);
|
Chris@16
|
2336 const int r = traits_type::compare(pos1 + data(), s, Min(n1, n2));
|
Chris@16
|
2337 return r != 0 ? r : n1 > n2 ? 1 : n1 < n2 ? -1 : 0;
|
Chris@16
|
2338 }
|
Chris@16
|
2339
|
Chris@16
|
2340 std::ptrdiff_t compare(size_type pos1, size_type n1,
|
Chris@16
|
2341 const flex_string& str,
|
Chris@16
|
2342 size_type pos2, size_type n2) const
|
Chris@16
|
2343 {
|
Chris@16
|
2344 Enforce(pos2 <= str.size(), (std::out_of_range*)0, "");
|
Chris@16
|
2345 return compare(pos1, n1, str.data() + pos2, Min(n2, str.size() - pos2));
|
Chris@16
|
2346 }
|
Chris@16
|
2347
|
Chris@16
|
2348 std::ptrdiff_t compare(const value_type* s) const
|
Chris@16
|
2349 {
|
Chris@16
|
2350 // Could forward to compare(0, size(), s, traits_type::length(s))
|
Chris@16
|
2351 // but that does two extra checks
|
Chris@16
|
2352 const size_type n1(size()), n2(traits_type::length(s));
|
Chris@16
|
2353 const int r = traits_type::compare(data(), s, Min(n1, n2));
|
Chris@16
|
2354 return r != 0 ? r : n1 > n2 ? 1 : n1 < n2 ? -1 : 0;
|
Chris@16
|
2355 }
|
Chris@16
|
2356 };
|
Chris@16
|
2357
|
Chris@16
|
2358 // non-member functions
|
Chris@16
|
2359 template <typename E, class T, class A, class S>
|
Chris@16
|
2360 flex_string<E, T, A, S> operator+(const flex_string<E, T, A, S>& lhs,
|
Chris@16
|
2361 const flex_string<E, T, A, S>& rhs)
|
Chris@16
|
2362 {
|
Chris@16
|
2363 flex_string<E, T, A, S> result;
|
Chris@16
|
2364 result.reserve(lhs.size() + rhs.size());
|
Chris@16
|
2365 result.append(lhs).append(rhs);
|
Chris@16
|
2366 return result;
|
Chris@16
|
2367 }
|
Chris@16
|
2368
|
Chris@16
|
2369 template <typename E, class T, class A, class S>
|
Chris@16
|
2370 flex_string<E, T, A, S> operator+(const typename flex_string<E, T, A, S>::value_type* lhs,
|
Chris@16
|
2371 const flex_string<E, T, A, S>& rhs)
|
Chris@16
|
2372 {
|
Chris@16
|
2373 flex_string<E, T, A, S> result;
|
Chris@16
|
2374 const typename flex_string<E, T, A, S>::size_type len =
|
Chris@16
|
2375 flex_string<E, T, A, S>::traits_type::length(lhs);
|
Chris@16
|
2376 result.reserve(len + rhs.size());
|
Chris@16
|
2377 result.append(lhs, len).append(rhs);
|
Chris@16
|
2378 return result;
|
Chris@16
|
2379 }
|
Chris@16
|
2380
|
Chris@16
|
2381 template <typename E, class T, class A, class S>
|
Chris@16
|
2382 flex_string<E, T, A, S> operator+(
|
Chris@16
|
2383 typename flex_string<E, T, A, S>::value_type lhs,
|
Chris@16
|
2384 const flex_string<E, T, A, S>& rhs)
|
Chris@16
|
2385 {
|
Chris@16
|
2386 flex_string<E, T, A, S> result;
|
Chris@16
|
2387 result.reserve(1 + rhs.size());
|
Chris@16
|
2388 result.push_back(lhs);
|
Chris@16
|
2389 result.append(rhs);
|
Chris@16
|
2390 return result;
|
Chris@16
|
2391 }
|
Chris@16
|
2392
|
Chris@16
|
2393 template <typename E, class T, class A, class S>
|
Chris@16
|
2394 flex_string<E, T, A, S> operator+(const flex_string<E, T, A, S>& lhs,
|
Chris@16
|
2395 const typename flex_string<E, T, A, S>::value_type* rhs)
|
Chris@16
|
2396 {
|
Chris@16
|
2397 typedef typename flex_string<E, T, A, S>::size_type size_type;
|
Chris@16
|
2398 typedef typename flex_string<E, T, A, S>::traits_type traits_type;
|
Chris@16
|
2399
|
Chris@16
|
2400 flex_string<E, T, A, S> result;
|
Chris@16
|
2401 const size_type len = traits_type::length(rhs);
|
Chris@16
|
2402 result.reserve(lhs.size() + len);
|
Chris@16
|
2403 result.append(lhs).append(rhs, len);
|
Chris@16
|
2404 return result;
|
Chris@16
|
2405 }
|
Chris@16
|
2406
|
Chris@16
|
2407 template <typename E, class T, class A, class S>
|
Chris@16
|
2408 flex_string<E, T, A, S> operator+(const flex_string<E, T, A, S>& lhs,
|
Chris@16
|
2409 typename flex_string<E, T, A, S>::value_type rhs)
|
Chris@16
|
2410 {
|
Chris@16
|
2411 flex_string<E, T, A, S> result;
|
Chris@16
|
2412 result.reserve(lhs.size() + 1);
|
Chris@16
|
2413 result.append(lhs);
|
Chris@16
|
2414 result.push_back(rhs);
|
Chris@16
|
2415 return result;
|
Chris@16
|
2416 }
|
Chris@16
|
2417
|
Chris@16
|
2418 template <typename E, class T, class A, class S>
|
Chris@16
|
2419 inline bool operator==(const flex_string<E, T, A, S>& lhs,
|
Chris@16
|
2420 const flex_string<E, T, A, S>& rhs)
|
Chris@16
|
2421 { return lhs.compare(rhs) == 0; }
|
Chris@16
|
2422
|
Chris@16
|
2423 template <typename E, class T, class A, class S>
|
Chris@16
|
2424 inline bool operator==(const typename flex_string<E, T, A, S>::value_type* lhs,
|
Chris@16
|
2425 const flex_string<E, T, A, S>& rhs)
|
Chris@16
|
2426 { return rhs == lhs; }
|
Chris@16
|
2427
|
Chris@16
|
2428 template <typename E, class T, class A, class S>
|
Chris@16
|
2429 inline bool operator==(const flex_string<E, T, A, S>& lhs,
|
Chris@16
|
2430 const typename flex_string<E, T, A, S>::value_type* rhs)
|
Chris@16
|
2431 { return lhs.compare(rhs) == 0; }
|
Chris@16
|
2432
|
Chris@16
|
2433 template <typename E, class T, class A, class S>
|
Chris@16
|
2434 inline bool operator!=(const flex_string<E, T, A, S>& lhs,
|
Chris@16
|
2435 const flex_string<E, T, A, S>& rhs)
|
Chris@16
|
2436 { return !(lhs == rhs); }
|
Chris@16
|
2437
|
Chris@16
|
2438 template <typename E, class T, class A, class S>
|
Chris@16
|
2439 inline bool operator!=(const typename flex_string<E, T, A, S>::value_type* lhs,
|
Chris@16
|
2440 const flex_string<E, T, A, S>& rhs)
|
Chris@16
|
2441 { return !(lhs == rhs); }
|
Chris@16
|
2442
|
Chris@16
|
2443 template <typename E, class T, class A, class S>
|
Chris@16
|
2444 inline bool operator!=(const flex_string<E, T, A, S>& lhs,
|
Chris@16
|
2445 const typename flex_string<E, T, A, S>::value_type* rhs)
|
Chris@16
|
2446 { return !(lhs == rhs); }
|
Chris@16
|
2447
|
Chris@16
|
2448 template <typename E, class T, class A, class S>
|
Chris@16
|
2449 inline bool operator<(const flex_string<E, T, A, S>& lhs,
|
Chris@16
|
2450 const flex_string<E, T, A, S>& rhs)
|
Chris@16
|
2451 { return lhs.compare(rhs) < 0; }
|
Chris@16
|
2452
|
Chris@16
|
2453 template <typename E, class T, class A, class S>
|
Chris@16
|
2454 inline bool operator<(const flex_string<E, T, A, S>& lhs,
|
Chris@16
|
2455 const typename flex_string<E, T, A, S>::value_type* rhs)
|
Chris@16
|
2456 { return lhs.compare(rhs) < 0; }
|
Chris@16
|
2457
|
Chris@16
|
2458 template <typename E, class T, class A, class S>
|
Chris@16
|
2459 inline bool operator<(const typename flex_string<E, T, A, S>::value_type* lhs,
|
Chris@16
|
2460 const flex_string<E, T, A, S>& rhs)
|
Chris@16
|
2461 { return rhs.compare(lhs) > 0; }
|
Chris@16
|
2462
|
Chris@16
|
2463 template <typename E, class T, class A, class S>
|
Chris@16
|
2464 inline bool operator>(const flex_string<E, T, A, S>& lhs,
|
Chris@16
|
2465 const flex_string<E, T, A, S>& rhs)
|
Chris@16
|
2466 { return rhs < lhs; }
|
Chris@16
|
2467
|
Chris@16
|
2468 template <typename E, class T, class A, class S>
|
Chris@16
|
2469 inline bool operator>(const flex_string<E, T, A, S>& lhs,
|
Chris@16
|
2470 const typename flex_string<E, T, A, S>::value_type* rhs)
|
Chris@16
|
2471 { return rhs < lhs; }
|
Chris@16
|
2472
|
Chris@16
|
2473 template <typename E, class T, class A, class S>
|
Chris@16
|
2474 bool operator>(const typename flex_string<E, T, A, S>::value_type* lhs,
|
Chris@16
|
2475 const flex_string<E, T, A, S>& rhs)
|
Chris@16
|
2476 { return rhs < lhs; }
|
Chris@16
|
2477
|
Chris@16
|
2478 template <typename E, class T, class A, class S>
|
Chris@16
|
2479 inline bool operator<=(const flex_string<E, T, A, S>& lhs,
|
Chris@16
|
2480 const flex_string<E, T, A, S>& rhs)
|
Chris@16
|
2481 { return !(rhs < lhs); }
|
Chris@16
|
2482
|
Chris@16
|
2483 template <typename E, class T, class A, class S>
|
Chris@16
|
2484 inline bool operator<=(const flex_string<E, T, A, S>& lhs,
|
Chris@16
|
2485 const typename flex_string<E, T, A, S>::value_type* rhs)
|
Chris@16
|
2486 { return !(rhs < lhs); }
|
Chris@16
|
2487
|
Chris@16
|
2488 template <typename E, class T, class A, class S>
|
Chris@16
|
2489 bool operator<=(const typename flex_string<E, T, A, S>::value_type* lhs,
|
Chris@16
|
2490 const flex_string<E, T, A, S>& rhs)
|
Chris@16
|
2491 { return !(rhs < lhs); }
|
Chris@16
|
2492
|
Chris@16
|
2493 template <typename E, class T, class A, class S>
|
Chris@16
|
2494 bool operator>=(const flex_string<E, T, A, S>& lhs,
|
Chris@16
|
2495 const flex_string<E, T, A, S>& rhs)
|
Chris@16
|
2496 { return !(lhs < rhs); }
|
Chris@16
|
2497
|
Chris@16
|
2498 template <typename E, class T, class A, class S>
|
Chris@16
|
2499 bool operator>=(const flex_string<E, T, A, S>& lhs,
|
Chris@16
|
2500 const typename flex_string<E, T, A, S>::value_type* rhs)
|
Chris@16
|
2501 { return !(lhs < rhs); }
|
Chris@16
|
2502
|
Chris@16
|
2503 template <typename E, class T, class A, class S>
|
Chris@16
|
2504 inline bool operator>=(const typename flex_string<E, T, A, S>::value_type* lhs,
|
Chris@16
|
2505 const flex_string<E, T, A, S>& rhs)
|
Chris@16
|
2506 { return !(lhs < rhs); }
|
Chris@16
|
2507
|
Chris@16
|
2508 template <typename E, class T, class A, class S>
|
Chris@16
|
2509 void swap(flex_string<E, T, A, S>& lhs, flex_string<E, T, A, S>& rhs)
|
Chris@16
|
2510 {
|
Chris@16
|
2511 // subclause 21.3.7.8:
|
Chris@16
|
2512 lhs.swap(rhs);
|
Chris@16
|
2513 }
|
Chris@16
|
2514
|
Chris@16
|
2515 template <typename E, class T, class A, class S>
|
Chris@16
|
2516 inline std::basic_istream<typename flex_string<E, T, A, S>::value_type,
|
Chris@16
|
2517 typename flex_string<E, T, A, S>::traits_type>&
|
Chris@16
|
2518 operator>>(
|
Chris@16
|
2519 std::basic_istream<typename flex_string<E, T, A, S>::value_type,
|
Chris@16
|
2520 typename flex_string<E, T, A, S>::traits_type>& is,
|
Chris@16
|
2521 flex_string<E, T, A, S>& str);
|
Chris@16
|
2522
|
Chris@16
|
2523 template <typename E, class T, class A, class S>
|
Chris@16
|
2524 std::basic_ostream<typename flex_string<E, T, A, S>::value_type,
|
Chris@16
|
2525 typename flex_string<E, T, A, S>::traits_type>&
|
Chris@16
|
2526 operator<<(
|
Chris@16
|
2527 std::basic_ostream<typename flex_string<E, T, A, S>::value_type,
|
Chris@16
|
2528 typename flex_string<E, T, A, S>::traits_type>& os,
|
Chris@16
|
2529 const flex_string<E, T, A, S>& str)
|
Chris@16
|
2530 { return os << str.c_str(); }
|
Chris@16
|
2531
|
Chris@16
|
2532 template <typename E1, class T, class A, class S>
|
Chris@16
|
2533 const typename flex_string<E1, T, A, S>::size_type
|
Chris@16
|
2534 flex_string<E1, T, A, S>::npos = (typename flex_string<E1, T, A, S>::size_type)(-1);
|
Chris@16
|
2535
|
Chris@16
|
2536 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
2537 } // namespace util
|
Chris@16
|
2538 } // namespace wave
|
Chris@16
|
2539 } // namespace boost
|
Chris@16
|
2540
|
Chris@16
|
2541 #if BOOST_WAVE_SERIALIZATION != 0
|
Chris@16
|
2542 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
2543 namespace boost { namespace serialization {
|
Chris@16
|
2544
|
Chris@16
|
2545 #if !defined(BOOST_WAVE_FLEX_STRING_SERIALIZATION_HACK)
|
Chris@16
|
2546
|
Chris@16
|
2547 // FIXME: This doesn't work because of the missing flex_string::operator>>()
|
Chris@16
|
2548 template <typename E, class T, class A, class S>
|
Chris@16
|
2549 struct implementation_level<boost::wave::util::flex_string<E, T, A, S> >
|
Chris@16
|
2550 {
|
Chris@16
|
2551 typedef mpl::integral_c_tag tag;
|
Chris@16
|
2552 typedef mpl::int_<boost::serialization::primitive_type> type;
|
Chris@16
|
2553 BOOST_STATIC_CONSTANT(
|
Chris@16
|
2554 int,
|
Chris@16
|
2555 value = implementation_level::type::value
|
Chris@16
|
2556 );
|
Chris@16
|
2557 };
|
Chris@16
|
2558
|
Chris@16
|
2559 #else
|
Chris@16
|
2560
|
Chris@16
|
2561 // We serialize flex_strings as vectors of char's for now
|
Chris@16
|
2562 template<class Archive, typename E, class T, class A, class S>
|
Chris@16
|
2563 inline void save(Archive & ar,
|
Chris@16
|
2564 boost::wave::util::flex_string<E, T, A, S> const &t,
|
Chris@16
|
2565 const unsigned int file_version)
|
Chris@16
|
2566 {
|
Chris@16
|
2567 boost::serialization::stl::save_collection<
|
Chris@16
|
2568 Archive, wave::util::flex_string<E, T, A, S> >(ar, t);
|
Chris@16
|
2569 }
|
Chris@16
|
2570
|
Chris@16
|
2571 template<class Archive, typename E, class T, class A, class S>
|
Chris@16
|
2572 inline void load(Archive & ar, boost::wave::util::flex_string<E, T, A, S> &t,
|
Chris@16
|
2573 const unsigned int file_version)
|
Chris@16
|
2574 {
|
Chris@16
|
2575 boost::serialization::stl::load_collection<
|
Chris@16
|
2576 Archive, boost::wave::util::flex_string<E, T, A, S>,
|
Chris@16
|
2577 boost::serialization::stl::archive_input_seq<
|
Chris@16
|
2578 Archive, boost::wave::util::flex_string<E, T, A, S> >,
|
Chris@16
|
2579 boost::serialization::stl::reserve_imp<
|
Chris@16
|
2580 boost::wave::util::flex_string<E, T, A, S> >
|
Chris@16
|
2581 >(ar, t);
|
Chris@16
|
2582 }
|
Chris@16
|
2583
|
Chris@16
|
2584 // split non-intrusive serialization function member into separate
|
Chris@16
|
2585 // non intrusive save/load member functions
|
Chris@16
|
2586 template<class Archive, typename E, class T, class A, class S>
|
Chris@16
|
2587 inline void serialize(Archive & ar, boost::wave::util::flex_string<E, T, A, S> &t,
|
Chris@16
|
2588 const unsigned int file_version)
|
Chris@16
|
2589 {
|
Chris@16
|
2590 boost::serialization::split_free(ar, t, file_version);
|
Chris@16
|
2591 }
|
Chris@16
|
2592
|
Chris@16
|
2593 #endif
|
Chris@16
|
2594
|
Chris@16
|
2595 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
2596 }} // boost::serialization
|
Chris@16
|
2597 #endif
|
Chris@16
|
2598
|
Chris@16
|
2599 // the suffix header occurs after all of the code
|
Chris@16
|
2600 #ifdef BOOST_HAS_ABI_HEADERS
|
Chris@16
|
2601 #include BOOST_ABI_SUFFIX
|
Chris@16
|
2602 #endif
|
Chris@16
|
2603
|
Chris@16
|
2604 #endif // FLEX_STRING_INC_
|