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 53 136 38.9
branch 10 42 23.8
condition n/a
subroutine n/a
pod n/a
total 63 178 35.3


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