]> git.cworth.org Git - vogl/blob - src/extlib/loki/include/loki/flex/cowstringopt.h
Initial vogl checkin
[vogl] / src / extlib / loki / include / loki / flex / cowstringopt.h
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
105         Storage &Data() const
106         {
107                 return *reinterpret_cast<Storage *>(buf_);
108         }
109
110         RefCountType GetRefs() const
111         {
112                 const Storage &d = Data();
113                 assert(d.size() > 0);
114                 assert(*d.begin() > 0);
115                 return *d.begin();
116         }
117
118         RefCountType &Refs()
119         {
120                 Storage &d = Data();
121                 assert(d.size() > 0);
122                 return reinterpret_cast<RefCountType &>(*d.begin());
123         }
124
125         void MakeUnique() const
126         {
127                 assert(GetRefs() >= 1);
128                 if (GetRefs() == 1) return;
129
130                 union
131                 {
132                         char buf_[sizeof(Storage)];
133                         Align align_;
134                 } temp;
135
136                 --(*Data().begin()); // Harmut Kaiser fix:
137                 // decrement the use count of the remaining object
138                 new(buf_) Storage(
139                     *new(temp.buf_) Storage(Data()),
140                     flex_string_details::Shallow());
141                 *Data().begin() = 1;
142         }
143
144 public:
145         CowStringOpt(const CowStringOpt &s)
146         {
147                 if (s.GetRefs() == std::numeric_limits<RefCountType>::max())
148                 {
149                         // must make a brand new copy
150                         new(buf_) Storage(s.Data()); // non shallow
151                         Refs() = 1;
152                 }
153                 else
154                 {
155                         new(buf_) Storage(s.Data(), flex_string_details::Shallow());
156                         ++Refs();
157                 }
158                 assert(Data().size() > 0);
159         }
160
161         CowStringOpt(const allocator_type &a)
162         {
163                 new(buf_) Storage(1, 1, a);
164         }
165
166         CowStringOpt(const E *s, size_type len, const allocator_type &a)
167         {
168                 // Warning - MSVC's debugger has trouble tracing through the code below.
169                 // It seems to be a const-correctness issue
170                 //
171                 new(buf_) Storage(a);
172                 Data().reserve(len + 1);
173                 Data().resize(1, 1);
174                 Data().append(s, s + len);
175         }
176
177         CowStringOpt(size_type len, E c, const allocator_type &a)
178         {
179                 new(buf_) Storage(len + 1, c, a);
180                 Refs() = 1;
181         }
182
183         CowStringOpt &operator=(const CowStringOpt &rhs)
184         {
185                 CowStringOpt(rhs).swap(*this);
186                 return *this;
187         }
188
189         ~CowStringOpt()
190         {
191                 assert(Data().size() > 0);
192                 if (--Refs() == 0) Data().~Storage();
193         }
194
195         iterator begin()
196         {
197                 assert(Data().size() > 0);
198                 MakeUnique();
199                 return Data().begin() + 1;
200         }
201
202         const_iterator begin() const
203         {
204                 assert(Data().size() > 0);
205                 return Data().begin() + 1;
206         }
207
208         iterator end()
209         {
210                 MakeUnique();
211                 return Data().end();
212         }
213
214         const_iterator end() const
215         {
216                 return Data().end();
217         }
218
219         size_type size() const
220         {
221                 assert(Data().size() > 0);
222                 return Data().size() - 1;
223         }
224
225         size_type max_size() const
226         {
227                 assert(Data().max_size() > 0);
228                 return Data().max_size() - 1;
229         }
230
231         size_type capacity() const
232         {
233                 assert(Data().capacity() > 0);
234                 return Data().capacity() - 1;
235         }
236
237         void resize(size_type n, E c)
238         {
239                 assert(Data().size() > 0);
240                 MakeUnique();
241                 Data().resize(n + 1, c);
242         }
243
244         template <class FwdIterator>
245         void append(FwdIterator b, FwdIterator e)
246         {
247                 MakeUnique();
248                 Data().append(b, e);
249         }
250
251         void reserve(size_type res_arg)
252         {
253                 if (capacity() > res_arg) return;
254                 MakeUnique();
255                 Data().reserve(res_arg + 1);
256         }
257
258         void swap(CowStringOpt &rhs)
259         {
260                 Data().swap(rhs.Data());
261         }
262
263         const E *c_str() const
264         {
265                 assert(Data().size() > 0);
266                 return Data().c_str() + 1;
267         }
268
269         const E *data() const
270         {
271                 assert(Data().size() > 0);
272                 return Data().data() + 1;
273         }
274
275         allocator_type get_allocator() const
276         {
277                 return Data().get_allocator();
278         }
279 };
280
281
282 #endif // COW_STRING_OPT_INC_