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

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

cpp: added missing return statements and fixed return types on operators caused by bad copypastas

  • Property mode set to 100644
File size: 58.8 KB
Line 
1/*
2 * Copyright (c) 2017 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_STRING
30#define LIBCPP_STRING
31
32#include <algorithm>
33#include <iosfwd>
34#include <iterator>
35#include <cstdio>
36#include <cstdlib>
37#include <cstring>
38#include <memory>
39#include <utility>
40
41#include <initializer_list>
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
66 static void assign(char_type& c1, const char_type& c2) noexcept
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 {
88 return std::str_size(s);
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 {
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 };
239
240 template<>
241 struct char_traits<char32_t>
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 };
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
337 static void assign(char_type& c1, const char_type& c2) noexcept
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 {
354 // TODO: This function does not exits...
355 //return std::wstr_lcmp(s1, s2, n);
356 return 0;
357 }
358
359 static size_t length(const char_type* s)
360 {
361 return std::wstr_size(s);
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 {
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;
434
435 using reference = value_type&;
436 using const_reference = const value_type&;
437 using pointer = typename allocator_traits<allocator_type>::pointer;
438 using const_pointer = typename allocator_traits<allocator_type>::const_pointer;
439
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>;
444
445 static constexpr size_type npos = -1;
446
447 /**
448 * 21.4.2, construct/copy/destroy:
449 */
450 basic_string() noexcept
451 : basic_string(allocator_type{})
452 { /* DUMMY BODY */ }
453
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 */
463 data_ = allocator_.allocate(default_capacity_);
464 capacity_ = default_capacity_;
465 }
466
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 }
473
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 }
482
483 basic_string(const basic_string& other, size_type pos, size_type n = npos,
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 }
491
492 basic_string(const value_type* str, size_type n, const allocator_type& alloc = allocator_type{})
493 : data_{}, size_{n}, capacity_{n}, allocator_{alloc}
494 {
495 init_(str, size_);
496 }
497
498 basic_string(const value_type* str, const allocator_type& alloc = allocator_type{})
499 : data_{}, size_{}, capacity_{}, allocator_{alloc}
500 {
501 init_(str, traits_type::length(str));
502 }
503
504 basic_string(size_type n, value_type c, const allocator_type& alloc = allocator_type{})
505 : data_{}, size_{n}, capacity_{n}, allocator_{alloc}
506 {
507 data_ = allocator_.allocate(capacity_);
508 for (size_type i = 0; i < size_; ++i)
509 traits_type::assign(data_[i], c);
510 ensure_null_terminator_();
511 }
512
513 template<class InputIterator>
514 basic_string(InputIterator first, InputIterator last,
515 const allocator_type& alloc = allocator_type{})
516 : data_{}, size_{}, capacity_{}, allocator_{alloc}
517 {
518 if constexpr (is_integral<InputIterator>::value)
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);
531 init_(first, len);
532 }
533 }
534
535 basic_string(initializer_list<value_type> init, const allocator_type& alloc = allocator_type{})
536 : basic_string{init.begin(), init.size(), alloc}
537 { /* DUMMY BODY */ }
538
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 }
544
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 }
552
553 ~basic_string()
554 {
555 allocator_.deallocate(data_, capacity_);
556 }
557
558 basic_string& operator=(const basic_string& other)
559 {
560 if (this != &other)
561 {
562 basic_string tmp{other};
563 swap(tmp);
564 }
565
566 return *this;
567 }
568
569 basic_string& operator=(basic_string&& other)
570 noexcept(allocator_traits<allocator_type>::propagate_on_container_move_assignment::value ||
571 allocator_traits<allocator_type>::is_always_equal::value)
572 {
573 if (this != &other)
574 swap(other);
575
576 return *this;
577 }
578
579 basic_string& operator=(const value_type* other)
580 {
581 *this = basic_string{other};
582
583 return *this;
584 }
585
586 basic_string& operator=(value_type c)
587 {
588 *this = basic_string{1, c};
589
590 return *this;
591 }
592
593 basic_string& operator=(initializer_list<value_type> init)
594 {
595 *this = basic_string{init};
596
597 return *this;
598 }
599
600 /**
601 * 21.4.3, iterators:
602 */
603
604 iterator begin() noexcept
605 {
606 return &data_[0];
607 }
608
609 const_iterator begin() const noexcept
610 {
611 return &data_[0];
612 }
613
614 iterator end() noexcept
615 {
616 return begin() + size_;
617 }
618
619 const_iterator end() const noexcept
620 {
621 return begin() + size_;
622 }
623
624 reverse_iterator rbegin() noexcept
625 {
626 return make_reverse_iterator(end());
627 }
628
629 const_reverse_iterator rbegin() const noexcept
630 {
631 return make_reverse_iterator(cend());
632 }
633
634 reverse_iterator rend() noexcept
635 {
636 return make_reverse_iterator(begin());
637 }
638
639 const_reverse_iterator rend() const noexcept
640 {
641 return make_reverse_iterator(cbegin());
642 }
643
644 const_iterator cbegin() const noexcept
645 {
646 return &data_[0];
647 }
648
649 const_iterator cend() const noexcept
650 {
651 return cbegin() + size_;
652 }
653
654 const_reverse_iterator crbegin() const noexcept
655 {
656 return rbegin();
657 }
658
659 const_reverse_iterator crend() const noexcept
660 {
661 return rend();
662 }
663
664 /**
665 * 21.4.4, capacity:
666 */
667
668 size_type size() const noexcept
669 {
670 return size_;
671 }
672
673 size_type length() const noexcept
674 {
675 return size();
676 }
677
678 size_type max_size() const noexcept
679 {
680 return allocator_traits<allocator_type>::max_size(allocator_);
681 }
682
683 void resize(size_type new_size, value_type c)
684 {
685 // TODO: if new_size > max_size() throw length_error.
686 if (new_size > size_)
687 {
688 ensure_free_space_(new_size - size_ + 1);
689 for (size_type i = size_; i < new_size; ++i)
690 traits_type::assign(data_[i], i);
691 }
692
693 size_ = new_size;
694 ensure_null_terminator_();
695 }
696
697 void resize(size_type new_size)
698 {
699 resize(new_size, value_type{});
700 }
701
702 size_type capacity() const noexcept
703 {
704 return capacity_;
705 }
706
707 void reserve(size_type new_capacity = 0)
708 {
709 // TODO: if new_capacity > max_size() throw
710 // length_error (this function shall have no
711 // effect in such case)
712 if (new_capacity > capacity_)
713 resize_with_copy_(size_, new_capacity);
714 else if (new_capacity < capacity)
715 shrink_to_fit(); // Non-binding request, but why not.
716 }
717
718 void shrink_to_fit()
719 {
720 if (size_ != capacity_)
721 resize_with_copy_(size_);
722 }
723
724 void clear() noexcept
725 {
726 size_ = 0;
727 }
728
729 bool empty() const noexcept
730 {
731 return size_ == 0;
732 }
733
734 /**
735 * 21.4.5, element access:
736 */
737
738 const_reference operator[](size_type idx) const
739 {
740 return data_[idx];
741 }
742
743 reference operator[](size_type idx)
744 {
745 return data_[idx];
746 }
747
748 const_reference at(size_type idx) const
749 {
750 // TODO: bounds checking
751 return data_[idx];
752 }
753
754 reference at(size_type idx)
755 {
756 // TODO: bounds checking
757 return data_[idx];
758 }
759
760 const_reference front() const
761 {
762 return at(0);
763 }
764
765 reference front()
766 {
767 return at(0);
768 }
769
770 const_reference back() const
771 {
772 return at(size_ - 1);
773 }
774
775 reference back()
776 {
777 return at(size_ - 1);
778 }
779
780 /**
781 * 21.4.6, modifiers:
782 */
783
784 basic_string& operator+=(const basic_string& str)
785 {
786 return append(str);
787 }
788
789 basic_string& operator+=(const value_type* str)
790 {
791 return append(str);
792 }
793
794 basic_string& operator+=(value_type c)
795 {
796 push_back(c);
797 return *this;
798 }
799
800 basic_string& operator+=(initializer_list<value_type> init)
801 {
802 return append(init.begin(), init.size());
803 }
804
805 basic_string& append(const basic_string& str)
806 {
807 return append(str.data(), str.size());
808 }
809
810 basic_string& append(const basic_string& str, size_type pos,
811 size_type n = npos)
812 {
813 if (pos < str.size())
814 {
815 auto len = min(n, str.size() - pos);
816
817 return append(str.data() + pos, len);
818 }
819 // TODO: Else throw out_of_range.
820 }
821
822 basic_string& append(const value_type* str, size_type n)
823 {
824 // TODO: if (size_ + n > max_size()) throw length_error
825 ensure_free_space_(n);
826 traits_type::copy(data_ + size(), str, n);
827 size_ += n;
828 ensure_null_terminator_();
829
830 return *this;
831 }
832
833 basic_string& append(const value_type* str)
834 {
835 return append(str, traits_type::length(str));
836 }
837
838 basic_string& append(size_type n, value_type c)
839 {
840 return append(basic_string(n, c));
841 }
842
843 template<class InputIterator>
844 basic_string& append(InputIterator first, InputIterator last)
845 {
846 return append(basic_string(first, last));
847 }
848
849 basic_string& append(initializer_list<value_type> init)
850 {
851 return append(init.begin(), init.size());
852 }
853
854 void push_back(value_type c)
855 {
856 ensure_free_space_(1);
857 traits_type::assign(data_[size_++], c);
858 ensure_null_terminator_();
859 }
860
861 basic_string& assign(const basic_string& str)
862 {
863 return assign(str, 0, npos);
864 }
865
866 basic_string& assign(basic_string&& str)
867 {
868 swap(str);
869
870 return *this;
871 }
872
873 basic_string& assign(const basic_string& str, size_type pos,
874 size_type n = npos)
875 {
876 if (pos < str.size())
877 {
878 auto len = min(n, str.size() - pos);
879 ensure_free_space_(len);
880
881 return assign(str.data() + pos, len);
882 }
883 // TODO: Else throw out_of_range.
884
885 return *this;
886 }
887
888 basic_string& assign(const value_type* str, size_type n)
889 {
890 // TODO: if (n > max_size()) throw length_error.
891 resize_without_copy_(n);
892 traits_type::copy(begin(), str, n);
893 size_ = n;
894 ensure_null_terminator_();
895
896 return *this;
897 }
898
899 basic_string& assign(const value_type* str)
900 {
901 return assign(str, traits_type::length(str));
902 }
903
904 basic_string& assign(size_type n, value_type c)
905 {
906 return assign(basic_string(n, c));
907 }
908
909 template<class InputIterator>
910 basic_string& assign(InputIterator first, InputIterator last)
911 {
912 return assign(basic_string(first, last));
913 }
914
915 basic_string& assign(initializer_list<value_type> init)
916 {
917 return assign(init.begin(), init.size());
918 }
919
920 basic_string& insert(size_type pos, const basic_string& str)
921 {
922 // TODO: if (pos > str.size()) throw out_of_range.
923 return insert(pos, str.data(), str.size());
924 }
925
926 basic_string& insert(size_type pos1, const basic_string& str,
927 size_type pos2, size_type n = npos)
928 {
929 // TODO: if (pos1 > size() or pos2 > str.size()) throw
930 // out_of_range.
931 auto len = min(n, str.size() - pos2);
932
933 return insert(pos1, str.data() + pos2, len);
934 }
935
936 basic_string& insert(size_type pos, const value_type* str, size_type n)
937 {
938 // TODO: throw out_of_range if pos > size()
939 // TODO: throw length_error if size() + n > max_size()
940 ensure_free_space_(n);
941
942 copy_backward_(begin() + pos, end(), end() + n);
943 copy_(str, str + n, begin() + pos);
944 size_ += n;
945
946 ensure_null_terminator_();
947 return *this;
948 }
949
950 basic_string& insert(size_type pos, const value_type* str)
951 {
952 return insert(pos, str, traits_type::length(str));
953 }
954
955 basic_string& insert(size_type pos, size_type n, value_type c)
956 {
957 return insert(pos, basic_string(n, c));
958 }
959
960 iterator insert(const_iterator pos, value_type c)
961 {
962 auto idx = static_cast<size_type>(pos - begin());
963
964 ensure_free_space_(1);
965 copy_backward_(begin() + idx, end(), end() + 1);
966 traits_type::assign(data_[idx], c);
967
968 ++size_;
969 ensure_null_terminator_();
970
971 return begin() + idx;
972 }
973
974 iterator insert(const_iterator pos, size_type n, value_type c)
975 {
976 if (n == 0)
977 return const_cast<iterator>(pos);
978
979 auto idx = static_cast<size_type>(pos - begin());
980
981 ensure_free_space_(n);
982 copy_backward_(begin() + idx, end(), end() + n);
983
984 auto it = begin() + idx;
985 for (size_type i = 0; i < n; ++i)
986 traits_type::assign(*it++, c);
987 size_ += n;
988 ensure_null_terminator_();
989
990 return begin() + idx;
991 }
992
993 template<class InputIterator>
994 iterator insert(const_iterator pos, InputIterator first,
995 InputIterator last)
996 {
997 if (first == last)
998 return const_cast<iterator>(pos);
999
1000 auto idx = static_cast<size_type>(pos - begin());
1001 auto str = basic_string{first, last};
1002 insert(idx, str);
1003
1004 return begin() + idx;
1005 }
1006
1007 iterator insert(const_iterator pos, initializer_list<value_type> init)
1008 {
1009 return insert(pos, init.begin(), init.end());
1010 }
1011
1012 basic_string& erase(size_type pos = 0, size_type n = npos)
1013 {
1014 auto len = min(n, size_ - pos);
1015 copy_(begin() + pos + n, end(), begin() + pos);
1016 size_ -= len;
1017 ensure_null_terminator_();
1018
1019 return *this;
1020 }
1021
1022 iterator erase(const_iterator pos)
1023 {
1024 auto idx = static_cast<size_type>(pos - cbegin());
1025 erase(idx, 1);
1026
1027 return begin() + idx;
1028 }
1029
1030 iterator erase(const_iterator first, const_iterator last)
1031 {
1032 auto idx = static_cast<size_type>(first - cbegin());
1033 auto count = static_cast<size_type>(last - first);
1034 erase(idx, count);
1035
1036 return begin() + idx;
1037 }
1038
1039 void pop_back()
1040 {
1041 --size_;
1042 ensure_null_terminator_();
1043 }
1044
1045 basic_string& replace(size_type pos, size_type n, const basic_string& str)
1046 {
1047 // TODO: throw out_of_range if pos > size()
1048 return replace(pos, n, str.data(), str.size());
1049 }
1050
1051 basic_string& replace(size_type pos1, size_type n1, const basic_string& str,
1052 size_type pos2, size_type n2 = npos)
1053 {
1054 // TODO: throw out_of_range if pos1 > size() or pos2 > str.size()
1055 auto len = min(n2, str.size() - pos2);
1056 return replace(pos1, n1, str.data() + pos2, len);
1057 }
1058
1059 basic_string& replace(size_type pos, size_type n1, const value_type* str,
1060 size_type n2)
1061 {
1062 // TODO: throw out_of_range if pos > size()
1063 // TODO: if size() - len > max_size() - n2 throw length_error
1064 auto len = min(n1, size_ - pos);
1065
1066 basic_string tmp{};
1067 tmp.resize_without_copy_(size_ - len + n2);
1068
1069 // Prefix.
1070 copy_(begin(), begin() + pos, tmp.begin());
1071
1072 // Substitution.
1073 traits_type::copy(tmp.begin() + pos, str, n2);
1074
1075 // Suffix.
1076 copy_(begin() + pos + len, end(), tmp.begin() + pos + n2);
1077
1078 tmp.size_ = size_ - len + n2;
1079 swap(tmp);
1080 return *this;
1081 }
1082
1083 basic_string& replace(size_type pos, size_type n, const value_type* str)
1084 {
1085 return replace(pos, n, str, traits_type::length(str));
1086 }
1087
1088 basic_string& replace(size_type pos, size_type n1, size_type n2,
1089 value_type c)
1090 {
1091 return replace(pos, n1, basic_string(n2, c));
1092 }
1093
1094 basic_string& replace(const_iterator i1, const_iterator i2,
1095 const basic_string& str)
1096 {
1097 return replace(i1 - begin(), i2 - i1, str);
1098 }
1099
1100 basic_string& replace(const_iterator i1, const_iterator i2,
1101 const value_type* str, size_type n)
1102 {
1103 return replace(i1 - begin(), i2 - i1, str, n);
1104 }
1105
1106 basic_string& replace(const_iterator i1, const_iterator i2,
1107 const value_type* str)
1108 {
1109 return replace(i1 - begin(), i2 - i1, str, traits_type::length(str));
1110 }
1111
1112 basic_string& replace(const_iterator i1, const_iterator i2,
1113 size_type n, value_type c)
1114 {
1115 return replace(i1 - begin(), i2 - i1, basic_string(n, c));
1116 }
1117
1118 template<class InputIterator>
1119 basic_string& replace(const_iterator i1, const_iterator i2,
1120 InputIterator j1, InputIterator j2)
1121 {
1122 return replace(i1 - begin(), i2 - i1, basic_string(j1, j2));
1123 }
1124
1125 basic_string& replace(const_iterator i1, const_iterator i2,
1126 initializer_list<value_type> init)
1127 {
1128 return replace(i1 - begin(), i2 - i1, init.begin(), init.size());
1129 }
1130
1131 size_type copy(value_type* str, size_type n, size_type pos = 0) const
1132 {
1133 auto len = min(n , size_ - pos);
1134 for (size_type i = 0; i < len; ++i)
1135 traits_type::assign(str[i], data_[pos + i]);
1136
1137 return len;
1138 }
1139
1140 void swap(basic_string& other)
1141 noexcept(allocator_traits<allocator_type>::propagate_on_container_swap::value ||
1142 allocator_traits<allocator_type>::is_always_equal::value)
1143 {
1144 std::swap(data_, other.data_);
1145 std::swap(size_, other.size_);
1146 std::swap(capacity_, other.capacity_);
1147 }
1148
1149 /**
1150 * 21.4.7, string operations:
1151 */
1152
1153 const value_type* c_str() const noexcept
1154 {
1155 return data_;
1156 }
1157
1158 const value_type* data() const noexcept
1159 {
1160 return data_;
1161 }
1162
1163 allocator_type get_allocator() const noexcept
1164 {
1165 return allocator_type{allocator_};
1166 }
1167
1168 /**
1169 * Note: The following find functions have 4 versions each:
1170 * (1) takes basic_string
1171 * (2) takes c string and length
1172 * (3) takes c string
1173 * (4) takes value_type
1174 * According to the C++14 standard, only (1) is marked as
1175 * noexcept and the other three return the first one with
1176 * a newly allocated strings (and thus cannot be noexcept).
1177 * However, allocating a new string results in memory
1178 * allocation and copying of the source and thus we have
1179 * decided to follow C++17 signatures of these functions
1180 * (i.e. all of them being marked as noexcept) and use
1181 * (2) for the actual implementation (and avoiding any
1182 * allocations or copying in the process and also providing
1183 * stronger guarantees to the user).
1184 */
1185
1186 size_type find(const basic_string& str, size_type pos = 0) const noexcept
1187 {
1188 return find(str.c_str(), pos, str.size());
1189 }
1190
1191 size_type find(const value_type* str, size_type pos, size_type len) const noexcept
1192 {
1193 if (empty() || len == 0 || len + pos > size())
1194 return npos;
1195
1196 size_type idx{pos};
1197
1198 while (idx + len < size_)
1199 {
1200 if (substr_starts_at_(idx, str, len))
1201 return idx;
1202 ++idx;
1203 }
1204
1205 return npos;
1206 }
1207
1208 size_type find(const value_type* str, size_type pos = 0) const noexcept
1209 {
1210 return find(str, pos, traits_type::length(str));
1211 }
1212
1213 size_type find(value_type c, size_type pos = 0) const noexcept
1214 {
1215 if (empty())
1216 return npos;
1217
1218 for (size_type i = pos; i < size_; ++i)
1219 {
1220 if (traits_type::eq(c, data_[i]))
1221 return i;
1222 }
1223
1224 return npos;
1225 }
1226
1227 size_type rfind(const basic_string& str, size_type pos = npos) const noexcept
1228 {
1229 return rfind(str.c_str(), pos, str.size());
1230 }
1231
1232 size_type rfind(const value_type* str, size_type pos, size_type len) const noexcept
1233 {
1234 if (empty() || len == 0 || len + pos > size())
1235 return npos;
1236
1237 size_type idx{min(pos, size_ - 1) + 1};
1238
1239 while (idx > 0)
1240 {
1241 if (substr_starts_at_(idx - 1, str, len))
1242 return idx - 1;
1243 --idx;
1244 }
1245
1246 return npos;
1247 }
1248
1249 size_type rfind(const value_type* str, size_type pos = npos) const noexcept
1250 {
1251 return rfind(str, pos, traits_type::length(str));
1252 }
1253
1254 size_type rfind(value_type c, size_type pos = npos) const noexcept
1255 {
1256 if (empty())
1257 return npos;
1258
1259 for (size_type i = min(pos + 1, size_ - 1) + 1; i > 0; --i)
1260 {
1261 if (traits_type::eq(c, data_[i - 1]))
1262 return i - 1;
1263 }
1264
1265 return npos;
1266 }
1267
1268 size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept
1269 {
1270 return find_first_of(str.c_str(), pos, str.size());
1271 }
1272
1273 size_type find_first_of(const value_type* str, size_type pos, size_type len) const noexcept
1274 {
1275 if (empty() || len == 0 || pos >= size())
1276 return npos;
1277
1278 size_type idx{pos};
1279
1280 while (idx < size_)
1281 {
1282 if (is_any_of_(idx, str, len))
1283 return idx;
1284 ++idx;
1285 }
1286
1287 return npos;
1288 }
1289
1290 size_type find_first_of(const value_type* str, size_type pos = 0) const noexcept
1291 {
1292 return find_first_of(str, pos, traits_type::length(str));
1293 }
1294
1295 size_type find_first_of(value_type c, size_type pos = 0) const noexcept
1296 {
1297 return find(c, pos);
1298 }
1299
1300 size_type find_last_of(const basic_string& str, size_type pos = npos) const noexcept
1301 {
1302 return find_last_of(str.c_str(), pos, str.size());
1303 }
1304
1305 size_type find_last_of(const value_type* str, size_type pos, size_type len) const noexcept
1306 {
1307 if (empty() || len == 0)
1308 return npos;
1309
1310 for (size_type i = min(pos, size_ - 1) + 1; i > 0; --i)
1311 {
1312 if (is_any_of_(i - 1, str, len))
1313 return i - 1;
1314 }
1315
1316 return npos;
1317 }
1318
1319 size_type find_last_of(const value_type* str, size_type pos = npos) const noexcept
1320 {
1321 return find_last_of(str, pos, traits_type::length(str));
1322 }
1323
1324 size_type find_last_of(value_type c, size_type pos = npos) const noexcept
1325 {
1326 return rfind(c, pos);
1327 }
1328
1329 size_type find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept
1330 {
1331 return find_first_not_of(str.c_str(), pos, str.size());
1332 }
1333
1334 size_type find_first_not_of(const value_type* str, size_type pos, size_type len) const noexcept
1335 {
1336 if (empty() || pos >= size())
1337 return npos;
1338
1339 size_type idx{pos};
1340
1341 while (idx < size_)
1342 {
1343 if (!is_any_of_(idx, str, len))
1344 return idx;
1345 ++idx;
1346 }
1347
1348 return npos;
1349 }
1350
1351 size_type find_first_not_of(const value_type* str, size_type pos = 0) const noexcept
1352 {
1353 return find_first_not_of(str, pos, traits_type::length(str));
1354 }
1355
1356 size_type find_first_not_of(value_type c, size_type pos = 0) const noexcept
1357 {
1358 if (empty())
1359 return npos;
1360
1361 for (size_type i = pos; i < size_; ++i)
1362 {
1363 if (!traits_type::eq(c, data_[i]))
1364 return i;
1365 }
1366
1367 return npos;
1368 }
1369
1370 size_type find_last_not_of(const basic_string& str, size_type pos = npos) const noexcept
1371 {
1372 return find_last_not_of(str.c_str(), pos, str.size());
1373 }
1374
1375 size_type find_last_not_of(const value_type* str, size_type pos, size_type len) const noexcept
1376 {
1377 if (empty())
1378 return npos;
1379
1380 for (size_type i = min(pos, size_ - 1) + 1; i > 0; --i)
1381 {
1382 if (!is_any_of_(i - 1, str, len))
1383 return i - 1;
1384 }
1385
1386 return npos;
1387 }
1388
1389 size_type find_last_not_of(const value_type* str, size_type pos = npos) const noexcept
1390 {
1391 return find_last_not_of(str, pos, traits_type::length(str));
1392 }
1393
1394 size_type find_last_not_of(value_type c, size_type pos = npos) const noexcept
1395 {
1396 if (empty())
1397 return npos;
1398
1399 pos = min(pos, size_ - 1);
1400
1401 for (size_type i = min(pos, size_ - 1) + 1; i > 1; --i)
1402 {
1403 if (!traits_type::eq(c, data_[i - 1]))
1404 return i - 1;
1405 }
1406
1407 return npos;
1408 }
1409
1410 basic_string substr(size_type pos = 0, size_type n = npos) const
1411 {
1412 // TODO: throw out_of_range if pos > size().
1413 auto len = min(n, size_ - pos);
1414 return basic_string{data() + pos, len};
1415 }
1416
1417 int compare(const basic_string& other) const noexcept
1418 {
1419 auto len = min(size(), other.size());
1420 auto comp = traits_type::compare(data_, other.data(), len);
1421
1422 if (comp != 0)
1423 return comp;
1424 else if (size() == other.size())
1425 return 0;
1426 else if (size() > other.size())
1427 return 1;
1428 else
1429 return -1;
1430 }
1431
1432 int compare(size_type pos, size_type n, const basic_string& other) const
1433 {
1434 return basic_string{*this, pos, n}.compare(other);
1435 }
1436
1437 int compare(size_type pos1, size_type n1, const basic_string& other,
1438 size_type pos2, size_type n2 = npos) const
1439 {
1440 return basic_string{*this, pos1, n1}.compare(basic_string{other, pos2, n2});
1441 }
1442
1443 int compare(const value_type* other) const
1444 {
1445 return compare(basic_string(other));
1446 }
1447
1448 int compare(size_type pos, size_type n, const value_type* other) const
1449 {
1450 return basic_string{*this, pos, n}.compare(basic_string{other});
1451 }
1452
1453 int compare(size_type pos, size_type n1,
1454 const value_type* other, size_type n2) const
1455 {
1456 return basic_string{*this, pos, n1}.compare(basic_string{other, n2});
1457 }
1458
1459 private:
1460 value_type* data_;
1461 size_type size_;
1462 size_type capacity_;
1463 allocator_type allocator_;
1464
1465 /**
1466 * Arbitrary value, standard just requires
1467 * data() to have some capacity.
1468 * (Well, we could've done data_ = &data_ and
1469 * set capacity to 0, but that would be too cryptic.)
1470 */
1471 static constexpr size_type default_capacity_{4};
1472
1473 void init_(const value_type* str, size_type size)
1474 {
1475 if (data_)
1476 allocator_.deallocate(data_, capacity_);
1477
1478 size_ = size;
1479 capacity_ = size;
1480
1481 data_ = allocator_.allocate(capacity_);
1482 traits_type::copy(data_, str, size);
1483 ensure_null_terminator_();
1484 }
1485
1486 size_type next_capacity_(size_type hint = 0) const noexcept
1487 {
1488 if (hint != 0)
1489 return max(capacity_ * 2, hint);
1490 else
1491 return max(capacity_ * 2, 2ul);
1492 }
1493
1494 void ensure_free_space_(size_type n)
1495 {
1496 /**
1497 * Note: We cannot use reserve like we
1498 * did in vector, because in string
1499 * reserve can cause shrinking.
1500 */
1501 if (size_ + 1 + n > capacity_)
1502 resize_with_copy_(size_, max(size_ + 1 + n, next_capacity_()));
1503 }
1504
1505 void resize_without_copy_(size_type capacity)
1506 {
1507 if (data_)
1508 allocator_.deallocate(data_, capacity_);
1509
1510 data_ = allocator_.allocate(capacity);
1511 size_ = 0;
1512 capacity_ = capacity;
1513 ensure_null_terminator_();
1514 }
1515
1516 void resize_with_copy_(size_type size, size_type capacity)
1517 {
1518 if(capacity_ == 0 || capacity_ < capacity)
1519 {
1520 auto new_data = allocator_.allocate(capacity);
1521
1522 auto to_copy = min(size, size_);
1523 traits_type::move(new_data, data_, to_copy);
1524
1525 std::swap(data_, new_data);
1526
1527 allocator_.deallocate(new_data, capacity_);
1528 }
1529
1530 capacity_ = capacity;
1531 size_ = size;
1532 ensure_null_terminator_();
1533 }
1534
1535 template<class Iterator1, class Iterator2>
1536 Iterator2 copy_(Iterator1 first, Iterator1 last,
1537 Iterator2 result)
1538 {
1539 while (first != last)
1540 traits_type::assign(*result++, *first++);
1541
1542 return result;
1543 }
1544
1545 template<class Iterator1, class Iterator2>
1546 Iterator2 copy_backward_(Iterator1 first, Iterator1 last,
1547 Iterator2 result)
1548 {
1549 while (last != first)
1550 traits_type::assign(*--result, *--last);
1551
1552 return result;
1553 }
1554
1555 void ensure_null_terminator_()
1556 {
1557 value_type c{};
1558 traits_type::assign(data_[size_], c);
1559 }
1560
1561 bool is_any_of_(size_type idx, const value_type* str, size_type len) const
1562 {
1563 for (size_type i = 0; i < len; ++i)
1564 {
1565 if (traits_type::eq(data_[idx], str[i]))
1566 return true;
1567 }
1568
1569 return false;
1570 }
1571
1572 bool substr_starts_at_(size_type idx, const value_type* str, size_type len) const
1573 {
1574 size_type i{};
1575 for (i = 0; i < len; ++i)
1576 {
1577 if (!traits_type::eq(data_[idx + i], str[i]))
1578 break;
1579 }
1580
1581 return i == len;
1582 }
1583 };
1584
1585 using string = basic_string<char>;
1586 using u16string = basic_string<char16_t>;
1587 using u32string = basic_string<char32_t>;
1588 using wstring = basic_string<wchar_t>;
1589
1590 /**
1591 * 21.4.8, basic_string non-member functions:
1592 */
1593
1594 /**
1595 * 21.4.8.1, operator+:
1596 */
1597
1598 template<class Char, class Traits, class Allocator>
1599 basic_string<Char, Traits, Allocator>
1600 operator+(const basic_string<Char, Traits, Allocator>& lhs,
1601 const basic_string<Char, Traits, Allocator>& rhs)
1602 {
1603 return basic_string<Char, Traits, Allocator>{lhs}.append(rhs);
1604 }
1605
1606 template<class Char, class Traits, class Allocator>
1607 basic_string<Char, Traits, Allocator>
1608 operator+(basic_string<Char, Traits, Allocator>&& lhs,
1609 const basic_string<Char, Traits, Allocator>& rhs)
1610 {
1611 return move(lhs.append(rhs));
1612 }
1613
1614 template<class Char, class Traits, class Allocator>
1615 basic_string<Char, Traits, Allocator>
1616 operator+(const basic_string<Char, Traits, Allocator>& lhs,
1617 basic_string<Char, Traits, Allocator>&& rhs)
1618 {
1619 return move(rhs.insert(0, lhs));
1620 }
1621
1622 template<class Char, class Traits, class Allocator>
1623 basic_string<Char, Traits, Allocator>
1624 operator+(basic_string<Char, Traits, Allocator>&& lhs,
1625 basic_string<Char, Traits, Allocator>&& rhs)
1626 {
1627 return move(lhs.append(rhs));
1628 }
1629
1630 template<class Char, class Traits, class Allocator>
1631 basic_string<Char, Traits, Allocator>
1632 operator+(const Char* lhs,
1633 const basic_string<Char, Traits, Allocator>& rhs)
1634 {
1635 return basic_string<Char, Traits, Allocator>{lhs} + rhs;
1636 }
1637
1638 template<class Char, class Traits, class Allocator>
1639 basic_string<Char, Traits, Allocator>
1640 operator+(const Char* lhs,
1641 basic_string<Char, Traits, Allocator>&& rhs)
1642 {
1643 return move(rhs.insert(0, lhs));
1644 }
1645
1646 template<class Char, class Traits, class Allocator>
1647 basic_string<Char, Traits, Allocator>
1648 operator+(Char lhs,
1649 const basic_string<Char, Traits, Allocator>& rhs)
1650 {
1651 return basic_string<Char, Traits, Allocator>{1, lhs}.append(rhs);
1652 }
1653
1654 template<class Char, class Traits, class Allocator>
1655 basic_string<Char, Traits, Allocator>
1656 operator+(Char lhs,
1657 basic_string<Char, Traits, Allocator>&& rhs)
1658 {
1659 return move(rhs.insert(0, 1, lhs));
1660 }
1661
1662 template<class Char, class Traits, class Allocator>
1663 basic_string<Char, Traits, Allocator>
1664 operator+(const basic_string<Char, Traits, Allocator>& lhs,
1665 const Char* rhs)
1666 {
1667 return lhs + basic_string<Char, Traits, Allocator>{rhs};
1668 }
1669
1670 template<class Char, class Traits, class Allocator>
1671 basic_string<Char, Traits, Allocator>
1672 operator+(basic_string<Char, Traits, Allocator>&& lhs,
1673 const Char* rhs)
1674 {
1675 return move(lhs.append(rhs));
1676 }
1677
1678 template<class Char, class Traits, class Allocator>
1679 basic_string<Char, Traits, Allocator>
1680 operator+(const basic_string<Char, Traits, Allocator>& lhs,
1681 Char rhs)
1682 {
1683 return lhs + basic_string<Char, Traits, Allocator>{1, rhs};
1684 }
1685
1686 template<class Char, class Traits, class Allocator>
1687 basic_string<Char, Traits, Allocator>
1688 operator+(basic_string<Char, Traits, Allocator>&& lhs,
1689 Char rhs)
1690 {
1691 return move(lhs.append(1, rhs));
1692 }
1693
1694 /**
1695 * 21.4.8.2, operator==:
1696 */
1697
1698 template<class Char, class Traits, class Allocator>
1699 bool operator==(const basic_string<Char, Traits, Allocator>& lhs,
1700 const basic_string<Char, Traits, Allocator>& rhs) noexcept
1701 {
1702 return lhs.compare(rhs) == 0;
1703 }
1704
1705 template<class Char, class Traits, class Allocator>
1706 bool operator==(const Char* lhs,
1707 const basic_string<Char, Traits, Allocator>& rhs)
1708 {
1709 return rhs == lhs;
1710 }
1711
1712 template<class Char, class Traits, class Allocator>
1713 bool operator==(const basic_string<Char, Traits, Allocator>& lhs,
1714 const Char* rhs)
1715 {
1716 return lhs.compare(rhs) == 0;
1717 }
1718
1719 /**
1720 * 21.4.8.3, operator!=:
1721 */
1722
1723 template<class Char, class Traits, class Allocator>
1724 bool 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 bool operator!=(const Char* lhs,
1732 const basic_string<Char, Traits, Allocator>& rhs)
1733 {
1734 return rhs != lhs;
1735 }
1736
1737 template<class Char, class Traits, class Allocator>
1738 bool operator!=(const basic_string<Char, Traits, Allocator>& lhs,
1739 const Char* rhs)
1740 {
1741 return lhs.compare(rhs) != 0;
1742 }
1743
1744 /**
1745 * 21.4.8.4, operator<:
1746 */
1747
1748 template<class Char, class Traits, class Allocator>
1749 bool operator<(const basic_string<Char, Traits, Allocator>& lhs,
1750 const basic_string<Char, Traits, Allocator>& rhs) noexcept
1751 {
1752 return lhs.compare(rhs) < 0;
1753 }
1754
1755 template<class Char, class Traits, class Allocator>
1756 bool operator<(const Char* lhs,
1757 const basic_string<Char, Traits, Allocator>& rhs)
1758 {
1759 return rhs.compare(lhs) > 0;
1760 }
1761
1762 template<class Char, class Traits, class Allocator>
1763 bool operator<(const basic_string<Char, Traits, Allocator>& lhs,
1764 const Char* rhs)
1765 {
1766 return lhs.compare(rhs) < 0;
1767 }
1768
1769 /**
1770 * 21.4.8.5, operator>:
1771 */
1772
1773 template<class Char, class Traits, class Allocator>
1774 bool operator>(const basic_string<Char, Traits, Allocator>& lhs,
1775 const basic_string<Char, Traits, Allocator>& rhs) noexcept
1776 {
1777 return lhs.compare(rhs) > 0;
1778 }
1779
1780 template<class Char, class Traits, class Allocator>
1781 bool operator>(const Char* lhs,
1782 const basic_string<Char, Traits, Allocator>& rhs)
1783 {
1784 return rhs.compare(lhs) < 0;
1785 }
1786
1787 template<class Char, class Traits, class Allocator>
1788 bool operator>(const basic_string<Char, Traits, Allocator>& lhs,
1789 const Char* rhs)
1790 {
1791 return lhs.compare(rhs) > 0;
1792 }
1793
1794 /**
1795 * 21.4.8.6, operator<=:
1796 */
1797
1798 template<class Char, class Traits, class Allocator>
1799 bool operator<=(const basic_string<Char, Traits, Allocator>& lhs,
1800 const basic_string<Char, Traits, Allocator>& rhs) noexcept
1801 {
1802 return lhs.compare(rhs) <= 0;
1803 }
1804
1805 template<class Char, class Traits, class Allocator>
1806 bool operator<=(const Char* lhs,
1807 const basic_string<Char, Traits, Allocator>& rhs)
1808 {
1809 return rhs.compare(lhs) >= 0;
1810 }
1811
1812 template<class Char, class Traits, class Allocator>
1813 bool operator<=(const basic_string<Char, Traits, Allocator>& lhs,
1814 const Char* rhs)
1815 {
1816 return lhs.compare(rhs) <= 0;
1817 }
1818
1819 /**
1820 * 21.4.8.7, operator>=:
1821 */
1822
1823 template<class Char, class Traits, class Allocator>
1824 bool operator>=(const basic_string<Char, Traits, Allocator>& lhs,
1825 const basic_string<Char, Traits, Allocator>& rhs) noexcept
1826 {
1827 return lhs.compare(rhs) >= 0;
1828 }
1829
1830 template<class Char, class Traits, class Allocator>
1831 bool operator>=(const Char* lhs,
1832 const basic_string<Char, Traits, Allocator>& rhs)
1833 {
1834 return rhs.compare(lhs) <= 0;
1835 }
1836
1837 template<class Char, class Traits, class Allocator>
1838 bool operator>=(const basic_string<Char, Traits, Allocator>& lhs,
1839 const Char* rhs)
1840 {
1841 return lhs.compare(rhs) >= 0;
1842 }
1843
1844 /**
1845 * 21.4.8.8, swap:
1846 */
1847
1848 template<class Char, class Traits, class Allocator>
1849 void swap(basic_string<Char, Traits, Allocator>& lhs,
1850 basic_string<Char, Traits, Allocator>& rhs)
1851 noexcept(noexcept(lhs.swap(rhs)))
1852 {
1853 lhs.swap(rhs);
1854 }
1855
1856 /**
1857 * 21.4.8.9, inserters and extractors:
1858 */
1859
1860 // TODO: implement
1861
1862 /**
1863 * 21.5, numeric conversions:
1864 */
1865
1866 int stoi(const string& str, size_t* idx = nullptr, int base = 10);
1867 long stol(const string& str, size_t* idx = nullptr, int base = 10);
1868 unsigned long stoul(const string& str, size_t* idx = nullptr, int base = 10);
1869 long long stoll(const string& str, size_t* idx = nullptr, int base = 10);
1870 unsigned long long stoull(const string& str, size_t* idx = nullptr, int base = 10);
1871
1872 float stof(const string& str, size_t* idx = nullptr);
1873 double stod(const string& str, size_t* idx = nullptr);
1874 long double stold(const string& str, size_t* idx = nullptr);
1875
1876 string to_string(int val);
1877 string to_string(unsigned val);
1878 string to_string(long val);
1879 string to_string(unsigned long val);
1880 string to_string(long long val);
1881 string to_string(unsigned long long val);
1882 string to_string(float val);
1883 string to_string(double val);
1884 string to_string(long double val);
1885
1886 int stoi(const wstring& str, size_t* idx = nullptr, int base = 10);
1887 long stol(const wstring& str, size_t* idx = nullptr, int base = 10);
1888 unsigned long stoul(const wstring& str, size_t* idx = nullptr, int base = 10);
1889 long long stoll(const wstring& str, size_t* idx = nullptr, int base = 10);
1890 unsigned long long stoull(const wstring& str, size_t* idx = nullptr, int base = 10);
1891
1892 float stof(const wstring& str, size_t* idx = nullptr);
1893 double stod(const wstring& str, size_t* idx = nullptr);
1894 long double stold(const wstring& str, size_t* idx = nullptr);
1895
1896 wstring to_wstring(int val);
1897 wstring to_wstring(unsigned val);
1898 wstring to_wstring(long val);
1899 wstring to_wstring(unsigned long val);
1900 wstring to_wstring(long long val);
1901 wstring to_wstring(unsigned long long val);
1902 wstring to_wstring(float val);
1903 wstring to_wstring(double val);
1904 wstring to_wstring(long double val);
1905
1906 /**
1907 * 21.6, hash support:
1908 */
1909
1910 // TODO: implement
1911
1912 /**
1913 * 21.7, suffix for basic_string literals:
1914 */
1915
1916 /**
1917 * Note: According to the standard, literal suffixes that do not
1918 * start with an underscore are reserved for future standardization,
1919 * but since we are implementing the standard, we're going to ignore it.
1920 * This should work (according to their documentation) work for clang,
1921 * but that should be tested.
1922 */
1923#pragma GCC diagnostic push
1924#pragma GCC diagnostic ignored "-Wliteral-suffix"
1925 string operator "" s(const char* str, size_t len);
1926 u16string operator "" s(const char16_t* str, size_t len);
1927 u32string operator "" s(const char32_t* str, size_t len);
1928
1929 /* Problem: wchar_t == int in HelenOS, but standard forbids it.
1930 wstring operator "" s(const wchar_t* str, size_t len);
1931 */
1932#pragma GCC diagnostic pop
1933}
1934
1935#endif
Note: See TracBrowser for help on using the repository browser.