]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/wave/util/flex_string.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / wave / util / flex_string.hpp
CommitLineData
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////////////////////////////////////////////////////////////////////////////////
43template <typename E, class A = @>
44class 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///////////////////////////////////////////////////////////////////////////////
121namespace boost {
122namespace wave {
123namespace util {
124
125namespace 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
207template <class T> class mallocator
208{
209public:
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
264private:
265 void operator=(const mallocator&);
266};
267
268template<> 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
278template <class T>
b32b8144 279inline bool operator==(const mallocator<T>&,
7c673cae
FG
280 const mallocator<T>&) {
281 return true;
282}
283
284template <class T>
b32b8144 285inline bool operator!=(const mallocator<T>&,
7c673cae
FG
286 const mallocator<T>&) {
287 return false;
288}
289
290template <class Allocator>
291typename 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
302template <class Allocator>
303typename 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
319template <typename E, class A = std::allocator<E> >
320class SimpleStringStorage
321{
322 // The "public" below exists because MSVC can't do template typedefs
323public:
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
336private:
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
360private:
361 // Warning - this doesn't initialize pData_. Used in reserve()
362 SimpleStringStorage()
363 { }
364
365public:
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
533template <typename E, class A>
534const typename SimpleStringStorage<E, A>::Data
b32b8144 535SimpleStringStorage<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
544template <typename E, class A = std::allocator<E> >
545class 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
589public:
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
750template <typename E, class A = std::allocator<E> >
751class VectorStringStorage : protected std::vector<E, A>
752{
753 typedef std::vector<E, A> base;
754
755public: // 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 868template <class Storage, unsigned int threshold,
7c673cae
FG
869 typename Align = typename Storage::value_type*>
870class SmallStringOpt
871{
872public:
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 879private:
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
886public:
b32b8144 887 enum { maxSmallString =
7c673cae 888 (temp2 + sizeof(value_type) - 1) / sizeof(value_type) };
b32b8144 889
7c673cae
FG
890private:
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
918public:
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
1190template <
b32b8144 1191 typename Storage,
7c673cae
FG
1192 typename Align = BOOST_DEDUCED_TYPENAME Storage::value_type*
1193>
1194class CowString
1195{
1196 typedef typename Storage::value_type E;
1197 typedef typename flex_string_details::get_unsigned<E>::result RefCountType;
1198
1199public:
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
1207private:
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
1255public:
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
1413template <typename E,
1414 class T = std::char_traits<E>,
1415 class A = std::allocator<E>,
1416 class Storage = AllocatorStringStorage<E, A> >
1417class 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
1459public:
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
1480private:
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
1486public:
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
1772private:
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
1939public:
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
2015private:
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
2099public:
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
2359template <typename E, class T, class A, class S>
b32b8144 2360flex_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
2369template <typename E, class T, class A, class S>
b32b8144 2370flex_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
2381template <typename E, class T, class A, class S>
2382flex_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
2393template <typename E, class T, class A, class S>
b32b8144 2394flex_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
2407template <typename E, class T, class A, class S>
b32b8144 2408flex_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
2418template <typename E, class T, class A, class S>
b32b8144 2419inline 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
2423template <typename E, class T, class A, class S>
b32b8144 2424inline 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
2428template <typename E, class T, class A, class S>
b32b8144 2429inline 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
2433template <typename E, class T, class A, class S>
b32b8144 2434inline 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
2438template <typename E, class T, class A, class S>
b32b8144 2439inline 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
2443template <typename E, class T, class A, class S>
b32b8144 2444inline 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
2448template <typename E, class T, class A, class S>
b32b8144 2449inline 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
2453template <typename E, class T, class A, class S>
b32b8144 2454inline 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
2458template <typename E, class T, class A, class S>
b32b8144 2459inline 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
2463template <typename E, class T, class A, class S>
b32b8144 2464inline 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
2468template <typename E, class T, class A, class S>
b32b8144 2469inline 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
2473template <typename E, class T, class A, class S>
b32b8144 2474bool 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
2478template <typename E, class T, class A, class S>
b32b8144 2479inline 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
2483template <typename E, class T, class A, class S>
b32b8144 2484inline 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
2488template <typename E, class T, class A, class S>
b32b8144 2489bool 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
2493template <typename E, class T, class A, class S>
b32b8144 2494bool 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
2498template <typename E, class T, class A, class S>
b32b8144 2499bool 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
2503template <typename E, class T, class A, class S>
b32b8144 2504inline 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
2508template <typename E, class T, class A, class S>
2509void 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
2515template <typename E, class T, class A, class S>
b32b8144 2516inline std::basic_istream<typename flex_string<E, T, A, S>::value_type,
7c673cae
FG
2517 typename flex_string<E, T, A, S>::traits_type>&
2518operator>>(
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
2523template <typename E, class T, class A, class S>
2524std::basic_ostream<typename flex_string<E, T, A, S>::value_type,
2525 typename flex_string<E, T, A, S>::traits_type>&
2526operator<<(
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
2532template <typename E1, class T, class A, class S>
2533const typename flex_string<E1, T, A, S>::size_type
2534flex_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///////////////////////////////////////////////////////////////////////////////
2543namespace 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>>()
2548template <typename E, class T, class A, class S>
2549struct 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
2562template<class Archive, typename E, class T, class A, class S>
b32b8144 2563inline 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
2571template<class Archive, typename E, class T, class A, class S>
2572inline 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
2586template<class Archive, typename E, class T, class A, class S>
2587inline 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_