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