1
////////////////////////////////////////////////////////////////////////////////
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
////////////////////////////////////////////////////////////////////////////////
13
#ifndef SMALL_STRING_OPT_INC_
14
#define SMALL_STRING_OPT_INC_
16
// $Id: smallstringopt.h 754 2006-10-17 19:59:11Z syntheticpp $
19
////////////////////////////////////////////////////////////////////////////////
20
// class template SmallStringOpt
21
// Builds the small string optimization over any other storage
22
////////////////////////////////////////////////////////////////////////////////
24
/* This is the template for a storage policy
25
////////////////////////////////////////////////////////////////////////////////
26
template <typename E, class A = @>
31
typedef @ const_iterator;
32
typedef A allocator_type;
35
StoragePolicy(const StoragePolicy& s);
36
StoragePolicy(const A&);
37
StoragePolicy(const E* s, size_type len, const A&);
38
StoragePolicy(size_type len, E c, const A&);
42
const_iterator begin() const;
44
const_iterator end() const;
46
size_type size() const;
47
size_type max_size() const;
48
size_type capacity() const;
50
void reserve(size_type res_arg);
52
void append(const E* s, size_type sz);
54
template <class InputIterator>
55
void append(InputIterator b, InputIterator e);
57
void resize(size_type newSize, E fill);
59
void swap(StoragePolicy& rhs);
61
const E* c_str() const;
62
const E* data() const;
64
A get_allocator() const;
66
////////////////////////////////////////////////////////////////////////////////
75
#include "flex_string_details.h"
77
////////////////////////////////////////////////////////////////////////////////
78
// class template SmallStringOpt
79
// Builds the small string optimization over any other storage
80
////////////////////////////////////////////////////////////////////////////////
82
template <class Storage, unsigned int threshold,
83
typename Align = typename Storage::value_type*>
87
typedef typename Storage::value_type value_type;
88
typedef value_type* iterator;
89
typedef const value_type* const_iterator;
90
typedef typename Storage::allocator_type allocator_type;
91
typedef typename allocator_type::size_type size_type;
92
typedef typename Storage::reference reference;
95
enum { temp1 = threshold * sizeof(value_type) > sizeof(Storage)
96
? threshold * sizeof(value_type)
99
enum { temp2 = temp1 > sizeof(Align) ? temp1 : sizeof(Align) };
102
enum { maxSmallString =
103
(temp2 + sizeof(value_type) - 1) / sizeof(value_type) };
106
enum { magic = maxSmallString + 1 };
110
mutable value_type buf_[maxSmallString + 1];
114
Storage& GetStorage()
116
assert(buf_[maxSmallString] == magic);
117
Storage* p = reinterpret_cast<Storage*>(&buf_[0]);
121
const Storage& GetStorage() const
123
assert(buf_[maxSmallString] == magic);
124
const Storage *p = reinterpret_cast<const Storage*>(&buf_[0]);
130
return buf_[maxSmallString] != magic;
134
SmallStringOpt(const SmallStringOpt& s)
138
flex_string_details::pod_copy(
145
new(buf_) Storage(s.GetStorage());
147
buf_[maxSmallString] = s.buf_[maxSmallString];
150
SmallStringOpt(const allocator_type&)
152
buf_[maxSmallString] = maxSmallString;
155
SmallStringOpt(const value_type* s, size_type len, const allocator_type& a)
157
if (len <= maxSmallString)
159
flex_string_details::pod_copy(s, s + len, buf_);
160
buf_[maxSmallString] = value_type(maxSmallString - len);
164
new(buf_) Storage(s, len, a);
165
buf_[maxSmallString] = magic;
169
SmallStringOpt(size_type len, value_type c, const allocator_type& a)
171
if (len <= maxSmallString)
173
flex_string_details::pod_fill(buf_, buf_ + len, c);
174
buf_[maxSmallString] = value_type(maxSmallString - len);
178
new(buf_) Storage(len, c, a);
179
buf_[maxSmallString] = magic;
183
SmallStringOpt& operator=(const SmallStringOpt& rhs)
189
append(rhs.data(), rhs.data() + rhs.size());
196
if (!Small()) GetStorage().~Storage();
201
if (Small()) return buf_;
202
return &*GetStorage().begin();
205
const_iterator begin() const
207
if (Small()) return buf_;
208
return &*GetStorage().begin();
213
if (Small()) return buf_ + maxSmallString - buf_[maxSmallString];
214
return &*GetStorage().end();
217
const_iterator end() const
219
if (Small()) return buf_ + maxSmallString - buf_[maxSmallString];
220
return &*GetStorage().end();
223
size_type size() const
225
assert(!Small() || maxSmallString >= buf_[maxSmallString]);
227
? maxSmallString - buf_[maxSmallString]
228
: GetStorage().size();
231
size_type max_size() const
232
{ return get_allocator().max_size(); }
234
size_type capacity() const
235
{ return Small() ? maxSmallString : GetStorage().capacity(); }
237
void reserve(size_type res_arg)
241
if (res_arg <= maxSmallString) return;
242
SmallStringOpt temp(*this);
243
this->~SmallStringOpt();
244
new(buf_) Storage(temp.data(), temp.size(),
245
temp.get_allocator());
246
buf_[maxSmallString] = magic;
247
GetStorage().reserve(res_arg);
251
GetStorage().reserve(res_arg);
253
assert(capacity() >= res_arg);
256
template <class FwdIterator>
257
void append(FwdIterator b, FwdIterator e)
261
GetStorage().append(b, e);
265
// append to a small string
267
sz = std::distance(b, e),
268
neededCapacity = maxSmallString - buf_[maxSmallString] + sz;
270
if (maxSmallString < neededCapacity)
272
// need to change storage strategy
273
allocator_type alloc;
275
temp.reserve(neededCapacity);
276
temp.append(buf_, buf_ + maxSmallString - buf_[maxSmallString]);
278
buf_[maxSmallString] = magic;
279
new(buf_) Storage(temp.get_allocator());
280
GetStorage().swap(temp);
284
std::copy(b, e, buf_ + maxSmallString - buf_[maxSmallString]);
285
buf_[maxSmallString] = buf_[maxSmallString] - value_type(sz);
290
void resize(size_type n, value_type c)
294
if (n > maxSmallString)
296
// Small string resized to big string
297
SmallStringOpt temp(*this); // can't throw
298
// 11-17-2001: correct exception safety bug
299
Storage newString(temp.data(), temp.size(),
300
temp.get_allocator());
301
newString.resize(n, c);
302
// We make the reasonable assumption that an empty Storage
303
// constructor won't throw
304
this->~SmallStringOpt();
305
new(&buf_[0]) Storage(temp.get_allocator());
306
buf_[maxSmallString] = value_type(magic);
307
GetStorage().swap(newString);
311
// Small string resized to small string
312
// 11-17-2001: bug fix: terminating zero not copied
313
size_type toFill = n > size() ? n - size() : 0;
314
flex_string_details::pod_fill(end(), end() + toFill, c);
315
buf_[maxSmallString] = value_type(maxSmallString - n);
320
if (n > maxSmallString)
322
// Big string resized to big string
323
GetStorage().resize(n, c);
327
// Big string resized to small string
328
// 11-17=2001: bug fix in the assertion below
329
assert(capacity() > n);
330
SmallStringOpt newObj(data(), n, get_allocator());
336
void swap(SmallStringOpt& rhs)
342
// Small swapped with small
343
std::swap_ranges(buf_, buf_ + maxSmallString + 1,
348
// Small swapped with big
349
// Make a copy of myself - can't throw
350
SmallStringOpt temp(*this);
352
this->~SmallStringOpt();
353
// Make an empty storage for myself (likely won't throw)
354
new(buf_) Storage(0, value_type(), rhs.get_allocator());
355
buf_[maxSmallString] = magic;
356
// Recurse to this same function
359
rhs.~SmallStringOpt();
360
// Build the new small string into rhs
361
new(&rhs) SmallStringOpt(temp);
368
// Big swapped with small
369
// Already implemented, recurse with reversed args
374
// Big swapped with big
375
GetStorage().swap(rhs.GetStorage());
380
const value_type* c_str() const
382
if (!Small()) return GetStorage().c_str();
383
buf_[maxSmallString - buf_[maxSmallString]] = value_type();
387
const value_type* data() const
388
{ return Small() ? buf_ : GetStorage().data(); }
390
allocator_type get_allocator() const
391
{ return allocator_type(); }
395
#endif // SMALL_STRING_OPT_INC_