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

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

cpp: added basic_stringbuf as friend

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