Mercurial > hg > vamp-build-and-test
comparison DEPENDENCIES/generic/include/boost/wave/util/flex_string.hpp @ 16:2665513ce2d3
Add boost headers
author | Chris Cannam |
---|---|
date | Tue, 05 Aug 2014 11:11:38 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
15:663ca0da4350 | 16:2665513ce2d3 |
---|---|
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 inline void pod_fill(Pod* b, Pod* e, T c) | |
140 { | |
141 switch ((e - b) & 7) | |
142 { | |
143 case 0: | |
144 while (b != e) | |
145 { | |
146 *b = c; ++b; BOOST_FALLTHROUGH; | |
147 case 7: *b = c; ++b; BOOST_FALLTHROUGH; | |
148 case 6: *b = c; ++b; BOOST_FALLTHROUGH; | |
149 case 5: *b = c; ++b; BOOST_FALLTHROUGH; | |
150 case 4: *b = c; ++b; BOOST_FALLTHROUGH; | |
151 case 3: *b = c; ++b; BOOST_FALLTHROUGH; | |
152 case 2: *b = c; ++b; BOOST_FALLTHROUGH; | |
153 case 1: *b = c; ++b; | |
154 } | |
155 } | |
156 } | |
157 | |
158 template <class Pod> | |
159 inline void pod_move(const Pod* b, const Pod* e, Pod* d) | |
160 { | |
161 using namespace std; | |
162 memmove(d, b, (e - b) * sizeof(*b)); | |
163 } | |
164 | |
165 template <class Pod> | |
166 inline Pod* pod_copy(const Pod* b, const Pod* e, Pod* d) | |
167 { | |
168 const std::size_t s = e - b; | |
169 using namespace std; | |
170 memcpy(d, b, s * sizeof(*b)); | |
171 return d + s; | |
172 } | |
173 | |
174 template <typename T> struct get_unsigned | |
175 { | |
176 typedef T result; | |
177 }; | |
178 | |
179 template <> struct get_unsigned<char> | |
180 { | |
181 typedef unsigned char result; | |
182 }; | |
183 | |
184 template <> struct get_unsigned<signed char> | |
185 { | |
186 typedef unsigned char result; | |
187 }; | |
188 | |
189 template <> struct get_unsigned<short int> | |
190 { | |
191 typedef unsigned short int result; | |
192 }; | |
193 | |
194 template <> struct get_unsigned<int> | |
195 { | |
196 typedef unsigned int result; | |
197 }; | |
198 | |
199 template <> struct get_unsigned<long int> | |
200 { | |
201 typedef unsigned long int result; | |
202 }; | |
203 | |
204 enum Shallow {}; | |
205 } | |
206 | |
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 void Free(void* p, size_type sz) | |
565 { | |
566 A::deallocate(static_cast<E*>(p), sz); | |
567 } | |
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 AllocatorStringStorage(const AllocatorStringStorage& rhs) | |
601 : A(rhs.get_allocator()) | |
602 { | |
603 const size_type sz = rhs.size(); | |
604 Init(sz, sz); | |
605 if (sz) flex_string_details::pod_copy(rhs.begin(), rhs.end(), begin()); | |
606 } | |
607 | |
608 AllocatorStringStorage(const AllocatorStringStorage& s, | |
609 flex_string_details::Shallow) | |
610 : A(s.get_allocator()) | |
611 { | |
612 pData_ = s.pData_; | |
613 } | |
614 | |
615 AllocatorStringStorage(const A& a) : A(a) | |
616 { | |
617 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 AllocatorStringStorage(size_type len, E c, const A& a) | |
629 : A(a) | |
630 { | |
631 Init(len, len); | |
632 flex_string_details::pod_fill(&*begin(), &*end(), c); | |
633 } | |
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 ~AllocatorStringStorage() | |
645 { | |
646 if (capacity()) | |
647 { | |
648 Free(pData_, | |
649 sizeof(Data) + capacity() * sizeof(E)); | |
650 } | |
651 } | |
652 | |
653 iterator begin() | |
654 { return pData_->buffer_; } | |
655 | |
656 const_iterator begin() const | |
657 { return pData_->buffer_; } | |
658 | |
659 iterator end() | |
660 { return pData_->pEnd_; } | |
661 | |
662 const_iterator end() const | |
663 { return pData_->pEnd_; } | |
664 | |
665 size_type size() const | |
666 { return size_type(end() - begin()); } | |
667 | |
668 size_type max_size() const | |
669 { return A::max_size(); } | |
670 | |
671 size_type capacity() const | |
672 { return size_type(pData_->pEndOfMem_ - pData_->buffer_); } | |
673 | |
674 void resize(size_type n, E c) | |
675 { | |
676 reserve(n); | |
677 iterator newEnd = begin() + n; | |
678 iterator oldEnd = end(); | |
679 if (newEnd > oldEnd) | |
680 { | |
681 // Copy the characters | |
682 flex_string_details::pod_fill(oldEnd, newEnd, c); | |
683 } | |
684 if (capacity()) pData_->pEnd_ = newEnd; | |
685 } | |
686 | |
687 void reserve(size_type res_arg) | |
688 { | |
689 if (res_arg <= capacity()) | |
690 { | |
691 // @@@ shrink to fit here | |
692 return; | |
693 } | |
694 | |
695 A& myAlloc = *this; | |
696 AllocatorStringStorage newStr(myAlloc); | |
697 newStr.Init(size(), res_arg); | |
698 | |
699 flex_string_details::pod_copy(begin(), end(), newStr.begin()); | |
700 | |
701 swap(newStr); | |
702 } | |
703 | |
704 template <class ForwardIterator> | |
705 void append(ForwardIterator b, ForwardIterator e) | |
706 { | |
707 const size_type | |
708 sz = std::distance(b, e), | |
709 neededCapacity = size() + sz; | |
710 | |
711 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 reserve(neededCapacity); | |
716 } | |
717 std::copy(b, e, end()); | |
718 pData_->pEnd_ += sz; | |
719 } | |
720 | |
721 void swap(AllocatorStringStorage& rhs) | |
722 { | |
723 // @@@ The following line is commented due to a bug in MSVC | |
724 //std::swap(lhsAlloc, rhsAlloc); | |
725 std::swap(pData_, rhs.pData_); | |
726 } | |
727 | |
728 const E* c_str() const | |
729 { | |
730 if (pData_ != &SimpleStringStorage<E, A>::emptyString_) | |
731 { | |
732 *pData_->pEnd_ = E(); | |
733 } | |
734 return &*begin(); | |
735 } | |
736 | |
737 const E* data() const | |
738 { return &*begin(); } | |
739 | |
740 A get_allocator() const | |
741 { 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 Storage& Data() const | |
1215 { | |
1216 Storage* p = reinterpret_cast<Storage*>(&buf_[0]); | |
1217 return *p; | |
1218 } | |
1219 | |
1220 RefCountType GetRefs() const | |
1221 { | |
1222 const Storage& d = Data(); | |
1223 BOOST_ASSERT(d.size() > 0); | |
1224 BOOST_ASSERT(static_cast<RefCountType>(*d.begin()) != 0); | |
1225 return *d.begin(); | |
1226 } | |
1227 | |
1228 RefCountType& Refs() | |
1229 { | |
1230 Storage& d = Data(); | |
1231 BOOST_ASSERT(d.size() > 0); | |
1232 return reinterpret_cast<RefCountType&>(*d.begin()); | |
1233 } | |
1234 | |
1235 void MakeUnique() const | |
1236 { | |
1237 BOOST_ASSERT(GetRefs() >= 1); | |
1238 if (GetRefs() == 1) return; | |
1239 | |
1240 union | |
1241 { | |
1242 char buf_[sizeof(Storage)]; | |
1243 Align align_; | |
1244 } temp; | |
1245 | |
1246 --(*Data().begin()); // decrement the use count of the remaining object | |
1247 | |
1248 Storage* p = reinterpret_cast<Storage*>(&temp.buf_[0]); | |
1249 new(buf_) Storage( | |
1250 *new(p) Storage(Data()), | |
1251 flex_string_details::Shallow()); | |
1252 *Data().begin() = 1; | |
1253 } | |
1254 | |
1255 public: | |
1256 CowString(const CowString& s) | |
1257 { | |
1258 if (s.GetRefs() == (std::numeric_limits<RefCountType>::max)()) | |
1259 { | |
1260 // must make a brand new copy | |
1261 new(buf_) Storage(s.Data()); // non shallow | |
1262 Refs() = 1; | |
1263 } | |
1264 else | |
1265 { | |
1266 new(buf_) Storage(s.Data(), flex_string_details::Shallow()); | |
1267 ++Refs(); | |
1268 } | |
1269 BOOST_ASSERT(Data().size() > 0); | |
1270 } | |
1271 | |
1272 CowString(const allocator_type& a) | |
1273 { | |
1274 new(buf_) Storage(1, 1, a); | |
1275 } | |
1276 | |
1277 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 new(buf_) Storage(a); | |
1283 Data().reserve(len + 1); | |
1284 Data().resize(1, 1); | |
1285 Data().append(s, s + len); | |
1286 } | |
1287 | |
1288 CowString(size_type len, E c, const allocator_type& a) | |
1289 { | |
1290 new(buf_) Storage(len + 1, c, a); | |
1291 Refs() = 1; | |
1292 } | |
1293 | |
1294 CowString& operator=(const CowString& rhs) | |
1295 { | |
1296 // CowString(rhs).swap(*this); | |
1297 if (--Refs() == 0) | |
1298 Data().~Storage(); | |
1299 if (rhs.GetRefs() == (std::numeric_limits<RefCountType>::max)()) | |
1300 { | |
1301 // must make a brand new copy | |
1302 new(buf_) Storage(rhs.Data()); // non shallow | |
1303 Refs() = 1; | |
1304 } | |
1305 else | |
1306 { | |
1307 new(buf_) Storage(rhs.Data(), flex_string_details::Shallow()); | |
1308 ++Refs(); | |
1309 } | |
1310 BOOST_ASSERT(Data().size() > 0); | |
1311 return *this; | |
1312 } | |
1313 | |
1314 ~CowString() | |
1315 { | |
1316 BOOST_ASSERT(Data().size() > 0); | |
1317 if (--Refs() == 0) | |
1318 Data().~Storage(); | |
1319 } | |
1320 | |
1321 iterator begin() | |
1322 { | |
1323 BOOST_ASSERT(Data().size() > 0); | |
1324 MakeUnique(); | |
1325 return Data().begin() + 1; | |
1326 } | |
1327 | |
1328 const_iterator begin() const | |
1329 { | |
1330 BOOST_ASSERT(Data().size() > 0); | |
1331 return Data().begin() + 1; | |
1332 } | |
1333 | |
1334 iterator end() | |
1335 { | |
1336 MakeUnique(); | |
1337 return Data().end(); | |
1338 } | |
1339 | |
1340 const_iterator end() const | |
1341 { | |
1342 return Data().end(); | |
1343 } | |
1344 | |
1345 size_type size() const | |
1346 { | |
1347 BOOST_ASSERT(Data().size() > 0); | |
1348 return Data().size() - 1; | |
1349 } | |
1350 | |
1351 size_type max_size() const | |
1352 { | |
1353 BOOST_ASSERT(Data().max_size() > 0); | |
1354 return Data().max_size() - 1; | |
1355 } | |
1356 | |
1357 size_type capacity() const | |
1358 { | |
1359 BOOST_ASSERT(Data().capacity() > 0); | |
1360 return Data().capacity() - 1; | |
1361 } | |
1362 | |
1363 void resize(size_type n, E c) | |
1364 { | |
1365 BOOST_ASSERT(Data().size() > 0); | |
1366 MakeUnique(); | |
1367 Data().resize(n + 1, c); | |
1368 } | |
1369 | |
1370 template <class FwdIterator> | |
1371 void append(FwdIterator b, FwdIterator e) | |
1372 { | |
1373 MakeUnique(); | |
1374 Data().append(b, e); | |
1375 } | |
1376 | |
1377 void reserve(size_type res_arg) | |
1378 { | |
1379 if (capacity() > res_arg) return; | |
1380 MakeUnique(); | |
1381 Data().reserve(res_arg + 1); | |
1382 } | |
1383 | |
1384 void swap(CowString& rhs) | |
1385 { | |
1386 Data().swap(rhs.Data()); | |
1387 } | |
1388 | |
1389 const E* c_str() const | |
1390 { | |
1391 BOOST_ASSERT(Data().size() > 0); | |
1392 return Data().c_str() + 1; | |
1393 } | |
1394 | |
1395 const E* data() const | |
1396 { | |
1397 BOOST_ASSERT(Data().size() > 0); | |
1398 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 static inline void Enforce(bool condition, Exception*, const char* msg) | |
1426 { BOOST_ASSERT(condition && msg); } | |
1427 #endif // defined(BOOST_WAVE_FLEXSTRING_THROW_ON_ENFORCE) | |
1428 | |
1429 #ifndef NDEBUG | |
1430 bool Sane() const | |
1431 { | |
1432 return | |
1433 begin() <= end() && | |
1434 empty() == (size() == 0) && | |
1435 empty() == (begin() == end()) && | |
1436 size() <= max_size() && | |
1437 capacity() <= max_size() && | |
1438 size() <= capacity(); | |
1439 } | |
1440 | |
1441 struct Invariant; | |
1442 friend struct Invariant; | |
1443 struct Invariant | |
1444 { | |
1445 Invariant(const flex_string& s) : s_(s) | |
1446 { | |
1447 BOOST_ASSERT(s_.Sane()); | |
1448 } | |
1449 ~Invariant() | |
1450 { | |
1451 BOOST_ASSERT(s_.Sane()); | |
1452 } | |
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 static size_type Min(size_type lhs, size_type rhs) | |
1482 { return lhs < rhs ? lhs : rhs; } | |
1483 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 explicit flex_string(const A& a = A()) | |
1489 : Storage(a) | |
1490 {} | |
1491 | |
1492 flex_string(const flex_string& str) | |
1493 : Storage(str) | |
1494 { | |
1495 } | |
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 flex_string(const value_type* s, const A& a = A()) | |
1506 : Storage(s, traits_type::length(s), a) | |
1507 {} | |
1508 | |
1509 flex_string(const value_type* s, size_type n, const A& a = A()) | |
1510 : Storage(s, n, a) | |
1511 {} | |
1512 | |
1513 flex_string(size_type n, value_type c, const A& a = A()) | |
1514 : Storage(n, c, a) | |
1515 {} | |
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 ~flex_string() | |
1525 {} | |
1526 | |
1527 flex_string& operator=(const flex_string& str) | |
1528 { | |
1529 if (this != &str) { | |
1530 Storage& s = *this; | |
1531 s = str; | |
1532 } | |
1533 return *this; | |
1534 } | |
1535 | |
1536 flex_string& operator=(const value_type* s) | |
1537 { | |
1538 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 iterator begin() | |
1550 { return Storage::begin(); } | |
1551 | |
1552 const_iterator begin() const | |
1553 { return Storage::begin(); } | |
1554 | |
1555 iterator end() | |
1556 { return Storage::end(); } | |
1557 | |
1558 const_iterator end() const | |
1559 { 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 size_type size() const | |
1582 { return Storage::size(); } | |
1583 | |
1584 size_type length() const | |
1585 { return size(); } | |
1586 | |
1587 size_type max_size() const | |
1588 { return Storage::max_size(); } | |
1589 | |
1590 void resize(size_type n, value_type c) | |
1591 { Storage::resize(n, c); } | |
1592 | |
1593 void resize(size_type n) | |
1594 { resize(n, value_type()); } | |
1595 | |
1596 size_type capacity() const | |
1597 { return Storage::capacity(); } | |
1598 | |
1599 void reserve(size_type res_arg = 0) | |
1600 { | |
1601 Enforce(res_arg <= max_size(), (std::length_error*)0, ""); | |
1602 Storage::reserve(res_arg); | |
1603 } | |
1604 | |
1605 void clear() | |
1606 { resize(0); } | |
1607 | |
1608 bool empty() const | |
1609 { return size() == 0; } | |
1610 | |
1611 // 21.3.4 element access: | |
1612 const_reference operator[](size_type pos) const | |
1613 { return *(begin() + pos); } | |
1614 | |
1615 reference operator[](size_type pos) | |
1616 { 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 flex_string& operator+=(const flex_string& str) | |
1632 { return append(str); } | |
1633 | |
1634 flex_string& operator+=(const value_type* s) | |
1635 { return append(s); } | |
1636 | |
1637 flex_string& operator+=(value_type c) | |
1638 { | |
1639 push_back(c); | |
1640 return *this; | |
1641 } | |
1642 | |
1643 flex_string& append(const flex_string& str) | |
1644 { return append(str, 0, npos); } | |
1645 | |
1646 flex_string& append(const flex_string& str, const size_type pos, | |
1647 size_type n) | |
1648 { | |
1649 const size_type sz = str.size(); | |
1650 Enforce(pos <= sz, (std::out_of_range*)0, ""); | |
1651 Procust(n, sz - pos); | |
1652 return append(str.c_str() + pos, n); | |
1653 } | |
1654 | |
1655 flex_string& append(const value_type* s, const size_type n) | |
1656 { | |
1657 #ifndef NDEBUG | |
1658 Invariant checker(*this); | |
1659 #endif | |
1660 if (IsAliasedRange(s, s + n)) | |
1661 { | |
1662 const size_type offset = s - &*begin(); | |
1663 Storage::reserve(size() + n); | |
1664 s = &*begin() + offset; | |
1665 } | |
1666 Storage::append(s, s+ n); | |
1667 return *this; | |
1668 } | |
1669 | |
1670 flex_string& append(const value_type* s) | |
1671 { 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 flex_string& assign(const value_type* s, size_type n) | |
1712 { | |
1713 #ifndef NDEBUG | |
1714 Invariant checker(*this); | |
1715 #endif | |
1716 if (size() >= n) | |
1717 { | |
1718 std::copy(s, s + n, begin()); | |
1719 resize(n); | |
1720 } | |
1721 else | |
1722 { | |
1723 const value_type *const s2 = s + size(); | |
1724 std::copy(s, s2, begin()); | |
1725 append(s2, n - size()); | |
1726 } | |
1727 return *this; | |
1728 } | |
1729 | |
1730 flex_string& assign(const value_type* s) | |
1731 { 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 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 bool IsAliasedRange(Iterator beginIterator, Iterator endIterator) | |
1801 { | |
1802 if(!empty() && beginIterator != endIterator) | |
1803 { | |
1804 typedef const typename std::iterator_traits<Iterator>::value_type * | |
1805 pointer; | |
1806 | |
1807 pointer myBegin(&*begin()); | |
1808 pointer myEnd(&*begin() + size()); | |
1809 pointer rangeBegin(DereferenceValidIterator(beginIterator)); | |
1810 | |
1811 const std::less_equal<pointer> less_equal = std::less_equal<pointer>(); | |
1812 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 occurences 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 const value_type* c_str() const | |
2131 { return Storage::c_str(); } | |
2132 | |
2133 const value_type* data() const | |
2134 { 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 size_type find (const value_type* s, size_type pos, size_type n) const | |
2143 { | |
2144 const size_type size_(size()); | |
2145 if (n + pos > size_) | |
2146 return npos; | |
2147 for (; pos < size_; ++pos) | |
2148 { | |
2149 if (traits_type::compare(&*begin() + pos, s, n) == 0) | |
2150 { | |
2151 return pos; | |
2152 } | |
2153 } | |
2154 return npos; | |
2155 } | |
2156 | |
2157 size_type find (const value_type* s, size_type pos = 0) const | |
2158 { 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 size_type find_first_of(const value_type* s, | |
2195 size_type pos, size_type n) const | |
2196 { | |
2197 if (pos > length() || n == 0) return npos; | |
2198 const_iterator i(begin() + pos), | |
2199 finish(end()); | |
2200 for (; i != finish; ++i) | |
2201 { | |
2202 if (traits_type::find(s, n, *i) != 0) | |
2203 { | |
2204 return i - begin(); | |
2205 } | |
2206 } | |
2207 return npos; | |
2208 } | |
2209 | |
2210 size_type find_first_of(const value_type* s, size_type pos = 0) const | |
2211 { return find_first_of(s, pos, traits_type::length(s)); } | |
2212 | |
2213 size_type find_first_of(value_type c, size_type pos = 0) const | |
2214 { 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 size_type find_last_of (const value_type* s, size_type pos, | |
2221 size_type n) const | |
2222 { | |
2223 if (!empty() && n > 0) | |
2224 { | |
2225 pos = Min(pos, length() - 1); | |
2226 const_iterator i(begin() + pos); | |
2227 for (;; --i) | |
2228 { | |
2229 if (traits_type::find(s, n, *i) != 0) | |
2230 { | |
2231 return i - begin(); | |
2232 } | |
2233 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 size_type find_last_of (value_type c, size_type pos = npos) const | |
2244 { 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 size_type find_first_not_of(const value_type* s, size_type pos, | |
2251 size_type n) const | |
2252 { | |
2253 if (pos < length()) | |
2254 { | |
2255 const_iterator | |
2256 i(begin() + pos), | |
2257 finish(end()); | |
2258 for (; i != finish; ++i) | |
2259 { | |
2260 if (traits_type::find(s, n, *i) == 0) | |
2261 { | |
2262 return i - begin(); | |
2263 } | |
2264 } | |
2265 } | |
2266 return npos; | |
2267 } | |
2268 | |
2269 size_type find_first_not_of(const value_type* s, | |
2270 size_type pos = 0) const | |
2271 { 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 size_type find_last_not_of(const value_type* s, size_type pos, | |
2281 size_type n) const | |
2282 { | |
2283 if (!empty()) | |
2284 { | |
2285 pos = Min(pos, size() - 1); | |
2286 const_iterator i(begin() + pos); | |
2287 for (;; --i) | |
2288 { | |
2289 if (traits_type::find(s, n, *i) == 0) | |
2290 { | |
2291 return i - begin(); | |
2292 } | |
2293 if (i == begin()) break; | |
2294 } | |
2295 } | |
2296 return npos; | |
2297 } | |
2298 | |
2299 size_type find_last_not_of(const value_type* s, | |
2300 size_type pos = npos) const | |
2301 { return find_last_not_of(s, pos, traits_type::length(s)); } | |
2302 | |
2303 size_type find_last_not_of (value_type c, size_type pos = npos) const | |
2304 { return find_last_not_of(&c, pos, 1); } | |
2305 | |
2306 flex_string substr(size_type pos = 0, size_type n = npos) const | |
2307 { | |
2308 Enforce(pos <= size(), (std::out_of_range*)0, ""); | |
2309 return flex_string(data() + pos, Min(n, size() - pos)); | |
2310 } | |
2311 | |
2312 std::ptrdiff_t compare(const flex_string& str) const | |
2313 { | |
2314 // FIX due to Goncalo N M de Carvalho July 18, 2005 | |
2315 return compare(0, size(), str); | |
2316 } | |
2317 | |
2318 std::ptrdiff_t compare(size_type pos1, size_type n1, | |
2319 const flex_string& str) const | |
2320 { 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 std::ptrdiff_t compare(size_type pos1, size_type n1, | |
2332 const value_type* s, size_type n2) const | |
2333 { | |
2334 Enforce(pos1 <= size(), (std::out_of_range*)0, ""); | |
2335 Procust(n1, size() - pos1); | |
2336 const int r = traits_type::compare(pos1 + data(), s, Min(n1, n2)); | |
2337 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 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 const size_type n1(size()), n2(traits_type::length(s)); | |
2353 const int r = traits_type::compare(data(), s, Min(n1, n2)); | |
2354 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 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 flex_string<E, T, A, S> result; | |
2364 result.reserve(lhs.size() + rhs.size()); | |
2365 result.append(lhs).append(rhs); | |
2366 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 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 flex_string<E, T, A, S> result; | |
2401 const size_type len = traits_type::length(rhs); | |
2402 result.reserve(lhs.size() + len); | |
2403 result.append(lhs).append(rhs, len); | |
2404 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 inline bool operator==(const flex_string<E, T, A, S>& lhs, | |
2420 const flex_string<E, T, A, S>& rhs) | |
2421 { return lhs.compare(rhs) == 0; } | |
2422 | |
2423 template <typename E, class T, class A, class S> | |
2424 inline bool operator==(const typename flex_string<E, T, A, S>::value_type* lhs, | |
2425 const flex_string<E, T, A, S>& rhs) | |
2426 { return rhs == lhs; } | |
2427 | |
2428 template <typename E, class T, class A, class S> | |
2429 inline bool operator==(const flex_string<E, T, A, S>& lhs, | |
2430 const typename flex_string<E, T, A, S>::value_type* rhs) | |
2431 { return lhs.compare(rhs) == 0; } | |
2432 | |
2433 template <typename E, class T, class A, class S> | |
2434 inline bool operator!=(const flex_string<E, T, A, S>& lhs, | |
2435 const flex_string<E, T, A, S>& rhs) | |
2436 { 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 inline bool operator!=(const flex_string<E, T, A, S>& lhs, | |
2445 const typename flex_string<E, T, A, S>::value_type* rhs) | |
2446 { return !(lhs == rhs); } | |
2447 | |
2448 template <typename E, class T, class A, class S> | |
2449 inline bool operator<(const flex_string<E, T, A, S>& lhs, | |
2450 const flex_string<E, T, A, S>& rhs) | |
2451 { 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 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 { 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_ |