summaryrefslogtreecommitdiff
path: root/boost/wave/util/flex_string.hpp
diff options
context:
space:
mode:
authorAnas Nashif <anas.nashif@intel.com>2012-10-30 12:57:26 -0700
committerAnas Nashif <anas.nashif@intel.com>2012-10-30 12:57:26 -0700
commit1a78a62555be32868418fe52f8e330c9d0f95d5a (patch)
treed3765a80e7d3b9640ec2e930743630cd6b9fce2b /boost/wave/util/flex_string.hpp
downloadboost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.gz
boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.bz2
boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.zip
Imported Upstream version 1.49.0upstream/1.49.0
Diffstat (limited to 'boost/wave/util/flex_string.hpp')
-rw-r--r--boost/wave/util/flex_string.hpp2672
1 files changed, 2672 insertions, 0 deletions
diff --git a/boost/wave/util/flex_string.hpp b/boost/wave/util/flex_string.hpp
new file mode 100644
index 0000000000..da16235676
--- /dev/null
+++ b/boost/wave/util/flex_string.hpp
@@ -0,0 +1,2672 @@
+/*=============================================================================
+ 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>
+#include <ios>
+
+#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_