1 //////////////////////////////////////////////////////////////////////////////// 2 // flex_string 3 // Copyright (c) 2001 by Andrei Alexandrescu 4 // Permission to use, copy, modify, distribute and sell this software for any 5 // purpose is hereby granted without fee, provided that the above copyright 6 // notice appear in all copies and that both that copyright notice and this 7 // permission notice appear in supporting documentation. 8 // The author makes no representations about the 9 // suitability of this software for any purpose. It is provided "as is" 10 // without express or implied warranty. 11 //////////////////////////////////////////////////////////////////////////////// 12 13 #ifndef COW_STRING_OPT_INC_ 14 #define COW_STRING_OPT_INC_ 15 16 // $Id: cowstringopt.h 836 2007-09-20 15:51:37Z aandrei $ 17 18 19 //////////////////////////////////////////////////////////////////////////////// 20 // class template CowStringOpt 21 // Implements Copy on Write over any storage 22 //////////////////////////////////////////////////////////////////////////////// 23 24 25 /* This is the template for a storage policy 26 //////////////////////////////////////////////////////////////////////////////// 27 template <typename E, class A = @> 28 class StoragePolicy 29 { 30 typedef E value_type; 31 typedef @ iterator; 32 typedef @ const_iterator; 33 typedef A allocator_type; 34 typedef @ size_type; 35 36 StoragePolicy(const StoragePolicy& s); 37 StoragePolicy(const A&); 38 StoragePolicy(const E* s, size_type len, const A&); 39 StoragePolicy(size_type len, E c, const A&); 40 ~StoragePolicy(); 41 42 iterator begin(); 43 const_iterator begin() const; 44 iterator end(); 45 const_iterator end() const; 46 47 size_type size() const; 48 size_type max_size() const; 49 size_type capacity() const; 50 51 void reserve(size_type res_arg); 52 53 void append(const E* s, size_type sz); 54 55 template <class InputIterator> 56 void append(InputIterator b, InputIterator e); 57 58 void resize(size_type newSize, E fill); 59 60 void swap(StoragePolicy& rhs); 61 62 const E* c_str() const; 63 const E* data() const; 64 65 A get_allocator() const; 66 }; 67 //////////////////////////////////////////////////////////////////////////////// 68 */ 69 70 #include <memory> 71 #include <algorithm> 72 #include <functional> 73 #include <cassert> 74 #include <limits> 75 #include <stdexcept> 76 #include "flex_string_details.h" 77 78 79 //////////////////////////////////////////////////////////////////////////////// 80 // class template CowStringOpt 81 // Implements Copy on Write over any storage 82 //////////////////////////////////////////////////////////////////////////////// 83 84 template <class Storage, typename Align = typename Storage::value_type*> 85 class CowStringOpt 86 { 87 typedef typename Storage::value_type E; 88 typedef typename flex_string_details::get_unsigned<E>::result RefCountType; 89 90 public: 91 typedef E value_type; 92 typedef typename Storage::iterator iterator; 93 typedef typename Storage::const_iterator const_iterator; 94 typedef typename Storage::allocator_type allocator_type; 95 typedef typename allocator_type::size_type size_type; 96 typedef typename Storage::reference reference; 97 98 private: 99 union 100 { 101 mutable char buf_[sizeof(Storage)]; 102 Align align_; 103 }; 104 Data()105 Storage& Data() const 106 { return *reinterpret_cast<Storage*>(buf_); } 107 GetRefs()108 RefCountType GetRefs() const 109 { 110 const Storage& d = Data(); 111 assert(d.size() > 0); 112 assert(*d.begin() > 0); 113 return *d.begin(); 114 } 115 Refs()116 RefCountType& Refs() 117 { 118 Storage& d = Data(); 119 assert(d.size() > 0); 120 return reinterpret_cast<RefCountType&>(*d.begin()); 121 } 122 MakeUnique()123 void MakeUnique() const 124 { 125 assert(GetRefs() >= 1); 126 if (GetRefs() == 1) return; 127 128 union 129 { 130 char buf_[sizeof(Storage)]; 131 Align align_; 132 } temp; 133 134 --(*Data().begin()); // Harmut Kaiser fix: 135 // decrement the use count of the remaining object 136 new(buf_) Storage( 137 *new(temp.buf_) Storage(Data()), 138 flex_string_details::Shallow()); 139 *Data().begin() = 1; 140 } 141 142 public: CowStringOpt(const CowStringOpt & s)143 CowStringOpt(const CowStringOpt& s) 144 { 145 if (s.GetRefs() == std::numeric_limits<RefCountType>::max()) 146 { 147 // must make a brand new copy 148 new(buf_) Storage(s.Data()); // non shallow 149 Refs() = 1; 150 } 151 else 152 { 153 new(buf_) Storage(s.Data(), flex_string_details::Shallow()); 154 ++Refs(); 155 } 156 assert(Data().size() > 0); 157 } 158 CowStringOpt(const allocator_type & a)159 CowStringOpt(const allocator_type& a) 160 { 161 new(buf_) Storage(1, 1, a); 162 } 163 CowStringOpt(const E * s,size_type len,const allocator_type & a)164 CowStringOpt(const E* s, size_type len, const allocator_type& a) 165 { 166 // Warning - MSVC's debugger has trouble tracing through the code below. 167 // It seems to be a const-correctness issue 168 // 169 new(buf_) Storage(a); 170 Data().reserve(len + 1); 171 Data().resize(1, 1); 172 Data().append(s, s + len); 173 } 174 CowStringOpt(size_type len,E c,const allocator_type & a)175 CowStringOpt(size_type len, E c, const allocator_type& a) 176 { 177 new(buf_) Storage(len + 1, c, a); 178 Refs() = 1; 179 } 180 181 CowStringOpt& operator=(const CowStringOpt& rhs) 182 { 183 CowStringOpt(rhs).swap(*this); 184 return *this; 185 } 186 ~CowStringOpt()187 ~CowStringOpt() 188 { 189 assert(Data().size() > 0); 190 if (--Refs() == 0) Data().~Storage(); 191 } 192 begin()193 iterator begin() 194 { 195 assert(Data().size() > 0); 196 MakeUnique(); 197 return Data().begin() + 1; 198 } 199 begin()200 const_iterator begin() const 201 { 202 assert(Data().size() > 0); 203 return Data().begin() + 1; 204 } 205 end()206 iterator end() 207 { 208 MakeUnique(); 209 return Data().end(); 210 } 211 end()212 const_iterator end() const 213 { 214 return Data().end(); 215 } 216 size()217 size_type size() const 218 { 219 assert(Data().size() > 0); 220 return Data().size() - 1; 221 } 222 max_size()223 size_type max_size() const 224 { 225 assert(Data().max_size() > 0); 226 return Data().max_size() - 1; 227 } 228 capacity()229 size_type capacity() const 230 { 231 assert(Data().capacity() > 0); 232 return Data().capacity() - 1; 233 } 234 resize(size_type n,E c)235 void resize(size_type n, E c) 236 { 237 assert(Data().size() > 0); 238 MakeUnique(); 239 Data().resize(n + 1, c); 240 } 241 242 template <class FwdIterator> append(FwdIterator b,FwdIterator e)243 void append(FwdIterator b, FwdIterator e) 244 { 245 MakeUnique(); 246 Data().append(b, e); 247 } 248 reserve(size_type res_arg)249 void reserve(size_type res_arg) 250 { 251 if (capacity() > res_arg) return; 252 MakeUnique(); 253 Data().reserve(res_arg + 1); 254 } 255 swap(CowStringOpt & rhs)256 void swap(CowStringOpt& rhs) 257 { 258 Data().swap(rhs.Data()); 259 } 260 c_str()261 const E* c_str() const 262 { 263 assert(Data().size() > 0); 264 return Data().c_str() + 1; 265 } 266 data()267 const E* data() const 268 { 269 assert(Data().size() > 0); 270 return Data().data() + 1; 271 } 272 get_allocator()273 allocator_type get_allocator() const 274 { 275 return Data().get_allocator(); 276 } 277 }; 278 279 280 #endif // COW_STRING_OPT_INC_ 281