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