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