File Coverage

/usr/local/lib/perl5/site_perl/5.26.1/x86_64-linux/CPP/panda/lib.x/i/panda/basic_string.h
Criterion Covered Total %
statement 75 135 55.5
branch 14 42 33.3
condition n/a
subroutine n/a
pod n/a
total 89 177 50.2


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