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