Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:53:42

0001 /*=============================================================================
0002     Boost.Wave: A Standard compliant C++ preprocessor library
0003     http://www.boost.org/
0004 
0005     Copyright (c) 2001 by Andrei Alexandrescu. Distributed under the Boost
0006     Software License, Version 1.0. (See accompanying file
0007     LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0008 =============================================================================*/
0009 
0010 // This code is taken from:
0011 // Andrei Alexandrescu, Generic<Programming>: A Policy-Based basic_string
0012 // Implementation. http://www.cuj.com/documents/s=7994/cujcexp1906alexandr/
0013 //
0014 // #HK030306:
0015 //      - Moved into the namespace boost::wave::util
0016 //      - Added a bunch of missing typename(s)
0017 //      - Integrated with boost config
0018 //      - Added a missing header include
0019 //      - Added special constructors and operator= to allow CowString to be
0020 //        a real COW-string (removed unnecessary data copying)
0021 //      - Fixed a string terminating bug in append
0022 //
0023 // #HK040109:
0024 //      - Incorporated the changes from Andrei's latest version of this class
0025 //
0026 // #HK070307:
0027 //      - Once again incorporated the changes from Andrei's latest version of
0028 //        this class
0029 //
0030 // #HK090523:
0031 //      - Incorporated the changes from latest version of flex_string as
0032 //        maintained in Loki
0033 //
0034 // #HK130910:
0035 //      - Removed the getline implementation which was borrowed from the SGI
0036 //        STL as the license for this code is not compatible with Boost.
0037 
0038 #ifndef BOOST_FLEX_STRING_INC_
0039 #define BOOST_FLEX_STRING_INC_
0040 
0041 /*
0042 ////////////////////////////////////////////////////////////////////////////////
0043 template <typename E, class A = @>
0044 class StoragePolicy
0045 {
0046     typedef E value_type;
0047     typedef @ iterator;
0048     typedef @ const_iterator;
0049     typedef A allocator_type;
0050     typedef @ size_type;
0051 
0052     StoragePolicy(const StoragePolicy& s);
0053     StoragePolicy(const A&);
0054     StoragePolicy(const E* s, size_type len, const A&);
0055     StoragePolicy(size_type len, E c, const A&);
0056     ~StoragePolicy();
0057 
0058     iterator begin();
0059     const_iterator begin() const;
0060     iterator end();
0061     const_iterator end() const;
0062 
0063     size_type size() const;
0064     size_type max_size() const;
0065     size_type capacity() const;
0066 
0067     void reserve(size_type res_arg);
0068 
0069     void append(const E* s, size_type sz);
0070 
0071     template <class InputIterator>
0072     void append(InputIterator b, InputIterator e);
0073 
0074     void resize(size_type newSize, E fill);
0075 
0076     void swap(StoragePolicy& rhs);
0077 
0078     const E* c_str() const;
0079     const E* data() const;
0080 
0081     A get_allocator() const;
0082 };
0083 ////////////////////////////////////////////////////////////////////////////////
0084 */
0085 
0086 #include <boost/config.hpp>
0087 #include <boost/assert.hpp>
0088 #include <boost/throw_exception.hpp>
0089 
0090 #include <boost/core/allocator_access.hpp>
0091 #include <boost/iterator/reverse_iterator.hpp>
0092 
0093 #include <boost/wave/wave_config.hpp>
0094 #if BOOST_WAVE_SERIALIZATION != 0
0095 #include <boost/serialization/serialization.hpp>
0096 #include <boost/serialization/split_free.hpp>
0097 #include <boost/serialization/collections_save_imp.hpp>
0098 #include <boost/serialization/collections_load_imp.hpp>
0099 #define BOOST_WAVE_FLEX_STRING_SERIALIZATION_HACK 1
0100 #endif
0101 
0102 #include <memory>
0103 #include <new>
0104 #include <vector>
0105 #include <algorithm>
0106 #include <functional>
0107 #include <limits>
0108 #include <stdexcept>
0109 #include <ios>
0110 
0111 #include <cstddef>
0112 #include <cstring>
0113 #include <cstdlib>
0114 
0115 // this must occur after all of the includes and before any code appears
0116 #ifdef BOOST_HAS_ABI_HEADERS
0117 #include BOOST_ABI_PREFIX
0118 #endif
0119 
0120 ///////////////////////////////////////////////////////////////////////////////
0121 namespace boost {
0122 namespace wave {
0123 namespace util {
0124 
0125 namespace flex_string_details
0126 {
0127     template <class InIt, class OutIt>
0128     OutIt copy_n(InIt b,
0129         typename std::iterator_traits<InIt>::difference_type n, OutIt d)
0130     {
0131         for (/**/; n != 0; --n, ++b, ++d)
0132         {
0133             *d = *b;
0134         }
0135         return d;
0136     }
0137 
0138     template <class Pod, class T>
0139     inline void pod_fill(Pod* b, Pod* e, T c)
0140     {
0141         switch ((e - b) & 7)
0142         {
0143         case 0:
0144             while (b != e)
0145             {
0146                 *b = c; ++b; BOOST_FALLTHROUGH;
0147         case 7: *b = c; ++b; BOOST_FALLTHROUGH;
0148         case 6: *b = c; ++b; BOOST_FALLTHROUGH;
0149         case 5: *b = c; ++b; BOOST_FALLTHROUGH;
0150         case 4: *b = c; ++b; BOOST_FALLTHROUGH;
0151         case 3: *b = c; ++b; BOOST_FALLTHROUGH;
0152         case 2: *b = c; ++b; BOOST_FALLTHROUGH;
0153         case 1: *b = c; ++b;
0154             }
0155         }
0156     }
0157 
0158     template <class Pod>
0159     inline void pod_move(const Pod* b, const Pod* e, Pod* d)
0160     {
0161         using namespace std;
0162         memmove(d, b, (e - b) * sizeof(*b));
0163     }
0164 
0165     template <class Pod>
0166     inline Pod* pod_copy(const Pod* b, const Pod* e, Pod* d)
0167     {
0168         const std::size_t s = e - b;
0169         using namespace std;
0170         memcpy(d, b, s * sizeof(*b));
0171         return d + s;
0172     }
0173 
0174     template <typename T> struct get_unsigned
0175     {
0176         typedef T result;
0177     };
0178 
0179     template <> struct get_unsigned<char>
0180     {
0181         typedef unsigned char result;
0182     };
0183 
0184     template <> struct get_unsigned<signed char>
0185     {
0186         typedef unsigned char result;
0187     };
0188 
0189     template <> struct get_unsigned<short int>
0190     {
0191         typedef unsigned short int result;
0192     };
0193 
0194     template <> struct get_unsigned<int>
0195     {
0196         typedef unsigned int result;
0197     };
0198 
0199     template <> struct get_unsigned<long int>
0200     {
0201         typedef unsigned long int result;
0202     };
0203 
0204     enum Shallow {};
0205 }
0206 
0207 template <class T> class mallocator
0208 {
0209 public:
0210     typedef T                 value_type;
0211     typedef value_type*       pointer;
0212     typedef const value_type* const_pointer;
0213     typedef value_type&       reference;
0214     typedef const value_type& const_reference;
0215     typedef std::size_t       size_type;
0216     //typedef unsigned int      size_type;
0217     //typedef std::ptrdiff_t    difference_type;
0218     typedef int               difference_type;
0219 
0220     template <class U>
0221     struct rebind { typedef mallocator<U> other; };
0222 
0223     mallocator() {}
0224     mallocator(const mallocator&) {}
0225     //template <class U>
0226     //mallocator(const mallocator<U>&) {}
0227     ~mallocator() {}
0228 
0229     pointer address(reference x) const { return &x; }
0230     const_pointer address(const_reference x) const
0231     {
0232         return x;
0233     }
0234 
0235     pointer allocate(size_type n, const_pointer = 0)
0236     {
0237         using namespace std;
0238         void* p = malloc(n * sizeof(T));
0239         if (!p) boost::throw_exception(std::bad_alloc());
0240         return static_cast<pointer>(p);
0241     }
0242 
0243     void deallocate(pointer p, size_type)
0244     {
0245         using namespace std;
0246         free(p);
0247     }
0248 
0249     size_type max_size() const
0250     {
0251         return static_cast<size_type>(-1) / sizeof(T);
0252     }
0253 
0254     void construct(pointer p, const value_type& x)
0255     {
0256         new(p) value_type(x);
0257     }
0258 
0259     void destroy(pointer p)
0260     {
0261         p->~value_type();
0262     }
0263 
0264 private:
0265     void operator=(const mallocator&);
0266 };
0267 
0268 template<> class mallocator<void>
0269 {
0270   typedef void        value_type;
0271   typedef void*       pointer;
0272   typedef const void* const_pointer;
0273 
0274   template <class U>
0275   struct rebind { typedef mallocator<U> other; };
0276 };
0277 
0278 template <class T>
0279 inline bool operator==(const mallocator<T>&,
0280                        const mallocator<T>&) {
0281   return true;
0282 }
0283 
0284 template <class T>
0285 inline bool operator!=(const mallocator<T>&,
0286                        const mallocator<T>&) {
0287   return false;
0288 }
0289 
0290 #if defined(BOOST_GCC) && BOOST_GCC >= 40700
0291 // gcc 11.2 fails to deduce below that pData_ never points to emptyString_ if capacity() == 0 and emits warnings like these:
0292 // 'operator delete(void*, unsigned long)' called on unallocated object 'boost::wave::util::SimpleStringStorage<char, std::allocator<char> >::emptyString_' [-Wfree-nonheap-object]
0293 // Unfortunately, suppressing this warning doesn't work, so we have to use __builtin_unreachable() to assert that this never happens.
0294 // __builtin_unreachable is supported since gcc 4.6, -Wfree-nonheap-object is supported since 4.7.
0295 #define BOOST_WAVE_COMPILE_TIME_ASSERT(x) if (!(x)) __builtin_unreachable()
0296 #else
0297 #define BOOST_WAVE_COMPILE_TIME_ASSERT(x)
0298 #endif
0299 
0300 ////////////////////////////////////////////////////////////////////////////////
0301 // class template SimpleStringStorage
0302 // Allocates memory with malloc
0303 ////////////////////////////////////////////////////////////////////////////////
0304 
0305 template <typename E, class A = std::allocator<E> >
0306 class SimpleStringStorage
0307 {
0308     // The "public" below exists because MSVC can't do template typedefs
0309 public:
0310     struct Data
0311     {
0312         Data() : pEnd_(buffer_), pEndOfMem_(buffer_) { buffer_[0] = E(0); }
0313 
0314         E* pEnd_;
0315         E* pEndOfMem_;
0316         E buffer_[1];
0317     };
0318     static const Data emptyString_;
0319 
0320     typedef typename boost::allocator_size_type<A>::type size_type;
0321 
0322 private:
0323     Data* pData_;
0324 
0325     void Init(size_type size, size_type capacity)
0326     {
0327         BOOST_ASSERT(size <= capacity);
0328         if (capacity == 0)
0329         {
0330             pData_ = const_cast<Data*>(&emptyString_);
0331         }
0332         else
0333         {
0334             // 11-17-2000: comment added:
0335             //     No need to allocate (capacity + 1) to
0336             //     accommodate the terminating 0, because Data already
0337             //     has one character in there
0338             pData_ = static_cast<Data*>(
0339                 malloc(sizeof(Data) + capacity * sizeof(E)));
0340             if (!pData_) boost::throw_exception(std::bad_alloc());
0341             pData_->pEnd_ = pData_->buffer_ + size;
0342             pData_->pEndOfMem_ = pData_->buffer_ + capacity;
0343         }
0344     }
0345 
0346 private:
0347     // Warning - this doesn't initialize pData_. Used in reserve()
0348     SimpleStringStorage()
0349     { }
0350 
0351 public:
0352     typedef E value_type;
0353     typedef E* iterator;
0354     typedef const E* const_iterator;
0355     typedef A allocator_type;
0356 
0357     SimpleStringStorage(const SimpleStringStorage& rhs)
0358     {
0359         const size_type sz = rhs.size();
0360         Init(sz, sz);
0361         if (sz) flex_string_details::pod_copy(rhs.begin(), rhs.end(), begin());
0362     }
0363 
0364     SimpleStringStorage(const SimpleStringStorage& s,
0365         flex_string_details::Shallow)
0366         : pData_(s.pData_)
0367     {
0368     }
0369 
0370     SimpleStringStorage(const A&)
0371     { pData_ = const_cast<Data*>(&emptyString_); }
0372 
0373     SimpleStringStorage(const E* s, size_type len, const A&)
0374     {
0375         Init(len, len);
0376         flex_string_details::pod_copy(s, s + len, begin());
0377     }
0378 
0379     SimpleStringStorage(size_type len, E c, const A&)
0380     {
0381         Init(len, len);
0382         flex_string_details::pod_fill(begin(), end(), c);
0383     }
0384 
0385     SimpleStringStorage& operator=(const SimpleStringStorage& rhs)
0386     {
0387         const size_type sz = rhs.size();
0388         reserve(sz);
0389         flex_string_details::pod_copy(&*rhs.begin(), &*rhs.end(), begin());
0390         pData_->pEnd_ = &*begin() + sz;
0391         return *this;
0392     }
0393 
0394     ~SimpleStringStorage()
0395     {
0396         BOOST_ASSERT(begin() <= end());
0397         if (capacity() > 0)
0398         {
0399             BOOST_WAVE_COMPILE_TIME_ASSERT(pData_ != &emptyString_);
0400             free(pData_);
0401         }
0402     }
0403 
0404     iterator begin()
0405     { return pData_->buffer_; }
0406 
0407     const_iterator begin() const
0408     { return pData_->buffer_; }
0409 
0410     iterator end()
0411     { return pData_->pEnd_; }
0412 
0413     const_iterator end() const
0414     { return pData_->pEnd_; }
0415 
0416     size_type size() const
0417     { return pData_->pEnd_ - pData_->buffer_; }
0418 
0419     size_type max_size() const
0420     { return std::size_t(-1) / sizeof(E) - sizeof(Data) - 1; }
0421 
0422     size_type capacity() const
0423     { return pData_->pEndOfMem_ - pData_->buffer_; }
0424 
0425     void reserve(size_type res_arg)
0426     {
0427         size_type cap = capacity();
0428         if (res_arg <= cap)
0429         {
0430             // @@@ insert shrinkage here if you wish
0431             return;
0432         }
0433 
0434         if (cap == 0)
0435         {
0436             Init(0, res_arg);
0437         }
0438         else
0439         {
0440             const size_type sz = size();
0441 
0442             void* p = realloc(pData_,
0443                 sizeof(Data) + res_arg * sizeof(E));
0444             if (!p) boost::throw_exception(std::bad_alloc());
0445 
0446             if (p != pData_)
0447             {
0448                 pData_ = static_cast<Data*>(p);
0449                 pData_->pEnd_ = pData_->buffer_ + sz;
0450             }
0451             pData_->pEndOfMem_ = pData_->buffer_ + res_arg;
0452         }
0453     }
0454 
0455     void append(const E* s, size_type sz)
0456     {
0457         const size_type neededCapacity = size() + sz;
0458 
0459         if (capacity() < neededCapacity)
0460         {
0461             const iterator b = begin();
0462             static std::less_equal<const E*> le;
0463             if (le(b, s) && le(s, end()))
0464             {
0465                // aliased
0466                 const size_type offset = s - b;
0467                 reserve(neededCapacity);
0468                 s = begin() + offset;
0469             }
0470             else
0471             {
0472                 reserve(neededCapacity);
0473             }
0474         }
0475         flex_string_details::pod_copy(s, s + sz, end());
0476         pData_->pEnd_ += sz;
0477     }
0478 
0479     template <class InputIterator>
0480     void append(InputIterator b, InputIterator e)
0481     {
0482         // @@@ todo: optimize this depending on iterator type
0483         for (; b != e; ++b)
0484         {
0485             *this += *b;
0486         }
0487     }
0488 
0489     void resize(size_type newSize, E fill)
0490     {
0491         const int delta = int(newSize - size());
0492         if (delta == 0) return;
0493 
0494         if (delta > 0)
0495         {
0496             if (newSize > capacity())
0497             {
0498                 reserve(newSize);
0499             }
0500             E* e = &*end();
0501             flex_string_details::pod_fill(e, e + delta, fill);
0502         }
0503         pData_->pEnd_ = pData_->buffer_ + newSize;
0504     }
0505 
0506     void swap(SimpleStringStorage& rhs)
0507     {
0508         std::swap(pData_, rhs.pData_);
0509     }
0510 
0511     const E* c_str() const
0512     {
0513         if (capacity() > 0) *pData_->pEnd_ = E();
0514         return pData_->buffer_;
0515     }
0516 
0517     const E* data() const
0518     { return pData_->buffer_; }
0519 
0520     A get_allocator() const
0521     { return A(); }
0522 };
0523 
0524 template <typename E, class A>
0525 const typename SimpleStringStorage<E, A>::Data
0526 SimpleStringStorage<E, A>::emptyString_ =
0527     typename SimpleStringStorage<E, A>::Data();
0528 
0529 ////////////////////////////////////////////////////////////////////////////////
0530 // class template AllocatorStringStorage
0531 // Allocates with your allocator
0532 // Takes advantage of the Empty Base Optimization if available
0533 ////////////////////////////////////////////////////////////////////////////////
0534 
0535 template <typename E, class A = std::allocator<E> >
0536 class AllocatorStringStorage : public A
0537 {
0538     typedef typename boost::allocator_size_type<A>::type size_type;
0539     typedef typename SimpleStringStorage<E, A>::Data Data;
0540 
0541     void* Alloc(size_type sz, const void* p = 0)
0542     {
0543         return boost::allocator_allocate(static_cast<A&>(*this), 1 + (sz - 1) / sizeof(E),
0544             static_cast<const char*>(p));
0545     }
0546 
0547     void Free(void* p, size_type sz)
0548     {
0549         boost::allocator_deallocate(static_cast<A&>(*this), static_cast<E*>(p), sz);
0550     }
0551 
0552     Data* pData_;
0553 
0554     void Init(size_type size, size_type cap)
0555     {
0556         BOOST_ASSERT(size <= cap);
0557 
0558         if (cap == 0)
0559         {
0560             pData_ = const_cast<Data*>(
0561                 &SimpleStringStorage<E, A>::emptyString_);
0562         }
0563         else
0564         {
0565             pData_ = static_cast<Data*>(Alloc(
0566                 cap * sizeof(E) + sizeof(Data)));
0567             pData_->pEnd_ = pData_->buffer_ + size;
0568             pData_->pEndOfMem_ = pData_->buffer_ + cap;
0569         }
0570     }
0571 
0572 public:
0573     typedef E value_type;
0574     typedef E* iterator;
0575     typedef const E* const_iterator;
0576     typedef A allocator_type;
0577 
0578     AllocatorStringStorage()
0579     : A(), pData_(0)
0580     {
0581     }
0582 
0583     AllocatorStringStorage(const AllocatorStringStorage& rhs)
0584     : A(rhs.get_allocator())
0585     {
0586         const size_type sz = rhs.size();
0587         Init(sz, sz);
0588         if (sz) flex_string_details::pod_copy(rhs.begin(), rhs.end(), begin());
0589     }
0590 
0591     AllocatorStringStorage(const AllocatorStringStorage& s,
0592         flex_string_details::Shallow)
0593     : A(s.get_allocator())
0594     {
0595         pData_ = s.pData_;
0596     }
0597 
0598     AllocatorStringStorage(const A& a) : A(a)
0599     {
0600         pData_ = const_cast<Data*>(
0601             &SimpleStringStorage<E, A>::emptyString_);
0602     }
0603 
0604     AllocatorStringStorage(const E* s, size_type len, const A& a)
0605     : A(a)
0606     {
0607         Init(len, len);
0608         flex_string_details::pod_copy(s, s + len, begin());
0609     }
0610 
0611     AllocatorStringStorage(size_type len, E c, const A& a)
0612     : A(a)
0613     {
0614         Init(len, len);
0615         flex_string_details::pod_fill(&*begin(), &*end(), c);
0616     }
0617 
0618     AllocatorStringStorage& operator=(const AllocatorStringStorage& rhs)
0619     {
0620         const size_type sz = rhs.size();
0621         reserve(sz);
0622         flex_string_details::pod_copy(&*rhs.begin(), &*rhs.end(), begin());
0623         pData_->pEnd_ = &*begin() + rhs.size();
0624         return *this;
0625     }
0626 
0627     ~AllocatorStringStorage()
0628     {
0629         if (capacity())
0630         {
0631             BOOST_WAVE_COMPILE_TIME_ASSERT(pData_ != (&SimpleStringStorage<E, A>::emptyString_));
0632             Free(pData_,
0633                 sizeof(Data) + capacity() * sizeof(E));
0634         }
0635     }
0636 
0637     iterator begin()
0638     { return pData_->buffer_; }
0639 
0640     const_iterator begin() const
0641     { return pData_->buffer_; }
0642 
0643     iterator end()
0644     { return pData_->pEnd_; }
0645 
0646     const_iterator end() const
0647     { return pData_->pEnd_; }
0648 
0649     size_type size() const
0650     { return size_type(end() - begin()); }
0651 
0652     size_type max_size() const
0653     { return boost::allocator_max_size(static_cast<const A&>(*this)); }
0654 
0655     size_type capacity() const
0656     { return size_type(pData_->pEndOfMem_ - pData_->buffer_); }
0657 
0658     void resize(size_type n, E c)
0659     {
0660         reserve(n);
0661         iterator newEnd = begin() + n;
0662         iterator oldEnd = end();
0663         if (newEnd > oldEnd)
0664         {
0665             // Copy the characters
0666             flex_string_details::pod_fill(oldEnd, newEnd, c);
0667         }
0668         if (capacity()) pData_->pEnd_ = newEnd;
0669     }
0670 
0671     void reserve(size_type res_arg)
0672     {
0673         if (res_arg <= capacity())
0674         {
0675             // @@@ shrink to fit here
0676             return;
0677         }
0678 
0679         A& myAlloc = *this;
0680         AllocatorStringStorage newStr(myAlloc);
0681         newStr.Init(size(), res_arg);
0682 
0683         flex_string_details::pod_copy(begin(), end(), newStr.begin());
0684 
0685         swap(newStr);
0686     }
0687 
0688     template <class ForwardIterator>
0689     void append(ForwardIterator b, ForwardIterator e)
0690     {
0691         const size_type
0692             sz = std::distance(b, e),
0693             neededCapacity = size() + sz;
0694 
0695         if (capacity() < neededCapacity)
0696         {
0697 //             typedef std::less_equal<const E*> le_type;
0698 //             BOOST_ASSERT(!(le_type()(begin(), &*b) && le_type()(&*b, end())));
0699             reserve(neededCapacity);
0700         }
0701         std::copy(b, e, end());
0702         pData_->pEnd_ += sz;
0703     }
0704 
0705     void swap(AllocatorStringStorage& rhs)
0706     {
0707         // @@@ The following line is commented due to a bug in MSVC
0708         //std::swap(lhsAlloc, rhsAlloc);
0709         std::swap(pData_, rhs.pData_);
0710     }
0711 
0712     const E* c_str() const
0713     {
0714         if (capacity() > 0)
0715         {
0716             *pData_->pEnd_ = E();
0717         }
0718         return &*begin();
0719     }
0720 
0721     const E* data() const
0722     { return &*begin(); }
0723 
0724     A get_allocator() const
0725     { return *this; }
0726 };
0727 
0728 ////////////////////////////////////////////////////////////////////////////////
0729 // class template VectorStringStorage
0730 // Uses std::vector
0731 // Takes advantage of the Empty Base Optimization if available
0732 ////////////////////////////////////////////////////////////////////////////////
0733 
0734 template <typename E, class A = std::allocator<E> >
0735 class VectorStringStorage : protected std::vector<E, A>
0736 {
0737     typedef std::vector<E, A> base;
0738 
0739 public: // protected:
0740     typedef E value_type;
0741     typedef typename base::iterator iterator;
0742     typedef typename base::const_iterator const_iterator;
0743     typedef A allocator_type;
0744     typedef typename boost::allocator_size_type<A>::type size_type;
0745 
0746     VectorStringStorage(const VectorStringStorage& s) : base(s)
0747     { }
0748 
0749     VectorStringStorage(const A& a) : base(1, E(), a)
0750     { }
0751 
0752     VectorStringStorage(const E* s, size_type len, const A& a)
0753     : base(a)
0754     {
0755         base::reserve(len + 1);
0756         base::insert(base::end(), s, s + len);
0757         // Terminating zero
0758         base::insert(base::end(), E());
0759     }
0760 
0761     VectorStringStorage(size_type len, E c, const A& a)
0762     : base(len + 1, c, a)
0763     {
0764         // Terminating zero
0765         base::back() = E();
0766     }
0767 
0768     VectorStringStorage& operator=(const VectorStringStorage& rhs)
0769     {
0770         base& v = *this;
0771         v = rhs;
0772         return *this;
0773     }
0774 
0775     iterator begin()
0776     { return base::begin(); }
0777 
0778     const_iterator begin() const
0779     { return base::begin(); }
0780 
0781     iterator end()
0782     { return base::end() - 1; }
0783 
0784     const_iterator end() const
0785     { return base::end() - 1; }
0786 
0787     size_type size() const
0788     { return base::size() - 1; }
0789 
0790     size_type max_size() const
0791     { return base::max_size() - 1; }
0792 
0793     size_type capacity() const
0794     { return base::capacity() - 1; }
0795 
0796     void reserve(size_type res_arg)
0797     {
0798         BOOST_ASSERT(res_arg < max_size());
0799         base::reserve(res_arg + 1);
0800     }
0801 
0802     void append(const E* s, size_type sz)
0803     {
0804         // Check for aliasing because std::vector doesn't do it.
0805         static std::less_equal<const E*> le;
0806         if (!base::empty())
0807         {
0808             const E* start = &base::front();
0809             if (le(start, s) && le(s, start + size()))
0810             {
0811                 // aliased
0812                 const size_type offset = s - start;
0813                 reserve(size() + sz);
0814                 s = &base::front() + offset;
0815             }
0816         }
0817         base::insert(end(), s, s + sz);
0818     }
0819 
0820     template <class InputIterator>
0821     void append(InputIterator b, InputIterator e)
0822     {
0823         base::insert(end(), b, e);
0824     }
0825 
0826     void resize(size_type n, E c)
0827     {
0828         base::reserve(n + 1);
0829         base::back() = c;
0830         base::resize(n + 1, c);
0831         base::back() = E();
0832     }
0833 
0834     void swap(VectorStringStorage& rhs)
0835     { base::swap(rhs); }
0836 
0837     const E* c_str() const
0838     { return &*begin(); }
0839 
0840     const E* data() const
0841     { return &*begin(); }
0842 
0843     A get_allocator() const
0844     { return base::get_allocator(); }
0845 };
0846 
0847 ////////////////////////////////////////////////////////////////////////////////
0848 // class template SmallStringOpt
0849 // Builds the small string optimization over any other storage
0850 ////////////////////////////////////////////////////////////////////////////////
0851 
0852 template <class Storage, unsigned int threshold,
0853     typename Align = typename Storage::value_type*>
0854 class SmallStringOpt
0855 {
0856 public:
0857     typedef typename Storage::value_type value_type;
0858     typedef value_type* iterator;
0859     typedef const value_type* const_iterator;
0860     typedef typename Storage::allocator_type allocator_type;
0861     typedef typename boost::allocator_size_type<allocator_type>::type size_type;
0862 
0863 private:
0864   enum { temp1 = threshold * sizeof(value_type) > sizeof(Storage)
0865         ? threshold  * sizeof(value_type)
0866         : sizeof(Storage) };
0867 
0868     enum { temp2 = temp1 > sizeof(Align) ? temp1 : sizeof(Align) };
0869 
0870 public:
0871     enum { maxSmallString =
0872     (temp2 + sizeof(value_type) - 1) / sizeof(value_type) };
0873 
0874 private:
0875     enum { magic = maxSmallString + 1 };
0876 
0877     union
0878     {
0879         mutable value_type buf_[maxSmallString + 1];
0880         Align align_;
0881     };
0882 
0883     Storage& GetStorage()
0884     {
0885         BOOST_ASSERT(buf_[maxSmallString] == magic);
0886         Storage* p = reinterpret_cast<Storage*>(&buf_[0]);
0887         return *p;
0888     }
0889 
0890     const Storage& GetStorage() const
0891     {
0892         BOOST_ASSERT(buf_[maxSmallString] == magic);
0893         const Storage *p = reinterpret_cast<const Storage*>(&buf_[0]);
0894         return *p;
0895     }
0896 
0897     bool Small() const
0898     {
0899         return buf_[maxSmallString] != magic;
0900     }
0901 
0902 public:
0903   SmallStringOpt(const SmallStringOpt& s)
0904     {
0905         if (s.Small())
0906         {
0907             flex_string_details::pod_copy(
0908                 s.buf_,
0909                 s.buf_ + s.size(),
0910                 buf_);
0911         }
0912         else
0913         {
0914             new(buf_) Storage(s.GetStorage());
0915         }
0916         buf_[maxSmallString] = s.buf_[maxSmallString];
0917     }
0918 
0919     SmallStringOpt(const allocator_type&)
0920     {
0921         buf_[maxSmallString] = maxSmallString;
0922     }
0923 
0924     SmallStringOpt(const value_type* s, size_type len, const allocator_type& a)
0925     {
0926         if (len <= maxSmallString)
0927         {
0928             flex_string_details::pod_copy(s, s + len, buf_);
0929             buf_[maxSmallString] = value_type(maxSmallString - len);
0930         }
0931         else
0932         {
0933             new(buf_) Storage(s, len, a);
0934             buf_[maxSmallString] = magic;
0935         }
0936     }
0937 
0938     SmallStringOpt(size_type len, value_type c, const allocator_type& a)
0939     {
0940         if (len <= maxSmallString)
0941         {
0942             flex_string_details::pod_fill(buf_, buf_ + len, c);
0943             buf_[maxSmallString] = value_type(maxSmallString - len);
0944         }
0945         else
0946         {
0947             new(buf_) Storage(len, c, a);
0948             buf_[maxSmallString] = magic;
0949         }
0950     }
0951 
0952     SmallStringOpt& operator=(const SmallStringOpt& rhs)
0953     {
0954         reserve(rhs.size());
0955         resize(0, 0);
0956         append(rhs.data(), rhs.size());
0957         return *this;
0958     }
0959 
0960     ~SmallStringOpt()
0961     {
0962         if (!Small()) GetStorage().~Storage();
0963     }
0964 
0965     iterator begin()
0966     {
0967         if (Small()) return buf_;
0968         return &*GetStorage().begin();
0969     }
0970 
0971     const_iterator begin() const
0972     {
0973         if (Small()) return buf_;
0974         return &*GetStorage().begin();
0975     }
0976 
0977     iterator end()
0978     {
0979         if (Small()) return buf_ + maxSmallString - buf_[maxSmallString];
0980         return &*GetStorage().end();
0981     }
0982 
0983     const_iterator end() const
0984     {
0985         if (Small()) return buf_ + maxSmallString - buf_[maxSmallString];
0986         return &*GetStorage().end();
0987     }
0988 
0989     size_type size() const
0990     {
0991         BOOST_ASSERT(!Small() || maxSmallString >= buf_[maxSmallString]);
0992         return Small()
0993             ? maxSmallString - buf_[maxSmallString]
0994             : GetStorage().size();
0995     }
0996 
0997     size_type max_size() const
0998     { return boost::allocator_max_size(get_allocator()); }
0999 
1000     size_type capacity() const
1001     { return Small() ? maxSmallString : GetStorage().capacity(); }
1002 
1003     void reserve(size_type res_arg)
1004     {
1005         if (Small())
1006         {
1007             if (res_arg <= maxSmallString) return;
1008             SmallStringOpt temp(*this);
1009             this->~SmallStringOpt();
1010             new(buf_) Storage(temp.data(), temp.size(),
1011                 temp.get_allocator());
1012             buf_[maxSmallString] = magic;
1013             GetStorage().reserve(res_arg);
1014         }
1015         else
1016         {
1017             GetStorage().reserve(res_arg);
1018         }
1019         BOOST_ASSERT(capacity() >= res_arg);
1020     }
1021 
1022     void append(const value_type* s, size_type sz)
1023     {
1024         if (!Small())
1025         {
1026             GetStorage().append(s, sz);
1027         }
1028         else
1029         {
1030             // append to a small string
1031             const size_type neededCapacity =
1032                 maxSmallString - buf_[maxSmallString] + sz;
1033 
1034             if (maxSmallString < neededCapacity)
1035             {
1036                 // need to change storage strategy
1037                 allocator_type alloc;
1038                 Storage temp(alloc);
1039                 temp.reserve(neededCapacity);
1040                 temp.append(buf_, maxSmallString - buf_[maxSmallString]);
1041                 temp.append(s, sz);
1042                 buf_[maxSmallString] = magic;
1043                 new(buf_) Storage(temp.get_allocator());
1044                 GetStorage().swap(temp);
1045             }
1046             else
1047             {
1048                 flex_string_details::pod_move(s, s + sz,
1049                     buf_ + maxSmallString - buf_[maxSmallString]);
1050                 buf_[maxSmallString] -= value_type(sz);
1051             }
1052         }
1053     }
1054 
1055     template <class InputIterator>
1056     void append(InputIterator b, InputIterator e)
1057     {
1058         // @@@ todo: optimize this depending on iterator type
1059         for (; b != e; ++b)
1060         {
1061             *this += *b;
1062         }
1063     }
1064 
1065     void resize(size_type n, value_type c)
1066     {
1067         if (Small())
1068         {
1069             if (n > maxSmallString)
1070             {
1071                 // Small string resized to big string
1072                 SmallStringOpt temp(*this); // can't throw
1073                 // 11-17-2001: correct exception safety bug
1074                 Storage newString(temp.data(), temp.size(),
1075                     temp.get_allocator());
1076                 newString.resize(n, c);
1077                 // We make the reasonable assumption that an empty Storage
1078                 //     constructor won't throw
1079                 this->~SmallStringOpt();
1080                 new(&buf_[0]) Storage(temp.get_allocator());
1081                 buf_[maxSmallString] = value_type(magic);
1082                 GetStorage().swap(newString);
1083             }
1084             else
1085             {
1086                 // Small string resized to small string
1087                 // 11-17-2001: bug fix: terminating zero not copied
1088                 size_type toFill = n > size() ? n - size() : 0;
1089                 flex_string_details::pod_fill(end(), end() + toFill, c);
1090                 buf_[maxSmallString] = value_type(maxSmallString - n);
1091             }
1092         }
1093         else
1094         {
1095             if (n > maxSmallString)
1096             {
1097                 // Big string resized to big string
1098                 GetStorage().resize(n, c);
1099             }
1100             else
1101             {
1102                 // Big string resized to small string
1103                 // 11-17=2001: bug fix in the BOOST_ASSERTion below
1104                 BOOST_ASSERT(capacity() > n);
1105                 SmallStringOpt newObj(data(), n, get_allocator());
1106                 newObj.swap(*this);
1107             }
1108         }
1109     }
1110 
1111     void swap(SmallStringOpt& rhs)
1112     {
1113         if (Small())
1114         {
1115             if (rhs.Small())
1116             {
1117                 // Small swapped with small
1118                 std::swap_ranges(buf_, buf_ + maxSmallString + 1,
1119                     rhs.buf_);
1120             }
1121             else
1122             {
1123                 // Small swapped with big
1124                 // Make a copy of myself - can't throw
1125                 SmallStringOpt temp(*this);
1126                 // Nuke myself
1127                 this->~SmallStringOpt();
1128                 // Make an empty storage for myself (likely won't throw)
1129                 new(buf_) Storage(0, value_type(), rhs.get_allocator());
1130                 buf_[maxSmallString] = magic;
1131                 // Recurse to this same function
1132                 swap(rhs);
1133                 // Nuke rhs
1134                 rhs.~SmallStringOpt();
1135                 // Build the new small string into rhs
1136                 new(&rhs) SmallStringOpt(temp);
1137             }
1138         }
1139         else
1140         {
1141             if (rhs.Small())
1142             {
1143                 // Big swapped with small
1144                 // Already implemented, recurse with reversed args
1145                 rhs.swap(*this);
1146             }
1147             else
1148             {
1149                 // Big swapped with big
1150                 GetStorage().swap(rhs.GetStorage());
1151             }
1152         }
1153     }
1154 
1155     const value_type* c_str() const
1156     {
1157         if (!Small()) return GetStorage().c_str();
1158         buf_[maxSmallString - buf_[maxSmallString]] = value_type();
1159         return buf_;
1160     }
1161 
1162     const value_type* data() const
1163     { return Small() ? buf_ : GetStorage().data(); }
1164 
1165     allocator_type get_allocator() const
1166     { return allocator_type(); }
1167 };
1168 
1169 ////////////////////////////////////////////////////////////////////////////////
1170 // class template CowString
1171 // Implements Copy on Write over any storage
1172 ////////////////////////////////////////////////////////////////////////////////
1173 
1174 template <
1175     typename Storage,
1176     typename Align = BOOST_DEDUCED_TYPENAME Storage::value_type*
1177 >
1178 class CowString
1179 {
1180     typedef typename Storage::value_type E;
1181     typedef typename flex_string_details::get_unsigned<E>::result RefCountType;
1182 
1183 public:
1184     typedef E value_type;
1185     typedef typename Storage::iterator iterator;
1186     typedef typename Storage::const_iterator const_iterator;
1187     typedef typename Storage::allocator_type allocator_type;
1188     typedef typename boost::allocator_size_type<allocator_type>::type size_type;
1189     typedef typename Storage::value_type& reference;
1190 
1191 private:
1192     union
1193     {
1194         mutable char buf_[sizeof(Storage)];
1195         Align align_;
1196     };
1197 
1198     Storage& Data() const
1199     {
1200         Storage* p = reinterpret_cast<Storage*>(&buf_[0]);
1201         return *p;
1202     }
1203 
1204     RefCountType GetRefs() const
1205     {
1206         const Storage& d = Data();
1207         BOOST_ASSERT(d.size() > 0);
1208         BOOST_ASSERT(static_cast<RefCountType>(*d.begin()) != 0);
1209         return *d.begin();
1210     }
1211 
1212     RefCountType& Refs()
1213     {
1214         Storage& d = Data();
1215         BOOST_ASSERT(d.size() > 0);
1216         return reinterpret_cast<RefCountType&>(*d.begin());
1217     }
1218 
1219     void MakeUnique() const
1220     {
1221         BOOST_ASSERT(GetRefs() >= 1);
1222         if (GetRefs() == 1) return;
1223 
1224         union
1225         {
1226             char buf_[sizeof(Storage)];
1227             Align align_;
1228         } temp;
1229 
1230         --(*Data().begin()); // decrement the use count of the remaining object
1231 
1232         Storage* p = reinterpret_cast<Storage*>(&temp.buf_[0]);
1233         new(buf_) Storage(
1234             *new(p) Storage(Data()),
1235             flex_string_details::Shallow());
1236         *Data().begin() = 1;
1237     }
1238 
1239 public:
1240     CowString(const CowString& s)
1241     {
1242         if (s.GetRefs() == (std::numeric_limits<RefCountType>::max)())
1243         {
1244             // must make a brand new copy
1245             new(buf_) Storage(s.Data()); // non shallow
1246             Refs() = 1;
1247         }
1248         else
1249         {
1250             new(buf_) Storage(s.Data(), flex_string_details::Shallow());
1251             ++Refs();
1252         }
1253         BOOST_ASSERT(Data().size() > 0);
1254     }
1255 
1256     CowString(const allocator_type& a)
1257     {
1258         new(buf_) Storage(1, 1, a);
1259     }
1260 
1261     CowString(const E* s, size_type len, const allocator_type& a)
1262     {
1263         // Warning - MSVC's debugger has trouble tracing through the code below.
1264         // It seems to be a const-correctness issue
1265         //
1266         new(buf_) Storage(a);
1267         Data().reserve(len + 1);
1268         Data().resize(1, 1);
1269         Data().append(s, s + len);
1270     }
1271 
1272     CowString(size_type len, E c, const allocator_type& a)
1273     {
1274         new(buf_) Storage(len + 1, c, a);
1275         Refs() = 1;
1276     }
1277 
1278     CowString& operator=(const CowString& rhs)
1279     {
1280 //        CowString(rhs).swap(*this);
1281         if (--Refs() == 0)
1282             Data().~Storage();
1283         if (rhs.GetRefs() == (std::numeric_limits<RefCountType>::max)())
1284         {
1285             // must make a brand new copy
1286             new(buf_) Storage(rhs.Data()); // non shallow
1287             Refs() = 1;
1288         }
1289         else
1290         {
1291             new(buf_) Storage(rhs.Data(), flex_string_details::Shallow());
1292             ++Refs();
1293         }
1294         BOOST_ASSERT(Data().size() > 0);
1295         return *this;
1296     }
1297 
1298     ~CowString()
1299     {
1300         BOOST_ASSERT(Data().size() > 0);
1301         if (--Refs() == 0)
1302             Data().~Storage();
1303     }
1304 
1305     iterator begin()
1306     {
1307         BOOST_ASSERT(Data().size() > 0);
1308         MakeUnique();
1309         return Data().begin() + 1;
1310     }
1311 
1312     const_iterator begin() const
1313     {
1314         BOOST_ASSERT(Data().size() > 0);
1315         return Data().begin() + 1;
1316     }
1317 
1318     iterator end()
1319     {
1320         MakeUnique();
1321         return Data().end();
1322     }
1323 
1324     const_iterator end() const
1325     {
1326         return Data().end();
1327     }
1328 
1329     size_type size() const
1330     {
1331         BOOST_ASSERT(Data().size() > 0);
1332         return Data().size() - 1;
1333     }
1334 
1335     size_type max_size() const
1336     {
1337         BOOST_ASSERT(Data().max_size() > 0);
1338         return Data().max_size() - 1;
1339     }
1340 
1341     size_type capacity() const
1342     {
1343         BOOST_ASSERT(Data().capacity() > 0);
1344         return Data().capacity() - 1;
1345     }
1346 
1347     void resize(size_type n, E c)
1348     {
1349         BOOST_ASSERT(Data().size() > 0);
1350         MakeUnique();
1351         Data().resize(n + 1, c);
1352     }
1353 
1354     template <class FwdIterator>
1355     void append(FwdIterator b, FwdIterator e)
1356     {
1357         MakeUnique();
1358         Data().append(b, e);
1359     }
1360 
1361     void reserve(size_type res_arg)
1362     {
1363         if (capacity() > res_arg) return;
1364         MakeUnique();
1365         Data().reserve(res_arg + 1);
1366     }
1367 
1368     void swap(CowString& rhs)
1369     {
1370         Data().swap(rhs.Data());
1371     }
1372 
1373     const E* c_str() const
1374     {
1375         BOOST_ASSERT(Data().size() > 0);
1376         return Data().c_str() + 1;
1377     }
1378 
1379     const E* data() const
1380     {
1381         BOOST_ASSERT(Data().size() > 0);
1382         return Data().data() + 1;
1383     }
1384 
1385     allocator_type get_allocator() const
1386     {
1387         return Data().get_allocator();
1388     }
1389 };
1390 
1391 ////////////////////////////////////////////////////////////////////////////////
1392 // class template flex_string
1393 // a std::basic_string compatible implementation
1394 // Uses a Storage policy
1395 ////////////////////////////////////////////////////////////////////////////////
1396 
1397 template <typename E,
1398     class T = std::char_traits<E>,
1399     class A = std::allocator<E>,
1400     class Storage = AllocatorStringStorage<E, A> >
1401 class flex_string : private Storage
1402 {
1403 #if defined(BOOST_WAVE_FLEXSTRING_THROW_ON_ENFORCE)
1404     template <typename Exception>
1405     static void Enforce(bool condition, Exception*, const char* msg)
1406     { if (!condition) boost::throw_exception(Exception(msg)); }
1407 #else
1408     template <typename Exception>
1409     static inline void Enforce(bool condition, Exception*, const char* msg)
1410     { BOOST_ASSERT(condition && msg); }
1411 #endif // defined(BOOST_WAVE_FLEXSTRING_THROW_ON_ENFORCE)
1412 
1413 #ifndef NDEBUG
1414     bool Sane() const
1415     {
1416         return
1417             begin() <= end() &&
1418             empty() == (size() == 0) &&
1419             empty() == (begin() == end()) &&
1420             size() <= max_size() &&
1421             capacity() <= max_size() &&
1422             size() <= capacity();
1423     }
1424 
1425     struct Invariant;
1426     friend struct Invariant;
1427     struct Invariant
1428     {
1429         Invariant(const flex_string& s) : s_(s)
1430         {
1431             BOOST_ASSERT(s_.Sane());
1432         }
1433         ~Invariant()
1434         {
1435             BOOST_ASSERT(s_.Sane());
1436         }
1437     private:
1438         const flex_string& s_;
1439         Invariant& operator=(const Invariant&);
1440     };
1441 #endif
1442 
1443 public:
1444     // types
1445     typedef T traits_type;
1446     typedef typename traits_type::char_type value_type;
1447     typedef A allocator_type;
1448 
1449     typedef typename boost::allocator_value_type<A>::type& reference;
1450     typedef typename boost::allocator_value_type<A>::type const& const_reference;
1451     typedef typename boost::allocator_pointer<A>::type pointer;
1452     typedef typename boost::allocator_const_pointer<A>::type const_pointer;
1453     typedef typename boost::allocator_size_type<A>::type size_type;
1454 
1455     typedef typename Storage::iterator iterator;
1456     typedef typename Storage::const_iterator const_iterator;
1457 
1458     typedef boost::reverse_iterator<iterator> reverse_iterator;
1459     typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
1460 
1461     static const size_type npos;    // = size_type(-1)
1462 
1463 private:
1464     static size_type Min(size_type lhs, size_type rhs)
1465     { return lhs < rhs ? lhs : rhs; }
1466     static void Procust(size_type& n, size_type nmax)
1467     { if (n > nmax) n = nmax; }
1468 
1469 public:
1470     // 21.3.1 construct/copy/destroy
1471     explicit flex_string(const A& a = A())
1472     : Storage(a)
1473     {}
1474 
1475     flex_string(const flex_string& str)
1476     : Storage(str)
1477     {
1478     }
1479 
1480     flex_string(const flex_string& str, size_type pos,
1481         size_type n = npos, const A& a = A())
1482     : Storage(a)
1483     {
1484         Enforce(pos <= str.size(), (std::out_of_range*)0, "");
1485         assign(str, pos, n);
1486     }
1487 
1488     flex_string(const value_type* s, const A& a = A())
1489     : Storage(s, traits_type::length(s), a)
1490     {}
1491 
1492     flex_string(const value_type* s, size_type n, const A& a = A())
1493     : Storage(s, n, a)
1494     {}
1495 
1496     flex_string(size_type n, value_type c, const A& a = A())
1497     : Storage(n, c, a)
1498     {}
1499 
1500     template <class InputIterator>
1501     flex_string(InputIterator begin, InputIterator end, const A& a = A())
1502     : Storage(a)
1503     {
1504         assign(begin, end);
1505     }
1506 
1507     ~flex_string()
1508     {}
1509 
1510     flex_string& operator=(const flex_string& str)
1511     {
1512         if (this != &str) {
1513             Storage& s = *this;
1514             s = str;
1515         }
1516         return *this;
1517     }
1518 
1519     flex_string& operator=(const value_type* s)
1520     {
1521         assign(s);
1522         return *this;
1523     }
1524 
1525     flex_string& operator=(value_type c)
1526     {
1527         assign(1, c);
1528         return *this;
1529     }
1530 
1531     // 21.3.2 iterators:
1532     iterator begin()
1533     { return Storage::begin(); }
1534 
1535     const_iterator begin() const
1536     { return Storage::begin(); }
1537 
1538     iterator end()
1539     { return Storage::end(); }
1540 
1541     const_iterator end() const
1542     { return Storage::end(); }
1543 
1544     reverse_iterator rbegin()
1545     { return reverse_iterator(end()); }
1546 
1547     const_reverse_iterator rbegin() const
1548     { return const_reverse_iterator(end()); }
1549 
1550     reverse_iterator rend()
1551     { return reverse_iterator(begin()); }
1552 
1553     const_reverse_iterator rend() const
1554     { return const_reverse_iterator(begin()); }
1555 
1556 #if BOOST_WAVE_FLEX_STRING_SERIALIZATION_HACK != 0
1557     //  temporary hack to make it easier to serialize flex_string's using
1558     //  the Boost.Serialization library
1559     value_type & back() { return *(begin()+size()-1); }
1560     value_type const& back() const { return *(begin()+size()-1); }
1561 #endif
1562 
1563     // 21.3.3 capacity:
1564     size_type size() const
1565     { return Storage::size(); }
1566 
1567     size_type length() const
1568     { return size(); }
1569 
1570     size_type max_size() const
1571     { return Storage::max_size(); }
1572 
1573     void resize(size_type n, value_type c)
1574     { Storage::resize(n, c); }
1575 
1576     void resize(size_type n)
1577     { resize(n, value_type()); }
1578 
1579     size_type capacity() const
1580     { return Storage::capacity(); }
1581 
1582     void reserve(size_type res_arg = 0)
1583     {
1584         Enforce(res_arg <= max_size(), (std::length_error*)0, "");
1585         Storage::reserve(res_arg);
1586     }
1587 
1588     void clear()
1589     { resize(0); }
1590 
1591     bool empty() const
1592     { return size() == 0; }
1593 
1594     // 21.3.4 element access:
1595     const_reference operator[](size_type pos) const
1596     { return *(begin() + pos); }
1597 
1598     reference operator[](size_type pos)
1599     { return *(begin() + pos); }
1600 
1601     const_reference at(size_type n) const
1602     {
1603         Enforce(n < size(), (std::out_of_range*)0, "");
1604         return (*this)[n];
1605     }
1606 
1607     reference at(size_type n)
1608     {
1609         Enforce(n < size(), (std::out_of_range*)0, "");
1610         return (*this)[n];
1611     }
1612 
1613     // 21.3.5 modifiers:
1614     flex_string& operator+=(const flex_string& str)
1615     { return append(str); }
1616 
1617     flex_string& operator+=(const value_type* s)
1618     { return append(s); }
1619 
1620     flex_string& operator+=(value_type c)
1621     {
1622         push_back(c);
1623         return *this;
1624     }
1625 
1626     flex_string& append(const flex_string& str)
1627     { return append(str, 0, npos); }
1628 
1629     flex_string& append(const flex_string& str, const size_type pos,
1630         size_type n)
1631     {
1632         const size_type sz = str.size();
1633         Enforce(pos <= sz, (std::out_of_range*)0, "");
1634         Procust(n, sz - pos);
1635         return append(str.c_str() + pos, n);
1636     }
1637 
1638     flex_string& append(const value_type* s, const size_type n)
1639     {
1640 #ifndef NDEBUG
1641         Invariant checker(*this);
1642 #endif
1643         if (IsAliasedRange(s, s + n))
1644         {
1645             const size_type offset = s - &*begin();
1646             Storage::reserve(size() + n);
1647             s = &*begin() + offset;
1648         }
1649         Storage::append(s, s+ n);
1650         return *this;
1651     }
1652 
1653     flex_string& append(const value_type* s)
1654     { return append(s, traits_type::length(s)); }
1655 
1656     flex_string& append(size_type n, value_type c)
1657     {
1658         resize(size() + n, c);
1659         return *this;
1660     }
1661 
1662     template<class InputIterator>
1663     flex_string& append(InputIterator first, InputIterator last)
1664     {
1665         insert(end(), first, last);
1666         return *this;
1667     }
1668 
1669     void push_back(value_type c)
1670     {
1671         const size_type cap = capacity();
1672         if (size() == cap)
1673         {
1674             reserve(cap << 1u);
1675         }
1676         Storage::append(&c, &c + 1);
1677     }
1678 
1679     flex_string& assign(const flex_string& str)
1680     {
1681         if (&str == this) return *this;
1682         return assign(str.data(), str.size());
1683     }
1684 
1685     flex_string& assign(const flex_string& str, size_type pos,
1686         size_type n)
1687     {
1688         const size_type sz = str.size();
1689         Enforce(pos <= str.size(), (std::out_of_range*)0, "");
1690         Procust(n, sz - pos);
1691         return assign(str.data() + pos, n);
1692     }
1693 
1694     flex_string& assign(const value_type* s, size_type n)
1695     {
1696 #ifndef NDEBUG
1697         Invariant checker(*this);
1698 #endif
1699         if (size() >= n)
1700         {
1701             std::copy(s, s + n, begin());
1702             resize(n);
1703         }
1704         else
1705         {
1706             const value_type *const s2 = s + size();
1707             std::copy(s, s2, begin());
1708             append(s2, n - size());
1709         }
1710         return *this;
1711     }
1712 
1713     flex_string& assign(const value_type* s)
1714     { return assign(s, traits_type::length(s)); }
1715 
1716     template <class ItOrLength, class ItOrChar>
1717     flex_string& assign(ItOrLength first_or_n, ItOrChar last_or_c)
1718     { return replace(begin(), end(), first_or_n, last_or_c); }
1719 
1720     flex_string& insert(size_type pos1, const flex_string& str)
1721     { return insert(pos1, str.data(), str.size()); }
1722 
1723     flex_string& insert(size_type pos1, const flex_string& str,
1724         size_type pos2, size_type n)
1725     {
1726         Enforce(pos2 <= str.length(), (std::out_of_range*)0, "");
1727         Procust(n, str.length() - pos2);
1728         return insert(pos1, str.data() + pos2, n);
1729     }
1730 
1731     flex_string& insert(size_type pos, const value_type* s, size_type n)
1732     {
1733         Enforce(pos <= length(), (std::out_of_range*)0, "");
1734         insert(begin() + pos, s, s + n);
1735         return *this;
1736     }
1737 
1738     flex_string& insert(size_type pos, const value_type* s)
1739     { return insert(pos, s, traits_type::length(s)); }
1740 
1741     flex_string& insert(size_type pos, size_type n, value_type c)
1742     {
1743         Enforce(pos <= length(), (std::out_of_range*)0, "");
1744         insert(begin() + pos, n, c);
1745         return *this;
1746     }
1747 
1748     iterator insert(iterator p, value_type c = value_type())
1749     {
1750         const size_type pos = p - begin();
1751         insert(pos, &c, 1);
1752         return begin() + pos;
1753     }
1754 
1755 private:
1756     // Care must be taken when dereferencing some iterator types.
1757     //
1758     // Users can implement this function in their namespace if their storage
1759     // uses a special iterator type, the function will be found through ADL.
1760     template<class Iterator>
1761     const typename std::iterator_traits<Iterator>::value_type*
1762     DereferenceValidIterator(Iterator it) const
1763     {
1764         return &*it;
1765     }
1766 
1767     // Care must be taken when dereferencing a reverse iterators, hence this
1768     // special case. This isn't in the std namespace so as not to pollute it or
1769     // create name clashes.
1770     template<typename Iterator>
1771     const typename std::iterator_traits<Iterator>::value_type*
1772     DereferenceValidIterator(std::reverse_iterator<Iterator> it) const
1773     {
1774         return &*--it;
1775     }
1776 
1777     // Determine if the range aliases the current string.
1778     //
1779     // This method cannot be const because calling begin/end on copy-on-write
1780     // implementations must have side effects.
1781     // A const version wouldn't make the string unique through this call.
1782     template<class Iterator>
1783     bool IsAliasedRange(Iterator beginIterator, Iterator endIterator)
1784     {
1785         if(!empty() && beginIterator != endIterator)
1786         {
1787             typedef const typename std::iterator_traits<Iterator>::value_type *
1788                 value_pointer;
1789 
1790             value_pointer myBegin(&*begin());
1791             value_pointer myEnd(&*begin() + size());
1792             value_pointer rangeBegin(DereferenceValidIterator(beginIterator));
1793 
1794             const std::less_equal<value_pointer> less_equal = std::less_equal<value_pointer>();
1795             if(less_equal(myBegin, rangeBegin) && less_equal(rangeBegin, myEnd))
1796                 return true;
1797         }
1798         return false;
1799     }
1800 
1801     template <int i> class Selector {};
1802 
1803     flex_string& InsertImplDiscr(iterator p,
1804         size_type n, value_type c, Selector<1>)
1805     {
1806 #ifndef NDEBUG
1807         Invariant checker(*this);
1808 #endif
1809         BOOST_ASSERT(begin() <= p && p <= end());
1810         const size_type insertOffset(p - begin());
1811         const size_type originalSize(size());
1812         if(n < originalSize - insertOffset)
1813         {
1814             // The new characters fit within the original string.
1815             // The characters that are pushed back need to be moved because
1816             // they're aliased.
1817             // The appended characters will all be overwritten by the move.
1818             append(n, value_type(0));
1819             value_type* begin(&*begin());
1820             flex_string_details::pod_move(begin + insertOffset,
1821                 begin + originalSize, begin + insertOffset + n);
1822             std::fill(begin + insertOffset, begin + insertOffset + n, c);
1823         }
1824         else
1825         {
1826             // The new characters exceed the original string.
1827             // The characters that are pushed back can simply be copied since
1828             // they aren't aliased.
1829             // The appended characters will partly be overwritten by the copy.
1830             append(n, c);
1831             value_type* begin(&*begin());
1832             flex_string_details::pod_copy(begin + insertOffset,
1833                 begin + originalSize, begin + insertOffset + n);
1834             std::fill(begin + insertOffset, begin + originalSize, c);
1835         }
1836         return *this;
1837     }
1838 
1839     template<class InputIterator>
1840     flex_string& InsertImplDiscr(iterator i,
1841         InputIterator b, InputIterator e, Selector<0>)
1842     {
1843         InsertImpl(i, b, e,
1844             typename std::iterator_traits<InputIterator>::iterator_category());
1845         return *this;
1846     }
1847 
1848     template <class FwdIterator>
1849     void InsertImpl(iterator i,
1850         FwdIterator s1, FwdIterator s2, std::forward_iterator_tag)
1851     {
1852         if(s1 == s2)
1853         {
1854             // Insert an empty range.
1855             return;
1856         }
1857 
1858         if(IsAliasedRange(s1, s2))
1859         {
1860             // The source range is contained in the current string, copy it
1861             // and recurse.
1862             const flex_string temporary(s1, s2);
1863             InsertImpl(i, temporary.begin(), temporary.end(),
1864                 typename std::iterator_traits<FwdIterator>::iterator_category());
1865             return;
1866         }
1867 
1868 #ifndef NDEBUG
1869         Invariant checker(*this);
1870 #endif
1871         const size_type pos = i - begin();
1872         const typename std::iterator_traits<FwdIterator>::difference_type n2 =
1873             std::distance(s1, s2);
1874 
1875         BOOST_ASSERT(n2 >= 0);
1876         using namespace flex_string_details;
1877         BOOST_ASSERT(pos <= size());
1878 
1879         const typename std::iterator_traits<FwdIterator>::difference_type maxn2 =
1880             capacity() - size();
1881         if (maxn2 < n2)
1882         {
1883             // Reallocate the string.
1884             BOOST_ASSERT(!IsAliasedRange(s1, s2));
1885             reserve(size() + n2);
1886             i = begin() + pos;
1887         }
1888         if (pos + n2 <= size())
1889         {
1890             const iterator tailBegin = end() - n2;
1891             Storage::append(tailBegin, tailBegin + n2);
1892             std::copy(reverse_iterator(tailBegin), reverse_iterator(i),
1893                 reverse_iterator(tailBegin + n2));
1894             std::copy(s1, s2, i);
1895         }
1896         else
1897         {
1898             FwdIterator t = s1;
1899             const size_type old_size = size();
1900             std::advance(t, old_size - pos);
1901             BOOST_ASSERT(std::distance(t, s2) >= 0);
1902             Storage::append(t, s2);
1903             Storage::append(data() + pos, data() + old_size);
1904             std::copy(s1, t, i);
1905         }
1906     }
1907 
1908     template <class InputIterator>
1909     void InsertImpl(iterator insertPosition,
1910         InputIterator inputBegin, InputIterator inputEnd,
1911         std::input_iterator_tag)
1912     {
1913         flex_string temporary(begin(), insertPosition);
1914         for (; inputBegin != inputEnd; ++inputBegin)
1915         {
1916             temporary.push_back(*inputBegin);
1917         }
1918         temporary.append(insertPosition, end());
1919         swap(temporary);
1920     }
1921 
1922 public:
1923     template <class ItOrLength, class ItOrChar>
1924     void insert(iterator p, ItOrLength first_or_n, ItOrChar last_or_c)
1925     {
1926         Selector<std::numeric_limits<ItOrLength>::is_specialized> sel;
1927         InsertImplDiscr(p, first_or_n, last_or_c, sel);
1928     }
1929 
1930     flex_string& erase(size_type pos = 0, size_type n = npos)
1931     {
1932 #ifndef NDEBUG
1933         Invariant checker(*this);
1934 #endif
1935         Enforce(pos <= length(), (std::out_of_range*)0, "");
1936         Procust(n, length() - pos);
1937         std::copy(begin() + pos + n, end(), begin() + pos);
1938         resize(length() - n);
1939         return *this;
1940     }
1941 
1942     iterator erase(iterator position)
1943     {
1944         const size_type pos(position - begin());
1945         erase(pos, 1);
1946         return begin() + pos;
1947     }
1948 
1949     iterator erase(iterator first, iterator last)
1950     {
1951         const size_type pos(first - begin());
1952         erase(pos, last - first);
1953         return begin() + pos;
1954     }
1955 
1956     // Replaces at most n1 chars of *this, starting with pos1 with the content of str
1957     flex_string& replace(size_type pos1, size_type n1, const flex_string& str)
1958     { return replace(pos1, n1, str, 0, npos); }
1959 
1960     // Replaces at most n1 chars of *this, starting with pos1,
1961     // with at most n2 chars of str starting with pos2
1962     flex_string& replace(size_type pos1, size_type n1, const flex_string& str,
1963         size_type pos2, size_type n2)
1964     {
1965         Enforce(pos2 <= str.length(), (std::out_of_range*)0, "");
1966         return replace(pos1, n1, str.data() + pos2,
1967             Min(n2, str.size() - pos2));
1968     }
1969 
1970     // Replaces at most n1 chars of *this, starting with pos, with chars from s
1971     flex_string& replace(size_type pos, size_type n1, const value_type* s)
1972     { return replace(pos, n1, s, traits_type::length(s)); }
1973 
1974     // Replaces at most n1 chars of *this, starting with pos, with n2 occurrences of c
1975     // consolidated with
1976     // Replaces at most n1 chars of *this, starting with pos,
1977     // with at most n2 chars of str.
1978     // str must have at least n2 chars.
1979     template <class StrOrLength, class NumOrChar>
1980     flex_string& replace(size_type pos, size_type n1,
1981         StrOrLength s_or_n2, NumOrChar n_or_c)
1982     {
1983 #ifndef NDEBUG
1984         Invariant checker(*this);
1985 #endif
1986         Enforce(pos <= size(), (std::out_of_range*)0, "");
1987         Procust(n1, length() - pos);
1988         const iterator b = begin() + pos;
1989         return replace(b, b + n1, s_or_n2, n_or_c);
1990     }
1991 
1992     flex_string& replace(iterator i1, iterator i2, const flex_string& str)
1993     { return replace(i1, i2, str.c_str(), str.length()); }
1994 
1995     flex_string& replace(iterator i1, iterator i2, const value_type* s)
1996     { return replace(i1, i2, s, traits_type::length(s)); }
1997 
1998 private:
1999     flex_string& ReplaceImplDiscr(iterator i1, iterator i2,
2000         const value_type* s, size_type n, Selector<2>)
2001     {
2002         BOOST_ASSERT(i1 <= i2);
2003         BOOST_ASSERT(begin() <= i1 && i1 <= end());
2004         BOOST_ASSERT(begin() <= i2 && i2 <= end());
2005         return replace(i1, i2, s, s + n);
2006     }
2007 
2008     flex_string& ReplaceImplDiscr(iterator i1, iterator i2,
2009         size_type n2, value_type c, Selector<1>)
2010     {
2011         const size_type n1 = i2 - i1;
2012         if (n1 > n2)
2013         {
2014             std::fill(i1, i1 + n2, c);
2015             erase(i1 + n2, i2);
2016         }
2017         else
2018         {
2019             std::fill(i1, i2, c);
2020             insert(i2, n2 - n1, c);
2021         }
2022         return *this;
2023     }
2024 
2025     template <class InputIterator>
2026     flex_string& ReplaceImplDiscr(iterator i1, iterator i2,
2027         InputIterator b, InputIterator e, Selector<0>)
2028     {
2029         ReplaceImpl(i1, i2, b, e,
2030             typename std::iterator_traits<InputIterator>::iterator_category());
2031         return *this;
2032     }
2033 
2034     template <class FwdIterator>
2035     void ReplaceImpl(iterator i1, iterator i2,
2036         FwdIterator s1, FwdIterator s2, std::forward_iterator_tag)
2037     {
2038 #ifndef NDEBUG
2039         Invariant checker(*this);
2040 #endif
2041         const typename std::iterator_traits<iterator>::difference_type n1 =
2042             i2 - i1;
2043         BOOST_ASSERT(n1 >= 0);
2044         const typename std::iterator_traits<FwdIterator>::difference_type n2 =
2045             std::distance(s1, s2);
2046         BOOST_ASSERT(n2 >= 0);
2047 
2048         if (IsAliasedRange(s1, s2))
2049         {
2050             // Aliased replace, copy to new string.
2051             flex_string temporary;
2052             temporary.reserve(size() - n1 + n2);
2053             temporary.append(begin(), i1).append(s1, s2).append(i2, end());
2054             swap(temporary);
2055             return;
2056         }
2057 
2058         if (n1 > n2)
2059         {
2060             // Shrinks
2061             std::copy(s1, s2, i1);
2062             erase(i1 + n2, i2);
2063         }
2064         else
2065         {
2066             // Grows
2067             flex_string_details::copy_n(s1, n1, i1);
2068             std::advance(s1, n1);
2069             insert(i2, s1, s2);
2070         }
2071     }
2072 
2073     template <class InputIterator>
2074     void ReplaceImpl(iterator i1, iterator i2,
2075         InputIterator b, InputIterator e, std::input_iterator_tag)
2076     {
2077         flex_string temp(begin(), i1);
2078         temp.append(b, e).append(i2, end());
2079         swap(temp);
2080     }
2081 
2082 public:
2083     template <class T1, class T2>
2084     flex_string& replace(iterator i1, iterator i2,
2085         T1 first_or_n_or_s, T2 last_or_c_or_n)
2086     {
2087         const bool
2088             num1 = std::numeric_limits<T1>::is_specialized,
2089             num2 = std::numeric_limits<T2>::is_specialized;
2090         return ReplaceImplDiscr(i1, i2, first_or_n_or_s, last_or_c_or_n,
2091             Selector<num1 ? (num2 ? 1 : -1) : (num2 ? 2 : 0)>());
2092     }
2093 
2094     size_type copy(value_type* s, size_type n, size_type pos = 0) const
2095     {
2096         Enforce(pos <= size(), (std::out_of_range*)0, "");
2097         n = Min(n, size() - pos);
2098 
2099         flex_string_details::pod_copy(
2100             &*begin() + pos,
2101             &*begin() + pos + n,
2102             s);
2103         return n;
2104     }
2105 
2106     void swap(flex_string& rhs)
2107     {
2108         Storage& srhs = rhs;
2109         this->Storage::swap(srhs);
2110     }
2111 
2112     // 21.3.6 string operations:
2113     const value_type* c_str() const
2114     { return Storage::c_str(); }
2115 
2116     const value_type* data() const
2117     { return Storage::data(); }
2118 
2119     allocator_type get_allocator() const
2120     { return Storage::get_allocator(); }
2121 
2122     size_type find(const flex_string& str, size_type pos = 0) const
2123     { return find(str.data(), pos, str.length()); }
2124 
2125     size_type find (const value_type* s, size_type pos, size_type n) const
2126     {
2127         const size_type size_(size());
2128         if (n + pos > size_)
2129             return npos;
2130         for (; pos < size_; ++pos)
2131         {
2132             if (traits_type::compare(&*begin() + pos, s, n) == 0)
2133             {
2134                 return pos;
2135             }
2136         }
2137         return npos;
2138     }
2139 
2140     size_type find (const value_type* s, size_type pos = 0) const
2141     { return find(s, pos, traits_type::length(s)); }
2142 
2143     size_type find (value_type c, size_type pos = 0) const
2144     { return find(&c, pos, 1); }
2145 
2146     size_type rfind(const flex_string& str, size_type pos = npos) const
2147     { return rfind(str.c_str(), pos, str.length()); }
2148 
2149     size_type rfind(const value_type* s, size_type pos, size_type n) const
2150     {
2151         if (n > length()) return npos;
2152         pos = Min(pos, length() - n);
2153         if (n == 0) return pos;
2154 
2155         const_iterator i(begin() + pos);
2156         for (; ; --i)
2157         {
2158             if (traits_type::eq(*i, *s)
2159                 && traits_type::compare(&*i, s, n) == 0)
2160             {
2161                 return i - begin();
2162             }
2163             if (i == begin()) break;
2164         }
2165         return npos;
2166     }
2167 
2168     size_type rfind(const value_type* s, size_type pos = npos) const
2169     { return rfind(s, pos, traits_type::length(s)); }
2170 
2171     size_type rfind(value_type c, size_type pos = npos) const
2172     { return rfind(&c, pos, 1); }
2173 
2174     size_type find_first_of(const flex_string& str, size_type pos = 0) const
2175     { return find_first_of(str.c_str(), pos, str.length()); }
2176 
2177     size_type find_first_of(const value_type* s,
2178         size_type pos, size_type n) const
2179     {
2180         if (pos > length() || n == 0) return npos;
2181         const_iterator i(begin() + pos),
2182             finish(end());
2183         for (; i != finish; ++i)
2184         {
2185             if (traits_type::find(s, n, *i) != 0)
2186             {
2187                 return i - begin();
2188             }
2189         }
2190         return npos;
2191     }
2192 
2193     size_type find_first_of(const value_type* s, size_type pos = 0) const
2194     { return find_first_of(s, pos, traits_type::length(s)); }
2195 
2196     size_type find_first_of(value_type c, size_type pos = 0) const
2197     { return find_first_of(&c, pos, 1); }
2198 
2199     size_type find_last_of (const flex_string& str,
2200         size_type pos = npos) const
2201     { return find_last_of(str.c_str(), pos, str.length()); }
2202 
2203     size_type find_last_of (const value_type* s, size_type pos,
2204         size_type n) const
2205     {
2206         if (!empty() && n > 0)
2207         {
2208             pos = Min(pos, length() - 1);
2209             const_iterator i(begin() + pos);
2210             for (;; --i)
2211             {
2212                 if (traits_type::find(s, n, *i) != 0)
2213                 {
2214                     return i - begin();
2215                 }
2216                 if (i == begin()) break;
2217             }
2218         }
2219         return npos;
2220     }
2221 
2222     size_type find_last_of (const value_type* s,
2223         size_type pos = npos) const
2224     { return find_last_of(s, pos, traits_type::length(s)); }
2225 
2226     size_type find_last_of (value_type c, size_type pos = npos) const
2227     { return find_last_of(&c, pos, 1); }
2228 
2229     size_type find_first_not_of(const flex_string& str,
2230         size_type pos = 0) const
2231     { return find_first_not_of(str.data(), pos, str.size()); }
2232 
2233     size_type find_first_not_of(const value_type* s, size_type pos,
2234         size_type n) const
2235     {
2236         if (pos < length())
2237         {
2238             const_iterator
2239                 i(begin() + pos),
2240                 finish(end());
2241             for (; i != finish; ++i)
2242             {
2243                 if (traits_type::find(s, n, *i) == 0)
2244                 {
2245                     return i - begin();
2246                 }
2247             }
2248         }
2249         return npos;
2250     }
2251 
2252     size_type find_first_not_of(const value_type* s,
2253         size_type pos = 0) const
2254     { return find_first_not_of(s, pos, traits_type::length(s)); }
2255 
2256     size_type find_first_not_of(value_type c, size_type pos = 0) const
2257     { return find_first_not_of(&c, pos, 1); }
2258 
2259     size_type find_last_not_of(const flex_string& str,
2260         size_type pos = npos) const
2261     { return find_last_not_of(str.c_str(), pos, str.length()); }
2262 
2263     size_type find_last_not_of(const value_type* s, size_type pos,
2264         size_type n) const
2265     {
2266         if (!empty())
2267         {
2268             pos = Min(pos, size() - 1);
2269             const_iterator i(begin() + pos);
2270             for (;; --i)
2271             {
2272                 if (traits_type::find(s, n, *i) == 0)
2273                 {
2274                     return i - begin();
2275                 }
2276                 if (i == begin()) break;
2277             }
2278         }
2279         return npos;
2280     }
2281 
2282     size_type find_last_not_of(const value_type* s,
2283         size_type pos = npos) const
2284     { return find_last_not_of(s, pos, traits_type::length(s)); }
2285 
2286     size_type find_last_not_of (value_type c, size_type pos = npos) const
2287     { return find_last_not_of(&c, pos, 1); }
2288 
2289     flex_string substr(size_type pos = 0, size_type n = npos) const
2290     {
2291         Enforce(pos <= size(), (std::out_of_range*)0, "");
2292         return flex_string(data() + pos, Min(n, size() - pos));
2293     }
2294 
2295     std::ptrdiff_t compare(const flex_string& str) const
2296     {
2297         // FIX due to Goncalo N M de Carvalho July 18, 2005
2298         return compare(0, size(), str);
2299     }
2300 
2301     std::ptrdiff_t compare(size_type pos1, size_type n1,
2302         const flex_string& str) const
2303     { return compare(pos1, n1, str.data(), str.size()); }
2304 
2305     // FIX to compare: added the TC
2306     // (http://www.comeaucomputing.com/iso/lwg-defects.html number 5)
2307     // Thanks to Caleb Epstein for the fix
2308     std::ptrdiff_t compare(size_type pos1, size_type n1,
2309         const value_type* s) const
2310     {
2311         return compare(pos1, n1, s, traits_type::length(s));
2312     }
2313 
2314     std::ptrdiff_t compare(size_type pos1, size_type n1,
2315         const value_type* s, size_type n2) const
2316     {
2317         Enforce(pos1 <= size(), (std::out_of_range*)0, "");
2318         Procust(n1, size() - pos1);
2319         const int r = traits_type::compare(pos1 + data(), s, Min(n1, n2));
2320         return r != 0 ? r : n1 > n2 ? 1 : n1 < n2 ? -1 : 0;
2321     }
2322 
2323     std::ptrdiff_t compare(size_type pos1, size_type n1,
2324         const flex_string& str,
2325         size_type pos2, size_type n2) const
2326     {
2327         Enforce(pos2 <= str.size(), (std::out_of_range*)0, "");
2328         return compare(pos1, n1, str.data() + pos2, Min(n2, str.size() - pos2));
2329     }
2330 
2331     std::ptrdiff_t compare(const value_type* s) const
2332     {
2333         // Could forward to compare(0, size(), s, traits_type::length(s))
2334         // but that does two extra checks
2335         const size_type n1(size()), n2(traits_type::length(s));
2336         const int r = traits_type::compare(data(), s, Min(n1, n2));
2337         return r != 0 ? r : n1 > n2 ? 1 : n1 < n2 ? -1 : 0;
2338     }
2339 };
2340 
2341 // non-member functions
2342 template <typename E, class T, class A, class S>
2343 flex_string<E, T, A, S> operator+(const flex_string<E, T, A, S>& lhs,
2344     const flex_string<E, T, A, S>& rhs)
2345 {
2346     flex_string<E, T, A, S> result;
2347     result.reserve(lhs.size() + rhs.size());
2348     result.append(lhs).append(rhs);
2349     return result;
2350 }
2351 
2352 template <typename E, class T, class A, class S>
2353 flex_string<E, T, A, S> operator+(const typename flex_string<E, T, A, S>::value_type* lhs,
2354     const flex_string<E, T, A, S>& rhs)
2355 {
2356     flex_string<E, T, A, S> result;
2357     const typename flex_string<E, T, A, S>::size_type len =
2358         flex_string<E, T, A, S>::traits_type::length(lhs);
2359     result.reserve(len + rhs.size());
2360     result.append(lhs, len).append(rhs);
2361     return result;
2362 }
2363 
2364 template <typename E, class T, class A, class S>
2365 flex_string<E, T, A, S> operator+(
2366     typename flex_string<E, T, A, S>::value_type lhs,
2367     const flex_string<E, T, A, S>& rhs)
2368 {
2369     flex_string<E, T, A, S> result;
2370     result.reserve(1 + rhs.size());
2371     result.push_back(lhs);
2372     result.append(rhs);
2373     return result;
2374 }
2375 
2376 template <typename E, class T, class A, class S>
2377 flex_string<E, T, A, S> operator+(const flex_string<E, T, A, S>& lhs,
2378     const typename flex_string<E, T, A, S>::value_type* rhs)
2379 {
2380     typedef typename flex_string<E, T, A, S>::size_type size_type;
2381     typedef typename flex_string<E, T, A, S>::traits_type traits_type;
2382 
2383     flex_string<E, T, A, S> result;
2384     const size_type len = traits_type::length(rhs);
2385     result.reserve(lhs.size() + len);
2386     result.append(lhs).append(rhs, len);
2387     return result;
2388 }
2389 
2390 template <typename E, class T, class A, class S>
2391 flex_string<E, T, A, S> operator+(const flex_string<E, T, A, S>& lhs,
2392     typename flex_string<E, T, A, S>::value_type rhs)
2393 {
2394     flex_string<E, T, A, S> result;
2395     result.reserve(lhs.size() + 1);
2396     result.append(lhs);
2397     result.push_back(rhs);
2398     return result;
2399 }
2400 
2401 template <typename E, class T, class A, class S>
2402 inline bool operator==(const flex_string<E, T, A, S>& lhs,
2403     const flex_string<E, T, A, S>& rhs)
2404 { return lhs.compare(rhs) == 0; }
2405 
2406 template <typename E, class T, class A, class S>
2407 inline bool operator==(const typename flex_string<E, T, A, S>::value_type* lhs,
2408     const flex_string<E, T, A, S>& rhs)
2409 { return rhs == lhs; }
2410 
2411 template <typename E, class T, class A, class S>
2412 inline bool operator==(const flex_string<E, T, A, S>& lhs,
2413     const typename flex_string<E, T, A, S>::value_type* rhs)
2414 { return lhs.compare(rhs) == 0; }
2415 
2416 template <typename E, class T, class A, class S>
2417 inline bool operator!=(const flex_string<E, T, A, S>& lhs,
2418     const flex_string<E, T, A, S>& rhs)
2419 { return !(lhs == rhs); }
2420 
2421 template <typename E, class T, class A, class S>
2422 inline bool operator!=(const typename flex_string<E, T, A, S>::value_type* lhs,
2423     const flex_string<E, T, A, S>& rhs)
2424 { return !(lhs == rhs); }
2425 
2426 template <typename E, class T, class A, class S>
2427 inline bool operator!=(const flex_string<E, T, A, S>& lhs,
2428     const typename flex_string<E, T, A, S>::value_type* rhs)
2429 { return !(lhs == rhs); }
2430 
2431 template <typename E, class T, class A, class S>
2432 inline bool operator<(const flex_string<E, T, A, S>& lhs,
2433     const flex_string<E, T, A, S>& rhs)
2434 { return lhs.compare(rhs) < 0; }
2435 
2436 template <typename E, class T, class A, class S>
2437 inline bool operator<(const flex_string<E, T, A, S>& lhs,
2438     const typename flex_string<E, T, A, S>::value_type* rhs)
2439 { return lhs.compare(rhs) < 0; }
2440 
2441 template <typename E, class T, class A, class S>
2442 inline bool operator<(const typename flex_string<E, T, A, S>::value_type* lhs,
2443     const flex_string<E, T, A, S>& rhs)
2444 { return rhs.compare(lhs) > 0; }
2445 
2446 template <typename E, class T, class A, class S>
2447 inline bool operator>(const flex_string<E, T, A, S>& lhs,
2448     const flex_string<E, T, A, S>& rhs)
2449 { return rhs < lhs; }
2450 
2451 template <typename E, class T, class A, class S>
2452 inline bool operator>(const flex_string<E, T, A, S>& lhs,
2453     const typename flex_string<E, T, A, S>::value_type* rhs)
2454 { return rhs < lhs; }
2455 
2456 template <typename E, class T, class A, class S>
2457 bool operator>(const typename flex_string<E, T, A, S>::value_type* lhs,
2458     const flex_string<E, T, A, S>& rhs)
2459 { return rhs < lhs; }
2460 
2461 template <typename E, class T, class A, class S>
2462 inline bool operator<=(const flex_string<E, T, A, S>& lhs,
2463     const flex_string<E, T, A, S>& rhs)
2464 { return !(rhs < lhs); }
2465 
2466 template <typename E, class T, class A, class S>
2467 inline bool operator<=(const flex_string<E, T, A, S>& lhs,
2468     const typename flex_string<E, T, A, S>::value_type* rhs)
2469 { return !(rhs < lhs); }
2470 
2471 template <typename E, class T, class A, class S>
2472 bool operator<=(const typename flex_string<E, T, A, S>::value_type* lhs,
2473     const flex_string<E, T, A, S>& rhs)
2474 { return !(rhs < lhs); }
2475 
2476 template <typename E, class T, class A, class S>
2477 bool operator>=(const flex_string<E, T, A, S>& lhs,
2478     const flex_string<E, T, A, S>& rhs)
2479 { return !(lhs < rhs); }
2480 
2481 template <typename E, class T, class A, class S>
2482 bool operator>=(const flex_string<E, T, A, S>& lhs,
2483     const typename flex_string<E, T, A, S>::value_type* rhs)
2484 { return !(lhs < rhs); }
2485 
2486 template <typename E, class T, class A, class S>
2487 inline bool operator>=(const typename flex_string<E, T, A, S>::value_type* lhs,
2488     const flex_string<E, T, A, S>& rhs)
2489 { return !(lhs < rhs); }
2490 
2491 template <typename E, class T, class A, class S>
2492 void swap(flex_string<E, T, A, S>& lhs, flex_string<E, T, A, S>& rhs)
2493 {
2494     // subclause 21.3.7.8:
2495     lhs.swap(rhs);
2496 }
2497 
2498 template <typename E, class T, class A, class S>
2499 inline std::basic_istream<typename flex_string<E, T, A, S>::value_type,
2500     typename flex_string<E, T, A, S>::traits_type>&
2501 operator>>(
2502     std::basic_istream<typename flex_string<E, T, A, S>::value_type,
2503     typename flex_string<E, T, A, S>::traits_type>& is,
2504     flex_string<E, T, A, S>& str);
2505 
2506 template <typename E, class T, class A, class S>
2507 std::basic_ostream<typename flex_string<E, T, A, S>::value_type,
2508     typename flex_string<E, T, A, S>::traits_type>&
2509 operator<<(
2510     std::basic_ostream<typename flex_string<E, T, A, S>::value_type,
2511     typename flex_string<E, T, A, S>::traits_type>& os,
2512     const flex_string<E, T, A, S>& str)
2513 { return os << str.c_str(); }
2514 
2515 template <typename E1, class T, class A, class S>
2516 const typename flex_string<E1, T, A, S>::size_type
2517 flex_string<E1, T, A, S>::npos = (typename flex_string<E1, T, A, S>::size_type)(-1);
2518 
2519 ///////////////////////////////////////////////////////////////////////////////
2520 }   // namespace util
2521 }   // namespace wave
2522 }   // namespace boost
2523 
2524 #if BOOST_WAVE_SERIALIZATION != 0
2525 ///////////////////////////////////////////////////////////////////////////////
2526 namespace boost { namespace serialization {
2527 
2528 #if !defined(BOOST_WAVE_FLEX_STRING_SERIALIZATION_HACK)
2529 
2530 // FIXME: This doesn't work because of the missing flex_string::operator>>()
2531 template <typename E, class T, class A, class S>
2532 struct implementation_level<boost::wave::util::flex_string<E, T, A, S> >
2533 {
2534     typedef mpl::integral_c_tag tag;
2535     typedef mpl::int_<boost::serialization::primitive_type> type;
2536     BOOST_STATIC_CONSTANT(
2537         int,
2538         value = implementation_level::type::value
2539     );
2540 };
2541 
2542 #else
2543 
2544 //  We serialize flex_strings as vectors of char's for now
2545 template<class Archive, typename E, class T, class A, class S>
2546 inline void save(Archive & ar,
2547     boost::wave::util::flex_string<E, T, A, S> const &t,
2548     const unsigned int file_version)
2549 {
2550     boost::serialization::stl::save_collection<
2551         Archive, wave::util::flex_string<E, T, A, S> >(ar, t);
2552 }
2553 
2554 template<class Archive, typename E, class T, class A, class S>
2555 inline void load(Archive & ar, boost::wave::util::flex_string<E, T, A, S> &t,
2556     const unsigned int file_version)
2557 {
2558     boost::serialization::stl::load_collection<
2559         Archive, boost::wave::util::flex_string<E, T, A, S>,
2560         boost::serialization::stl::archive_input_seq<
2561             Archive, boost::wave::util::flex_string<E, T, A, S> >,
2562         boost::serialization::stl::reserve_imp<
2563             boost::wave::util::flex_string<E, T, A, S> >
2564     >(ar, t);
2565 }
2566 
2567 // split non-intrusive serialization function member into separate
2568 // non intrusive save/load member functions
2569 template<class Archive, typename E, class T, class A, class S>
2570 inline void serialize(Archive & ar, boost::wave::util::flex_string<E, T, A, S> &t,
2571     const unsigned int file_version)
2572 {
2573     boost::serialization::split_free(ar, t, file_version);
2574 }
2575 
2576 #endif
2577 
2578 ///////////////////////////////////////////////////////////////////////////////
2579 }} // boost::serialization
2580 #endif
2581 
2582 // the suffix header occurs after all of the code
2583 #ifdef BOOST_HAS_ABI_HEADERS
2584 #include BOOST_ABI_SUFFIX
2585 #endif
2586 
2587 #endif // BOOST_FLEX_STRING_INC_