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