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

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

cpp: added string non-member functions and some conversion operators

  • Property mode set to 100644
File size: 59.3 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>
[82b6716]154 {
155 // TODO: implement
156 using char_type = char16_t;
157 using int_type = int16_t;
158 using off_type = streamoff;
159 using pos_type = streampos;
160 /* using state_type = mbstate_t; */
161
162 static void assign(char_type& c1, const char_type& c2) noexcept
163 {
164 c1 = c2;
165 }
166
167 static constexpr bool eq(char_type c1, char_type c2) noexcept
168 {
169 return c1 == c2;
170 }
171
172 static constexpr bool lt(char_type c1, char_type c2) noexcept
173 {
174 return c1 < c2;
175 }
176
177 static int compare(const char_type* s1, const char_type* s2, size_t n)
178 {
179 // TODO: implement
180 return 0;
181 }
182
183 static size_t length(const char_type* s)
184 {
185 // TODO: implement
186 return 0;
187 }
188
189 static const char_type* find(const char_type* s, size_t n, const char_type& c)
190 {
191 // TODO: implement
192 return nullptr;
193 }
194
195 static char_type* move(char_type* s1, const char_type* s2, size_t n)
196 {
197 // TODO: implement
198 return nullptr;
199 }
200
201 static char_type* copy(char_type* s1, const char_type* s2, size_t n)
202 {
203 // TODO: implement
204 return nullptr;
205 }
206
207 static char_type* assign(char_type* s, size_t n, char_type c)
208 {
209 // TODO: implement
210 return nullptr;
211 }
212
213 static constexpr int_type not_eof(int_type c) noexcept
214 {
215 // TODO: implement
216 return int_type{};
217 }
218
219 static constexpr char_type to_char_type(int_type c) noexcept
220 {
221 return static_cast<char_type>(c);
222 }
223
224 static constexpr int_type to_int_type(char_type c) noexcept
225 {
226 return static_cast<int_type>(c);
227 }
228
229 static constexpr bool eq_int_type(int_type c1, int_type c2) noexcept
230 {
231 return c1 == c2;
232 }
233
234 static constexpr int_type eof() noexcept
235 {
236 return static_cast<int_type>(EOF);
237 }
238 };
[52d025c]239
240 template<>
241 struct char_traits<char32_t>
[82b6716]242 {
243 // TODO: implement
244 using char_type = char32_t;
245 using int_type = int32_t;
246 using off_type = streamoff;
247 using pos_type = streampos;
248 /* using state_type = mbstate_t; */
249
250 static void assign(char_type& c1, const char_type& c2) noexcept
251 {
252 c1 = c2;
253 }
254
255 static constexpr bool eq(char_type c1, char_type c2) noexcept
256 {
257 return c1 == c2;
258 }
259
260 static constexpr bool lt(char_type c1, char_type c2) noexcept
261 {
262 return c1 < c2;
263 }
264
265 static int compare(const char_type* s1, const char_type* s2, size_t n)
266 {
267 // TODO: implement
268 return 0;
269 }
270
271 static size_t length(const char_type* s)
272 {
273 // TODO: implement
274 return 0;
275 }
276
277 static const char_type* find(const char_type* s, size_t n, const char_type& c)
278 {
279 // TODO: implement
280 return nullptr;
281 }
282
283 static char_type* move(char_type* s1, const char_type* s2, size_t n)
284 {
285 // TODO: implement
286 return nullptr;
287 }
288
289 static char_type* copy(char_type* s1, const char_type* s2, size_t n)
290 {
291 // TODO: implement
292 return nullptr;
293 }
294
295 static char_type* assign(char_type* s, size_t n, char_type c)
296 {
297 // TODO: implement
298 return nullptr;
299 }
300
301 static constexpr int_type not_eof(int_type c) noexcept
302 {
303 // TODO: implement
304 return int_type{};
305 }
306
307 static constexpr char_type to_char_type(int_type c) noexcept
308 {
309 return static_cast<char_type>(c);
310 }
311
312 static constexpr int_type to_int_type(char_type c) noexcept
313 {
314 return static_cast<int_type>(c);
315 }
316
317 static constexpr bool eq_int_type(int_type c1, int_type c2) noexcept
318 {
319 return c1 == c2;
320 }
321
322 static constexpr int_type eof() noexcept
323 {
324 return static_cast<int_type>(EOF);
325 }
326 };
[52d025c]327
328 template<>
329 struct char_traits<wchar_t>
330 {
331 using char_type = wchar_t;
332 using int_type = wint_t;
333 using off_type = streamoff;
334 using pos_type = wstreampos;
335 /* using state_type = mbstate_t; */
336
[2d302d6]337 static void assign(char_type& c1, const char_type& c2) noexcept
[52d025c]338 {
339 c1 = c2;
340 }
341
342 static constexpr bool eq(char_type c1, char_type c2) noexcept
343 {
344 return c1 == c2;
345 }
346
347 static constexpr bool lt(char_type c1, char_type c2) noexcept
348 {
349 return c1 < c2;
350 }
351
352 static int compare(const char_type* s1, const char_type* s2, size_t n)
353 {
[dc0fff11]354 // TODO: This function does not exits...
355 //return std::wstr_lcmp(s1, s2, n);
356 return 0;
[52d025c]357 }
358
359 static size_t length(const char_type* s)
360 {
[2d302d6]361 return std::wstr_size(s);
[52d025c]362 }
363
364 static const char_type* find(const char_type* s, size_t n, const char_type& c)
365 {
366 size_t i{};
367 while (i++ < n)
368 {
369 if (s[i] == c)
370 return s + i;
371 }
372
373 return nullptr;
374 }
375
376 static char_type* move(char_type* s1, const char_type* s2, size_t n)
377 {
378 return static_cast<char_type*>(memmove(s1, s2, n * sizeof(wchar_t)));
379 }
380
381 static char_type* copy(char_type* s1, const char_type* s2, size_t n)
382 {
383 return static_cast<char_type*>(memcpy(s1, s2, n * sizeof(wchar_t)));
384 }
385
386 static char_type* assign(char_type* s, size_t n, char_type c)
387 {
388 return static_cast<char_type*>(memset(s, static_cast<int>(c), n * sizeof(wchar_t)));
389 }
390
391 static constexpr int_type not_eof(int_type c) noexcept
392 {
393 if (!eq_int_type(c, eof()))
394 return c;
395 else
396 return to_int_type(L'a'); // We just need something that is not eof.
397 }
398
399 static constexpr char_type to_char_type(int_type c) noexcept
400 {
401 return static_cast<char_type>(c);
402 }
403
404 static constexpr int_type to_int_type(char_type c) noexcept
405 {
406 return static_cast<int_type>(c);
407 }
408
409 static constexpr bool eq_int_type(int_type c1, int_type c2) noexcept
410 {
411 return c1 == c2;
412 }
413
414 static constexpr int_type eof() noexcept
415 {
416 return static_cast<int_type>(EOF);
417 }
418 };
419
420 /**
421 * 21.4, class template basic_string:
422 */
423
424 template<class Char, class Traits = char_traits<Char>,
425 class Allocator = allocator<Char>>
426 class basic_string
427 {
[177a576]428 public:
429 using traits_type = Traits;
430 using value_type = typename traits_type::char_type;
431 using allocator_type = Allocator;
432 using size_type = typename allocator_traits<allocator_type>::size_type;
433 using difference_type = typename allocator_traits<allocator_type>::difference_type;
[52d025c]434
[177a576]435 using reference = value_type&;
436 using const_reference = const value_type&;
[dc0fff11]437 using pointer = typename allocator_traits<allocator_type>::pointer;
438 using const_pointer = typename allocator_traits<allocator_type>::const_pointer;
[52d025c]439
[177a576]440 using iterator = pointer;
441 using const_iterator = const_pointer;
442 using reverse_iterator = std::reverse_iterator<iterator>;
443 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
[52d025c]444
[177a576]445 static constexpr size_type npos = -1;
[52d025c]446
[177a576]447 /**
448 * 21.4.2, construct/copy/destroy:
449 */
450 basic_string() noexcept
451 : basic_string(allocator_type{})
452 { /* DUMMY BODY */ }
[52d025c]453
[681fdcca]454 explicit basic_string(const allocator_type& alloc)
455 : data_{}, size_{}, capacity_{}, allocator_{alloc}
456 {
457 /**
458 * Postconditions:
459 * data() = non-null copyable value that can have 0 added to it.
460 * size() = 0
461 * capacity() = unspecified
462 */
[dc0fff11]463 data_ = allocator_.allocate(default_capacity_);
464 capacity_ = default_capacity_;
[681fdcca]465 }
[52d025c]466
[681fdcca]467 basic_string(const basic_string& other)
468 : data_{}, size_{other.size_}, capacity_{other.capacity_},
469 allocator_{other.allocator_}
470 {
471 init_(other.data(), size_);
472 }
[52d025c]473
[681fdcca]474 basic_string(basic_string&& other)
475 : data_{other.data_}, size_{other.size_},
476 capacity_{other.capacity_}, allocator_{move(other.allocator_)}
477 {
478 other.data_ = nullptr;
479 other.size_ = 0;
480 other.capacity_ = 0;
481 }
[52d025c]482
[177a576]483 basic_string(const basic_string& other, size_type pos, size_type n = npos,
[681fdcca]484 const allocator_type& alloc = allocator_type{})
485 : data_{}, size_{}, capacity_{}, allocator_{alloc}
486 {
487 // TODO: if pos < other.size() throw out_of_range.
488 auto len = min(n, other.size() - pos);
489 init_(other.data() + pos, len);
490 }
[52d025c]491
[dc0fff11]492 basic_string(const value_type* str, size_type n, const allocator_type& alloc = allocator_type{})
[681fdcca]493 : data_{}, size_{n}, capacity_{n}, allocator_{alloc}
494 {
495 init_(str, size_);
496 }
[52d025c]497
[dc0fff11]498 basic_string(const value_type* str, const allocator_type& alloc = allocator_type{})
[681fdcca]499 : data_{}, size_{}, capacity_{}, allocator_{alloc}
500 {
[ed81b1f]501 init_(str, traits_type::length(str));
[681fdcca]502 }
[52d025c]503
[dc0fff11]504 basic_string(size_type n, value_type c, const allocator_type& alloc = allocator_type{})
[681fdcca]505 : data_{}, size_{n}, capacity_{n}, allocator_{alloc}
506 {
507 data_ = allocator_.allocate(capacity_);
508 for (size_type i = 0; i < size_; ++i)
[53e8686]509 traits_type::assign(data_[i], c);
[681fdcca]510 ensure_null_terminator_();
511 }
[52d025c]512
[177a576]513 template<class InputIterator>
514 basic_string(InputIterator first, InputIterator last,
[dc0fff11]515 const allocator_type& alloc = allocator_type{})
[681fdcca]516 : data_{}, size_{}, capacity_{}, allocator_{alloc}
517 {
[dc0fff11]518 if constexpr (is_integral<InputIterator>::value)
[681fdcca]519 { // Required by the standard.
520 size_ = static_cast<size_type>(first);
521 capacity_ = size_;
522 data_ = allocator_.allocate(capacity_);
523
524 for (size_type i = 0; i < size_; ++i)
525 traits_type::assign(data_[i], static_cast<value_type>(last));
526 ensure_null_terminator_();
527 }
528 else
529 {
530 auto len = static_cast<size_type>(last - first);
[ed81b1f]531 init_(first, len);
[681fdcca]532 }
533 }
[52d025c]534
[dc0fff11]535 basic_string(initializer_list<value_type> init, const allocator_type& alloc = allocator_type{})
[681fdcca]536 : basic_string{init.begin(), init.size(), alloc}
537 { /* DUMMY BODY */ }
[52d025c]538
[681fdcca]539 basic_string(const basic_string& other, const allocator_type& alloc)
540 : data_{}, size_{other.size_}, capacity_{other.capacity_}, allocator_{alloc}
541 {
542 init_(other.data(), size_);
543 }
[52d025c]544
[681fdcca]545 basic_string(basic_string&& other, const allocator_type& alloc)
546 : data_{other.data_}, size_{other.size_}, capacity_{other.capacity_}, allocator_{alloc}
547 {
548 other.data_ = nullptr;
549 other.size_ = 0;
550 other.capacity_ = 0;
551 }
[52d025c]552
[681fdcca]553 ~basic_string()
554 {
555 allocator_.deallocate(data_, capacity_);
556 }
[52d025c]557
[681fdcca]558 basic_string& operator=(const basic_string& other)
559 {
560 if (this != &other)
561 {
562 basic_string tmp{other};
563 swap(tmp);
564 }
565 }
[52d025c]566
[177a576]567 basic_string& operator=(basic_string&& other)
568 noexcept(allocator_traits<allocator_type>::propagate_on_container_move_assignment::value ||
[681fdcca]569 allocator_traits<allocator_type>::is_always_equal::value)
570 {
571 if (this != &other)
572 swap(other);
573 }
[52d025c]574
[681fdcca]575 basic_string& operator=(const value_type* other)
576 {
577 *this = basic_string{other};
[52d025c]578
[681fdcca]579 return *this;
580 }
[52d025c]581
[681fdcca]582 basic_string& operator=(value_type c)
583 {
584 *this = basic_string{1, c};
585
586 return *this;
587 }
588
589 basic_string& operator=(initializer_list<value_type> init)
590 {
591 *this = basic_string{init};
592
593 return *this;
594 }
[52d025c]595
[177a576]596 /**
597 * 21.4.3, iterators:
598 */
[52d025c]599
[b08a62c]600 iterator begin() noexcept
601 {
602 return &data_[0];
603 }
[52d025c]604
[b08a62c]605 const_iterator begin() const noexcept
606 {
607 return &data_[0];
608 }
[52d025c]609
[b08a62c]610 iterator end() noexcept
611 {
612 return begin() + size_;
613 }
[52d025c]614
[b08a62c]615 const_iterator end() const noexcept
616 {
617 return begin() + size_;
618 }
[52d025c]619
[177a576]620 reverse_iterator rbegin() noexcept
621 {
[98c99ba]622 return make_reverse_iterator(end());
[177a576]623 }
[52d025c]624
[177a576]625 const_reverse_iterator rbegin() const noexcept
626 {
[98c99ba]627 return make_reverse_iterator(cend());
[177a576]628 }
[52d025c]629
[177a576]630 reverse_iterator rend() noexcept
631 {
[98c99ba]632 return make_reverse_iterator(begin());
[177a576]633 }
[52d025c]634
[177a576]635 const_reverse_iterator rend() const noexcept
636 {
[98c99ba]637 return make_reverse_iterator(cbegin());
[177a576]638 }
[52d025c]639
[b08a62c]640 const_iterator cbegin() const noexcept
641 {
642 return &data_[0];
643 }
[52d025c]644
[b08a62c]645 const_iterator cend() const noexcept
646 {
647 return cbegin() + size_;
648 }
[52d025c]649
[177a576]650 const_reverse_iterator crbegin() const noexcept
651 {
[98c99ba]652 return rbegin();
[177a576]653 }
[52d025c]654
[177a576]655 const_reverse_iterator crend() const noexcept
656 {
[98c99ba]657 return rend();
[177a576]658 }
[52d025c]659
[177a576]660 /**
661 * 21.4.4, capacity:
662 */
[52d025c]663
[b08a62c]664 size_type size() const noexcept
665 {
666 return size_;
667 }
[52d025c]668
[b08a62c]669 size_type length() const noexcept
670 {
[ed81b1f]671 return size();
[b08a62c]672 }
[52d025c]673
[b08a62c]674 size_type max_size() const noexcept
675 {
676 return allocator_traits<allocator_type>::max_size(allocator_);
677 }
[52d025c]678
[681fdcca]679 void resize(size_type new_size, value_type c)
680 {
681 // TODO: if new_size > max_size() throw length_error.
682 if (new_size > size_)
683 {
684 ensure_free_space_(new_size - size_ + 1);
685 for (size_type i = size_; i < new_size; ++i)
686 traits_type::assign(data_[i], i);
687 }
688
689 size_ = new_size;
690 ensure_null_terminator_();
691 }
[52d025c]692
[681fdcca]693 void resize(size_type new_size)
694 {
695 resize(new_size, value_type{});
696 }
[52d025c]697
[b08a62c]698 size_type capacity() const noexcept
699 {
700 return capacity_;
701 }
[52d025c]702
[681fdcca]703 void reserve(size_type new_capacity = 0)
704 {
705 // TODO: if new_capacity > max_size() throw
706 // length_error (this function shall have no
707 // effect in such case)
708 if (new_capacity > capacity_)
709 resize_with_copy_(size_, new_capacity);
710 else if (new_capacity < capacity)
711 shrink_to_fit(); // Non-binding request, but why not.
712 }
[52d025c]713
[681fdcca]714 void shrink_to_fit()
715 {
716 if (size_ != capacity_)
717 resize_with_copy_(size_);
718 }
[52d025c]719
[681fdcca]720 void clear() noexcept
721 {
722 size_ = 0;
723 }
[52d025c]724
[b08a62c]725 bool empty() const noexcept
726 {
727 return size_ == 0;
728 }
[52d025c]729
[177a576]730 /**
731 * 21.4.5, element access:
732 */
[52d025c]733
[b08a62c]734 const_reference operator[](size_type idx) const
735 {
736 return data_[idx];
737 }
[52d025c]738
[b08a62c]739 reference operator[](size_type idx)
740 {
741 return data_[idx];
742 }
[52d025c]743
[b08a62c]744 const_reference at(size_type idx) const
745 {
746 // TODO: bounds checking
747 return data_[idx];
748 }
[52d025c]749
[b08a62c]750 reference at(size_type idx)
751 {
752 // TODO: bounds checking
753 return data_[idx];
754 }
[52d025c]755
[b08a62c]756 const_reference front() const
757 {
758 return at(0);
759 }
[52d025c]760
[b08a62c]761 reference front()
762 {
763 return at(0);
764 }
[52d025c]765
[b08a62c]766 const_reference back() const
767 {
768 return at(size_ - 1);
769 }
[52d025c]770
[b08a62c]771 reference back()
772 {
773 return at(size_ - 1);
774 }
[52d025c]775
[177a576]776 /**
777 * 21.4.6, modifiers:
778 */
[52d025c]779
[681fdcca]780 basic_string& operator+=(const basic_string& str)
781 {
782 return append(str);
783 }
[52d025c]784
[681fdcca]785 basic_string& operator+=(const value_type* str)
786 {
787 return append(str);
788 }
[52d025c]789
[681fdcca]790 basic_string& operator+=(value_type c)
791 {
792 push_back(c);
793 return *this;
794 }
[52d025c]795
[681fdcca]796 basic_string& operator+=(initializer_list<value_type> init)
797 {
798 return append(init.begin(), init.size());
799 }
[52d025c]800
[681fdcca]801 basic_string& append(const basic_string& str)
802 {
803 return append(str.data(), str.size());
804 }
[52d025c]805
[dc0fff11]806 basic_string& append(const basic_string& str, size_type pos,
[681fdcca]807 size_type n = npos)
808 {
809 if (pos < str.size())
810 {
811 auto len = min(n, str.size() - pos);
812
813 return append(str.data() + pos, len);
814 }
815 // TODO: Else throw out_of_range.
816 }
[52d025c]817
[681fdcca]818 basic_string& append(const value_type* str, size_type n)
819 {
820 // TODO: if (size_ + n > max_size()) throw length_error
821 ensure_free_space_(n);
[ed81b1f]822 traits_type::copy(data_ + size(), str, n);
823 size_ += n;
[681fdcca]824 ensure_null_terminator_();
[52d025c]825
[681fdcca]826 return *this;
827 }
[52d025c]828
[681fdcca]829 basic_string& append(const value_type* str)
830 {
[ed81b1f]831 return append(str, traits_type::length(str));
[681fdcca]832 }
833
834 basic_string& append(size_type n, value_type c)
835 {
836 return append(basic_string(n, c));
837 }
[52d025c]838
[177a576]839 template<class InputIterator>
[681fdcca]840 basic_string& append(InputIterator first, InputIterator last)
841 {
[dc0fff11]842 return append(basic_string(first, last));
[681fdcca]843 }
[52d025c]844
[681fdcca]845 basic_string& append(initializer_list<value_type> init)
846 {
847 return append(init.begin(), init.size());
848 }
[52d025c]849
[681fdcca]850 void push_back(value_type c)
851 {
852 ensure_free_space_(1);
853 traits_type::assign(data_[size_++], c);
854 ensure_null_terminator_();
855 }
[52d025c]856
[681fdcca]857 basic_string& assign(const basic_string& str)
858 {
859 return assign(str, 0, npos);
860 }
[52d025c]861
[681fdcca]862 basic_string& assign(basic_string&& str)
863 {
864 swap(str);
865
866 return *this;
867 }
[52d025c]868
[177a576]869 basic_string& assign(const basic_string& str, size_type pos,
[681fdcca]870 size_type n = npos)
871 {
872 if (pos < str.size())
873 {
874 auto len = min(n, str.size() - pos);
875 ensure_free_space_(len);
876
877 return assign(str.data() + pos, len);
878 }
879 // TODO: Else throw out_of_range.
[dc0fff11]880
881 return *this;
[681fdcca]882 }
[52d025c]883
[681fdcca]884 basic_string& assign(const value_type* str, size_type n)
885 {
886 // TODO: if (n > max_size()) throw length_error.
887 resize_without_copy_(n);
888 traits_type::copy(begin(), str, n);
[dc0fff11]889 size_ = n;
890 ensure_null_terminator_();
[681fdcca]891
892 return *this;
893 }
[52d025c]894
[681fdcca]895 basic_string& assign(const value_type* str)
896 {
897 return assign(str, traits_type::length(str));
898 }
[52d025c]899
[681fdcca]900 basic_string& assign(size_type n, value_type c)
901 {
902 return assign(basic_string(n, c));
903 }
[52d025c]904
[177a576]905 template<class InputIterator>
[681fdcca]906 basic_string& assign(InputIterator first, InputIterator last)
907 {
908 return assign(basic_string(first, last));
909 }
[52d025c]910
[681fdcca]911 basic_string& assign(initializer_list<value_type> init)
912 {
913 return assign(init.begin(), init.size());
914 }
[52d025c]915
[681fdcca]916 basic_string& insert(size_type pos, const basic_string& str)
917 {
918 // TODO: if (pos > str.size()) throw out_of_range.
919 return insert(pos, str.data(), str.size());
920 }
[52d025c]921
[177a576]922 basic_string& insert(size_type pos1, const basic_string& str,
[681fdcca]923 size_type pos2, size_type n = npos)
924 {
925 // TODO: if (pos1 > size() or pos2 > str.size()) throw
926 // out_of_range.
927 auto len = min(n, str.size() - pos2);
[52d025c]928
[681fdcca]929 return insert(pos1, str.data() + pos2, len);
930 }
[52d025c]931
[681fdcca]932 basic_string& insert(size_type pos, const value_type* str, size_type n)
933 {
[2d302d6]934 // TODO: throw out_of_range if pos > size()
935 // TODO: throw length_error if size() + n > max_size()
936 ensure_free_space_(n);
937
[681fdcca]938 copy_backward_(begin() + pos, end(), end() + n);
[2d302d6]939 copy_(str, str + n, begin() + pos);
940 size_ += n;
[52d025c]941
[2d302d6]942 ensure_null_terminator_();
[681fdcca]943 return *this;
944 }
[52d025c]945
[681fdcca]946 basic_string& insert(size_type pos, const value_type* str)
947 {
948 return insert(pos, str, traits_type::length(str));
949 }
[52d025c]950
[681fdcca]951 basic_string& insert(size_type pos, size_type n, value_type c)
952 {
953 return insert(pos, basic_string(n, c));
954 }
955
956 iterator insert(const_iterator pos, value_type c)
957 {
958 auto idx = static_cast<size_type>(pos - begin());
959
960 ensure_free_space_(1);
[2d302d6]961 copy_backward_(begin() + idx, end(), end() + 1);
962 traits_type::assign(data_[idx], c);
963
964 ++size_;
[681fdcca]965 ensure_null_terminator_();
966
967 return begin() + idx;
968 }
969
970 iterator insert(const_iterator pos, size_type n, value_type c)
971 {
972 if (n == 0)
973 return const_cast<iterator>(pos);
974
975 auto idx = static_cast<size_type>(pos - begin());
976
977 ensure_free_space_(n);
[2d302d6]978 copy_backward_(begin() + idx, end(), end() + n);
[681fdcca]979
[2d302d6]980 auto it = begin() + idx;
[681fdcca]981 for (size_type i = 0; i < n; ++i)
[dc0fff11]982 traits_type::assign(*it++, c);
[2d302d6]983 size_ += n;
[681fdcca]984 ensure_null_terminator_();
985
986 return begin() + idx;
987 }
[52d025c]988
[177a576]989 template<class InputIterator>
990 iterator insert(const_iterator pos, InputIterator first,
[681fdcca]991 InputIterator last)
992 {
[2d302d6]993 if (first == last)
994 return const_cast<iterator>(pos);
995
996 auto idx = static_cast<size_type>(pos - begin());
997 auto str = basic_string{first, last};
998 insert(idx, str);
999
1000 return begin() + idx;
[681fdcca]1001 }
[52d025c]1002
[681fdcca]1003 iterator insert(const_iterator pos, initializer_list<value_type> init)
1004 {
1005 return insert(pos, init.begin(), init.end());
1006 }
[52d025c]1007
[dc0fff11]1008 basic_string& erase(size_type pos = 0, size_type n = npos)
[681fdcca]1009 {
1010 auto len = min(n, size_ - pos);
1011 copy_(begin() + pos + n, end(), begin() + pos);
1012 size_ -= len;
1013 ensure_null_terminator_();
[e07bbbc]1014
1015 return *this;
[681fdcca]1016 }
[52d025c]1017
[e07bbbc]1018 iterator erase(const_iterator pos)
1019 {
1020 auto idx = static_cast<size_type>(pos - cbegin());
[dc0fff11]1021 erase(idx, 1);
[52d025c]1022
[e07bbbc]1023 return begin() + idx;
1024 }
1025
1026 iterator erase(const_iterator first, const_iterator last)
1027 {
1028 auto idx = static_cast<size_type>(first - cbegin());
1029 auto count = static_cast<size_type>(last - first);
1030 erase(idx, count);
1031
1032 return begin() + idx;
1033 }
[52d025c]1034
[681fdcca]1035 void pop_back()
1036 {
1037 --size_;
1038 ensure_null_terminator_();
1039 }
[52d025c]1040
[b0b46d59]1041 basic_string& replace(size_type pos, size_type n, const basic_string& str)
1042 {
1043 // TODO: throw out_of_range if pos > size()
1044 return replace(pos, n, str.data(), str.size());
1045 }
[52d025c]1046
[dc0fff11]1047 basic_string& replace(size_type pos1, size_type n1, const basic_string& str,
[b0b46d59]1048 size_type pos2, size_type n2 = npos)
1049 {
1050 // TODO: throw out_of_range if pos1 > size() or pos2 > str.size()
1051 auto len = min(n2, str.size() - pos2);
1052 return replace(pos1, n1, str.data() + pos2, len);
1053 }
[52d025c]1054
[177a576]1055 basic_string& replace(size_type pos, size_type n1, const value_type* str,
[b0b46d59]1056 size_type n2)
1057 {
1058 // TODO: throw out_of_range if pos > size()
1059 // TODO: if size() - len > max_size() - n2 throw length_error
[53e8686]1060 auto len = min(n1, size_ - pos);
1061
[b0b46d59]1062 basic_string tmp{};
1063 tmp.resize_without_copy_(size_ - len + n2);
[53e8686]1064
1065 // Prefix.
[b0b46d59]1066 copy_(begin(), begin() + pos, tmp.begin());
[53e8686]1067
1068 // Substitution.
1069 traits_type::copy(tmp.begin() + pos, str, n2);
1070
1071 // Suffix.
1072 copy_(begin() + pos + len, end(), tmp.begin() + pos + n2);
1073
1074 tmp.size_ = size_ - len + n2;
[b0b46d59]1075 swap(tmp);
1076 return *this;
1077 }
[52d025c]1078
[b0b46d59]1079 basic_string& replace(size_type pos, size_type n, const value_type* str)
1080 {
1081 return replace(pos, n, str, traits_type::length(str));
1082 }
[52d025c]1083
[177a576]1084 basic_string& replace(size_type pos, size_type n1, size_type n2,
[b0b46d59]1085 value_type c)
1086 {
1087 return replace(pos, n1, basic_string(n2, c));
1088 }
[52d025c]1089
[177a576]1090 basic_string& replace(const_iterator i1, const_iterator i2,
[b0b46d59]1091 const basic_string& str)
1092 {
1093 return replace(i1 - begin(), i2 - i1, str);
1094 }
[52d025c]1095
[177a576]1096 basic_string& replace(const_iterator i1, const_iterator i2,
[b0b46d59]1097 const value_type* str, size_type n)
1098 {
[dc0fff11]1099 return replace(i1 - begin(), i2 - i1, str, n);
[b0b46d59]1100 }
[52d025c]1101
[177a576]1102 basic_string& replace(const_iterator i1, const_iterator i2,
[b0b46d59]1103 const value_type* str)
1104 {
1105 return replace(i1 - begin(), i2 - i1, str, traits_type::length(str));
1106 }
[52d025c]1107
[177a576]1108 basic_string& replace(const_iterator i1, const_iterator i2,
[b0b46d59]1109 size_type n, value_type c)
1110 {
1111 return replace(i1 - begin(), i2 - i1, basic_string(n, c));
1112 }
[52d025c]1113
[177a576]1114 template<class InputIterator>
1115 basic_string& replace(const_iterator i1, const_iterator i2,
[b0b46d59]1116 InputIterator j1, InputIterator j2)
1117 {
1118 return replace(i1 - begin(), i2 - i1, basic_string(j1, j2));
1119 }
[52d025c]1120
[177a576]1121 basic_string& replace(const_iterator i1, const_iterator i2,
[b0b46d59]1122 initializer_list<value_type> init)
1123 {
1124 return replace(i1 - begin(), i2 - i1, init.begin(), init.size());
1125 }
[52d025c]1126
[27473fb8]1127 size_type copy(value_type* str, size_type n, size_type pos = 0) const
1128 {
1129 auto len = min(n , size_ - pos);
1130 for (size_type i = 0; i < len; ++i)
1131 traits_type::assign(str[i], data_[pos + i]);
1132
1133 return len;
1134 }
[52d025c]1135
[177a576]1136 void swap(basic_string& other)
1137 noexcept(allocator_traits<allocator_type>::propagate_on_container_swap::value ||
[53e8686]1138 allocator_traits<allocator_type>::is_always_equal::value)
[b08a62c]1139 {
1140 std::swap(data_, other.data_);
1141 std::swap(size_, other.size_);
1142 std::swap(capacity_, other.capacity_);
1143 }
[52d025c]1144
[177a576]1145 /**
1146 * 21.4.7, string operations:
1147 */
[52d025c]1148
[b08a62c]1149 const value_type* c_str() const noexcept
1150 {
1151 return data_;
1152 }
[52d025c]1153
[b08a62c]1154 const value_type* data() const noexcept
1155 {
1156 return data_;
1157 }
[52d025c]1158
[b08a62c]1159 allocator_type get_allocator() const noexcept
1160 {
1161 return allocator_type{allocator_};
1162 }
[52d025c]1163
[e07bbbc]1164 /**
1165 * Note: The following find functions have 4 versions each:
1166 * (1) takes basic_string
1167 * (2) takes c string and length
1168 * (3) takes c string
1169 * (4) takes value_type
1170 * According to the C++14 standard, only (1) is marked as
1171 * noexcept and the other three return the first one with
1172 * a newly allocated strings (and thus cannot be noexcept).
1173 * However, allocating a new string results in memory
1174 * allocation and copying of the source and thus we have
1175 * decided to follow C++17 signatures of these functions
1176 * (i.e. all of them being marked as noexcept) and use
1177 * (2) for the actual implementation (and avoiding any
1178 * allocations or copying in the process and also providing
1179 * stronger guarantees to the user).
1180 */
1181
1182 size_type find(const basic_string& str, size_type pos = 0) const noexcept
1183 {
1184 return find(str.c_str(), pos, str.size());
1185 }
1186
1187 size_type find(const value_type* str, size_type pos, size_type len) const noexcept
1188 {
[a6ca1bc]1189 if (empty() || len == 0 || len + pos > size())
[e07bbbc]1190 return npos;
1191
1192 size_type idx{pos};
1193
1194 while (idx + len < size_)
1195 {
1196 if (substr_starts_at_(idx, str, len))
1197 return idx;
1198 ++idx;
1199 }
1200
1201 return npos;
1202 }
1203
1204 size_type find(const value_type* str, size_type pos = 0) const noexcept
1205 {
1206 return find(str, pos, traits_type::length(str));
1207 }
1208
1209 size_type find(value_type c, size_type pos = 0) const noexcept
1210 {
1211 if (empty())
1212 return npos;
1213
1214 for (size_type i = pos; i < size_; ++i)
1215 {
1216 if (traits_type::eq(c, data_[i]))
1217 return i;
1218 }
1219
1220 return npos;
1221 }
1222
1223 size_type rfind(const basic_string& str, size_type pos = npos) const noexcept
1224 {
1225 return rfind(str.c_str(), pos, str.size());
1226 }
1227
1228 size_type rfind(const value_type* str, size_type pos, size_type len) const noexcept
1229 {
[a6ca1bc]1230 if (empty() || len == 0 || len + pos > size())
[e07bbbc]1231 return npos;
1232
1233 size_type idx{min(pos, size_ - 1) + 1};
1234
1235 while (idx > 0)
1236 {
1237 if (substr_starts_at_(idx - 1, str, len))
1238 return idx - 1;
1239 --idx;
1240 }
1241
1242 return npos;
1243 }
1244
1245 size_type rfind(const value_type* str, size_type pos = npos) const noexcept
1246 {
1247 return rfind(str, pos, traits_type::length(str));
1248 }
1249
1250 size_type rfind(value_type c, size_type pos = npos) const noexcept
1251 {
1252 if (empty())
1253 return npos;
1254
[a6ca1bc]1255 for (size_type i = min(pos + 1, size_ - 1) + 1; i > 0; --i)
[e07bbbc]1256 {
1257 if (traits_type::eq(c, data_[i - 1]))
1258 return i - 1;
1259 }
1260
1261 return npos;
1262 }
1263
1264 size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept
1265 {
1266 return find_first_of(str.c_str(), pos, str.size());
1267 }
1268
1269 size_type find_first_of(const value_type* str, size_type pos, size_type len) const noexcept
1270 {
[a6ca1bc]1271 if (empty() || len == 0 || pos >= size())
[e07bbbc]1272 return npos;
1273
1274 size_type idx{pos};
1275
1276 while (idx < size_)
1277 {
1278 if (is_any_of_(idx, str, len))
1279 return idx;
1280 ++idx;
1281 }
1282
1283 return npos;
1284 }
1285
1286 size_type find_first_of(const value_type* str, size_type pos = 0) const noexcept
1287 {
1288 return find_first_of(str, pos, traits_type::length(str));
1289 }
1290
1291 size_type find_first_of(value_type c, size_type pos = 0) const noexcept
1292 {
1293 return find(c, pos);
1294 }
[52d025c]1295
[e07bbbc]1296 size_type find_last_of(const basic_string& str, size_type pos = npos) const noexcept
1297 {
1298 return find_last_of(str.c_str(), pos, str.size());
1299 }
[52d025c]1300
[e07bbbc]1301 size_type find_last_of(const value_type* str, size_type pos, size_type len) const noexcept
1302 {
[a6ca1bc]1303 if (empty() || len == 0)
[e07bbbc]1304 return npos;
[52d025c]1305
[e07bbbc]1306 for (size_type i = min(pos, size_ - 1) + 1; i > 0; --i)
1307 {
1308 if (is_any_of_(i - 1, str, len))
1309 return i - 1;
1310 }
[52d025c]1311
[e07bbbc]1312 return npos;
1313 }
[52d025c]1314
[e07bbbc]1315 size_type find_last_of(const value_type* str, size_type pos = npos) const noexcept
1316 {
1317 return find_last_of(str, pos, traits_type::length(str));
1318 }
[52d025c]1319
[e07bbbc]1320 size_type find_last_of(value_type c, size_type pos = npos) const noexcept
1321 {
1322 return rfind(c, pos);
1323 }
[52d025c]1324
[e07bbbc]1325 size_type find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept
1326 {
1327 return find_first_not_of(str.c_str(), pos, str.size());
1328 }
[52d025c]1329
[e07bbbc]1330 size_type find_first_not_of(const value_type* str, size_type pos, size_type len) const noexcept
1331 {
[a6ca1bc]1332 if (empty() || pos >= size())
[e07bbbc]1333 return npos;
[52d025c]1334
[e07bbbc]1335 size_type idx{pos};
[52d025c]1336
[e07bbbc]1337 while (idx < size_)
1338 {
1339 if (!is_any_of_(idx, str, len))
1340 return idx;
1341 ++idx;
1342 }
[52d025c]1343
[e07bbbc]1344 return npos;
1345 }
[52d025c]1346
[e07bbbc]1347 size_type find_first_not_of(const value_type* str, size_type pos = 0) const noexcept
1348 {
[a6ca1bc]1349 return find_first_not_of(str, pos, traits_type::length(str));
[e07bbbc]1350 }
[52d025c]1351
[e07bbbc]1352 size_type find_first_not_of(value_type c, size_type pos = 0) const noexcept
1353 {
1354 if (empty())
1355 return npos;
[52d025c]1356
[e07bbbc]1357 for (size_type i = pos; i < size_; ++i)
1358 {
1359 if (!traits_type::eq(c, data_[i]))
1360 return i;
1361 }
[52d025c]1362
[e07bbbc]1363 return npos;
1364 }
[52d025c]1365
[e07bbbc]1366 size_type find_last_not_of(const basic_string& str, size_type pos = npos) const noexcept
1367 {
1368 return find_last_not_of(str.c_str(), pos, str.size());
1369 }
[52d025c]1370
[e07bbbc]1371 size_type find_last_not_of(const value_type* str, size_type pos, size_type len) const noexcept
1372 {
1373 if (empty())
1374 return npos;
[52d025c]1375
[e07bbbc]1376 for (size_type i = min(pos, size_ - 1) + 1; i > 0; --i)
1377 {
[a6ca1bc]1378 if (!is_any_of_(i - 1, str, len))
[e07bbbc]1379 return i - 1;
1380 }
[52d025c]1381
[e07bbbc]1382 return npos;
1383 }
[52d025c]1384
[e07bbbc]1385 size_type find_last_not_of(const value_type* str, size_type pos = npos) const noexcept
1386 {
1387 return find_last_not_of(str, pos, traits_type::length(str));
1388 }
[52d025c]1389
[e07bbbc]1390 size_type find_last_not_of(value_type c, size_type pos = npos) const noexcept
1391 {
1392 if (empty())
1393 return npos;
[52d025c]1394
[e07bbbc]1395 pos = min(pos, size_ - 1);
[52d025c]1396
[e07bbbc]1397 for (size_type i = min(pos, size_ - 1) + 1; i > 1; --i)
1398 {
1399 if (!traits_type::eq(c, data_[i - 1]))
1400 return i - 1;
1401 }
[52d025c]1402
[e07bbbc]1403 return npos;
1404 }
[52d025c]1405
[e07bbbc]1406 basic_string substr(size_type pos = 0, size_type n = npos) const
1407 {
1408 // TODO: throw out_of_range if pos > size().
1409 auto len = min(n, size_ - pos);
1410 return basic_string{data() + pos, len};
1411 }
[52d025c]1412
[e07bbbc]1413 int compare(const basic_string& other) const noexcept
1414 {
1415 auto len = min(size(), other.size());
1416 auto comp = traits_type::compare(data_, other.data(), len);
1417
1418 if (comp != 0)
1419 return comp;
1420 else if (size() == other.size())
1421 return 0;
1422 else if (size() > other.size())
1423 return 1;
[4e6fb2f]1424 else
[e07bbbc]1425 return -1;
1426 }
1427
1428 int compare(size_type pos, size_type n, const basic_string& other) const
1429 {
1430 return basic_string{*this, pos, n}.compare(other);
1431 }
[52d025c]1432
[177a576]1433 int compare(size_type pos1, size_type n1, const basic_string& other,
[e07bbbc]1434 size_type pos2, size_type n2 = npos) const
1435 {
1436 return basic_string{*this, pos1, n1}.compare(basic_string{other, pos2, n2});
1437 }
[52d025c]1438
[e07bbbc]1439 int compare(const value_type* other) const
1440 {
1441 return compare(basic_string(other));
1442 }
[52d025c]1443
[e07bbbc]1444 int compare(size_type pos, size_type n, const value_type* other) const
1445 {
1446 return basic_string{*this, pos, n}.compare(basic_string{other});
1447 }
[52d025c]1448
[e07bbbc]1449 int compare(size_type pos, size_type n1,
1450 const value_type* other, size_type n2) const
1451 {
1452 return basic_string{*this, pos, n1}.compare(basic_string{other, n2});
1453 }
[b08a62c]1454
1455 private:
1456 value_type* data_;
1457 size_type size_;
1458 size_type capacity_;
1459 allocator_type allocator_;
[681fdcca]1460
1461 /**
1462 * Arbitrary value, standard just requires
1463 * data() to have some capacity.
1464 * (Well, we could've done data_ = &data_ and
1465 * set capacity to 0, but that would be too cryptic.)
1466 */
[dc0fff11]1467 static constexpr size_type default_capacity_{4};
[681fdcca]1468
1469 void init_(const value_type* str, size_type size)
1470 {
1471 if (data_)
1472 allocator_.deallocate(data_, capacity_);
1473
1474 size_ = size;
1475 capacity_ = size;
1476
1477 data_ = allocator_.allocate(capacity_);
1478 traits_type::copy(data_, str, size);
1479 ensure_null_terminator_();
1480 }
1481
1482 size_type next_capacity_(size_type hint = 0) const noexcept
1483 {
1484 if (hint != 0)
1485 return max(capacity_ * 2, hint);
1486 else
1487 return max(capacity_ * 2, 2ul);
1488 }
1489
1490 void ensure_free_space_(size_type n)
1491 {
1492 /**
1493 * Note: We cannot use reserve like we
1494 * did in vector, because in string
1495 * reserve can cause shrinking.
1496 */
[dc0fff11]1497 if (size_ + 1 + n > capacity_)
[681fdcca]1498 resize_with_copy_(size_, max(size_ + 1 + n, next_capacity_()));
1499 }
1500
1501 void resize_without_copy_(size_type capacity)
1502 {
1503 if (data_)
1504 allocator_.deallocate(data_, capacity_);
1505
1506 data_ = allocator_.allocate(capacity);
1507 size_ = 0;
1508 capacity_ = capacity;
1509 ensure_null_terminator_();
1510 }
1511
1512 void resize_with_copy_(size_type size, size_type capacity)
1513 {
1514 if(capacity_ == 0 || capacity_ < capacity)
1515 {
1516 auto new_data = allocator_.allocate(capacity);
1517
1518 auto to_copy = min(size, size_);
1519 traits_type::move(new_data, data_, to_copy);
1520
1521 std::swap(data_, new_data);
1522
1523 allocator_.deallocate(new_data, capacity_);
1524 }
1525
1526 capacity_ = capacity;
1527 size_ = size;
1528 ensure_null_terminator_();
1529 }
1530
[2d302d6]1531 template<class Iterator1, class Iterator2>
1532 Iterator2 copy_(Iterator1 first, Iterator1 last,
1533 Iterator2 result)
[681fdcca]1534 {
1535 while (first != last)
1536 traits_type::assign(*result++, *first++);
1537
1538 return result;
1539 }
1540
[2d302d6]1541 template<class Iterator1, class Iterator2>
1542 Iterator2 copy_backward_(Iterator1 first, Iterator1 last,
1543 Iterator2 result)
[681fdcca]1544 {
[2d302d6]1545 while (last != first)
1546 traits_type::assign(*--result, *--last);
[681fdcca]1547
1548 return result;
1549 }
1550
1551 void ensure_null_terminator_()
1552 {
[dc0fff11]1553 value_type c{};
1554 traits_type::assign(data_[size_], c);
[681fdcca]1555 }
[e07bbbc]1556
[a6ca1bc]1557 bool is_any_of_(size_type idx, const value_type* str, size_type len) const
[e07bbbc]1558 {
[a6ca1bc]1559 for (size_type i = 0; i < len; ++i)
[e07bbbc]1560 {
[a6ca1bc]1561 if (traits_type::eq(data_[idx], str[i]))
[e07bbbc]1562 return true;
1563 }
1564
1565 return false;
1566 }
1567
1568 bool substr_starts_at_(size_type idx, const value_type* str, size_type len) const
1569 {
1570 size_type i{};
1571 for (i = 0; i < len; ++i)
1572 {
1573 if (!traits_type::eq(data_[idx + i], str[i]))
1574 break;
1575 }
1576
1577 return i == len;
1578 }
[52d025c]1579 };
[dc0fff11]1580
[82b6716]1581 using string = basic_string<char>;
1582 using u16string = basic_string<char16_t>;
1583 using u32string = basic_string<char32_t>;
1584 using wstring = basic_string<wchar_t>;
1585
1586 /**
1587 * 21.4.8, basic_string non-member functions:
1588 */
1589
1590 /**
1591 * 21.4.8.1, operator+:
1592 */
1593
1594 template<class Char, class Traits, class Allocator>
1595 basic_string<Char, Traits, Allocator>
1596 operator+(const basic_string<Char, Traits, Allocator>& lhs,
1597 const basic_string<Char, Traits, Allocator>& rhs)
1598 {
1599 return basic_string<Char, Traits, Allocator>{lhs}.append(rhs);
1600 }
1601
1602 template<class Char, class Traits, class Allocator>
1603 basic_string<Char, Traits, Allocator>
1604 operator+(basic_string<Char, Traits, Allocator>&& lhs,
1605 const basic_string<Char, Traits, Allocator>& rhs)
1606 {
1607 return move(lhs.append(rhs));
1608 }
1609
1610 template<class Char, class Traits, class Allocator>
1611 basic_string<Char, Traits, Allocator>
1612 operator+(const basic_string<Char, Traits, Allocator>& lhs,
1613 basic_string<Char, Traits, Allocator>&& rhs)
1614 {
1615 return move(rhs.insert(0, lhs));
1616 }
1617
1618 template<class Char, class Traits, class Allocator>
1619 basic_string<Char, Traits, Allocator>
1620 operator+(basic_string<Char, Traits, Allocator>&& lhs,
1621 basic_string<Char, Traits, Allocator>&& rhs)
1622 {
1623 return move(lhs.append(rhs));
1624 }
1625
1626 template<class Char, class Traits, class Allocator>
1627 basic_string<Char, Traits, Allocator>
1628 operator+(const Char* lhs,
1629 const basic_string<Char, Traits, Allocator>& rhs)
1630 {
1631 return basic_string<Char, Traits, Allocator>{lhs} + rhs;
1632 }
1633
1634 template<class Char, class Traits, class Allocator>
1635 basic_string<Char, Traits, Allocator>
1636 operator+(const Char* lhs,
1637 basic_string<Char, Traits, Allocator>&& rhs)
1638 {
1639 return move(rhs.insert(0, lhs));
1640 }
1641
1642 template<class Char, class Traits, class Allocator>
1643 basic_string<Char, Traits, Allocator>
1644 operator+(Char lhs,
1645 const basic_string<Char, Traits, Allocator>& rhs)
1646 {
1647 return basic_string<Char, Traits, Allocator>{1, lhs}.append(rhs);
1648 }
1649
1650 template<class Char, class Traits, class Allocator>
1651 basic_string<Char, Traits, Allocator>
1652 operator+(Char lhs,
1653 basic_string<Char, Traits, Allocator>&& rhs)
1654 {
1655 return move(rhs.insert(0, 1, lhs));
1656 }
1657
1658 template<class Char, class Traits, class Allocator>
1659 basic_string<Char, Traits, Allocator>
1660 operator+(const basic_string<Char, Traits, Allocator>& lhs,
1661 const Char* rhs)
1662 {
1663 return lhs + basic_string<Char, Traits, Allocator>{rhs};
1664 }
1665
1666 template<class Char, class Traits, class Allocator>
1667 basic_string<Char, Traits, Allocator>
1668 operator+(basic_string<Char, Traits, Allocator>&& lhs,
1669 const Char* rhs)
1670 {
1671 return move(lhs.append(rhs));
1672 }
1673
1674 template<class Char, class Traits, class Allocator>
1675 basic_string<Char, Traits, Allocator>
1676 operator+(const basic_string<Char, Traits, Allocator>& lhs,
1677 Char rhs)
1678 {
1679 return lhs + basic_string<Char, Traits, Allocator>{1, rhs};
1680 }
1681
1682 template<class Char, class Traits, class Allocator>
1683 basic_string<Char, Traits, Allocator>
1684 operator+(basic_string<Char, Traits, Allocator>&& lhs,
1685 Char rhs)
1686 {
1687 return move(lhs.append(1, rhs));
1688 }
1689
1690 /**
1691 * 21.4.8.2, operator==:
1692 */
1693
1694 template<class Char, class Traits, class Allocator>
1695 basic_string<Char, Traits, Allocator>
1696 operator==(const basic_string<Char, Traits, Allocator>& lhs,
1697 const basic_string<Char, Traits, Allocator>& rhs) noexcept
1698 {
1699 return lhs.compare(rhs) == 0;
1700 }
1701
1702 template<class Char, class Traits, class Allocator>
1703 basic_string<Char, Traits, Allocator>
1704 operator==(const Char* lhs,
1705 const basic_string<Char, Traits, Allocator>& rhs)
1706 {
1707 return rhs == lhs;
1708 }
1709
1710 template<class Char, class Traits, class Allocator>
1711 basic_string<Char, Traits, Allocator>
1712 operator==(const basic_string<Char, Traits, Allocator>& lhs,
1713 const Char* rhs)
1714 {
1715 return lhs.compare(rhs) == 0;
1716 }
1717
1718 /**
1719 * 21.4.8.3, operator!=:
1720 */
1721
1722 template<class Char, class Traits, class Allocator>
1723 basic_string<Char, Traits, Allocator>
1724 operator!=(const basic_string<Char, Traits, Allocator>& lhs,
1725 const basic_string<Char, Traits, Allocator>& rhs) noexcept
1726 {
1727 return !(lhs == rhs);
1728 }
1729
1730 template<class Char, class Traits, class Allocator>
1731 basic_string<Char, Traits, Allocator>
1732 operator!=(const Char* lhs,
1733 const basic_string<Char, Traits, Allocator>& rhs)
1734 {
1735 return rhs != lhs;
1736 }
1737
1738 template<class Char, class Traits, class Allocator>
1739 basic_string<Char, Traits, Allocator>
1740 operator!=(const basic_string<Char, Traits, Allocator>& lhs,
1741 const Char* rhs)
1742 {
1743 return lhs.compare(rhs) != 0;
1744 }
1745
1746 /**
1747 * 21.4.8.4, operator<:
1748 */
1749
1750 template<class Char, class Traits, class Allocator>
1751 basic_string<Char, Traits, Allocator>
1752 operator<(const basic_string<Char, Traits, Allocator>& lhs,
1753 const basic_string<Char, Traits, Allocator>& rhs) noexcept
1754 {
1755 return lhs.compare(rhs) < 0;
1756 }
1757
1758 template<class Char, class Traits, class Allocator>
1759 basic_string<Char, Traits, Allocator>
1760 operator<(const Char* lhs,
1761 const basic_string<Char, Traits, Allocator>& rhs)
1762 {
1763 return rhs.compare(lhs) > 0;
1764 }
1765
1766 template<class Char, class Traits, class Allocator>
1767 basic_string<Char, Traits, Allocator>
1768 operator<(const basic_string<Char, Traits, Allocator>& lhs,
1769 const Char* rhs)
1770 {
1771 return lhs.compare(rhs) < 0;
1772 }
1773
1774 /**
1775 * 21.4.8.5, operator>:
1776 */
1777
1778 template<class Char, class Traits, class Allocator>
1779 basic_string<Char, Traits, Allocator>
1780 operator>(const basic_string<Char, Traits, Allocator>& lhs,
1781 const basic_string<Char, Traits, Allocator>& rhs) noexcept
1782 {
1783 return lhs.compare(rhs) > 0;
1784 }
1785
1786 template<class Char, class Traits, class Allocator>
1787 basic_string<Char, Traits, Allocator>
1788 operator>(const Char* lhs,
1789 const basic_string<Char, Traits, Allocator>& rhs)
1790 {
1791 return rhs.compare(lhs) < 0;
1792 }
1793
1794 template<class Char, class Traits, class Allocator>
1795 basic_string<Char, Traits, Allocator>
1796 operator>(const basic_string<Char, Traits, Allocator>& lhs,
1797 const Char* rhs)
1798 {
1799 return lhs.compare(rhs) > 0;
1800 }
1801
1802 /**
1803 * 21.4.8.6, operator<=:
1804 */
1805
1806 template<class Char, class Traits, class Allocator>
1807 basic_string<Char, Traits, Allocator>
1808 operator<=(const basic_string<Char, Traits, Allocator>& lhs,
1809 const basic_string<Char, Traits, Allocator>& rhs) noexcept
1810 {
1811 return lhs.compare(rhs) <= 0;
1812 }
1813
1814 template<class Char, class Traits, class Allocator>
1815 basic_string<Char, Traits, Allocator>
1816 operator<=(const Char* lhs,
1817 const basic_string<Char, Traits, Allocator>& rhs)
1818 {
1819 return rhs.compare(lhs) >= 0;
1820 }
1821
1822 template<class Char, class Traits, class Allocator>
1823 basic_string<Char, Traits, Allocator>
1824 operator<=(const basic_string<Char, Traits, Allocator>& lhs,
1825 const Char* rhs)
1826 {
1827 return lhs.compare(rhs) <= 0;
1828 }
1829
1830 /**
1831 * 21.4.8.7, operator>=:
1832 */
1833
1834 template<class Char, class Traits, class Allocator>
1835 basic_string<Char, Traits, Allocator>
1836 operator>=(const basic_string<Char, Traits, Allocator>& lhs,
1837 const basic_string<Char, Traits, Allocator>& rhs) noexcept
1838 {
1839 return lhs.compare(rhs) >= 0;
1840 }
1841
1842 template<class Char, class Traits, class Allocator>
1843 basic_string<Char, Traits, Allocator>
1844 operator>=(const Char* lhs,
1845 const basic_string<Char, Traits, Allocator>& rhs)
1846 {
1847 return rhs.compare(lhs) <= 0;
1848 }
1849
1850 template<class Char, class Traits, class Allocator>
1851 basic_string<Char, Traits, Allocator>
1852 operator>=(const basic_string<Char, Traits, Allocator>& lhs,
1853 const Char* rhs)
1854 {
1855 return lhs.compare(rhs) >= 0;
1856 }
1857
1858 /**
1859 * 21.4.8.8, swap:
1860 */
1861
1862 template<class Char, class Traits, class Allocator>
1863 void swap(basic_string<Char, Traits, Allocator>& lhs,
1864 basic_string<Char, Traits, Allocator>& rhs)
1865 noexcept(noexcept(lhs.swap(rhs)))
1866 {
1867 lhs.swap(rhs);
1868 }
1869
1870 /**
1871 * 21.4.8.9, inserters and extractors:
1872 */
1873
1874 // TODO: implement
1875
1876 /**
1877 * 21.5, numeric conversions:
1878 */
1879
1880 int stoi(const string& str, size_t* idx = nullptr, int base = 10);
1881 long stol(const string& str, size_t* idx = nullptr, int base = 10);
1882 unsigned long stoul(const string& str, size_t* idx = nullptr, int base = 10);
1883 long long stoll(const string& str, size_t* idx = nullptr, int base = 10);
1884 unsigned long long stoull(const string& str, size_t* idx = nullptr, int base = 10);
1885
1886 float stof(const string& str, size_t* idx = nullptr);
1887 double stod(const string& str, size_t* idx = nullptr);
1888 long double stold(const string& str, size_t* idx = nullptr);
1889
1890 string to_string(int val);
1891 string to_string(unsigned val);
1892 string to_string(long val);
1893 string to_string(unsigned long val);
1894 string to_string(long long val);
1895 string to_string(unsigned long long val);
1896 string to_string(float val);
1897 string to_string(double val);
1898 string to_string(long double val);
1899
1900 int stoi(const wstring& str, size_t* idx = nullptr, int base = 10);
1901 long stol(const wstring& str, size_t* idx = nullptr, int base = 10);
1902 unsigned long stoul(const wstring& str, size_t* idx = nullptr, int base = 10);
1903 long long stoll(const wstring& str, size_t* idx = nullptr, int base = 10);
1904 unsigned long long stoull(const wstring& str, size_t* idx = nullptr, int base = 10);
1905
1906 float stof(const wstring& str, size_t* idx = nullptr);
1907 double stod(const wstring& str, size_t* idx = nullptr);
1908 long double stold(const wstring& str, size_t* idx = nullptr);
1909
1910 wstring to_wstring(int val);
1911 wstring to_wstring(unsigned val);
1912 wstring to_wstring(long val);
1913 wstring to_wstring(unsigned long val);
1914 wstring to_wstring(long long val);
1915 wstring to_wstring(unsigned long long val);
1916 wstring to_wstring(float val);
1917 wstring to_wstring(double val);
1918 wstring to_wstring(long double val);
1919
1920 /**
1921 * 21.6, hash support:
1922 */
1923
1924 // TODO: implement
1925
1926 /**
1927 * 21.7, suffix for basic_string literals:
1928 */
1929
1930 /**
1931 * Note: According to the standard, literal suffixes that do not
1932 * start with an underscore are reserved for future standardization,
1933 * but since we are implementing the standard, we're going to ignore it.
1934 * This should work (according to their documentation) work for clang,
1935 * but that should be tested.
1936 */
1937#pragma GCC diagnostic push
1938#pragma GCC diagnostic ignored "-Wliteral-suffix"
1939 string operator "" s(const char* str, size_t len);
1940 u16string operator "" s(const char16_t* str, size_t len);
1941 u32string operator "" s(const char32_t* str, size_t len);
1942
1943 /* Problem: wchar_t == int in HelenOS, but standard forbids it.
1944 wstring operator "" s(const wchar_t* str, size_t len);
1945 */
1946#pragma GCC diagnostic pop
[52d025c]1947}
1948
1949#endif
Note: See TracBrowser for help on using the repository browser.