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

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

cpp: fixed issues created by the addition of abi/_bits, changes to the build system and added <cwchar> that was made possible by the addition of <wchar.h> to libc

  • 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 allocator_traits<allocator_type>::max_size(allocator_);
682 }
683
684 void resize(size_type new_size, value_type c)
685 {
686 // TODO: if new_size > max_size() throw length_error.
687 if (new_size > size_)
688 {
689 ensure_free_space_(new_size - size_ + 1);
690 for (size_type i = size_; i < new_size; ++i)
691 traits_type::assign(data_[i], i);
692 }
693
694 size_ = new_size;
695 ensure_null_terminator_();
696 }
697
698 void resize(size_type new_size)
699 {
700 resize(new_size, value_type{});
701 }
702
703 size_type capacity() const noexcept
704 {
705 return capacity_;
706 }
707
708 void reserve(size_type new_capacity = 0)
709 {
710 // TODO: if new_capacity > max_size() throw
711 // length_error (this function shall have no
712 // effect in such case)
713 if (new_capacity > capacity_)
714 resize_with_copy_(size_, new_capacity);
715 else if (new_capacity < capacity)
716 shrink_to_fit(); // Non-binding request, but why not.
717 }
718
719 void shrink_to_fit()
720 {
721 if (size_ != capacity_)
722 resize_with_copy_(size_);
723 }
724
725 void clear() noexcept
726 {
727 size_ = 0;
728 }
729
730 bool empty() const noexcept
731 {
732 return size_ == 0;
733 }
734
735 /**
736 * 21.4.5, element access:
737 */
738
739 const_reference operator[](size_type idx) const
740 {
741 return data_[idx];
742 }
743
744 reference operator[](size_type idx)
745 {
746 return data_[idx];
747 }
748
749 const_reference at(size_type idx) const
750 {
751 // TODO: bounds checking
752 return data_[idx];
753 }
754
755 reference at(size_type idx)
756 {
757 // TODO: bounds checking
758 return data_[idx];
759 }
760
761 const_reference front() const
762 {
763 return at(0);
764 }
765
766 reference front()
767 {
768 return at(0);
769 }
770
771 const_reference back() const
772 {
773 return at(size_ - 1);
774 }
775
776 reference back()
777 {
778 return at(size_ - 1);
779 }
780
781 /**
782 * 21.4.6, modifiers:
783 */
784
785 basic_string& operator+=(const basic_string& str)
786 {
787 return append(str);
788 }
789
790 basic_string& operator+=(const value_type* str)
791 {
792 return append(str);
793 }
794
795 basic_string& operator+=(value_type c)
796 {
797 push_back(c);
798 return *this;
799 }
800
801 basic_string& operator+=(initializer_list<value_type> init)
802 {
803 return append(init.begin(), init.size());
804 }
805
806 basic_string& append(const basic_string& str)
807 {
808 return append(str.data(), str.size());
809 }
810
811 basic_string& append(const basic_string& str, size_type pos,
812 size_type n = npos)
813 {
814 if (pos < str.size())
815 {
816 auto len = min(n, str.size() - pos);
817
818 return append(str.data() + pos, len);
819 }
820 // TODO: Else throw out_of_range.
821 }
822
823 basic_string& append(const value_type* str, size_type n)
824 {
825 // TODO: if (size_ + n > max_size()) throw length_error
826 ensure_free_space_(n);
827 traits_type::copy(data_ + size(), str, n);
828 size_ += n;
829 ensure_null_terminator_();
830
831 return *this;
832 }
833
834 basic_string& append(const value_type* str)
835 {
836 return append(str, traits_type::length(str));
837 }
838
839 basic_string& append(size_type n, value_type c)
840 {
841 return append(basic_string(n, c));
842 }
843
844 template<class InputIterator>
845 basic_string& append(InputIterator first, InputIterator last)
846 {
847 return append(basic_string(first, last));
848 }
849
850 basic_string& append(initializer_list<value_type> init)
851 {
852 return append(init.begin(), init.size());
853 }
854
855 void push_back(value_type c)
856 {
857 ensure_free_space_(1);
858 traits_type::assign(data_[size_++], c);
859 ensure_null_terminator_();
860 }
861
862 basic_string& assign(const basic_string& str)
863 {
864 return assign(str, 0, npos);
865 }
866
867 basic_string& assign(basic_string&& str)
868 {
869 swap(str);
870
871 return *this;
872 }
873
874 basic_string& assign(const basic_string& str, size_type pos,
875 size_type n = npos)
876 {
877 if (pos < str.size())
878 {
879 auto len = min(n, str.size() - pos);
880 ensure_free_space_(len);
881
882 return assign(str.data() + pos, len);
883 }
884 // TODO: Else throw out_of_range.
885
886 return *this;
887 }
888
889 basic_string& assign(const value_type* str, size_type n)
890 {
891 // TODO: if (n > max_size()) throw length_error.
892 resize_without_copy_(n);
893 traits_type::copy(begin(), str, n);
894 size_ = n;
895 ensure_null_terminator_();
896
897 return *this;
898 }
899
900 basic_string& assign(const value_type* str)
901 {
902 return assign(str, traits_type::length(str));
903 }
904
905 basic_string& assign(size_type n, value_type c)
906 {
907 return assign(basic_string(n, c));
908 }
909
910 template<class InputIterator>
911 basic_string& assign(InputIterator first, InputIterator last)
912 {
913 return assign(basic_string(first, last));
914 }
915
916 basic_string& assign(initializer_list<value_type> init)
917 {
918 return assign(init.begin(), init.size());
919 }
920
921 basic_string& insert(size_type pos, const basic_string& str)
922 {
923 // TODO: if (pos > str.size()) throw out_of_range.
924 return insert(pos, str.data(), str.size());
925 }
926
927 basic_string& insert(size_type pos1, const basic_string& str,
928 size_type pos2, size_type n = npos)
929 {
930 // TODO: if (pos1 > size() or pos2 > str.size()) throw
931 // out_of_range.
932 auto len = min(n, str.size() - pos2);
933
934 return insert(pos1, str.data() + pos2, len);
935 }
936
937 basic_string& insert(size_type pos, const value_type* str, size_type n)
938 {
939 // TODO: throw out_of_range if pos > size()
940 // TODO: throw length_error if size() + n > max_size()
941 ensure_free_space_(n);
942
943 copy_backward_(begin() + pos, end(), end() + n);
944 copy_(str, str + n, begin() + pos);
945 size_ += n;
946
947 ensure_null_terminator_();
948 return *this;
949 }
950
951 basic_string& insert(size_type pos, const value_type* str)
952 {
953 return insert(pos, str, traits_type::length(str));
954 }
955
956 basic_string& insert(size_type pos, size_type n, value_type c)
957 {
958 return insert(pos, basic_string(n, c));
959 }
960
961 iterator insert(const_iterator pos, value_type c)
962 {
963 auto idx = static_cast<size_type>(pos - begin());
964
965 ensure_free_space_(1);
966 copy_backward_(begin() + idx, end(), end() + 1);
967 traits_type::assign(data_[idx], c);
968
969 ++size_;
970 ensure_null_terminator_();
971
972 return begin() + idx;
973 }
974
975 iterator insert(const_iterator pos, size_type n, value_type c)
976 {
977 if (n == 0)
978 return const_cast<iterator>(pos);
979
980 auto idx = static_cast<size_type>(pos - begin());
981
982 ensure_free_space_(n);
983 copy_backward_(begin() + idx, end(), end() + n);
984
985 auto it = begin() + idx;
986 for (size_type i = 0; i < n; ++i)
987 traits_type::assign(*it++, c);
988 size_ += n;
989 ensure_null_terminator_();
990
991 return begin() + idx;
992 }
993
994 template<class InputIterator>
995 iterator insert(const_iterator pos, InputIterator first,
996 InputIterator last)
997 {
998 if (first == last)
999 return const_cast<iterator>(pos);
1000
1001 auto idx = static_cast<size_type>(pos - begin());
1002 auto str = basic_string{first, last};
1003 insert(idx, str);
1004
1005 return begin() + idx;
1006 }
1007
1008 iterator insert(const_iterator pos, initializer_list<value_type> init)
1009 {
1010 return insert(pos, init.begin(), init.end());
1011 }
1012
1013 basic_string& erase(size_type pos = 0, size_type n = npos)
1014 {
1015 auto len = min(n, size_ - pos);
1016 copy_(begin() + pos + n, end(), begin() + pos);
1017 size_ -= len;
1018 ensure_null_terminator_();
1019
1020 return *this;
1021 }
1022
1023 iterator erase(const_iterator pos)
1024 {
1025 auto idx = static_cast<size_type>(pos - cbegin());
1026 erase(idx, 1);
1027
1028 return begin() + idx;
1029 }
1030
1031 iterator erase(const_iterator first, const_iterator last)
1032 {
1033 auto idx = static_cast<size_type>(first - cbegin());
1034 auto count = static_cast<size_type>(last - first);
1035 erase(idx, count);
1036
1037 return begin() + idx;
1038 }
1039
1040 void pop_back()
1041 {
1042 --size_;
1043 ensure_null_terminator_();
1044 }
1045
1046 basic_string& replace(size_type pos, size_type n, const basic_string& str)
1047 {
1048 // TODO: throw out_of_range if pos > size()
1049 return replace(pos, n, str.data(), str.size());
1050 }
1051
1052 basic_string& replace(size_type pos1, size_type n1, const basic_string& str,
1053 size_type pos2, size_type n2 = npos)
1054 {
1055 // TODO: throw out_of_range if pos1 > size() or pos2 > str.size()
1056 auto len = min(n2, str.size() - pos2);
1057 return replace(pos1, n1, str.data() + pos2, len);
1058 }
1059
1060 basic_string& replace(size_type pos, size_type n1, const value_type* str,
1061 size_type n2)
1062 {
1063 // TODO: throw out_of_range if pos > size()
1064 // TODO: if size() - len > max_size() - n2 throw length_error
1065 auto len = min(n1, size_ - pos);
1066
1067 basic_string tmp{};
1068 tmp.resize_without_copy_(size_ - len + n2);
1069
1070 // Prefix.
1071 copy_(begin(), begin() + pos, tmp.begin());
1072
1073 // Substitution.
1074 traits_type::copy(tmp.begin() + pos, str, n2);
1075
1076 // Suffix.
1077 copy_(begin() + pos + len, end(), tmp.begin() + pos + n2);
1078
1079 tmp.size_ = size_ - len + n2;
1080 swap(tmp);
1081 return *this;
1082 }
1083
1084 basic_string& replace(size_type pos, size_type n, const value_type* str)
1085 {
1086 return replace(pos, n, str, traits_type::length(str));
1087 }
1088
1089 basic_string& replace(size_type pos, size_type n1, size_type n2,
1090 value_type c)
1091 {
1092 return replace(pos, n1, basic_string(n2, c));
1093 }
1094
1095 basic_string& replace(const_iterator i1, const_iterator i2,
1096 const basic_string& str)
1097 {
1098 return replace(i1 - begin(), i2 - i1, str);
1099 }
1100
1101 basic_string& replace(const_iterator i1, const_iterator i2,
1102 const value_type* str, size_type n)
1103 {
1104 return replace(i1 - begin(), i2 - i1, str, n);
1105 }
1106
1107 basic_string& replace(const_iterator i1, const_iterator i2,
1108 const value_type* str)
1109 {
1110 return replace(i1 - begin(), i2 - i1, str, traits_type::length(str));
1111 }
1112
1113 basic_string& replace(const_iterator i1, const_iterator i2,
1114 size_type n, value_type c)
1115 {
1116 return replace(i1 - begin(), i2 - i1, basic_string(n, c));
1117 }
1118
1119 template<class InputIterator>
1120 basic_string& replace(const_iterator i1, const_iterator i2,
1121 InputIterator j1, InputIterator j2)
1122 {
1123 return replace(i1 - begin(), i2 - i1, basic_string(j1, j2));
1124 }
1125
1126 basic_string& replace(const_iterator i1, const_iterator i2,
1127 initializer_list<value_type> init)
1128 {
1129 return replace(i1 - begin(), i2 - i1, init.begin(), init.size());
1130 }
1131
1132 size_type copy(value_type* str, size_type n, size_type pos = 0) const
1133 {
1134 auto len = min(n , size_ - pos);
1135 for (size_type i = 0; i < len; ++i)
1136 traits_type::assign(str[i], data_[pos + i]);
1137
1138 return len;
1139 }
1140
1141 void swap(basic_string& other)
1142 noexcept(allocator_traits<allocator_type>::propagate_on_container_swap::value ||
1143 allocator_traits<allocator_type>::is_always_equal::value)
1144 {
1145 std::swap(data_, other.data_);
1146 std::swap(size_, other.size_);
1147 std::swap(capacity_, other.capacity_);
1148 }
1149
1150 /**
1151 * 21.4.7, string operations:
1152 */
1153
1154 const value_type* c_str() const noexcept
1155 {
1156 return data_;
1157 }
1158
1159 const value_type* data() const noexcept
1160 {
1161 return data_;
1162 }
1163
1164 allocator_type get_allocator() const noexcept
1165 {
1166 return allocator_type{allocator_};
1167 }
1168
1169 /**
1170 * Note: The following find functions have 4 versions each:
1171 * (1) takes basic_string
1172 * (2) takes c string and length
1173 * (3) takes c string
1174 * (4) takes value_type
1175 * According to the C++14 standard, only (1) is marked as
1176 * noexcept and the other three return the first one with
1177 * a newly allocated strings (and thus cannot be noexcept).
1178 * However, allocating a new string results in memory
1179 * allocation and copying of the source and thus we have
1180 * decided to follow C++17 signatures of these functions
1181 * (i.e. all of them being marked as noexcept) and use
1182 * (2) for the actual implementation (and avoiding any
1183 * allocations or copying in the process and also providing
1184 * stronger guarantees to the user).
1185 */
1186
1187 size_type find(const basic_string& str, size_type pos = 0) const noexcept
1188 {
1189 return find(str.c_str(), pos, str.size());
1190 }
1191
1192 size_type find(const value_type* str, size_type pos, size_type len) const noexcept
1193 {
1194 if (empty() || len == 0 || len + pos > size())
1195 return npos;
1196
1197 size_type idx{pos};
1198
1199 while (idx + len < size_)
1200 {
1201 if (substr_starts_at_(idx, str, len))
1202 return idx;
1203 ++idx;
1204 }
1205
1206 return npos;
1207 }
1208
1209 size_type find(const value_type* str, size_type pos = 0) const noexcept
1210 {
1211 return find(str, pos, traits_type::length(str));
1212 }
1213
1214 size_type find(value_type c, size_type pos = 0) const noexcept
1215 {
1216 if (empty())
1217 return npos;
1218
1219 for (size_type i = pos; i < size_; ++i)
1220 {
1221 if (traits_type::eq(c, data_[i]))
1222 return i;
1223 }
1224
1225 return npos;
1226 }
1227
1228 size_type rfind(const basic_string& str, size_type pos = npos) const noexcept
1229 {
1230 return rfind(str.c_str(), pos, str.size());
1231 }
1232
1233 size_type rfind(const value_type* str, size_type pos, size_type len) const noexcept
1234 {
1235 if (empty() || len == 0 || len + pos > size())
1236 return npos;
1237
1238 size_type idx{min(pos, size_ - 1) + 1};
1239
1240 while (idx > 0)
1241 {
1242 if (substr_starts_at_(idx - 1, str, len))
1243 return idx - 1;
1244 --idx;
1245 }
1246
1247 return npos;
1248 }
1249
1250 size_type rfind(const value_type* str, size_type pos = npos) const noexcept
1251 {
1252 return rfind(str, pos, traits_type::length(str));
1253 }
1254
1255 size_type rfind(value_type c, size_type pos = npos) const noexcept
1256 {
1257 if (empty())
1258 return npos;
1259
1260 for (size_type i = min(pos + 1, size_ - 1) + 1; i > 0; --i)
1261 {
1262 if (traits_type::eq(c, data_[i - 1]))
1263 return i - 1;
1264 }
1265
1266 return npos;
1267 }
1268
1269 size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept
1270 {
1271 return find_first_of(str.c_str(), pos, str.size());
1272 }
1273
1274 size_type find_first_of(const value_type* str, size_type pos, size_type len) const noexcept
1275 {
1276 if (empty() || len == 0 || pos >= size())
1277 return npos;
1278
1279 size_type idx{pos};
1280
1281 while (idx < size_)
1282 {
1283 if (is_any_of_(idx, str, len))
1284 return idx;
1285 ++idx;
1286 }
1287
1288 return npos;
1289 }
1290
1291 size_type find_first_of(const value_type* str, size_type pos = 0) const noexcept
1292 {
1293 return find_first_of(str, pos, traits_type::length(str));
1294 }
1295
1296 size_type find_first_of(value_type c, size_type pos = 0) const noexcept
1297 {
1298 return find(c, pos);
1299 }
1300
1301 size_type find_last_of(const basic_string& str, size_type pos = npos) const noexcept
1302 {
1303 return find_last_of(str.c_str(), pos, str.size());
1304 }
1305
1306 size_type find_last_of(const value_type* str, size_type pos, size_type len) const noexcept
1307 {
1308 if (empty() || len == 0)
1309 return npos;
1310
1311 for (size_type i = min(pos, size_ - 1) + 1; i > 0; --i)
1312 {
1313 if (is_any_of_(i - 1, str, len))
1314 return i - 1;
1315 }
1316
1317 return npos;
1318 }
1319
1320 size_type find_last_of(const value_type* str, size_type pos = npos) const noexcept
1321 {
1322 return find_last_of(str, pos, traits_type::length(str));
1323 }
1324
1325 size_type find_last_of(value_type c, size_type pos = npos) const noexcept
1326 {
1327 return rfind(c, pos);
1328 }
1329
1330 size_type find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept
1331 {
1332 return find_first_not_of(str.c_str(), pos, str.size());
1333 }
1334
1335 size_type find_first_not_of(const value_type* str, size_type pos, size_type len) const noexcept
1336 {
1337 if (empty() || pos >= size())
1338 return npos;
1339
1340 size_type idx{pos};
1341
1342 while (idx < size_)
1343 {
1344 if (!is_any_of_(idx, str, len))
1345 return idx;
1346 ++idx;
1347 }
1348
1349 return npos;
1350 }
1351
1352 size_type find_first_not_of(const value_type* str, size_type pos = 0) const noexcept
1353 {
1354 return find_first_not_of(str, pos, traits_type::length(str));
1355 }
1356
1357 size_type find_first_not_of(value_type c, size_type pos = 0) const noexcept
1358 {
1359 if (empty())
1360 return npos;
1361
1362 for (size_type i = pos; i < size_; ++i)
1363 {
1364 if (!traits_type::eq(c, data_[i]))
1365 return i;
1366 }
1367
1368 return npos;
1369 }
1370
1371 size_type find_last_not_of(const basic_string& str, size_type pos = npos) const noexcept
1372 {
1373 return find_last_not_of(str.c_str(), pos, str.size());
1374 }
1375
1376 size_type find_last_not_of(const value_type* str, size_type pos, size_type len) const noexcept
1377 {
1378 if (empty())
1379 return npos;
1380
1381 for (size_type i = min(pos, size_ - 1) + 1; i > 0; --i)
1382 {
1383 if (!is_any_of_(i - 1, str, len))
1384 return i - 1;
1385 }
1386
1387 return npos;
1388 }
1389
1390 size_type find_last_not_of(const value_type* str, size_type pos = npos) const noexcept
1391 {
1392 return find_last_not_of(str, pos, traits_type::length(str));
1393 }
1394
1395 size_type find_last_not_of(value_type c, size_type pos = npos) const noexcept
1396 {
1397 if (empty())
1398 return npos;
1399
1400 pos = min(pos, size_ - 1);
1401
1402 for (size_type i = min(pos, size_ - 1) + 1; i > 1; --i)
1403 {
1404 if (!traits_type::eq(c, data_[i - 1]))
1405 return i - 1;
1406 }
1407
1408 return npos;
1409 }
1410
1411 basic_string substr(size_type pos = 0, size_type n = npos) const
1412 {
1413 // TODO: throw out_of_range if pos > size().
1414 auto len = min(n, size_ - pos);
1415 return basic_string{data() + pos, len};
1416 }
1417
1418 int compare(const basic_string& other) const noexcept
1419 {
1420 auto len = min(size(), other.size());
1421 auto comp = traits_type::compare(data_, other.data(), len);
1422
1423 if (comp != 0)
1424 return comp;
1425 else if (size() == other.size())
1426 return 0;
1427 else if (size() > other.size())
1428 return 1;
1429 else
1430 return -1;
1431 }
1432
1433 int compare(size_type pos, size_type n, const basic_string& other) const
1434 {
1435 return basic_string{*this, pos, n}.compare(other);
1436 }
1437
1438 int compare(size_type pos1, size_type n1, const basic_string& other,
1439 size_type pos2, size_type n2 = npos) const
1440 {
1441 return basic_string{*this, pos1, n1}.compare(basic_string{other, pos2, n2});
1442 }
1443
1444 int compare(const value_type* other) const
1445 {
1446 return compare(basic_string(other));
1447 }
1448
1449 int compare(size_type pos, size_type n, const value_type* other) const
1450 {
1451 return basic_string{*this, pos, n}.compare(basic_string{other});
1452 }
1453
1454 int compare(size_type pos, size_type n1,
1455 const value_type* other, size_type n2) const
1456 {
1457 return basic_string{*this, pos, n1}.compare(basic_string{other, n2});
1458 }
1459
1460 private:
1461 value_type* data_;
1462 size_type size_;
1463 size_type capacity_;
1464 allocator_type allocator_;
1465
1466 /**
1467 * Arbitrary value, standard just requires
1468 * data() to have some capacity.
1469 * (Well, we could've done data_ = &data_ and
1470 * set capacity to 0, but that would be too cryptic.)
1471 */
1472 static constexpr size_type default_capacity_{4};
1473
1474 void init_(const value_type* str, size_type size)
1475 {
1476 if (data_)
1477 allocator_.deallocate(data_, capacity_);
1478
1479 size_ = size;
1480 capacity_ = size;
1481
1482 data_ = allocator_.allocate(capacity_);
1483 traits_type::copy(data_, str, size);
1484 ensure_null_terminator_();
1485 }
1486
1487 size_type next_capacity_(size_type hint = 0) const noexcept
1488 {
1489 if (hint != 0)
1490 return max(capacity_ * 2, hint);
1491 else
1492 return max(capacity_ * 2, 2ul);
1493 }
1494
1495 void ensure_free_space_(size_type n)
1496 {
1497 /**
1498 * Note: We cannot use reserve like we
1499 * did in vector, because in string
1500 * reserve can cause shrinking.
1501 */
1502 if (size_ + 1 + n > capacity_)
1503 resize_with_copy_(size_, max(size_ + 1 + n, next_capacity_()));
1504 }
1505
1506 void resize_without_copy_(size_type capacity)
1507 {
1508 if (data_)
1509 allocator_.deallocate(data_, capacity_);
1510
1511 data_ = allocator_.allocate(capacity);
1512 size_ = 0;
1513 capacity_ = capacity;
1514 ensure_null_terminator_();
1515 }
1516
1517 void resize_with_copy_(size_type size, size_type capacity)
1518 {
1519 if(capacity_ == 0 || capacity_ < capacity)
1520 {
1521 auto new_data = allocator_.allocate(capacity);
1522
1523 auto to_copy = min(size, size_);
1524 traits_type::move(new_data, data_, to_copy);
1525
1526 std::swap(data_, new_data);
1527
1528 allocator_.deallocate(new_data, capacity_);
1529 }
1530
1531 capacity_ = capacity;
1532 size_ = size;
1533 ensure_null_terminator_();
1534 }
1535
1536 template<class Iterator1, class Iterator2>
1537 Iterator2 copy_(Iterator1 first, Iterator1 last,
1538 Iterator2 result)
1539 {
1540 while (first != last)
1541 traits_type::assign(*result++, *first++);
1542
1543 return result;
1544 }
1545
1546 template<class Iterator1, class Iterator2>
1547 Iterator2 copy_backward_(Iterator1 first, Iterator1 last,
1548 Iterator2 result)
1549 {
1550 while (last != first)
1551 traits_type::assign(*--result, *--last);
1552
1553 return result;
1554 }
1555
1556 void ensure_null_terminator_()
1557 {
1558 value_type c{};
1559 traits_type::assign(data_[size_], c);
1560 }
1561
1562 bool is_any_of_(size_type idx, const value_type* str, size_type len) const
1563 {
1564 for (size_type i = 0; i < len; ++i)
1565 {
1566 if (traits_type::eq(data_[idx], str[i]))
1567 return true;
1568 }
1569
1570 return false;
1571 }
1572
1573 bool substr_starts_at_(size_type idx, const value_type* str, size_type len) const
1574 {
1575 size_type i{};
1576 for (i = 0; i < len; ++i)
1577 {
1578 if (!traits_type::eq(data_[idx + i], str[i]))
1579 break;
1580 }
1581
1582 return i == len;
1583 }
1584 };
1585
1586 using string = basic_string<char>;
1587 using u16string = basic_string<char16_t>;
1588 using u32string = basic_string<char32_t>;
1589 using wstring = basic_string<wchar_t>;
1590
1591 /**
1592 * 21.4.8, basic_string non-member functions:
1593 */
1594
1595 /**
1596 * 21.4.8.1, operator+:
1597 */
1598
1599 template<class Char, class Traits, class Allocator>
1600 basic_string<Char, Traits, Allocator>
1601 operator+(const basic_string<Char, Traits, Allocator>& lhs,
1602 const basic_string<Char, Traits, Allocator>& rhs)
1603 {
1604 return basic_string<Char, Traits, Allocator>{lhs}.append(rhs);
1605 }
1606
1607 template<class Char, class Traits, class Allocator>
1608 basic_string<Char, Traits, Allocator>
1609 operator+(basic_string<Char, Traits, Allocator>&& lhs,
1610 const basic_string<Char, Traits, Allocator>& rhs)
1611 {
1612 return move(lhs.append(rhs));
1613 }
1614
1615 template<class Char, class Traits, class Allocator>
1616 basic_string<Char, Traits, Allocator>
1617 operator+(const basic_string<Char, Traits, Allocator>& lhs,
1618 basic_string<Char, Traits, Allocator>&& rhs)
1619 {
1620 return move(rhs.insert(0, lhs));
1621 }
1622
1623 template<class Char, class Traits, class Allocator>
1624 basic_string<Char, Traits, Allocator>
1625 operator+(basic_string<Char, Traits, Allocator>&& lhs,
1626 basic_string<Char, Traits, Allocator>&& rhs)
1627 {
1628 return move(lhs.append(rhs));
1629 }
1630
1631 template<class Char, class Traits, class Allocator>
1632 basic_string<Char, Traits, Allocator>
1633 operator+(const Char* lhs,
1634 const basic_string<Char, Traits, Allocator>& rhs)
1635 {
1636 return basic_string<Char, Traits, Allocator>{lhs} + rhs;
1637 }
1638
1639 template<class Char, class Traits, class Allocator>
1640 basic_string<Char, Traits, Allocator>
1641 operator+(const Char* lhs,
1642 basic_string<Char, Traits, Allocator>&& rhs)
1643 {
1644 return move(rhs.insert(0, lhs));
1645 }
1646
1647 template<class Char, class Traits, class Allocator>
1648 basic_string<Char, Traits, Allocator>
1649 operator+(Char lhs,
1650 const basic_string<Char, Traits, Allocator>& rhs)
1651 {
1652 return basic_string<Char, Traits, Allocator>{1, lhs}.append(rhs);
1653 }
1654
1655 template<class Char, class Traits, class Allocator>
1656 basic_string<Char, Traits, Allocator>
1657 operator+(Char lhs,
1658 basic_string<Char, Traits, Allocator>&& rhs)
1659 {
1660 return move(rhs.insert(0, 1, lhs));
1661 }
1662
1663 template<class Char, class Traits, class Allocator>
1664 basic_string<Char, Traits, Allocator>
1665 operator+(const basic_string<Char, Traits, Allocator>& lhs,
1666 const Char* rhs)
1667 {
1668 return lhs + basic_string<Char, Traits, Allocator>{rhs};
1669 }
1670
1671 template<class Char, class Traits, class Allocator>
1672 basic_string<Char, Traits, Allocator>
1673 operator+(basic_string<Char, Traits, Allocator>&& lhs,
1674 const Char* rhs)
1675 {
1676 return move(lhs.append(rhs));
1677 }
1678
1679 template<class Char, class Traits, class Allocator>
1680 basic_string<Char, Traits, Allocator>
1681 operator+(const basic_string<Char, Traits, Allocator>& lhs,
1682 Char rhs)
1683 {
1684 return lhs + basic_string<Char, Traits, Allocator>{1, rhs};
1685 }
1686
1687 template<class Char, class Traits, class Allocator>
1688 basic_string<Char, Traits, Allocator>
1689 operator+(basic_string<Char, Traits, Allocator>&& lhs,
1690 Char rhs)
1691 {
1692 return move(lhs.append(1, rhs));
1693 }
1694
1695 /**
1696 * 21.4.8.2, operator==:
1697 */
1698
1699 template<class Char, class Traits, class Allocator>
1700 bool operator==(const basic_string<Char, Traits, Allocator>& lhs,
1701 const basic_string<Char, Traits, Allocator>& rhs) noexcept
1702 {
1703 return lhs.compare(rhs) == 0;
1704 }
1705
1706 template<class Char, class Traits, class Allocator>
1707 bool operator==(const Char* lhs,
1708 const basic_string<Char, Traits, Allocator>& rhs)
1709 {
1710 return rhs == lhs;
1711 }
1712
1713 template<class Char, class Traits, class Allocator>
1714 bool operator==(const basic_string<Char, Traits, Allocator>& lhs,
1715 const Char* rhs)
1716 {
1717 return lhs.compare(rhs) == 0;
1718 }
1719
1720 /**
1721 * 21.4.8.3, operator!=:
1722 */
1723
1724 template<class Char, class Traits, class Allocator>
1725 bool operator!=(const basic_string<Char, Traits, Allocator>& lhs,
1726 const basic_string<Char, Traits, Allocator>& rhs) noexcept
1727 {
1728 return !(lhs == rhs);
1729 }
1730
1731 template<class Char, class Traits, class Allocator>
1732 bool operator!=(const Char* lhs,
1733 const basic_string<Char, Traits, Allocator>& rhs)
1734 {
1735 return rhs != lhs;
1736 }
1737
1738 template<class Char, class Traits, class Allocator>
1739 bool operator!=(const basic_string<Char, Traits, Allocator>& lhs,
1740 const Char* rhs)
1741 {
1742 return lhs.compare(rhs) != 0;
1743 }
1744
1745 /**
1746 * 21.4.8.4, operator<:
1747 */
1748
1749 template<class Char, class Traits, class Allocator>
1750 bool operator<(const basic_string<Char, Traits, Allocator>& lhs,
1751 const basic_string<Char, Traits, Allocator>& rhs) noexcept
1752 {
1753 return lhs.compare(rhs) < 0;
1754 }
1755
1756 template<class Char, class Traits, class Allocator>
1757 bool operator<(const Char* lhs,
1758 const basic_string<Char, Traits, Allocator>& rhs)
1759 {
1760 return rhs.compare(lhs) > 0;
1761 }
1762
1763 template<class Char, class Traits, class Allocator>
1764 bool operator<(const basic_string<Char, Traits, Allocator>& lhs,
1765 const Char* rhs)
1766 {
1767 return lhs.compare(rhs) < 0;
1768 }
1769
1770 /**
1771 * 21.4.8.5, operator>:
1772 */
1773
1774 template<class Char, class Traits, class Allocator>
1775 bool operator>(const basic_string<Char, Traits, Allocator>& lhs,
1776 const basic_string<Char, Traits, Allocator>& rhs) noexcept
1777 {
1778 return lhs.compare(rhs) > 0;
1779 }
1780
1781 template<class Char, class Traits, class Allocator>
1782 bool operator>(const Char* lhs,
1783 const basic_string<Char, Traits, Allocator>& rhs)
1784 {
1785 return rhs.compare(lhs) < 0;
1786 }
1787
1788 template<class Char, class Traits, class Allocator>
1789 bool operator>(const basic_string<Char, Traits, Allocator>& lhs,
1790 const Char* rhs)
1791 {
1792 return lhs.compare(rhs) > 0;
1793 }
1794
1795 /**
1796 * 21.4.8.6, operator<=:
1797 */
1798
1799 template<class Char, class Traits, class Allocator>
1800 bool operator<=(const basic_string<Char, Traits, Allocator>& lhs,
1801 const basic_string<Char, Traits, Allocator>& rhs) noexcept
1802 {
1803 return lhs.compare(rhs) <= 0;
1804 }
1805
1806 template<class Char, class Traits, class Allocator>
1807 bool operator<=(const Char* lhs,
1808 const basic_string<Char, Traits, Allocator>& rhs)
1809 {
1810 return rhs.compare(lhs) >= 0;
1811 }
1812
1813 template<class Char, class Traits, class Allocator>
1814 bool operator<=(const basic_string<Char, Traits, Allocator>& lhs,
1815 const Char* rhs)
1816 {
1817 return lhs.compare(rhs) <= 0;
1818 }
1819
1820 /**
1821 * 21.4.8.7, operator>=:
1822 */
1823
1824 template<class Char, class Traits, class Allocator>
1825 bool operator>=(const basic_string<Char, Traits, Allocator>& lhs,
1826 const basic_string<Char, Traits, Allocator>& rhs) noexcept
1827 {
1828 return lhs.compare(rhs) >= 0;
1829 }
1830
1831 template<class Char, class Traits, class Allocator>
1832 bool operator>=(const Char* lhs,
1833 const basic_string<Char, Traits, Allocator>& rhs)
1834 {
1835 return rhs.compare(lhs) <= 0;
1836 }
1837
1838 template<class Char, class Traits, class Allocator>
1839 bool operator>=(const basic_string<Char, Traits, Allocator>& lhs,
1840 const Char* rhs)
1841 {
1842 return lhs.compare(rhs) >= 0;
1843 }
1844
1845 /**
1846 * 21.4.8.8, swap:
1847 */
1848
1849 template<class Char, class Traits, class Allocator>
1850 void swap(basic_string<Char, Traits, Allocator>& lhs,
1851 basic_string<Char, Traits, Allocator>& rhs)
1852 noexcept(noexcept(lhs.swap(rhs)))
1853 {
1854 lhs.swap(rhs);
1855 }
1856
1857 /**
1858 * 21.4.8.9, inserters and extractors:
1859 */
1860
1861 // TODO: implement
1862
1863 /**
1864 * 21.5, numeric conversions:
1865 */
1866
1867 int stoi(const string& str, size_t* idx = nullptr, int base = 10);
1868 long stol(const string& str, size_t* idx = nullptr, int base = 10);
1869 unsigned long stoul(const string& str, size_t* idx = nullptr, int base = 10);
1870 long long stoll(const string& str, size_t* idx = nullptr, int base = 10);
1871 unsigned long long stoull(const string& str, size_t* idx = nullptr, int base = 10);
1872
1873 float stof(const string& str, size_t* idx = nullptr);
1874 double stod(const string& str, size_t* idx = nullptr);
1875 long double stold(const string& str, size_t* idx = nullptr);
1876
1877 string to_string(int val);
1878 string to_string(unsigned val);
1879 string to_string(long val);
1880 string to_string(unsigned long val);
1881 string to_string(long long val);
1882 string to_string(unsigned long long val);
1883 string to_string(float val);
1884 string to_string(double val);
1885 string to_string(long double val);
1886
1887 int stoi(const wstring& str, size_t* idx = nullptr, int base = 10);
1888 long stol(const wstring& str, size_t* idx = nullptr, int base = 10);
1889 unsigned long stoul(const wstring& str, size_t* idx = nullptr, int base = 10);
1890 long long stoll(const wstring& str, size_t* idx = nullptr, int base = 10);
1891 unsigned long long stoull(const wstring& str, size_t* idx = nullptr, int base = 10);
1892
1893 float stof(const wstring& str, size_t* idx = nullptr);
1894 double stod(const wstring& str, size_t* idx = nullptr);
1895 long double stold(const wstring& str, size_t* idx = nullptr);
1896
1897 wstring to_wstring(int val);
1898 wstring to_wstring(unsigned val);
1899 wstring to_wstring(long val);
1900 wstring to_wstring(unsigned long val);
1901 wstring to_wstring(long long val);
1902 wstring to_wstring(unsigned long long val);
1903 wstring to_wstring(float val);
1904 wstring to_wstring(double val);
1905 wstring to_wstring(long double val);
1906
1907 /**
1908 * 21.6, hash support:
1909 */
1910
1911 // TODO: implement
1912
1913 /**
1914 * 21.7, suffix for basic_string literals:
1915 */
1916
1917 /**
1918 * Note: According to the standard, literal suffixes that do not
1919 * start with an underscore are reserved for future standardization,
1920 * but since we are implementing the standard, we're going to ignore it.
1921 * This should work (according to their documentation) work for clang,
1922 * but that should be tested.
1923 */
1924#pragma GCC diagnostic push
1925#pragma GCC diagnostic ignored "-Wliteral-suffix"
1926 string operator "" s(const char* str, size_t len);
1927 u16string operator "" s(const char16_t* str, size_t len);
1928 u32string operator "" s(const char32_t* str, size_t len);
1929
1930 /* Problem: wchar_t == int in HelenOS, but standard forbids it.
1931 wstring operator "" s(const wchar_t* str, size_t len);
1932 */
1933#pragma GCC diagnostic pop
1934}
1935
1936#endif
Note: See TracBrowser for help on using the repository browser.