/*============================================================================= 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: 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 // // #HK130910: // - Removed the getline implementation which was borrowed from the SGI // STL as the license for this code is not compatible with Boost. #ifndef FLEX_STRING_INC_ #define FLEX_STRING_INC_ /* //////////////////////////////////////////////////////////////////////////////// template 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 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 #include #include #include #include #if BOOST_WAVE_SERIALIZATION != 0 #include #include #include #include #define BOOST_WAVE_FLEX_STRING_SERIALIZATION_HACK 1 #endif #include #include #include #include #include #include #include #include #include #include #include #include // 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 OutIt copy_n(InIt b, typename std::iterator_traits::difference_type n, OutIt d) { for (/**/; n != 0; --n, ++b, ++d) { *d = *b; } return d; } template inline void pod_fill(Pod* b, Pod* e, T c) { switch ((e - b) & 7) { case 0: while (b != e) { *b = c; ++b; BOOST_FALLTHROUGH; case 7: *b = c; ++b; BOOST_FALLTHROUGH; case 6: *b = c; ++b; BOOST_FALLTHROUGH; case 5: *b = c; ++b; BOOST_FALLTHROUGH; case 4: *b = c; ++b; BOOST_FALLTHROUGH; case 3: *b = c; ++b; BOOST_FALLTHROUGH; case 2: *b = c; ++b; BOOST_FALLTHROUGH; case 1: *b = c; ++b; } } } template inline void pod_move(const Pod* b, const Pod* e, Pod* d) { using namespace std; memmove(d, b, (e - b) * sizeof(*b)); } template 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 struct get_unsigned { typedef T result; }; template <> struct get_unsigned { typedef unsigned char result; }; template <> struct get_unsigned { typedef unsigned char result; }; template <> struct get_unsigned { typedef unsigned short int result; }; template <> struct get_unsigned { typedef unsigned int result; }; template <> struct get_unsigned { typedef unsigned long int result; }; enum Shallow {}; } template 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 struct rebind { typedef mallocator other; }; mallocator() {} mallocator(const mallocator&) {} //template //mallocator(const mallocator&) {} ~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(p); } void deallocate(pointer p, size_type) { using namespace std; free(p); } size_type max_size() const { return static_cast(-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 { typedef void value_type; typedef void* pointer; typedef const void* const_pointer; template struct rebind { typedef mallocator other; }; }; template inline bool operator==(const mallocator&, const mallocator&) { return true; } template inline bool operator!=(const mallocator&, const mallocator&) { return false; } template 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 typename Allocator::pointer Reallocate( Allocator& alloc, typename Allocator::pointer p, typename Allocator::size_type oldObjCount, typename Allocator::size_type newObjCount, mallocator*) { // @@@ not implemented return NULL; } //////////////////////////////////////////////////////////////////////////////// // class template SimpleStringStorage // Allocates memory with malloc //////////////////////////////////////////////////////////////////////////////// template > 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(&emptyString_); } else { // 11-17-2000: comment added: // No need to allocate (capacity + 1) to // accommodate the terminating 0, because Data already // has one character in there pData_ = static_cast( 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(&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(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 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 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 const typename SimpleStringStorage::Data SimpleStringStorage::emptyString_ = typename SimpleStringStorage::Data(); //////////////////////////////////////////////////////////////////////////////// // class template AllocatorStringStorage // Allocates with your allocator // Takes advantage of the Empty Base Optimization if available //////////////////////////////////////////////////////////////////////////////// template > class AllocatorStringStorage : public A { typedef typename A::size_type size_type; typedef typename SimpleStringStorage::Data Data; void* Alloc(size_type sz, const void* p = 0) { return A::allocate(1 + (sz - 1) / sizeof(E), static_cast(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(p), sz); } Data* pData_; void Init(size_type size, size_type cap) { BOOST_ASSERT(size <= cap); if (cap == 0) { pData_ = const_cast( &SimpleStringStorage::emptyString_); } else { pData_ = static_cast(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( &SimpleStringStorage::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 void append(ForwardIterator b, ForwardIterator e) { const size_type sz = std::distance(b, e), neededCapacity = size() + sz; if (capacity() < neededCapacity) { // typedef std::less_equal 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::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 > class VectorStringStorage : protected std::vector { typedef std::vector 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 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 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 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(&buf_[0]); return *p; } const Storage& GetStorage() const { BOOST_ASSERT(buf_[maxSmallString] == magic); const Storage *p = reinterpret_cast(&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 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::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(&buf_[0]); return *p; } RefCountType GetRefs() const { const Storage& d = Data(); BOOST_ASSERT(d.size() > 0); BOOST_ASSERT(static_cast(*d.begin()) != 0); return *d.begin(); } RefCountType& Refs() { Storage& d = Data(); BOOST_ASSERT(d.size() > 0); return reinterpret_cast(*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(&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::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::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 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 , class A = std::allocator, class Storage = AllocatorStringStorage > class flex_string : private Storage { #if defined(BOOST_WAVE_FLEXSTRING_THROW_ON_ENFORCE) template static void Enforce(bool condition, Exception*, const char* msg) { if (!condition) boost::throw_exception(Exception(msg)); } #else template 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 reverse_iterator; typedef boost::reverse_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 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 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 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 const typename std::iterator_traits::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 const typename std::iterator_traits::value_type* DereferenceValidIterator(std::reverse_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 bool IsAliasedRange(Iterator beginIterator, Iterator endIterator) { if(!empty() && beginIterator != endIterator) { typedef const typename std::iterator_traits::value_type * pointer; pointer myBegin(&*begin()); pointer myEnd(&*begin() + size()); pointer rangeBegin(DereferenceValidIterator(beginIterator)); const std::less_equal less_equal = std::less_equal(); if(less_equal(myBegin, rangeBegin) && less_equal(rangeBegin, myEnd)) return true; } return false; } template 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 flex_string& InsertImplDiscr(iterator i, InputIterator b, InputIterator e, Selector<0>) { InsertImpl(i, b, e, typename std::iterator_traits::iterator_category()); return *this; } template 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::iterator_category()); return; } #ifndef NDEBUG Invariant checker(*this); #endif const size_type pos = i - begin(); const typename std::iterator_traits::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::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 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 void insert(iterator p, ItOrLength first_or_n, ItOrChar last_or_c) { Selector::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 occurrences 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 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 flex_string& ReplaceImplDiscr(iterator i1, iterator i2, InputIterator b, InputIterator e, Selector<0>) { ReplaceImpl(i1, i2, b, e, typename std::iterator_traits::iterator_category()); return *this; } template 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::difference_type n1 = i2 - i1; BOOST_ASSERT(n1 >= 0); const typename std::iterator_traits::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 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 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::is_specialized, num2 = std::numeric_limits::is_specialized; return ReplaceImplDiscr(i1, i2, first_or_n_or_s, last_or_c_or_n, Selector()); } 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 flex_string operator+(const flex_string& lhs, const flex_string& rhs) { flex_string result; result.reserve(lhs.size() + rhs.size()); result.append(lhs).append(rhs); return result; } template flex_string operator+(const typename flex_string::value_type* lhs, const flex_string& rhs) { flex_string result; const typename flex_string::size_type len = flex_string::traits_type::length(lhs); result.reserve(len + rhs.size()); result.append(lhs, len).append(rhs); return result; } template flex_string operator+( typename flex_string::value_type lhs, const flex_string& rhs) { flex_string result; result.reserve(1 + rhs.size()); result.push_back(lhs); result.append(rhs); return result; } template flex_string operator+(const flex_string& lhs, const typename flex_string::value_type* rhs) { typedef typename flex_string::size_type size_type; typedef typename flex_string::traits_type traits_type; flex_string result; const size_type len = traits_type::length(rhs); result.reserve(lhs.size() + len); result.append(lhs).append(rhs, len); return result; } template flex_string operator+(const flex_string& lhs, typename flex_string::value_type rhs) { flex_string result; result.reserve(lhs.size() + 1); result.append(lhs); result.push_back(rhs); return result; } template inline bool operator==(const flex_string& lhs, const flex_string& rhs) { return lhs.compare(rhs) == 0; } template inline bool operator==(const typename flex_string::value_type* lhs, const flex_string& rhs) { return rhs == lhs; } template inline bool operator==(const flex_string& lhs, const typename flex_string::value_type* rhs) { return lhs.compare(rhs) == 0; } template inline bool operator!=(const flex_string& lhs, const flex_string& rhs) { return !(lhs == rhs); } template inline bool operator!=(const typename flex_string::value_type* lhs, const flex_string& rhs) { return !(lhs == rhs); } template inline bool operator!=(const flex_string& lhs, const typename flex_string::value_type* rhs) { return !(lhs == rhs); } template inline bool operator<(const flex_string& lhs, const flex_string& rhs) { return lhs.compare(rhs) < 0; } template inline bool operator<(const flex_string& lhs, const typename flex_string::value_type* rhs) { return lhs.compare(rhs) < 0; } template inline bool operator<(const typename flex_string::value_type* lhs, const flex_string& rhs) { return rhs.compare(lhs) > 0; } template inline bool operator>(const flex_string& lhs, const flex_string& rhs) { return rhs < lhs; } template inline bool operator>(const flex_string& lhs, const typename flex_string::value_type* rhs) { return rhs < lhs; } template bool operator>(const typename flex_string::value_type* lhs, const flex_string& rhs) { return rhs < lhs; } template inline bool operator<=(const flex_string& lhs, const flex_string& rhs) { return !(rhs < lhs); } template inline bool operator<=(const flex_string& lhs, const typename flex_string::value_type* rhs) { return !(rhs < lhs); } template bool operator<=(const typename flex_string::value_type* lhs, const flex_string& rhs) { return !(rhs < lhs); } template bool operator>=(const flex_string& lhs, const flex_string& rhs) { return !(lhs < rhs); } template bool operator>=(const flex_string& lhs, const typename flex_string::value_type* rhs) { return !(lhs < rhs); } template inline bool operator>=(const typename flex_string::value_type* lhs, const flex_string& rhs) { return !(lhs < rhs); } template void swap(flex_string& lhs, flex_string& rhs) { // subclause 21.3.7.8: lhs.swap(rhs); } template inline std::basic_istream::value_type, typename flex_string::traits_type>& operator>>( std::basic_istream::value_type, typename flex_string::traits_type>& is, flex_string& str); template std::basic_ostream::value_type, typename flex_string::traits_type>& operator<<( std::basic_ostream::value_type, typename flex_string::traits_type>& os, const flex_string& str) { return os << str.c_str(); } template const typename flex_string::size_type flex_string::npos = (typename flex_string::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 struct implementation_level > { typedef mpl::integral_c_tag tag; typedef mpl::int_ type; BOOST_STATIC_CONSTANT( int, value = implementation_level::type::value ); }; #else // We serialize flex_strings as vectors of char's for now template inline void save(Archive & ar, boost::wave::util::flex_string const &t, const unsigned int file_version) { boost::serialization::stl::save_collection< Archive, wave::util::flex_string >(ar, t); } template inline void load(Archive & ar, boost::wave::util::flex_string &t, const unsigned int file_version) { boost::serialization::stl::load_collection< Archive, boost::wave::util::flex_string, boost::serialization::stl::archive_input_seq< Archive, boost::wave::util::flex_string >, boost::serialization::stl::reserve_imp< boost::wave::util::flex_string > >(ar, t); } // split non-intrusive serialization function member into separate // non intrusive save/load member functions template inline void serialize(Archive & ar, boost::wave::util::flex_string &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_