//////////////////////////////////////////////////////////////////////////////// // 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 COW_STRING_OPT_INC_ #define COW_STRING_OPT_INC_ // $Id$ //////////////////////////////////////////////////////////////////////////////// // class template CowStringOpt // Implements Copy on Write over any storage //////////////////////////////////////////////////////////////////////////////// /* 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); 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 #include #include "flex_string_details.h" //////////////////////////////////////////////////////////////////////////////// // class template CowStringOpt // Implements Copy on Write over any storage //////////////////////////////////////////////////////////////////////////////// template class CowStringOpt { 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 { return *reinterpret_cast(buf_); } RefCountType GetRefs() const { const Storage& d = Data(); assert(d.size() > 0); assert(*d.begin() > 0); return *d.begin(); } RefCountType& Refs() { Storage& d = Data(); assert(d.size() > 0); return reinterpret_cast(*d.begin()); } void MakeUnique() const { assert(GetRefs() >= 1); if (GetRefs() == 1) return; union { char buf_[sizeof(Storage)]; Align align_; } temp; --(*Data().begin()); // Harmut Kaiser fix: // decrement the use count of the remaining object new(buf_) Storage( *new(temp.buf_) Storage(Data()), flex_string_details::Shallow()); *Data().begin() = 1; } public: CowStringOpt(const CowStringOpt& 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(); } assert(Data().size() > 0); } CowStringOpt(const allocator_type& a) { new(buf_) Storage(1, 1, a); } CowStringOpt(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); } CowStringOpt(size_type len, E c, const allocator_type& a) { new(buf_) Storage(len + 1, c, a); Refs() = 1; } CowStringOpt& operator=(const CowStringOpt& rhs) { CowStringOpt(rhs).swap(*this); return *this; } ~CowStringOpt() { assert(Data().size() > 0); if (--Refs() == 0) Data().~Storage(); } iterator begin() { assert(Data().size() > 0); MakeUnique(); return Data().begin() + 1; } const_iterator begin() const { 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 { assert(Data().size() > 0); return Data().size() - 1; } size_type max_size() const { assert(Data().max_size() > 0); return Data().max_size() - 1; } size_type capacity() const { assert(Data().capacity() > 0); return Data().capacity() - 1; } void resize(size_type n, E c) { 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(CowStringOpt& rhs) { Data().swap(rhs.Data()); } const E* c_str() const { assert(Data().size() > 0); return Data().c_str() + 1; } const E* data() const { assert(Data().size() > 0); return Data().data() + 1; } allocator_type get_allocator() const { return Data().get_allocator(); } }; #endif // COW_STRING_OPT_INC_