//////////////////////////////////////////////////////////////////////////////// // flex_string // Copyright (c) 2001 by Andrei Alexandrescu // Permission to use, copy, modify, distribute and sell this software for any // purpose is hereby granted without fee, provided that the above copyright // notice appear in all copies and that both that copyright notice and this // permission notice appear in supporting documentation. // The author makes no representations about the // suitability of this software for any purpose. It is provided "as is" // without express or implied warranty. //////////////////////////////////////////////////////////////////////////////// #ifndef SIMPLE_STRING_STORAGE_INC_ #define SIMPLE_STRING_STORAGE_INC_ // $Id$ /* This is the template for a storage policy //////////////////////////////////////////////////////////////////////////////// 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); template void append(ForwardIterator b, ForwardIterator 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 #include //////////////////////////////////////////////////////////////////////////////// // 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) { assert(size <= capacity); if (capacity == 0) { pData_ = const_cast(&emptyString_); } else { // 11-17-2000: comment added: // No need to allocate (capacity + 1) to // accomodate the terminating 0, because Data already // has one one character in there pData_ = static_cast( malloc(sizeof(Data) + capacity * sizeof(E))); if (!pData_) throw 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; typedef typename A::reference reference; 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() { 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 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) throw std::bad_alloc(); if (p != pData_) { pData_ = static_cast(p); pData_->pEnd_ = pData_->buffer_ + sz; } pData_->pEndOfMem_ = pData_->buffer_ + res_arg; } } template void append(InputIterator b, InputIterator e) { const size_type sz = std::distance(b, e), neededCapacity = size() + sz; if (capacity() < neededCapacity) { static std::less_equal le; (void) le; assert(!(le(begin(), &*b) && le(&*b, end()))); // no aliasing reserve(neededCapacity); } std::copy(b, e, end()); pData_->pEnd_ += sz; } 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_; //{ // const_cast(SimpleStringStorage::emptyString_.buffer_), // const_cast(SimpleStringStorage::emptyString_.buffer_), // { E() } //}; #endif // SIMPLE_STRING_STORAGE_INC_