text: /*=============================================================================
      Boost.Wave: A Standard compliant C++ preprocessor library
      http://www.boost.org/
  
      Copyright (c) 2001 by Andrei Alexandrescu. Distributed under the Boost
      Software License, Version 1.0. (See accompanying file
      LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  =============================================================================*/
  
  // This code is taken from: 
  // Andrei Alexandrescu, Generic<Programming>: A Policy-Based basic_string 
  // Implementation. http://www.cuj.com/documents/s=7994/cujcexp1906alexandr/
  //
  // #HK030306: 
  //      - Moved into the namespace boost::wave::util 
  //      - Added a bunch of missing typename(s) 
  //      - Integrated with boost config
  //      - Added a missing header include
  //      - Added special constructors and operator= to allow CowString to be 
  //        a real COW-string (removed unnecessary data copying)
  //      - Fixed a string terminating bug in append
  //
  // #HK040109:
  //      - Incorporated the changes from Andrei's latest version of this class
  //
  // #HK070307:
  //      - Once again incorporated the changes from Andrei's latest version of 
  //        this class
  //
  // #HK090523:
  //      - Incorporated the changes from latest version of flex_string as 
  //        maintained in Loki
  
  #ifndef FLEX_STRING_INC_
  #define FLEX_STRING_INC_
  
  /*
  ////////////////////////////////////////////////////////////////////////////////
  template <typename E, class A = @>
  class StoragePolicy
  {
      typedef E value_type;
      typedef @ iterator;
      typedef @ const_iterator;
      typedef A allocator_type;
      typedef @ size_type;
      
      StoragePolicy(const StoragePolicy& s);
      StoragePolicy(const A&);
      StoragePolicy(const E* s, size_type len, const A&);
      StoragePolicy(size_type len, E c, const A&);
      ~StoragePolicy();
  
      iterator begin();
      const_iterator begin() const;
      iterator end();
      const_iterator end() const;
      
      size_type size() const;
      size_type max_size() const;
      size_type capacity() const;
  
      void reserve(size_type res_arg);
  
      void append(const E* s, size_type sz);
      
      template <class InputIterator>
      void append(InputIterator b, InputIterator e);
  
      void resize(size_type newSize, E fill);
  
      void swap(StoragePolicy& rhs);
      
      const E* c_str() const;
      const E* data() const;
      
      A get_allocator() const;
  };
  ////////////////////////////////////////////////////////////////////////////////
  */
  
  #include <boost/config.hpp>
  #include <boost/assert.hpp>
  #include <boost/throw_exception.hpp>
  
  #include <boost/iterator/reverse_iterator.hpp>
  
  #include <boost/wave/wave_config.hpp>
  #if BOOST_WAVE_SERIALIZATION != 0
  #include <boost/serialization/serialization.hpp>
  #include <boost/serialization/split_free.hpp>
  #include <boost/serialization/collections_save_imp.hpp>
  #include <boost/serialization/collections_load_imp.hpp>
  #define BOOST_WAVE_FLEX_STRING_SERIALIZATION_HACK 1
  #endif
  
  #include <memory>
  #include <new>
  #include <string>
  #include <vector>
  #include <algorithm>
  #include <functional>
  #include <limits>
  #include <stdexcept>
  
  #if defined(__PATHSCALE__)
    #include <ios>
  #else
    #include <iosfwd>
  #endif
  
  #include <cstddef>
  #include <cstring>
  #include <cstdlib>
  
  // this must occur after all of the includes and before any code appears
  #ifdef BOOST_HAS_ABI_HEADERS
  #include BOOST_ABI_PREFIX
  #endif
  
  ///////////////////////////////////////////////////////////////////////////////
  namespace boost {
  namespace wave {
  namespace util {
  
  namespace flex_string_details
  {
      template <class InIt, class OutIt>
      OutIt copy_n(InIt b, 
          typename std::iterator_traits<InIt>::difference_type n, OutIt d)
      {
          for (/**/; n != 0; --n, ++b, ++d)
          {
              *d = *b;
          }
          return d;
      }
  
      template <class Pod, class T>
      inline void pod_fill(Pod* b, Pod* e, T c)
      {
          switch ((e - b) & 7)
          {
          case 0:
              while (b != e)
              {
                  *b = c; ++b;
          case 7: *b = c; ++b;
          case 6: *b = c; ++b;
          case 5: *b = c; ++b;
          case 4: *b = c; ++b;
          case 3: *b = c; ++b;
          case 2: *b = c; ++b;
          case 1: *b = c; ++b;
              }
          }
      }
  
      template <class Pod>
      inline void pod_move(const Pod* b, const Pod* e, Pod* d)
      {
          using namespace std;
          memmove(d, b, (e - b) * sizeof(*b));
      }
  
      template <class Pod>
      inline Pod* pod_copy(const Pod* b, const Pod* e, Pod* d)
      {
          const std::size_t s = e - b;
          using namespace std;
          memcpy(d, b, s * sizeof(*b));
          return d + s;
      }
  
      template <typename T> struct get_unsigned
      {
          typedef T result;
      };
  
      template <> struct get_unsigned<char>
      {
          typedef unsigned char result;
      };
  
      template <> struct get_unsigned<signed char>
      {
          typedef unsigned char result;
      };
  
      template <> struct get_unsigned<short int>
      {
          typedef unsigned short int result;
      };
  
      template <> struct get_unsigned<int>
      {
          typedef unsigned int result;
      };
  
      template <> struct get_unsigned<long int>
      {
          typedef unsigned long int result;
      };
  
      enum Shallow {};
  }
  
  template <class T> class mallocator
  {
  public:
      typedef T                 value_type;
      typedef value_type*       pointer;
      typedef const value_type* const_pointer;
      typedef value_type&       reference;
      typedef const value_type& const_reference;
      typedef std::size_t       size_type;
      //typedef unsigned int      size_type;
      //typedef std::ptrdiff_t    difference_type;
      typedef int               difference_type;
  
      template <class U> 
      struct rebind { typedef mallocator<U> other; };
  
      mallocator() {}
      mallocator(const mallocator&) {}
      //template <class U> 
      //mallocator(const mallocator<U>&) {}
      ~mallocator() {}
  
      pointer address(reference x) const { return &x; }
      const_pointer address(const_reference x) const 
      { 
          return x;
      }
  
      pointer allocate(size_type n, const_pointer = 0) 
      {
          using namespace std;
          void* p = malloc(n * sizeof(T));
          if (!p) boost::throw_exception(std::bad_alloc());
          return static_cast<pointer>(p);
      }
  
      void deallocate(pointer p, size_type) 
      { 
          using namespace std;
          free(p); 
      }
  
      size_type max_size() const 
      { 
          return static_cast<size_type>(-1) / sizeof(T);
      }
  
      void construct(pointer p, const value_type& x) 
      { 
          new(p) value_type(x); 
      }
  
      void destroy(pointer p) 
      { 
          p->~value_type(); 
      }
  
  private:
      void operator=(const mallocator&);
  };
  
  template<> class mallocator<void>
  {
    typedef void        value_type;
    typedef void*       pointer;
    typedef const void* const_pointer;
  
    template <class U> 
    struct rebind { typedef mallocator<U> other; };
  };
  
  template <class T>
  inline bool operator==(const mallocator<T>&, 
                         const mallocator<T>&) {
    return true;
  }
  
  template <class T>
  inline bool operator!=(const mallocator<T>&, 
                         const mallocator<T>&) {
    return false;
  }
  
  template <class Allocator>
  typename Allocator::pointer Reallocate(
      Allocator& alloc,
      typename Allocator::pointer p, 
      typename Allocator::size_type oldObjCount,
      typename Allocator::size_type newObjCount,
      void*)
  {
      // @@@ not implemented
      return NULL;
  }
  
  template <class Allocator>
  typename Allocator::pointer Reallocate(
      Allocator& alloc,
      typename Allocator::pointer p, 
      typename Allocator::size_type oldObjCount,
      typename Allocator::size_type newObjCount,
      mallocator<void>*)
  {
      // @@@ not implemented
      return NULL;
  }
  
  ////////////////////////////////////////////////////////////////////////////////
  // class template SimpleStringStorage
  // Allocates memory with malloc
  ////////////////////////////////////////////////////////////////////////////////
  
  template <typename E, class A = std::allocator<E> >
  class SimpleStringStorage
  {
      // The "public" below exists because MSVC can't do template typedefs
  public:
      struct Data
      {
          Data() : pEnd_(buffer_), pEndOfMem_(buffer_) { buffer_[0] = E(0); }
  
          E* pEnd_;
          E* pEndOfMem_;
          E buffer_[1];
      };
      static const Data emptyString_;
  
      typedef typename A::size_type size_type;
  
  private:
      Data* pData_;
  
      void Init(size_type size, size_type capacity)
      {
          BOOST_ASSERT(size <= capacity);
          if (capacity == 0) 
          {
              pData_ = const_cast<Data*>(&emptyString_);
          }
          else
          {
              // 11-17-2000: comment added: 
              //     No need to allocate (capacity + 1) to 
              //     accommodate the terminating 0, because Data already
              //     has one one character in there
              pData_ = static_cast<Data*>(
                  malloc(sizeof(Data) + capacity * sizeof(E)));
              if (!pData_) boost::throw_exception(std::bad_alloc());
              pData_->pEnd_ = pData_->buffer_ + size;
              pData_->pEndOfMem_ = pData_->buffer_ + capacity;
          }
      }
  
  private:
      // Warning - this doesn't initialize pData_. Used in reserve()
      SimpleStringStorage()
      { }
  
  public:
      typedef E value_type;
      typedef E* iterator;
      typedef const E* const_iterator;
      typedef A allocator_type;
  
      SimpleStringStorage(const SimpleStringStorage& rhs) 
      {
          const size_type sz = rhs.size();
          Init(sz, sz);
          if (sz) flex_string_details::pod_copy(rhs.begin(), rhs.end(), begin());
      }
  
      SimpleStringStorage(const SimpleStringStorage& s, 
          flex_string_details::Shallow) 
          : pData_(s.pData_)
      {
      }
  
      SimpleStringStorage(const A&)
      { pData_ = const_cast<Data*>(&emptyString_); }
  
      SimpleStringStorage(const E* s, size_type len, const A&)
      {
          Init(len, len);
          flex_string_details::pod_copy(s, s + len, begin());
      }
  
      SimpleStringStorage(size_type len, E c, const A&)
      {
          Init(len, len);
          flex_string_details::pod_fill(begin(), end(), c);
      }
  
      SimpleStringStorage& operator=(const SimpleStringStorage& rhs)
      {
          const size_type sz = rhs.size();
          reserve(sz);
          flex_string_details::pod_copy(&*rhs.begin(), &*rhs.end(), begin());
          pData_->pEnd_ = &*begin() + sz;
          return *this;
      }
  
      ~SimpleStringStorage()
      {
          BOOST_ASSERT(begin() <= end());
          if (pData_ != &emptyString_) free(pData_);
      }
  
      iterator begin()
      { return pData_->buffer_; }
  
      const_iterator begin() const
      { return pData_->buffer_; }
  
      iterator end()
      { return pData_->pEnd_; }
  
      const_iterator end() const
      { return pData_->pEnd_; }
  
      size_type size() const
      { return pData_->pEnd_ - pData_->buffer_; }
  
      size_type max_size() const
      { return std::size_t(-1) / sizeof(E) - sizeof(Data) - 1; }
  
      size_type capacity() const
      { return pData_->pEndOfMem_ - pData_->buffer_; }
  
      void reserve(size_type res_arg)
      {
          if (res_arg <= capacity())
          {
              // @@@ insert shrinkage here if you wish
              return;
          }
  
          if (pData_ == &emptyString_) 
          {
              Init(0, res_arg);
          }
          else
          {
              const size_type sz = size();
  
              void* p = realloc(pData_, 
                  sizeof(Data) + res_arg * sizeof(E));
              if (!p) boost::throw_exception(std::bad_alloc());
          
              if (p != pData_)
              {
                  pData_ = static_cast<Data*>(p);
                  pData_->pEnd_ = pData_->buffer_ + sz;
              }
              pData_->pEndOfMem_ = pData_->buffer_ + res_arg;
          }
      }
  
      void append(const E* s, size_type sz)
      {
          const size_type neededCapacity = size() + sz;
  
          if (capacity() < neededCapacity)
          {
              const iterator b = begin();
              static std::less_equal<const E*> le;
              if (le(b, s) && le(s, end()))
              {
                 // aliased
                  const size_type offset = s - b;
                  reserve(neededCapacity);
                  s = begin() + offset;
              }
              else
              {
                  reserve(neededCapacity);
              }
          }
          flex_string_details::pod_copy(s, s + sz, end());
          pData_->pEnd_ += sz;
      }
  
      template <class InputIterator>
      void append(InputIterator b, InputIterator e)
      {
          // @@@ todo: optimize this depending on iterator type
          for (; b != e; ++b)
          {
              *this += *b;
          }
      }
  
      void resize(size_type newSize, E fill)
      {
          const int delta = int(newSize - size());
          if (delta == 0) return;
  
          if (delta > 0)
          {
              if (newSize > capacity()) 
              {
                  reserve(newSize);
              }
              E* e = &*end();
              flex_string_details::pod_fill(e, e + delta, fill);
          }
          pData_->pEnd_ = pData_->buffer_ + newSize;
      }
  
      void swap(SimpleStringStorage& rhs)
      {
          std::swap(pData_, rhs.pData_);
      }
      
      const E* c_str() const
      {
          if (pData_ != &emptyString_) *pData_->pEnd_ = E();
          return pData_->buffer_; 
      }
  
      const E* data() const
      { return pData_->buffer_; }
      
      A get_allocator() const
      { return A(); }
  };
  
  template <typename E, class A>
  const typename SimpleStringStorage<E, A>::Data
  SimpleStringStorage<E, A>::emptyString_ = 
      typename SimpleStringStorage<E, A>::Data();
  
  ////////////////////////////////////////////////////////////////////////////////
  // class template AllocatorStringStorage
  // Allocates with your allocator
  // Takes advantage of the Empty Base Optimization if available
  ////////////////////////////////////////////////////////////////////////////////
  
  template <typename E, class A = std::allocator<E> >
  class AllocatorStringStorage : public A
  {
      typedef typename A::size_type size_type;
      typedef typename SimpleStringStorage<E, A>::Data Data;
  
      void* Alloc(size_type sz, const void* p = 0)
      {
          return A::allocate(1 + (sz - 1) / sizeof(E), 
              static_cast<const char*>(p));
      }
  
      void* Realloc(void* p, size_type oldSz, size_type newSz)
      {
          void* r = Alloc(newSz);
          flex_string_details::pod_copy(p, p + Min(oldSz, newSz), r);
          Free(p, oldSz);
          return r;
      }
  
      void Free(void* p, size_type sz)
      {
          A::deallocate(static_cast<E*>(p), sz);
      }
  
      Data* pData_;
  
      void Init(size_type size, size_type cap)
      {
          BOOST_ASSERT(size <= cap);
  
          if (cap == 0)
          {
              pData_ = const_cast<Data*>(
                  &SimpleStringStorage<E, A>::emptyString_);
          }
          else
          {
              pData_ = static_cast<Data*>(Alloc(
                  cap * sizeof(E) + sizeof(Data)));
              pData_->pEnd_ = pData_->buffer_ + size;
              pData_->pEndOfMem_ = pData_->buffer_ + cap;
          }
      }
  
  public:
      typedef E value_type;
      typedef E* iterator;
      typedef const E* const_iterator;
      typedef A allocator_type;
  
      AllocatorStringStorage() 
      : A(), pData_(0)
      {
      }
  
      AllocatorStringStorage(const AllocatorStringStorage& rhs) 
      : A(rhs.get_allocator())
      {
          const size_type sz = rhs.size();
          Init(sz, sz);
          if (sz) flex_string_details::pod_copy(rhs.begin(), rhs.end(), begin());
      }
  
      AllocatorStringStorage(const AllocatorStringStorage& s, 
          flex_string_details::Shallow) 
      : A(s.get_allocator())
      {
          pData_ = s.pData_;
      }
  
      AllocatorStringStorage(const A& a) : A(a)
      { 
          pData_ = const_cast<Data*>(
              &SimpleStringStorage<E, A>::emptyString_);
      }
  
      AllocatorStringStorage(const E* s, size_type len, const A& a)
      : A(a)
      {
          Init(len, len);
          flex_string_details::pod_copy(s, s + len, begin());
      }
  
      AllocatorStringStorage(size_type len, E c, const A& a)
      : A(a)
      {
          Init(len, len);
          flex_string_details::pod_fill(&*begin(), &*end(), c);
      }
  
      AllocatorStringStorage& operator=(const AllocatorStringStorage& rhs)
      {
          const size_type sz = rhs.size();
          reserve(sz);
          flex_string_details::pod_copy(&*rhs.begin(), &*rhs.end(), begin());
          pData_->pEnd_ = &*begin() + rhs.size();
          return *this;
      }
  
      ~AllocatorStringStorage()
      {
          if (capacity())
          {
              Free(pData_, 
                  sizeof(Data) + capacity() * sizeof(E));
          }
      }
  
      iterator begin()
      { return pData_->buffer_; }
  
      const_iterator begin() const
      { return pData_->buffer_; }
  
      iterator end()
      { return pData_->pEnd_; }
  
      const_iterator end() const
      { return pData_->pEnd_; }
  
      size_type size() const
      { return size_type(end() - begin()); }
  
      size_type max_size() const
      { return A::max_size(); }
  
      size_type capacity() const
      { return size_type(pData_->pEndOfMem_ - pData_->buffer_); }
  
      void resize(size_type n, E c)
      {
          reserve(n);
          iterator newEnd = begin() + n;
          iterator oldEnd = end();
          if (newEnd > oldEnd) 
          {
              // Copy the characters
              flex_string_details::pod_fill(oldEnd, newEnd, c);
          }
          if (capacity()) pData_->pEnd_ = newEnd;
      }
  
      void reserve(size_type res_arg)
      {
          if (res_arg <= capacity())
          {
              // @@@ shrink to fit here 
              return;
          }
  
          A& myAlloc = *this;
          AllocatorStringStorage newStr(myAlloc);
          newStr.Init(size(), res_arg);
  
          flex_string_details::pod_copy(begin(), end(), newStr.begin());
  
          swap(newStr);
      }
  
      template <class ForwardIterator>
      void append(ForwardIterator b, ForwardIterator e)
      {
          const size_type 
              sz = std::distance(b, e),
              neededCapacity = size() + sz;
  
          if (capacity() < neededCapacity)
          {
  //             typedef std::less_equal<const E*> le_type;
  //             BOOST_ASSERT(!(le_type()(begin(), &*b) && le_type()(&*b, end())));
              reserve(neededCapacity);
          }
          std::copy(b, e, end());
          pData_->pEnd_ += sz;
      }
  
      void swap(AllocatorStringStorage& rhs)
      {
          // @@@ The following line is commented due to a bug in MSVC
          //std::swap(lhsAlloc, rhsAlloc);
          std::swap(pData_, rhs.pData_);
      }
  
      const E* c_str() const
      { 
          if (pData_ != &SimpleStringStorage<E, A>::emptyString_) 
          {
              *pData_->pEnd_ = E();
          }
          return &*begin(); 
      }
  
      const E* data() const
      { return &*begin(); }
  
      A get_allocator() const
      { return *this; }
  };
  
  ////////////////////////////////////////////////////////////////////////////////
  // class template VectorStringStorage
  // Uses std::vector
  // Takes advantage of the Empty Base Optimization if available
  ////////////////////////////////////////////////////////////////////////////////
  
  template <typename E, class A = std::allocator<E> >
  class VectorStringStorage : protected std::vector<E, A>
  {
      typedef std::vector<E, A> base;
  
  public: // protected:
      typedef E value_type;
      typedef typename base::iterator iterator;
      typedef typename base::const_iterator const_iterator;
      typedef A allocator_type;
      typedef typename A::size_type size_type;
      
      VectorStringStorage(const VectorStringStorage& s) : base(s)
      { }
      
      VectorStringStorage(const A& a) : base(1, E(), a)
      { }
      
      VectorStringStorage(const E* s, size_type len, const A& a)
      : base(a)
      {
          base::reserve(len + 1);
          base::insert(base::end(), s, s + len);
          // Terminating zero
          base::insert(base::end(), E());
      }
  
      VectorStringStorage(size_type len, E c, const A& a)
      : base(len + 1, c, a)
      {
          // Terminating zero
          base::back() = E();
      }
      
      VectorStringStorage& operator=(const VectorStringStorage& rhs)
      {
          base& v = *this;
          v = rhs;
          return *this;
      }
     
      iterator begin()
      { return base::begin(); }
      
      const_iterator begin() const
      { return base::begin(); }
      
      iterator end()
      { return base::end() - 1; }
      
      const_iterator end() const
      { return base::end() - 1; }
      
      size_type size() const
      { return base::size() - 1; }
  
      size_type max_size() const
      { return base::max_size() - 1; }
  
      size_type capacity() const
      { return base::capacity() - 1; }
  
      void reserve(size_type res_arg)
      { 
          BOOST_ASSERT(res_arg < max_size());
          base::reserve(res_arg + 1); 
      }
      
      void append(const E* s, size_type sz)
      {
          // Check for aliasing because std::vector doesn't do it.
          static std::less_equal<const E*> le;
          if (!base::empty())
          {
              const E* start = &base::front();
              if (le(start, s) && le(s, start + size()))
              {
                  // aliased
                  const size_type offset = s - start;
                  reserve(size() + sz);
                  s = &base::front() + offset;
              }
          }
          base::insert(end(), s, s + sz);
      }
      
      template <class InputIterator>
      void append(InputIterator b, InputIterator e)
      {
          base::insert(end(), b, e);
      }
  
      void resize(size_type n, E c)
      {
          base::reserve(n + 1);
          base::back() = c;
          base::resize(n + 1, c);
          base::back() = E();
      }
  
      void swap(VectorStringStorage& rhs)
      { base::swap(rhs); }
      
      const E* c_str() const
      { return &*begin(); }
  
      const E* data() const
      { return &*begin(); }
      
      A get_allocator() const
      { return base::get_allocator(); }
  };
  
  ////////////////////////////////////////////////////////////////////////////////
  // class template SmallStringOpt
  // Builds the small string optimization over any other storage
  ////////////////////////////////////////////////////////////////////////////////
  
  template <class Storage, unsigned int threshold, 
      typename Align = typename Storage::value_type*>
  class SmallStringOpt
  {
  public:
      typedef typename Storage::value_type value_type;
      typedef value_type* iterator;
      typedef const value_type* const_iterator;
      typedef typename Storage::allocator_type allocator_type;
      typedef typename allocator_type::size_type size_type;
      
  private:
    enum { temp1 = threshold * sizeof(value_type) > sizeof(Storage) 
          ? threshold  * sizeof(value_type) 
          : sizeof(Storage) };
      
      enum { temp2 = temp1 > sizeof(Align) ? temp1 : sizeof(Align) };
  
  public:
      enum { maxSmallString = 
      (temp2 + sizeof(value_type) - 1) / sizeof(value_type) };
      
  private:
      enum { magic = maxSmallString + 1 };
      
      union
      {
          mutable value_type buf_[maxSmallString + 1];
          Align align_;
      };
  
      Storage& GetStorage()
      {
          BOOST_ASSERT(buf_[maxSmallString] == magic);
          Storage* p = reinterpret_cast<Storage*>(&buf_[0]);
          return *p;
      }
  
      const Storage& GetStorage() const
      {
          BOOST_ASSERT(buf_[maxSmallString] == magic);
          const Storage *p = reinterpret_cast<const Storage*>(&buf_[0]);
          return *p;
      }
  
      bool Small() const
      {
          return buf_[maxSmallString] != magic;
      }
  
  public:
    SmallStringOpt(const SmallStringOpt& s)
      {
          if (s.Small())
          {
              flex_string_details::pod_copy(
                  s.buf_, 
                  s.buf_ + s.size(), 
                  buf_);
          }
          else
          {
              new(buf_) Storage(s.GetStorage());
          }
          buf_[maxSmallString] = s.buf_[maxSmallString];
      }
  
      SmallStringOpt(const allocator_type&)
      {
          buf_[maxSmallString] = maxSmallString;
      }
  
      SmallStringOpt(const value_type* s, size_type len, const allocator_type& a)
      {
          if (len <= maxSmallString)
          {
              flex_string_details::pod_copy(s, s + len, buf_);
              buf_[maxSmallString] = value_type(maxSmallString - len);
          }
          else
          {
              new(buf_) Storage(s, len, a);
              buf_[maxSmallString] = magic;
          }
      }
  
      SmallStringOpt(size_type len, value_type c, const allocator_type& a)
      {
          if (len <= maxSmallString)
          {
              flex_string_details::pod_fill(buf_, buf_ + len, c);
              buf_[maxSmallString] = value_type(maxSmallString - len);
          }
          else
          {
              new(buf_) Storage(len, c, a);
              buf_[maxSmallString] = magic;
          }
      }
  
      SmallStringOpt& operator=(const SmallStringOpt& rhs)
      {
          reserve(rhs.size());
          resize(0, 0);
          append(rhs.data(), rhs.size());
          return *this;
      }
  
      ~SmallStringOpt()
      {
          if (!Small()) GetStorage().~Storage();
      }
  
      iterator begin()
      {
          if (Small()) return buf_;
          return &*GetStorage().begin(); 
      }
  
      const_iterator begin() const
      {
          if (Small()) return buf_;
          return &*GetStorage().begin(); 
      }
  
      iterator end()
      {
          if (Small()) return buf_ + maxSmallString - buf_[maxSmallString];
          return &*GetStorage().end(); 
      }
  
      const_iterator end() const
      {
          if (Small()) return buf_ + maxSmallString - buf_[maxSmallString];
          return &*GetStorage().end(); 
      }
  
      size_type size() const
      {
          BOOST_ASSERT(!Small() || maxSmallString >= buf_[maxSmallString]);
          return Small() 
              ? maxSmallString - buf_[maxSmallString] 
              : GetStorage().size();
      }
  
      size_type max_size() const
      { return get_allocator().max_size(); }
  
      size_type capacity() const
      { return Small() ? maxSmallString : GetStorage().capacity(); }
  
      void reserve(size_type res_arg)
      {
          if (Small())
          {
              if (res_arg <= maxSmallString) return;
              SmallStringOpt temp(*this);
              this->~SmallStringOpt();
              new(buf_) Storage(temp.data(), temp.size(), 
                  temp.get_allocator());
              buf_[maxSmallString] = magic;
              GetStorage().reserve(res_arg);
          }
          else
          {
              GetStorage().reserve(res_arg);
          }
          BOOST_ASSERT(capacity() >= res_arg);
      }
  
      void append(const value_type* s, size_type sz)
      {
          if (!Small())
          {
              GetStorage().append(s, sz);
          }
          else
          {
              // append to a small string
              const size_type neededCapacity = 
                  maxSmallString - buf_[maxSmallString] + sz;
  
              if (maxSmallString < neededCapacity)
              {
                  // need to change storage strategy
                  allocator_type alloc;
                  Storage temp(alloc);
                  temp.reserve(neededCapacity);
                  temp.append(buf_, maxSmallString - buf_[maxSmallString]);
                  temp.append(s, sz);
                  buf_[maxSmallString] = magic;
                  new(buf_) Storage(temp.get_allocator());
                  GetStorage().swap(temp);
              }
              else
              {
                  flex_string_details::pod_move(s, s + sz, 
                      buf_ + maxSmallString - buf_[maxSmallString]);
                  buf_[maxSmallString] -= value_type(sz);
              }
          }
      }
  
      template <class InputIterator>
      void append(InputIterator b, InputIterator e)
      {
          // @@@ todo: optimize this depending on iterator type
          for (; b != e; ++b)
          {
              *this += *b;
          }
      }
  
      void resize(size_type n, value_type c)
      {
          if (Small())
          {
              if (n > maxSmallString)
              {
                  // Small string resized to big string
                  SmallStringOpt temp(*this); // can't throw
                  // 11-17-2001: correct exception safety bug
                  Storage newString(temp.data(), temp.size(), 
                      temp.get_allocator());
                  newString.resize(n, c);
                  // We make the reasonable assumption that an empty Storage
                  //     constructor won't throw
                  this->~SmallStringOpt();
                  new(&buf_[0]) Storage(temp.get_allocator());
                  buf_[maxSmallString] = value_type(magic);
                  GetStorage().swap(newString);
              }
              else
              {
                  // Small string resized to small string
                  // 11-17-2001: bug fix: terminating zero not copied
                  size_type toFill = n > size() ? n - size() : 0;
                  flex_string_details::pod_fill(end(), end() + toFill, c);
                  buf_[maxSmallString] = value_type(maxSmallString - n);
              }
          }
          else
          {
              if (n > maxSmallString)
              {
                  // Big string resized to big string
                  GetStorage().resize(n, c);
              }
              else
              {
                  // Big string resized to small string
                  // 11-17=2001: bug fix in the BOOST_ASSERTion below
                  BOOST_ASSERT(capacity() > n);
                  SmallStringOpt newObj(data(), n, get_allocator());
                  newObj.swap(*this);
              }
          }
      }
  
      void swap(SmallStringOpt& rhs)
      {
          if (Small())
          {
              if (rhs.Small())
              {
                  // Small swapped with small
                  std::swap_ranges(buf_, buf_ + maxSmallString + 1, 
                      rhs.buf_);
              }
              else
              {
                  // Small swapped with big
                  // Make a copy of myself - can't throw
                  SmallStringOpt temp(*this);
                  // Nuke myself
                  this->~SmallStringOpt();
                  // Make an empty storage for myself (likely won't throw)
                  new(buf_) Storage(0, value_type(), rhs.get_allocator());
                  buf_[maxSmallString] = magic;
                  // Recurse to this same function
                  swap(rhs);
                  // Nuke rhs
                  rhs.~SmallStringOpt();
                  // Build the new small string into rhs
                  new(&rhs) SmallStringOpt(temp);
              }
          }
          else
          {
              if (rhs.Small())
              {
                  // Big swapped with small
                  // Already implemented, recurse with reversed args
                  rhs.swap(*this);
              }
              else
              {
                  // Big swapped with big
                  GetStorage().swap(rhs.GetStorage());
              }
          }
      }
  
      const value_type* c_str() const
      { 
          if (!Small()) return GetStorage().c_str(); 
          buf_[maxSmallString - buf_[maxSmallString]] = value_type();
          return buf_;
      }
  
      const value_type* data() const
      { return Small() ? buf_ : GetStorage().data(); }
      
      allocator_type get_allocator() const
      { return allocator_type(); }
  };
  
  ////////////////////////////////////////////////////////////////////////////////
  // class template CowString
  // Implements Copy on Write over any storage
  ////////////////////////////////////////////////////////////////////////////////
  
  template <
      typename Storage, 
      typename Align = BOOST_DEDUCED_TYPENAME Storage::value_type*
  >
  class CowString
  {
      typedef typename Storage::value_type E;
      typedef typename flex_string_details::get_unsigned<E>::result RefCountType;
  
  public:
      typedef E value_type;
      typedef typename Storage::iterator iterator;
      typedef typename Storage::const_iterator const_iterator;
      typedef typename Storage::allocator_type allocator_type;
      typedef typename allocator_type::size_type size_type;
      typedef typename Storage::reference reference;
      
  private:
      union
      {
          mutable char buf_[sizeof(Storage)];
          Align align_;
      };
  
      Storage& Data() const
      { 
          Storage* p = reinterpret_cast<Storage*>(&buf_[0]);
          return *p;
      }
  
      RefCountType GetRefs() const
      {
          const Storage& d = Data();
          BOOST_ASSERT(d.size() > 0);
          BOOST_ASSERT(static_cast<RefCountType>(*d.begin()) != 0);
          return *d.begin();
      }
      
      RefCountType& Refs()
      {
          Storage& d = Data();
          BOOST_ASSERT(d.size() > 0);
          return reinterpret_cast<RefCountType&>(*d.begin());
      }
      
      void MakeUnique() const
      {
          BOOST_ASSERT(GetRefs() >= 1);
          if (GetRefs() == 1) return;
  
          union
          {
              char buf_[sizeof(Storage)];
              Align align_;
          } temp;
  
          --(*Data().begin()); // decrement the use count of the remaining object
  
          Storage* p = reinterpret_cast<Storage*>(&temp.buf_[0]);
          new(buf_) Storage(
              *new(p) Storage(Data()), 
              flex_string_details::Shallow());
          *Data().begin() = 1;
      }
  
  public:
      CowString(const CowString& s)
      {
          if (s.GetRefs() == (std::numeric_limits<RefCountType>::max)())
          {
              // must make a brand new copy
              new(buf_) Storage(s.Data()); // non shallow
              Refs() = 1;
          }
          else
          {
              new(buf_) Storage(s.Data(), flex_string_details::Shallow());
              ++Refs();
          }
          BOOST_ASSERT(Data().size() > 0);
      }
      
      CowString(const allocator_type& a)
      {
          new(buf_) Storage(1, 1, a);
      }
      
      CowString(const E* s, size_type len, const allocator_type& a)
      {
          // Warning - MSVC's debugger has trouble tracing through the code below.
          // It seems to be a const-correctness issue
          //
          new(buf_) Storage(a);
          Data().reserve(len + 1);
          Data().resize(1, 1);
          Data().append(s, s + len);
      }
  
      CowString(size_type len, E c, const allocator_type& a)
      {
          new(buf_) Storage(len + 1, c, a);
          Refs() = 1;
      }
      
      CowString& operator=(const CowString& rhs)
      {
  //        CowString(rhs).swap(*this);
          if (--Refs() == 0) 
              Data().~Storage();
          if (rhs.GetRefs() == (std::numeric_limits<RefCountType>::max)())
          {
              // must make a brand new copy
              new(buf_) Storage(rhs.Data()); // non shallow
              Refs() = 1;
          }
          else
          {
              new(buf_) Storage(rhs.Data(), flex_string_details::Shallow());
              ++Refs();
          }
          BOOST_ASSERT(Data().size() > 0);
          return *this;
      }
  
      ~CowString()
      {
          BOOST_ASSERT(Data().size() > 0);
          if (--Refs() == 0) 
              Data().~Storage();
      }
  
      iterator begin()
      {
          BOOST_ASSERT(Data().size() > 0);
          MakeUnique();
          return Data().begin() + 1; 
      }
      
      const_iterator begin() const
      {
          BOOST_ASSERT(Data().size() > 0);
          return Data().begin() + 1; 
      }
      
      iterator end()
      {
          MakeUnique();
          return Data().end(); 
      }
      
      const_iterator end() const
      {
          return Data().end(); 
      }
      
      size_type size() const
      {
          BOOST_ASSERT(Data().size() > 0);
          return Data().size() - 1;
      }
  
      size_type max_size() const
      { 
          BOOST_ASSERT(Data().max_size() > 0);
          return Data().max_size() - 1;
      }
  
      size_type capacity() const
      { 
          BOOST_ASSERT(Data().capacity() > 0);
          return Data().capacity() - 1;
      }
  
      void resize(size_type n, E c)
      {
          BOOST_ASSERT(Data().size() > 0);
          MakeUnique();
          Data().resize(n + 1, c);
      }
  
      template <class FwdIterator>
      void append(FwdIterator b, FwdIterator e)
      {
          MakeUnique();
          Data().append(b, e);
      }
      
      void reserve(size_type res_arg)
      {
          if (capacity() > res_arg) return;
          MakeUnique();
          Data().reserve(res_arg + 1);
      }
      
      void swap(CowString& rhs)
      {
          Data().swap(rhs.Data());
      }
      
      const E* c_str() const
      { 
          BOOST_ASSERT(Data().size() > 0);
          return Data().c_str() + 1;
      }
  
      const E* data() const
      { 
          BOOST_ASSERT(Data().size() > 0);
          return Data().data() + 1;
      }
      
      allocator_type get_allocator() const
      { 
          return Data().get_allocator();
      }
  };
  
  ////////////////////////////////////////////////////////////////////////////////
  // class template flex_string
  // a std::basic_string compatible implementation 
  // Uses a Storage policy 
  ////////////////////////////////////////////////////////////////////////////////
  
  template <typename E,
      class T = std::char_traits<E>,
      class A = std::allocator<E>,
      class Storage = AllocatorStringStorage<E, A> >
  class flex_string : private Storage
  {
  #if defined(BOOST_WAVE_FLEXSTRING_THROW_ON_ENFORCE)
      template <typename Exception>
      static void Enforce(bool condition, Exception*, const char* msg)
      { if (!condition) boost::throw_exception(Exception(msg)); }
  #else
      template <typename Exception>
      static inline void Enforce(bool condition, Exception*, const char* msg)
      { BOOST_ASSERT(condition && msg); }
  #endif // defined(BOOST_WAVE_FLEXSTRING_THROW_ON_ENFORCE)
  
  #ifndef NDEBUG
      bool Sane() const
      {
          return
              begin() <= end() &&
              empty() == (size() == 0) &&
              empty() == (begin() == end()) &&
              size() <= max_size() &&
              capacity() <= max_size() &&
              size() <= capacity();
      }
  
      struct Invariant;
      friend struct Invariant;
      struct Invariant
      {
          Invariant(const flex_string& s) : s_(s)
          {
              BOOST_ASSERT(s_.Sane());
          }
          ~Invariant()
          {
              BOOST_ASSERT(s_.Sane());
          }
      private:
          const flex_string& s_;
          Invariant& operator=(const Invariant&);
      };
  #endif
  
  public:
      // types
      typedef T traits_type;
      typedef typename traits_type::char_type value_type;
      typedef A allocator_type;
      typedef typename A::size_type size_type;
      typedef typename A::difference_type difference_type;
      
      typedef typename A::reference reference;
      typedef typename A::const_reference const_reference;
      typedef typename A::pointer pointer;
      typedef typename A::const_pointer const_pointer;
      
      typedef typename Storage::iterator iterator;
      typedef typename Storage::const_iterator const_iterator;
  
      typedef boost::reverse_iterator<iterator> reverse_iterator;
      typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
  
      static const size_type npos;    // = size_type(-1)
  
  private:
      static size_type Min(size_type lhs, size_type rhs)
      { return lhs < rhs ? lhs : rhs; }
      static void Procust(size_type& n, size_type nmax)
      { if (n > nmax) n = nmax; }
      
  public:    
      // 21.3.1 construct/copy/destroy
      explicit flex_string(const A& a = A())
      : Storage(a) 
      {}
      
      flex_string(const flex_string& str)
      : Storage(str) 
      {
      }
      
      flex_string(const flex_string& str, size_type pos, 
          size_type n = npos, const A& a = A())
      : Storage(a) 
      {
          Enforce(pos <= str.size(), (std::out_of_range*)0, "");
          assign(str, pos, n);
      }
      
      flex_string(const value_type* s, const A& a = A())
      : Storage(s, traits_type::length(s), a)
      {}
      
      flex_string(const value_type* s, size_type n, const A& a = A())
      : Storage(s, n, a)
      {}
      
      flex_string(size_type n, value_type c, const A& a = A())
      : Storage(n, c, a)
      {}
  
      template <class InputIterator>
      flex_string(InputIterator begin, InputIterator end, const A& a = A())
      : Storage(a)
      {
          assign(begin, end);
      }
  
      ~flex_string()
      {}
      
      flex_string& operator=(const flex_string& str)
      {
          if (this != &str) {
              Storage& s = *this;
              s = str;
          }
          return *this;
      }   
      
      flex_string& operator=(const value_type* s)
      {
          assign(s);
          return *this;
      }
  
      flex_string& operator=(value_type c)
      {
          assign(1, c);
          return *this;
      }
      
      // 21.3.2 iterators:
      iterator begin()
      { return Storage::begin(); }
      
      const_iterator begin() const
      { return Storage::begin(); }
      
      iterator end()
      { return Storage::end(); }
      
      const_iterator end() const
      { return Storage::end(); }
  
      reverse_iterator rbegin()
      { return reverse_iterator(end()); }
      
      const_reverse_iterator rbegin() const
      { return const_reverse_iterator(end()); }
      
      reverse_iterator rend()
      { return reverse_iterator(begin()); }
      
      const_reverse_iterator rend() const
      { return const_reverse_iterator(begin()); }
  
  #if BOOST_WAVE_FLEX_STRING_SERIALIZATION_HACK != 0
      //  temporary hack to make it easier to serialize flex_string's using
      //  the Boost.Serialization library 
      value_type & back() { return *(begin()+size()-1); }
      value_type const& back() const { return *(begin()+size()-1); }
  #endif
  
      // 21.3.3 capacity:
      size_type size() const
      { return Storage::size(); }
      
      size_type length() const
      { return size(); }
      
      size_type max_size() const
      { return Storage::max_size(); }
  
      void resize(size_type n, value_type c)
      { Storage::resize(n, c); }
      
      void resize(size_type n)
      { resize(n, value_type()); }
      
      size_type capacity() const
      { return Storage::capacity(); }
      
      void reserve(size_type res_arg = 0)
      {
          Enforce(res_arg <= max_size(), (std::length_error*)0, "");
          Storage::reserve(res_arg);
      }
      
      void clear()
      { resize(0); } 
      
      bool empty() const
      { return size() == 0; }
      
      // 21.3.4 element access:
      const_reference operator[](size_type pos) const
      { return *(begin() + pos); }
      
      reference operator[](size_type pos)
      { return *(begin() + pos); }
  
      const_reference at(size_type n) const
      {
          Enforce(n < size(), (std::out_of_range*)0, "");
          return (*this)[n];
      }
      
      reference at(size_type n)
      {
          Enforce(n < size(), (std::out_of_range*)0, "");
          return (*this)[n];
      }
      
      // 21.3.5 modifiers:
      flex_string& operator+=(const flex_string& str)
      { return append(str); }
      
      flex_string& operator+=(const value_type* s)
      { return append(s); }
  
      flex_string& operator+=(value_type c)
      { 
          push_back(c);
          return *this;
      }
      
      flex_string& append(const flex_string& str)
      { return append(str, 0, npos); }
      
      flex_string& append(const flex_string& str, const size_type pos,
          size_type n)
      { 
          const size_type sz = str.size();
          Enforce(pos <= sz, (std::out_of_range*)0, "");
          Procust(n, sz - pos);
          return append(str.c_str() + pos, n); 
      }
      
      flex_string& append(const value_type* s, const size_type n)
      { 
  #ifndef NDEBUG
          Invariant checker(*this); 
  #endif
          if (IsAliasedRange(s, s + n))
          {
              const size_type offset = s - &*begin();
              Storage::reserve(size() + n);
              s = &*begin() + offset;
          }
          Storage::append(s, s+ n); 
          return *this;
      }
      
      flex_string& append(const value_type* s)
      { return append(s, traits_type::length(s)); }
      
      flex_string& append(size_type n, value_type c)
      { 
          resize(size() + n, c);
          return *this;
      }
  
      template<class InputIterator>
      flex_string& append(InputIterator first, InputIterator last)
      {
          insert(end(), first, last);
          return *this;
      }
  
      void push_back(value_type c)
      { 
          const size_type cap = capacity();
          if (size() == cap)
          {
              reserve(cap << 1u);
          }
          Storage::append(&c, &c + 1);
      }
  
      flex_string& assign(const flex_string& str)
      { 
          if (&str == this) return *this;
          return assign(str.data(), str.size());
      }
      
      flex_string& assign(const flex_string& str, size_type pos,
          size_type n)
      { 
          const size_type sz = str.size();
          Enforce(pos <= str.size(), (std::out_of_range*)0, "");
          Procust(n, sz - pos);
          return assign(str.data() + pos, n);
      }
      
      flex_string& assign(const value_type* s, size_type n)
      {
  #ifndef NDEBUG
          Invariant checker(*this); 
  #endif
          if (size() >= n)
          {
              std::copy(s, s + n, begin());
              resize(n);
          }
          else
          {
              const value_type *const s2 = s + size();
              std::copy(s, s2, begin());
              append(s2, n - size());
          }
          return *this;
      }
      
      flex_string& assign(const value_type* s)
      { return assign(s, traits_type::length(s)); }
      
      template <class ItOrLength, class ItOrChar>
      flex_string& assign(ItOrLength first_or_n, ItOrChar last_or_c)
      { return replace(begin(), end(), first_or_n, last_or_c); }
      
      flex_string& insert(size_type pos1, const flex_string& str)
      { return insert(pos1, str.data(), str.size()); }
      
      flex_string& insert(size_type pos1, const flex_string& str,
          size_type pos2, size_type n)
      { 
          Enforce(pos2 <= str.length(), (std::out_of_range*)0, "");
          Procust(n, str.length() - pos2);
          return insert(pos1, str.data() + pos2, n); 
      }
      
      flex_string& insert(size_type pos, const value_type* s, size_type n)
      { 
          Enforce(pos <= length(), (std::out_of_range*)0, "");
          insert(begin() + pos, s, s + n); 
          return *this;
      }
      
      flex_string& insert(size_type pos, const value_type* s)
      { return insert(pos, s, traits_type::length(s)); }
      
      flex_string& insert(size_type pos, size_type n, value_type c)
      { 
          Enforce(pos <= length(), (std::out_of_range*)0, "");
          insert(begin() + pos, n, c);
          return *this;
      }
      
      iterator insert(iterator p, value_type c = value_type()) 
      {
          const size_type pos = p - begin();
          insert(pos, &c, 1);
          return begin() + pos;
      }
      
  private:
      // Care must be taken when dereferencing some iterator types.
      //
      // Users can implement this function in their namespace if their storage 
      // uses a special iterator type, the function will be found through ADL.
      template<class Iterator>
      const typename std::iterator_traits<Iterator>::value_type* 
      DereferenceValidIterator(Iterator it) const
      {
          return &*it;
      }
  
      // Care must be taken when dereferencing a reverse iterators, hence this 
      // special case. This isn't in the std namespace so as not to pollute it or 
      // create name clashes.
      template<typename Iterator>
      const typename std::iterator_traits<Iterator>::value_type* 
      DereferenceValidIterator(std::reverse_iterator<Iterator> it) const
      {
          return &*--it;
      }
  
      // Determine if the range aliases the current string.
      //
      // This method cannot be const because calling begin/end on copy-on-write 
      // implementations must have side effects.
      // A const version wouldn't make the string unique through this call.
      template<class Iterator>
      bool IsAliasedRange(Iterator beginIterator, Iterator endIterator)
      {
          if(!empty() && beginIterator != endIterator)
          {
              typedef const typename std::iterator_traits<Iterator>::value_type * 
                  pointer;
  
              pointer myBegin(&*begin());
              pointer myEnd(&*begin() + size());
              pointer rangeBegin(DereferenceValidIterator(beginIterator));
  
              const std::less_equal<pointer> less_equal = std::less_equal<pointer>();
              if(less_equal(myBegin, rangeBegin) && less_equal(rangeBegin, myEnd))
                  return true;
          }
          return false;
      }
  
      template <int i> class Selector {};
  
      flex_string& InsertImplDiscr(iterator p, 
          size_type n, value_type c, Selector<1>)
      { 
  #ifndef NDEBUG
          Invariant checker(*this); 
  #endif
          BOOST_ASSERT(begin() <= p && p <= end());
          const size_type insertOffset(p - begin());
          const size_type originalSize(size());
          if(n < originalSize - insertOffset)
          {
              // The new characters fit within the original string.
              // The characters that are pushed back need to be moved because 
              // they're aliased.
              // The appended characters will all be overwritten by the move.
              append(n, value_type(0));
              value_type* begin(&*begin());
              flex_string_details::pod_move(begin + insertOffset, 
                  begin + originalSize, begin + insertOffset + n);
              std::fill(begin + insertOffset, begin + insertOffset + n, c);
          }
          else
          {
              // The new characters exceed the original string.
              // The characters that are pushed back can simply be copied since 
              // they aren't aliased.
              // The appended characters will partly be overwritten by the copy.
              append(n, c);
              value_type* begin(&*begin());
              flex_string_details::pod_copy(begin + insertOffset, 
                  begin + originalSize, begin + insertOffset + n);
              std::fill(begin + insertOffset, begin + originalSize, c);
          }
          return *this;
      }
  
      template<class InputIterator>
      flex_string& InsertImplDiscr(iterator i,
          InputIterator b, InputIterator e, Selector<0>)
      { 
          InsertImpl(i, b, e, 
              typename std::iterator_traits<InputIterator>::iterator_category());
          return *this;
      }
  
      template <class FwdIterator>
      void InsertImpl(iterator i,
          FwdIterator s1, FwdIterator s2, std::forward_iterator_tag)
      { 
          if(s1 == s2)
          {
              // Insert an empty range.
              return;
          }
  
          if(IsAliasedRange(s1, s2))
          {
              // The source range is contained in the current string, copy it 
              // and recurse.
              const flex_string temporary(s1, s2);
              InsertImpl(i, temporary.begin(), temporary.end(),
                  typename std::iterator_traits<FwdIterator>::iterator_category());
              return;
          }
  
  #ifndef NDEBUG
          Invariant checker(*this); 
  #endif
          const size_type pos = i - begin();
          const typename std::iterator_traits<FwdIterator>::difference_type n2 = 
              std::distance(s1, s2);
  
          BOOST_ASSERT(n2 >= 0);
          using namespace flex_string_details;
          BOOST_ASSERT(pos <= size());
  
          const typename std::iterator_traits<FwdIterator>::difference_type maxn2 = 
              capacity() - size();
          if (maxn2 < n2)
          {
              // Reallocate the string.
              BOOST_ASSERT(!IsAliasedRange(s1, s2));
              reserve(size() + n2);
              i = begin() + pos;
          }
          if (pos + n2 <= size())
          {
              const iterator tailBegin = end() - n2;
              Storage::append(tailBegin, tailBegin + n2);
              std::copy(reverse_iterator(tailBegin), reverse_iterator(i), 
                  reverse_iterator(tailBegin + n2));
              std::copy(s1, s2, i);
          }
          else
          {
              FwdIterator t = s1;
              const size_type old_size = size();
              std::advance(t, old_size - pos);
              BOOST_ASSERT(std::distance(t, s2) >= 0);
              Storage::append(t, s2);
              Storage::append(data() + pos, data() + old_size);
              std::copy(s1, t, i);
          }
      }
  
      template <class InputIterator>
      void InsertImpl(iterator insertPosition,
          InputIterator inputBegin, InputIterator inputEnd, 
          std::input_iterator_tag)
      {
          flex_string temporary(begin(), insertPosition);
          for (; inputBegin != inputEnd; ++inputBegin)
          {
              temporary.push_back(*inputBegin);
          }
          temporary.append(insertPosition, end());
          swap(temporary);
      }
  
  public:
      template <class ItOrLength, class ItOrChar>
      void insert(iterator p, ItOrLength first_or_n, ItOrChar last_or_c)
      { 
          Selector<std::numeric_limits<ItOrLength>::is_specialized> sel;
          InsertImplDiscr(p, first_or_n, last_or_c, sel);
      }
      
      flex_string& erase(size_type pos = 0, size_type n = npos)
      { 
  #ifndef NDEBUG
          Invariant checker(*this); 
  #endif
          Enforce(pos <= length(), (std::out_of_range*)0, "");
          Procust(n, length() - pos);
          std::copy(begin() + pos + n, end(), begin() + pos);
          resize(length() - n);
          return *this;
      }
      
      iterator erase(iterator position)
      {
          const size_type pos(position - begin());
          erase(pos, 1);
          return begin() + pos;
      }
      
      iterator erase(iterator first, iterator last)
      {
          const size_type pos(first - begin());
          erase(pos, last - first);
          return begin() + pos;
      }
  
      // Replaces at most n1 chars of *this, starting with pos1 with the content of str
      flex_string& replace(size_type pos1, size_type n1, const flex_string& str)
      { return replace(pos1, n1, str, 0, npos); }
      
      // Replaces at most n1 chars of *this, starting with pos1,
      // with at most n2 chars of str starting with pos2
      flex_string& replace(size_type pos1, size_type n1, const flex_string& str,
          size_type pos2, size_type n2)
      {
          Enforce(pos2 <= str.length(), (std::out_of_range*)0, "");
          return replace(pos1, n1, str.data() + pos2, 
              Min(n2, str.size() - pos2));
      }
      
      // Replaces at most n1 chars of *this, starting with pos, with chars from s
      flex_string& replace(size_type pos, size_type n1, const value_type* s)
      { return replace(pos, n1, s, traits_type::length(s)); }
      
      // Replaces at most n1 chars of *this, starting with pos, with n2 occurences of c
      // consolidated with
      // Replaces at most n1 chars of *this, starting with pos,
      // with at most n2 chars of str.
      // str must have at least n2 chars.
      template <class StrOrLength, class NumOrChar>
      flex_string& replace(size_type pos, size_type n1, 
          StrOrLength s_or_n2, NumOrChar n_or_c)
      {
  #ifndef NDEBUG
          Invariant checker(*this); 
  #endif
          Enforce(pos <= size(), (std::out_of_range*)0, "");
          Procust(n1, length() - pos);
          const iterator b = begin() + pos;
          return replace(b, b + n1, s_or_n2, n_or_c);
      }
  
      flex_string& replace(iterator i1, iterator i2, const flex_string& str)
      { return replace(i1, i2, str.c_str(), str.length()); }
      
      flex_string& replace(iterator i1, iterator i2, const value_type* s)
      { return replace(i1, i2, s, traits_type::length(s)); }
  
  private:
      flex_string& ReplaceImplDiscr(iterator i1, iterator i2, 
          const value_type* s, size_type n, Selector<2>)
      { 
          BOOST_ASSERT(i1 <= i2);
          BOOST_ASSERT(begin() <= i1 && i1 <= end());
          BOOST_ASSERT(begin() <= i2 && i2 <= end());
          return replace(i1, i2, s, s + n); 
      }
      
      flex_string& ReplaceImplDiscr(iterator i1, iterator i2,
          size_type n2, value_type c, Selector<1>)
      { 
          const size_type n1 = i2 - i1;
          if (n1 > n2)
          {
              std::fill(i1, i1 + n2, c);
              erase(i1 + n2, i2);
          }
          else
          {
              std::fill(i1, i2, c);
              insert(i2, n2 - n1, c);
          }
          return *this;
      }
  
      template <class InputIterator>
      flex_string& ReplaceImplDiscr(iterator i1, iterator i2,
          InputIterator b, InputIterator e, Selector<0>)
      { 
          ReplaceImpl(i1, i2, b, e, 
              typename std::iterator_traits<InputIterator>::iterator_category());
          return *this;
      }
  
      template <class FwdIterator>
      void ReplaceImpl(iterator i1, iterator i2,
          FwdIterator s1, FwdIterator s2, std::forward_iterator_tag)
      { 
  #ifndef NDEBUG
          Invariant checker(*this); 
  #endif
          const typename std::iterator_traits<iterator>::difference_type n1 = 
              i2 - i1;
          BOOST_ASSERT(n1 >= 0);
          const typename std::iterator_traits<FwdIterator>::difference_type n2 = 
          std::distance(s1, s2);
          BOOST_ASSERT(n2 >= 0);
  
          if (IsAliasedRange(s1, s2))
          {
              // Aliased replace, copy to new string.
              flex_string temporary;
              temporary.reserve(size() - n1 + n2);
              temporary.append(begin(), i1).append(s1, s2).append(i2, end());
              swap(temporary);
              return;
          }
  
          if (n1 > n2)
          {
              // Shrinks
              std::copy(s1, s2, i1);
              erase(i1 + n2, i2);
          }
          else
          {
              // Grows
              flex_string_details::copy_n(s1, n1, i1);
              std::advance(s1, n1);
              insert(i2, s1, s2);
          }
      }
  
      template <class InputIterator>
      void ReplaceImpl(iterator i1, iterator i2,
          InputIterator b, InputIterator e, std::input_iterator_tag)
      {
          flex_string temp(begin(), i1);
          temp.append(b, e).append(i2, end());
          swap(temp);
      }
  
  public:
      template <class T1, class T2>
      flex_string& replace(iterator i1, iterator i2,
          T1 first_or_n_or_s, T2 last_or_c_or_n)
      { 
          const bool 
              num1 = std::numeric_limits<T1>::is_specialized,
              num2 = std::numeric_limits<T2>::is_specialized;
          return ReplaceImplDiscr(i1, i2, first_or_n_or_s, last_or_c_or_n, 
              Selector<num1 ? (num2 ? 1 : -1) : (num2 ? 2 : 0)>()); 
      }
         
      size_type copy(value_type* s, size_type n, size_type pos = 0) const
      {
          Enforce(pos <= size(), (std::out_of_range*)0, "");
          n = Min(n, size() - pos);
          
          flex_string_details::pod_copy(
              &*begin() + pos,
              &*begin() + pos + n,
              s);
          return n;
      }
      
      void swap(flex_string& rhs)
      {
          Storage& srhs = rhs;
          this->Storage::swap(srhs);
      }
      
      // 21.3.6 string operations:
      const value_type* c_str() const
      { return Storage::c_str(); }
      
      const value_type* data() const
      { return Storage::data(); }
      
      allocator_type get_allocator() const
      { return Storage::get_allocator(); }
      
      size_type find(const flex_string& str, size_type pos = 0) const
      { return find(str.data(), pos, str.length()); }
  
      size_type find (const value_type* s, size_type pos, size_type n) const
      {
          const size_type size_(size());
          if (n + pos > size_) 
              return npos; 
          for (; pos < size_; ++pos)
          {
              if (traits_type::compare(&*begin() + pos, s, n) == 0)
              {
                  return pos;
              }
          }
          return npos;
      }
      
      size_type find (const value_type* s, size_type pos = 0) const
      { return find(s, pos, traits_type::length(s)); }
  
      size_type find (value_type c, size_type pos = 0) const
      { return find(&c, pos, 1); }
      
      size_type rfind(const flex_string& str, size_type pos = npos) const
      { return rfind(str.c_str(), pos, str.length()); }
      
      size_type rfind(const value_type* s, size_type pos, size_type n) const
      {
          if (n > length()) return npos;
          pos = Min(pos, length() - n);
          if (n == 0) return pos;
  
          const_iterator i(begin() + pos);
          for (; ; --i)
          {
              if (traits_type::eq(*i, *s) 
                  && traits_type::compare(&*i, s, n) == 0)
              {
                  return i - begin();
              }
              if (i == begin()) break;
          }
          return npos;
      }
  
      size_type rfind(const value_type* s, size_type pos = npos) const
      { return rfind(s, pos, traits_type::length(s)); }
  
      size_type rfind(value_type c, size_type pos = npos) const
      { return rfind(&c, pos, 1); }
      
      size_type find_first_of(const flex_string& str, size_type pos = 0) const
      { return find_first_of(str.c_str(), pos, str.length()); }
      
      size_type find_first_of(const value_type* s, 
          size_type pos, size_type n) const
      {
          if (pos > length() || n == 0) return npos;
          const_iterator i(begin() + pos),
              finish(end());
          for (; i != finish; ++i)
          {
              if (traits_type::find(s, n, *i) != 0)
              {
                  return i - begin();
              }
          }
          return npos;
      }
          
      size_type find_first_of(const value_type* s, size_type pos = 0) const
      { return find_first_of(s, pos, traits_type::length(s)); }
      
      size_type find_first_of(value_type c, size_type pos = 0) const
      { return find_first_of(&c, pos, 1); }
      
      size_type find_last_of (const flex_string& str,
          size_type pos = npos) const
      { return find_last_of(str.c_str(), pos, str.length()); }
      
      size_type find_last_of (const value_type* s, size_type pos, 
          size_type n) const
      {
          if (!empty() && n > 0)
          {
              pos = Min(pos, length() - 1);
              const_iterator i(begin() + pos);
              for (;; --i)
              {
                  if (traits_type::find(s, n, *i) != 0)
                  {
                      return i - begin();
                  }
                  if (i == begin()) break;
              }
          }
          return npos;
      }
  
      size_type find_last_of (const value_type* s, 
          size_type pos = npos) const
      { return find_last_of(s, pos, traits_type::length(s)); }
  
      size_type find_last_of (value_type c, size_type pos = npos) const
      { return find_last_of(&c, pos, 1); }
      
      size_type find_first_not_of(const flex_string& str,
          size_type pos = 0) const
      { return find_first_not_of(str.data(), pos, str.size()); }
      
      size_type find_first_not_of(const value_type* s, size_type pos,
          size_type n) const
      {
          if (pos < length())
          {
              const_iterator 
                  i(begin() + pos),
                  finish(end());
              for (; i != finish; ++i)
              {
                  if (traits_type::find(s, n, *i) == 0)
                  {
                      return i - begin();
                  }
              }
          }
          return npos;
      }
      
      size_type find_first_not_of(const value_type* s, 
          size_type pos = 0) const
      { return find_first_not_of(s, pos, traits_type::length(s)); }
          
      size_type find_first_not_of(value_type c, size_type pos = 0) const
      { return find_first_not_of(&c, pos, 1); }
      
      size_type find_last_not_of(const flex_string& str,
          size_type pos = npos) const
      { return find_last_not_of(str.c_str(), pos, str.length()); }
      
      size_type find_last_not_of(const value_type* s, size_type pos,
          size_type n) const
      {
          if (!empty())
          {
              pos = Min(pos, size() - 1);
              const_iterator i(begin() + pos);
              for (;; --i)
              {
                  if (traits_type::find(s, n, *i) == 0)
                  {
                      return i - begin();
                  }
                  if (i == begin()) break;
              }
          }
          return npos;
      }
  
      size_type find_last_not_of(const value_type* s, 
          size_type pos = npos) const
      { return find_last_not_of(s, pos, traits_type::length(s)); }
      
      size_type find_last_not_of (value_type c, size_type pos = npos) const
      { return find_last_not_of(&c, pos, 1); }
      
      flex_string substr(size_type pos = 0, size_type n = npos) const
      {
          Enforce(pos <= size(), (std::out_of_range*)0, "");
          return flex_string(data() + pos, Min(n, size() - pos));
      }
  
      std::ptrdiff_t compare(const flex_string& str) const
      { 
          // FIX due to Goncalo N M de Carvalho July 18, 2005
          return compare(0, size(), str);
      }
      
      std::ptrdiff_t compare(size_type pos1, size_type n1,
          const flex_string& str) const
      { return compare(pos1, n1, str.data(), str.size()); }
      
      // FIX to compare: added the TC 
      // (http://www.comeaucomputing.com/iso/lwg-defects.html number 5)
      // Thanks to Caleb Epstein for the fix
      std::ptrdiff_t compare(size_type pos1, size_type n1,
          const value_type* s) const
      {
          return compare(pos1, n1, s, traits_type::length(s));
      }
      
      std::ptrdiff_t compare(size_type pos1, size_type n1,
          const value_type* s, size_type n2) const
      {
          Enforce(pos1 <= size(), (std::out_of_range*)0, "");
          Procust(n1, size() - pos1);
          const int r = traits_type::compare(pos1 + data(), s, Min(n1, n2));
          return r != 0 ? r : n1 > n2 ? 1 : n1 < n2 ? -1 : 0;
      }
  
      std::ptrdiff_t compare(size_type pos1, size_type n1,
          const flex_string& str,
          size_type pos2, size_type n2) const
      {
          Enforce(pos2 <= str.size(), (std::out_of_range*)0, "");
          return compare(pos1, n1, str.data() + pos2, Min(n2, str.size() - pos2));
      }
  
      std::ptrdiff_t compare(const value_type* s) const
      { 
          // Could forward to compare(0, size(), s, traits_type::length(s)) 
          // but that does two extra checks 
          const size_type n1(size()), n2(traits_type::length(s)); 
          const int r = traits_type::compare(data(), s, Min(n1, n2)); 
          return r != 0 ? r : n1 > n2 ? 1 : n1 < n2 ? -1 : 0; 
      }
  };
  
  // non-member functions
  template <typename E, class T, class A, class S>
  flex_string<E, T, A, S> operator+(const flex_string<E, T, A, S>& lhs, 
      const flex_string<E, T, A, S>& rhs)
  {
      flex_string<E, T, A, S> result;
      result.reserve(lhs.size() + rhs.size());
      result.append(lhs).append(rhs);
      return result;
  }
  
  template <typename E, class T, class A, class S>
  flex_string<E, T, A, S> operator+(const typename flex_string<E, T, A, S>::value_type* lhs, 
      const flex_string<E, T, A, S>& rhs)
  {
      flex_string<E, T, A, S> result;
      const typename flex_string<E, T, A, S>::size_type len = 
          flex_string<E, T, A, S>::traits_type::length(lhs);
      result.reserve(len + rhs.size());
      result.append(lhs, len).append(rhs);
      return result;
  }
  
  template <typename E, class T, class A, class S>
  flex_string<E, T, A, S> operator+(
      typename flex_string<E, T, A, S>::value_type lhs, 
      const flex_string<E, T, A, S>& rhs)
  {
      flex_string<E, T, A, S> result;
      result.reserve(1 + rhs.size());
      result.push_back(lhs);
      result.append(rhs);
      return result;
  }
  
  template <typename E, class T, class A, class S>
  flex_string<E, T, A, S> operator+(const flex_string<E, T, A, S>& lhs, 
      const typename flex_string<E, T, A, S>::value_type* rhs)
  {
      typedef typename flex_string<E, T, A, S>::size_type size_type;
      typedef typename flex_string<E, T, A, S>::traits_type traits_type;
  
      flex_string<E, T, A, S> result;
      const size_type len = traits_type::length(rhs);
      result.reserve(lhs.size() + len);
      result.append(lhs).append(rhs, len);
      return result;
  }
  
  template <typename E, class T, class A, class S>
  flex_string<E, T, A, S> operator+(const flex_string<E, T, A, S>& lhs, 
      typename flex_string<E, T, A, S>::value_type rhs)
  {
      flex_string<E, T, A, S> result;
      result.reserve(lhs.size() + 1);
      result.append(lhs);
      result.push_back(rhs);
      return result;
  }
  
  template <typename E, class T, class A, class S>
  inline bool operator==(const flex_string<E, T, A, S>& lhs, 
      const flex_string<E, T, A, S>& rhs)
  { return lhs.compare(rhs) == 0; }
  
  template <typename E, class T, class A, class S>
  inline bool operator==(const typename flex_string<E, T, A, S>::value_type* lhs, 
      const flex_string<E, T, A, S>& rhs)
  { return rhs == lhs; }
  
  template <typename E, class T, class A, class S>
  inline bool operator==(const flex_string<E, T, A, S>& lhs, 
      const typename flex_string<E, T, A, S>::value_type* rhs)
  { return lhs.compare(rhs) == 0; }
  
  template <typename E, class T, class A, class S>
  inline bool operator!=(const flex_string<E, T, A, S>& lhs, 
      const flex_string<E, T, A, S>& rhs)
  { return !(lhs == rhs); }
  
  template <typename E, class T, class A, class S>
  inline bool operator!=(const typename flex_string<E, T, A, S>::value_type* lhs, 
      const flex_string<E, T, A, S>& rhs)
  { return !(lhs == rhs); }
  
  template <typename E, class T, class A, class S>
  inline bool operator!=(const flex_string<E, T, A, S>& lhs, 
      const typename flex_string<E, T, A, S>::value_type* rhs)
  { return !(lhs == rhs); }
  
  template <typename E, class T, class A, class S>
  inline bool operator<(const flex_string<E, T, A, S>& lhs, 
      const flex_string<E, T, A, S>& rhs)
  { return lhs.compare(rhs) < 0; }
  
  template <typename E, class T, class A, class S>
  inline bool operator<(const flex_string<E, T, A, S>& lhs, 
      const typename flex_string<E, T, A, S>::value_type* rhs)
  { return lhs.compare(rhs) < 0; }
  
  template <typename E, class T, class A, class S>
  inline bool operator<(const typename flex_string<E, T, A, S>::value_type* lhs, 
      const flex_string<E, T, A, S>& rhs)
  { return rhs.compare(lhs) > 0; }
  
  template <typename E, class T, class A, class S>
  inline bool operator>(const flex_string<E, T, A, S>& lhs, 
      const flex_string<E, T, A, S>& rhs)
  { return rhs < lhs; }
  
  template <typename E, class T, class A, class S>
  inline bool operator>(const flex_string<E, T, A, S>& lhs, 
      const typename flex_string<E, T, A, S>::value_type* rhs)
  { return rhs < lhs; }
  
  template <typename E, class T, class A, class S>
  bool operator>(const typename flex_string<E, T, A, S>::value_type* lhs, 
      const flex_string<E, T, A, S>& rhs)
  { return rhs < lhs; }
  
  template <typename E, class T, class A, class S>
  inline bool operator<=(const flex_string<E, T, A, S>& lhs, 
      const flex_string<E, T, A, S>& rhs)
  { return !(rhs < lhs); }
  
  template <typename E, class T, class A, class S>
  inline bool operator<=(const flex_string<E, T, A, S>& lhs, 
      const typename flex_string<E, T, A, S>::value_type* rhs)
  { return !(rhs < lhs); }
  
  template <typename E, class T, class A, class S>
  bool operator<=(const typename flex_string<E, T, A, S>::value_type* lhs, 
      const flex_string<E, T, A, S>& rhs)
  { return !(rhs < lhs); }
  
  template <typename E, class T, class A, class S>
  bool operator>=(const flex_string<E, T, A, S>& lhs, 
      const flex_string<E, T, A, S>& rhs)
  { return !(lhs < rhs); }
  
  template <typename E, class T, class A, class S>
  bool operator>=(const flex_string<E, T, A, S>& lhs, 
      const typename flex_string<E, T, A, S>::value_type* rhs)
  { return !(lhs < rhs); }
  
  template <typename E, class T, class A, class S>
  inline bool operator>=(const typename flex_string<E, T, A, S>::value_type* lhs, 
      const flex_string<E, T, A, S>& rhs)
  { return !(lhs < rhs); }
  
  template <typename E, class T, class A, class S>
  void swap(flex_string<E, T, A, S>& lhs, flex_string<E, T, A, S>& rhs)
  {
      // subclause 21.3.7.8:
      lhs.swap(rhs);
  }
  
  template <typename E, class T, class A, class S>
  inline std::basic_istream<typename flex_string<E, T, A, S>::value_type, 
      typename flex_string<E, T, A, S>::traits_type>&
  operator>>(
      std::basic_istream<typename flex_string<E, T, A, S>::value_type, 
      typename flex_string<E, T, A, S>::traits_type>& is,
      flex_string<E, T, A, S>& str);
  
  template <typename E, class T, class A, class S>
  std::basic_ostream<typename flex_string<E, T, A, S>::value_type,
      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)
  { return os << str.c_str(); }
  
  
  // The getline below implementations are from the SGI STL (http://www.sgi.com/tech/stl/) 
  // and come with the following copyright:
  // 
  // Permission to use, copy, modify, distribute and sell this software and its 
  // documentation for any purpose is hereby granted without fee, provided that 
  // the below copyright notice appears in all copies and that both the copyright 
  // notice and this permission notice appear in supporting documentation. Silicon 
  // Graphics makes no representations about the suitability of this software for 
  // any purpose. It is provided "as is" without express or implied warranty.
  // 
  // Copyright (c) 1997-1999
  // Silicon Graphics Computer Systems, Inc.
  // 
  // Copyright (c) 1994
  // Hewlett-Packard Company 
  
  template <typename E, class T, class A, class S>
  std::basic_istream<typename flex_string<E, T, A, S>::value_type,
      typename flex_string<E, T, A, S>::traits_type>&
  getline(
      std::basic_istream<typename flex_string<E, T, A, S>::value_type, 
          typename flex_string<E, T, A, S>::traits_type>& is,
      flex_string<E, T, A, S>& str,
      typename flex_string<E, T, A, S>::value_type delim)
  {
      size_t nread = 0;
      typename std::basic_istream<typename flex_string<E, T, A, S>::value_type,
          typename flex_string<E, T, A, S>::traits_type>::sentry sentry(is, true);
  
      if (sentry) {
          std::basic_streambuf<typename flex_string<E, T, A, S>::value_type,
              typename flex_string<E, T, A, S>::traits_type>* buf = is.rdbuf();
          str.clear();
  
          while (nread < str.max_size()) {
              int c1 = buf->sbumpc();
              if (flex_string<E, T, A, S>::traits_type::eq_int_type(c1,
                  flex_string<E, T, A, S>::traits_type::eof()))
              {
                  is.setstate(std::ios_base::eofbit);
                  break;
              }
              else {
                  ++nread;
                  typename flex_string<E, T, A, S>::value_type c =
                      flex_string<E, T, A, S>::traits_type::to_char_type(c1);
  
                  if (!flex_string<E, T, A, S>::traits_type::eq(c, delim))
                      str.push_back(c);
                  else
                      break;         // Character is extracted but not appended.
              }
          }
      }
      if (nread == 0 || nread >= str.max_size())
          is.setstate(std::ios_base::failbit);
  
      return is;
  }
  
  template <typename E, class T, class A, class S>
  std::basic_istream<typename flex_string<E, T, A, S>::value_type, 
      typename flex_string<E, T, A, S>::traits_type>&
  getline(
      std::basic_istream<typename flex_string<E, T, A, S>::value_type, 
          typename flex_string<E, T, A, S>::traits_type>& is,
      flex_string<E, T, A, S>& str)
  {
      return getline(is, str, is.widen('\n'));
  }
  
  template <typename E1, class T, class A, class S>
  const typename flex_string<E1, T, A, S>::size_type
  flex_string<E1, T, A, S>::npos = (typename flex_string<E1, T, A, S>::size_type)(-1);
  
  ///////////////////////////////////////////////////////////////////////////////
  }   // namespace util
  }   // namespace wave
  }   // namespace boost
  
  #if BOOST_WAVE_SERIALIZATION != 0
  ///////////////////////////////////////////////////////////////////////////////
  namespace boost { namespace serialization {
  
  #if !defined(BOOST_WAVE_FLEX_STRING_SERIALIZATION_HACK)
  
  // FIXME: This doesn't work because of the missing flex_string::operator>>()
  template <typename E, class T, class A, class S>
  struct implementation_level<boost::wave::util::flex_string<E, T, A, S> >
  {
      typedef mpl::integral_c_tag tag;
      typedef mpl::int_<boost::serialization::primitive_type> type;
      BOOST_STATIC_CONSTANT(
          int,
          value = implementation_level::type::value
      );
  };
  
  #else
  
  //  We serialize flex_strings as vectors of char's for now
  template<class Archive, typename E, class T, class A, class S>
  inline void save(Archive & ar, 
      boost::wave::util::flex_string<E, T, A, S> const &t,
      const unsigned int file_version)
  {
      boost::serialization::stl::save_collection<
          Archive, wave::util::flex_string<E, T, A, S> >(ar, t);
  }
  
  template<class Archive, typename E, class T, class A, class S>
  inline void load(Archive & ar, boost::wave::util::flex_string<E, T, A, S> &t,
      const unsigned int file_version)
  {
      boost::serialization::stl::load_collection<
          Archive, boost::wave::util::flex_string<E, T, A, S>,
          boost::serialization::stl::archive_input_seq<
              Archive, boost::wave::util::flex_string<E, T, A, S> >,
          boost::serialization::stl::reserve_imp<
              boost::wave::util::flex_string<E, T, A, S> >
      >(ar, t);
  }
  
  // split non-intrusive serialization function member into separate
  // non intrusive save/load member functions
  template<class Archive, typename E, class T, class A, class S>
  inline void serialize(Archive & ar, boost::wave::util::flex_string<E, T, A, S> &t,
      const unsigned int file_version)
  {
      boost::serialization::split_free(ar, t, file_version);
  }
  
  #endif
  
  ///////////////////////////////////////////////////////////////////////////////
  }} // boost::serialization
  #endif
  
  // the suffix header occurs after all of the code
  #ifdef BOOST_HAS_ABI_HEADERS
  #include BOOST_ABI_SUFFIX
  #endif
  
  #endif // FLEX_STRING_INC_
  