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
RevLine 
[52d025c]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 {
[681fdcca]83 return std::str_size(s) + 1;
[52d025c]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 {
[681fdcca]186 return std::wstr_size(s) + 1;
[52d025c]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 {
[177a576]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;
[52d025c]259
[177a576]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;
[52d025c]264
[177a576]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>;
[52d025c]269
[177a576]270 static constexpr size_type npos = -1;
[52d025c]271
[177a576]272 /**
273 * 21.4.2, construct/copy/destroy:
274 */
275 basic_string() noexcept
276 : basic_string(allocator_type{})
277 { /* DUMMY BODY */ }
[52d025c]278
[681fdcca]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 }
[52d025c]291
[681fdcca]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 }
[52d025c]298
[681fdcca]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 }
[52d025c]307
[177a576]308 basic_string(const basic_string& other, size_type pos, size_type n = npos,
[681fdcca]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 }
[52d025c]316
[681fdcca]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 }
[52d025c]322
[681fdcca]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 }
[52d025c]328
[681fdcca]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 }
[52d025c]337
[177a576]338 template<class InputIterator>
339 basic_string(InputIterator first, InputIterator last,
[681fdcca]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 }
[52d025c]359
[681fdcca]360 basic_string(initializer_list<value_type> init, const allocator_type& alloc = allocator{})
361 : basic_string{init.begin(), init.size(), alloc}
362 { /* DUMMY BODY */ }
[52d025c]363
[681fdcca]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 }
[52d025c]369
[681fdcca]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 }
[52d025c]377
[681fdcca]378 ~basic_string()
379 {
380 allocator_.deallocate(data_, capacity_);
381 }
[52d025c]382
[681fdcca]383 basic_string& operator=(const basic_string& other)
384 {
385 if (this != &other)
386 {
387 basic_string tmp{other};
388 swap(tmp);
389 }
390 }
[52d025c]391
[177a576]392 basic_string& operator=(basic_string&& other)
393 noexcept(allocator_traits<allocator_type>::propagate_on_container_move_assignment::value ||
[681fdcca]394 allocator_traits<allocator_type>::is_always_equal::value)
395 {
396 if (this != &other)
397 swap(other);
398 }
[52d025c]399
[681fdcca]400 basic_string& operator=(const value_type* other)
401 {
402 *this = basic_string{other};
[52d025c]403
[681fdcca]404 return *this;
405 }
[52d025c]406
[681fdcca]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 }
[52d025c]420
[177a576]421 /**
422 * 21.4.3, iterators:
423 */
[52d025c]424
[b08a62c]425 iterator begin() noexcept
426 {
427 return &data_[0];
428 }
[52d025c]429
[b08a62c]430 const_iterator begin() const noexcept
431 {
432 return &data_[0];
433 }
[52d025c]434
[b08a62c]435 iterator end() noexcept
436 {
437 return begin() + size_;
438 }
[52d025c]439
[b08a62c]440 const_iterator end() const noexcept
441 {
442 return begin() + size_;
443 }
[52d025c]444
[177a576]445 reverse_iterator rbegin() noexcept
446 {
[98c99ba]447 return make_reverse_iterator(end());
[177a576]448 }
[52d025c]449
[177a576]450 const_reverse_iterator rbegin() const noexcept
451 {
[98c99ba]452 return make_reverse_iterator(cend());
[177a576]453 }
[52d025c]454
[177a576]455 reverse_iterator rend() noexcept
456 {
[98c99ba]457 return make_reverse_iterator(begin());
[177a576]458 }
[52d025c]459
[177a576]460 const_reverse_iterator rend() const noexcept
461 {
[98c99ba]462 return make_reverse_iterator(cbegin());
[177a576]463 }
[52d025c]464
[b08a62c]465 const_iterator cbegin() const noexcept
466 {
467 return &data_[0];
468 }
[52d025c]469
[b08a62c]470 const_iterator cend() const noexcept
471 {
472 return cbegin() + size_;
473 }
[52d025c]474
[177a576]475 const_reverse_iterator crbegin() const noexcept
476 {
[98c99ba]477 return rbegin();
[177a576]478 }
[52d025c]479
[177a576]480 const_reverse_iterator crend() const noexcept
481 {
[98c99ba]482 return rend();
[177a576]483 }
[52d025c]484
[177a576]485 /**
486 * 21.4.4, capacity:
487 */
[52d025c]488
[b08a62c]489 size_type size() const noexcept
490 {
491 return size_;
492 }
[52d025c]493
[b08a62c]494 size_type length() const noexcept
495 {
496 return size_;
497 }
[52d025c]498
[b08a62c]499 size_type max_size() const noexcept
500 {
501 return allocator_traits<allocator_type>::max_size(allocator_);
502 }
[52d025c]503
[681fdcca]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 }
[52d025c]517
[681fdcca]518 void resize(size_type new_size)
519 {
520 resize(new_size, value_type{});
521 }
[52d025c]522
[b08a62c]523 size_type capacity() const noexcept
524 {
525 return capacity_;
526 }
[52d025c]527
[681fdcca]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 }
[52d025c]538
[681fdcca]539 void shrink_to_fit()
540 {
541 if (size_ != capacity_)
542 resize_with_copy_(size_);
543 }
[52d025c]544
[681fdcca]545 void clear() noexcept
546 {
547 size_ = 0;
548 }
[52d025c]549
[b08a62c]550 bool empty() const noexcept
551 {
552 return size_ == 0;
553 }
[52d025c]554
[177a576]555 /**
556 * 21.4.5, element access:
557 */
[52d025c]558
[b08a62c]559 const_reference operator[](size_type idx) const
560 {
561 return data_[idx];
562 }
[52d025c]563
[b08a62c]564 reference operator[](size_type idx)
565 {
566 return data_[idx];
567 }
[52d025c]568
[b08a62c]569 const_reference at(size_type idx) const
570 {
571 // TODO: bounds checking
572 return data_[idx];
573 }
[52d025c]574
[b08a62c]575 reference at(size_type idx)
576 {
577 // TODO: bounds checking
578 return data_[idx];
579 }
[52d025c]580
[b08a62c]581 const_reference front() const
582 {
583 return at(0);
584 }
[52d025c]585
[b08a62c]586 reference front()
587 {
588 return at(0);
589 }
[52d025c]590
[b08a62c]591 const_reference back() const
592 {
593 return at(size_ - 1);
594 }
[52d025c]595
[b08a62c]596 reference back()
597 {
598 return at(size_ - 1);
599 }
[52d025c]600
[177a576]601 /**
602 * 21.4.6, modifiers:
603 */
[52d025c]604
[681fdcca]605 basic_string& operator+=(const basic_string& str)
606 {
607 return append(str);
608 }
[52d025c]609
[681fdcca]610 basic_string& operator+=(const value_type* str)
611 {
612 return append(str);
613 }
[52d025c]614
[681fdcca]615 basic_string& operator+=(value_type c)
616 {
617 push_back(c);
618 return *this;
619 }
[52d025c]620
[681fdcca]621 basic_string& operator+=(initializer_list<value_type> init)
622 {
623 return append(init.begin(), init.size());
624 }
[52d025c]625
[681fdcca]626 basic_string& append(const basic_string& str)
627 {
628 return append(str.data(), str.size());
629 }
[52d025c]630
[177a576]631 basic_string& append(const basic_string& str, size_type pos
[681fdcca]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 }
[52d025c]643
[681fdcca]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_();
[52d025c]651
[681fdcca]652 return *this;
653 }
[52d025c]654
[681fdcca]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 }
[52d025c]664
[177a576]665 template<class InputIterator>
[681fdcca]666 basic_string& append(InputIterator first, InputIterator last)
667 {
668 return append(basic_string(frist, last));
669 }
[52d025c]670
[681fdcca]671 basic_string& append(initializer_list<value_type> init)
672 {
673 return append(init.begin(), init.size());
674 }
[52d025c]675
[681fdcca]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 }
[52d025c]682
[681fdcca]683 basic_string& assign(const basic_string& str)
684 {
685 return assign(str, 0, npos);
686 }
[52d025c]687
[681fdcca]688 basic_string& assign(basic_string&& str)
689 {
690 swap(str);
691
692 return *this;
693 }
[52d025c]694
[177a576]695 basic_string& assign(const basic_string& str, size_type pos,
[681fdcca]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 }
[52d025c]707
[681fdcca]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 }
[52d025c]716
[681fdcca]717 basic_string& assign(const value_type* str)
718 {
719 return assign(str, traits_type::length(str));
720 }
[52d025c]721
[681fdcca]722 basic_string& assign(size_type n, value_type c)
723 {
724 return assign(basic_string(n, c));
725 }
[52d025c]726
[177a576]727 template<class InputIterator>
[681fdcca]728 basic_string& assign(InputIterator first, InputIterator last)
729 {
730 return assign(basic_string(first, last));
731 }
[52d025c]732
[681fdcca]733 basic_string& assign(initializer_list<value_type> init)
734 {
735 return assign(init.begin(), init.size());
736 }
[52d025c]737
[681fdcca]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 }
[52d025c]743
[177a576]744 basic_string& insert(size_type pos1, const basic_string& str,
[681fdcca]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);
[52d025c]750
[681fdcca]751 return insert(pos1, str.data() + pos2, len);
752 }
[52d025c]753
[681fdcca]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);
[52d025c]759
[681fdcca]760 return *this;
761 }
[52d025c]762
[681fdcca]763 basic_string& insert(size_type pos, const value_type* str)
764 {
765 return insert(pos, str, traits_type::length(str));
766 }
[52d025c]767
[681fdcca]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 }
[52d025c]801
[177a576]802 template<class InputIterator>
803 iterator insert(const_iterator pos, InputIterator first,
[681fdcca]804 InputIterator last)
805 {
806 return insert(pos - begin(), basic_string(first, last));
807 }
[52d025c]808
[681fdcca]809 iterator insert(const_iterator pos, initializer_list<value_type> init)
810 {
811 return insert(pos, init.begin(), init.end());
812 }
[52d025c]813
[681fdcca]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 }
[52d025c]821
[177a576]822 iterator erase(const_iterator pos);
[52d025c]823
[177a576]824 iterator erase(const_iterator pos, const_iterator last);
[52d025c]825
[681fdcca]826 void pop_back()
827 {
828 --size_;
829 ensure_null_terminator_();
830 }
[52d025c]831
[b0b46d59]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 }
[52d025c]837
[177a576]838 basic_string& replace(size_type pos1, size_type n1, const basic_string& str
[b0b46d59]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 }
[52d025c]845
[177a576]846 basic_string& replace(size_type pos, size_type n1, const value_type* str,
[b0b46d59]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 }
[52d025c]861
[b0b46d59]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 }
[52d025c]866
[177a576]867 basic_string& replace(size_type pos, size_type n1, size_type n2,
[b0b46d59]868 value_type c)
869 {
870 return replace(pos, n1, basic_string(n2, c));
871 }
[52d025c]872
[177a576]873 basic_string& replace(const_iterator i1, const_iterator i2,
[b0b46d59]874 const basic_string& str)
875 {
876 return replace(i1 - begin(), i2 - i1, str);
877 }
[52d025c]878
[177a576]879 basic_string& replace(const_iterator i1, const_iterator i2,
[b0b46d59]880 const value_type* str, size_type n)
881 {
882 return replace(i1 - begin(), i2 - i1, s, n);
883 }
[52d025c]884
[177a576]885 basic_string& replace(const_iterator i1, const_iterator i2,
[b0b46d59]886 const value_type* str)
887 {
888 return replace(i1 - begin(), i2 - i1, str, traits_type::length(str));
889 }
[52d025c]890
[177a576]891 basic_string& replace(const_iterator i1, const_iterator i2,
[b0b46d59]892 size_type n, value_type c)
893 {
894 return replace(i1 - begin(), i2 - i1, basic_string(n, c));
895 }
[52d025c]896
[177a576]897 template<class InputIterator>
898 basic_string& replace(const_iterator i1, const_iterator i2,
[b0b46d59]899 InputIterator j1, InputIterator j2)
900 {
901 return replace(i1 - begin(), i2 - i1, basic_string(j1, j2));
902 }
[52d025c]903
[177a576]904 basic_string& replace(const_iterator i1, const_iterator i2,
[b0b46d59]905 initializer_list<value_type> init)
906 {
907 return replace(i1 - begin(), i2 - i1, init.begin(), init.size());
908 }
[52d025c]909
[177a576]910 size_type copy(value_type* str, size_type n, size_type pos = 0) const;
[52d025c]911
[177a576]912 void swap(basic_string& other)
913 noexcept(allocator_traits<allocator_type>::propagate_on_container_swap::value ||
[b08a62c]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 }
[52d025c]920
[177a576]921 /**
922 * 21.4.7, string operations:
923 */
[52d025c]924
[b08a62c]925 const value_type* c_str() const noexcept
926 {
927 return data_;
928 }
[52d025c]929
[b08a62c]930 const value_type* data() const noexcept
931 {
932 return data_;
933 }
[52d025c]934
[b08a62c]935 allocator_type get_allocator() const noexcept
936 {
937 return allocator_type{allocator_};
938 }
[52d025c]939
[177a576]940 size_type find(const basic_string& str, size_type pos = 0) const noexcept;
[52d025c]941
[177a576]942 size_type find(const value_type* str, size_type pos, size_type n) const;
[52d025c]943
[177a576]944 size_type find(const value_type* str, size_type pos = 0) const;
[52d025c]945
[177a576]946 size_type find(value_type c, size_type pos = 0) const;
[52d025c]947
[177a576]948 size_type rfind(const basic_string& str, size_type pos = npos) const noexcept;
[52d025c]949
[177a576]950 size_type rfind(const value_type* str, size_type pos, size_type n) const;
[52d025c]951
[177a576]952 size_type rfind(const value_type* str, size_type pos = npos) const;
[52d025c]953
[177a576]954 size_type rfind(value_type c, size_type pos = npos) const;
[52d025c]955
[177a576]956 size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept;
[52d025c]957
[177a576]958 size_type find_first_of(const value_type* str, size_type pos, size_type n) const;
[52d025c]959
[177a576]960 size_type find_first_of(const value_type* str, size_type pos = 0) const;
[52d025c]961
[177a576]962 size_type find_first_of(value_type c, size_type pos = 0) const;
[52d025c]963
[177a576]964 size_type find_last_of(const basic_string& str, size_type pos = npos) const noexcept;
[52d025c]965
[177a576]966 size_type find_last_of(const value_type* str, size_type pos, size_type n) const;
[52d025c]967
[177a576]968 size_type find_last_of(const value_type* str, size_type pos = npos) const;
[52d025c]969
[177a576]970 size_type find_last_of(value_type c, size_type pos = npos) const;
[52d025c]971
[177a576]972 size_type find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept;
[52d025c]973
[177a576]974 size_type find_first_not_of(const value_type* str, size_type pos, size_type n) const;
[52d025c]975
[177a576]976 size_type find_first_not_of(const value_type* str, size_type pos = 0) const;
[52d025c]977
[177a576]978 size_type find_first_not_of(value_type c, size_type pos = 0) const;
[52d025c]979
[177a576]980 size_type find_last_not_of(const basic_string& str, size_type pos = npos) const noexcept;
[52d025c]981
[177a576]982 size_type find_last_not_of(const value_type* str, size_type pos, size_type n) const;
[52d025c]983
[177a576]984 size_type find_last_not_of(const value_type* str, size_type pos = npos) const;
[52d025c]985
[177a576]986 size_type find_last_not_of(value_type c, size_type pos = npos) const;
[52d025c]987
[177a576]988 basic_string substr(size_type pos = 0, size_type n = npos) const;
[52d025c]989
[177a576]990 int compare(const basic_string& other) const noexcept;
[52d025c]991
[177a576]992 int compare(size_type pos, size_type n, const basic_string& other) const;
[52d025c]993
[177a576]994 int compare(size_type pos1, size_type n1, const basic_string& other,
995 size_type pos2, size_type n2 = npos) const;
[52d025c]996
[177a576]997 int compare(const value_type* other) const;
[52d025c]998
[177a576]999 int compare(size_type pos, size_type n, const value_type* other) const;
[52d025c]1000
[177a576]1001 int compare(size_type pos1, size_type n1,
1002 const value_type* other, size_type n2) const;
[b08a62c]1003
1004 private:
1005 value_type* data_;
1006 size_type size_;
1007 size_type capacity_;
1008 allocator_type allocator_;
[681fdcca]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 }
[52d025c]1104 };
1105}
1106
1107#endif
Note: See TracBrowser for help on using the repository browser.