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