annotate DEPENDENCIES/generic/include/boost/wave/util/flex_string.hpp @ 125:34e428693f5d vext

Vext -> Repoint
author Chris Cannam
date Thu, 14 Jun 2018 11:15:39 +0100
parents 2665513ce2d3
children
rev   line source
Chris@16 1 /*=============================================================================
Chris@16 2 Boost.Wave: A Standard compliant C++ preprocessor library
Chris@16 3 http://www.boost.org/
Chris@16 4
Chris@16 5 Copyright (c) 2001 by Andrei Alexandrescu. Distributed under the Boost
Chris@16 6 Software License, Version 1.0. (See accompanying file
Chris@16 7 LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Chris@16 8 =============================================================================*/
Chris@16 9
Chris@16 10 // This code is taken from:
Chris@16 11 // Andrei Alexandrescu, Generic<Programming>: A Policy-Based basic_string
Chris@16 12 // Implementation. http://www.cuj.com/documents/s=7994/cujcexp1906alexandr/
Chris@16 13 //
Chris@16 14 // #HK030306:
Chris@16 15 // - Moved into the namespace boost::wave::util
Chris@16 16 // - Added a bunch of missing typename(s)
Chris@16 17 // - Integrated with boost config
Chris@16 18 // - Added a missing header include
Chris@16 19 // - Added special constructors and operator= to allow CowString to be
Chris@16 20 // a real COW-string (removed unnecessary data copying)
Chris@16 21 // - Fixed a string terminating bug in append
Chris@16 22 //
Chris@16 23 // #HK040109:
Chris@16 24 // - Incorporated the changes from Andrei's latest version of this class
Chris@16 25 //
Chris@16 26 // #HK070307:
Chris@16 27 // - Once again incorporated the changes from Andrei's latest version of
Chris@16 28 // this class
Chris@16 29 //
Chris@16 30 // #HK090523:
Chris@16 31 // - Incorporated the changes from latest version of flex_string as
Chris@16 32 // maintained in Loki
Chris@16 33 //
Chris@16 34 // #HK130910:
Chris@16 35 // - Removed the getline implementation which was borrowed from the SGI
Chris@16 36 // STL as the license for this code is not compatible with Boost.
Chris@16 37
Chris@16 38 #ifndef FLEX_STRING_INC_
Chris@16 39 #define FLEX_STRING_INC_
Chris@16 40
Chris@16 41 /*
Chris@16 42 ////////////////////////////////////////////////////////////////////////////////
Chris@16 43 template <typename E, class A = @>
Chris@16 44 class StoragePolicy
Chris@16 45 {
Chris@16 46 typedef E value_type;
Chris@16 47 typedef @ iterator;
Chris@16 48 typedef @ const_iterator;
Chris@16 49 typedef A allocator_type;
Chris@16 50 typedef @ size_type;
Chris@16 51
Chris@16 52 StoragePolicy(const StoragePolicy& s);
Chris@16 53 StoragePolicy(const A&);
Chris@16 54 StoragePolicy(const E* s, size_type len, const A&);
Chris@16 55 StoragePolicy(size_type len, E c, const A&);
Chris@16 56 ~StoragePolicy();
Chris@16 57
Chris@16 58 iterator begin();
Chris@16 59 const_iterator begin() const;
Chris@16 60 iterator end();
Chris@16 61 const_iterator end() const;
Chris@16 62
Chris@16 63 size_type size() const;
Chris@16 64 size_type max_size() const;
Chris@16 65 size_type capacity() const;
Chris@16 66
Chris@16 67 void reserve(size_type res_arg);
Chris@16 68
Chris@16 69 void append(const E* s, size_type sz);
Chris@16 70
Chris@16 71 template <class InputIterator>
Chris@16 72 void append(InputIterator b, InputIterator e);
Chris@16 73
Chris@16 74 void resize(size_type newSize, E fill);
Chris@16 75
Chris@16 76 void swap(StoragePolicy& rhs);
Chris@16 77
Chris@16 78 const E* c_str() const;
Chris@16 79 const E* data() const;
Chris@16 80
Chris@16 81 A get_allocator() const;
Chris@16 82 };
Chris@16 83 ////////////////////////////////////////////////////////////////////////////////
Chris@16 84 */
Chris@16 85
Chris@16 86 #include <boost/config.hpp>
Chris@16 87 #include <boost/assert.hpp>
Chris@16 88 #include <boost/throw_exception.hpp>
Chris@16 89
Chris@16 90 #include <boost/iterator/reverse_iterator.hpp>
Chris@16 91
Chris@16 92 #include <boost/wave/wave_config.hpp>
Chris@16 93 #if BOOST_WAVE_SERIALIZATION != 0
Chris@16 94 #include <boost/serialization/serialization.hpp>
Chris@16 95 #include <boost/serialization/split_free.hpp>
Chris@16 96 #include <boost/serialization/collections_save_imp.hpp>
Chris@16 97 #include <boost/serialization/collections_load_imp.hpp>
Chris@16 98 #define BOOST_WAVE_FLEX_STRING_SERIALIZATION_HACK 1
Chris@16 99 #endif
Chris@16 100
Chris@16 101 #include <memory>
Chris@16 102 #include <new>
Chris@16 103 #include <string>
Chris@16 104 #include <vector>
Chris@16 105 #include <algorithm>
Chris@16 106 #include <functional>
Chris@16 107 #include <limits>
Chris@16 108 #include <stdexcept>
Chris@16 109 #include <ios>
Chris@16 110
Chris@16 111 #include <cstddef>
Chris@16 112 #include <cstring>
Chris@16 113 #include <cstdlib>
Chris@16 114
Chris@16 115 // this must occur after all of the includes and before any code appears
Chris@16 116 #ifdef BOOST_HAS_ABI_HEADERS
Chris@16 117 #include BOOST_ABI_PREFIX
Chris@16 118 #endif
Chris@16 119
Chris@16 120 ///////////////////////////////////////////////////////////////////////////////
Chris@16 121 namespace boost {
Chris@16 122 namespace wave {
Chris@16 123 namespace util {
Chris@16 124
Chris@16 125 namespace flex_string_details
Chris@16 126 {
Chris@16 127 template <class InIt, class OutIt>
Chris@16 128 OutIt copy_n(InIt b,
Chris@16 129 typename std::iterator_traits<InIt>::difference_type n, OutIt d)
Chris@16 130 {
Chris@16 131 for (/**/; n != 0; --n, ++b, ++d)
Chris@16 132 {
Chris@16 133 *d = *b;
Chris@16 134 }
Chris@16 135 return d;
Chris@16 136 }
Chris@16 137
Chris@16 138 template <class Pod, class T>
Chris@16 139 inline void pod_fill(Pod* b, Pod* e, T c)
Chris@16 140 {
Chris@16 141 switch ((e - b) & 7)
Chris@16 142 {
Chris@16 143 case 0:
Chris@16 144 while (b != e)
Chris@16 145 {
Chris@16 146 *b = c; ++b; BOOST_FALLTHROUGH;
Chris@16 147 case 7: *b = c; ++b; BOOST_FALLTHROUGH;
Chris@16 148 case 6: *b = c; ++b; BOOST_FALLTHROUGH;
Chris@16 149 case 5: *b = c; ++b; BOOST_FALLTHROUGH;
Chris@16 150 case 4: *b = c; ++b; BOOST_FALLTHROUGH;
Chris@16 151 case 3: *b = c; ++b; BOOST_FALLTHROUGH;
Chris@16 152 case 2: *b = c; ++b; BOOST_FALLTHROUGH;
Chris@16 153 case 1: *b = c; ++b;
Chris@16 154 }
Chris@16 155 }
Chris@16 156 }
Chris@16 157
Chris@16 158 template <class Pod>
Chris@16 159 inline void pod_move(const Pod* b, const Pod* e, Pod* d)
Chris@16 160 {
Chris@16 161 using namespace std;
Chris@16 162 memmove(d, b, (e - b) * sizeof(*b));
Chris@16 163 }
Chris@16 164
Chris@16 165 template <class Pod>
Chris@16 166 inline Pod* pod_copy(const Pod* b, const Pod* e, Pod* d)
Chris@16 167 {
Chris@16 168 const std::size_t s = e - b;
Chris@16 169 using namespace std;
Chris@16 170 memcpy(d, b, s * sizeof(*b));
Chris@16 171 return d + s;
Chris@16 172 }
Chris@16 173
Chris@16 174 template <typename T> struct get_unsigned
Chris@16 175 {
Chris@16 176 typedef T result;
Chris@16 177 };
Chris@16 178
Chris@16 179 template <> struct get_unsigned<char>
Chris@16 180 {
Chris@16 181 typedef unsigned char result;
Chris@16 182 };
Chris@16 183
Chris@16 184 template <> struct get_unsigned<signed char>
Chris@16 185 {
Chris@16 186 typedef unsigned char result;
Chris@16 187 };
Chris@16 188
Chris@16 189 template <> struct get_unsigned<short int>
Chris@16 190 {
Chris@16 191 typedef unsigned short int result;
Chris@16 192 };
Chris@16 193
Chris@16 194 template <> struct get_unsigned<int>
Chris@16 195 {
Chris@16 196 typedef unsigned int result;
Chris@16 197 };
Chris@16 198
Chris@16 199 template <> struct get_unsigned<long int>
Chris@16 200 {
Chris@16 201 typedef unsigned long int result;
Chris@16 202 };
Chris@16 203
Chris@16 204 enum Shallow {};
Chris@16 205 }
Chris@16 206
Chris@16 207 template <class T> class mallocator
Chris@16 208 {
Chris@16 209 public:
Chris@16 210 typedef T value_type;
Chris@16 211 typedef value_type* pointer;
Chris@16 212 typedef const value_type* const_pointer;
Chris@16 213 typedef value_type& reference;
Chris@16 214 typedef const value_type& const_reference;
Chris@16 215 typedef std::size_t size_type;
Chris@16 216 //typedef unsigned int size_type;
Chris@16 217 //typedef std::ptrdiff_t difference_type;
Chris@16 218 typedef int difference_type;
Chris@16 219
Chris@16 220 template <class U>
Chris@16 221 struct rebind { typedef mallocator<U> other; };
Chris@16 222
Chris@16 223 mallocator() {}
Chris@16 224 mallocator(const mallocator&) {}
Chris@16 225 //template <class U>
Chris@16 226 //mallocator(const mallocator<U>&) {}
Chris@16 227 ~mallocator() {}
Chris@16 228
Chris@16 229 pointer address(reference x) const { return &x; }
Chris@16 230 const_pointer address(const_reference x) const
Chris@16 231 {
Chris@16 232 return x;
Chris@16 233 }
Chris@16 234
Chris@16 235 pointer allocate(size_type n, const_pointer = 0)
Chris@16 236 {
Chris@16 237 using namespace std;
Chris@16 238 void* p = malloc(n * sizeof(T));
Chris@16 239 if (!p) boost::throw_exception(std::bad_alloc());
Chris@16 240 return static_cast<pointer>(p);
Chris@16 241 }
Chris@16 242
Chris@16 243 void deallocate(pointer p, size_type)
Chris@16 244 {
Chris@16 245 using namespace std;
Chris@16 246 free(p);
Chris@16 247 }
Chris@16 248
Chris@16 249 size_type max_size() const
Chris@16 250 {
Chris@16 251 return static_cast<size_type>(-1) / sizeof(T);
Chris@16 252 }
Chris@16 253
Chris@16 254 void construct(pointer p, const value_type& x)
Chris@16 255 {
Chris@16 256 new(p) value_type(x);
Chris@16 257 }
Chris@16 258
Chris@16 259 void destroy(pointer p)
Chris@16 260 {
Chris@16 261 p->~value_type();
Chris@16 262 }
Chris@16 263
Chris@16 264 private:
Chris@16 265 void operator=(const mallocator&);
Chris@16 266 };
Chris@16 267
Chris@16 268 template<> class mallocator<void>
Chris@16 269 {
Chris@16 270 typedef void value_type;
Chris@16 271 typedef void* pointer;
Chris@16 272 typedef const void* const_pointer;
Chris@16 273
Chris@16 274 template <class U>
Chris@16 275 struct rebind { typedef mallocator<U> other; };
Chris@16 276 };
Chris@16 277
Chris@16 278 template <class T>
Chris@16 279 inline bool operator==(const mallocator<T>&,
Chris@16 280 const mallocator<T>&) {
Chris@16 281 return true;
Chris@16 282 }
Chris@16 283
Chris@16 284 template <class T>
Chris@16 285 inline bool operator!=(const mallocator<T>&,
Chris@16 286 const mallocator<T>&) {
Chris@16 287 return false;
Chris@16 288 }
Chris@16 289
Chris@16 290 template <class Allocator>
Chris@16 291 typename Allocator::pointer Reallocate(
Chris@16 292 Allocator& alloc,
Chris@16 293 typename Allocator::pointer p,
Chris@16 294 typename Allocator::size_type oldObjCount,
Chris@16 295 typename Allocator::size_type newObjCount,
Chris@16 296 void*)
Chris@16 297 {
Chris@16 298 // @@@ not implemented
Chris@16 299 return NULL;
Chris@16 300 }
Chris@16 301
Chris@16 302 template <class Allocator>
Chris@16 303 typename Allocator::pointer Reallocate(
Chris@16 304 Allocator& alloc,
Chris@16 305 typename Allocator::pointer p,
Chris@16 306 typename Allocator::size_type oldObjCount,
Chris@16 307 typename Allocator::size_type newObjCount,
Chris@16 308 mallocator<void>*)
Chris@16 309 {
Chris@16 310 // @@@ not implemented
Chris@16 311 return NULL;
Chris@16 312 }
Chris@16 313
Chris@16 314 ////////////////////////////////////////////////////////////////////////////////
Chris@16 315 // class template SimpleStringStorage
Chris@16 316 // Allocates memory with malloc
Chris@16 317 ////////////////////////////////////////////////////////////////////////////////
Chris@16 318
Chris@16 319 template <typename E, class A = std::allocator<E> >
Chris@16 320 class SimpleStringStorage
Chris@16 321 {
Chris@16 322 // The "public" below exists because MSVC can't do template typedefs
Chris@16 323 public:
Chris@16 324 struct Data
Chris@16 325 {
Chris@16 326 Data() : pEnd_(buffer_), pEndOfMem_(buffer_) { buffer_[0] = E(0); }
Chris@16 327
Chris@16 328 E* pEnd_;
Chris@16 329 E* pEndOfMem_;
Chris@16 330 E buffer_[1];
Chris@16 331 };
Chris@16 332 static const Data emptyString_;
Chris@16 333
Chris@16 334 typedef typename A::size_type size_type;
Chris@16 335
Chris@16 336 private:
Chris@16 337 Data* pData_;
Chris@16 338
Chris@16 339 void Init(size_type size, size_type capacity)
Chris@16 340 {
Chris@16 341 BOOST_ASSERT(size <= capacity);
Chris@16 342 if (capacity == 0)
Chris@16 343 {
Chris@16 344 pData_ = const_cast<Data*>(&emptyString_);
Chris@16 345 }
Chris@16 346 else
Chris@16 347 {
Chris@16 348 // 11-17-2000: comment added:
Chris@16 349 // No need to allocate (capacity + 1) to
Chris@16 350 // accommodate the terminating 0, because Data already
Chris@16 351 // has one character in there
Chris@16 352 pData_ = static_cast<Data*>(
Chris@16 353 malloc(sizeof(Data) + capacity * sizeof(E)));
Chris@16 354 if (!pData_) boost::throw_exception(std::bad_alloc());
Chris@16 355 pData_->pEnd_ = pData_->buffer_ + size;
Chris@16 356 pData_->pEndOfMem_ = pData_->buffer_ + capacity;
Chris@16 357 }
Chris@16 358 }
Chris@16 359
Chris@16 360 private:
Chris@16 361 // Warning - this doesn't initialize pData_. Used in reserve()
Chris@16 362 SimpleStringStorage()
Chris@16 363 { }
Chris@16 364
Chris@16 365 public:
Chris@16 366 typedef E value_type;
Chris@16 367 typedef E* iterator;
Chris@16 368 typedef const E* const_iterator;
Chris@16 369 typedef A allocator_type;
Chris@16 370
Chris@16 371 SimpleStringStorage(const SimpleStringStorage& rhs)
Chris@16 372 {
Chris@16 373 const size_type sz = rhs.size();
Chris@16 374 Init(sz, sz);
Chris@16 375 if (sz) flex_string_details::pod_copy(rhs.begin(), rhs.end(), begin());
Chris@16 376 }
Chris@16 377
Chris@16 378 SimpleStringStorage(const SimpleStringStorage& s,
Chris@16 379 flex_string_details::Shallow)
Chris@16 380 : pData_(s.pData_)
Chris@16 381 {
Chris@16 382 }
Chris@16 383
Chris@16 384 SimpleStringStorage(const A&)
Chris@16 385 { pData_ = const_cast<Data*>(&emptyString_); }
Chris@16 386
Chris@16 387 SimpleStringStorage(const E* s, size_type len, const A&)
Chris@16 388 {
Chris@16 389 Init(len, len);
Chris@16 390 flex_string_details::pod_copy(s, s + len, begin());
Chris@16 391 }
Chris@16 392
Chris@16 393 SimpleStringStorage(size_type len, E c, const A&)
Chris@16 394 {
Chris@16 395 Init(len, len);
Chris@16 396 flex_string_details::pod_fill(begin(), end(), c);
Chris@16 397 }
Chris@16 398
Chris@16 399 SimpleStringStorage& operator=(const SimpleStringStorage& rhs)
Chris@16 400 {
Chris@16 401 const size_type sz = rhs.size();
Chris@16 402 reserve(sz);
Chris@16 403 flex_string_details::pod_copy(&*rhs.begin(), &*rhs.end(), begin());
Chris@16 404 pData_->pEnd_ = &*begin() + sz;
Chris@16 405 return *this;
Chris@16 406 }
Chris@16 407
Chris@16 408 ~SimpleStringStorage()
Chris@16 409 {
Chris@16 410 BOOST_ASSERT(begin() <= end());
Chris@16 411 if (pData_ != &emptyString_) free(pData_);
Chris@16 412 }
Chris@16 413
Chris@16 414 iterator begin()
Chris@16 415 { return pData_->buffer_; }
Chris@16 416
Chris@16 417 const_iterator begin() const
Chris@16 418 { return pData_->buffer_; }
Chris@16 419
Chris@16 420 iterator end()
Chris@16 421 { return pData_->pEnd_; }
Chris@16 422
Chris@16 423 const_iterator end() const
Chris@16 424 { return pData_->pEnd_; }
Chris@16 425
Chris@16 426 size_type size() const
Chris@16 427 { return pData_->pEnd_ - pData_->buffer_; }
Chris@16 428
Chris@16 429 size_type max_size() const
Chris@16 430 { return std::size_t(-1) / sizeof(E) - sizeof(Data) - 1; }
Chris@16 431
Chris@16 432 size_type capacity() const
Chris@16 433 { return pData_->pEndOfMem_ - pData_->buffer_; }
Chris@16 434
Chris@16 435 void reserve(size_type res_arg)
Chris@16 436 {
Chris@16 437 if (res_arg <= capacity())
Chris@16 438 {
Chris@16 439 // @@@ insert shrinkage here if you wish
Chris@16 440 return;
Chris@16 441 }
Chris@16 442
Chris@16 443 if (pData_ == &emptyString_)
Chris@16 444 {
Chris@16 445 Init(0, res_arg);
Chris@16 446 }
Chris@16 447 else
Chris@16 448 {
Chris@16 449 const size_type sz = size();
Chris@16 450
Chris@16 451 void* p = realloc(pData_,
Chris@16 452 sizeof(Data) + res_arg * sizeof(E));
Chris@16 453 if (!p) boost::throw_exception(std::bad_alloc());
Chris@16 454
Chris@16 455 if (p != pData_)
Chris@16 456 {
Chris@16 457 pData_ = static_cast<Data*>(p);
Chris@16 458 pData_->pEnd_ = pData_->buffer_ + sz;
Chris@16 459 }
Chris@16 460 pData_->pEndOfMem_ = pData_->buffer_ + res_arg;
Chris@16 461 }
Chris@16 462 }
Chris@16 463
Chris@16 464 void append(const E* s, size_type sz)
Chris@16 465 {
Chris@16 466 const size_type neededCapacity = size() + sz;
Chris@16 467
Chris@16 468 if (capacity() < neededCapacity)
Chris@16 469 {
Chris@16 470 const iterator b = begin();
Chris@16 471 static std::less_equal<const E*> le;
Chris@16 472 if (le(b, s) && le(s, end()))
Chris@16 473 {
Chris@16 474 // aliased
Chris@16 475 const size_type offset = s - b;
Chris@16 476 reserve(neededCapacity);
Chris@16 477 s = begin() + offset;
Chris@16 478 }
Chris@16 479 else
Chris@16 480 {
Chris@16 481 reserve(neededCapacity);
Chris@16 482 }
Chris@16 483 }
Chris@16 484 flex_string_details::pod_copy(s, s + sz, end());
Chris@16 485 pData_->pEnd_ += sz;
Chris@16 486 }
Chris@16 487
Chris@16 488 template <class InputIterator>
Chris@16 489 void append(InputIterator b, InputIterator e)
Chris@16 490 {
Chris@16 491 // @@@ todo: optimize this depending on iterator type
Chris@16 492 for (; b != e; ++b)
Chris@16 493 {
Chris@16 494 *this += *b;
Chris@16 495 }
Chris@16 496 }
Chris@16 497
Chris@16 498 void resize(size_type newSize, E fill)
Chris@16 499 {
Chris@16 500 const int delta = int(newSize - size());
Chris@16 501 if (delta == 0) return;
Chris@16 502
Chris@16 503 if (delta > 0)
Chris@16 504 {
Chris@16 505 if (newSize > capacity())
Chris@16 506 {
Chris@16 507 reserve(newSize);
Chris@16 508 }
Chris@16 509 E* e = &*end();
Chris@16 510 flex_string_details::pod_fill(e, e + delta, fill);
Chris@16 511 }
Chris@16 512 pData_->pEnd_ = pData_->buffer_ + newSize;
Chris@16 513 }
Chris@16 514
Chris@16 515 void swap(SimpleStringStorage& rhs)
Chris@16 516 {
Chris@16 517 std::swap(pData_, rhs.pData_);
Chris@16 518 }
Chris@16 519
Chris@16 520 const E* c_str() const
Chris@16 521 {
Chris@16 522 if (pData_ != &emptyString_) *pData_->pEnd_ = E();
Chris@16 523 return pData_->buffer_;
Chris@16 524 }
Chris@16 525
Chris@16 526 const E* data() const
Chris@16 527 { return pData_->buffer_; }
Chris@16 528
Chris@16 529 A get_allocator() const
Chris@16 530 { return A(); }
Chris@16 531 };
Chris@16 532
Chris@16 533 template <typename E, class A>
Chris@16 534 const typename SimpleStringStorage<E, A>::Data
Chris@16 535 SimpleStringStorage<E, A>::emptyString_ =
Chris@16 536 typename SimpleStringStorage<E, A>::Data();
Chris@16 537
Chris@16 538 ////////////////////////////////////////////////////////////////////////////////
Chris@16 539 // class template AllocatorStringStorage
Chris@16 540 // Allocates with your allocator
Chris@16 541 // Takes advantage of the Empty Base Optimization if available
Chris@16 542 ////////////////////////////////////////////////////////////////////////////////
Chris@16 543
Chris@16 544 template <typename E, class A = std::allocator<E> >
Chris@16 545 class AllocatorStringStorage : public A
Chris@16 546 {
Chris@16 547 typedef typename A::size_type size_type;
Chris@16 548 typedef typename SimpleStringStorage<E, A>::Data Data;
Chris@16 549
Chris@16 550 void* Alloc(size_type sz, const void* p = 0)
Chris@16 551 {
Chris@16 552 return A::allocate(1 + (sz - 1) / sizeof(E),
Chris@16 553 static_cast<const char*>(p));
Chris@16 554 }
Chris@16 555
Chris@16 556 void* Realloc(void* p, size_type oldSz, size_type newSz)
Chris@16 557 {
Chris@16 558 void* r = Alloc(newSz);
Chris@16 559 flex_string_details::pod_copy(p, p + Min(oldSz, newSz), r);
Chris@16 560 Free(p, oldSz);
Chris@16 561 return r;
Chris@16 562 }
Chris@16 563
Chris@16 564 void Free(void* p, size_type sz)
Chris@16 565 {
Chris@16 566 A::deallocate(static_cast<E*>(p), sz);
Chris@16 567 }
Chris@16 568
Chris@16 569 Data* pData_;
Chris@16 570
Chris@16 571 void Init(size_type size, size_type cap)
Chris@16 572 {
Chris@16 573 BOOST_ASSERT(size <= cap);
Chris@16 574
Chris@16 575 if (cap == 0)
Chris@16 576 {
Chris@16 577 pData_ = const_cast<Data*>(
Chris@16 578 &SimpleStringStorage<E, A>::emptyString_);
Chris@16 579 }
Chris@16 580 else
Chris@16 581 {
Chris@16 582 pData_ = static_cast<Data*>(Alloc(
Chris@16 583 cap * sizeof(E) + sizeof(Data)));
Chris@16 584 pData_->pEnd_ = pData_->buffer_ + size;
Chris@16 585 pData_->pEndOfMem_ = pData_->buffer_ + cap;
Chris@16 586 }
Chris@16 587 }
Chris@16 588
Chris@16 589 public:
Chris@16 590 typedef E value_type;
Chris@16 591 typedef E* iterator;
Chris@16 592 typedef const E* const_iterator;
Chris@16 593 typedef A allocator_type;
Chris@16 594
Chris@16 595 AllocatorStringStorage()
Chris@16 596 : A(), pData_(0)
Chris@16 597 {
Chris@16 598 }
Chris@16 599
Chris@16 600 AllocatorStringStorage(const AllocatorStringStorage& rhs)
Chris@16 601 : A(rhs.get_allocator())
Chris@16 602 {
Chris@16 603 const size_type sz = rhs.size();
Chris@16 604 Init(sz, sz);
Chris@16 605 if (sz) flex_string_details::pod_copy(rhs.begin(), rhs.end(), begin());
Chris@16 606 }
Chris@16 607
Chris@16 608 AllocatorStringStorage(const AllocatorStringStorage& s,
Chris@16 609 flex_string_details::Shallow)
Chris@16 610 : A(s.get_allocator())
Chris@16 611 {
Chris@16 612 pData_ = s.pData_;
Chris@16 613 }
Chris@16 614
Chris@16 615 AllocatorStringStorage(const A& a) : A(a)
Chris@16 616 {
Chris@16 617 pData_ = const_cast<Data*>(
Chris@16 618 &SimpleStringStorage<E, A>::emptyString_);
Chris@16 619 }
Chris@16 620
Chris@16 621 AllocatorStringStorage(const E* s, size_type len, const A& a)
Chris@16 622 : A(a)
Chris@16 623 {
Chris@16 624 Init(len, len);
Chris@16 625 flex_string_details::pod_copy(s, s + len, begin());
Chris@16 626 }
Chris@16 627
Chris@16 628 AllocatorStringStorage(size_type len, E c, const A& a)
Chris@16 629 : A(a)
Chris@16 630 {
Chris@16 631 Init(len, len);
Chris@16 632 flex_string_details::pod_fill(&*begin(), &*end(), c);
Chris@16 633 }
Chris@16 634
Chris@16 635 AllocatorStringStorage& operator=(const AllocatorStringStorage& rhs)
Chris@16 636 {
Chris@16 637 const size_type sz = rhs.size();
Chris@16 638 reserve(sz);
Chris@16 639 flex_string_details::pod_copy(&*rhs.begin(), &*rhs.end(), begin());
Chris@16 640 pData_->pEnd_ = &*begin() + rhs.size();
Chris@16 641 return *this;
Chris@16 642 }
Chris@16 643
Chris@16 644 ~AllocatorStringStorage()
Chris@16 645 {
Chris@16 646 if (capacity())
Chris@16 647 {
Chris@16 648 Free(pData_,
Chris@16 649 sizeof(Data) + capacity() * sizeof(E));
Chris@16 650 }
Chris@16 651 }
Chris@16 652
Chris@16 653 iterator begin()
Chris@16 654 { return pData_->buffer_; }
Chris@16 655
Chris@16 656 const_iterator begin() const
Chris@16 657 { return pData_->buffer_; }
Chris@16 658
Chris@16 659 iterator end()
Chris@16 660 { return pData_->pEnd_; }
Chris@16 661
Chris@16 662 const_iterator end() const
Chris@16 663 { return pData_->pEnd_; }
Chris@16 664
Chris@16 665 size_type size() const
Chris@16 666 { return size_type(end() - begin()); }
Chris@16 667
Chris@16 668 size_type max_size() const
Chris@16 669 { return A::max_size(); }
Chris@16 670
Chris@16 671 size_type capacity() const
Chris@16 672 { return size_type(pData_->pEndOfMem_ - pData_->buffer_); }
Chris@16 673
Chris@16 674 void resize(size_type n, E c)
Chris@16 675 {
Chris@16 676 reserve(n);
Chris@16 677 iterator newEnd = begin() + n;
Chris@16 678 iterator oldEnd = end();
Chris@16 679 if (newEnd > oldEnd)
Chris@16 680 {
Chris@16 681 // Copy the characters
Chris@16 682 flex_string_details::pod_fill(oldEnd, newEnd, c);
Chris@16 683 }
Chris@16 684 if (capacity()) pData_->pEnd_ = newEnd;
Chris@16 685 }
Chris@16 686
Chris@16 687 void reserve(size_type res_arg)
Chris@16 688 {
Chris@16 689 if (res_arg <= capacity())
Chris@16 690 {
Chris@16 691 // @@@ shrink to fit here
Chris@16 692 return;
Chris@16 693 }
Chris@16 694
Chris@16 695 A& myAlloc = *this;
Chris@16 696 AllocatorStringStorage newStr(myAlloc);
Chris@16 697 newStr.Init(size(), res_arg);
Chris@16 698
Chris@16 699 flex_string_details::pod_copy(begin(), end(), newStr.begin());
Chris@16 700
Chris@16 701 swap(newStr);
Chris@16 702 }
Chris@16 703
Chris@16 704 template <class ForwardIterator>
Chris@16 705 void append(ForwardIterator b, ForwardIterator e)
Chris@16 706 {
Chris@16 707 const size_type
Chris@16 708 sz = std::distance(b, e),
Chris@16 709 neededCapacity = size() + sz;
Chris@16 710
Chris@16 711 if (capacity() < neededCapacity)
Chris@16 712 {
Chris@16 713 // typedef std::less_equal<const E*> le_type;
Chris@16 714 // BOOST_ASSERT(!(le_type()(begin(), &*b) && le_type()(&*b, end())));
Chris@16 715 reserve(neededCapacity);
Chris@16 716 }
Chris@16 717 std::copy(b, e, end());
Chris@16 718 pData_->pEnd_ += sz;
Chris@16 719 }
Chris@16 720
Chris@16 721 void swap(AllocatorStringStorage& rhs)
Chris@16 722 {
Chris@16 723 // @@@ The following line is commented due to a bug in MSVC
Chris@16 724 //std::swap(lhsAlloc, rhsAlloc);
Chris@16 725 std::swap(pData_, rhs.pData_);
Chris@16 726 }
Chris@16 727
Chris@16 728 const E* c_str() const
Chris@16 729 {
Chris@16 730 if (pData_ != &SimpleStringStorage<E, A>::emptyString_)
Chris@16 731 {
Chris@16 732 *pData_->pEnd_ = E();
Chris@16 733 }
Chris@16 734 return &*begin();
Chris@16 735 }
Chris@16 736
Chris@16 737 const E* data() const
Chris@16 738 { return &*begin(); }
Chris@16 739
Chris@16 740 A get_allocator() const
Chris@16 741 { return *this; }
Chris@16 742 };
Chris@16 743
Chris@16 744 ////////////////////////////////////////////////////////////////////////////////
Chris@16 745 // class template VectorStringStorage
Chris@16 746 // Uses std::vector
Chris@16 747 // Takes advantage of the Empty Base Optimization if available
Chris@16 748 ////////////////////////////////////////////////////////////////////////////////
Chris@16 749
Chris@16 750 template <typename E, class A = std::allocator<E> >
Chris@16 751 class VectorStringStorage : protected std::vector<E, A>
Chris@16 752 {
Chris@16 753 typedef std::vector<E, A> base;
Chris@16 754
Chris@16 755 public: // protected:
Chris@16 756 typedef E value_type;
Chris@16 757 typedef typename base::iterator iterator;
Chris@16 758 typedef typename base::const_iterator const_iterator;
Chris@16 759 typedef A allocator_type;
Chris@16 760 typedef typename A::size_type size_type;
Chris@16 761
Chris@16 762 VectorStringStorage(const VectorStringStorage& s) : base(s)
Chris@16 763 { }
Chris@16 764
Chris@16 765 VectorStringStorage(const A& a) : base(1, E(), a)
Chris@16 766 { }
Chris@16 767
Chris@16 768 VectorStringStorage(const E* s, size_type len, const A& a)
Chris@16 769 : base(a)
Chris@16 770 {
Chris@16 771 base::reserve(len + 1);
Chris@16 772 base::insert(base::end(), s, s + len);
Chris@16 773 // Terminating zero
Chris@16 774 base::insert(base::end(), E());
Chris@16 775 }
Chris@16 776
Chris@16 777 VectorStringStorage(size_type len, E c, const A& a)
Chris@16 778 : base(len + 1, c, a)
Chris@16 779 {
Chris@16 780 // Terminating zero
Chris@16 781 base::back() = E();
Chris@16 782 }
Chris@16 783
Chris@16 784 VectorStringStorage& operator=(const VectorStringStorage& rhs)
Chris@16 785 {
Chris@16 786 base& v = *this;
Chris@16 787 v = rhs;
Chris@16 788 return *this;
Chris@16 789 }
Chris@16 790
Chris@16 791 iterator begin()
Chris@16 792 { return base::begin(); }
Chris@16 793
Chris@16 794 const_iterator begin() const
Chris@16 795 { return base::begin(); }
Chris@16 796
Chris@16 797 iterator end()
Chris@16 798 { return base::end() - 1; }
Chris@16 799
Chris@16 800 const_iterator end() const
Chris@16 801 { return base::end() - 1; }
Chris@16 802
Chris@16 803 size_type size() const
Chris@16 804 { return base::size() - 1; }
Chris@16 805
Chris@16 806 size_type max_size() const
Chris@16 807 { return base::max_size() - 1; }
Chris@16 808
Chris@16 809 size_type capacity() const
Chris@16 810 { return base::capacity() - 1; }
Chris@16 811
Chris@16 812 void reserve(size_type res_arg)
Chris@16 813 {
Chris@16 814 BOOST_ASSERT(res_arg < max_size());
Chris@16 815 base::reserve(res_arg + 1);
Chris@16 816 }
Chris@16 817
Chris@16 818 void append(const E* s, size_type sz)
Chris@16 819 {
Chris@16 820 // Check for aliasing because std::vector doesn't do it.
Chris@16 821 static std::less_equal<const E*> le;
Chris@16 822 if (!base::empty())
Chris@16 823 {
Chris@16 824 const E* start = &base::front();
Chris@16 825 if (le(start, s) && le(s, start + size()))
Chris@16 826 {
Chris@16 827 // aliased
Chris@16 828 const size_type offset = s - start;
Chris@16 829 reserve(size() + sz);
Chris@16 830 s = &base::front() + offset;
Chris@16 831 }
Chris@16 832 }
Chris@16 833 base::insert(end(), s, s + sz);
Chris@16 834 }
Chris@16 835
Chris@16 836 template <class InputIterator>
Chris@16 837 void append(InputIterator b, InputIterator e)
Chris@16 838 {
Chris@16 839 base::insert(end(), b, e);
Chris@16 840 }
Chris@16 841
Chris@16 842 void resize(size_type n, E c)
Chris@16 843 {
Chris@16 844 base::reserve(n + 1);
Chris@16 845 base::back() = c;
Chris@16 846 base::resize(n + 1, c);
Chris@16 847 base::back() = E();
Chris@16 848 }
Chris@16 849
Chris@16 850 void swap(VectorStringStorage& rhs)
Chris@16 851 { base::swap(rhs); }
Chris@16 852
Chris@16 853 const E* c_str() const
Chris@16 854 { return &*begin(); }
Chris@16 855
Chris@16 856 const E* data() const
Chris@16 857 { return &*begin(); }
Chris@16 858
Chris@16 859 A get_allocator() const
Chris@16 860 { return base::get_allocator(); }
Chris@16 861 };
Chris@16 862
Chris@16 863 ////////////////////////////////////////////////////////////////////////////////
Chris@16 864 // class template SmallStringOpt
Chris@16 865 // Builds the small string optimization over any other storage
Chris@16 866 ////////////////////////////////////////////////////////////////////////////////
Chris@16 867
Chris@16 868 template <class Storage, unsigned int threshold,
Chris@16 869 typename Align = typename Storage::value_type*>
Chris@16 870 class SmallStringOpt
Chris@16 871 {
Chris@16 872 public:
Chris@16 873 typedef typename Storage::value_type value_type;
Chris@16 874 typedef value_type* iterator;
Chris@16 875 typedef const value_type* const_iterator;
Chris@16 876 typedef typename Storage::allocator_type allocator_type;
Chris@16 877 typedef typename allocator_type::size_type size_type;
Chris@16 878
Chris@16 879 private:
Chris@16 880 enum { temp1 = threshold * sizeof(value_type) > sizeof(Storage)
Chris@16 881 ? threshold * sizeof(value_type)
Chris@16 882 : sizeof(Storage) };
Chris@16 883
Chris@16 884 enum { temp2 = temp1 > sizeof(Align) ? temp1 : sizeof(Align) };
Chris@16 885
Chris@16 886 public:
Chris@16 887 enum { maxSmallString =
Chris@16 888 (temp2 + sizeof(value_type) - 1) / sizeof(value_type) };
Chris@16 889
Chris@16 890 private:
Chris@16 891 enum { magic = maxSmallString + 1 };
Chris@16 892
Chris@16 893 union
Chris@16 894 {
Chris@16 895 mutable value_type buf_[maxSmallString + 1];
Chris@16 896 Align align_;
Chris@16 897 };
Chris@16 898
Chris@16 899 Storage& GetStorage()
Chris@16 900 {
Chris@16 901 BOOST_ASSERT(buf_[maxSmallString] == magic);
Chris@16 902 Storage* p = reinterpret_cast<Storage*>(&buf_[0]);
Chris@16 903 return *p;
Chris@16 904 }
Chris@16 905
Chris@16 906 const Storage& GetStorage() const
Chris@16 907 {
Chris@16 908 BOOST_ASSERT(buf_[maxSmallString] == magic);
Chris@16 909 const Storage *p = reinterpret_cast<const Storage*>(&buf_[0]);
Chris@16 910 return *p;
Chris@16 911 }
Chris@16 912
Chris@16 913 bool Small() const
Chris@16 914 {
Chris@16 915 return buf_[maxSmallString] != magic;
Chris@16 916 }
Chris@16 917
Chris@16 918 public:
Chris@16 919 SmallStringOpt(const SmallStringOpt& s)
Chris@16 920 {
Chris@16 921 if (s.Small())
Chris@16 922 {
Chris@16 923 flex_string_details::pod_copy(
Chris@16 924 s.buf_,
Chris@16 925 s.buf_ + s.size(),
Chris@16 926 buf_);
Chris@16 927 }
Chris@16 928 else
Chris@16 929 {
Chris@16 930 new(buf_) Storage(s.GetStorage());
Chris@16 931 }
Chris@16 932 buf_[maxSmallString] = s.buf_[maxSmallString];
Chris@16 933 }
Chris@16 934
Chris@16 935 SmallStringOpt(const allocator_type&)
Chris@16 936 {
Chris@16 937 buf_[maxSmallString] = maxSmallString;
Chris@16 938 }
Chris@16 939
Chris@16 940 SmallStringOpt(const value_type* s, size_type len, const allocator_type& a)
Chris@16 941 {
Chris@16 942 if (len <= maxSmallString)
Chris@16 943 {
Chris@16 944 flex_string_details::pod_copy(s, s + len, buf_);
Chris@16 945 buf_[maxSmallString] = value_type(maxSmallString - len);
Chris@16 946 }
Chris@16 947 else
Chris@16 948 {
Chris@16 949 new(buf_) Storage(s, len, a);
Chris@16 950 buf_[maxSmallString] = magic;
Chris@16 951 }
Chris@16 952 }
Chris@16 953
Chris@16 954 SmallStringOpt(size_type len, value_type c, const allocator_type& a)
Chris@16 955 {
Chris@16 956 if (len <= maxSmallString)
Chris@16 957 {
Chris@16 958 flex_string_details::pod_fill(buf_, buf_ + len, c);
Chris@16 959 buf_[maxSmallString] = value_type(maxSmallString - len);
Chris@16 960 }
Chris@16 961 else
Chris@16 962 {
Chris@16 963 new(buf_) Storage(len, c, a);
Chris@16 964 buf_[maxSmallString] = magic;
Chris@16 965 }
Chris@16 966 }
Chris@16 967
Chris@16 968 SmallStringOpt& operator=(const SmallStringOpt& rhs)
Chris@16 969 {
Chris@16 970 reserve(rhs.size());
Chris@16 971 resize(0, 0);
Chris@16 972 append(rhs.data(), rhs.size());
Chris@16 973 return *this;
Chris@16 974 }
Chris@16 975
Chris@16 976 ~SmallStringOpt()
Chris@16 977 {
Chris@16 978 if (!Small()) GetStorage().~Storage();
Chris@16 979 }
Chris@16 980
Chris@16 981 iterator begin()
Chris@16 982 {
Chris@16 983 if (Small()) return buf_;
Chris@16 984 return &*GetStorage().begin();
Chris@16 985 }
Chris@16 986
Chris@16 987 const_iterator begin() const
Chris@16 988 {
Chris@16 989 if (Small()) return buf_;
Chris@16 990 return &*GetStorage().begin();
Chris@16 991 }
Chris@16 992
Chris@16 993 iterator end()
Chris@16 994 {
Chris@16 995 if (Small()) return buf_ + maxSmallString - buf_[maxSmallString];
Chris@16 996 return &*GetStorage().end();
Chris@16 997 }
Chris@16 998
Chris@16 999 const_iterator end() const
Chris@16 1000 {
Chris@16 1001 if (Small()) return buf_ + maxSmallString - buf_[maxSmallString];
Chris@16 1002 return &*GetStorage().end();
Chris@16 1003 }
Chris@16 1004
Chris@16 1005 size_type size() const
Chris@16 1006 {
Chris@16 1007 BOOST_ASSERT(!Small() || maxSmallString >= buf_[maxSmallString]);
Chris@16 1008 return Small()
Chris@16 1009 ? maxSmallString - buf_[maxSmallString]
Chris@16 1010 : GetStorage().size();
Chris@16 1011 }
Chris@16 1012
Chris@16 1013 size_type max_size() const
Chris@16 1014 { return get_allocator().max_size(); }
Chris@16 1015
Chris@16 1016 size_type capacity() const
Chris@16 1017 { return Small() ? maxSmallString : GetStorage().capacity(); }
Chris@16 1018
Chris@16 1019 void reserve(size_type res_arg)
Chris@16 1020 {
Chris@16 1021 if (Small())
Chris@16 1022 {
Chris@16 1023 if (res_arg <= maxSmallString) return;
Chris@16 1024 SmallStringOpt temp(*this);
Chris@16 1025 this->~SmallStringOpt();
Chris@16 1026 new(buf_) Storage(temp.data(), temp.size(),
Chris@16 1027 temp.get_allocator());
Chris@16 1028 buf_[maxSmallString] = magic;
Chris@16 1029 GetStorage().reserve(res_arg);
Chris@16 1030 }
Chris@16 1031 else
Chris@16 1032 {
Chris@16 1033 GetStorage().reserve(res_arg);
Chris@16 1034 }
Chris@16 1035 BOOST_ASSERT(capacity() >= res_arg);
Chris@16 1036 }
Chris@16 1037
Chris@16 1038 void append(const value_type* s, size_type sz)
Chris@16 1039 {
Chris@16 1040 if (!Small())
Chris@16 1041 {
Chris@16 1042 GetStorage().append(s, sz);
Chris@16 1043 }
Chris@16 1044 else
Chris@16 1045 {
Chris@16 1046 // append to a small string
Chris@16 1047 const size_type neededCapacity =
Chris@16 1048 maxSmallString - buf_[maxSmallString] + sz;
Chris@16 1049
Chris@16 1050 if (maxSmallString < neededCapacity)
Chris@16 1051 {
Chris@16 1052 // need to change storage strategy
Chris@16 1053 allocator_type alloc;
Chris@16 1054 Storage temp(alloc);
Chris@16 1055 temp.reserve(neededCapacity);
Chris@16 1056 temp.append(buf_, maxSmallString - buf_[maxSmallString]);
Chris@16 1057 temp.append(s, sz);
Chris@16 1058 buf_[maxSmallString] = magic;
Chris@16 1059 new(buf_) Storage(temp.get_allocator());
Chris@16 1060 GetStorage().swap(temp);
Chris@16 1061 }
Chris@16 1062 else
Chris@16 1063 {
Chris@16 1064 flex_string_details::pod_move(s, s + sz,
Chris@16 1065 buf_ + maxSmallString - buf_[maxSmallString]);
Chris@16 1066 buf_[maxSmallString] -= value_type(sz);
Chris@16 1067 }
Chris@16 1068 }
Chris@16 1069 }
Chris@16 1070
Chris@16 1071 template <class InputIterator>
Chris@16 1072 void append(InputIterator b, InputIterator e)
Chris@16 1073 {
Chris@16 1074 // @@@ todo: optimize this depending on iterator type
Chris@16 1075 for (; b != e; ++b)
Chris@16 1076 {
Chris@16 1077 *this += *b;
Chris@16 1078 }
Chris@16 1079 }
Chris@16 1080
Chris@16 1081 void resize(size_type n, value_type c)
Chris@16 1082 {
Chris@16 1083 if (Small())
Chris@16 1084 {
Chris@16 1085 if (n > maxSmallString)
Chris@16 1086 {
Chris@16 1087 // Small string resized to big string
Chris@16 1088 SmallStringOpt temp(*this); // can't throw
Chris@16 1089 // 11-17-2001: correct exception safety bug
Chris@16 1090 Storage newString(temp.data(), temp.size(),
Chris@16 1091 temp.get_allocator());
Chris@16 1092 newString.resize(n, c);
Chris@16 1093 // We make the reasonable assumption that an empty Storage
Chris@16 1094 // constructor won't throw
Chris@16 1095 this->~SmallStringOpt();
Chris@16 1096 new(&buf_[0]) Storage(temp.get_allocator());
Chris@16 1097 buf_[maxSmallString] = value_type(magic);
Chris@16 1098 GetStorage().swap(newString);
Chris@16 1099 }
Chris@16 1100 else
Chris@16 1101 {
Chris@16 1102 // Small string resized to small string
Chris@16 1103 // 11-17-2001: bug fix: terminating zero not copied
Chris@16 1104 size_type toFill = n > size() ? n - size() : 0;
Chris@16 1105 flex_string_details::pod_fill(end(), end() + toFill, c);
Chris@16 1106 buf_[maxSmallString] = value_type(maxSmallString - n);
Chris@16 1107 }
Chris@16 1108 }
Chris@16 1109 else
Chris@16 1110 {
Chris@16 1111 if (n > maxSmallString)
Chris@16 1112 {
Chris@16 1113 // Big string resized to big string
Chris@16 1114 GetStorage().resize(n, c);
Chris@16 1115 }
Chris@16 1116 else
Chris@16 1117 {
Chris@16 1118 // Big string resized to small string
Chris@16 1119 // 11-17=2001: bug fix in the BOOST_ASSERTion below
Chris@16 1120 BOOST_ASSERT(capacity() > n);
Chris@16 1121 SmallStringOpt newObj(data(), n, get_allocator());
Chris@16 1122 newObj.swap(*this);
Chris@16 1123 }
Chris@16 1124 }
Chris@16 1125 }
Chris@16 1126
Chris@16 1127 void swap(SmallStringOpt& rhs)
Chris@16 1128 {
Chris@16 1129 if (Small())
Chris@16 1130 {
Chris@16 1131 if (rhs.Small())
Chris@16 1132 {
Chris@16 1133 // Small swapped with small
Chris@16 1134 std::swap_ranges(buf_, buf_ + maxSmallString + 1,
Chris@16 1135 rhs.buf_);
Chris@16 1136 }
Chris@16 1137 else
Chris@16 1138 {
Chris@16 1139 // Small swapped with big
Chris@16 1140 // Make a copy of myself - can't throw
Chris@16 1141 SmallStringOpt temp(*this);
Chris@16 1142 // Nuke myself
Chris@16 1143 this->~SmallStringOpt();
Chris@16 1144 // Make an empty storage for myself (likely won't throw)
Chris@16 1145 new(buf_) Storage(0, value_type(), rhs.get_allocator());
Chris@16 1146 buf_[maxSmallString] = magic;
Chris@16 1147 // Recurse to this same function
Chris@16 1148 swap(rhs);
Chris@16 1149 // Nuke rhs
Chris@16 1150 rhs.~SmallStringOpt();
Chris@16 1151 // Build the new small string into rhs
Chris@16 1152 new(&rhs) SmallStringOpt(temp);
Chris@16 1153 }
Chris@16 1154 }
Chris@16 1155 else
Chris@16 1156 {
Chris@16 1157 if (rhs.Small())
Chris@16 1158 {
Chris@16 1159 // Big swapped with small
Chris@16 1160 // Already implemented, recurse with reversed args
Chris@16 1161 rhs.swap(*this);
Chris@16 1162 }
Chris@16 1163 else
Chris@16 1164 {
Chris@16 1165 // Big swapped with big
Chris@16 1166 GetStorage().swap(rhs.GetStorage());
Chris@16 1167 }
Chris@16 1168 }
Chris@16 1169 }
Chris@16 1170
Chris@16 1171 const value_type* c_str() const
Chris@16 1172 {
Chris@16 1173 if (!Small()) return GetStorage().c_str();
Chris@16 1174 buf_[maxSmallString - buf_[maxSmallString]] = value_type();
Chris@16 1175 return buf_;
Chris@16 1176 }
Chris@16 1177
Chris@16 1178 const value_type* data() const
Chris@16 1179 { return Small() ? buf_ : GetStorage().data(); }
Chris@16 1180
Chris@16 1181 allocator_type get_allocator() const
Chris@16 1182 { return allocator_type(); }
Chris@16 1183 };
Chris@16 1184
Chris@16 1185 ////////////////////////////////////////////////////////////////////////////////
Chris@16 1186 // class template CowString
Chris@16 1187 // Implements Copy on Write over any storage
Chris@16 1188 ////////////////////////////////////////////////////////////////////////////////
Chris@16 1189
Chris@16 1190 template <
Chris@16 1191 typename Storage,
Chris@16 1192 typename Align = BOOST_DEDUCED_TYPENAME Storage::value_type*
Chris@16 1193 >
Chris@16 1194 class CowString
Chris@16 1195 {
Chris@16 1196 typedef typename Storage::value_type E;
Chris@16 1197 typedef typename flex_string_details::get_unsigned<E>::result RefCountType;
Chris@16 1198
Chris@16 1199 public:
Chris@16 1200 typedef E value_type;
Chris@16 1201 typedef typename Storage::iterator iterator;
Chris@16 1202 typedef typename Storage::const_iterator const_iterator;
Chris@16 1203 typedef typename Storage::allocator_type allocator_type;
Chris@16 1204 typedef typename allocator_type::size_type size_type;
Chris@16 1205 typedef typename Storage::reference reference;
Chris@16 1206
Chris@16 1207 private:
Chris@16 1208 union
Chris@16 1209 {
Chris@16 1210 mutable char buf_[sizeof(Storage)];
Chris@16 1211 Align align_;
Chris@16 1212 };
Chris@16 1213
Chris@16 1214 Storage& Data() const
Chris@16 1215 {
Chris@16 1216 Storage* p = reinterpret_cast<Storage*>(&buf_[0]);
Chris@16 1217 return *p;
Chris@16 1218 }
Chris@16 1219
Chris@16 1220 RefCountType GetRefs() const
Chris@16 1221 {
Chris@16 1222 const Storage& d = Data();
Chris@16 1223 BOOST_ASSERT(d.size() > 0);
Chris@16 1224 BOOST_ASSERT(static_cast<RefCountType>(*d.begin()) != 0);
Chris@16 1225 return *d.begin();
Chris@16 1226 }
Chris@16 1227
Chris@16 1228 RefCountType& Refs()
Chris@16 1229 {
Chris@16 1230 Storage& d = Data();
Chris@16 1231 BOOST_ASSERT(d.size() > 0);
Chris@16 1232 return reinterpret_cast<RefCountType&>(*d.begin());
Chris@16 1233 }
Chris@16 1234
Chris@16 1235 void MakeUnique() const
Chris@16 1236 {
Chris@16 1237 BOOST_ASSERT(GetRefs() >= 1);
Chris@16 1238 if (GetRefs() == 1) return;
Chris@16 1239
Chris@16 1240 union
Chris@16 1241 {
Chris@16 1242 char buf_[sizeof(Storage)];
Chris@16 1243 Align align_;
Chris@16 1244 } temp;
Chris@16 1245
Chris@16 1246 --(*Data().begin()); // decrement the use count of the remaining object
Chris@16 1247
Chris@16 1248 Storage* p = reinterpret_cast<Storage*>(&temp.buf_[0]);
Chris@16 1249 new(buf_) Storage(
Chris@16 1250 *new(p) Storage(Data()),
Chris@16 1251 flex_string_details::Shallow());
Chris@16 1252 *Data().begin() = 1;
Chris@16 1253 }
Chris@16 1254
Chris@16 1255 public:
Chris@16 1256 CowString(const CowString& s)
Chris@16 1257 {
Chris@16 1258 if (s.GetRefs() == (std::numeric_limits<RefCountType>::max)())
Chris@16 1259 {
Chris@16 1260 // must make a brand new copy
Chris@16 1261 new(buf_) Storage(s.Data()); // non shallow
Chris@16 1262 Refs() = 1;
Chris@16 1263 }
Chris@16 1264 else
Chris@16 1265 {
Chris@16 1266 new(buf_) Storage(s.Data(), flex_string_details::Shallow());
Chris@16 1267 ++Refs();
Chris@16 1268 }
Chris@16 1269 BOOST_ASSERT(Data().size() > 0);
Chris@16 1270 }
Chris@16 1271
Chris@16 1272 CowString(const allocator_type& a)
Chris@16 1273 {
Chris@16 1274 new(buf_) Storage(1, 1, a);
Chris@16 1275 }
Chris@16 1276
Chris@16 1277 CowString(const E* s, size_type len, const allocator_type& a)
Chris@16 1278 {
Chris@16 1279 // Warning - MSVC's debugger has trouble tracing through the code below.
Chris@16 1280 // It seems to be a const-correctness issue
Chris@16 1281 //
Chris@16 1282 new(buf_) Storage(a);
Chris@16 1283 Data().reserve(len + 1);
Chris@16 1284 Data().resize(1, 1);
Chris@16 1285 Data().append(s, s + len);
Chris@16 1286 }
Chris@16 1287
Chris@16 1288 CowString(size_type len, E c, const allocator_type& a)
Chris@16 1289 {
Chris@16 1290 new(buf_) Storage(len + 1, c, a);
Chris@16 1291 Refs() = 1;
Chris@16 1292 }
Chris@16 1293
Chris@16 1294 CowString& operator=(const CowString& rhs)
Chris@16 1295 {
Chris@16 1296 // CowString(rhs).swap(*this);
Chris@16 1297 if (--Refs() == 0)
Chris@16 1298 Data().~Storage();
Chris@16 1299 if (rhs.GetRefs() == (std::numeric_limits<RefCountType>::max)())
Chris@16 1300 {
Chris@16 1301 // must make a brand new copy
Chris@16 1302 new(buf_) Storage(rhs.Data()); // non shallow
Chris@16 1303 Refs() = 1;
Chris@16 1304 }
Chris@16 1305 else
Chris@16 1306 {
Chris@16 1307 new(buf_) Storage(rhs.Data(), flex_string_details::Shallow());
Chris@16 1308 ++Refs();
Chris@16 1309 }
Chris@16 1310 BOOST_ASSERT(Data().size() > 0);
Chris@16 1311 return *this;
Chris@16 1312 }
Chris@16 1313
Chris@16 1314 ~CowString()
Chris@16 1315 {
Chris@16 1316 BOOST_ASSERT(Data().size() > 0);
Chris@16 1317 if (--Refs() == 0)
Chris@16 1318 Data().~Storage();
Chris@16 1319 }
Chris@16 1320
Chris@16 1321 iterator begin()
Chris@16 1322 {
Chris@16 1323 BOOST_ASSERT(Data().size() > 0);
Chris@16 1324 MakeUnique();
Chris@16 1325 return Data().begin() + 1;
Chris@16 1326 }
Chris@16 1327
Chris@16 1328 const_iterator begin() const
Chris@16 1329 {
Chris@16 1330 BOOST_ASSERT(Data().size() > 0);
Chris@16 1331 return Data().begin() + 1;
Chris@16 1332 }
Chris@16 1333
Chris@16 1334 iterator end()
Chris@16 1335 {
Chris@16 1336 MakeUnique();
Chris@16 1337 return Data().end();
Chris@16 1338 }
Chris@16 1339
Chris@16 1340 const_iterator end() const
Chris@16 1341 {
Chris@16 1342 return Data().end();
Chris@16 1343 }
Chris@16 1344
Chris@16 1345 size_type size() const
Chris@16 1346 {
Chris@16 1347 BOOST_ASSERT(Data().size() > 0);
Chris@16 1348 return Data().size() - 1;
Chris@16 1349 }
Chris@16 1350
Chris@16 1351 size_type max_size() const
Chris@16 1352 {
Chris@16 1353 BOOST_ASSERT(Data().max_size() > 0);
Chris@16 1354 return Data().max_size() - 1;
Chris@16 1355 }
Chris@16 1356
Chris@16 1357 size_type capacity() const
Chris@16 1358 {
Chris@16 1359 BOOST_ASSERT(Data().capacity() > 0);
Chris@16 1360 return Data().capacity() - 1;
Chris@16 1361 }
Chris@16 1362
Chris@16 1363 void resize(size_type n, E c)
Chris@16 1364 {
Chris@16 1365 BOOST_ASSERT(Data().size() > 0);
Chris@16 1366 MakeUnique();
Chris@16 1367 Data().resize(n + 1, c);
Chris@16 1368 }
Chris@16 1369
Chris@16 1370 template <class FwdIterator>
Chris@16 1371 void append(FwdIterator b, FwdIterator e)
Chris@16 1372 {
Chris@16 1373 MakeUnique();
Chris@16 1374 Data().append(b, e);
Chris@16 1375 }
Chris@16 1376
Chris@16 1377 void reserve(size_type res_arg)
Chris@16 1378 {
Chris@16 1379 if (capacity() > res_arg) return;
Chris@16 1380 MakeUnique();
Chris@16 1381 Data().reserve(res_arg + 1);
Chris@16 1382 }
Chris@16 1383
Chris@16 1384 void swap(CowString& rhs)
Chris@16 1385 {
Chris@16 1386 Data().swap(rhs.Data());
Chris@16 1387 }
Chris@16 1388
Chris@16 1389 const E* c_str() const
Chris@16 1390 {
Chris@16 1391 BOOST_ASSERT(Data().size() > 0);
Chris@16 1392 return Data().c_str() + 1;
Chris@16 1393 }
Chris@16 1394
Chris@16 1395 const E* data() const
Chris@16 1396 {
Chris@16 1397 BOOST_ASSERT(Data().size() > 0);
Chris@16 1398 return Data().data() + 1;
Chris@16 1399 }
Chris@16 1400
Chris@16 1401 allocator_type get_allocator() const
Chris@16 1402 {
Chris@16 1403 return Data().get_allocator();
Chris@16 1404 }
Chris@16 1405 };
Chris@16 1406
Chris@16 1407 ////////////////////////////////////////////////////////////////////////////////
Chris@16 1408 // class template flex_string
Chris@16 1409 // a std::basic_string compatible implementation
Chris@16 1410 // Uses a Storage policy
Chris@16 1411 ////////////////////////////////////////////////////////////////////////////////
Chris@16 1412
Chris@16 1413 template <typename E,
Chris@16 1414 class T = std::char_traits<E>,
Chris@16 1415 class A = std::allocator<E>,
Chris@16 1416 class Storage = AllocatorStringStorage<E, A> >
Chris@16 1417 class flex_string : private Storage
Chris@16 1418 {
Chris@16 1419 #if defined(BOOST_WAVE_FLEXSTRING_THROW_ON_ENFORCE)
Chris@16 1420 template <typename Exception>
Chris@16 1421 static void Enforce(bool condition, Exception*, const char* msg)
Chris@16 1422 { if (!condition) boost::throw_exception(Exception(msg)); }
Chris@16 1423 #else
Chris@16 1424 template <typename Exception>
Chris@16 1425 static inline void Enforce(bool condition, Exception*, const char* msg)
Chris@16 1426 { BOOST_ASSERT(condition && msg); }
Chris@16 1427 #endif // defined(BOOST_WAVE_FLEXSTRING_THROW_ON_ENFORCE)
Chris@16 1428
Chris@16 1429 #ifndef NDEBUG
Chris@16 1430 bool Sane() const
Chris@16 1431 {
Chris@16 1432 return
Chris@16 1433 begin() <= end() &&
Chris@16 1434 empty() == (size() == 0) &&
Chris@16 1435 empty() == (begin() == end()) &&
Chris@16 1436 size() <= max_size() &&
Chris@16 1437 capacity() <= max_size() &&
Chris@16 1438 size() <= capacity();
Chris@16 1439 }
Chris@16 1440
Chris@16 1441 struct Invariant;
Chris@16 1442 friend struct Invariant;
Chris@16 1443 struct Invariant
Chris@16 1444 {
Chris@16 1445 Invariant(const flex_string& s) : s_(s)
Chris@16 1446 {
Chris@16 1447 BOOST_ASSERT(s_.Sane());
Chris@16 1448 }
Chris@16 1449 ~Invariant()
Chris@16 1450 {
Chris@16 1451 BOOST_ASSERT(s_.Sane());
Chris@16 1452 }
Chris@16 1453 private:
Chris@16 1454 const flex_string& s_;
Chris@16 1455 Invariant& operator=(const Invariant&);
Chris@16 1456 };
Chris@16 1457 #endif
Chris@16 1458
Chris@16 1459 public:
Chris@16 1460 // types
Chris@16 1461 typedef T traits_type;
Chris@16 1462 typedef typename traits_type::char_type value_type;
Chris@16 1463 typedef A allocator_type;
Chris@16 1464 typedef typename A::size_type size_type;
Chris@16 1465 typedef typename A::difference_type difference_type;
Chris@16 1466
Chris@16 1467 typedef typename A::reference reference;
Chris@16 1468 typedef typename A::const_reference const_reference;
Chris@16 1469 typedef typename A::pointer pointer;
Chris@16 1470 typedef typename A::const_pointer const_pointer;
Chris@16 1471
Chris@16 1472 typedef typename Storage::iterator iterator;
Chris@16 1473 typedef typename Storage::const_iterator const_iterator;
Chris@16 1474
Chris@16 1475 typedef boost::reverse_iterator<iterator> reverse_iterator;
Chris@16 1476 typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
Chris@16 1477
Chris@16 1478 static const size_type npos; // = size_type(-1)
Chris@16 1479
Chris@16 1480 private:
Chris@16 1481 static size_type Min(size_type lhs, size_type rhs)
Chris@16 1482 { return lhs < rhs ? lhs : rhs; }
Chris@16 1483 static void Procust(size_type& n, size_type nmax)
Chris@16 1484 { if (n > nmax) n = nmax; }
Chris@16 1485
Chris@16 1486 public:
Chris@16 1487 // 21.3.1 construct/copy/destroy
Chris@16 1488 explicit flex_string(const A& a = A())
Chris@16 1489 : Storage(a)
Chris@16 1490 {}
Chris@16 1491
Chris@16 1492 flex_string(const flex_string& str)
Chris@16 1493 : Storage(str)
Chris@16 1494 {
Chris@16 1495 }
Chris@16 1496
Chris@16 1497 flex_string(const flex_string& str, size_type pos,
Chris@16 1498 size_type n = npos, const A& a = A())
Chris@16 1499 : Storage(a)
Chris@16 1500 {
Chris@16 1501 Enforce(pos <= str.size(), (std::out_of_range*)0, "");
Chris@16 1502 assign(str, pos, n);
Chris@16 1503 }
Chris@16 1504
Chris@16 1505 flex_string(const value_type* s, const A& a = A())
Chris@16 1506 : Storage(s, traits_type::length(s), a)
Chris@16 1507 {}
Chris@16 1508
Chris@16 1509 flex_string(const value_type* s, size_type n, const A& a = A())
Chris@16 1510 : Storage(s, n, a)
Chris@16 1511 {}
Chris@16 1512
Chris@16 1513 flex_string(size_type n, value_type c, const A& a = A())
Chris@16 1514 : Storage(n, c, a)
Chris@16 1515 {}
Chris@16 1516
Chris@16 1517 template <class InputIterator>
Chris@16 1518 flex_string(InputIterator begin, InputIterator end, const A& a = A())
Chris@16 1519 : Storage(a)
Chris@16 1520 {
Chris@16 1521 assign(begin, end);
Chris@16 1522 }
Chris@16 1523
Chris@16 1524 ~flex_string()
Chris@16 1525 {}
Chris@16 1526
Chris@16 1527 flex_string& operator=(const flex_string& str)
Chris@16 1528 {
Chris@16 1529 if (this != &str) {
Chris@16 1530 Storage& s = *this;
Chris@16 1531 s = str;
Chris@16 1532 }
Chris@16 1533 return *this;
Chris@16 1534 }
Chris@16 1535
Chris@16 1536 flex_string& operator=(const value_type* s)
Chris@16 1537 {
Chris@16 1538 assign(s);
Chris@16 1539 return *this;
Chris@16 1540 }
Chris@16 1541
Chris@16 1542 flex_string& operator=(value_type c)
Chris@16 1543 {
Chris@16 1544 assign(1, c);
Chris@16 1545 return *this;
Chris@16 1546 }
Chris@16 1547
Chris@16 1548 // 21.3.2 iterators:
Chris@16 1549 iterator begin()
Chris@16 1550 { return Storage::begin(); }
Chris@16 1551
Chris@16 1552 const_iterator begin() const
Chris@16 1553 { return Storage::begin(); }
Chris@16 1554
Chris@16 1555 iterator end()
Chris@16 1556 { return Storage::end(); }
Chris@16 1557
Chris@16 1558 const_iterator end() const
Chris@16 1559 { return Storage::end(); }
Chris@16 1560
Chris@16 1561 reverse_iterator rbegin()
Chris@16 1562 { return reverse_iterator(end()); }
Chris@16 1563
Chris@16 1564 const_reverse_iterator rbegin() const
Chris@16 1565 { return const_reverse_iterator(end()); }
Chris@16 1566
Chris@16 1567 reverse_iterator rend()
Chris@16 1568 { return reverse_iterator(begin()); }
Chris@16 1569
Chris@16 1570 const_reverse_iterator rend() const
Chris@16 1571 { return const_reverse_iterator(begin()); }
Chris@16 1572
Chris@16 1573 #if BOOST_WAVE_FLEX_STRING_SERIALIZATION_HACK != 0
Chris@16 1574 // temporary hack to make it easier to serialize flex_string's using
Chris@16 1575 // the Boost.Serialization library
Chris@16 1576 value_type & back() { return *(begin()+size()-1); }
Chris@16 1577 value_type const& back() const { return *(begin()+size()-1); }
Chris@16 1578 #endif
Chris@16 1579
Chris@16 1580 // 21.3.3 capacity:
Chris@16 1581 size_type size() const
Chris@16 1582 { return Storage::size(); }
Chris@16 1583
Chris@16 1584 size_type length() const
Chris@16 1585 { return size(); }
Chris@16 1586
Chris@16 1587 size_type max_size() const
Chris@16 1588 { return Storage::max_size(); }
Chris@16 1589
Chris@16 1590 void resize(size_type n, value_type c)
Chris@16 1591 { Storage::resize(n, c); }
Chris@16 1592
Chris@16 1593 void resize(size_type n)
Chris@16 1594 { resize(n, value_type()); }
Chris@16 1595
Chris@16 1596 size_type capacity() const
Chris@16 1597 { return Storage::capacity(); }
Chris@16 1598
Chris@16 1599 void reserve(size_type res_arg = 0)
Chris@16 1600 {
Chris@16 1601 Enforce(res_arg <= max_size(), (std::length_error*)0, "");
Chris@16 1602 Storage::reserve(res_arg);
Chris@16 1603 }
Chris@16 1604
Chris@16 1605 void clear()
Chris@16 1606 { resize(0); }
Chris@16 1607
Chris@16 1608 bool empty() const
Chris@16 1609 { return size() == 0; }
Chris@16 1610
Chris@16 1611 // 21.3.4 element access:
Chris@16 1612 const_reference operator[](size_type pos) const
Chris@16 1613 { return *(begin() + pos); }
Chris@16 1614
Chris@16 1615 reference operator[](size_type pos)
Chris@16 1616 { return *(begin() + pos); }
Chris@16 1617
Chris@16 1618 const_reference at(size_type n) const
Chris@16 1619 {
Chris@16 1620 Enforce(n < size(), (std::out_of_range*)0, "");
Chris@16 1621 return (*this)[n];
Chris@16 1622 }
Chris@16 1623
Chris@16 1624 reference at(size_type n)
Chris@16 1625 {
Chris@16 1626 Enforce(n < size(), (std::out_of_range*)0, "");
Chris@16 1627 return (*this)[n];
Chris@16 1628 }
Chris@16 1629
Chris@16 1630 // 21.3.5 modifiers:
Chris@16 1631 flex_string& operator+=(const flex_string& str)
Chris@16 1632 { return append(str); }
Chris@16 1633
Chris@16 1634 flex_string& operator+=(const value_type* s)
Chris@16 1635 { return append(s); }
Chris@16 1636
Chris@16 1637 flex_string& operator+=(value_type c)
Chris@16 1638 {
Chris@16 1639 push_back(c);
Chris@16 1640 return *this;
Chris@16 1641 }
Chris@16 1642
Chris@16 1643 flex_string& append(const flex_string& str)
Chris@16 1644 { return append(str, 0, npos); }
Chris@16 1645
Chris@16 1646 flex_string& append(const flex_string& str, const size_type pos,
Chris@16 1647 size_type n)
Chris@16 1648 {
Chris@16 1649 const size_type sz = str.size();
Chris@16 1650 Enforce(pos <= sz, (std::out_of_range*)0, "");
Chris@16 1651 Procust(n, sz - pos);
Chris@16 1652 return append(str.c_str() + pos, n);
Chris@16 1653 }
Chris@16 1654
Chris@16 1655 flex_string& append(const value_type* s, const size_type n)
Chris@16 1656 {
Chris@16 1657 #ifndef NDEBUG
Chris@16 1658 Invariant checker(*this);
Chris@16 1659 #endif
Chris@16 1660 if (IsAliasedRange(s, s + n))
Chris@16 1661 {
Chris@16 1662 const size_type offset = s - &*begin();
Chris@16 1663 Storage::reserve(size() + n);
Chris@16 1664 s = &*begin() + offset;
Chris@16 1665 }
Chris@16 1666 Storage::append(s, s+ n);
Chris@16 1667 return *this;
Chris@16 1668 }
Chris@16 1669
Chris@16 1670 flex_string& append(const value_type* s)
Chris@16 1671 { return append(s, traits_type::length(s)); }
Chris@16 1672
Chris@16 1673 flex_string& append(size_type n, value_type c)
Chris@16 1674 {
Chris@16 1675 resize(size() + n, c);
Chris@16 1676 return *this;
Chris@16 1677 }
Chris@16 1678
Chris@16 1679 template<class InputIterator>
Chris@16 1680 flex_string& append(InputIterator first, InputIterator last)
Chris@16 1681 {
Chris@16 1682 insert(end(), first, last);
Chris@16 1683 return *this;
Chris@16 1684 }
Chris@16 1685
Chris@16 1686 void push_back(value_type c)
Chris@16 1687 {
Chris@16 1688 const size_type cap = capacity();
Chris@16 1689 if (size() == cap)
Chris@16 1690 {
Chris@16 1691 reserve(cap << 1u);
Chris@16 1692 }
Chris@16 1693 Storage::append(&c, &c + 1);
Chris@16 1694 }
Chris@16 1695
Chris@16 1696 flex_string& assign(const flex_string& str)
Chris@16 1697 {
Chris@16 1698 if (&str == this) return *this;
Chris@16 1699 return assign(str.data(), str.size());
Chris@16 1700 }
Chris@16 1701
Chris@16 1702 flex_string& assign(const flex_string& str, size_type pos,
Chris@16 1703 size_type n)
Chris@16 1704 {
Chris@16 1705 const size_type sz = str.size();
Chris@16 1706 Enforce(pos <= str.size(), (std::out_of_range*)0, "");
Chris@16 1707 Procust(n, sz - pos);
Chris@16 1708 return assign(str.data() + pos, n);
Chris@16 1709 }
Chris@16 1710
Chris@16 1711 flex_string& assign(const value_type* s, size_type n)
Chris@16 1712 {
Chris@16 1713 #ifndef NDEBUG
Chris@16 1714 Invariant checker(*this);
Chris@16 1715 #endif
Chris@16 1716 if (size() >= n)
Chris@16 1717 {
Chris@16 1718 std::copy(s, s + n, begin());
Chris@16 1719 resize(n);
Chris@16 1720 }
Chris@16 1721 else
Chris@16 1722 {
Chris@16 1723 const value_type *const s2 = s + size();
Chris@16 1724 std::copy(s, s2, begin());
Chris@16 1725 append(s2, n - size());
Chris@16 1726 }
Chris@16 1727 return *this;
Chris@16 1728 }
Chris@16 1729
Chris@16 1730 flex_string& assign(const value_type* s)
Chris@16 1731 { return assign(s, traits_type::length(s)); }
Chris@16 1732
Chris@16 1733 template <class ItOrLength, class ItOrChar>
Chris@16 1734 flex_string& assign(ItOrLength first_or_n, ItOrChar last_or_c)
Chris@16 1735 { return replace(begin(), end(), first_or_n, last_or_c); }
Chris@16 1736
Chris@16 1737 flex_string& insert(size_type pos1, const flex_string& str)
Chris@16 1738 { return insert(pos1, str.data(), str.size()); }
Chris@16 1739
Chris@16 1740 flex_string& insert(size_type pos1, const flex_string& str,
Chris@16 1741 size_type pos2, size_type n)
Chris@16 1742 {
Chris@16 1743 Enforce(pos2 <= str.length(), (std::out_of_range*)0, "");
Chris@16 1744 Procust(n, str.length() - pos2);
Chris@16 1745 return insert(pos1, str.data() + pos2, n);
Chris@16 1746 }
Chris@16 1747
Chris@16 1748 flex_string& insert(size_type pos, const value_type* s, size_type n)
Chris@16 1749 {
Chris@16 1750 Enforce(pos <= length(), (std::out_of_range*)0, "");
Chris@16 1751 insert(begin() + pos, s, s + n);
Chris@16 1752 return *this;
Chris@16 1753 }
Chris@16 1754
Chris@16 1755 flex_string& insert(size_type pos, const value_type* s)
Chris@16 1756 { return insert(pos, s, traits_type::length(s)); }
Chris@16 1757
Chris@16 1758 flex_string& insert(size_type pos, size_type n, value_type c)
Chris@16 1759 {
Chris@16 1760 Enforce(pos <= length(), (std::out_of_range*)0, "");
Chris@16 1761 insert(begin() + pos, n, c);
Chris@16 1762 return *this;
Chris@16 1763 }
Chris@16 1764
Chris@16 1765 iterator insert(iterator p, value_type c = value_type())
Chris@16 1766 {
Chris@16 1767 const size_type pos = p - begin();
Chris@16 1768 insert(pos, &c, 1);
Chris@16 1769 return begin() + pos;
Chris@16 1770 }
Chris@16 1771
Chris@16 1772 private:
Chris@16 1773 // Care must be taken when dereferencing some iterator types.
Chris@16 1774 //
Chris@16 1775 // Users can implement this function in their namespace if their storage
Chris@16 1776 // uses a special iterator type, the function will be found through ADL.
Chris@16 1777 template<class Iterator>
Chris@16 1778 const typename std::iterator_traits<Iterator>::value_type*
Chris@16 1779 DereferenceValidIterator(Iterator it) const
Chris@16 1780 {
Chris@16 1781 return &*it;
Chris@16 1782 }
Chris@16 1783
Chris@16 1784 // Care must be taken when dereferencing a reverse iterators, hence this
Chris@16 1785 // special case. This isn't in the std namespace so as not to pollute it or
Chris@16 1786 // create name clashes.
Chris@16 1787 template<typename Iterator>
Chris@16 1788 const typename std::iterator_traits<Iterator>::value_type*
Chris@16 1789 DereferenceValidIterator(std::reverse_iterator<Iterator> it) const
Chris@16 1790 {
Chris@16 1791 return &*--it;
Chris@16 1792 }
Chris@16 1793
Chris@16 1794 // Determine if the range aliases the current string.
Chris@16 1795 //
Chris@16 1796 // This method cannot be const because calling begin/end on copy-on-write
Chris@16 1797 // implementations must have side effects.
Chris@16 1798 // A const version wouldn't make the string unique through this call.
Chris@16 1799 template<class Iterator>
Chris@16 1800 bool IsAliasedRange(Iterator beginIterator, Iterator endIterator)
Chris@16 1801 {
Chris@16 1802 if(!empty() && beginIterator != endIterator)
Chris@16 1803 {
Chris@16 1804 typedef const typename std::iterator_traits<Iterator>::value_type *
Chris@16 1805 pointer;
Chris@16 1806
Chris@16 1807 pointer myBegin(&*begin());
Chris@16 1808 pointer myEnd(&*begin() + size());
Chris@16 1809 pointer rangeBegin(DereferenceValidIterator(beginIterator));
Chris@16 1810
Chris@16 1811 const std::less_equal<pointer> less_equal = std::less_equal<pointer>();
Chris@16 1812 if(less_equal(myBegin, rangeBegin) && less_equal(rangeBegin, myEnd))
Chris@16 1813 return true;
Chris@16 1814 }
Chris@16 1815 return false;
Chris@16 1816 }
Chris@16 1817
Chris@16 1818 template <int i> class Selector {};
Chris@16 1819
Chris@16 1820 flex_string& InsertImplDiscr(iterator p,
Chris@16 1821 size_type n, value_type c, Selector<1>)
Chris@16 1822 {
Chris@16 1823 #ifndef NDEBUG
Chris@16 1824 Invariant checker(*this);
Chris@16 1825 #endif
Chris@16 1826 BOOST_ASSERT(begin() <= p && p <= end());
Chris@16 1827 const size_type insertOffset(p - begin());
Chris@16 1828 const size_type originalSize(size());
Chris@16 1829 if(n < originalSize - insertOffset)
Chris@16 1830 {
Chris@16 1831 // The new characters fit within the original string.
Chris@16 1832 // The characters that are pushed back need to be moved because
Chris@16 1833 // they're aliased.
Chris@16 1834 // The appended characters will all be overwritten by the move.
Chris@16 1835 append(n, value_type(0));
Chris@16 1836 value_type* begin(&*begin());
Chris@16 1837 flex_string_details::pod_move(begin + insertOffset,
Chris@16 1838 begin + originalSize, begin + insertOffset + n);
Chris@16 1839 std::fill(begin + insertOffset, begin + insertOffset + n, c);
Chris@16 1840 }
Chris@16 1841 else
Chris@16 1842 {
Chris@16 1843 // The new characters exceed the original string.
Chris@16 1844 // The characters that are pushed back can simply be copied since
Chris@16 1845 // they aren't aliased.
Chris@16 1846 // The appended characters will partly be overwritten by the copy.
Chris@16 1847 append(n, c);
Chris@16 1848 value_type* begin(&*begin());
Chris@16 1849 flex_string_details::pod_copy(begin + insertOffset,
Chris@16 1850 begin + originalSize, begin + insertOffset + n);
Chris@16 1851 std::fill(begin + insertOffset, begin + originalSize, c);
Chris@16 1852 }
Chris@16 1853 return *this;
Chris@16 1854 }
Chris@16 1855
Chris@16 1856 template<class InputIterator>
Chris@16 1857 flex_string& InsertImplDiscr(iterator i,
Chris@16 1858 InputIterator b, InputIterator e, Selector<0>)
Chris@16 1859 {
Chris@16 1860 InsertImpl(i, b, e,
Chris@16 1861 typename std::iterator_traits<InputIterator>::iterator_category());
Chris@16 1862 return *this;
Chris@16 1863 }
Chris@16 1864
Chris@16 1865 template <class FwdIterator>
Chris@16 1866 void InsertImpl(iterator i,
Chris@16 1867 FwdIterator s1, FwdIterator s2, std::forward_iterator_tag)
Chris@16 1868 {
Chris@16 1869 if(s1 == s2)
Chris@16 1870 {
Chris@16 1871 // Insert an empty range.
Chris@16 1872 return;
Chris@16 1873 }
Chris@16 1874
Chris@16 1875 if(IsAliasedRange(s1, s2))
Chris@16 1876 {
Chris@16 1877 // The source range is contained in the current string, copy it
Chris@16 1878 // and recurse.
Chris@16 1879 const flex_string temporary(s1, s2);
Chris@16 1880 InsertImpl(i, temporary.begin(), temporary.end(),
Chris@16 1881 typename std::iterator_traits<FwdIterator>::iterator_category());
Chris@16 1882 return;
Chris@16 1883 }
Chris@16 1884
Chris@16 1885 #ifndef NDEBUG
Chris@16 1886 Invariant checker(*this);
Chris@16 1887 #endif
Chris@16 1888 const size_type pos = i - begin();
Chris@16 1889 const typename std::iterator_traits<FwdIterator>::difference_type n2 =
Chris@16 1890 std::distance(s1, s2);
Chris@16 1891
Chris@16 1892 BOOST_ASSERT(n2 >= 0);
Chris@16 1893 using namespace flex_string_details;
Chris@16 1894 BOOST_ASSERT(pos <= size());
Chris@16 1895
Chris@16 1896 const typename std::iterator_traits<FwdIterator>::difference_type maxn2 =
Chris@16 1897 capacity() - size();
Chris@16 1898 if (maxn2 < n2)
Chris@16 1899 {
Chris@16 1900 // Reallocate the string.
Chris@16 1901 BOOST_ASSERT(!IsAliasedRange(s1, s2));
Chris@16 1902 reserve(size() + n2);
Chris@16 1903 i = begin() + pos;
Chris@16 1904 }
Chris@16 1905 if (pos + n2 <= size())
Chris@16 1906 {
Chris@16 1907 const iterator tailBegin = end() - n2;
Chris@16 1908 Storage::append(tailBegin, tailBegin + n2);
Chris@16 1909 std::copy(reverse_iterator(tailBegin), reverse_iterator(i),
Chris@16 1910 reverse_iterator(tailBegin + n2));
Chris@16 1911 std::copy(s1, s2, i);
Chris@16 1912 }
Chris@16 1913 else
Chris@16 1914 {
Chris@16 1915 FwdIterator t = s1;
Chris@16 1916 const size_type old_size = size();
Chris@16 1917 std::advance(t, old_size - pos);
Chris@16 1918 BOOST_ASSERT(std::distance(t, s2) >= 0);
Chris@16 1919 Storage::append(t, s2);
Chris@16 1920 Storage::append(data() + pos, data() + old_size);
Chris@16 1921 std::copy(s1, t, i);
Chris@16 1922 }
Chris@16 1923 }
Chris@16 1924
Chris@16 1925 template <class InputIterator>
Chris@16 1926 void InsertImpl(iterator insertPosition,
Chris@16 1927 InputIterator inputBegin, InputIterator inputEnd,
Chris@16 1928 std::input_iterator_tag)
Chris@16 1929 {
Chris@16 1930 flex_string temporary(begin(), insertPosition);
Chris@16 1931 for (; inputBegin != inputEnd; ++inputBegin)
Chris@16 1932 {
Chris@16 1933 temporary.push_back(*inputBegin);
Chris@16 1934 }
Chris@16 1935 temporary.append(insertPosition, end());
Chris@16 1936 swap(temporary);
Chris@16 1937 }
Chris@16 1938
Chris@16 1939 public:
Chris@16 1940 template <class ItOrLength, class ItOrChar>
Chris@16 1941 void insert(iterator p, ItOrLength first_or_n, ItOrChar last_or_c)
Chris@16 1942 {
Chris@16 1943 Selector<std::numeric_limits<ItOrLength>::is_specialized> sel;
Chris@16 1944 InsertImplDiscr(p, first_or_n, last_or_c, sel);
Chris@16 1945 }
Chris@16 1946
Chris@16 1947 flex_string& erase(size_type pos = 0, size_type n = npos)
Chris@16 1948 {
Chris@16 1949 #ifndef NDEBUG
Chris@16 1950 Invariant checker(*this);
Chris@16 1951 #endif
Chris@16 1952 Enforce(pos <= length(), (std::out_of_range*)0, "");
Chris@16 1953 Procust(n, length() - pos);
Chris@16 1954 std::copy(begin() + pos + n, end(), begin() + pos);
Chris@16 1955 resize(length() - n);
Chris@16 1956 return *this;
Chris@16 1957 }
Chris@16 1958
Chris@16 1959 iterator erase(iterator position)
Chris@16 1960 {
Chris@16 1961 const size_type pos(position - begin());
Chris@16 1962 erase(pos, 1);
Chris@16 1963 return begin() + pos;
Chris@16 1964 }
Chris@16 1965
Chris@16 1966 iterator erase(iterator first, iterator last)
Chris@16 1967 {
Chris@16 1968 const size_type pos(first - begin());
Chris@16 1969 erase(pos, last - first);
Chris@16 1970 return begin() + pos;
Chris@16 1971 }
Chris@16 1972
Chris@16 1973 // Replaces at most n1 chars of *this, starting with pos1 with the content of str
Chris@16 1974 flex_string& replace(size_type pos1, size_type n1, const flex_string& str)
Chris@16 1975 { return replace(pos1, n1, str, 0, npos); }
Chris@16 1976
Chris@16 1977 // Replaces at most n1 chars of *this, starting with pos1,
Chris@16 1978 // with at most n2 chars of str starting with pos2
Chris@16 1979 flex_string& replace(size_type pos1, size_type n1, const flex_string& str,
Chris@16 1980 size_type pos2, size_type n2)
Chris@16 1981 {
Chris@16 1982 Enforce(pos2 <= str.length(), (std::out_of_range*)0, "");
Chris@16 1983 return replace(pos1, n1, str.data() + pos2,
Chris@16 1984 Min(n2, str.size() - pos2));
Chris@16 1985 }
Chris@16 1986
Chris@16 1987 // Replaces at most n1 chars of *this, starting with pos, with chars from s
Chris@16 1988 flex_string& replace(size_type pos, size_type n1, const value_type* s)
Chris@16 1989 { return replace(pos, n1, s, traits_type::length(s)); }
Chris@16 1990
Chris@16 1991 // Replaces at most n1 chars of *this, starting with pos, with n2 occurences of c
Chris@16 1992 // consolidated with
Chris@16 1993 // Replaces at most n1 chars of *this, starting with pos,
Chris@16 1994 // with at most n2 chars of str.
Chris@16 1995 // str must have at least n2 chars.
Chris@16 1996 template <class StrOrLength, class NumOrChar>
Chris@16 1997 flex_string& replace(size_type pos, size_type n1,
Chris@16 1998 StrOrLength s_or_n2, NumOrChar n_or_c)
Chris@16 1999 {
Chris@16 2000 #ifndef NDEBUG
Chris@16 2001 Invariant checker(*this);
Chris@16 2002 #endif
Chris@16 2003 Enforce(pos <= size(), (std::out_of_range*)0, "");
Chris@16 2004 Procust(n1, length() - pos);
Chris@16 2005 const iterator b = begin() + pos;
Chris@16 2006 return replace(b, b + n1, s_or_n2, n_or_c);
Chris@16 2007 }
Chris@16 2008
Chris@16 2009 flex_string& replace(iterator i1, iterator i2, const flex_string& str)
Chris@16 2010 { return replace(i1, i2, str.c_str(), str.length()); }
Chris@16 2011
Chris@16 2012 flex_string& replace(iterator i1, iterator i2, const value_type* s)
Chris@16 2013 { return replace(i1, i2, s, traits_type::length(s)); }
Chris@16 2014
Chris@16 2015 private:
Chris@16 2016 flex_string& ReplaceImplDiscr(iterator i1, iterator i2,
Chris@16 2017 const value_type* s, size_type n, Selector<2>)
Chris@16 2018 {
Chris@16 2019 BOOST_ASSERT(i1 <= i2);
Chris@16 2020 BOOST_ASSERT(begin() <= i1 && i1 <= end());
Chris@16 2021 BOOST_ASSERT(begin() <= i2 && i2 <= end());
Chris@16 2022 return replace(i1, i2, s, s + n);
Chris@16 2023 }
Chris@16 2024
Chris@16 2025 flex_string& ReplaceImplDiscr(iterator i1, iterator i2,
Chris@16 2026 size_type n2, value_type c, Selector<1>)
Chris@16 2027 {
Chris@16 2028 const size_type n1 = i2 - i1;
Chris@16 2029 if (n1 > n2)
Chris@16 2030 {
Chris@16 2031 std::fill(i1, i1 + n2, c);
Chris@16 2032 erase(i1 + n2, i2);
Chris@16 2033 }
Chris@16 2034 else
Chris@16 2035 {
Chris@16 2036 std::fill(i1, i2, c);
Chris@16 2037 insert(i2, n2 - n1, c);
Chris@16 2038 }
Chris@16 2039 return *this;
Chris@16 2040 }
Chris@16 2041
Chris@16 2042 template <class InputIterator>
Chris@16 2043 flex_string& ReplaceImplDiscr(iterator i1, iterator i2,
Chris@16 2044 InputIterator b, InputIterator e, Selector<0>)
Chris@16 2045 {
Chris@16 2046 ReplaceImpl(i1, i2, b, e,
Chris@16 2047 typename std::iterator_traits<InputIterator>::iterator_category());
Chris@16 2048 return *this;
Chris@16 2049 }
Chris@16 2050
Chris@16 2051 template <class FwdIterator>
Chris@16 2052 void ReplaceImpl(iterator i1, iterator i2,
Chris@16 2053 FwdIterator s1, FwdIterator s2, std::forward_iterator_tag)
Chris@16 2054 {
Chris@16 2055 #ifndef NDEBUG
Chris@16 2056 Invariant checker(*this);
Chris@16 2057 #endif
Chris@16 2058 const typename std::iterator_traits<iterator>::difference_type n1 =
Chris@16 2059 i2 - i1;
Chris@16 2060 BOOST_ASSERT(n1 >= 0);
Chris@16 2061 const typename std::iterator_traits<FwdIterator>::difference_type n2 =
Chris@16 2062 std::distance(s1, s2);
Chris@16 2063 BOOST_ASSERT(n2 >= 0);
Chris@16 2064
Chris@16 2065 if (IsAliasedRange(s1, s2))
Chris@16 2066 {
Chris@16 2067 // Aliased replace, copy to new string.
Chris@16 2068 flex_string temporary;
Chris@16 2069 temporary.reserve(size() - n1 + n2);
Chris@16 2070 temporary.append(begin(), i1).append(s1, s2).append(i2, end());
Chris@16 2071 swap(temporary);
Chris@16 2072 return;
Chris@16 2073 }
Chris@16 2074
Chris@16 2075 if (n1 > n2)
Chris@16 2076 {
Chris@16 2077 // Shrinks
Chris@16 2078 std::copy(s1, s2, i1);
Chris@16 2079 erase(i1 + n2, i2);
Chris@16 2080 }
Chris@16 2081 else
Chris@16 2082 {
Chris@16 2083 // Grows
Chris@16 2084 flex_string_details::copy_n(s1, n1, i1);
Chris@16 2085 std::advance(s1, n1);
Chris@16 2086 insert(i2, s1, s2);
Chris@16 2087 }
Chris@16 2088 }
Chris@16 2089
Chris@16 2090 template <class InputIterator>
Chris@16 2091 void ReplaceImpl(iterator i1, iterator i2,
Chris@16 2092 InputIterator b, InputIterator e, std::input_iterator_tag)
Chris@16 2093 {
Chris@16 2094 flex_string temp(begin(), i1);
Chris@16 2095 temp.append(b, e).append(i2, end());
Chris@16 2096 swap(temp);
Chris@16 2097 }
Chris@16 2098
Chris@16 2099 public:
Chris@16 2100 template <class T1, class T2>
Chris@16 2101 flex_string& replace(iterator i1, iterator i2,
Chris@16 2102 T1 first_or_n_or_s, T2 last_or_c_or_n)
Chris@16 2103 {
Chris@16 2104 const bool
Chris@16 2105 num1 = std::numeric_limits<T1>::is_specialized,
Chris@16 2106 num2 = std::numeric_limits<T2>::is_specialized;
Chris@16 2107 return ReplaceImplDiscr(i1, i2, first_or_n_or_s, last_or_c_or_n,
Chris@16 2108 Selector<num1 ? (num2 ? 1 : -1) : (num2 ? 2 : 0)>());
Chris@16 2109 }
Chris@16 2110
Chris@16 2111 size_type copy(value_type* s, size_type n, size_type pos = 0) const
Chris@16 2112 {
Chris@16 2113 Enforce(pos <= size(), (std::out_of_range*)0, "");
Chris@16 2114 n = Min(n, size() - pos);
Chris@16 2115
Chris@16 2116 flex_string_details::pod_copy(
Chris@16 2117 &*begin() + pos,
Chris@16 2118 &*begin() + pos + n,
Chris@16 2119 s);
Chris@16 2120 return n;
Chris@16 2121 }
Chris@16 2122
Chris@16 2123 void swap(flex_string& rhs)
Chris@16 2124 {
Chris@16 2125 Storage& srhs = rhs;
Chris@16 2126 this->Storage::swap(srhs);
Chris@16 2127 }
Chris@16 2128
Chris@16 2129 // 21.3.6 string operations:
Chris@16 2130 const value_type* c_str() const
Chris@16 2131 { return Storage::c_str(); }
Chris@16 2132
Chris@16 2133 const value_type* data() const
Chris@16 2134 { return Storage::data(); }
Chris@16 2135
Chris@16 2136 allocator_type get_allocator() const
Chris@16 2137 { return Storage::get_allocator(); }
Chris@16 2138
Chris@16 2139 size_type find(const flex_string& str, size_type pos = 0) const
Chris@16 2140 { return find(str.data(), pos, str.length()); }
Chris@16 2141
Chris@16 2142 size_type find (const value_type* s, size_type pos, size_type n) const
Chris@16 2143 {
Chris@16 2144 const size_type size_(size());
Chris@16 2145 if (n + pos > size_)
Chris@16 2146 return npos;
Chris@16 2147 for (; pos < size_; ++pos)
Chris@16 2148 {
Chris@16 2149 if (traits_type::compare(&*begin() + pos, s, n) == 0)
Chris@16 2150 {
Chris@16 2151 return pos;
Chris@16 2152 }
Chris@16 2153 }
Chris@16 2154 return npos;
Chris@16 2155 }
Chris@16 2156
Chris@16 2157 size_type find (const value_type* s, size_type pos = 0) const
Chris@16 2158 { return find(s, pos, traits_type::length(s)); }
Chris@16 2159
Chris@16 2160 size_type find (value_type c, size_type pos = 0) const
Chris@16 2161 { return find(&c, pos, 1); }
Chris@16 2162
Chris@16 2163 size_type rfind(const flex_string& str, size_type pos = npos) const
Chris@16 2164 { return rfind(str.c_str(), pos, str.length()); }
Chris@16 2165
Chris@16 2166 size_type rfind(const value_type* s, size_type pos, size_type n) const
Chris@16 2167 {
Chris@16 2168 if (n > length()) return npos;
Chris@16 2169 pos = Min(pos, length() - n);
Chris@16 2170 if (n == 0) return pos;
Chris@16 2171
Chris@16 2172 const_iterator i(begin() + pos);
Chris@16 2173 for (; ; --i)
Chris@16 2174 {
Chris@16 2175 if (traits_type::eq(*i, *s)
Chris@16 2176 && traits_type::compare(&*i, s, n) == 0)
Chris@16 2177 {
Chris@16 2178 return i - begin();
Chris@16 2179 }
Chris@16 2180 if (i == begin()) break;
Chris@16 2181 }
Chris@16 2182 return npos;
Chris@16 2183 }
Chris@16 2184
Chris@16 2185 size_type rfind(const value_type* s, size_type pos = npos) const
Chris@16 2186 { return rfind(s, pos, traits_type::length(s)); }
Chris@16 2187
Chris@16 2188 size_type rfind(value_type c, size_type pos = npos) const
Chris@16 2189 { return rfind(&c, pos, 1); }
Chris@16 2190
Chris@16 2191 size_type find_first_of(const flex_string& str, size_type pos = 0) const
Chris@16 2192 { return find_first_of(str.c_str(), pos, str.length()); }
Chris@16 2193
Chris@16 2194 size_type find_first_of(const value_type* s,
Chris@16 2195 size_type pos, size_type n) const
Chris@16 2196 {
Chris@16 2197 if (pos > length() || n == 0) return npos;
Chris@16 2198 const_iterator i(begin() + pos),
Chris@16 2199 finish(end());
Chris@16 2200 for (; i != finish; ++i)
Chris@16 2201 {
Chris@16 2202 if (traits_type::find(s, n, *i) != 0)
Chris@16 2203 {
Chris@16 2204 return i - begin();
Chris@16 2205 }
Chris@16 2206 }
Chris@16 2207 return npos;
Chris@16 2208 }
Chris@16 2209
Chris@16 2210 size_type find_first_of(const value_type* s, size_type pos = 0) const
Chris@16 2211 { return find_first_of(s, pos, traits_type::length(s)); }
Chris@16 2212
Chris@16 2213 size_type find_first_of(value_type c, size_type pos = 0) const
Chris@16 2214 { return find_first_of(&c, pos, 1); }
Chris@16 2215
Chris@16 2216 size_type find_last_of (const flex_string& str,
Chris@16 2217 size_type pos = npos) const
Chris@16 2218 { return find_last_of(str.c_str(), pos, str.length()); }
Chris@16 2219
Chris@16 2220 size_type find_last_of (const value_type* s, size_type pos,
Chris@16 2221 size_type n) const
Chris@16 2222 {
Chris@16 2223 if (!empty() && n > 0)
Chris@16 2224 {
Chris@16 2225 pos = Min(pos, length() - 1);
Chris@16 2226 const_iterator i(begin() + pos);
Chris@16 2227 for (;; --i)
Chris@16 2228 {
Chris@16 2229 if (traits_type::find(s, n, *i) != 0)
Chris@16 2230 {
Chris@16 2231 return i - begin();
Chris@16 2232 }
Chris@16 2233 if (i == begin()) break;
Chris@16 2234 }
Chris@16 2235 }
Chris@16 2236 return npos;
Chris@16 2237 }
Chris@16 2238
Chris@16 2239 size_type find_last_of (const value_type* s,
Chris@16 2240 size_type pos = npos) const
Chris@16 2241 { return find_last_of(s, pos, traits_type::length(s)); }
Chris@16 2242
Chris@16 2243 size_type find_last_of (value_type c, size_type pos = npos) const
Chris@16 2244 { return find_last_of(&c, pos, 1); }
Chris@16 2245
Chris@16 2246 size_type find_first_not_of(const flex_string& str,
Chris@16 2247 size_type pos = 0) const
Chris@16 2248 { return find_first_not_of(str.data(), pos, str.size()); }
Chris@16 2249
Chris@16 2250 size_type find_first_not_of(const value_type* s, size_type pos,
Chris@16 2251 size_type n) const
Chris@16 2252 {
Chris@16 2253 if (pos < length())
Chris@16 2254 {
Chris@16 2255 const_iterator
Chris@16 2256 i(begin() + pos),
Chris@16 2257 finish(end());
Chris@16 2258 for (; i != finish; ++i)
Chris@16 2259 {
Chris@16 2260 if (traits_type::find(s, n, *i) == 0)
Chris@16 2261 {
Chris@16 2262 return i - begin();
Chris@16 2263 }
Chris@16 2264 }
Chris@16 2265 }
Chris@16 2266 return npos;
Chris@16 2267 }
Chris@16 2268
Chris@16 2269 size_type find_first_not_of(const value_type* s,
Chris@16 2270 size_type pos = 0) const
Chris@16 2271 { return find_first_not_of(s, pos, traits_type::length(s)); }
Chris@16 2272
Chris@16 2273 size_type find_first_not_of(value_type c, size_type pos = 0) const
Chris@16 2274 { return find_first_not_of(&c, pos, 1); }
Chris@16 2275
Chris@16 2276 size_type find_last_not_of(const flex_string& str,
Chris@16 2277 size_type pos = npos) const
Chris@16 2278 { return find_last_not_of(str.c_str(), pos, str.length()); }
Chris@16 2279
Chris@16 2280 size_type find_last_not_of(const value_type* s, size_type pos,
Chris@16 2281 size_type n) const
Chris@16 2282 {
Chris@16 2283 if (!empty())
Chris@16 2284 {
Chris@16 2285 pos = Min(pos, size() - 1);
Chris@16 2286 const_iterator i(begin() + pos);
Chris@16 2287 for (;; --i)
Chris@16 2288 {
Chris@16 2289 if (traits_type::find(s, n, *i) == 0)
Chris@16 2290 {
Chris@16 2291 return i - begin();
Chris@16 2292 }
Chris@16 2293 if (i == begin()) break;
Chris@16 2294 }
Chris@16 2295 }
Chris@16 2296 return npos;
Chris@16 2297 }
Chris@16 2298
Chris@16 2299 size_type find_last_not_of(const value_type* s,
Chris@16 2300 size_type pos = npos) const
Chris@16 2301 { return find_last_not_of(s, pos, traits_type::length(s)); }
Chris@16 2302
Chris@16 2303 size_type find_last_not_of (value_type c, size_type pos = npos) const
Chris@16 2304 { return find_last_not_of(&c, pos, 1); }
Chris@16 2305
Chris@16 2306 flex_string substr(size_type pos = 0, size_type n = npos) const
Chris@16 2307 {
Chris@16 2308 Enforce(pos <= size(), (std::out_of_range*)0, "");
Chris@16 2309 return flex_string(data() + pos, Min(n, size() - pos));
Chris@16 2310 }
Chris@16 2311
Chris@16 2312 std::ptrdiff_t compare(const flex_string& str) const
Chris@16 2313 {
Chris@16 2314 // FIX due to Goncalo N M de Carvalho July 18, 2005
Chris@16 2315 return compare(0, size(), str);
Chris@16 2316 }
Chris@16 2317
Chris@16 2318 std::ptrdiff_t compare(size_type pos1, size_type n1,
Chris@16 2319 const flex_string& str) const
Chris@16 2320 { return compare(pos1, n1, str.data(), str.size()); }
Chris@16 2321
Chris@16 2322 // FIX to compare: added the TC
Chris@16 2323 // (http://www.comeaucomputing.com/iso/lwg-defects.html number 5)
Chris@16 2324 // Thanks to Caleb Epstein for the fix
Chris@16 2325 std::ptrdiff_t compare(size_type pos1, size_type n1,
Chris@16 2326 const value_type* s) const
Chris@16 2327 {
Chris@16 2328 return compare(pos1, n1, s, traits_type::length(s));
Chris@16 2329 }
Chris@16 2330
Chris@16 2331 std::ptrdiff_t compare(size_type pos1, size_type n1,
Chris@16 2332 const value_type* s, size_type n2) const
Chris@16 2333 {
Chris@16 2334 Enforce(pos1 <= size(), (std::out_of_range*)0, "");
Chris@16 2335 Procust(n1, size() - pos1);
Chris@16 2336 const int r = traits_type::compare(pos1 + data(), s, Min(n1, n2));
Chris@16 2337 return r != 0 ? r : n1 > n2 ? 1 : n1 < n2 ? -1 : 0;
Chris@16 2338 }
Chris@16 2339
Chris@16 2340 std::ptrdiff_t compare(size_type pos1, size_type n1,
Chris@16 2341 const flex_string& str,
Chris@16 2342 size_type pos2, size_type n2) const
Chris@16 2343 {
Chris@16 2344 Enforce(pos2 <= str.size(), (std::out_of_range*)0, "");
Chris@16 2345 return compare(pos1, n1, str.data() + pos2, Min(n2, str.size() - pos2));
Chris@16 2346 }
Chris@16 2347
Chris@16 2348 std::ptrdiff_t compare(const value_type* s) const
Chris@16 2349 {
Chris@16 2350 // Could forward to compare(0, size(), s, traits_type::length(s))
Chris@16 2351 // but that does two extra checks
Chris@16 2352 const size_type n1(size()), n2(traits_type::length(s));
Chris@16 2353 const int r = traits_type::compare(data(), s, Min(n1, n2));
Chris@16 2354 return r != 0 ? r : n1 > n2 ? 1 : n1 < n2 ? -1 : 0;
Chris@16 2355 }
Chris@16 2356 };
Chris@16 2357
Chris@16 2358 // non-member functions
Chris@16 2359 template <typename E, class T, class A, class S>
Chris@16 2360 flex_string<E, T, A, S> operator+(const flex_string<E, T, A, S>& lhs,
Chris@16 2361 const flex_string<E, T, A, S>& rhs)
Chris@16 2362 {
Chris@16 2363 flex_string<E, T, A, S> result;
Chris@16 2364 result.reserve(lhs.size() + rhs.size());
Chris@16 2365 result.append(lhs).append(rhs);
Chris@16 2366 return result;
Chris@16 2367 }
Chris@16 2368
Chris@16 2369 template <typename E, class T, class A, class S>
Chris@16 2370 flex_string<E, T, A, S> operator+(const typename flex_string<E, T, A, S>::value_type* lhs,
Chris@16 2371 const flex_string<E, T, A, S>& rhs)
Chris@16 2372 {
Chris@16 2373 flex_string<E, T, A, S> result;
Chris@16 2374 const typename flex_string<E, T, A, S>::size_type len =
Chris@16 2375 flex_string<E, T, A, S>::traits_type::length(lhs);
Chris@16 2376 result.reserve(len + rhs.size());
Chris@16 2377 result.append(lhs, len).append(rhs);
Chris@16 2378 return result;
Chris@16 2379 }
Chris@16 2380
Chris@16 2381 template <typename E, class T, class A, class S>
Chris@16 2382 flex_string<E, T, A, S> operator+(
Chris@16 2383 typename flex_string<E, T, A, S>::value_type lhs,
Chris@16 2384 const flex_string<E, T, A, S>& rhs)
Chris@16 2385 {
Chris@16 2386 flex_string<E, T, A, S> result;
Chris@16 2387 result.reserve(1 + rhs.size());
Chris@16 2388 result.push_back(lhs);
Chris@16 2389 result.append(rhs);
Chris@16 2390 return result;
Chris@16 2391 }
Chris@16 2392
Chris@16 2393 template <typename E, class T, class A, class S>
Chris@16 2394 flex_string<E, T, A, S> operator+(const flex_string<E, T, A, S>& lhs,
Chris@16 2395 const typename flex_string<E, T, A, S>::value_type* rhs)
Chris@16 2396 {
Chris@16 2397 typedef typename flex_string<E, T, A, S>::size_type size_type;
Chris@16 2398 typedef typename flex_string<E, T, A, S>::traits_type traits_type;
Chris@16 2399
Chris@16 2400 flex_string<E, T, A, S> result;
Chris@16 2401 const size_type len = traits_type::length(rhs);
Chris@16 2402 result.reserve(lhs.size() + len);
Chris@16 2403 result.append(lhs).append(rhs, len);
Chris@16 2404 return result;
Chris@16 2405 }
Chris@16 2406
Chris@16 2407 template <typename E, class T, class A, class S>
Chris@16 2408 flex_string<E, T, A, S> operator+(const flex_string<E, T, A, S>& lhs,
Chris@16 2409 typename flex_string<E, T, A, S>::value_type rhs)
Chris@16 2410 {
Chris@16 2411 flex_string<E, T, A, S> result;
Chris@16 2412 result.reserve(lhs.size() + 1);
Chris@16 2413 result.append(lhs);
Chris@16 2414 result.push_back(rhs);
Chris@16 2415 return result;
Chris@16 2416 }
Chris@16 2417
Chris@16 2418 template <typename E, class T, class A, class S>
Chris@16 2419 inline bool operator==(const flex_string<E, T, A, S>& lhs,
Chris@16 2420 const flex_string<E, T, A, S>& rhs)
Chris@16 2421 { return lhs.compare(rhs) == 0; }
Chris@16 2422
Chris@16 2423 template <typename E, class T, class A, class S>
Chris@16 2424 inline bool operator==(const typename flex_string<E, T, A, S>::value_type* lhs,
Chris@16 2425 const flex_string<E, T, A, S>& rhs)
Chris@16 2426 { return rhs == lhs; }
Chris@16 2427
Chris@16 2428 template <typename E, class T, class A, class S>
Chris@16 2429 inline bool operator==(const flex_string<E, T, A, S>& lhs,
Chris@16 2430 const typename flex_string<E, T, A, S>::value_type* rhs)
Chris@16 2431 { return lhs.compare(rhs) == 0; }
Chris@16 2432
Chris@16 2433 template <typename E, class T, class A, class S>
Chris@16 2434 inline bool operator!=(const flex_string<E, T, A, S>& lhs,
Chris@16 2435 const flex_string<E, T, A, S>& rhs)
Chris@16 2436 { return !(lhs == rhs); }
Chris@16 2437
Chris@16 2438 template <typename E, class T, class A, class S>
Chris@16 2439 inline bool operator!=(const typename flex_string<E, T, A, S>::value_type* lhs,
Chris@16 2440 const flex_string<E, T, A, S>& rhs)
Chris@16 2441 { return !(lhs == rhs); }
Chris@16 2442
Chris@16 2443 template <typename E, class T, class A, class S>
Chris@16 2444 inline bool operator!=(const flex_string<E, T, A, S>& lhs,
Chris@16 2445 const typename flex_string<E, T, A, S>::value_type* rhs)
Chris@16 2446 { return !(lhs == rhs); }
Chris@16 2447
Chris@16 2448 template <typename E, class T, class A, class S>
Chris@16 2449 inline bool operator<(const flex_string<E, T, A, S>& lhs,
Chris@16 2450 const flex_string<E, T, A, S>& rhs)
Chris@16 2451 { return lhs.compare(rhs) < 0; }
Chris@16 2452
Chris@16 2453 template <typename E, class T, class A, class S>
Chris@16 2454 inline bool operator<(const flex_string<E, T, A, S>& lhs,
Chris@16 2455 const typename flex_string<E, T, A, S>::value_type* rhs)
Chris@16 2456 { return lhs.compare(rhs) < 0; }
Chris@16 2457
Chris@16 2458 template <typename E, class T, class A, class S>
Chris@16 2459 inline bool operator<(const typename flex_string<E, T, A, S>::value_type* lhs,
Chris@16 2460 const flex_string<E, T, A, S>& rhs)
Chris@16 2461 { return rhs.compare(lhs) > 0; }
Chris@16 2462
Chris@16 2463 template <typename E, class T, class A, class S>
Chris@16 2464 inline bool operator>(const flex_string<E, T, A, S>& lhs,
Chris@16 2465 const flex_string<E, T, A, S>& rhs)
Chris@16 2466 { return rhs < lhs; }
Chris@16 2467
Chris@16 2468 template <typename E, class T, class A, class S>
Chris@16 2469 inline bool operator>(const flex_string<E, T, A, S>& lhs,
Chris@16 2470 const typename flex_string<E, T, A, S>::value_type* rhs)
Chris@16 2471 { return rhs < lhs; }
Chris@16 2472
Chris@16 2473 template <typename E, class T, class A, class S>
Chris@16 2474 bool operator>(const typename flex_string<E, T, A, S>::value_type* lhs,
Chris@16 2475 const flex_string<E, T, A, S>& rhs)
Chris@16 2476 { return rhs < lhs; }
Chris@16 2477
Chris@16 2478 template <typename E, class T, class A, class S>
Chris@16 2479 inline bool operator<=(const flex_string<E, T, A, S>& lhs,
Chris@16 2480 const flex_string<E, T, A, S>& rhs)
Chris@16 2481 { return !(rhs < lhs); }
Chris@16 2482
Chris@16 2483 template <typename E, class T, class A, class S>
Chris@16 2484 inline bool operator<=(const flex_string<E, T, A, S>& lhs,
Chris@16 2485 const typename flex_string<E, T, A, S>::value_type* rhs)
Chris@16 2486 { return !(rhs < lhs); }
Chris@16 2487
Chris@16 2488 template <typename E, class T, class A, class S>
Chris@16 2489 bool operator<=(const typename flex_string<E, T, A, S>::value_type* lhs,
Chris@16 2490 const flex_string<E, T, A, S>& rhs)
Chris@16 2491 { return !(rhs < lhs); }
Chris@16 2492
Chris@16 2493 template <typename E, class T, class A, class S>
Chris@16 2494 bool operator>=(const flex_string<E, T, A, S>& lhs,
Chris@16 2495 const flex_string<E, T, A, S>& rhs)
Chris@16 2496 { return !(lhs < rhs); }
Chris@16 2497
Chris@16 2498 template <typename E, class T, class A, class S>
Chris@16 2499 bool operator>=(const flex_string<E, T, A, S>& lhs,
Chris@16 2500 const typename flex_string<E, T, A, S>::value_type* rhs)
Chris@16 2501 { return !(lhs < rhs); }
Chris@16 2502
Chris@16 2503 template <typename E, class T, class A, class S>
Chris@16 2504 inline bool operator>=(const typename flex_string<E, T, A, S>::value_type* lhs,
Chris@16 2505 const flex_string<E, T, A, S>& rhs)
Chris@16 2506 { return !(lhs < rhs); }
Chris@16 2507
Chris@16 2508 template <typename E, class T, class A, class S>
Chris@16 2509 void swap(flex_string<E, T, A, S>& lhs, flex_string<E, T, A, S>& rhs)
Chris@16 2510 {
Chris@16 2511 // subclause 21.3.7.8:
Chris@16 2512 lhs.swap(rhs);
Chris@16 2513 }
Chris@16 2514
Chris@16 2515 template <typename E, class T, class A, class S>
Chris@16 2516 inline std::basic_istream<typename flex_string<E, T, A, S>::value_type,
Chris@16 2517 typename flex_string<E, T, A, S>::traits_type>&
Chris@16 2518 operator>>(
Chris@16 2519 std::basic_istream<typename flex_string<E, T, A, S>::value_type,
Chris@16 2520 typename flex_string<E, T, A, S>::traits_type>& is,
Chris@16 2521 flex_string<E, T, A, S>& str);
Chris@16 2522
Chris@16 2523 template <typename E, class T, class A, class S>
Chris@16 2524 std::basic_ostream<typename flex_string<E, T, A, S>::value_type,
Chris@16 2525 typename flex_string<E, T, A, S>::traits_type>&
Chris@16 2526 operator<<(
Chris@16 2527 std::basic_ostream<typename flex_string<E, T, A, S>::value_type,
Chris@16 2528 typename flex_string<E, T, A, S>::traits_type>& os,
Chris@16 2529 const flex_string<E, T, A, S>& str)
Chris@16 2530 { return os << str.c_str(); }
Chris@16 2531
Chris@16 2532 template <typename E1, class T, class A, class S>
Chris@16 2533 const typename flex_string<E1, T, A, S>::size_type
Chris@16 2534 flex_string<E1, T, A, S>::npos = (typename flex_string<E1, T, A, S>::size_type)(-1);
Chris@16 2535
Chris@16 2536 ///////////////////////////////////////////////////////////////////////////////
Chris@16 2537 } // namespace util
Chris@16 2538 } // namespace wave
Chris@16 2539 } // namespace boost
Chris@16 2540
Chris@16 2541 #if BOOST_WAVE_SERIALIZATION != 0
Chris@16 2542 ///////////////////////////////////////////////////////////////////////////////
Chris@16 2543 namespace boost { namespace serialization {
Chris@16 2544
Chris@16 2545 #if !defined(BOOST_WAVE_FLEX_STRING_SERIALIZATION_HACK)
Chris@16 2546
Chris@16 2547 // FIXME: This doesn't work because of the missing flex_string::operator>>()
Chris@16 2548 template <typename E, class T, class A, class S>
Chris@16 2549 struct implementation_level<boost::wave::util::flex_string<E, T, A, S> >
Chris@16 2550 {
Chris@16 2551 typedef mpl::integral_c_tag tag;
Chris@16 2552 typedef mpl::int_<boost::serialization::primitive_type> type;
Chris@16 2553 BOOST_STATIC_CONSTANT(
Chris@16 2554 int,
Chris@16 2555 value = implementation_level::type::value
Chris@16 2556 );
Chris@16 2557 };
Chris@16 2558
Chris@16 2559 #else
Chris@16 2560
Chris@16 2561 // We serialize flex_strings as vectors of char's for now
Chris@16 2562 template<class Archive, typename E, class T, class A, class S>
Chris@16 2563 inline void save(Archive & ar,
Chris@16 2564 boost::wave::util::flex_string<E, T, A, S> const &t,
Chris@16 2565 const unsigned int file_version)
Chris@16 2566 {
Chris@16 2567 boost::serialization::stl::save_collection<
Chris@16 2568 Archive, wave::util::flex_string<E, T, A, S> >(ar, t);
Chris@16 2569 }
Chris@16 2570
Chris@16 2571 template<class Archive, typename E, class T, class A, class S>
Chris@16 2572 inline void load(Archive & ar, boost::wave::util::flex_string<E, T, A, S> &t,
Chris@16 2573 const unsigned int file_version)
Chris@16 2574 {
Chris@16 2575 boost::serialization::stl::load_collection<
Chris@16 2576 Archive, boost::wave::util::flex_string<E, T, A, S>,
Chris@16 2577 boost::serialization::stl::archive_input_seq<
Chris@16 2578 Archive, boost::wave::util::flex_string<E, T, A, S> >,
Chris@16 2579 boost::serialization::stl::reserve_imp<
Chris@16 2580 boost::wave::util::flex_string<E, T, A, S> >
Chris@16 2581 >(ar, t);
Chris@16 2582 }
Chris@16 2583
Chris@16 2584 // split non-intrusive serialization function member into separate
Chris@16 2585 // non intrusive save/load member functions
Chris@16 2586 template<class Archive, typename E, class T, class A, class S>
Chris@16 2587 inline void serialize(Archive & ar, boost::wave::util::flex_string<E, T, A, S> &t,
Chris@16 2588 const unsigned int file_version)
Chris@16 2589 {
Chris@16 2590 boost::serialization::split_free(ar, t, file_version);
Chris@16 2591 }
Chris@16 2592
Chris@16 2593 #endif
Chris@16 2594
Chris@16 2595 ///////////////////////////////////////////////////////////////////////////////
Chris@16 2596 }} // boost::serialization
Chris@16 2597 #endif
Chris@16 2598
Chris@16 2599 // the suffix header occurs after all of the code
Chris@16 2600 #ifdef BOOST_HAS_ABI_HEADERS
Chris@16 2601 #include BOOST_ABI_SUFFIX
Chris@16 2602 #endif
Chris@16 2603
Chris@16 2604 #endif // FLEX_STRING_INC_