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