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 
10 // This code is taken from:
11 // Andrei Alexandrescu, Generic<Programming>: A Policy-Based basic_string
12 // Implementation. http://www.cuj.com/documents/s=7994/cujcexp1906alexandr/
13 //
14 // #HK030306:
15 //      - Moved into the namespace boost::wave::util
16 //      - Added a bunch of missing typename(s)
17 //      - Integrated with boost config
18 //      - Added a missing header include
19 //      - Added special constructors and operator= to allow CowString to be
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:
27 //      - Once again incorporated the changes from Andrei's latest version of
28 //        this class
29 //
30 // #HK090523:
31 //      - Incorporated the changes from latest version of flex_string as
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;
51 
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;
62 
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);
70 
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);
77 
78     const E* c_str() const;
79     const E* data() const;
80 
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>
copy_n(InIt b,typename std::iterator_traits<InIt>::difference_type n,OutIt d)128     OutIt copy_n(InIt b,
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>
pod_fill(Pod * b,Pod * e,T c)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>
pod_move(const Pod * b,const Pod * e,Pod * d)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>
pod_copy(const Pod * b,const Pod * e,Pod * d)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 
220     template <class U>
221     struct rebind { typedef mallocator<U> other; };
222 
mallocator()223     mallocator() {}
mallocator(const mallocator &)224     mallocator(const mallocator&) {}
225     //template <class U>
226     //mallocator(const mallocator<U>&) {}
~mallocator()227     ~mallocator() {}
228 
address(reference x) const229     pointer address(reference x) const { return &x; }
address(const_reference x) const230     const_pointer address(const_reference x) const
231     {
232         return x;
233     }
234 
allocate(size_type n,const_pointer=0)235     pointer allocate(size_type n, const_pointer = 0)
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 
deallocate(pointer p,size_type)243     void deallocate(pointer p, size_type)
244     {
245         using namespace std;
246         free(p);
247     }
248 
max_size() const249     size_type max_size() const
250     {
251         return static_cast<size_type>(-1) / sizeof(T);
252     }
253 
construct(pointer p,const value_type & x)254     void construct(pointer p, const value_type& x)
255     {
256         new(p) value_type(x);
257     }
258 
destroy(pointer p)259     void destroy(pointer p)
260     {
261         p->~value_type();
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 
274   template <class U>
275   struct rebind { typedef mallocator<U> other; };
276 };
277 
278 template <class T>
operator ==(const mallocator<T> &,const mallocator<T> &)279 inline bool operator==(const mallocator<T>&,
280                        const mallocator<T>&) {
281   return true;
282 }
283 
284 template <class T>
operator !=(const mallocator<T> &,const mallocator<T> &)285 inline bool operator!=(const mallocator<T>&,
286                        const mallocator<T>&) {
287   return false;
288 }
289 
290 template <class Allocator>
Reallocate(Allocator & alloc,typename Allocator::pointer p,typename Allocator::size_type oldObjCount,typename Allocator::size_type newObjCount,void *)291 typename Allocator::pointer Reallocate(
292     Allocator& alloc,
293     typename Allocator::pointer p,
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>
Reallocate(Allocator & alloc,typename Allocator::pointer p,typename Allocator::size_type oldObjCount,typename Allocator::size_type newObjCount,mallocator<void> *)303 typename Allocator::pointer Reallocate(
304     Allocator& alloc,
305     typename Allocator::pointer p,
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     {
Databoost::wave::util::SimpleStringStorage::Data326         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 
Init(size_type size,size_type capacity)339     void Init(size_type size, size_type capacity)
340     {
341         BOOST_ASSERT(size <= capacity);
342         if (capacity == 0)
343         {
344             pData_ = const_cast<Data*>(&emptyString_);
345         }
346         else
347         {
348             // 11-17-2000: comment added:
349             //     No need to allocate (capacity + 1) to
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()
SimpleStringStorage()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 
SimpleStringStorage(const SimpleStringStorage & rhs)371     SimpleStringStorage(const SimpleStringStorage& rhs)
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 
SimpleStringStorage(const SimpleStringStorage & s,flex_string_details::Shallow)378     SimpleStringStorage(const SimpleStringStorage& s,
379         flex_string_details::Shallow)
380         : pData_(s.pData_)
381     {
382     }
383 
SimpleStringStorage(const A &)384     SimpleStringStorage(const A&)
385     { pData_ = const_cast<Data*>(&emptyString_); }
386 
SimpleStringStorage(const E * s,size_type len,const A &)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 
SimpleStringStorage(size_type len,E c,const A &)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 
operator =(const SimpleStringStorage & rhs)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 
~SimpleStringStorage()408     ~SimpleStringStorage()
409     {
410         BOOST_ASSERT(begin() <= end());
411         if (pData_ != &emptyString_) free(pData_);
412     }
413 
begin()414     iterator begin()
415     { return pData_->buffer_; }
416 
begin() const417     const_iterator begin() const
418     { return pData_->buffer_; }
419 
end()420     iterator end()
421     { return pData_->pEnd_; }
422 
end() const423     const_iterator end() const
424     { return pData_->pEnd_; }
425 
size() const426     size_type size() const
427     { return pData_->pEnd_ - pData_->buffer_; }
428 
max_size() const429     size_type max_size() const
430     { return std::size_t(-1) / sizeof(E) - sizeof(Data) - 1; }
431 
capacity() const432     size_type capacity() const
433     { return pData_->pEndOfMem_ - pData_->buffer_; }
434 
reserve(size_type res_arg)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 
443         if (pData_ == &emptyString_)
444         {
445             Init(0, res_arg);
446         }
447         else
448         {
449             const size_type sz = size();
450 
451             void* p = realloc(pData_,
452                 sizeof(Data) + res_arg * sizeof(E));
453             if (!p) boost::throw_exception(std::bad_alloc());
454 
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 
append(const E * s,size_type sz)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>
append(InputIterator b,InputIterator e)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 
resize(size_type newSize,E fill)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         {
505             if (newSize > capacity())
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 
swap(SimpleStringStorage & rhs)515     void swap(SimpleStringStorage& rhs)
516     {
517         std::swap(pData_, rhs.pData_);
518     }
519 
c_str() const520     const E* c_str() const
521     {
522         if (pData_ != &emptyString_) *pData_->pEnd_ = E();
523         return pData_->buffer_;
524     }
525 
data() const526     const E* data() const
527     { return pData_->buffer_; }
528 
get_allocator() const529     A get_allocator() const
530     { return A(); }
531 };
532 
533 template <typename E, class A>
534 const typename SimpleStringStorage<E, A>::Data
535 SimpleStringStorage<E, A>::emptyString_ =
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 
Alloc(size_type sz,const void * p=0)550     void* Alloc(size_type sz, const void* p = 0)
551     {
552         return A::allocate(1 + (sz - 1) / sizeof(E),
553             static_cast<const char*>(p));
554     }
555 
Realloc(void * p,size_type oldSz,size_type newSz)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 
Free(void * p,size_type sz)564     void Free(void* p, size_type sz)
565     {
566         A::deallocate(static_cast<E*>(p), sz);
567     }
568 
569     Data* pData_;
570 
Init(size_type size,size_type cap)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 
AllocatorStringStorage()595     AllocatorStringStorage()
596     : A(), pData_(0)
597     {
598     }
599 
AllocatorStringStorage(const AllocatorStringStorage & rhs)600     AllocatorStringStorage(const AllocatorStringStorage& rhs)
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 
AllocatorStringStorage(const AllocatorStringStorage & s,flex_string_details::Shallow)608     AllocatorStringStorage(const AllocatorStringStorage& s,
609         flex_string_details::Shallow)
610     : A(s.get_allocator())
611     {
612         pData_ = s.pData_;
613     }
614 
AllocatorStringStorage(const A & a)615     AllocatorStringStorage(const A& a) : A(a)
616     {
617         pData_ = const_cast<Data*>(
618             &SimpleStringStorage<E, A>::emptyString_);
619     }
620 
AllocatorStringStorage(const E * s,size_type len,const A & a)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 
AllocatorStringStorage(size_type len,E c,const A & a)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 
operator =(const AllocatorStringStorage & rhs)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 
~AllocatorStringStorage()644     ~AllocatorStringStorage()
645     {
646         if (capacity())
647         {
648             Free(pData_,
649                 sizeof(Data) + capacity() * sizeof(E));
650         }
651     }
652 
begin()653     iterator begin()
654     { return pData_->buffer_; }
655 
begin() const656     const_iterator begin() const
657     { return pData_->buffer_; }
658 
end()659     iterator end()
660     { return pData_->pEnd_; }
661 
end() const662     const_iterator end() const
663     { return pData_->pEnd_; }
664 
size() const665     size_type size() const
666     { return size_type(end() - begin()); }
667 
max_size() const668     size_type max_size() const
669     { return A::max_size(); }
670 
capacity() const671     size_type capacity() const
672     { return size_type(pData_->pEndOfMem_ - pData_->buffer_); }
673 
resize(size_type n,E c)674     void resize(size_type n, E c)
675     {
676         reserve(n);
677         iterator newEnd = begin() + n;
678         iterator oldEnd = end();
679         if (newEnd > oldEnd)
680         {
681             // Copy the characters
682             flex_string_details::pod_fill(oldEnd, newEnd, c);
683         }
684         if (capacity()) pData_->pEnd_ = newEnd;
685     }
686 
reserve(size_type res_arg)687     void reserve(size_type res_arg)
688     {
689         if (res_arg <= capacity())
690         {
691             // @@@ shrink to fit here
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>
append(ForwardIterator b,ForwardIterator e)705     void append(ForwardIterator b, ForwardIterator e)
706     {
707         const size_type
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 
swap(AllocatorStringStorage & rhs)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 
c_str() const728     const E* c_str() const
729     {
730         if (pData_ != &SimpleStringStorage<E, A>::emptyString_)
731         {
732             *pData_->pEnd_ = E();
733         }
734         return &*begin();
735     }
736 
data() const737     const E* data() const
738     { return &*begin(); }
739 
get_allocator() const740     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;
761 
VectorStringStorage(const VectorStringStorage & s)762     VectorStringStorage(const VectorStringStorage& s) : base(s)
763     { }
764 
VectorStringStorage(const A & a)765     VectorStringStorage(const A& a) : base(1, E(), a)
766     { }
767 
VectorStringStorage(const E * s,size_type len,const A & a)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 
VectorStringStorage(size_type len,E c,const A & a)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     }
783 
operator =(const VectorStringStorage & rhs)784     VectorStringStorage& operator=(const VectorStringStorage& rhs)
785     {
786         base& v = *this;
787         v = rhs;
788         return *this;
789     }
790 
begin()791     iterator begin()
792     { return base::begin(); }
793 
begin() const794     const_iterator begin() const
795     { return base::begin(); }
796 
end()797     iterator end()
798     { return base::end() - 1; }
799 
end() const800     const_iterator end() const
801     { return base::end() - 1; }
802 
size() const803     size_type size() const
804     { return base::size() - 1; }
805 
max_size() const806     size_type max_size() const
807     { return base::max_size() - 1; }
808 
capacity() const809     size_type capacity() const
810     { return base::capacity() - 1; }
811 
reserve(size_type res_arg)812     void reserve(size_type res_arg)
813     {
814         BOOST_ASSERT(res_arg < max_size());
815         base::reserve(res_arg + 1);
816     }
817 
append(const E * s,size_type sz)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     }
835 
836     template <class InputIterator>
append(InputIterator b,InputIterator e)837     void append(InputIterator b, InputIterator e)
838     {
839         base::insert(end(), b, e);
840     }
841 
resize(size_type n,E c)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 
swap(VectorStringStorage & rhs)850     void swap(VectorStringStorage& rhs)
851     { base::swap(rhs); }
852 
c_str() const853     const E* c_str() const
854     { return &*begin(); }
855 
data() const856     const E* data() const
857     { return &*begin(); }
858 
get_allocator() const859     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 
868 template <class Storage, unsigned int threshold,
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;
878 
879 private:
880   enum { temp1 = threshold * sizeof(value_type) > sizeof(Storage)
881         ? threshold  * sizeof(value_type)
882         : sizeof(Storage) };
883 
884     enum { temp2 = temp1 > sizeof(Align) ? temp1 : sizeof(Align) };
885 
886 public:
887     enum { maxSmallString =
888     (temp2 + sizeof(value_type) - 1) / sizeof(value_type) };
889 
890 private:
891     enum { magic = maxSmallString + 1 };
892 
893     union
894     {
895         mutable value_type buf_[maxSmallString + 1];
896         Align align_;
897     };
898 
GetStorage()899     Storage& GetStorage()
900     {
901         BOOST_ASSERT(buf_[maxSmallString] == magic);
902         Storage* p = reinterpret_cast<Storage*>(&buf_[0]);
903         return *p;
904     }
905 
GetStorage() const906     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 
Small() const913     bool Small() const
914     {
915         return buf_[maxSmallString] != magic;
916     }
917 
918 public:
SmallStringOpt(const SmallStringOpt & s)919   SmallStringOpt(const SmallStringOpt& s)
920     {
921         if (s.Small())
922         {
923             flex_string_details::pod_copy(
924                 s.buf_,
925                 s.buf_ + s.size(),
926                 buf_);
927         }
928         else
929         {
930             new(buf_) Storage(s.GetStorage());
931         }
932         buf_[maxSmallString] = s.buf_[maxSmallString];
933     }
934 
SmallStringOpt(const allocator_type &)935     SmallStringOpt(const allocator_type&)
936     {
937         buf_[maxSmallString] = maxSmallString;
938     }
939 
SmallStringOpt(const value_type * s,size_type len,const allocator_type & a)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 
SmallStringOpt(size_type len,value_type c,const allocator_type & a)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 
operator =(const SmallStringOpt & rhs)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 
~SmallStringOpt()976     ~SmallStringOpt()
977     {
978         if (!Small()) GetStorage().~Storage();
979     }
980 
begin()981     iterator begin()
982     {
983         if (Small()) return buf_;
984         return &*GetStorage().begin();
985     }
986 
begin() const987     const_iterator begin() const
988     {
989         if (Small()) return buf_;
990         return &*GetStorage().begin();
991     }
992 
end()993     iterator end()
994     {
995         if (Small()) return buf_ + maxSmallString - buf_[maxSmallString];
996         return &*GetStorage().end();
997     }
998 
end() const999     const_iterator end() const
1000     {
1001         if (Small()) return buf_ + maxSmallString - buf_[maxSmallString];
1002         return &*GetStorage().end();
1003     }
1004 
size() const1005     size_type size() const
1006     {
1007         BOOST_ASSERT(!Small() || maxSmallString >= buf_[maxSmallString]);
1008         return Small()
1009             ? maxSmallString - buf_[maxSmallString]
1010             : GetStorage().size();
1011     }
1012 
max_size() const1013     size_type max_size() const
1014     { return get_allocator().max_size(); }
1015 
capacity() const1016     size_type capacity() const
1017     { return Small() ? maxSmallString : GetStorage().capacity(); }
1018 
reserve(size_type res_arg)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();
1026             new(buf_) Storage(temp.data(), temp.size(),
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 
append(const value_type * s,size_type sz)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
1047             const size_type neededCapacity =
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             {
1064                 flex_string_details::pod_move(s, s + sz,
1065                     buf_ + maxSmallString - buf_[maxSmallString]);
1066                 buf_[maxSmallString] -= value_type(sz);
1067             }
1068         }
1069     }
1070 
1071     template <class InputIterator>
append(InputIterator b,InputIterator e)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 
resize(size_type n,value_type c)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
1090                 Storage newString(temp.data(), temp.size(),
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 
swap(SmallStringOpt & rhs)1127     void swap(SmallStringOpt& rhs)
1128     {
1129         if (Small())
1130         {
1131             if (rhs.Small())
1132             {
1133                 // Small swapped with small
1134                 std::swap_ranges(buf_, buf_ + maxSmallString + 1,
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 
c_str() const1171     const value_type* c_str() const
1172     {
1173         if (!Small()) return GetStorage().c_str();
1174         buf_[maxSmallString - buf_[maxSmallString]] = value_type();
1175         return buf_;
1176     }
1177 
data() const1178     const value_type* data() const
1179     { return Small() ? buf_ : GetStorage().data(); }
1180 
get_allocator() const1181     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 <
1191     typename Storage,
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;
1206 
1207 private:
1208     union
1209     {
1210         mutable char buf_[sizeof(Storage)];
1211         Align align_;
1212     };
1213 
Data() const1214     Storage& Data() const
1215     {
1216         Storage* p = reinterpret_cast<Storage*>(&buf_[0]);
1217         return *p;
1218     }
1219 
GetRefs() const1220     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     }
1227 
Refs()1228     RefCountType& Refs()
1229     {
1230         Storage& d = Data();
1231         BOOST_ASSERT(d.size() > 0);
1232         return reinterpret_cast<RefCountType&>(*d.begin());
1233     }
1234 
MakeUnique() const1235     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(
1250             *new(p) Storage(Data()),
1251             flex_string_details::Shallow());
1252         *Data().begin() = 1;
1253     }
1254 
1255 public:
CowString(const CowString & s)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     }
1271 
CowString(const allocator_type & a)1272     CowString(const allocator_type& a)
1273     {
1274         new(buf_) Storage(1, 1, a);
1275     }
1276 
CowString(const E * s,size_type len,const allocator_type & a)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 
CowString(size_type len,E c,const allocator_type & a)1288     CowString(size_type len, E c, const allocator_type& a)
1289     {
1290         new(buf_) Storage(len + 1, c, a);
1291         Refs() = 1;
1292     }
1293 
operator =(const CowString & rhs)1294     CowString& operator=(const CowString& rhs)
1295     {
1296 //        CowString(rhs).swap(*this);
1297         if (--Refs() == 0)
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 
~CowString()1314     ~CowString()
1315     {
1316         BOOST_ASSERT(Data().size() > 0);
1317         if (--Refs() == 0)
1318             Data().~Storage();
1319     }
1320 
begin()1321     iterator begin()
1322     {
1323         BOOST_ASSERT(Data().size() > 0);
1324         MakeUnique();
1325         return Data().begin() + 1;
1326     }
1327 
begin() const1328     const_iterator begin() const
1329     {
1330         BOOST_ASSERT(Data().size() > 0);
1331         return Data().begin() + 1;
1332     }
1333 
end()1334     iterator end()
1335     {
1336         MakeUnique();
1337         return Data().end();
1338     }
1339 
end() const1340     const_iterator end() const
1341     {
1342         return Data().end();
1343     }
1344 
size() const1345     size_type size() const
1346     {
1347         BOOST_ASSERT(Data().size() > 0);
1348         return Data().size() - 1;
1349     }
1350 
max_size() const1351     size_type max_size() const
1352     {
1353         BOOST_ASSERT(Data().max_size() > 0);
1354         return Data().max_size() - 1;
1355     }
1356 
capacity() const1357     size_type capacity() const
1358     {
1359         BOOST_ASSERT(Data().capacity() > 0);
1360         return Data().capacity() - 1;
1361     }
1362 
resize(size_type n,E c)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>
append(FwdIterator b,FwdIterator e)1371     void append(FwdIterator b, FwdIterator e)
1372     {
1373         MakeUnique();
1374         Data().append(b, e);
1375     }
1376 
reserve(size_type res_arg)1377     void reserve(size_type res_arg)
1378     {
1379         if (capacity() > res_arg) return;
1380         MakeUnique();
1381         Data().reserve(res_arg + 1);
1382     }
1383 
swap(CowString & rhs)1384     void swap(CowString& rhs)
1385     {
1386         Data().swap(rhs.Data());
1387     }
1388 
c_str() const1389     const E* c_str() const
1390     {
1391         BOOST_ASSERT(Data().size() > 0);
1392         return Data().c_str() + 1;
1393     }
1394 
data() const1395     const E* data() const
1396     {
1397         BOOST_ASSERT(Data().size() > 0);
1398         return Data().data() + 1;
1399     }
1400 
get_allocator() const1401     allocator_type get_allocator() const
1402     {
1403         return Data().get_allocator();
1404     }
1405 };
1406 
1407 ////////////////////////////////////////////////////////////////////////////////
1408 // class template flex_string
1409 // a std::basic_string compatible implementation
1410 // Uses a Storage policy
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>
Enforce(bool condition,Exception *,const char * msg)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
Sane() const1430     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     {
Invariantboost::wave::util::flex_string::Invariant1445         Invariant(const flex_string& s) : s_(s)
1446         {
1447             BOOST_ASSERT(s_.Sane());
1448         }
~Invariantboost::wave::util::flex_string::Invariant1449         ~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;
1466 
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;
1471 
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:
Min(size_type lhs,size_type rhs)1481     static size_type Min(size_type lhs, size_type rhs)
1482     { return lhs < rhs ? lhs : rhs; }
Procust(size_type & n,size_type nmax)1483     static void Procust(size_type& n, size_type nmax)
1484     { if (n > nmax) n = nmax; }
1485 
1486 public:
1487     // 21.3.1 construct/copy/destroy
flex_string(const A & a=A ())1488     explicit flex_string(const A& a = A())
1489     : Storage(a)
1490     {}
1491 
flex_string(const flex_string & str)1492     flex_string(const flex_string& str)
1493     : Storage(str)
1494     {
1495     }
1496 
flex_string(const flex_string & str,size_type pos,size_type n=npos,const A & a=A ())1497     flex_string(const flex_string& str, size_type pos,
1498         size_type n = npos, const A& a = A())
1499     : Storage(a)
1500     {
1501         Enforce(pos <= str.size(), (std::out_of_range*)0, "");
1502         assign(str, pos, n);
1503     }
1504 
flex_string(const value_type * s,const A & a=A ())1505     flex_string(const value_type* s, const A& a = A())
1506     : Storage(s, traits_type::length(s), a)
1507     {}
1508 
flex_string(const value_type * s,size_type n,const A & a=A ())1509     flex_string(const value_type* s, size_type n, const A& a = A())
1510     : Storage(s, n, a)
1511     {}
1512 
flex_string(size_type n,value_type c,const A & a=A ())1513     flex_string(size_type n, value_type c, const A& a = A())
1514     : Storage(n, c, a)
1515     {}
1516 
1517     template <class InputIterator>
flex_string(InputIterator begin,InputIterator end,const A & a=A ())1518     flex_string(InputIterator begin, InputIterator end, const A& a = A())
1519     : Storage(a)
1520     {
1521         assign(begin, end);
1522     }
1523 
~flex_string()1524     ~flex_string()
1525     {}
1526 
operator =(const flex_string & str)1527     flex_string& operator=(const flex_string& str)
1528     {
1529         if (this != &str) {
1530             Storage& s = *this;
1531             s = str;
1532         }
1533         return *this;
1534     }
1535 
operator =(const value_type * s)1536     flex_string& operator=(const value_type* s)
1537     {
1538         assign(s);
1539         return *this;
1540     }
1541 
operator =(value_type c)1542     flex_string& operator=(value_type c)
1543     {
1544         assign(1, c);
1545         return *this;
1546     }
1547 
1548     // 21.3.2 iterators:
begin()1549     iterator begin()
1550     { return Storage::begin(); }
1551 
begin() const1552     const_iterator begin() const
1553     { return Storage::begin(); }
1554 
end()1555     iterator end()
1556     { return Storage::end(); }
1557 
end() const1558     const_iterator end() const
1559     { return Storage::end(); }
1560 
rbegin()1561     reverse_iterator rbegin()
1562     { return reverse_iterator(end()); }
1563 
rbegin() const1564     const_reverse_iterator rbegin() const
1565     { return const_reverse_iterator(end()); }
1566 
rend()1567     reverse_iterator rend()
1568     { return reverse_iterator(begin()); }
1569 
rend() const1570     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
1575     //  the Boost.Serialization library
back()1576     value_type & back() { return *(begin()+size()-1); }
back() const1577     value_type const& back() const { return *(begin()+size()-1); }
1578 #endif
1579 
1580     // 21.3.3 capacity:
size() const1581     size_type size() const
1582     { return Storage::size(); }
1583 
length() const1584     size_type length() const
1585     { return size(); }
1586 
max_size() const1587     size_type max_size() const
1588     { return Storage::max_size(); }
1589 
resize(size_type n,value_type c)1590     void resize(size_type n, value_type c)
1591     { Storage::resize(n, c); }
1592 
resize(size_type n)1593     void resize(size_type n)
1594     { resize(n, value_type()); }
1595 
capacity() const1596     size_type capacity() const
1597     { return Storage::capacity(); }
1598 
reserve(size_type res_arg=0)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     }
1604 
clear()1605     void clear()
1606     { resize(0); }
1607 
empty() const1608     bool empty() const
1609     { return size() == 0; }
1610 
1611     // 21.3.4 element access:
operator [](size_type pos) const1612     const_reference operator[](size_type pos) const
1613     { return *(begin() + pos); }
1614 
operator [](size_type pos)1615     reference operator[](size_type pos)
1616     { return *(begin() + pos); }
1617 
at(size_type n) const1618     const_reference at(size_type n) const
1619     {
1620         Enforce(n < size(), (std::out_of_range*)0, "");
1621         return (*this)[n];
1622     }
1623 
at(size_type n)1624     reference at(size_type n)
1625     {
1626         Enforce(n < size(), (std::out_of_range*)0, "");
1627         return (*this)[n];
1628     }
1629 
1630     // 21.3.5 modifiers:
operator +=(const flex_string & str)1631     flex_string& operator+=(const flex_string& str)
1632     { return append(str); }
1633 
operator +=(const value_type * s)1634     flex_string& operator+=(const value_type* s)
1635     { return append(s); }
1636 
operator +=(value_type c)1637     flex_string& operator+=(value_type c)
1638     {
1639         push_back(c);
1640         return *this;
1641     }
1642 
append(const flex_string & str)1643     flex_string& append(const flex_string& str)
1644     { return append(str, 0, npos); }
1645 
append(const flex_string & str,const size_type pos,size_type n)1646     flex_string& append(const flex_string& str, const size_type pos,
1647         size_type n)
1648     {
1649         const size_type sz = str.size();
1650         Enforce(pos <= sz, (std::out_of_range*)0, "");
1651         Procust(n, sz - pos);
1652         return append(str.c_str() + pos, n);
1653     }
1654 
append(const value_type * s,const size_type n)1655     flex_string& append(const value_type* s, const size_type n)
1656     {
1657 #ifndef NDEBUG
1658         Invariant checker(*this);
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         }
1666         Storage::append(s, s+ n);
1667         return *this;
1668     }
1669 
append(const value_type * s)1670     flex_string& append(const value_type* s)
1671     { return append(s, traits_type::length(s)); }
1672 
append(size_type n,value_type c)1673     flex_string& append(size_type n, value_type c)
1674     {
1675         resize(size() + n, c);
1676         return *this;
1677     }
1678 
1679     template<class InputIterator>
append(InputIterator first,InputIterator last)1680     flex_string& append(InputIterator first, InputIterator last)
1681     {
1682         insert(end(), first, last);
1683         return *this;
1684     }
1685 
push_back(value_type c)1686     void push_back(value_type c)
1687     {
1688         const size_type cap = capacity();
1689         if (size() == cap)
1690         {
1691             reserve(cap << 1u);
1692         }
1693         Storage::append(&c, &c + 1);
1694     }
1695 
assign(const flex_string & str)1696     flex_string& assign(const flex_string& str)
1697     {
1698         if (&str == this) return *this;
1699         return assign(str.data(), str.size());
1700     }
1701 
assign(const flex_string & str,size_type pos,size_type n)1702     flex_string& assign(const flex_string& str, size_type pos,
1703         size_type n)
1704     {
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     }
1710 
assign(const value_type * s,size_type n)1711     flex_string& assign(const value_type* s, size_type n)
1712     {
1713 #ifndef NDEBUG
1714         Invariant checker(*this);
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     }
1729 
assign(const value_type * s)1730     flex_string& assign(const value_type* s)
1731     { return assign(s, traits_type::length(s)); }
1732 
1733     template <class ItOrLength, class ItOrChar>
assign(ItOrLength first_or_n,ItOrChar last_or_c)1734     flex_string& assign(ItOrLength first_or_n, ItOrChar last_or_c)
1735     { return replace(begin(), end(), first_or_n, last_or_c); }
1736 
insert(size_type pos1,const flex_string & str)1737     flex_string& insert(size_type pos1, const flex_string& str)
1738     { return insert(pos1, str.data(), str.size()); }
1739 
insert(size_type pos1,const flex_string & str,size_type pos2,size_type n)1740     flex_string& insert(size_type pos1, const flex_string& str,
1741         size_type pos2, size_type n)
1742     {
1743         Enforce(pos2 <= str.length(), (std::out_of_range*)0, "");
1744         Procust(n, str.length() - pos2);
1745         return insert(pos1, str.data() + pos2, n);
1746     }
1747 
insert(size_type pos,const value_type * s,size_type n)1748     flex_string& insert(size_type pos, const value_type* s, size_type n)
1749     {
1750         Enforce(pos <= length(), (std::out_of_range*)0, "");
1751         insert(begin() + pos, s, s + n);
1752         return *this;
1753     }
1754 
insert(size_type pos,const value_type * s)1755     flex_string& insert(size_type pos, const value_type* s)
1756     { return insert(pos, s, traits_type::length(s)); }
1757 
insert(size_type pos,size_type n,value_type c)1758     flex_string& insert(size_type pos, size_type n, value_type c)
1759     {
1760         Enforce(pos <= length(), (std::out_of_range*)0, "");
1761         insert(begin() + pos, n, c);
1762         return *this;
1763     }
1764 
insert(iterator p,value_type c=value_type ())1765     iterator insert(iterator p, value_type c = value_type())
1766     {
1767         const size_type pos = p - begin();
1768         insert(pos, &c, 1);
1769         return begin() + pos;
1770     }
1771 
1772 private:
1773     // Care must be taken when dereferencing some iterator types.
1774     //
1775     // Users can implement this function in their namespace if their storage
1776     // uses a special iterator type, the function will be found through ADL.
1777     template<class Iterator>
1778     const typename std::iterator_traits<Iterator>::value_type*
DereferenceValidIterator(Iterator it) const1779     DereferenceValidIterator(Iterator it) const
1780     {
1781         return &*it;
1782     }
1783 
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
1786     // create name clashes.
1787     template<typename Iterator>
1788     const typename std::iterator_traits<Iterator>::value_type*
DereferenceValidIterator(std::reverse_iterator<Iterator> it) const1789     DereferenceValidIterator(std::reverse_iterator<Iterator> it) const
1790     {
1791         return &*--it;
1792     }
1793 
1794     // Determine if the range aliases the current string.
1795     //
1796     // This method cannot be const because calling begin/end on copy-on-write
1797     // implementations must have side effects.
1798     // A const version wouldn't make the string unique through this call.
1799     template<class Iterator>
IsAliasedRange(Iterator beginIterator,Iterator endIterator)1800     bool IsAliasedRange(Iterator beginIterator, Iterator endIterator)
1801     {
1802         if(!empty() && beginIterator != endIterator)
1803         {
1804             typedef const typename std::iterator_traits<Iterator>::value_type *
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 
InsertImplDiscr(iterator p,size_type n,value_type c,Selector<1>)1820     flex_string& InsertImplDiscr(iterator p,
1821         size_type n, value_type c, Selector<1>)
1822     {
1823 #ifndef NDEBUG
1824         Invariant checker(*this);
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.
1832             // The characters that are pushed back need to be moved because
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());
1837             flex_string_details::pod_move(begin + insertOffset,
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.
1844             // The characters that are pushed back can simply be copied since
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());
1849             flex_string_details::pod_copy(begin + insertOffset,
1850                 begin + originalSize, begin + insertOffset + n);
1851             std::fill(begin + insertOffset, begin + originalSize, c);
1852         }
1853         return *this;
1854     }
1855 
1856     template<class InputIterator>
InsertImplDiscr(iterator i,InputIterator b,InputIterator e,Selector<0>)1857     flex_string& InsertImplDiscr(iterator i,
1858         InputIterator b, InputIterator e, Selector<0>)
1859     {
1860         InsertImpl(i, b, e,
1861             typename std::iterator_traits<InputIterator>::iterator_category());
1862         return *this;
1863     }
1864 
1865     template <class FwdIterator>
InsertImpl(iterator i,FwdIterator s1,FwdIterator s2,std::forward_iterator_tag)1866     void InsertImpl(iterator i,
1867         FwdIterator s1, FwdIterator s2, std::forward_iterator_tag)
1868     {
1869         if(s1 == s2)
1870         {
1871             // Insert an empty range.
1872             return;
1873         }
1874 
1875         if(IsAliasedRange(s1, s2))
1876         {
1877             // The source range is contained in the current string, copy it
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
1886         Invariant checker(*this);
1887 #endif
1888         const size_type pos = i - begin();
1889         const typename std::iterator_traits<FwdIterator>::difference_type n2 =
1890             std::distance(s1, s2);
1891 
1892         BOOST_ASSERT(n2 >= 0);
1893         using namespace flex_string_details;
1894         BOOST_ASSERT(pos <= size());
1895 
1896         const typename std::iterator_traits<FwdIterator>::difference_type maxn2 =
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);
1909             std::copy(reverse_iterator(tailBegin), reverse_iterator(i),
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>
InsertImpl(iterator insertPosition,InputIterator inputBegin,InputIterator inputEnd,std::input_iterator_tag)1926     void InsertImpl(iterator insertPosition,
1927         InputIterator inputBegin, InputIterator inputEnd,
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>
insert(iterator p,ItOrLength first_or_n,ItOrChar last_or_c)1941     void insert(iterator p, ItOrLength first_or_n, ItOrChar last_or_c)
1942     {
1943         Selector<std::numeric_limits<ItOrLength>::is_specialized> sel;
1944         InsertImplDiscr(p, first_or_n, last_or_c, sel);
1945     }
1946 
erase(size_type pos=0,size_type n=npos)1947     flex_string& erase(size_type pos = 0, size_type n = npos)
1948     {
1949 #ifndef NDEBUG
1950         Invariant checker(*this);
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     }
1958 
erase(iterator position)1959     iterator erase(iterator position)
1960     {
1961         const size_type pos(position - begin());
1962         erase(pos, 1);
1963         return begin() + pos;
1964     }
1965 
erase(iterator first,iterator last)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
replace(size_type pos1,size_type n1,const flex_string & str)1974     flex_string& replace(size_type pos1, size_type n1, const flex_string& str)
1975     { return replace(pos1, n1, str, 0, npos); }
1976 
1977     // Replaces at most n1 chars of *this, starting with pos1,
1978     // with at most n2 chars of str starting with pos2
replace(size_type pos1,size_type n1,const flex_string & str,size_type pos2,size_type n2)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, "");
1983         return replace(pos1, n1, str.data() + pos2,
1984             Min(n2, str.size() - pos2));
1985     }
1986 
1987     // Replaces at most n1 chars of *this, starting with pos, with chars from s
replace(size_type pos,size_type n1,const value_type * 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)); }
1990 
1991     // Replaces at most n1 chars of *this, starting with pos, with n2 occurences of c
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>
replace(size_type pos,size_type n1,StrOrLength s_or_n2,NumOrChar n_or_c)1997     flex_string& replace(size_type pos, size_type n1,
1998         StrOrLength s_or_n2, NumOrChar n_or_c)
1999     {
2000 #ifndef NDEBUG
2001         Invariant checker(*this);
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 
replace(iterator i1,iterator i2,const flex_string & str)2009     flex_string& replace(iterator i1, iterator i2, const flex_string& str)
2010     { return replace(i1, i2, str.c_str(), str.length()); }
2011 
replace(iterator i1,iterator i2,const value_type * s)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:
ReplaceImplDiscr(iterator i1,iterator i2,const value_type * s,size_type n,Selector<2>)2016     flex_string& ReplaceImplDiscr(iterator i1, iterator i2,
2017         const value_type* s, size_type n, Selector<2>)
2018     {
2019         BOOST_ASSERT(i1 <= i2);
2020         BOOST_ASSERT(begin() <= i1 && i1 <= end());
2021         BOOST_ASSERT(begin() <= i2 && i2 <= end());
2022         return replace(i1, i2, s, s + n);
2023     }
2024 
ReplaceImplDiscr(iterator i1,iterator i2,size_type n2,value_type c,Selector<1>)2025     flex_string& ReplaceImplDiscr(iterator i1, iterator i2,
2026         size_type n2, value_type c, Selector<1>)
2027     {
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>
ReplaceImplDiscr(iterator i1,iterator i2,InputIterator b,InputIterator e,Selector<0>)2043     flex_string& ReplaceImplDiscr(iterator i1, iterator i2,
2044         InputIterator b, InputIterator e, Selector<0>)
2045     {
2046         ReplaceImpl(i1, i2, b, e,
2047             typename std::iterator_traits<InputIterator>::iterator_category());
2048         return *this;
2049     }
2050 
2051     template <class FwdIterator>
ReplaceImpl(iterator i1,iterator i2,FwdIterator s1,FwdIterator s2,std::forward_iterator_tag)2052     void ReplaceImpl(iterator i1, iterator i2,
2053         FwdIterator s1, FwdIterator s2, std::forward_iterator_tag)
2054     {
2055 #ifndef NDEBUG
2056         Invariant checker(*this);
2057 #endif
2058         const typename std::iterator_traits<iterator>::difference_type n1 =
2059             i2 - i1;
2060         BOOST_ASSERT(n1 >= 0);
2061         const typename std::iterator_traits<FwdIterator>::difference_type n2 =
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>
ReplaceImpl(iterator i1,iterator i2,InputIterator b,InputIterator e,std::input_iterator_tag)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>
replace(iterator i1,iterator i2,T1 first_or_n_or_s,T2 last_or_c_or_n)2101     flex_string& replace(iterator i1, iterator i2,
2102         T1 first_or_n_or_s, T2 last_or_c_or_n)
2103     {
2104         const bool
2105             num1 = std::numeric_limits<T1>::is_specialized,
2106             num2 = std::numeric_limits<T2>::is_specialized;
2107         return ReplaceImplDiscr(i1, i2, first_or_n_or_s, last_or_c_or_n,
2108             Selector<num1 ? (num2 ? 1 : -1) : (num2 ? 2 : 0)>());
2109     }
2110 
copy(value_type * s,size_type n,size_type pos=0) const2111     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);
2115 
2116         flex_string_details::pod_copy(
2117             &*begin() + pos,
2118             &*begin() + pos + n,
2119             s);
2120         return n;
2121     }
2122 
swap(flex_string & rhs)2123     void swap(flex_string& rhs)
2124     {
2125         Storage& srhs = rhs;
2126         this->Storage::swap(srhs);
2127     }
2128 
2129     // 21.3.6 string operations:
c_str() const2130     const value_type* c_str() const
2131     { return Storage::c_str(); }
2132 
data() const2133     const value_type* data() const
2134     { return Storage::data(); }
2135 
get_allocator() const2136     allocator_type get_allocator() const
2137     { return Storage::get_allocator(); }
2138 
find(const flex_string & str,size_type pos=0) const2139     size_type find(const flex_string& str, size_type pos = 0) const
2140     { return find(str.data(), pos, str.length()); }
2141 
find(const value_type * s,size_type pos,size_type n) const2142     size_type find (const value_type* s, size_type pos, size_type n) const
2143     {
2144         const size_type size_(size());
2145         if (n + pos > size_)
2146             return npos;
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     }
2156 
find(const value_type * s,size_type pos=0) const2157     size_type find (const value_type* s, size_type pos = 0) const
2158     { return find(s, pos, traits_type::length(s)); }
2159 
find(value_type c,size_type pos=0) const2160     size_type find (value_type c, size_type pos = 0) const
2161     { return find(&c, pos, 1); }
2162 
rfind(const flex_string & str,size_type pos=npos) const2163     size_type rfind(const flex_string& str, size_type pos = npos) const
2164     { return rfind(str.c_str(), pos, str.length()); }
2165 
rfind(const value_type * s,size_type pos,size_type n) const2166     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         {
2175             if (traits_type::eq(*i, *s)
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 
rfind(const value_type * s,size_type pos=npos) const2185     size_type rfind(const value_type* s, size_type pos = npos) const
2186     { return rfind(s, pos, traits_type::length(s)); }
2187 
rfind(value_type c,size_type pos=npos) const2188     size_type rfind(value_type c, size_type pos = npos) const
2189     { return rfind(&c, pos, 1); }
2190 
find_first_of(const flex_string & str,size_type pos=0) const2191     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()); }
2193 
find_first_of(const value_type * s,size_type pos,size_type n) const2194     size_type find_first_of(const value_type* s,
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     }
2209 
find_first_of(const value_type * s,size_type pos=0) const2210     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)); }
2212 
find_first_of(value_type c,size_type pos=0) const2213     size_type find_first_of(value_type c, size_type pos = 0) const
2214     { return find_first_of(&c, pos, 1); }
2215 
find_last_of(const flex_string & str,size_type pos=npos) const2216     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()); }
2219 
find_last_of(const value_type * s,size_type pos,size_type n) const2220     size_type find_last_of (const value_type* s, size_type pos,
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 
find_last_of(const value_type * s,size_type pos=npos) const2239     size_type find_last_of (const value_type* s,
2240         size_type pos = npos) const
2241     { return find_last_of(s, pos, traits_type::length(s)); }
2242 
find_last_of(value_type c,size_type pos=npos) const2243     size_type find_last_of (value_type c, size_type pos = npos) const
2244     { return find_last_of(&c, pos, 1); }
2245 
find_first_not_of(const flex_string & str,size_type pos=0) const2246     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()); }
2249 
find_first_not_of(const value_type * s,size_type pos,size_type n) const2250     size_type find_first_not_of(const value_type* s, size_type pos,
2251         size_type n) const
2252     {
2253         if (pos < length())
2254         {
2255             const_iterator
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     }
2268 
find_first_not_of(const value_type * s,size_type pos=0) const2269     size_type find_first_not_of(const value_type* s,
2270         size_type pos = 0) const
2271     { return find_first_not_of(s, pos, traits_type::length(s)); }
2272 
find_first_not_of(value_type c,size_type pos=0) const2273     size_type find_first_not_of(value_type c, size_type pos = 0) const
2274     { return find_first_not_of(&c, pos, 1); }
2275 
find_last_not_of(const flex_string & str,size_type pos=npos) const2276     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()); }
2279 
find_last_not_of(const value_type * s,size_type pos,size_type n) const2280     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 
find_last_not_of(const value_type * s,size_type pos=npos) const2299     size_type find_last_not_of(const value_type* s,
2300         size_type pos = npos) const
2301     { return find_last_not_of(s, pos, traits_type::length(s)); }
2302 
find_last_not_of(value_type c,size_type pos=npos) const2303     size_type find_last_not_of (value_type c, size_type pos = npos) const
2304     { return find_last_not_of(&c, pos, 1); }
2305 
substr(size_type pos=0,size_type n=npos) const2306     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 
compare(const flex_string & str) const2312     std::ptrdiff_t compare(const flex_string& str) const
2313     {
2314         // FIX due to Goncalo N M de Carvalho July 18, 2005
2315         return compare(0, size(), str);
2316     }
2317 
compare(size_type pos1,size_type n1,const flex_string & str) const2318     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()); }
2321 
2322     // FIX to compare: added the TC
2323     // (http://www.comeaucomputing.com/iso/lwg-defects.html number 5)
2324     // Thanks to Caleb Epstein for the fix
compare(size_type pos1,size_type n1,const value_type * s) const2325     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     }
2330 
compare(size_type pos1,size_type n1,const value_type * s,size_type n2) const2331     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 
compare(size_type pos1,size_type n1,const flex_string & str,size_type pos2,size_type n2) const2340     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 
compare(const value_type * s) const2348     std::ptrdiff_t compare(const value_type* s) const
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;
2355     }
2356 };
2357 
2358 // non-member functions
2359 template <typename E, class T, class A, class S>
operator +(const flex_string<E,T,A,S> & lhs,const flex_string<E,T,A,S> & rhs)2360 flex_string<E, T, A, S> operator+(const flex_string<E, T, A, S>& lhs,
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>
operator +(const typename flex_string<E,T,A,S>::value_type * lhs,const flex_string<E,T,A,S> & rhs)2370 flex_string<E, T, A, S> operator+(const typename flex_string<E, T, A, S>::value_type* lhs,
2371     const flex_string<E, T, A, S>& rhs)
2372 {
2373     flex_string<E, T, A, S> result;
2374     const typename flex_string<E, T, A, S>::size_type len =
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>
operator +(typename flex_string<E,T,A,S>::value_type lhs,const flex_string<E,T,A,S> & rhs)2382 flex_string<E, T, A, S> operator+(
2383     typename flex_string<E, T, A, S>::value_type lhs,
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>
operator +(const flex_string<E,T,A,S> & lhs,const typename flex_string<E,T,A,S>::value_type * rhs)2394 flex_string<E, T, A, S> operator+(const flex_string<E, T, A, S>& lhs,
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>
operator +(const flex_string<E,T,A,S> & lhs,typename flex_string<E,T,A,S>::value_type rhs)2408 flex_string<E, T, A, S> operator+(const flex_string<E, T, A, S>& lhs,
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>
operator ==(const flex_string<E,T,A,S> & lhs,const flex_string<E,T,A,S> & rhs)2419 inline bool operator==(const flex_string<E, T, A, S>& lhs,
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>
operator ==(const typename flex_string<E,T,A,S>::value_type * lhs,const flex_string<E,T,A,S> & rhs)2424 inline bool operator==(const typename flex_string<E, T, A, S>::value_type* lhs,
2425     const flex_string<E, T, A, S>& rhs)
2426 { return rhs == lhs; }
2427 
2428 template <typename E, class T, class A, class S>
operator ==(const flex_string<E,T,A,S> & lhs,const typename flex_string<E,T,A,S>::value_type * rhs)2429 inline bool operator==(const flex_string<E, T, A, S>& lhs,
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>
operator !=(const flex_string<E,T,A,S> & lhs,const flex_string<E,T,A,S> & rhs)2434 inline bool operator!=(const flex_string<E, T, A, S>& lhs,
2435     const flex_string<E, T, A, S>& rhs)
2436 { return !(lhs == rhs); }
2437 
2438 template <typename E, class T, class A, class S>
operator !=(const typename flex_string<E,T,A,S>::value_type * lhs,const flex_string<E,T,A,S> & rhs)2439 inline bool operator!=(const typename flex_string<E, T, A, S>::value_type* lhs,
2440     const flex_string<E, T, A, S>& rhs)
2441 { return !(lhs == rhs); }
2442 
2443 template <typename E, class T, class A, class S>
operator !=(const flex_string<E,T,A,S> & lhs,const typename flex_string<E,T,A,S>::value_type * rhs)2444 inline bool operator!=(const flex_string<E, T, A, S>& lhs,
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>
operator <(const flex_string<E,T,A,S> & lhs,const flex_string<E,T,A,S> & rhs)2449 inline bool operator<(const flex_string<E, T, A, S>& lhs,
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>
operator <(const flex_string<E,T,A,S> & lhs,const typename flex_string<E,T,A,S>::value_type * rhs)2454 inline bool operator<(const flex_string<E, T, A, S>& lhs,
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>
operator <(const typename flex_string<E,T,A,S>::value_type * lhs,const flex_string<E,T,A,S> & rhs)2459 inline bool operator<(const typename flex_string<E, T, A, S>::value_type* lhs,
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>
operator >(const flex_string<E,T,A,S> & lhs,const flex_string<E,T,A,S> & rhs)2464 inline bool operator>(const flex_string<E, T, A, S>& lhs,
2465     const flex_string<E, T, A, S>& rhs)
2466 { return rhs < lhs; }
2467 
2468 template <typename E, class T, class A, class S>
operator >(const flex_string<E,T,A,S> & lhs,const typename flex_string<E,T,A,S>::value_type * rhs)2469 inline bool operator>(const flex_string<E, T, A, S>& lhs,
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>
operator >(const typename flex_string<E,T,A,S>::value_type * lhs,const flex_string<E,T,A,S> & rhs)2474 bool operator>(const typename flex_string<E, T, A, S>::value_type* lhs,
2475     const flex_string<E, T, A, S>& rhs)
2476 { return rhs < lhs; }
2477 
2478 template <typename E, class T, class A, class S>
operator <=(const flex_string<E,T,A,S> & lhs,const flex_string<E,T,A,S> & rhs)2479 inline bool operator<=(const flex_string<E, T, A, S>& lhs,
2480     const flex_string<E, T, A, S>& rhs)
2481 { return !(rhs < lhs); }
2482 
2483 template <typename E, class T, class A, class S>
operator <=(const flex_string<E,T,A,S> & lhs,const typename flex_string<E,T,A,S>::value_type * rhs)2484 inline bool operator<=(const flex_string<E, T, A, S>& lhs,
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>
operator <=(const typename flex_string<E,T,A,S>::value_type * lhs,const flex_string<E,T,A,S> & rhs)2489 bool operator<=(const typename flex_string<E, T, A, S>::value_type* lhs,
2490     const flex_string<E, T, A, S>& rhs)
2491 { return !(rhs < lhs); }
2492 
2493 template <typename E, class T, class A, class S>
operator >=(const flex_string<E,T,A,S> & lhs,const flex_string<E,T,A,S> & rhs)2494 bool operator>=(const flex_string<E, T, A, S>& lhs,
2495     const flex_string<E, T, A, S>& rhs)
2496 { return !(lhs < rhs); }
2497 
2498 template <typename E, class T, class A, class S>
operator >=(const flex_string<E,T,A,S> & lhs,const typename flex_string<E,T,A,S>::value_type * rhs)2499 bool operator>=(const flex_string<E, T, A, S>& lhs,
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>
operator >=(const typename flex_string<E,T,A,S>::value_type * lhs,const flex_string<E,T,A,S> & rhs)2504 inline bool operator>=(const typename flex_string<E, T, A, S>::value_type* lhs,
2505     const flex_string<E, T, A, S>& rhs)
2506 { return !(lhs < rhs); }
2507 
2508 template <typename E, class T, class A, class S>
swap(flex_string<E,T,A,S> & lhs,flex_string<E,T,A,S> & rhs)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>
2516 inline std::basic_istream<typename flex_string<E, T, A, S>::value_type,
2517     typename flex_string<E, T, A, S>::traits_type>&
2518 operator>>(
2519     std::basic_istream<typename flex_string<E, T, A, S>::value_type,
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>&
operator <<(std::basic_ostream<typename flex_string<E,T,A,S>::value_type,typename flex_string<E,T,A,S>::traits_type> & os,const flex_string<E,T,A,S> & str)2526 operator<<(
2527     std::basic_ostream<typename flex_string<E, T, A, S>::value_type,
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>
2563 inline void save(Archive & ar,
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_
2605