diff options
author | Anas Nashif <anas.nashif@intel.com> | 2012-10-30 12:57:26 -0700 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2012-10-30 12:57:26 -0700 |
commit | 1a78a62555be32868418fe52f8e330c9d0f95d5a (patch) | |
tree | d3765a80e7d3b9640ec2e930743630cd6b9fce2b /boost/wave/util/flex_string.hpp | |
download | boost-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.hpp | 2672 |
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_ |