source: mainline/uspace/lib/cpp/include/impl/string.hpp@ b0b46d59

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b0b46d59 was b0b46d59, checked in by Dzejrou <dzejrou@…>, 7 years ago

cpp: implemented most of std::string::replace

  • Property mode set to 100644
File size: 34.8 KB
Line 
1/*
2 * Copyright (c) 2017 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_STRING
30#define LIBCPP_STRING
31
32#include <initializer_list>
33#include <iosfwd>
34#include <cstdio>
35#include <cstdlib>
36#include <cstring>
37
38namespace std
39{
40
41 /**
42 * 21.2, char_traits:
43 */
44
45 template<class Char>
46 struct char_traits;
47
48 /**
49 * 21.2.3, char_traits specializations:
50 */
51
52 template<>
53 struct char_traits<char>
54 {
55 using char_type = char;
56 using int_type = int;
57 using off_type = streamoff;
58 using pos_type = streampos;
59 /* using state_type = mbstate_t; */
60
61 static void assign(char_type& c1, char_type& c2) noexcept
62 {
63 c1 = c2;
64 }
65
66 static constexpr bool eq(char_type c1, char_type c2) noexcept
67 {
68 return c1 == c2;
69 }
70
71 static constexpr bool lt(char_type c1, char_type c2) noexcept
72 {
73 return c1 < c2;
74 }
75
76 static int compare(const char_type* s1, const char_type* s2, size_t n)
77 {
78 return std::str_lcmp(s1, s2, n);
79 }
80
81 static size_t length(const char_type* s)
82 {
83 return std::str_size(s) + 1;
84 }
85
86 static const char_type* find(const char_type* s, size_t n, const char_type& c)
87 {
88 size_t i{};
89 while (i++ < n)
90 {
91 if (s[i] == c)
92 return s + i;
93 }
94
95 return nullptr;
96 }
97
98 static char_type* move(char_type* s1, const char_type* s2, size_t n)
99 {
100 return static_cast<char_type*>(memmove(s1, s2, n));
101 }
102
103 static char_type* copy(char_type* s1, const char_type* s2, size_t n)
104 {
105 return static_cast<char_type*>(memcpy(s1, s2, n));
106 }
107
108 static char_type* assign(char_type* s, size_t n, char_type c)
109 {
110 /**
111 * Note: Even though memset accepts int as its second argument,
112 * the actual implementation assigns that int to a dereferenced
113 * char pointer.
114 */
115 return static_cast<char_type*>(memset(s, static_cast<int>(c), n));
116 }
117
118 static constexpr int_type not_eof(int_type c) noexcept
119 {
120 if (!eq_int_type(c, eof()))
121 return c;
122 else
123 return to_int_type('a'); // We just need something that is not eof.
124 }
125
126 static constexpr char_type to_char_type(int_type c) noexcept
127 {
128 return static_cast<char_type>(c);
129 }
130
131 static constexpr int_type to_int_type(char_type c) noexcept
132 {
133 return static_cast<int_type>(c);
134 }
135
136 static constexpr bool eq_int_type(int_type c1, int_type c2) noexcept
137 {
138 return c1 == c2;
139 }
140
141 static constexpr int_type eof() noexcept
142 {
143 return static_cast<int_type>(EOF);
144 }
145 };
146
147 template<>
148 struct char_traits<char16_t>
149 { /* TODO: implement */ };
150
151 template<>
152 struct char_traits<char32_t>
153 { /* TODO: implement */ };
154
155 template<>
156 struct char_traits<wchar_t>
157 {
158 using char_type = wchar_t;
159 using int_type = wint_t;
160 using off_type = streamoff;
161 using pos_type = wstreampos;
162 /* using state_type = mbstate_t; */
163
164 static void assign(char_type& c1, char_type& c2) noexcept
165 {
166 c1 = c2;
167 }
168
169 static constexpr bool eq(char_type c1, char_type c2) noexcept
170 {
171 return c1 == c2;
172 }
173
174 static constexpr bool lt(char_type c1, char_type c2) noexcept
175 {
176 return c1 < c2;
177 }
178
179 static int compare(const char_type* s1, const char_type* s2, size_t n)
180 {
181 return std::wstr_lcmp(s1, s2, n);
182 }
183
184 static size_t length(const char_type* s)
185 {
186 return std::wstr_size(s) + 1;
187 }
188
189 static const char_type* find(const char_type* s, size_t n, const char_type& c)
190 {
191 size_t i{};
192 while (i++ < n)
193 {
194 if (s[i] == c)
195 return s + i;
196 }
197
198 return nullptr;
199 }
200
201 static char_type* move(char_type* s1, const char_type* s2, size_t n)
202 {
203 return static_cast<char_type*>(memmove(s1, s2, n * sizeof(wchar_t)));
204 }
205
206 static char_type* copy(char_type* s1, const char_type* s2, size_t n)
207 {
208 return static_cast<char_type*>(memcpy(s1, s2, n * sizeof(wchar_t)));
209 }
210
211 static char_type* assign(char_type* s, size_t n, char_type c)
212 {
213 return static_cast<char_type*>(memset(s, static_cast<int>(c), n * sizeof(wchar_t)));
214 }
215
216 static constexpr int_type not_eof(int_type c) noexcept
217 {
218 if (!eq_int_type(c, eof()))
219 return c;
220 else
221 return to_int_type(L'a'); // We just need something that is not eof.
222 }
223
224 static constexpr char_type to_char_type(int_type c) noexcept
225 {
226 return static_cast<char_type>(c);
227 }
228
229 static constexpr int_type to_int_type(char_type c) noexcept
230 {
231 return static_cast<int_type>(c);
232 }
233
234 static constexpr bool eq_int_type(int_type c1, int_type c2) noexcept
235 {
236 return c1 == c2;
237 }
238
239 static constexpr int_type eof() noexcept
240 {
241 return static_cast<int_type>(EOF);
242 }
243 };
244
245 /**
246 * 21.4, class template basic_string:
247 */
248
249 template<class Char, class Traits = char_traits<Char>,
250 class Allocator = allocator<Char>>
251 class basic_string
252 {
253 public:
254 using traits_type = Traits;
255 using value_type = typename traits_type::char_type;
256 using allocator_type = Allocator;
257 using size_type = typename allocator_traits<allocator_type>::size_type;
258 using difference_type = typename allocator_traits<allocator_type>::difference_type;
259
260 using reference = value_type&;
261 using const_reference = const value_type&;
262 using pointer = allocator_traits<allocator_type>::pointer;
263 using const_pointer = allocator_traits<allocator_type>::const_pointer;
264
265 using iterator = pointer;
266 using const_iterator = const_pointer;
267 using reverse_iterator = std::reverse_iterator<iterator>;
268 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
269
270 static constexpr size_type npos = -1;
271
272 /**
273 * 21.4.2, construct/copy/destroy:
274 */
275 basic_string() noexcept
276 : basic_string(allocator_type{})
277 { /* DUMMY BODY */ }
278
279 explicit basic_string(const allocator_type& alloc)
280 : data_{}, size_{}, capacity_{}, allocator_{alloc}
281 {
282 /**
283 * Postconditions:
284 * data() = non-null copyable value that can have 0 added to it.
285 * size() = 0
286 * capacity() = unspecified
287 */
288 data_ = allocator_.allocate(initial_capacity_);
289 capacity_ = initial_capacity_;
290 }
291
292 basic_string(const basic_string& other)
293 : data_{}, size_{other.size_}, capacity_{other.capacity_},
294 allocator_{other.allocator_}
295 {
296 init_(other.data(), size_);
297 }
298
299 basic_string(basic_string&& other)
300 : data_{other.data_}, size_{other.size_},
301 capacity_{other.capacity_}, allocator_{move(other.allocator_)}
302 {
303 other.data_ = nullptr;
304 other.size_ = 0;
305 other.capacity_ = 0;
306 }
307
308 basic_string(const basic_string& other, size_type pos, size_type n = npos,
309 const allocator_type& alloc = allocator_type{})
310 : data_{}, size_{}, capacity_{}, allocator_{alloc}
311 {
312 // TODO: if pos < other.size() throw out_of_range.
313 auto len = min(n, other.size() - pos);
314 init_(other.data() + pos, len);
315 }
316
317 basic_string(const value_type* str, size_type n, const allocator_type& alloc = allocator{})
318 : data_{}, size_{n}, capacity_{n}, allocator_{alloc}
319 {
320 init_(str, size_);
321 }
322
323 basic_string(const value_type* str, const allocator_type& alloc = allocator{})
324 : data_{}, size_{}, capacity_{}, allocator_{alloc}
325 {
326 init_(str, traits_type::length(str));
327 }
328
329 basic_string(size_type n, value_type c, const allocator_type& alloc = allocator{})
330 : data_{}, size_{n}, capacity_{n}, allocator_{alloc}
331 {
332 data_ = allocator_.allocate(capacity_);
333 for (size_type i = 0; i < size_; ++i)
334 traits_type::asign(data_[i], c);
335 ensure_null_terminator_();
336 }
337
338 template<class InputIterator>
339 basic_string(InputIterator first, InputIterator last,
340 const allocator_type& alloc = allocator{})
341 : data_{}, size_{}, capacity_{}, allocator_{alloc}
342 {
343 if constexpr (is_integral_t<InputIterator>)
344 { // Required by the standard.
345 size_ = static_cast<size_type>(first);
346 capacity_ = size_;
347 data_ = allocator_.allocate(capacity_);
348
349 for (size_type i = 0; i < size_; ++i)
350 traits_type::assign(data_[i], static_cast<value_type>(last));
351 ensure_null_terminator_();
352 }
353 else
354 {
355 auto len = static_cast<size_type>(last - first);
356 init_(static_cast<value_type*>(first), len);
357 }
358 }
359
360 basic_string(initializer_list<value_type> init, const allocator_type& alloc = allocator{})
361 : basic_string{init.begin(), init.size(), alloc}
362 { /* DUMMY BODY */ }
363
364 basic_string(const basic_string& other, const allocator_type& alloc)
365 : data_{}, size_{other.size_}, capacity_{other.capacity_}, allocator_{alloc}
366 {
367 init_(other.data(), size_);
368 }
369
370 basic_string(basic_string&& other, const allocator_type& alloc)
371 : data_{other.data_}, size_{other.size_}, capacity_{other.capacity_}, allocator_{alloc}
372 {
373 other.data_ = nullptr;
374 other.size_ = 0;
375 other.capacity_ = 0;
376 }
377
378 ~basic_string()
379 {
380 allocator_.deallocate(data_, capacity_);
381 }
382
383 basic_string& operator=(const basic_string& other)
384 {
385 if (this != &other)
386 {
387 basic_string tmp{other};
388 swap(tmp);
389 }
390 }
391
392 basic_string& operator=(basic_string&& other)
393 noexcept(allocator_traits<allocator_type>::propagate_on_container_move_assignment::value ||
394 allocator_traits<allocator_type>::is_always_equal::value)
395 {
396 if (this != &other)
397 swap(other);
398 }
399
400 basic_string& operator=(const value_type* other)
401 {
402 *this = basic_string{other};
403
404 return *this;
405 }
406
407 basic_string& operator=(value_type c)
408 {
409 *this = basic_string{1, c};
410
411 return *this;
412 }
413
414 basic_string& operator=(initializer_list<value_type> init)
415 {
416 *this = basic_string{init};
417
418 return *this;
419 }
420
421 /**
422 * 21.4.3, iterators:
423 */
424
425 iterator begin() noexcept
426 {
427 return &data_[0];
428 }
429
430 const_iterator begin() const noexcept
431 {
432 return &data_[0];
433 }
434
435 iterator end() noexcept
436 {
437 return begin() + size_;
438 }
439
440 const_iterator end() const noexcept
441 {
442 return begin() + size_;
443 }
444
445 reverse_iterator rbegin() noexcept
446 {
447 return make_reverse_iterator(end());
448 }
449
450 const_reverse_iterator rbegin() const noexcept
451 {
452 return make_reverse_iterator(cend());
453 }
454
455 reverse_iterator rend() noexcept
456 {
457 return make_reverse_iterator(begin());
458 }
459
460 const_reverse_iterator rend() const noexcept
461 {
462 return make_reverse_iterator(cbegin());
463 }
464
465 const_iterator cbegin() const noexcept
466 {
467 return &data_[0];
468 }
469
470 const_iterator cend() const noexcept
471 {
472 return cbegin() + size_;
473 }
474
475 const_reverse_iterator crbegin() const noexcept
476 {
477 return rbegin();
478 }
479
480 const_reverse_iterator crend() const noexcept
481 {
482 return rend();
483 }
484
485 /**
486 * 21.4.4, capacity:
487 */
488
489 size_type size() const noexcept
490 {
491 return size_;
492 }
493
494 size_type length() const noexcept
495 {
496 return size_;
497 }
498
499 size_type max_size() const noexcept
500 {
501 return allocator_traits<allocator_type>::max_size(allocator_);
502 }
503
504 void resize(size_type new_size, value_type c)
505 {
506 // TODO: if new_size > max_size() throw length_error.
507 if (new_size > size_)
508 {
509 ensure_free_space_(new_size - size_ + 1);
510 for (size_type i = size_; i < new_size; ++i)
511 traits_type::assign(data_[i], i);
512 }
513
514 size_ = new_size;
515 ensure_null_terminator_();
516 }
517
518 void resize(size_type new_size)
519 {
520 resize(new_size, value_type{});
521 }
522
523 size_type capacity() const noexcept
524 {
525 return capacity_;
526 }
527
528 void reserve(size_type new_capacity = 0)
529 {
530 // TODO: if new_capacity > max_size() throw
531 // length_error (this function shall have no
532 // effect in such case)
533 if (new_capacity > capacity_)
534 resize_with_copy_(size_, new_capacity);
535 else if (new_capacity < capacity)
536 shrink_to_fit(); // Non-binding request, but why not.
537 }
538
539 void shrink_to_fit()
540 {
541 if (size_ != capacity_)
542 resize_with_copy_(size_);
543 }
544
545 void clear() noexcept
546 {
547 size_ = 0;
548 }
549
550 bool empty() const noexcept
551 {
552 return size_ == 0;
553 }
554
555 /**
556 * 21.4.5, element access:
557 */
558
559 const_reference operator[](size_type idx) const
560 {
561 return data_[idx];
562 }
563
564 reference operator[](size_type idx)
565 {
566 return data_[idx];
567 }
568
569 const_reference at(size_type idx) const
570 {
571 // TODO: bounds checking
572 return data_[idx];
573 }
574
575 reference at(size_type idx)
576 {
577 // TODO: bounds checking
578 return data_[idx];
579 }
580
581 const_reference front() const
582 {
583 return at(0);
584 }
585
586 reference front()
587 {
588 return at(0);
589 }
590
591 const_reference back() const
592 {
593 return at(size_ - 1);
594 }
595
596 reference back()
597 {
598 return at(size_ - 1);
599 }
600
601 /**
602 * 21.4.6, modifiers:
603 */
604
605 basic_string& operator+=(const basic_string& str)
606 {
607 return append(str);
608 }
609
610 basic_string& operator+=(const value_type* str)
611 {
612 return append(str);
613 }
614
615 basic_string& operator+=(value_type c)
616 {
617 push_back(c);
618 return *this;
619 }
620
621 basic_string& operator+=(initializer_list<value_type> init)
622 {
623 return append(init.begin(), init.size());
624 }
625
626 basic_string& append(const basic_string& str)
627 {
628 return append(str.data(), str.size());
629 }
630
631 basic_string& append(const basic_string& str, size_type pos
632 size_type n = npos)
633 {
634 if (pos < str.size())
635 {
636 auto len = min(n, str.size() - pos);
637 ensure_free_space_(len);
638
639 return append(str.data() + pos, len);
640 }
641 // TODO: Else throw out_of_range.
642 }
643
644 basic_string& append(const value_type* str, size_type n)
645 {
646 // TODO: if (size_ + n > max_size()) throw length_error
647 ensure_free_space_(n);
648 traits_type::copy(data_ + size_, str, n);
649 size_ += n;
650 ensure_null_terminator_();
651
652 return *this;
653 }
654
655 basic_string& append(const value_type* str)
656 {
657 return append(str, traits_type::length(str));
658 }
659
660 basic_string& append(size_type n, value_type c)
661 {
662 return append(basic_string(n, c));
663 }
664
665 template<class InputIterator>
666 basic_string& append(InputIterator first, InputIterator last)
667 {
668 return append(basic_string(frist, last));
669 }
670
671 basic_string& append(initializer_list<value_type> init)
672 {
673 return append(init.begin(), init.size());
674 }
675
676 void push_back(value_type c)
677 {
678 ensure_free_space_(1);
679 traits_type::assign(data_[size_++], c);
680 ensure_null_terminator_();
681 }
682
683 basic_string& assign(const basic_string& str)
684 {
685 return assign(str, 0, npos);
686 }
687
688 basic_string& assign(basic_string&& str)
689 {
690 swap(str);
691
692 return *this;
693 }
694
695 basic_string& assign(const basic_string& str, size_type pos,
696 size_type n = npos)
697 {
698 if (pos < str.size())
699 {
700 auto len = min(n, str.size() - pos);
701 ensure_free_space_(len);
702
703 return assign(str.data() + pos, len);
704 }
705 // TODO: Else throw out_of_range.
706 }
707
708 basic_string& assign(const value_type* str, size_type n)
709 {
710 // TODO: if (n > max_size()) throw length_error.
711 resize_without_copy_(n);
712 traits_type::copy(begin(), str, n);
713
714 return *this;
715 }
716
717 basic_string& assign(const value_type* str)
718 {
719 return assign(str, traits_type::length(str));
720 }
721
722 basic_string& assign(size_type n, value_type c)
723 {
724 return assign(basic_string(n, c));
725 }
726
727 template<class InputIterator>
728 basic_string& assign(InputIterator first, InputIterator last)
729 {
730 return assign(basic_string(first, last));
731 }
732
733 basic_string& assign(initializer_list<value_type> init)
734 {
735 return assign(init.begin(), init.size());
736 }
737
738 basic_string& insert(size_type pos, const basic_string& str)
739 {
740 // TODO: if (pos > str.size()) throw out_of_range.
741 return insert(pos, str.data(), str.size());
742 }
743
744 basic_string& insert(size_type pos1, const basic_string& str,
745 size_type pos2, size_type n = npos)
746 {
747 // TODO: if (pos1 > size() or pos2 > str.size()) throw
748 // out_of_range.
749 auto len = min(n, str.size() - pos2);
750
751 return insert(pos1, str.data() + pos2, len);
752 }
753
754 basic_string& insert(size_type pos, const value_type* str, size_type n)
755 {
756 ensure_free_space_(size_ + n);
757 copy_backward_(begin() + pos, end(), end() + n);
758 copy_(begin() + pos, begin() + pos + n, str);
759
760 return *this;
761 }
762
763 basic_string& insert(size_type pos, const value_type* str)
764 {
765 return insert(pos, str, traits_type::length(str));
766 }
767
768 basic_string& insert(size_type pos, size_type n, value_type c)
769 {
770 return insert(pos, basic_string(n, c));
771 }
772
773 iterator insert(const_iterator pos, value_type c)
774 {
775 auto idx = static_cast<size_type>(pos - begin());
776
777 ensure_free_space_(1);
778 copy_backward_(begin() + pos, end(), end() + 1);
779 ensure_null_terminator_();
780
781 return begin() + idx;
782 }
783
784 iterator insert(const_iterator pos, size_type n, value_type c)
785 {
786 if (n == 0)
787 return const_cast<iterator>(pos);
788
789 auto idx = static_cast<size_type>(pos - begin());
790
791 ensure_free_space_(n);
792 copy_backward_(begin() + pos, end(), end() + n);
793
794 auto it = position;
795 for (size_type i = 0; i < n; ++i)
796 type_traits::assign(*it++, c);
797 ensure_null_terminator_();
798
799 return begin() + idx;
800 }
801
802 template<class InputIterator>
803 iterator insert(const_iterator pos, InputIterator first,
804 InputIterator last)
805 {
806 return insert(pos - begin(), basic_string(first, last));
807 }
808
809 iterator insert(const_iterator pos, initializer_list<value_type> init)
810 {
811 return insert(pos, init.begin(), init.end());
812 }
813
814 basic_string& erase(size_type pos = 0; size_type n = npos)
815 {
816 auto len = min(n, size_ - pos);
817 copy_(begin() + pos + n, end(), begin() + pos);
818 size_ -= len;
819 ensure_null_terminator_();
820 }
821
822 iterator erase(const_iterator pos);
823
824 iterator erase(const_iterator pos, const_iterator last);
825
826 void pop_back()
827 {
828 --size_;
829 ensure_null_terminator_();
830 }
831
832 basic_string& replace(size_type pos, size_type n, const basic_string& str)
833 {
834 // TODO: throw out_of_range if pos > size()
835 return replace(pos, n, str.data(), str.size());
836 }
837
838 basic_string& replace(size_type pos1, size_type n1, const basic_string& str
839 size_type pos2, size_type n2 = npos)
840 {
841 // TODO: throw out_of_range if pos1 > size() or pos2 > str.size()
842 auto len = min(n2, str.size() - pos2);
843 return replace(pos1, n1, str.data() + pos2, len);
844 }
845
846 basic_string& replace(size_type pos, size_type n1, const value_type* str,
847 size_type n2)
848 {
849 // TODO: format and comment this properly
850 // TODO: throw out_of_range if pos > size()
851 auto len = min(n1, size_ - pos);
852 // TODO: if size() - len > max_size() - n2 throw length_error
853 basic_string tmp{};
854 tmp.resize_without_copy_(size_ - len + n2);
855 copy_(begin(), begin() + pos, tmp.begin());
856 traits_type::copy(tmp.begin() + pos + 1, str, n2);
857 copy_(begin() + pos + len, end(), tmp.begin() + pos + 1 + n2);
858 swap(tmp);
859 return *this;
860 }
861
862 basic_string& replace(size_type pos, size_type n, const value_type* str)
863 {
864 return replace(pos, n, str, traits_type::length(str));
865 }
866
867 basic_string& replace(size_type pos, size_type n1, size_type n2,
868 value_type c)
869 {
870 return replace(pos, n1, basic_string(n2, c));
871 }
872
873 basic_string& replace(const_iterator i1, const_iterator i2,
874 const basic_string& str)
875 {
876 return replace(i1 - begin(), i2 - i1, str);
877 }
878
879 basic_string& replace(const_iterator i1, const_iterator i2,
880 const value_type* str, size_type n)
881 {
882 return replace(i1 - begin(), i2 - i1, s, n);
883 }
884
885 basic_string& replace(const_iterator i1, const_iterator i2,
886 const value_type* str)
887 {
888 return replace(i1 - begin(), i2 - i1, str, traits_type::length(str));
889 }
890
891 basic_string& replace(const_iterator i1, const_iterator i2,
892 size_type n, value_type c)
893 {
894 return replace(i1 - begin(), i2 - i1, basic_string(n, c));
895 }
896
897 template<class InputIterator>
898 basic_string& replace(const_iterator i1, const_iterator i2,
899 InputIterator j1, InputIterator j2)
900 {
901 return replace(i1 - begin(), i2 - i1, basic_string(j1, j2));
902 }
903
904 basic_string& replace(const_iterator i1, const_iterator i2,
905 initializer_list<value_type> init)
906 {
907 return replace(i1 - begin(), i2 - i1, init.begin(), init.size());
908 }
909
910 size_type copy(value_type* str, size_type n, size_type pos = 0) const;
911
912 void swap(basic_string& other)
913 noexcept(allocator_traits<allocator_type>::propagate_on_container_swap::value ||
914 allocator_traits<allocator_type>::is_always_equal)
915 {
916 std::swap(data_, other.data_);
917 std::swap(size_, other.size_);
918 std::swap(capacity_, other.capacity_);
919 }
920
921 /**
922 * 21.4.7, string operations:
923 */
924
925 const value_type* c_str() const noexcept
926 {
927 return data_;
928 }
929
930 const value_type* data() const noexcept
931 {
932 return data_;
933 }
934
935 allocator_type get_allocator() const noexcept
936 {
937 return allocator_type{allocator_};
938 }
939
940 size_type find(const basic_string& str, size_type pos = 0) const noexcept;
941
942 size_type find(const value_type* str, size_type pos, size_type n) const;
943
944 size_type find(const value_type* str, size_type pos = 0) const;
945
946 size_type find(value_type c, size_type pos = 0) const;
947
948 size_type rfind(const basic_string& str, size_type pos = npos) const noexcept;
949
950 size_type rfind(const value_type* str, size_type pos, size_type n) const;
951
952 size_type rfind(const value_type* str, size_type pos = npos) const;
953
954 size_type rfind(value_type c, size_type pos = npos) const;
955
956 size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept;
957
958 size_type find_first_of(const value_type* str, size_type pos, size_type n) const;
959
960 size_type find_first_of(const value_type* str, size_type pos = 0) const;
961
962 size_type find_first_of(value_type c, size_type pos = 0) const;
963
964 size_type find_last_of(const basic_string& str, size_type pos = npos) const noexcept;
965
966 size_type find_last_of(const value_type* str, size_type pos, size_type n) const;
967
968 size_type find_last_of(const value_type* str, size_type pos = npos) const;
969
970 size_type find_last_of(value_type c, size_type pos = npos) const;
971
972 size_type find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept;
973
974 size_type find_first_not_of(const value_type* str, size_type pos, size_type n) const;
975
976 size_type find_first_not_of(const value_type* str, size_type pos = 0) const;
977
978 size_type find_first_not_of(value_type c, size_type pos = 0) const;
979
980 size_type find_last_not_of(const basic_string& str, size_type pos = npos) const noexcept;
981
982 size_type find_last_not_of(const value_type* str, size_type pos, size_type n) const;
983
984 size_type find_last_not_of(const value_type* str, size_type pos = npos) const;
985
986 size_type find_last_not_of(value_type c, size_type pos = npos) const;
987
988 basic_string substr(size_type pos = 0, size_type n = npos) const;
989
990 int compare(const basic_string& other) const noexcept;
991
992 int compare(size_type pos, size_type n, const basic_string& other) const;
993
994 int compare(size_type pos1, size_type n1, const basic_string& other,
995 size_type pos2, size_type n2 = npos) const;
996
997 int compare(const value_type* other) const;
998
999 int compare(size_type pos, size_type n, const value_type* other) const;
1000
1001 int compare(size_type pos1, size_type n1,
1002 const value_type* other, size_type n2) const;
1003
1004 private:
1005 value_type* data_;
1006 size_type size_;
1007 size_type capacity_;
1008 allocator_type allocator_;
1009
1010 /**
1011 * Arbitrary value, standard just requires
1012 * data() to have some capacity.
1013 * (Well, we could've done data_ = &data_ and
1014 * set capacity to 0, but that would be too cryptic.)
1015 */
1016 static constexpr size_type default_capacity_{4}
1017
1018 void init_(const value_type* str, size_type size)
1019 {
1020 if (data_)
1021 allocator_.deallocate(data_, capacity_);
1022
1023 size_ = size;
1024 capacity_ = size;
1025
1026 data_ = allocator_.allocate(capacity_);
1027 traits_type::copy(data_, str, size);
1028 ensure_null_terminator_();
1029 }
1030
1031 size_type next_capacity_(size_type hint = 0) const noexcept
1032 {
1033 if (hint != 0)
1034 return max(capacity_ * 2, hint);
1035 else
1036 return max(capacity_ * 2, 2ul);
1037 }
1038
1039 void ensure_free_space_(size_type n)
1040 {
1041 /**
1042 * Note: We cannot use reserve like we
1043 * did in vector, because in string
1044 * reserve can cause shrinking.
1045 */
1046 if (size_ + 1 + n > capacity)
1047 resize_with_copy_(size_, max(size_ + 1 + n, next_capacity_()));
1048 }
1049
1050 void resize_without_copy_(size_type capacity)
1051 {
1052 if (data_)
1053 allocator_.deallocate(data_, capacity_);
1054
1055 data_ = allocator_.allocate(capacity);
1056 size_ = 0;
1057 capacity_ = capacity;
1058 ensure_null_terminator_();
1059 }
1060
1061 void resize_with_copy_(size_type size, size_type capacity)
1062 {
1063 if(capacity_ == 0 || capacity_ < capacity)
1064 {
1065 auto new_data = allocator_.allocate(capacity);
1066
1067 auto to_copy = min(size, size_);
1068 traits_type::move(new_data, data_, to_copy);
1069
1070 std::swap(data_, new_data);
1071
1072 allocator_.deallocate(new_data, capacity_);
1073 }
1074
1075 capacity_ = capacity;
1076 size_ = size;
1077 ensure_null_terminator_();
1078 }
1079
1080 iterator copy_(const_iterator first, const_iterator last,
1081 iterator result)
1082 {
1083 while (first != last)
1084 traits_type::assign(*result++, *first++);
1085
1086 ensure_null_terminator_();
1087 return result;
1088 }
1089
1090 iterator copy_backward_(const_iterator first, const_iterator last,
1091 iterator result)
1092 {
1093 while (last-- != first)
1094 traits_type::assign(*result--, *last);
1095
1096 ensure_null_terminator_();
1097 return result;
1098 }
1099
1100 void ensure_null_terminator_()
1101 {
1102 traits_type::assign(data_[size_], value_type{});
1103 }
1104 };
1105}
1106
1107#endif
Note: See TracBrowser for help on using the repository browser.