File Coverage

/usr/local/lib/perl5/site_perl/5.26.1/x86_64-linux/XS/libpanda.x/i/panda/basic_string.h
Criterion Covered Total %
statement 9 128 7.0
branch 3 46 6.5
condition n/a
subroutine n/a
pod n/a
total 12 174 6.9


line stmt bran cond sub pod time code
1             #pragma once
2             #include "hash.h"
3             #include "from_chars.h"
4             #include "string_view.h"
5             #include
6             #include
7             #include
8             #include
9             #include // swap
10             #include
11             #include
12             #include
13             #include
14             #include
15             #include
16              
17             namespace panda {
18              
19             /*
20             * panda::string is an std::string drop-in replacement which has the same API but is much more flexible and allows for behaviors that in other case
21             * would lead to a lot of unnecessary allocations/copying.
22             *
23             * Most important features are:
24             *
25             * - Copy-On-Write support (COW).
26             * Not only when assigning the whole string but also when any form of substr() is applied.
27             * If any of the COW copies is trying to change, it detaches from the original string, copying the content it needs.
28             * - External static string support.
29             * Can be created from external static(immortal) data without allocating memory and copying it.
30             * String will be allocated and copied when you first try to change it.
31             * For example if a function accepts string, you may pass it just a string literal "hello" and nothing is allocated or copied and even the length
32             * is counted in compile time.
33             * - External dynamic string support.
34             * Can be created from external dynamic(mortal) data without allocating memory and copying it.
35             * External data will be deallocated via custom destructor when the last string that references to the external data is lost.
36             * As for any other subtype of panda::string copying/substr/etc of such string does not copy anything
37             * - SSO support (small string optimization). Up to 23 bytes for 64bit / 11 bytes for 32bit.
38             * It does not mean that all strings <= MAX_SSO_CHARS are in SSO mode. SSO mode is used only when otherwise panda::string would have to allocate
39             * and copy something. For example if you call "otherstr = mystr.substr(offset, len)", then otherstr will not use SSO even if len <= MAX_SSO_CHARS,
40             * because it prefers to do nothing (COW-mode) instead of copying content to SSO location.
41             * - Support for getting r/w internal data buffer to manually fill it.
42             * The content of other strings which shares the data with current string will not be affected.
43             * - Reallocate instead of deallocate/allocate when possible, which in many cases is much faster
44             * - Supports auto convertations between basic_strings with different Allocator template parameter without copying and allocating anything.
45             * For example any basic_string<...> can be assigned to/from string as if they were of the same class.
46             *
47             * All these features covers almost all generic use cases, including creating zero-copy cascade parsers which in other case would lead to a lot of
48             * pain.
49             *
50             * c_str() is not supported, because strings are not null-terminated
51             */
52              
53             namespace string_detail {
54             template
55             struct mutable_charref {
56             using value_type = typename S::value_type;
57             using size_type = typename S::size_type;
58              
59             mutable_charref (S& string, size_type pos): _string(string), _pos(pos) {}
60              
61             template ::value>>
62             mutable_charref& operator= (Arg&& value) {
63             _string._detach();
64             _string._str[_pos] = std::forward(value);
65             return *this;
66             }
67              
68             operator value_type() const { return _string._str[_pos]; }
69              
70             private:
71             S& _string;
72             size_type _pos;
73             };
74              
75             enum class State : uint8_t {
76             LITERAL, // shares external data, no Buffer, no _storage.dtor (literal data is immortal)
77             SSO, // owns small string, no Buffer, no _storage.dtor
78             INTERNAL, // has InternalBuffer, may have _storage.dtor in case of basic_string <-> basic_string convertations
79             EXTERNAL, // has ExternalShared, shares external data, _storage.dtor present, _storage.external->dtor present
80             };
81              
82             template
83             struct Buffer {
84             size_t capacity;
85             uint32_t refcnt;
86             CharT start[(sizeof(void*)-4)/sizeof(CharT)]; // align to word size
87             };
88              
89             template
90             struct ExternalShared : Buffer {
91             using dtor_fn = void (*)(CharT*, size_t);
92             dtor_fn dtor; // deallocator for ExternalShared, may differ from Alloc::deallocate !
93             CharT* ptr; // pointer to external data originally passed to string's constructor
94             };
95             }
96              
97             template
98             struct DefaultStaticAllocator {
99             typedef T value_type;
100              
101 0           static T* allocate (size_t n) {
102 0           void* mem = malloc(n * sizeof(T));
103 0 0         if (!mem) throw std::bad_alloc();
104 0           return (T*)mem;
105             }
106              
107 0           static void deallocate (T* mem, size_t) {
108 0           free(mem);
109 0           }
110              
111 0           static T* reallocate (T* mem, size_t need, size_t /*old*/) {
112 0           void* new_mem = realloc(mem, need * sizeof(T));
113             //if (new_mem != mem) { call move constructors if applicable }
114 0           return (T*)new_mem;
115             }
116             };
117              
118             // GCC fails to determine maybe-uninitialized cases correctly for this code
119             #pragma GCC diagnostic push
120             #pragma GCC diagnostic ignored "-Wpragmas"
121             #pragma GCC diagnostic ignored "-Wunknown-warning-option"
122             #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
123              
124             template , class Alloc = DefaultStaticAllocator>
125             struct basic_string {
126             struct iterator;
127             typedef Traits traits_type;
128             typedef Alloc allocator_type;
129             typedef std::allocator_traits allocator_traits;
130             typedef typename Traits::char_type value_type;
131             typedef value_type& reference;
132             typedef const value_type& const_reference;
133             typedef typename allocator_traits::pointer pointer;
134             typedef typename allocator_traits::const_pointer const_pointer;
135             typedef const CharT* const_iterator;
136             typedef std::reverse_iterator reverse_iterator;
137             typedef std::reverse_iterator const_reverse_iterator;
138             typedef typename allocator_traits::difference_type difference_type;
139             typedef typename allocator_traits::size_type size_type;
140              
141             using ExternalShared = string_detail::ExternalShared;
142              
143             private:
144             using dtor_fn = typename ExternalShared::dtor_fn;
145             using State = string_detail::State;
146             using Buffer = string_detail::Buffer;
147             using mutable_charref = string_detail::mutable_charref;
148              
149             template friend struct basic_string;
150             friend mutable_charref;
151              
152             static constexpr const size_type BUF_CHARS = (sizeof(Buffer) - sizeof(Buffer().start)) / sizeof(CharT);
153             static constexpr const size_type EBUF_CHARS = sizeof(ExternalShared) / sizeof(CharT);
154             static constexpr const size_type MAX_SSO_BYTES = 3 * sizeof(void*) - 1; // last byte for _state
155             static constexpr const float GROW_RATE = 1.6;
156             static const CharT TERMINAL;
157              
158             union {
159             CharT* _str;
160             const CharT* _str_literal;
161             };
162              
163             size_type _length;
164              
165             #pragma pack(push, 1)
166             union { // the size of this union is MAX_SSO_BYTES. Last byte is kept for _state which is following this union (and thus packing is needed)
167             char __fill[MAX_SSO_BYTES];
168             CharT _sso[MAX_SSO_BYTES/sizeof(CharT)];
169             struct {
170             union {
171             Buffer* any; // when code doesn't matter if we in internal or external state
172             Buffer* internal;
173             ExternalShared* external;
174             };
175             dtor_fn dtor;
176             } _storage;
177             };
178             State _state;
179             #pragma pack(pop)
180              
181             public:
182             static const size_type npos = std::numeric_limits::max();
183             static const size_type MAX_SSO_CHARS = (MAX_SSO_BYTES / sizeof(CharT));
184             static const size_type MAX_SIZE = npos / sizeof(CharT) - BUF_CHARS;
185              
186             constexpr basic_string () noexcept : _str_literal(&TERMINAL), _length(0), _state(State::LITERAL) {}
187              
188             template // implicit constructor for literals, literals are expected to be null-terminated
189             constexpr basic_string (const CharT (&str)[SIZE]) noexcept : _str_literal(str), _length(SIZE-1), _state(State::LITERAL) {}
190              
191             template // implicit constructor for char arrays, array must be null-trminated, behaviour is similar to std::string
192             constexpr basic_string (CharT (&str)[SIZE]) noexcept : basic_string(str, traits_type::length(str)) {}
193              
194             template::value>::type>
195             // GCC < 6 has a bug determining return value type for literals, so this ctor must be implicitly available
196             #if !defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 6
197             explicit
198             #endif
199 0           basic_string (const _CharT* const& str) noexcept : basic_string(str, traits_type::length(str)) {}
200              
201             explicit
202             basic_string (size_type capacity) : _length(0) {
203             _new_auto(capacity);
204             }
205              
206 0           basic_string (const CharT* str, size_type len) : _length(len) {
207 0           _new_auto(len);
208 0           traits_type::copy(_str, str, len);
209 0           }
210              
211             basic_string (CharT* str, size_type len, size_type capacity, dtor_fn dtor) {
212             _new_external(str, len, capacity, dtor, (ExternalShared*)Alloc::allocate(EBUF_CHARS), &Alloc::deallocate);
213             }
214              
215             basic_string (CharT* str, size_type len, size_type capacity, dtor_fn dtor, ExternalShared* ebuf, dtor_fn ebuf_dtor) {
216             _new_external(str, len, capacity, dtor, ebuf, ebuf_dtor);
217             }
218              
219             basic_string (size_type len, CharT c) : _length(len) {
220             _new_auto(len);
221             traits_type::assign(_str, len, c);
222             }
223              
224             basic_string (const basic_string& oth) {
225             _cow(oth, 0, oth._length);
226             }
227              
228             template
229             basic_string (const basic_string& oth) {
230             _cow(oth, 0, oth._length);
231             }
232              
233             template
234             basic_string (const basic_string& oth, size_type pos) {
235             _cow_offset(oth, pos, oth._length);
236             }
237              
238             template
239             basic_string (const basic_string& oth, size_type pos, size_type len) {
240             _cow_offset(oth, pos, len);
241             }
242              
243             basic_string (basic_string&& oth) {
244             _move_from(std::move(oth));
245             }
246              
247             template
248             basic_string (basic_string&& oth) {
249             _move_from(std::move(oth));
250             }
251              
252             basic_string (std::initializer_list ilist) : basic_string(ilist.begin(), ilist.size()) {}
253              
254             explicit
255             basic_string (basic_string_view sv) : basic_string(sv.data(), sv.length()) {}
256              
257             explicit
258             basic_string (const std::basic_string& ss) : basic_string(ss.data(), ss.length()) {}
259              
260             template
261             basic_string& assign (const CharT (&str)[SIZE]) {
262             _release();
263             _state = State::LITERAL;
264             _str_literal = str;
265             _length = SIZE - 1;
266             return *this;
267             }
268              
269             struct iterator {
270             using size_type = typename basic_string::size_type;
271             using value_type = typename basic_string::value_type;
272             using reference = mutable_charref;
273             using pointer = mutable_charref;
274             using difference_type = std::ptrdiff_t;
275             using iterator_category = std::random_access_iterator_tag;
276             using const_iterator = typename basic_string::const_iterator;
277              
278             iterator (basic_string& string, size_type pos): _string(&string), _pos(pos) {}
279              
280             iterator () = default;
281             iterator (const iterator&) = default;
282             iterator (iterator&&) = default;
283              
284             iterator& operator=(const iterator&) = default;
285             iterator& operator=(iterator&&) = default;
286              
287             iterator& operator++ () { ++_pos; return *this; }
288             iterator operator++ (int) { iterator copy{*_string, _pos }; ++_pos; return copy; }
289             iterator& operator-- () { --_pos; return *this; }
290             iterator operator-- (int) { iterator copy{*_string, _pos }; --_pos; return copy; }
291             iterator& operator+= (int delta) { _pos += delta; return *this; }
292             iterator& operator-= (int delta) { _pos -= delta; return *this; }
293             reference operator* () { return reference{*_string, _pos}; }
294             reference operator-> () { return reference{*_string, _pos}; }
295             reference operator[] (size_type i) { return reference{*_string, i + _pos}; }
296              
297             difference_type operator- (const iterator& rhs) const { return static_cast(_pos - rhs._pos); }
298              
299             bool operator== (const iterator& rhs) const { return _pos == rhs._pos; }
300             bool operator!= (const iterator& rhs) const { return _pos != rhs._pos; }
301             bool operator< (const iterator& rhs) const { return rhs._pos - _pos > 0; }
302             bool operator> (const iterator& rhs) const { return _pos - rhs._pos > 0; }
303             bool operator<= (const iterator& rhs) const { return rhs._pos - _pos >= 0; }
304             bool operator>= (const iterator& rhs) const { return _pos - rhs._pos >= 0; }
305              
306             operator const_iterator () { return _string->data() + _pos; }
307              
308             friend inline iterator operator+ (int delta, const iterator& it) { return iterator{*it._string, it._pos + delta}; }
309             friend inline iterator operator+ (const iterator& it, int delta) { return iterator{*it._string, it._pos + delta}; }
310             friend inline iterator operator- (int delta, const iterator& it) { return iterator{*it._string, it._pos - delta}; }
311             friend inline iterator operator- (const iterator& it, int delta) { return iterator{*it._string, it._pos - delta}; }
312              
313             private:
314             basic_string* _string;
315             size_type _pos;
316             };
317              
318              
319             template::value>::type>
320             basic_string& assign (const _CharT* const& str) {
321             return assign(str, traits_type::length(str));
322             }
323              
324             basic_string& assign (const CharT* str, size_type len) {
325             _reserve_drop(len);
326             traits_type::copy(_str, str, len);
327             _length = len;
328             return *this;
329             }
330              
331             basic_string& assign (CharT* str, size_type len, size_type capacity, dtor_fn dtor) {
332             if (_state != State::EXTERNAL || _storage.external->refcnt != 1) {
333             _release();
334             _new_external(str, len, capacity, dtor, (ExternalShared*)Alloc::allocate(EBUF_CHARS), &Alloc::deallocate);
335             }
336             else _replace_external(str, len, capacity, dtor);
337             return *this;
338             }
339              
340             basic_string& assign (CharT* str, size_type len, size_type capacity, dtor_fn dtor, ExternalShared* ebuf, dtor_fn ebuf_dtor) {
341             // EXTERNAL refcnt==1 optimizations do not apply because user already allocated ebuf and in either case we would need to deallocate one ebuf
342             _release();
343             _new_external(str, len, capacity, dtor, ebuf, ebuf_dtor);
344             return *this;
345             }
346              
347             basic_string& assign (size_type len, CharT c) {
348             _reserve_drop(len);
349             traits_type::assign(_str, len, c);
350             _length = len;
351             return *this;
352             }
353              
354             template
355             basic_string& assign (const basic_string& source) {
356             if (std::is_same::value && this == (void*)&source) return *this;
357             _release();
358             _cow(source, 0, source._length);
359             return *this;
360             }
361              
362             template
363             basic_string& assign (const basic_string& source, size_type pos, size_type length = npos) {
364             if (std::is_same::value && this == (void*)&source)
365             offset(pos, length);
366             else {
367             _release();
368             _cow_offset(source, pos, length);
369             }
370             return *this;
371             }
372              
373             template
374             basic_string& assign (basic_string&& source) {
375             if (std::is_same::value && this == (void*)&source) return *this;
376             _release();
377             _move_from(std::move(source));
378             return *this;
379             }
380              
381             basic_string& assign (std::initializer_list ilist) {
382             return assign(ilist.begin(), ilist.size());
383             }
384              
385             basic_string& assign (basic_string_view sv) {
386             return assign(sv.data(), sv.length());
387             }
388              
389             template
390             basic_string& operator= (const CharT (&str)[SIZE]) { return assign(str); }
391             template::value>::type>
392             basic_string& operator= (const _CharT* const& str) { return assign(str); }
393             basic_string& operator= (CharT c) { return assign(1, c); }
394             basic_string& operator= (const basic_string& source) { return assign(source); }
395             template
396             basic_string& operator= (const basic_string& source) { return assign(source); }
397             basic_string& operator= (basic_string&& source) { return assign(std::move(source)); }
398             template
399             basic_string& operator= (basic_string&& source) { return assign(std::move(source)); }
400             basic_string& operator= (std::initializer_list ilist) { return assign(ilist); }
401             basic_string& operator= (basic_string_view sv) { return assign(sv); }
402              
403 0           constexpr size_type length () const { return _length; }
404             constexpr size_type size () const { return _length; }
405 0           constexpr const CharT* data () const { return _str; }
406             constexpr bool empty () const { return _length == 0; }
407             constexpr size_type max_size () const { return MAX_SIZE; }
408              
409             CharT* buf () { _detach(); return _str; }
410             CharT* shared_buf () { _shared_detach(); return _str; }
411              
412             CharT* reserve (size_type capacity) {
413             _reserve_save(capacity);
414             return _str;
415             }
416              
417             iterator begin () { return iterator(*this, 0); }
418             iterator end () { return iterator(*this, _length); }
419             reverse_iterator rbegin () { return reverse_iterator(end()); }
420             reverse_iterator rend () { return reverse_iterator(begin()); }
421              
422             constexpr const_iterator cbegin () const { return data(); }
423             constexpr const_iterator begin () const { return cbegin(); }
424             constexpr const_iterator cend () const { return data() + _length; }
425             constexpr const_iterator end () const { return cend(); }
426             constexpr const_reverse_iterator crbegin () const { return const_reverse_iterator(cend()); }
427             constexpr const_reverse_iterator rbegin () const { return crbegin(); }
428             constexpr const_reverse_iterator crend () const { return const_reverse_iterator(cbegin()); }
429             constexpr const_reverse_iterator rend () const { return crend(); }
430              
431             explicit
432             constexpr operator bool () const { return _length; }
433              
434             operator std::basic_string () const { return std::basic_string(_str, _length); }
435             operator basic_string_view () const { return basic_string_view(_str, _length); }
436              
437             const CharT& at (size_type pos) const {
438             if (pos >= _length) throw std::out_of_range("basic_string::at");
439             return _str[pos];
440             }
441              
442             mutable_charref at (size_type pos) {
443             if (pos >= _length) throw std::out_of_range("basic_string::at");
444             return mutable_charref{ *this, pos };
445             }
446              
447             constexpr const CharT& operator[] (size_type pos) const { return _str[pos]; }
448             mutable_charref operator[] (size_type pos) { return mutable_charref{ *this, pos }; }
449              
450             constexpr const CharT& front () const { return _str[0]; }
451             constexpr const CharT& back () const { return _str[_length-1]; }
452             mutable_charref front () { return mutable_charref{ *this, 0 }; }
453             mutable_charref back () { return mutable_charref{ *this, _length-1 }; }
454              
455 3           size_type capacity () const {
456 3           switch (_state) {
457 3 50         case State::INTERNAL: return _storage.internal->refcnt == 1 ? _capacity_internal() : 0;
458 0 0         case State::EXTERNAL: return _storage.external->refcnt == 1 ? _capacity_external() : 0;
459 0           case State::LITERAL: return 0;
460 0           case State::SSO: return _capacity_sso();
461             }
462 0           return 0;
463             }
464              
465             size_type shared_capacity () const {
466             switch (_state) {
467             case State::INTERNAL: return _capacity_internal();
468             case State::EXTERNAL: return _capacity_external();
469             case State::LITERAL: return 0;
470             case State::SSO: return _capacity_sso();
471             }
472             return 0;
473             }
474              
475             uint32_t use_count () const {
476             switch (_state) {
477             case State::INTERNAL:
478             case State::EXTERNAL:
479             return _storage.any->refcnt;
480             default: return 1;
481             }
482             }
483              
484             void length (size_type newlen) { _length = newlen; }
485              
486             void offset (size_type offset, size_type length = npos) {
487             if (offset > _length) throw std::out_of_range("basic_string::offset");
488             if (length > _length - offset) _length = _length - offset;
489             else _length = length;
490             _str += offset;
491             }
492              
493             basic_string substr (size_type offset = 0, size_type length = npos) const {
494             return basic_string(*this, offset, length);
495             }
496              
497             void resize (size_type count) { resize(count, CharT()); }
498              
499             void resize (size_type count, CharT ch) {
500             if (count > _length) {
501             _reserve_save(count);
502             traits_type::assign(_str + _length, count - _length, ch);
503             }
504             _length = count;
505             }
506              
507             void pop_back () { --_length; }
508             void clear () { _length = 0; }
509              
510             void shrink_to_fit () {
511             switch (_state) {
512             case State::INTERNAL:
513             if (_length <= MAX_SSO_CHARS) {
514             auto old_buf = _storage.internal;
515             auto old_dtor = _storage.dtor;
516             _detach_str(_length);
517             _release_internal(old_buf, old_dtor);
518             }
519             else if (_storage.internal->capacity > _length) {
520             if (_storage.internal->refcnt == 1) _internal_realloc(_length);
521             // else _detach_cow(_length); // NOTE: it's a very hard question should or should not we do it, NOT FOR NOW
522             }
523             break;
524             case State::EXTERNAL:
525             if (_length <= MAX_SSO_CHARS) {
526             auto old_buf = _storage.external;
527             auto old_dtor = _storage.dtor;
528             _detach_str(_length);
529             _release_external(old_buf, old_dtor);
530             }
531             else if (_storage.external->capacity > _length) {
532             if (_storage.external->refcnt == 1) _external_realloc(_length);
533             // else _detach_cow(_length); // NOTE: it's a very hard question should or should not we do it, NOT FOR NOW
534             }
535             break;
536             case State::LITERAL:
537             case State::SSO:
538             break;
539             }
540             }
541              
542             template
543             void swap (basic_string& oth) {
544             std::swap(_str, oth._str);
545             std::swap(_length, oth._length);
546             if (_state == State::SSO) oth._str = oth._sso + (oth._str - _sso);
547             if (oth._state == State::SSO) _str = _sso + (_str - oth._sso);
548             // swap union & state after it
549             std::swap(((void**)__fill)[0], ((void**)oth.__fill)[0]);
550             std::swap(((void**)__fill)[1], ((void**)oth.__fill)[1]);
551             std::swap(((void**)__fill)[2], ((void**)oth.__fill)[2]);
552             }
553              
554             size_type copy (CharT* dest, size_type count, size_type pos = 0) const {
555             if (pos > _length) throw std::out_of_range("basic_string::copy");
556             if (count > _length - pos) count = _length - pos;
557             traits_type::copy(dest, _str + pos, count);
558             return count;
559             }
560              
561             basic_string& erase (size_type pos = 0, size_type count = npos) {
562             if (pos > _length) throw std::out_of_range("basic_string::erase");
563              
564             if (count > _length - pos) { // remove trail
565             _length = pos;
566             return *this;
567             }
568              
569             _length -= count;
570              
571             if (pos == 0) { // remove head
572             _str += count;
573             return *this;
574             }
575              
576             switch (_state) {
577             case State::INTERNAL:
578             case State::EXTERNAL:
579             if (_storage.any->refcnt == 1) {
580             case State::SSO:
581             // move tail or head depending on what is shorter
582             if (pos >= _length - pos) traits_type::move(_str + pos, _str + pos + count, _length - pos); // tail is shorter
583             else { // head is shorter
584             traits_type::move(_str + count, _str, pos);
585             _str += count;
586             }
587             break;
588             }
589             else --_storage.any->refcnt; // fallthrough
590             case State::LITERAL:
591             auto old_str = _str;
592             _new_auto(_length);
593             traits_type::copy(_str, old_str, pos);
594             traits_type::copy(_str + pos, old_str + pos + count, _length - pos);
595             break;
596             }
597             return *this;
598             }
599              
600             const_iterator erase (const_iterator it) {
601             size_type pos = it - cbegin();
602             erase(pos, 1);
603             return cbegin() + pos;
604             }
605              
606             const_iterator erase (const_iterator first, const_iterator last) {
607             size_type pos = first - cbegin();
608             erase(pos, last - first);
609             return cbegin() + pos;
610             }
611              
612             template
613             int compare (const basic_string& str) const {
614             return _compare(_str, _length, str._str, str._length);
615             }
616              
617             template
618             int compare (size_type pos1, size_type count1, const basic_string& str) const {
619             if (pos1 > _length) throw std::out_of_range("basic_string::compare");
620             if (count1 > _length - pos1) count1 = _length - pos1;
621             return _compare(_str + pos1, count1, str._str, str._length);
622             }
623              
624             template
625             int compare (size_type pos1, size_type count1, const basic_string& str, size_type pos2, size_type count2 = npos) const {
626             if (pos1 > _length || pos2 > str._length) throw std::out_of_range("basic_string::compare");
627             if (count1 > _length - pos1) count1 = _length - pos1;
628             if (count2 > str._length - pos2) count2 = str._length - pos2;
629             return _compare(_str + pos1, count1, str._str + pos2, count2);
630             }
631              
632             template::value>::type>
633             int compare (const _CharT* const& s) const {
634             return _compare(_str, _length, s, traits_type::length(s));
635             }
636              
637             template
638             int compare (const CharT (&s)[SIZE]) const {
639             return _compare(_str, _length, s, SIZE-1);
640             }
641              
642             template::value>::type>
643             int compare (size_type pos1, size_type count1, const _CharT* const& s) const {
644             return compare(pos1, count1, s, traits_type::length(s));
645             }
646              
647             template
648             int compare (size_type pos1, size_type count1, const CharT (&s)[SIZE]) const {
649             return compare(pos1, count1, s, SIZE-1);
650             }
651              
652             int compare (size_type pos1, size_type count1, const CharT* ptr, size_type count2) const {
653             if (pos1 > _length) throw std::out_of_range("basic_string::compare");
654             if (count1 > _length - pos1) count1 = _length - pos1;
655             return _compare(_str + pos1, count1, ptr, count2);
656             }
657              
658             int compare (basic_string_view sv) const {
659             return _compare(_str, _length, sv.data(), sv.length());
660             }
661              
662             int compare (size_type pos1, size_type count1, basic_string_view sv) const {
663             return compare(pos1, count1, sv.data(), sv.length());
664             }
665              
666             template
667             size_type find (const basic_string& str, size_type pos = 0) const {
668             return find(str._str, pos, str._length);
669             }
670              
671             size_type find (const CharT* s, size_type pos, size_type count) const {
672             if (pos > _length) return npos;
673             if (count == 0) return pos;
674              
675             const CharT* ptr = traits_type::find(_str + pos, _length - pos, *s);
676             const CharT* end = _str + _length;
677             while (ptr && end >= ptr + count) {
678             if (traits_type::compare(ptr, s, count) == 0) return ptr - _str;
679             ptr = traits_type::find(ptr+1, end - ptr - 1, *s);
680             }
681              
682             return npos;
683             }
684              
685             template::value>::type>
686             size_type find (const _CharT* const& s, size_type pos = 0) const {
687             return find(s, pos, traits_type::length(s));
688             }
689              
690             template
691             size_type find (const CharT (&s)[SIZE], size_type pos = 0) const {
692             return find(s, pos, SIZE-1);
693             }
694              
695             size_type find (CharT ch, size_type pos = 0) const {
696             if (pos >= _length) return npos;
697             const CharT* ptr = traits_type::find(_str + pos, _length - pos, ch);
698             if (ptr) return ptr - _str;
699             return npos;
700             }
701              
702             size_type find (basic_string_view sv, size_type pos = 0) const {
703             return find(sv.data(), pos, sv.length());
704             }
705              
706             template
707             size_type rfind (const basic_string& str, size_type pos = npos) const {
708             return rfind(str._str, pos, str._length);
709             }
710              
711             size_type rfind (const CharT* s, size_type pos, size_type count) const {
712             for (const CharT* ptr = _str + ((pos >= _length - count) ? (_length - count) : pos); ptr >= _str; --ptr)
713             if (traits_type::compare(ptr, s, count) == 0) return ptr - _str;
714             return npos;
715             }
716              
717             template::value>::type>
718             size_type rfind (const _CharT* const& s, size_type pos = npos) const {
719             return rfind(s, pos, traits_type::length(s));
720             }
721              
722             template
723             size_type rfind (const CharT (&s)[SIZE], size_type pos = npos) const {
724             return rfind(s, pos, SIZE-1);
725             }
726              
727             size_type rfind (CharT ch, size_type pos = npos) const {
728             const CharT* ptr = _str + (pos >= _length ? _length : (pos+1));
729             while (--ptr >= _str) if (traits_type::eq(*ptr, ch)) return ptr - _str;
730             return npos;
731             }
732              
733             size_type rfind (basic_string_view sv, size_type pos = npos) const {
734             return rfind(sv.data(), pos, sv.length());
735             }
736              
737             template
738             size_type find_first_of (const basic_string& str, size_type pos = 0) const {
739             return find_first_of(str._str, pos, str._length);
740             }
741              
742             size_type find_first_of (const CharT* s, size_type pos, size_type count) const {
743             if (count == 0) return npos;
744             const CharT* end = _str + _length;
745             for (const CharT* ptr = _str + pos; ptr < end; ++ptr) if (traits_type::find(s, count, *ptr)) return ptr - _str;
746             return npos;
747             }
748              
749             template::value>::type>
750             size_type find_first_of (const _CharT* const& s, size_type pos = 0) const {
751             return find_first_of(s, pos, traits_type::length(s));
752             }
753              
754             template
755             size_type find_first_of (const CharT (&s)[SIZE], size_type pos = 0) const {
756             return find_first_of(s, pos, SIZE-1);
757             }
758              
759             size_type find_first_of (CharT ch, size_type pos = 0) const {
760             return find(ch, pos);
761             }
762              
763             size_type find_first_of (basic_string_view sv, size_type pos = 0) const {
764             return find_first_of(sv.data(), pos, sv.length());
765             }
766              
767             template
768             size_type find_first_not_of (const basic_string& str, size_type pos = 0) const {
769             return find_first_not_of(str._str, pos, str._length);
770             }
771              
772             size_type find_first_not_of (const CharT* s, size_type pos, size_type count) const {
773             if (count == 0) return pos >= _length ? npos : pos;
774             const CharT* end = _str + _length;
775             for (const CharT* ptr = _str + pos; ptr < end; ++ptr) if (!traits_type::find(s, count, *ptr)) return ptr - _str;
776             return npos;
777             }
778              
779             template::value>::type>
780             size_type find_first_not_of (const _CharT* const& s, size_type pos = 0) const {
781             return find_first_not_of(s, pos, traits_type::length(s));
782             }
783              
784             template
785             size_type find_first_not_of (const CharT (&s)[SIZE], size_type pos = 0) const {
786             return find_first_not_of(s, pos, SIZE-1);
787             }
788              
789             size_type find_first_not_of (CharT ch, size_type pos = 0) const {
790             const CharT* end = _str + _length;
791             for (const CharT* ptr = _str + pos; ptr < end; ++ptr) if (!traits_type::eq(*ptr, ch)) return ptr - _str;
792             return npos;
793             }
794              
795             size_type find_first_not_of (basic_string_view sv, size_type pos = 0) const {
796             return find_first_not_of(sv.data(), pos, sv.length());
797             }
798              
799             template
800             size_type find_last_of (const basic_string& str, size_type pos = npos) const {
801             return find_last_of(str._str, pos, str._length);
802             }
803              
804             size_type find_last_of (const CharT* s, size_type pos, size_type count) const {
805             if (count == 0) return npos;
806             for (const CharT* ptr = _str + (pos >= _length ? (_length - 1) : pos); ptr >= _str; --ptr)
807             if (traits_type::find(s, count, *ptr)) return ptr - _str;
808             return npos;
809             }
810              
811             template::value>::type>
812             size_type find_last_of (const _CharT* const& s, size_type pos = npos) const {
813             return find_last_of(s, pos, traits_type::length(s));
814             }
815              
816             template
817             size_type find_last_of (const CharT (&s)[SIZE], size_type pos = npos) const {
818             return find_last_of(s, pos, SIZE-1);
819             }
820              
821             size_type find_last_of (CharT ch, size_type pos = npos) const {
822             return rfind(ch, pos);
823             }
824              
825             size_type find_last_of (basic_string_view sv, size_type pos = npos) const {
826             return find_last_of(sv.data(), pos, sv.length());
827             }
828              
829             template
830             size_type find_last_not_of (const basic_string& str, size_type pos = npos) const {
831             return find_last_not_of(str._str, pos, str._length);
832             }
833              
834             size_type find_last_not_of (const CharT* s, size_type pos, size_type count) const {
835             if (count == 0) return pos >= _length ? (_length-1) : pos;
836             for (const CharT* ptr = _str + (pos >= _length ? (_length - 1) : pos); ptr >= _str; --ptr)
837             if (!traits_type::find(s, count, *ptr)) return ptr - _str;
838             return npos;
839             }
840              
841             template::value>::type>
842             size_type find_last_not_of (const _CharT* const& s, size_type pos = npos) const {
843             return find_last_not_of(s, pos, traits_type::length(s));
844             }
845              
846             template
847             size_type find_last_not_of (const CharT (&s)[SIZE], size_type pos = npos) const {
848             return find_last_not_of(s, pos, SIZE-1);
849             }
850              
851             size_type find_last_not_of (CharT ch, size_type pos = npos) const {
852             for (const CharT* ptr = _str + (pos >= _length ? (_length - 1) : pos); ptr >= _str; --ptr)
853             if (!traits_type::eq(*ptr, ch)) return ptr - _str;
854             return npos;
855             }
856              
857             size_type find_last_not_of (basic_string_view sv, size_type pos = npos) const {
858             return find_last_not_of(sv.data(), pos, sv.length());
859             }
860              
861             basic_string& append (size_type count, CharT ch) {
862             if (count) {
863             _reserve_save_extra(_length + count);
864             traits_type::assign(_str + _length, count, ch);
865             _length += count;
866             }
867             return *this;
868             }
869              
870             template
871             basic_string& append (const basic_string& str) {
872             if (str._length) { // can't call append(const CharT*, size_type) because otherwise if &str == this a fuckup would occur
873             _reserve_save_extra(_length + str._length);
874             traits_type::copy(_str + _length, str._str, str._length);
875             _length += str._length;
876             }
877             return *this;
878             }
879              
880             template
881             basic_string& append (const basic_string& str, size_type pos, size_type count = npos) {
882             if (pos > str._length) throw std::out_of_range("basic_string::append");
883             if (count > str._length - pos) count = str._length - pos;
884             if (count) { // can't call append(const CharT*, size_type) because otherwise if &str == this a fuckup would occur
885             _reserve_save_extra(_length + count);
886             traits_type::copy(_str + _length, str._str + pos, count);
887             _length += count;
888             }
889             return *this;
890             }
891              
892             basic_string& append (const CharT* s, size_type count) { // 's' MUST NOT BE any part of this->data()
893             if (count) {
894             _reserve_save_extra(_length + count);
895             traits_type::copy(_str + _length, s, count);
896             _length += count;
897             }
898             return *this;
899             }
900              
901             template::value>::type>
902             basic_string& append (const _CharT* const& s) {
903             return append(s, traits_type::length(s));
904             }
905              
906             template
907             basic_string& append (const CharT (&s)[SIZE]) {
908             return append(s, SIZE-1);
909             }
910              
911             basic_string& append (std::initializer_list ilist) {
912             return append(ilist.begin(), ilist.size());
913             }
914              
915             basic_string& append (basic_string_view sv) {
916             return append(sv.data(), sv.length());
917             }
918              
919             void push_back (CharT ch) {
920             append(1, ch);
921             }
922              
923             template
924             basic_string& operator+= (const CharT (&str)[SIZE]) { return append(str, SIZE-1); }
925             template::value>::type>
926             basic_string& operator+= (const _CharT* const& str) { return append(str); }
927             template
928             basic_string& operator+= (const basic_string& str) { return append(str); }
929             basic_string& operator+= (CharT ch) { return append(1, ch); }
930             basic_string& operator+= (std::initializer_list ilist) { return append(ilist); }
931             basic_string& operator+= (basic_string_view sv) { return append(sv); }
932              
933             basic_string& insert (size_type pos, const basic_string& str) {
934             if (this == &str) {
935             const basic_string tmp(str);
936             return insert(pos, tmp._str, tmp._length);
937             }
938             else return insert(pos, str._str, str._length);
939             }
940              
941             template
942             basic_string& insert (size_type pos, const basic_string& str) {
943             return insert(pos, str._str, str._length);
944             }
945              
946             basic_string& insert (size_type pos, const basic_string& str, size_type subpos, size_type sublen = npos) {
947             if (subpos > str._length) throw std::out_of_range("basic_string::insert");
948             if (sublen > str._length - subpos) sublen = str._length - subpos;
949             if (this == &str) {
950             const basic_string tmp(str);
951             return insert(pos, tmp._str + subpos, sublen);
952             }
953             else return insert(pos, str._str + subpos, sublen);
954             }
955              
956             template
957             basic_string& insert (size_type pos, const basic_string& str, size_type subpos, size_type sublen = npos) {
958             if (subpos > str._length) throw std::out_of_range("basic_string::insert");
959             if (sublen > str._length - subpos) sublen = str._length - subpos;
960             return insert(pos, str._str + subpos, sublen);
961             }
962              
963             template::value>::type>
964             basic_string& insert (size_type pos, const _CharT* const& s) {
965             return insert(pos, s, traits_type::length(s));
966             }
967              
968             template
969             basic_string& insert (size_type pos, const CharT (&s)[SIZE]) {
970             return insert(pos, s, SIZE-1);
971             }
972              
973             basic_string& insert (size_type pos, const CharT* s, size_type count) {
974             if (pos >= _length) {
975             if (pos == _length) return append(s, count);
976             throw std::out_of_range("basic_string::insert");
977             }
978             if (count == 0) return *this;
979             _reserve_middle(pos, 0, count);
980             traits_type::copy(_str + pos, s, count);
981             return *this;
982             }
983              
984             basic_string& insert (size_type pos, size_type count, CharT ch) {
985             if (pos >= _length) {
986             if (pos == _length) return append(count, ch);
987             throw std::out_of_range("basic_string::insert");
988             }
989             if (count == 0) return *this;
990             _reserve_middle(pos, 0, count);
991             traits_type::assign(_str + pos, count, ch);
992             return *this;
993             }
994              
995             iterator insert (const_iterator it, size_type count, CharT ch) {
996             size_type pos = it - cbegin();
997             insert(pos, count, ch);
998             return iterator{*this, pos};
999             }
1000              
1001             iterator insert (const_iterator it, CharT ch) {
1002             size_type pos = it - cbegin();
1003             insert(pos, 1, ch);
1004             return iterator{*this, pos};
1005             }
1006              
1007             basic_string& insert (const_iterator it, std::initializer_list ilist) {
1008             return insert(it - cbegin(), ilist.begin(), ilist.size());
1009             }
1010              
1011             basic_string& insert (size_type pos, basic_string_view sv) {
1012             return insert(pos, sv.data(), sv.length());
1013             }
1014              
1015             // fix ambiguity between iterator(char*) and size_t
1016             basic_string& insert (int pos, size_type count, CharT ch) { return insert((size_type)pos, count, ch); }
1017              
1018             basic_string& replace (size_type pos, size_type remove_count, const basic_string& str) {
1019             if (this == &str) {
1020             const basic_string tmp(str);
1021             return replace(pos, remove_count, tmp._str, tmp._length);
1022             }
1023             return replace(pos, remove_count, str._str, str._length);
1024             }
1025              
1026             template
1027             basic_string& replace (size_type pos, size_type remove_count, const basic_string& str) {
1028             return replace(pos, remove_count, str._str, str._length);
1029             }
1030              
1031             template
1032             basic_string& replace (const_iterator first, const_iterator last, const basic_string& str) {
1033             return replace(first - cbegin(), last - first, str);
1034             }
1035              
1036             basic_string& replace (size_type pos, size_type remove_count, const basic_string& str, size_type pos2, size_type insert_count = npos) {
1037             if (pos2 > str._length) throw std::out_of_range("basic_string::replace");
1038             if (insert_count > str._length - pos2) insert_count = str._length - pos2;
1039             if (this == &str) {
1040             const basic_string tmp(str);
1041             return replace(pos, remove_count, tmp._str + pos2, insert_count);
1042             }
1043             return replace(pos, remove_count, str._str + pos2, insert_count);
1044             }
1045              
1046             template
1047             basic_string& replace (size_type pos, size_type remove_count, const basic_string& str, size_type pos2, size_type insert_count = npos) {
1048             if (pos2 > str._length) throw std::out_of_range("basic_string::replace");
1049             if (insert_count > str._length - pos2) insert_count = str._length - pos2;
1050             return replace(pos, remove_count, str._str + pos2, insert_count);
1051             }
1052              
1053             basic_string& replace (size_type pos, size_type remove_count, const CharT* s, size_type insert_count) {
1054             if (pos >= _length) {
1055             if (pos == _length) return append(s, insert_count);
1056             throw std::out_of_range("basic_string::replace");
1057             }
1058             if (remove_count >= _length - pos) {
1059             _length = pos;
1060             return append(s, insert_count);
1061             }
1062             if (insert_count == 0) {
1063             if (remove_count == 0) return *this;
1064             return erase(pos, remove_count);
1065             }
1066             _reserve_middle(pos, remove_count, insert_count);
1067             traits_type::copy(_str + pos, s, insert_count);
1068             return *this;
1069             }
1070              
1071             basic_string& replace (const_iterator first, const_iterator last, const CharT* s, size_type insert_count) {
1072             return replace(first - cbegin(), last - first, s, insert_count);
1073             }
1074              
1075             template::value>::type>
1076             basic_string& replace (size_type pos, size_type remove_count, const _CharT* const& s) {
1077             return replace(pos, remove_count, s, traits_type::length(s));
1078             }
1079              
1080             template
1081             basic_string& replace (size_type pos, size_type remove_count, const CharT (&s)[SIZE]) {
1082             return replace(pos, remove_count, s, SIZE-1);
1083             }
1084              
1085             template::value>::type>
1086             basic_string& replace (const_iterator first, const_iterator last, const _CharT* const& s) {
1087             return replace(first, last, s, traits_type::length(s));
1088             }
1089              
1090             template
1091             basic_string& replace (const_iterator first, const_iterator last, const CharT (&s)[SIZE]) {
1092             return replace(first, last, s, SIZE-1);
1093             }
1094              
1095             basic_string& replace (size_type pos, size_type remove_count, size_type insert_count, CharT ch) {
1096             if (pos >= _length) {
1097             if (pos == _length) return append(insert_count, ch);
1098             throw std::out_of_range("basic_string::replace");
1099             }
1100             if (remove_count >= _length - pos) {
1101             _length = pos;
1102             return append(insert_count, ch);
1103             }
1104             if (insert_count == 0) {
1105             if (remove_count == 0) return *this;
1106             return erase(pos, remove_count);
1107             }
1108             _reserve_middle(pos, remove_count, insert_count);
1109             traits_type::assign(_str + pos, insert_count, ch);
1110             return *this;
1111             }
1112              
1113             basic_string& replace (const_iterator first, const_iterator last, size_type insert_count, CharT ch) {
1114             return replace(first - cbegin(), last - first, insert_count, ch);
1115             }
1116              
1117             basic_string& replace (const_iterator first, const_iterator last, std::initializer_list ilist) {
1118             return replace(first, last, ilist.begin(), ilist.size());
1119             }
1120              
1121             basic_string& replace (size_type pos, size_type remove_count, basic_string_view sv) {
1122             return replace(pos, remove_count, sv.data(), sv.length());
1123             }
1124              
1125             basic_string& replace (const_iterator first, const_iterator last, basic_string_view sv) {
1126             return replace(first - cbegin(), last - first, sv);
1127             }
1128              
1129             template
1130             from_chars_result to_number (V& value, int base = 10) const { return from_chars(_str, _str + _length, value, base); }
1131              
1132             template
1133             from_chars_result to_number (V& value, size_type pos, size_type count = npos, int base = 10) const {
1134             if (pos > _length) throw std::out_of_range("basic_string::to_number");
1135             if (count > _length - pos) count = _length - pos;
1136             return from_chars(_str + pos, _str + pos + count, value, base);
1137             }
1138              
1139             template
1140             static basic_string from_number (V value, int base = 10) {
1141             auto maxsz = to_chars_maxsize(base);
1142             basic_string ret(maxsz);
1143             auto res = to_chars(ret._str, ret._str + maxsz, value, base);
1144             assert(!res.ec);
1145             ret.length(res.ptr - ret.data());
1146             return ret;
1147             }
1148              
1149 3           const CharT* c_str () const {
1150 3 50         if (_state == State::LITERAL) return _str; // LITERALs are NT
1151             // _str[_length] access to possibly uninititalized memory, UB.
1152             // if we have r/o space after string, let's see if it's already NT
1153             // if (shared_capacity() > _length && _str[_length] == 0) return _str;
1154              
1155             // string is not NT
1156 3 50         if (capacity() <= _length) const_cast(this)->_reserve_save(_length + 1); // we're in COW mode or don't have space
1157 3           _str[_length] = 0;
1158 3           return _str;
1159             }
1160              
1161 0           ~basic_string () { _release(); }
1162              
1163             private:
1164              
1165 6           constexpr size_type _capacity_internal () const { return _storage.internal->capacity - (_str - _storage.internal->start); }
1166 0           constexpr size_type _capacity_external () const { return _storage.external->capacity - (_str - _storage.external->ptr); }
1167 0           constexpr size_type _capacity_sso () const { return MAX_SSO_CHARS - (_str - _sso); }
1168              
1169 0           void _new_auto (size_type capacity) {
1170 0 0         if (capacity <= MAX_SSO_CHARS) {
1171 0           _state = State::SSO;
1172 0           _str = _sso;
1173             } else {
1174 0 0         if (capacity > MAX_SIZE) throw std::length_error("basic_string::_new_auto");
    0          
1175 0           _state = State::INTERNAL;
1176 0           _storage.internal = (Buffer*)Alloc::allocate(capacity + BUF_CHARS);
1177 0           _storage.internal->capacity = capacity;
1178 0           _storage.internal->refcnt = 1;
1179 0           _str = _storage.internal->start;
1180 0           _storage.dtor = &Alloc::deallocate;
1181             }
1182 0           }
1183              
1184             // becomes INTERNAL for capacity, and copy _str to buffer in the way so that none of internal SSO members are written before copy is made.
1185 0           void _new_internal_from_sso (size_type capacity) {
1186 0           auto ibuf = (Buffer*)Alloc::allocate(capacity + BUF_CHARS);
1187 0           traits_type::copy(ibuf->start, _str, _length);
1188 0           ibuf->capacity = capacity;
1189 0           ibuf->refcnt = 1;
1190 0           _state = State::INTERNAL;
1191 0           _str = ibuf->start;
1192 0           _storage.internal = ibuf;
1193 0           _storage.dtor = &Alloc::deallocate;
1194 0           }
1195              
1196             void _new_internal_from_sso (size_type capacity, size_type pos, size_type remove_count, size_type insert_count) {
1197             auto ibuf = (Buffer*)Alloc::allocate(capacity + BUF_CHARS);
1198             if (pos) traits_type::copy(ibuf->start, _str, pos);
1199             traits_type::copy((CharT*)ibuf->start + pos + insert_count, _str + pos + remove_count, _length - pos - remove_count);
1200             ibuf->capacity = capacity;
1201             ibuf->refcnt = 1;
1202             _state = State::INTERNAL;
1203             _str = ibuf->start;
1204             _storage.internal = ibuf;
1205             _storage.dtor = &Alloc::deallocate;
1206             }
1207              
1208             void _new_external (CharT* str, size_type len, size_type capacity, dtor_fn dtor, ExternalShared* ebuf, dtor_fn ebuf_dtor) {
1209             _state = State::EXTERNAL;
1210             _str = str;
1211             _length = len;
1212             ebuf->capacity = capacity;
1213             ebuf->refcnt = 1;
1214             ebuf->dtor = ebuf_dtor;
1215             ebuf->ptr = str;
1216             _storage.dtor = dtor;
1217             _storage.external = ebuf;
1218             }
1219              
1220             // releases currently held external string and reuses current ExternalShared for the new external string
1221             void _replace_external (CharT* str, size_type len, size_type capacity, dtor_fn dtor) {
1222             _free_external_str();
1223             _str = str;
1224             _length = len;
1225             _storage.dtor = dtor;
1226             _storage.external->capacity = capacity;
1227             _storage.external->ptr = str;
1228             }
1229              
1230             template
1231             void _cow (const basic_string& oth, size_type offset, size_type length) {
1232             _length = length;
1233             switch (oth._state) {
1234             case State::INTERNAL:
1235             case State::EXTERNAL:
1236             _state = oth._state;
1237             _str = oth._str + offset;
1238             _storage.any = oth._storage.any;
1239             _storage.dtor = oth._storage.dtor;
1240             ++_storage.any->refcnt;
1241             break;
1242             case State::LITERAL:
1243             _state = State::LITERAL;
1244             _str_literal = oth._str_literal + offset;
1245             break;
1246             case State::SSO:
1247             memcpy(__fill, oth.__fill, MAX_SSO_BYTES+1); // also sets _state to SSO
1248             _str = _sso + (oth._str - oth._sso) + offset;
1249             break;
1250             }
1251             }
1252              
1253             template
1254             void _cow_offset (const basic_string& oth, size_type offset, size_type length) {
1255             if (offset > oth._length) throw std::out_of_range("basic_string::assign");
1256             if (length > oth._length - offset) length = oth._length - offset;
1257             _cow(oth, offset, length);
1258             }
1259              
1260             template
1261             void _move_from (basic_string&& oth) {
1262             _length = oth._length;
1263             memcpy(__fill, oth.__fill, MAX_SSO_BYTES+1); // also sets _state
1264             if (oth._state == State::SSO) _str = _sso + (oth._str - oth._sso);
1265             else _str = oth._str;
1266             oth._state = State::LITERAL;
1267             oth._str_literal = &TERMINAL;
1268             oth._length = 0;
1269             }
1270              
1271             // loses content, may change state, after call _str is guaranteed to be writable (detaches from COW and statics)
1272             void _reserve_drop (size_type capacity) {
1273             switch (_state) {
1274             case State::INTERNAL: _reserve_drop_internal(capacity); break;
1275             case State::EXTERNAL: _reserve_drop_external(capacity); break;
1276             case State::LITERAL:
1277             case State::SSO: _new_auto(capacity);
1278             }
1279             }
1280              
1281             void _reserve_drop_internal (size_type capacity) {
1282             if (_storage.internal->refcnt > 1) {
1283             --_storage.internal->refcnt;
1284             _new_auto(capacity);
1285             }
1286             else if (_storage.internal->capacity < capacity) { // could realloc save anything?
1287             _free_internal();
1288             _new_auto(capacity);
1289             }
1290             else _str = _storage.internal->start;
1291             }
1292              
1293             void _reserve_drop_external (size_type capacity) {
1294             if (_storage.external->refcnt > 1) {
1295             --_storage.external->refcnt;
1296             _new_auto(capacity);
1297             }
1298             else if (_storage.external->capacity < capacity) {
1299             _free_external();
1300             _new_auto(capacity);
1301             }
1302             else _str = _storage.external->ptr;
1303             }
1304              
1305             void _detach () {
1306             switch (_state) {
1307             case State::INTERNAL:
1308             case State::EXTERNAL:
1309             // suppress false-positive uninitialized warning for "_storage.any" for GCC
1310             if (_storage.any->refcnt > 1) _detach_cow(_length);
1311             break;
1312             case State::LITERAL:
1313             _detach_str(_length);
1314             break;
1315             case State::SSO: break;
1316             }
1317             }
1318              
1319 0           void _detach_cow (size_type capacity) {
1320 0           --_storage.any->refcnt;
1321 0           _detach_str(capacity);
1322 0           }
1323              
1324 0           void _detach_str (size_type capacity) {
1325             assert(capacity >= _length);
1326 0           auto old_str = _str;
1327 0           _new_auto(capacity);
1328 0           traits_type::copy(_str, old_str, _length);
1329 0           }
1330              
1331             void _shared_detach () {
1332             if (_state == State::LITERAL) _detach_str(_length);
1333             }
1334              
1335             void _reserve_save_extra (size_type capacity) { _reserve_save(capacity, GROW_RATE); }
1336              
1337 0           void _reserve_save (size_type capacity, float extra = 1) {
1338 0 0         if (capacity < _length) capacity = _length;
1339 0           switch (_state) {
1340 0           case State::INTERNAL: _reserve_save_internal(capacity, extra); break;
1341 0           case State::EXTERNAL: _reserve_save_external(capacity, extra); break;
1342 0           case State::LITERAL: _detach_str(capacity * extra); break;
1343 0           case State::SSO: _reserve_save_sso(capacity, extra); break;
1344             }
1345 0           }
1346              
1347 0           void _reserve_save_internal (size_type capacity, float extra) {
1348 0 0         if (_storage.internal->refcnt > 1) _detach_cow(capacity * extra);
1349 0 0         else if (_storage.internal->capacity < capacity) _internal_realloc(capacity * extra); // need to grow storage
1350 0 0         else if (_capacity_internal() < capacity) { // may not to grow storage if str is moved to the beginning
1351 0           traits_type::move(_storage.internal->start, _str, _length);
1352 0           _str = _storage.internal->start;
1353             }
1354 0           }
1355              
1356 0           void _internal_realloc (size_type capacity) {
1357             // see if we can reallocate. if _str != start we should not reallocate because we would need
1358             // either allocate more space than needed or move everything to the beginning before reallocation
1359 0 0         if (_storage.dtor == &Alloc::deallocate && _str == _storage.internal->start) {
    0          
1360 0 0         if (capacity > MAX_SIZE) throw std::length_error("basic_string::_internal_realloc");
    0          
1361 0           _storage.internal = (Buffer*)Alloc::reallocate((CharT*)_storage.internal, capacity + BUF_CHARS, _storage.internal->capacity + BUF_CHARS);
1362 0           _str = _storage.internal->start;
1363 0           _storage.internal->capacity = capacity;
1364             } else { // need to allocate/deallocate
1365 0           auto old_buf = _storage.internal;
1366 0           auto old_str = _str;
1367 0           auto old_dtor = _storage.dtor;
1368 0           _new_auto(capacity);
1369 0           traits_type::copy(_str, old_str, _length);
1370 0           _free_internal(old_buf, old_dtor);
1371             }
1372 0           }
1373              
1374 0           void _reserve_save_external (size_type capacity, float extra) {
1375 0 0         if (_storage.external->refcnt > 1) _detach_cow(capacity * extra);
1376 0 0         else if (_storage.external->capacity < capacity) _external_realloc(capacity * extra); // need to grow storage, switch to INTERNAL/SSO
1377 0 0         else if (_capacity_external() < capacity) { // may not to grow storage if str is moved to the beginning
1378 0           traits_type::move(_storage.external->ptr, _str, _length);
1379 0           _str = _storage.external->ptr;
1380             }
1381 0           }
1382              
1383 0           void _external_realloc (size_type capacity) {
1384 0           auto old_buf = _storage.external;
1385 0           auto old_str = _str;
1386 0           auto old_dtor = _storage.dtor;
1387 0           _new_auto(capacity);
1388 0           traits_type::copy(_str, old_str, _length);
1389 0           _free_external(old_buf, old_dtor);
1390 0           }
1391              
1392 0           void _reserve_save_sso (size_type capacity, float extra) {
1393 0 0         if (MAX_SSO_CHARS < capacity) {
1394 0           _new_internal_from_sso(capacity * extra);
1395 0           return;
1396             }
1397 0 0         else if (_capacity_sso() < capacity) {
1398 0           traits_type::move(_sso, _str, _length);
1399 0           _str = _sso;
1400             }
1401             }
1402              
1403             // splits string into pwo pieces at position 'pos' with insert_count distance between them replacing remove_count chars after pos.
1404             // Tries its best not to allocate memory. set the length of string to old length + insert_count - remove_count.
1405             // The content of part [pos, pos+insert_count) is undefined after operation
1406             void _reserve_middle (size_type pos, size_type remove_count, size_type insert_count) {
1407             size_type newlen = _length + insert_count - remove_count;
1408              
1409             switch (_state) {
1410             case State::INTERNAL:
1411             if (_storage.internal->refcnt > 1) {
1412             --_storage.internal->refcnt;
1413             _reserve_middle_new(pos, remove_count, insert_count);
1414             }
1415             else if (newlen > _storage.internal->capacity) {
1416             auto old_buf = _storage.internal;
1417             auto old_dtor = _storage.dtor;
1418             _reserve_middle_new(pos, remove_count, insert_count);
1419             _release_internal(old_buf, old_dtor);
1420             }
1421             else _reserve_middle_move(pos, remove_count, insert_count, _storage.internal->start, _capacity_internal());
1422             break;
1423             case State::EXTERNAL:
1424             if (_storage.external->refcnt > 1) {
1425             --_storage.external->refcnt;
1426             _reserve_middle_new(pos, remove_count, insert_count);
1427             }
1428             else if (newlen > _storage.external->capacity) {
1429             auto old_buf = _storage.external;
1430             auto old_dtor = _storage.dtor;
1431             _reserve_middle_new(pos, remove_count, insert_count);
1432             _release_external(old_buf, old_dtor);
1433             }
1434             else _reserve_middle_move(pos, remove_count, insert_count, _storage.external->ptr, _capacity_external());
1435             break;
1436             case State::LITERAL:
1437             _reserve_middle_new(pos, remove_count, insert_count);
1438             break;
1439             case State::SSO:
1440             if (newlen > MAX_SSO_CHARS) _new_internal_from_sso(newlen, pos, remove_count, insert_count);
1441             else _reserve_middle_move(pos, remove_count, insert_count, _sso, _capacity_sso());
1442             break;
1443             }
1444              
1445             _length = newlen;
1446             }
1447              
1448             void _reserve_middle_new (size_type pos, size_type remove_count, size_type insert_count) {
1449             auto old_str = _str;
1450             _new_auto(_length + insert_count - remove_count);
1451             if (pos) traits_type::copy(_str, old_str, pos);
1452             traits_type::copy(_str + pos + insert_count, old_str + pos + remove_count, _length - pos - remove_count);
1453             }
1454              
1455             void _reserve_middle_move (size_type pos, size_type remove_count, size_type insert_count, CharT* ptr_start, size_type capacity_tail) {
1456             if (remove_count >= insert_count) {
1457             traits_type::move(_str + pos + insert_count, _str + pos + remove_count, _length - pos - remove_count);
1458             return;
1459             }
1460              
1461             auto extra_count = insert_count - remove_count;
1462             bool has_head_space = _str >= ptr_start + extra_count;
1463             bool has_tail_space = (capacity_tail - _length) >= extra_count;
1464             if (has_head_space && has_tail_space) { // move what is shorter
1465             if (pos > _length - pos - remove_count) { // tail is shorter
1466             traits_type::move(_str + pos + insert_count, _str + pos + remove_count, _length - pos - remove_count);
1467             } else { // head is shorter
1468             if (pos) traits_type::move(_str - extra_count, _str, pos);
1469             _str -= extra_count;
1470             }
1471             }
1472             else if (has_head_space) {
1473             if (pos) traits_type::move(_str - extra_count, _str, pos);
1474             _str -= extra_count;
1475             }
1476             else if (has_tail_space) {
1477             traits_type::move(_str + pos + insert_count, _str + pos + remove_count, _length - pos - remove_count);
1478             }
1479             else {
1480             if (pos) traits_type::move(ptr_start, _str, pos);
1481             traits_type::move(ptr_start + pos + insert_count, _str + pos + remove_count, _length - pos - remove_count);
1482             _str = ptr_start;
1483             }
1484             }
1485              
1486             // leaves object in invalid state
1487 0           void _release () {
1488             // suppress false-positive GCC warning: ‘*((void*)& +16)’ may be used uninitialized in this function
1489 0           switch (_state) {
1490             case State::LITERAL :
1491 0           case State::SSO : break;
1492 0           case State::INTERNAL : _release_internal(); break;
1493 0           case State::EXTERNAL : _release_external(); break;
1494             }
1495 0           }
1496              
1497 0           void _release_internal () { _release_internal(_storage.internal, _storage.dtor); }
1498 0           void _release_external () { _release_external(_storage.external, _storage.dtor); }
1499              
1500             void _free_internal () { _free_internal(_storage.internal, _storage.dtor); }
1501             void _free_external () { _free_external_str(); _free_external_buf(); }
1502             void _free_external_str () { _free_external_str(_storage.external, _storage.dtor); }
1503             void _free_external_buf () { _free_external_buf(_storage.external); }
1504              
1505 0 0         static void _release_internal (Buffer* buf, dtor_fn dtor) { if (!--buf->refcnt) _free_internal(buf, dtor); }
1506 0 0         static void _release_external (ExternalShared* ebuf, dtor_fn dtor) { if (!--ebuf->refcnt) _free_external(ebuf, dtor); }
1507              
1508 0           static void _free_internal (Buffer* buf, dtor_fn dtor) { dtor((CharT*)buf, buf->capacity + BUF_CHARS); }
1509 0           static void _free_external (ExternalShared* ebuf, dtor_fn dtor) { _free_external_str(ebuf, dtor); _free_external_buf(ebuf); }
1510 0           static void _free_external_str (ExternalShared* ebuf, dtor_fn dtor) { dtor(ebuf->ptr, ebuf->capacity); }
1511 0           static void _free_external_buf (ExternalShared* ebuf) { ebuf->dtor((CharT*)ebuf, EBUF_CHARS); }
1512              
1513             static int _compare (const CharT* ptr1, size_type len1, const CharT* ptr2, size_type len2) {
1514             int r = traits_type::compare(ptr1, ptr2, std::min(len1, len2));
1515             if (!r) r = (len1 < len2) ? -1 : (len1 > len2 ? 1 : 0);
1516             return r;
1517             }
1518              
1519             };
1520              
1521             #pragma GCC diagnostic pop
1522              
1523             template const C basic_string::TERMINAL = C();
1524              
1525             template const typename basic_string::size_type basic_string::npos;
1526             template const typename basic_string::size_type basic_string::MAX_SSO_CHARS;
1527             template const typename basic_string::size_type basic_string::MAX_SIZE;
1528              
1529             template inline bool operator== (const basic_string& lhs, const basic_string& rhs) { return lhs.compare(rhs) == 0; }
1530             template inline bool operator== (const C* lhs, const basic_string& rhs) { return rhs.compare(lhs) == 0; }
1531             template inline bool operator== (const basic_string& lhs, const C* rhs) { return lhs.compare(rhs) == 0; }
1532             template inline bool operator== (basic_string_view lhs, const basic_string& rhs) { return rhs.compare(lhs) == 0; }
1533             template inline bool operator== (const basic_string& lhs, basic_string_view rhs) { return lhs.compare(rhs) == 0; }
1534              
1535             template inline bool operator!= (const basic_string& lhs, const basic_string& rhs) { return lhs.compare(rhs) != 0; }
1536             template inline bool operator!= (const C* lhs, const basic_string& rhs) { return rhs.compare(lhs) != 0; }
1537             template inline bool operator!= (const basic_string& lhs, const C* rhs) { return lhs.compare(rhs) != 0; }
1538             template inline bool operator!= (basic_string_view lhs, const basic_string& rhs) { return rhs.compare(lhs) != 0; }
1539             template inline bool operator!= (const basic_string& lhs, basic_string_view rhs) { return lhs.compare(rhs) != 0; }
1540              
1541             template inline bool operator< (const basic_string& lhs, const basic_string& rhs) { return lhs.compare(rhs) < 0; }
1542             template inline bool operator< (const C* lhs, const basic_string& rhs) { return rhs.compare(lhs) > 0; }
1543             template inline bool operator< (const basic_string& lhs, const C* rhs) { return lhs.compare(rhs) < 0; }
1544             template inline bool operator< (basic_string_view lhs, const basic_string& rhs) { return rhs.compare(lhs) > 0; }
1545             template inline bool operator< (const basic_string& lhs, basic_string_view rhs) { return lhs.compare(rhs) < 0; }
1546              
1547             template inline bool operator<= (const basic_string& lhs, const basic_string& rhs) { return lhs.compare(rhs) <= 0; }
1548             template inline bool operator<= (const C* lhs, const basic_string& rhs) { return rhs.compare(lhs) >= 0; }
1549             template inline bool operator<= (const basic_string& lhs, const C* rhs) { return lhs.compare(rhs) <= 0; }
1550             template inline bool operator<= (basic_string_view lhs, const basic_string& rhs) { return rhs.compare(lhs) >= 0; }
1551             template inline bool operator<= (const basic_string& lhs, basic_string_view rhs) { return lhs.compare(rhs) <= 0; }
1552              
1553             template inline bool operator> (const basic_string& lhs, const basic_string& rhs) { return lhs.compare(rhs) > 0; }
1554             template inline bool operator> (const C* lhs, const basic_string& rhs) { return rhs.compare(lhs) < 0; }
1555             template inline bool operator> (const basic_string& lhs, const C* rhs) { return lhs.compare(rhs) > 0; }
1556             template inline bool operator> (basic_string_view lhs, const basic_string& rhs) { return rhs.compare(lhs) < 0; }
1557             template inline bool operator> (const basic_string& lhs, basic_string_view rhs) { return lhs.compare(rhs) > 0; }
1558              
1559             template inline bool operator>= (const basic_string& lhs, const basic_string& rhs) { return lhs.compare(rhs) >= 0; }
1560             template inline bool operator>= (const C* lhs, const basic_string& rhs) { return rhs.compare(lhs) <= 0; }
1561             template inline bool operator>= (const basic_string& lhs, const C* rhs) { return lhs.compare(rhs) >= 0; }
1562             template inline bool operator>= (basic_string_view lhs, const basic_string& rhs) { return rhs.compare(lhs) <= 0; }
1563             template inline bool operator>= (const basic_string& lhs, basic_string_view rhs) { return lhs.compare(rhs) >= 0; }
1564              
1565             namespace {
1566             template
1567             inline basic_string _operator_plus (const C* lhs, size_t llen, const C* rhs, size_t rlen) {
1568             basic_string ret(llen + rlen);
1569             auto buf = const_cast(ret.data()); // avoid checks for detach
1570             T::copy(buf, lhs, llen);
1571             T::copy(buf + llen, rhs, rlen);
1572             ret.length(llen + rlen);
1573             return ret;
1574             }
1575             }
1576              
1577             template
1578             inline basic_string operator+ (const basic_string& lhs, const basic_string& rhs) {
1579             if (lhs.length() == 0) return rhs;
1580             if (rhs.length() == 0) return lhs;
1581             return _operator_plus(lhs.data(), lhs.length(), rhs.data(), rhs.length());
1582             }
1583              
1584             template
1585             inline basic_string operator+ (const C* lhs, const basic_string& rhs) {
1586             size_t llen = T::length(lhs);
1587             if (llen == 0) return rhs;
1588             if (rhs.length() == 0) return basic_string(lhs, llen);
1589             return _operator_plus(lhs, llen, rhs.data(), rhs.length());
1590             }
1591              
1592             template
1593             inline basic_string operator+ (basic_string_view lhs, const basic_string& rhs) {
1594             if (lhs.length() == 0) return rhs;
1595             if (rhs.length() == 0) return basic_string(lhs);
1596             return _operator_plus(lhs.data(), lhs.length(), rhs.data(), rhs.length());
1597             }
1598              
1599             template
1600             inline basic_string operator+ (C lhs, const basic_string& rhs) {
1601             if (rhs.length() == 0) return basic_string(1, lhs);
1602             return _operator_plus(&lhs, 1, rhs.data(), rhs.length());
1603             }
1604              
1605             template
1606             inline basic_string operator+ (const basic_string& lhs, const C* rhs) {
1607             size_t rlen = T::length(rhs);
1608             if (rlen == 0) return lhs;
1609             if (lhs.length() == 0) return basic_string(rhs, rlen);
1610             return _operator_plus(lhs.data(), lhs.length(), rhs, rlen);
1611             }
1612              
1613             template
1614             inline basic_string operator+ (const basic_string& lhs, basic_string_view rhs) {
1615             if (rhs.length() == 0) return lhs;
1616             if (lhs.length() == 0) return basic_string(rhs);
1617             return _operator_plus(lhs.data(), lhs.length(), rhs.data(), rhs.length());
1618             }
1619              
1620             template
1621             inline basic_string operator+ (const basic_string& lhs, C rhs) {
1622             if (lhs.length() == 0) return basic_string(1, rhs);
1623             return _operator_plus(lhs.data(), lhs.length(), &rhs, 1);
1624             }
1625              
1626             template
1627             inline basic_string operator+ (basic_string&& lhs, const basic_string& rhs) {
1628             return std::move(lhs.append(rhs));
1629             }
1630              
1631             template
1632             inline basic_string operator+ (const basic_string& lhs, basic_string&& rhs) {
1633             return std::move(rhs.insert(0, lhs));
1634             }
1635              
1636             template
1637             inline basic_string operator+ (basic_string&& lhs, basic_string&& rhs) {
1638             return std::move(lhs.append(std::move(rhs))); // NOTE: there is cases when inserting into second is faster. But we'll need some heuristics to determine that
1639             }
1640              
1641             template
1642             inline basic_string operator+ (const C* lhs, basic_string&& rhs) {
1643             return std::move(rhs.insert(0, lhs));
1644             }
1645              
1646             template
1647             inline basic_string operator+ (basic_string_view lhs, basic_string&& rhs) {
1648             return std::move(rhs.insert(0, lhs));
1649             }
1650              
1651             template
1652             inline basic_string operator+ (C lhs, basic_string&& rhs) {
1653             return std::move(rhs.insert(0, 1, lhs));
1654             }
1655              
1656             template
1657             inline basic_string operator+ (basic_string&& lhs, const C* rhs) {
1658             return std::move(lhs.append(rhs));
1659             }
1660              
1661             template
1662             inline basic_string operator+ (basic_string&& lhs, basic_string_view rhs) {
1663             return std::move(lhs.append(rhs));
1664             }
1665              
1666             template
1667             inline basic_string operator+ (basic_string&& lhs, C rhs) {
1668             return std::move(lhs.append(1, rhs));
1669             }
1670              
1671             template
1672             inline std::basic_ostream& operator<< (std::basic_ostream& os, const basic_string& str) {
1673             return os.write(str.data(), str.length());
1674             }
1675              
1676             template
1677             inline void swap (basic_string& lhs, basic_string& rhs) {
1678             lhs.swap(rhs);
1679             }
1680              
1681             }
1682              
1683             namespace std {
1684             template
1685             struct hash> {
1686             size_t operator() (const panda::basic_string& s) const {
1687             return panda::hash::hashXX(panda::string_view((const char*)s.data(), s.length() * sizeof(C)));
1688             }
1689             };
1690              
1691             template
1692             struct hash> {
1693             size_t operator() (const panda::basic_string& s) const {
1694             return panda::hash::hashXX(panda::string_view((const char*)s.data(), s.length() * sizeof(C)));
1695             }
1696             };
1697             }