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

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

cpp: minor refactoring, fixed some bugs found by the replace tests

  • Property mode set to 100644
File size: 44.0 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
[dc0fff11]32#include <algorithm>
[52d025c]33#include <iosfwd>
[dc0fff11]34#include <iterator>
[52d025c]35#include <cstdio>
36#include <cstdlib>
37#include <cstring>
[dc0fff11]38#include <memory>
39#include <utility>
40
41#include <initializer_list>
[52d025c]42
43namespace std
44{
45
46 /**
47 * 21.2, char_traits:
48 */
49
50 template<class Char>
51 struct char_traits;
52
53 /**
54 * 21.2.3, char_traits specializations:
55 */
56
57 template<>
58 struct char_traits<char>
59 {
60 using char_type = char;
61 using int_type = int;
62 using off_type = streamoff;
63 using pos_type = streampos;
64 /* using state_type = mbstate_t; */
65
[2d302d6]66 static void assign(char_type& c1, const char_type& c2) noexcept
[52d025c]67 {
68 c1 = c2;
69 }
70
71 static constexpr bool eq(char_type c1, char_type c2) noexcept
72 {
73 return c1 == c2;
74 }
75
76 static constexpr bool lt(char_type c1, char_type c2) noexcept
77 {
78 return c1 < c2;
79 }
80
81 static int compare(const char_type* s1, const char_type* s2, size_t n)
82 {
83 return std::str_lcmp(s1, s2, n);
84 }
85
86 static size_t length(const char_type* s)
87 {
[2d302d6]88 return std::str_size(s);
[52d025c]89 }
90
91 static const char_type* find(const char_type* s, size_t n, const char_type& c)
92 {
93 size_t i{};
94 while (i++ < n)
95 {
96 if (s[i] == c)
97 return s + i;
98 }
99
100 return nullptr;
101 }
102
103 static char_type* move(char_type* s1, const char_type* s2, size_t n)
104 {
105 return static_cast<char_type*>(memmove(s1, s2, n));
106 }
107
108 static char_type* copy(char_type* s1, const char_type* s2, size_t n)
109 {
110 return static_cast<char_type*>(memcpy(s1, s2, n));
111 }
112
113 static char_type* assign(char_type* s, size_t n, char_type c)
114 {
115 /**
116 * Note: Even though memset accepts int as its second argument,
117 * the actual implementation assigns that int to a dereferenced
118 * char pointer.
119 */
120 return static_cast<char_type*>(memset(s, static_cast<int>(c), n));
121 }
122
123 static constexpr int_type not_eof(int_type c) noexcept
124 {
125 if (!eq_int_type(c, eof()))
126 return c;
127 else
128 return to_int_type('a'); // We just need something that is not eof.
129 }
130
131 static constexpr char_type to_char_type(int_type c) noexcept
132 {
133 return static_cast<char_type>(c);
134 }
135
136 static constexpr int_type to_int_type(char_type c) noexcept
137 {
138 return static_cast<int_type>(c);
139 }
140
141 static constexpr bool eq_int_type(int_type c1, int_type c2) noexcept
142 {
143 return c1 == c2;
144 }
145
146 static constexpr int_type eof() noexcept
147 {
148 return static_cast<int_type>(EOF);
149 }
150 };
151
152 template<>
153 struct char_traits<char16_t>
154 { /* TODO: implement */ };
155
156 template<>
157 struct char_traits<char32_t>
158 { /* TODO: implement */ };
159
160 template<>
161 struct char_traits<wchar_t>
162 {
163 using char_type = wchar_t;
164 using int_type = wint_t;
165 using off_type = streamoff;
166 using pos_type = wstreampos;
167 /* using state_type = mbstate_t; */
168
[2d302d6]169 static void assign(char_type& c1, const char_type& c2) noexcept
[52d025c]170 {
171 c1 = c2;
172 }
173
174 static constexpr bool eq(char_type c1, char_type c2) noexcept
175 {
176 return c1 == c2;
177 }
178
179 static constexpr bool lt(char_type c1, char_type c2) noexcept
180 {
181 return c1 < c2;
182 }
183
184 static int compare(const char_type* s1, const char_type* s2, size_t n)
185 {
[dc0fff11]186 // TODO: This function does not exits...
187 //return std::wstr_lcmp(s1, s2, n);
188 return 0;
[52d025c]189 }
190
191 static size_t length(const char_type* s)
192 {
[2d302d6]193 return std::wstr_size(s);
[52d025c]194 }
195
196 static const char_type* find(const char_type* s, size_t n, const char_type& c)
197 {
198 size_t i{};
199 while (i++ < n)
200 {
201 if (s[i] == c)
202 return s + i;
203 }
204
205 return nullptr;
206 }
207
208 static char_type* move(char_type* s1, const char_type* s2, size_t n)
209 {
210 return static_cast<char_type*>(memmove(s1, s2, n * sizeof(wchar_t)));
211 }
212
213 static char_type* copy(char_type* s1, const char_type* s2, size_t n)
214 {
215 return static_cast<char_type*>(memcpy(s1, s2, n * sizeof(wchar_t)));
216 }
217
218 static char_type* assign(char_type* s, size_t n, char_type c)
219 {
220 return static_cast<char_type*>(memset(s, static_cast<int>(c), n * sizeof(wchar_t)));
221 }
222
223 static constexpr int_type not_eof(int_type c) noexcept
224 {
225 if (!eq_int_type(c, eof()))
226 return c;
227 else
228 return to_int_type(L'a'); // We just need something that is not eof.
229 }
230
231 static constexpr char_type to_char_type(int_type c) noexcept
232 {
233 return static_cast<char_type>(c);
234 }
235
236 static constexpr int_type to_int_type(char_type c) noexcept
237 {
238 return static_cast<int_type>(c);
239 }
240
241 static constexpr bool eq_int_type(int_type c1, int_type c2) noexcept
242 {
243 return c1 == c2;
244 }
245
246 static constexpr int_type eof() noexcept
247 {
248 return static_cast<int_type>(EOF);
249 }
250 };
251
252 /**
253 * 21.4, class template basic_string:
254 */
255
256 template<class Char, class Traits = char_traits<Char>,
257 class Allocator = allocator<Char>>
258 class basic_string
259 {
[177a576]260 public:
261 using traits_type = Traits;
262 using value_type = typename traits_type::char_type;
263 using allocator_type = Allocator;
264 using size_type = typename allocator_traits<allocator_type>::size_type;
265 using difference_type = typename allocator_traits<allocator_type>::difference_type;
[52d025c]266
[177a576]267 using reference = value_type&;
268 using const_reference = const value_type&;
[dc0fff11]269 using pointer = typename allocator_traits<allocator_type>::pointer;
270 using const_pointer = typename allocator_traits<allocator_type>::const_pointer;
[52d025c]271
[177a576]272 using iterator = pointer;
273 using const_iterator = const_pointer;
274 using reverse_iterator = std::reverse_iterator<iterator>;
275 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
[52d025c]276
[177a576]277 static constexpr size_type npos = -1;
[52d025c]278
[177a576]279 /**
280 * 21.4.2, construct/copy/destroy:
281 */
282 basic_string() noexcept
283 : basic_string(allocator_type{})
284 { /* DUMMY BODY */ }
[52d025c]285
[681fdcca]286 explicit basic_string(const allocator_type& alloc)
287 : data_{}, size_{}, capacity_{}, allocator_{alloc}
288 {
289 /**
290 * Postconditions:
291 * data() = non-null copyable value that can have 0 added to it.
292 * size() = 0
293 * capacity() = unspecified
294 */
[dc0fff11]295 data_ = allocator_.allocate(default_capacity_);
296 capacity_ = default_capacity_;
[681fdcca]297 }
[52d025c]298
[681fdcca]299 basic_string(const basic_string& other)
300 : data_{}, size_{other.size_}, capacity_{other.capacity_},
301 allocator_{other.allocator_}
302 {
303 init_(other.data(), size_);
304 }
[52d025c]305
[681fdcca]306 basic_string(basic_string&& other)
307 : data_{other.data_}, size_{other.size_},
308 capacity_{other.capacity_}, allocator_{move(other.allocator_)}
309 {
310 other.data_ = nullptr;
311 other.size_ = 0;
312 other.capacity_ = 0;
313 }
[52d025c]314
[177a576]315 basic_string(const basic_string& other, size_type pos, size_type n = npos,
[681fdcca]316 const allocator_type& alloc = allocator_type{})
317 : data_{}, size_{}, capacity_{}, allocator_{alloc}
318 {
319 // TODO: if pos < other.size() throw out_of_range.
320 auto len = min(n, other.size() - pos);
321 init_(other.data() + pos, len);
322 }
[52d025c]323
[dc0fff11]324 basic_string(const value_type* str, size_type n, const allocator_type& alloc = allocator_type{})
[681fdcca]325 : data_{}, size_{n}, capacity_{n}, allocator_{alloc}
326 {
327 init_(str, size_);
328 }
[52d025c]329
[dc0fff11]330 basic_string(const value_type* str, const allocator_type& alloc = allocator_type{})
[681fdcca]331 : data_{}, size_{}, capacity_{}, allocator_{alloc}
332 {
[ed81b1f]333 init_(str, traits_type::length(str));
[681fdcca]334 }
[52d025c]335
[dc0fff11]336 basic_string(size_type n, value_type c, const allocator_type& alloc = allocator_type{})
[681fdcca]337 : data_{}, size_{n}, capacity_{n}, allocator_{alloc}
338 {
339 data_ = allocator_.allocate(capacity_);
340 for (size_type i = 0; i < size_; ++i)
[53e8686]341 traits_type::assign(data_[i], c);
[681fdcca]342 ensure_null_terminator_();
343 }
[52d025c]344
[177a576]345 template<class InputIterator>
346 basic_string(InputIterator first, InputIterator last,
[dc0fff11]347 const allocator_type& alloc = allocator_type{})
[681fdcca]348 : data_{}, size_{}, capacity_{}, allocator_{alloc}
349 {
[dc0fff11]350 if constexpr (is_integral<InputIterator>::value)
[681fdcca]351 { // Required by the standard.
352 size_ = static_cast<size_type>(first);
353 capacity_ = size_;
354 data_ = allocator_.allocate(capacity_);
355
356 for (size_type i = 0; i < size_; ++i)
357 traits_type::assign(data_[i], static_cast<value_type>(last));
358 ensure_null_terminator_();
359 }
360 else
361 {
362 auto len = static_cast<size_type>(last - first);
[ed81b1f]363 init_(first, len);
[681fdcca]364 }
365 }
[52d025c]366
[dc0fff11]367 basic_string(initializer_list<value_type> init, const allocator_type& alloc = allocator_type{})
[681fdcca]368 : basic_string{init.begin(), init.size(), alloc}
369 { /* DUMMY BODY */ }
[52d025c]370
[681fdcca]371 basic_string(const basic_string& other, const allocator_type& alloc)
372 : data_{}, size_{other.size_}, capacity_{other.capacity_}, allocator_{alloc}
373 {
374 init_(other.data(), size_);
375 }
[52d025c]376
[681fdcca]377 basic_string(basic_string&& other, const allocator_type& alloc)
378 : data_{other.data_}, size_{other.size_}, capacity_{other.capacity_}, allocator_{alloc}
379 {
380 other.data_ = nullptr;
381 other.size_ = 0;
382 other.capacity_ = 0;
383 }
[52d025c]384
[681fdcca]385 ~basic_string()
386 {
387 allocator_.deallocate(data_, capacity_);
388 }
[52d025c]389
[681fdcca]390 basic_string& operator=(const basic_string& other)
391 {
392 if (this != &other)
393 {
394 basic_string tmp{other};
395 swap(tmp);
396 }
397 }
[52d025c]398
[177a576]399 basic_string& operator=(basic_string&& other)
400 noexcept(allocator_traits<allocator_type>::propagate_on_container_move_assignment::value ||
[681fdcca]401 allocator_traits<allocator_type>::is_always_equal::value)
402 {
403 if (this != &other)
404 swap(other);
405 }
[52d025c]406
[681fdcca]407 basic_string& operator=(const value_type* other)
408 {
409 *this = basic_string{other};
[52d025c]410
[681fdcca]411 return *this;
412 }
[52d025c]413
[681fdcca]414 basic_string& operator=(value_type c)
415 {
416 *this = basic_string{1, c};
417
418 return *this;
419 }
420
421 basic_string& operator=(initializer_list<value_type> init)
422 {
423 *this = basic_string{init};
424
425 return *this;
426 }
[52d025c]427
[177a576]428 /**
429 * 21.4.3, iterators:
430 */
[52d025c]431
[b08a62c]432 iterator begin() noexcept
433 {
434 return &data_[0];
435 }
[52d025c]436
[b08a62c]437 const_iterator begin() const noexcept
438 {
439 return &data_[0];
440 }
[52d025c]441
[b08a62c]442 iterator end() noexcept
443 {
444 return begin() + size_;
445 }
[52d025c]446
[b08a62c]447 const_iterator end() const noexcept
448 {
449 return begin() + size_;
450 }
[52d025c]451
[177a576]452 reverse_iterator rbegin() noexcept
453 {
[98c99ba]454 return make_reverse_iterator(end());
[177a576]455 }
[52d025c]456
[177a576]457 const_reverse_iterator rbegin() const noexcept
458 {
[98c99ba]459 return make_reverse_iterator(cend());
[177a576]460 }
[52d025c]461
[177a576]462 reverse_iterator rend() noexcept
463 {
[98c99ba]464 return make_reverse_iterator(begin());
[177a576]465 }
[52d025c]466
[177a576]467 const_reverse_iterator rend() const noexcept
468 {
[98c99ba]469 return make_reverse_iterator(cbegin());
[177a576]470 }
[52d025c]471
[b08a62c]472 const_iterator cbegin() const noexcept
473 {
474 return &data_[0];
475 }
[52d025c]476
[b08a62c]477 const_iterator cend() const noexcept
478 {
479 return cbegin() + size_;
480 }
[52d025c]481
[177a576]482 const_reverse_iterator crbegin() const noexcept
483 {
[98c99ba]484 return rbegin();
[177a576]485 }
[52d025c]486
[177a576]487 const_reverse_iterator crend() const noexcept
488 {
[98c99ba]489 return rend();
[177a576]490 }
[52d025c]491
[177a576]492 /**
493 * 21.4.4, capacity:
494 */
[52d025c]495
[b08a62c]496 size_type size() const noexcept
497 {
498 return size_;
499 }
[52d025c]500
[b08a62c]501 size_type length() const noexcept
502 {
[ed81b1f]503 return size();
[b08a62c]504 }
[52d025c]505
[b08a62c]506 size_type max_size() const noexcept
507 {
508 return allocator_traits<allocator_type>::max_size(allocator_);
509 }
[52d025c]510
[681fdcca]511 void resize(size_type new_size, value_type c)
512 {
513 // TODO: if new_size > max_size() throw length_error.
514 if (new_size > size_)
515 {
516 ensure_free_space_(new_size - size_ + 1);
517 for (size_type i = size_; i < new_size; ++i)
518 traits_type::assign(data_[i], i);
519 }
520
521 size_ = new_size;
522 ensure_null_terminator_();
523 }
[52d025c]524
[681fdcca]525 void resize(size_type new_size)
526 {
527 resize(new_size, value_type{});
528 }
[52d025c]529
[b08a62c]530 size_type capacity() const noexcept
531 {
532 return capacity_;
533 }
[52d025c]534
[681fdcca]535 void reserve(size_type new_capacity = 0)
536 {
537 // TODO: if new_capacity > max_size() throw
538 // length_error (this function shall have no
539 // effect in such case)
540 if (new_capacity > capacity_)
541 resize_with_copy_(size_, new_capacity);
542 else if (new_capacity < capacity)
543 shrink_to_fit(); // Non-binding request, but why not.
544 }
[52d025c]545
[681fdcca]546 void shrink_to_fit()
547 {
548 if (size_ != capacity_)
549 resize_with_copy_(size_);
550 }
[52d025c]551
[681fdcca]552 void clear() noexcept
553 {
554 size_ = 0;
555 }
[52d025c]556
[b08a62c]557 bool empty() const noexcept
558 {
559 return size_ == 0;
560 }
[52d025c]561
[177a576]562 /**
563 * 21.4.5, element access:
564 */
[52d025c]565
[b08a62c]566 const_reference operator[](size_type idx) const
567 {
568 return data_[idx];
569 }
[52d025c]570
[b08a62c]571 reference operator[](size_type idx)
572 {
573 return data_[idx];
574 }
[52d025c]575
[b08a62c]576 const_reference at(size_type idx) const
577 {
578 // TODO: bounds checking
579 return data_[idx];
580 }
[52d025c]581
[b08a62c]582 reference at(size_type idx)
583 {
584 // TODO: bounds checking
585 return data_[idx];
586 }
[52d025c]587
[b08a62c]588 const_reference front() const
589 {
590 return at(0);
591 }
[52d025c]592
[b08a62c]593 reference front()
594 {
595 return at(0);
596 }
[52d025c]597
[b08a62c]598 const_reference back() const
599 {
600 return at(size_ - 1);
601 }
[52d025c]602
[b08a62c]603 reference back()
604 {
605 return at(size_ - 1);
606 }
[52d025c]607
[177a576]608 /**
609 * 21.4.6, modifiers:
610 */
[52d025c]611
[681fdcca]612 basic_string& operator+=(const basic_string& str)
613 {
614 return append(str);
615 }
[52d025c]616
[681fdcca]617 basic_string& operator+=(const value_type* str)
618 {
619 return append(str);
620 }
[52d025c]621
[681fdcca]622 basic_string& operator+=(value_type c)
623 {
624 push_back(c);
625 return *this;
626 }
[52d025c]627
[681fdcca]628 basic_string& operator+=(initializer_list<value_type> init)
629 {
630 return append(init.begin(), init.size());
631 }
[52d025c]632
[681fdcca]633 basic_string& append(const basic_string& str)
634 {
635 return append(str.data(), str.size());
636 }
[52d025c]637
[dc0fff11]638 basic_string& append(const basic_string& str, size_type pos,
[681fdcca]639 size_type n = npos)
640 {
641 if (pos < str.size())
642 {
643 auto len = min(n, str.size() - pos);
644
645 return append(str.data() + pos, len);
646 }
647 // TODO: Else throw out_of_range.
648 }
[52d025c]649
[681fdcca]650 basic_string& append(const value_type* str, size_type n)
651 {
652 // TODO: if (size_ + n > max_size()) throw length_error
653 ensure_free_space_(n);
[ed81b1f]654 traits_type::copy(data_ + size(), str, n);
655 size_ += n;
[681fdcca]656 ensure_null_terminator_();
[52d025c]657
[681fdcca]658 return *this;
659 }
[52d025c]660
[681fdcca]661 basic_string& append(const value_type* str)
662 {
[ed81b1f]663 return append(str, traits_type::length(str));
[681fdcca]664 }
665
666 basic_string& append(size_type n, value_type c)
667 {
668 return append(basic_string(n, c));
669 }
[52d025c]670
[177a576]671 template<class InputIterator>
[681fdcca]672 basic_string& append(InputIterator first, InputIterator last)
673 {
[dc0fff11]674 return append(basic_string(first, last));
[681fdcca]675 }
[52d025c]676
[681fdcca]677 basic_string& append(initializer_list<value_type> init)
678 {
679 return append(init.begin(), init.size());
680 }
[52d025c]681
[681fdcca]682 void push_back(value_type c)
683 {
684 ensure_free_space_(1);
685 traits_type::assign(data_[size_++], c);
686 ensure_null_terminator_();
687 }
[52d025c]688
[681fdcca]689 basic_string& assign(const basic_string& str)
690 {
691 return assign(str, 0, npos);
692 }
[52d025c]693
[681fdcca]694 basic_string& assign(basic_string&& str)
695 {
696 swap(str);
697
698 return *this;
699 }
[52d025c]700
[177a576]701 basic_string& assign(const basic_string& str, size_type pos,
[681fdcca]702 size_type n = npos)
703 {
704 if (pos < str.size())
705 {
706 auto len = min(n, str.size() - pos);
707 ensure_free_space_(len);
708
709 return assign(str.data() + pos, len);
710 }
711 // TODO: Else throw out_of_range.
[dc0fff11]712
713 return *this;
[681fdcca]714 }
[52d025c]715
[681fdcca]716 basic_string& assign(const value_type* str, size_type n)
717 {
718 // TODO: if (n > max_size()) throw length_error.
719 resize_without_copy_(n);
720 traits_type::copy(begin(), str, n);
[dc0fff11]721 size_ = n;
722 ensure_null_terminator_();
[681fdcca]723
724 return *this;
725 }
[52d025c]726
[681fdcca]727 basic_string& assign(const value_type* str)
728 {
729 return assign(str, traits_type::length(str));
730 }
[52d025c]731
[681fdcca]732 basic_string& assign(size_type n, value_type c)
733 {
734 return assign(basic_string(n, c));
735 }
[52d025c]736
[177a576]737 template<class InputIterator>
[681fdcca]738 basic_string& assign(InputIterator first, InputIterator last)
739 {
740 return assign(basic_string(first, last));
741 }
[52d025c]742
[681fdcca]743 basic_string& assign(initializer_list<value_type> init)
744 {
745 return assign(init.begin(), init.size());
746 }
[52d025c]747
[681fdcca]748 basic_string& insert(size_type pos, const basic_string& str)
749 {
750 // TODO: if (pos > str.size()) throw out_of_range.
751 return insert(pos, str.data(), str.size());
752 }
[52d025c]753
[177a576]754 basic_string& insert(size_type pos1, const basic_string& str,
[681fdcca]755 size_type pos2, size_type n = npos)
756 {
757 // TODO: if (pos1 > size() or pos2 > str.size()) throw
758 // out_of_range.
759 auto len = min(n, str.size() - pos2);
[52d025c]760
[681fdcca]761 return insert(pos1, str.data() + pos2, len);
762 }
[52d025c]763
[681fdcca]764 basic_string& insert(size_type pos, const value_type* str, size_type n)
765 {
[2d302d6]766 // TODO: throw out_of_range if pos > size()
767 // TODO: throw length_error if size() + n > max_size()
768 ensure_free_space_(n);
769
[681fdcca]770 copy_backward_(begin() + pos, end(), end() + n);
[2d302d6]771 copy_(str, str + n, begin() + pos);
772 size_ += n;
[52d025c]773
[2d302d6]774 ensure_null_terminator_();
[681fdcca]775 return *this;
776 }
[52d025c]777
[681fdcca]778 basic_string& insert(size_type pos, const value_type* str)
779 {
780 return insert(pos, str, traits_type::length(str));
781 }
[52d025c]782
[681fdcca]783 basic_string& insert(size_type pos, size_type n, value_type c)
784 {
785 return insert(pos, basic_string(n, c));
786 }
787
788 iterator insert(const_iterator pos, value_type c)
789 {
790 auto idx = static_cast<size_type>(pos - begin());
791
792 ensure_free_space_(1);
[2d302d6]793 copy_backward_(begin() + idx, end(), end() + 1);
794 traits_type::assign(data_[idx], c);
795
796 ++size_;
[681fdcca]797 ensure_null_terminator_();
798
799 return begin() + idx;
800 }
801
802 iterator insert(const_iterator pos, size_type n, value_type c)
803 {
804 if (n == 0)
805 return const_cast<iterator>(pos);
806
807 auto idx = static_cast<size_type>(pos - begin());
808
809 ensure_free_space_(n);
[2d302d6]810 copy_backward_(begin() + idx, end(), end() + n);
[681fdcca]811
[2d302d6]812 auto it = begin() + idx;
[681fdcca]813 for (size_type i = 0; i < n; ++i)
[dc0fff11]814 traits_type::assign(*it++, c);
[2d302d6]815 size_ += n;
[681fdcca]816 ensure_null_terminator_();
817
818 return begin() + idx;
819 }
[52d025c]820
[177a576]821 template<class InputIterator>
822 iterator insert(const_iterator pos, InputIterator first,
[681fdcca]823 InputIterator last)
824 {
[2d302d6]825 if (first == last)
826 return const_cast<iterator>(pos);
827
828 auto idx = static_cast<size_type>(pos - begin());
829 auto str = basic_string{first, last};
830 insert(idx, str);
831
832 return begin() + idx;
[681fdcca]833 }
[52d025c]834
[681fdcca]835 iterator insert(const_iterator pos, initializer_list<value_type> init)
836 {
837 return insert(pos, init.begin(), init.end());
838 }
[52d025c]839
[dc0fff11]840 basic_string& erase(size_type pos = 0, size_type n = npos)
[681fdcca]841 {
842 auto len = min(n, size_ - pos);
843 copy_(begin() + pos + n, end(), begin() + pos);
844 size_ -= len;
845 ensure_null_terminator_();
[e07bbbc]846
847 return *this;
[681fdcca]848 }
[52d025c]849
[e07bbbc]850 iterator erase(const_iterator pos)
851 {
852 auto idx = static_cast<size_type>(pos - cbegin());
[dc0fff11]853 erase(idx, 1);
[52d025c]854
[e07bbbc]855 return begin() + idx;
856 }
857
858 iterator erase(const_iterator first, const_iterator last)
859 {
860 auto idx = static_cast<size_type>(first - cbegin());
861 auto count = static_cast<size_type>(last - first);
862 erase(idx, count);
863
864 return begin() + idx;
865 }
[52d025c]866
[681fdcca]867 void pop_back()
868 {
869 --size_;
870 ensure_null_terminator_();
871 }
[52d025c]872
[b0b46d59]873 basic_string& replace(size_type pos, size_type n, const basic_string& str)
874 {
875 // TODO: throw out_of_range if pos > size()
876 return replace(pos, n, str.data(), str.size());
877 }
[52d025c]878
[dc0fff11]879 basic_string& replace(size_type pos1, size_type n1, const basic_string& str,
[b0b46d59]880 size_type pos2, size_type n2 = npos)
881 {
882 // TODO: throw out_of_range if pos1 > size() or pos2 > str.size()
883 auto len = min(n2, str.size() - pos2);
884 return replace(pos1, n1, str.data() + pos2, len);
885 }
[52d025c]886
[177a576]887 basic_string& replace(size_type pos, size_type n1, const value_type* str,
[b0b46d59]888 size_type n2)
889 {
890 // TODO: throw out_of_range if pos > size()
891 // TODO: if size() - len > max_size() - n2 throw length_error
[53e8686]892 auto len = min(n1, size_ - pos);
893
[b0b46d59]894 basic_string tmp{};
895 tmp.resize_without_copy_(size_ - len + n2);
[53e8686]896
897 // Prefix.
[b0b46d59]898 copy_(begin(), begin() + pos, tmp.begin());
[53e8686]899
900 // Substitution.
901 traits_type::copy(tmp.begin() + pos, str, n2);
902
903 // Suffix.
904 copy_(begin() + pos + len, end(), tmp.begin() + pos + n2);
905
906 tmp.size_ = size_ - len + n2;
[b0b46d59]907 swap(tmp);
908 return *this;
909 }
[52d025c]910
[b0b46d59]911 basic_string& replace(size_type pos, size_type n, const value_type* str)
912 {
913 return replace(pos, n, str, traits_type::length(str));
914 }
[52d025c]915
[177a576]916 basic_string& replace(size_type pos, size_type n1, size_type n2,
[b0b46d59]917 value_type c)
918 {
919 return replace(pos, n1, basic_string(n2, c));
920 }
[52d025c]921
[177a576]922 basic_string& replace(const_iterator i1, const_iterator i2,
[b0b46d59]923 const basic_string& str)
924 {
925 return replace(i1 - begin(), i2 - i1, str);
926 }
[52d025c]927
[177a576]928 basic_string& replace(const_iterator i1, const_iterator i2,
[b0b46d59]929 const value_type* str, size_type n)
930 {
[dc0fff11]931 return replace(i1 - begin(), i2 - i1, str, n);
[b0b46d59]932 }
[52d025c]933
[177a576]934 basic_string& replace(const_iterator i1, const_iterator i2,
[b0b46d59]935 const value_type* str)
936 {
937 return replace(i1 - begin(), i2 - i1, str, traits_type::length(str));
938 }
[52d025c]939
[177a576]940 basic_string& replace(const_iterator i1, const_iterator i2,
[b0b46d59]941 size_type n, value_type c)
942 {
943 return replace(i1 - begin(), i2 - i1, basic_string(n, c));
944 }
[52d025c]945
[177a576]946 template<class InputIterator>
947 basic_string& replace(const_iterator i1, const_iterator i2,
[b0b46d59]948 InputIterator j1, InputIterator j2)
949 {
950 return replace(i1 - begin(), i2 - i1, basic_string(j1, j2));
951 }
[52d025c]952
[177a576]953 basic_string& replace(const_iterator i1, const_iterator i2,
[b0b46d59]954 initializer_list<value_type> init)
955 {
956 return replace(i1 - begin(), i2 - i1, init.begin(), init.size());
957 }
[52d025c]958
[27473fb8]959 size_type copy(value_type* str, size_type n, size_type pos = 0) const
960 {
961 auto len = min(n , size_ - pos);
962 for (size_type i = 0; i < len; ++i)
963 traits_type::assign(str[i], data_[pos + i]);
964
965 return len;
966 }
[52d025c]967
[177a576]968 void swap(basic_string& other)
969 noexcept(allocator_traits<allocator_type>::propagate_on_container_swap::value ||
[53e8686]970 allocator_traits<allocator_type>::is_always_equal::value)
[b08a62c]971 {
972 std::swap(data_, other.data_);
973 std::swap(size_, other.size_);
974 std::swap(capacity_, other.capacity_);
975 }
[52d025c]976
[177a576]977 /**
978 * 21.4.7, string operations:
979 */
[52d025c]980
[b08a62c]981 const value_type* c_str() const noexcept
982 {
983 return data_;
984 }
[52d025c]985
[b08a62c]986 const value_type* data() const noexcept
987 {
988 return data_;
989 }
[52d025c]990
[b08a62c]991 allocator_type get_allocator() const noexcept
992 {
993 return allocator_type{allocator_};
994 }
[52d025c]995
[e07bbbc]996 /**
997 * Note: The following find functions have 4 versions each:
998 * (1) takes basic_string
999 * (2) takes c string and length
1000 * (3) takes c string
1001 * (4) takes value_type
1002 * According to the C++14 standard, only (1) is marked as
1003 * noexcept and the other three return the first one with
1004 * a newly allocated strings (and thus cannot be noexcept).
1005 * However, allocating a new string results in memory
1006 * allocation and copying of the source and thus we have
1007 * decided to follow C++17 signatures of these functions
1008 * (i.e. all of them being marked as noexcept) and use
1009 * (2) for the actual implementation (and avoiding any
1010 * allocations or copying in the process and also providing
1011 * stronger guarantees to the user).
1012 */
1013
1014 size_type find(const basic_string& str, size_type pos = 0) const noexcept
1015 {
1016 return find(str.c_str(), pos, str.size());
1017 }
1018
1019 size_type find(const value_type* str, size_type pos, size_type len) const noexcept
1020 {
1021 if (empty() || len == 0 || len - pos > size())
1022 return npos;
1023
1024 size_type idx{pos};
1025
1026 while (idx + len < size_)
1027 {
1028 if (substr_starts_at_(idx, str, len))
1029 return idx;
1030 ++idx;
1031 }
1032
1033 return npos;
1034 }
1035
1036 size_type find(const value_type* str, size_type pos = 0) const noexcept
1037 {
1038 return find(str, pos, traits_type::length(str));
1039 }
1040
1041 size_type find(value_type c, size_type pos = 0) const noexcept
1042 {
1043 if (empty())
1044 return npos;
1045
1046 for (size_type i = pos; i < size_; ++i)
1047 {
1048 if (traits_type::eq(c, data_[i]))
1049 return i;
1050 }
1051
1052 return npos;
1053 }
1054
1055 size_type rfind(const basic_string& str, size_type pos = npos) const noexcept
1056 {
1057 return rfind(str.c_str(), pos, str.size());
1058 }
1059
1060 size_type rfind(const value_type* str, size_type pos, size_type len) const noexcept
1061 {
1062 if (empty() || len == 0 || len - pos > size())
1063 return npos;
1064
1065 size_type idx{min(pos, size_ - 1) + 1};
1066
1067 while (idx > 0)
1068 {
1069 if (substr_starts_at_(idx - 1, str, len))
1070 return idx - 1;
1071 --idx;
1072 }
1073
1074 return npos;
1075 }
1076
1077 size_type rfind(const value_type* str, size_type pos = npos) const noexcept
1078 {
1079 return rfind(str, pos, traits_type::length(str));
1080 }
1081
1082 size_type rfind(value_type c, size_type pos = npos) const noexcept
1083 {
1084 if (empty())
1085 return npos;
1086
1087 for (size_type i = min(pos, size_ - 1) + 1; i > 0; --i)
1088 {
1089 if (traits_type::eq(c, data_[i - 1]))
1090 return i - 1;
1091 }
1092
1093 return npos;
1094 }
1095
1096 size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept
1097 {
1098 return find_first_of(str.c_str(), pos, str.size());
1099 }
1100
1101 size_type find_first_of(const value_type* str, size_type pos, size_type len) const noexcept
1102 {
1103 if (empty() || len == 0 || pos + len > size())
1104 return npos;
1105
1106 size_type idx{pos};
1107
1108 while (idx < size_)
1109 {
1110 if (is_any_of_(idx, str, len))
1111 return idx;
1112 ++idx;
1113 }
1114
1115 return npos;
1116 }
1117
1118 size_type find_first_of(const value_type* str, size_type pos = 0) const noexcept
1119 {
1120 return find_first_of(str, pos, traits_type::length(str));
1121 }
1122
1123 size_type find_first_of(value_type c, size_type pos = 0) const noexcept
1124 {
1125 return find(c, pos);
1126 }
[52d025c]1127
[e07bbbc]1128 size_type find_last_of(const basic_string& str, size_type pos = npos) const noexcept
1129 {
1130 return find_last_of(str.c_str(), pos, str.size());
1131 }
[52d025c]1132
[e07bbbc]1133 size_type find_last_of(const value_type* str, size_type pos, size_type len) const noexcept
1134 {
1135 if (empty())
1136 return npos;
[52d025c]1137
[e07bbbc]1138 for (size_type i = min(pos, size_ - 1) + 1; i > 0; --i)
1139 {
1140 if (is_any_of_(i - 1, str, len))
1141 return i - 1;
1142 }
[52d025c]1143
[e07bbbc]1144 return npos;
1145 }
[52d025c]1146
[e07bbbc]1147 size_type find_last_of(const value_type* str, size_type pos = npos) const noexcept
1148 {
1149 return find_last_of(str, pos, traits_type::length(str));
1150 }
[52d025c]1151
[e07bbbc]1152 size_type find_last_of(value_type c, size_type pos = npos) const noexcept
1153 {
1154 return rfind(c, pos);
1155 }
[52d025c]1156
[e07bbbc]1157 size_type find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept
1158 {
1159 return find_first_not_of(str.c_str(), pos, str.size());
1160 }
[52d025c]1161
[e07bbbc]1162 size_type find_first_not_of(const value_type* str, size_type pos, size_type len) const noexcept
1163 {
1164 if (empty() || len == 0 || pos + len > size())
1165 return npos;
[52d025c]1166
[e07bbbc]1167 size_type idx{pos};
[52d025c]1168
[e07bbbc]1169 while (idx < size_)
1170 {
1171 if (!is_any_of_(idx, str, len))
1172 return idx;
1173 ++idx;
1174 }
[52d025c]1175
[e07bbbc]1176 return npos;
1177 }
[52d025c]1178
[e07bbbc]1179 size_type find_first_not_of(const value_type* str, size_type pos = 0) const noexcept
1180 {
1181 return find_first_not_of(str.c_str(), pos, str.size());
1182 }
[52d025c]1183
[e07bbbc]1184 size_type find_first_not_of(value_type c, size_type pos = 0) const noexcept
1185 {
1186 if (empty())
1187 return npos;
[52d025c]1188
[e07bbbc]1189 for (size_type i = pos; i < size_; ++i)
1190 {
1191 if (!traits_type::eq(c, data_[i]))
1192 return i;
1193 }
[52d025c]1194
[e07bbbc]1195 return npos;
1196 }
[52d025c]1197
[e07bbbc]1198 size_type find_last_not_of(const basic_string& str, size_type pos = npos) const noexcept
1199 {
1200 return find_last_not_of(str.c_str(), pos, str.size());
1201 }
[52d025c]1202
[e07bbbc]1203 size_type find_last_not_of(const value_type* str, size_type pos, size_type len) const noexcept
1204 {
1205 if (empty())
1206 return npos;
[52d025c]1207
[e07bbbc]1208 for (size_type i = min(pos, size_ - 1) + 1; i > 0; --i)
1209 {
1210 if (!is_one_of_(i - 1, str, len))
1211 return i - 1;
1212 }
[52d025c]1213
[e07bbbc]1214 return npos;
1215 }
[52d025c]1216
[e07bbbc]1217 size_type find_last_not_of(const value_type* str, size_type pos = npos) const noexcept
1218 {
1219 return find_last_not_of(str, pos, traits_type::length(str));
1220 }
[52d025c]1221
[e07bbbc]1222 size_type find_last_not_of(value_type c, size_type pos = npos) const noexcept
1223 {
1224 if (empty())
1225 return npos;
[52d025c]1226
[e07bbbc]1227 pos = min(pos, size_ - 1);
[52d025c]1228
[e07bbbc]1229 for (size_type i = min(pos, size_ - 1) + 1; i > 1; --i)
1230 {
1231 if (!traits_type::eq(c, data_[i - 1]))
1232 return i - 1;
1233 }
[52d025c]1234
[e07bbbc]1235 return npos;
1236 }
[52d025c]1237
[e07bbbc]1238 basic_string substr(size_type pos = 0, size_type n = npos) const
1239 {
1240 // TODO: throw out_of_range if pos > size().
1241 auto len = min(n, size_ - pos);
1242 return basic_string{data() + pos, len};
1243 }
[52d025c]1244
[e07bbbc]1245 int compare(const basic_string& other) const noexcept
1246 {
1247 auto len = min(size(), other.size());
1248 auto comp = traits_type::compare(data_, other.data(), len);
1249
1250 if (comp != 0)
1251 return comp;
1252 else if (size() == other.size())
1253 return 0;
1254 else if (size() > other.size())
1255 return 1;
1256 else if (size() < other.size())
1257 return -1;
1258 }
1259
1260 int compare(size_type pos, size_type n, const basic_string& other) const
1261 {
1262 return basic_string{*this, pos, n}.compare(other);
1263 }
[52d025c]1264
[177a576]1265 int compare(size_type pos1, size_type n1, const basic_string& other,
[e07bbbc]1266 size_type pos2, size_type n2 = npos) const
1267 {
1268 return basic_string{*this, pos1, n1}.compare(basic_string{other, pos2, n2});
1269 }
[52d025c]1270
[e07bbbc]1271 int compare(const value_type* other) const
1272 {
1273 return compare(basic_string(other));
1274 }
[52d025c]1275
[e07bbbc]1276 int compare(size_type pos, size_type n, const value_type* other) const
1277 {
1278 return basic_string{*this, pos, n}.compare(basic_string{other});
1279 }
[52d025c]1280
[e07bbbc]1281 int compare(size_type pos, size_type n1,
1282 const value_type* other, size_type n2) const
1283 {
1284 return basic_string{*this, pos, n1}.compare(basic_string{other, n2});
1285 }
[b08a62c]1286
1287 private:
1288 value_type* data_;
1289 size_type size_;
1290 size_type capacity_;
1291 allocator_type allocator_;
[681fdcca]1292
1293 /**
1294 * Arbitrary value, standard just requires
1295 * data() to have some capacity.
1296 * (Well, we could've done data_ = &data_ and
1297 * set capacity to 0, but that would be too cryptic.)
1298 */
[dc0fff11]1299 static constexpr size_type default_capacity_{4};
[681fdcca]1300
1301 void init_(const value_type* str, size_type size)
1302 {
1303 if (data_)
1304 allocator_.deallocate(data_, capacity_);
1305
1306 size_ = size;
1307 capacity_ = size;
1308
1309 data_ = allocator_.allocate(capacity_);
1310 traits_type::copy(data_, str, size);
1311 ensure_null_terminator_();
1312 }
1313
1314 size_type next_capacity_(size_type hint = 0) const noexcept
1315 {
1316 if (hint != 0)
1317 return max(capacity_ * 2, hint);
1318 else
1319 return max(capacity_ * 2, 2ul);
1320 }
1321
1322 void ensure_free_space_(size_type n)
1323 {
1324 /**
1325 * Note: We cannot use reserve like we
1326 * did in vector, because in string
1327 * reserve can cause shrinking.
1328 */
[dc0fff11]1329 if (size_ + 1 + n > capacity_)
[681fdcca]1330 resize_with_copy_(size_, max(size_ + 1 + n, next_capacity_()));
1331 }
1332
1333 void resize_without_copy_(size_type capacity)
1334 {
1335 if (data_)
1336 allocator_.deallocate(data_, capacity_);
1337
1338 data_ = allocator_.allocate(capacity);
1339 size_ = 0;
1340 capacity_ = capacity;
1341 ensure_null_terminator_();
1342 }
1343
1344 void resize_with_copy_(size_type size, size_type capacity)
1345 {
1346 if(capacity_ == 0 || capacity_ < capacity)
1347 {
1348 auto new_data = allocator_.allocate(capacity);
1349
1350 auto to_copy = min(size, size_);
1351 traits_type::move(new_data, data_, to_copy);
1352
1353 std::swap(data_, new_data);
1354
1355 allocator_.deallocate(new_data, capacity_);
1356 }
1357
1358 capacity_ = capacity;
1359 size_ = size;
1360 ensure_null_terminator_();
1361 }
1362
[2d302d6]1363 template<class Iterator1, class Iterator2>
1364 Iterator2 copy_(Iterator1 first, Iterator1 last,
1365 Iterator2 result)
[681fdcca]1366 {
1367 while (first != last)
1368 traits_type::assign(*result++, *first++);
1369
1370 return result;
1371 }
1372
[2d302d6]1373 template<class Iterator1, class Iterator2>
1374 Iterator2 copy_backward_(Iterator1 first, Iterator1 last,
1375 Iterator2 result)
[681fdcca]1376 {
[2d302d6]1377 while (last != first)
1378 traits_type::assign(*--result, *--last);
[681fdcca]1379
1380 return result;
1381 }
1382
1383 void ensure_null_terminator_()
1384 {
[dc0fff11]1385 value_type c{};
1386 traits_type::assign(data_[size_], c);
[681fdcca]1387 }
[e07bbbc]1388
1389 bool is_one_of_(size_type idx, const basic_string& str) const
1390 {
1391 auto cstr = str.c_str();
1392 for (size_type i = 0; i < str.size(); ++i)
1393 {
1394 if (traits_type::eq(data_[idx], cstr[i]))
1395 return true;
1396 }
1397
1398 return false;
1399 }
1400
1401 bool substr_starts_at_(size_type idx, const value_type* str, size_type len) const
1402 {
1403 size_type i{};
1404 for (i = 0; i < len; ++i)
1405 {
1406 if (!traits_type::eq(data_[idx + i], str[i]))
1407 break;
1408 }
1409
1410 return i == len;
1411 }
[52d025c]1412 };
[dc0fff11]1413
1414 using string = basic_string<char>;
[52d025c]1415}
1416
1417#endif
Note: See TracBrowser for help on using the repository browser.