FastLED 3.9.15
Loading...
Searching...
No Matches
basic_string.cpp.hpp
Go to the documentation of this file.
2#include "fl/stl/cstring.h"
3#include "fl/stl/noexcept.h"
4#include "fl/stl/span.h"
6
7namespace fl {
8
9// ODR-use definition
10const fl::size basic_string::npos;
11
12// ======= PUBLIC CONSTRUCTORS (span delegate) =======
13
14basic_string::basic_string(fl::span<char, static_cast<fl::size>(-1)> storage) FL_NOEXCEPT
15 : basic_string(storage.data(), storage.size()) {}
16
17// ======= DESTRUCTOR =======
18
20
21// ======= string_view CONSTRUCTOR FROM basic_string =======
22// Defined here (in the same TU as basic_string itself) so
23// string_view.h can stay light: it forward-declares basic_string
24// and declares this ctor without needing basic_string's complete
25// type.
26
28 : mData(str.c_str()), mSize(str.size()) {}
29
30// ======= ACCESSORS =======
31
32const char* basic_string::c_str() const {
33 if (mStorage.is<ConstView>()) {
34 const ConstView& view = mStorage.get<ConstView>();
35 if (view.data && view.length > 0 && view.data[view.length] != '\0') {
36 const_cast<basic_string*>(this)->materialize();
37 }
38 }
39 return constData();
40}
41
43 // Inline mode — already mutable
44 if (mStorage.empty()) {
45 return inlineBufferPtr();
46 }
47 struct Visitor {
48 basic_string* self;
49 char* result;
50 void accept(NotNullStringHolderPtr& heap) {
51 if (heap.get().use_count() > 1) {
52 // COW: detach from shared data before returning mutable pointer
54 fl::make_shared<StringHolder>(heap->data(), self->mLength));
55 result = self->heapData()->data();
56 } else {
57 result = heap->data();
58 }
59 }
60 void accept(ConstLiteral&) {
61 self->materialize();
62 result = self->hasHeapData() ? self->heapData()->data()
63 : self->inlineBufferPtr();
64 }
65 void accept(ConstView&) {
66 self->materialize();
67 result = self->hasHeapData() ? self->heapData()->data()
68 : self->inlineBufferPtr();
69 }
70 };
71 Visitor v{this, nullptr};
72 mStorage.visit(v);
73 return v.result;
74}
75
76fl::size basic_string::capacity() const {
77 if (hasHeapData()) {
78 return heapData()->capacity();
79 } else if (isNonOwning()) {
80 return 0;
81 }
82 return mInlineCapacity;
83}
84
85// ======= ELEMENT ACCESS =======
86
87char basic_string::operator[](fl::size index) const {
88 if (index >= mLength) {
89 return '\0';
90 }
91 return c_str()[index];
92}
93
94char& basic_string::operator[](fl::size index) {
95 static char dummy = '\0';
96 if (index >= mLength) {
97 dummy = '\0';
98 return dummy;
99 }
100 return c_str_mutable()[index];
101}
102
103char& basic_string::at(fl::size pos) {
104 static char dummy = '\0';
105 if (pos >= mLength) {
106 dummy = '\0';
107 return dummy;
108 }
109 return c_str_mutable()[pos];
110}
111
112const char& basic_string::at(fl::size pos) const {
113 static char dummy = '\0';
114 if (pos >= mLength) {
115 dummy = '\0';
116 return dummy;
117 }
118 return c_str()[pos];
119}
120
122 if (empty()) return '\0';
123 return c_str()[0];
124}
125
126char basic_string::back() const {
127 if (empty()) return '\0';
128 return c_str()[mLength - 1];
129}
130
131char basic_string::charAt(fl::size index) const {
132 if (index >= mLength) return '\0';
133 return c_str()[index];
134}
135
136// ======= COMPARISON OPERATORS =======
137
138bool basic_string::operator==(const basic_string& other) const { return fl::strcmp(c_str(), other.c_str()) == 0; }
139bool basic_string::operator!=(const basic_string& other) const { return fl::strcmp(c_str(), other.c_str()) != 0; }
140bool basic_string::operator<(const basic_string& other) const { return fl::strcmp(c_str(), other.c_str()) < 0; }
141bool basic_string::operator>(const basic_string& other) const { return fl::strcmp(c_str(), other.c_str()) > 0; }
142bool basic_string::operator<=(const basic_string& other) const { return fl::strcmp(c_str(), other.c_str()) <= 0; }
143bool basic_string::operator>=(const basic_string& other) const { return fl::strcmp(c_str(), other.c_str()) >= 0; }
144
145bool basic_string::operator==(const char* other) const { return fl::strcmp(c_str(), other ? other : "") == 0; }
146bool basic_string::operator!=(const char* other) const { return fl::strcmp(c_str(), other ? other : "") != 0; }
147
148// ======= HELPER METHODS =======
149
150const char* basic_string::constData() const {
151 if (isInline()) {
152 return inlineBufferPtr();
153 } else if (mStorage.is<NotNullStringHolderPtr>()) {
154 return mStorage.get<NotNullStringHolderPtr>()->data();
155 } else if (mStorage.is<ConstLiteral>()) {
156 return mStorage.get<ConstLiteral>().data;
157 } else if (mStorage.is<ConstView>()) {
158 return mStorage.get<ConstView>().data;
159 }
160 return "";
161}
162
164 if (mStorage.is<ConstLiteral>()) {
165 const char* data = mStorage.get<ConstLiteral>().data;
166 if (!data) {
167 mLength = 0;
168 mStorage.reset();
169 inlineBufferPtr()[0] = '\0';
170 return;
171 }
172 fl::size len = mLength;
173 if (len + 1 <= mInlineCapacity) {
175 inlineBufferPtr()[len] = '\0';
176 mStorage.reset();
177 } else {
179 }
180 } else if (mStorage.is<ConstView>()) {
181 const ConstView& view = mStorage.get<ConstView>();
182 if (!view.data) {
183 mLength = 0;
184 mStorage.reset();
185 inlineBufferPtr()[0] = '\0';
186 return;
187 }
188 fl::size len = view.length;
189 mLength = len;
190 if (len + 1 <= mInlineCapacity) {
191 fl::memcpy(inlineBufferPtr(), view.data, len);
192 inlineBufferPtr()[len] = '\0';
193 mStorage.reset();
194 } else {
196 }
197 }
198}
199
206
210
211// ======= WRITE =======
212
213fl::size basic_string::write(const fl::u8* data, fl::size n) {
214 const char* str = fl::bit_cast_ptr<const char>(static_cast<const void*>(data));
215 return write(str, n);
216}
217
218fl::size basic_string::write(char c) { return write(&c, 1); }
219
221 const char* str = fl::bit_cast_ptr<const char>(static_cast<const void*>(&c));
222 return write(str, 1);
225fl::size basic_string::write(const char* str, fl::size n) {
226 fl::size newLen = mLength + n;
227
228 // Handle non-owning storage
229 if (isNonOwning()) {
230 const char* existingData = constData();
231 fl::size existingLen = mLength;
232 if (newLen + 1 <= mInlineCapacity) {
233 if (existingLen > 0 && existingData) {
234 fl::memcpy(inlineBufferPtr(), existingData, existingLen);
235 }
236 fl::memcpy(inlineBufferPtr() + existingLen, str, n);
237 inlineBufferPtr()[newLen] = '\0';
238 mStorage.reset();
239 mLength = newLen;
240 } else {
242 if (existingLen > 0 && existingData) {
243 fl::memcpy(newData->data(), existingData, existingLen);
244 }
245 fl::memcpy(newData->data() + existingLen, str, n);
246 newData->data()[newLen] = '\0';
247 mStorage = newData;
248 mLength = newLen;
249 }
250 return mLength;
251 }
252
253 if (hasHeapData() && heapData().get().use_count() <= 1) {
255 if (!heap->hasCapacity(newLen)) {
256 // Check if str points into our buffer (self-referential write).
257 // grow() uses realloc which can relocate the buffer.
258 const char* bufStart = heap->data();
259 fl::size grow_length = fl::max(3, newLen * 3 / 2);
260 if (str >= bufStart && str < bufStart + mLength + 1) {
261 fl::size offset = static_cast<fl::size>(str - bufStart);
262 heap->grow(grow_length);
263 str = heap->data() + offset; // update to new location
264 } else {
265 heap->grow(grow_length);
266 }
267 }
268 fl::memcpy(heap->data() + mLength, str, n);
269 mLength = newLen;
270 heap->data()[mLength] = '\0';
271 return mLength;
272 } else if (hasHeapData()) {
273 // Copy-on-write
275 {
276 const NotNullStringHolderPtr& heap = heapData();
277 fl::memcpy(newData->data(), heap->data(), mLength);
278 fl::memcpy(newData->data() + mLength, str, n);
279 newData->data()[newLen] = '\0';
280 mStorage = newData;
281 mLength = newLen;
282 }
283 return mLength;
284 }
285 if (newLen + 1 <= mInlineCapacity) {
287 FL_DISABLE_WARNING(array-bounds)
290 mLength = newLen;
291 inlineBufferPtr()[mLength] = '\0';
292 return mLength;
293 }
294 // Transition from inline to heap
296 {
297 fl::memcpy(newData->data(), inlineBufferPtr(), mLength);
298 fl::memcpy(newData->data() + mLength, str, n);
299 newData->data()[newLen] = '\0';
300 mStorage = newData;
301 mLength = newLen;
302 }
303 return mLength;
304}
305
306fl::size basic_string::write(const fl::u16& n) {
307 char buf[64] = {0};
308 int len = fl::utoa32(static_cast<fl::u32>(n), buf, 10);
309 return write(buf, len);
310}
311
312fl::size basic_string::write(const fl::u32& val) {
313 char buf[64] = {0};
314 int len = fl::utoa32(val, buf, 10);
315 return write(buf, len);
316}
317
318fl::size basic_string::write(const u64& val) {
319 char buf[64] = {0};
320 int len = fl::utoa64(val, buf, 10);
321 return write(buf, len);
324fl::size basic_string::write(const i64& val) {
325 char buf[64] = {0};
326 int len = fl::itoa64(val, buf, 10);
327 return write(buf, len);
330fl::size basic_string::write(const fl::i32& val) {
331 char buf[64] = {0};
332 int len = fl::itoa(val, buf, 10);
333 return write(buf, len);
336fl::size basic_string::write(const fl::i8 val) {
337 char buf[64] = {0};
338 int len = fl::itoa(static_cast<fl::i32>(val), buf, 10);
339 return write(buf, len);
340}
341
342// ======= COPY =======
343
344void basic_string::copy(const char* str) {
345 fl::size len = fl::strlen(str);
346 mLength = len;
347 if (len + 1 <= mInlineCapacity) {
348 if (!isInline()) {
349 mStorage.reset();
350 }
351 fl::memcpy(inlineBufferPtr(), str, len + 1);
352 } else {
353 if (hasHeapData() && heapData().get().use_count() <= 1) {
354 heapData()->copy(str, len);
355 return;
361void basic_string::copy(const char* str, fl::size len) {
362 mLength = len;
363 if (len + 1 <= mInlineCapacity) {
364 if (!isInline()) {
365 mStorage.reset();
368 inlineBufferPtr()[len] = '\0';
369 } else {
370 if (hasHeapData() && heapData().get().use_count() <= 1) {
371 heapData()->copy(str, len);
372 return;
373 }
375 }
376}
377
379 fl::size len = other.size();
380 if (other.hasHeapData()) {
381 // Share the heap pointer
382 const auto& otherHeap = other.mStorage.get<NotNullStringHolderPtr>();
383 mStorage = otherHeap;
384 } else if (len + 1 <= mInlineCapacity) {
385 if (!isInline()) {
386 mStorage.reset();
387 }
388 const char* src = other.c_str();
389 char* dst = inlineBufferPtr();
390 fl::memcpy(dst, src, len + 1);
391 } else {
393 }
394 mLength = len;
395}
396
397fl::size basic_string::copy(char* dest, fl::size count, fl::size pos) const {
398 if (!dest) return 0;
399 if (pos >= mLength) return 0;
400 fl::size actualCount = count;
401 if (actualCount > mLength - pos) {
402 actualCount = mLength - pos;
403 }
404 if (actualCount > 0) {
405 fl::memcpy(dest, c_str() + pos, actualCount);
406 }
407 return actualCount;
408}
409
410// ======= ASSIGN =======
411
412void basic_string::assign(const char* str, fl::size len) {
413 mLength = len;
414 if (len + 1 <= mInlineCapacity) {
415 if (!isInline()) {
416 mStorage.reset();
417 }
418 fl::memcpy(inlineBufferPtr(), str, len);
419 inlineBufferPtr()[len] = '\0';
420 } else {
422 }
423}
424
426 copy(str);
427 return *this;
428}
429
430basic_string& basic_string::assign(const basic_string& str, fl::size pos, fl::size count) {
431 if (pos >= str.size()) {
432 clear();
433 return *this;
434 }
435 fl::size actualCount = count;
436 if (actualCount == npos || pos + actualCount > str.size()) {
437 actualCount = str.size() - pos;
438 }
439 copy(str.c_str() + pos, actualCount);
440 return *this;
441}
442
443basic_string& basic_string::assign(fl::size count, char c) {
444 if (count == 0) {
445 clear();
446 return *this;
447 }
448 mLength = count;
449 if (count + 1 <= mInlineCapacity) {
450 if (!isInline()) {
451 mStorage.reset();
452 }
453 for (fl::size i = 0; i < count; ++i) {
454 inlineBufferPtr()[i] = c;
455 }
456 inlineBufferPtr()[count] = '\0';
457 } else {
460 for (fl::size i = 0; i < count; ++i) {
461 ptr->data()[i] = c;
462 }
463 ptr->data()[count] = '\0';
464 }
465 return *this;
466}
467
472
473// ======= MEMORY MANAGEMENT =======
474
475void basic_string::reserve(fl::size newCapacity) {
476 if (newCapacity <= mLength) return;
477 if (newCapacity + 1 <= mInlineCapacity) return;
478 if (hasHeapData()) {
479 const NotNullStringHolderPtr& heap = heapData();
480 if (heap.get().use_count() <= 1 && heap->hasCapacity(newCapacity)) {
481 return;
482 }
483 }
485 fl::memcpy(newData->data(), c_str(), mLength);
486 newData->data()[mLength] = '\0';
487 mStorage = newData;
488}
489
490void basic_string::clear(bool freeMemory) {
491 mLength = 0;
492 if (isNonOwning() || (freeMemory && hasHeapData())) {
493 mStorage.reset();
494 inlineBufferPtr()[0] = '\0';
495 } else {
496 c_str_mutable()[0] = '\0';
497 }
498}
499
501 if (hasHeapData()) {
503 if (heap.get().use_count() > 1) return;
504 if (heap->capacity() <= mLength + 1) return;
505 if (mLength + 1 <= mInlineCapacity) {
506 fl::memcpy(inlineBufferPtr(), heap->data(), mLength + 1);
507 mStorage.reset();
508 return;
509 }
511 fl::memcpy(newData->data(), heap->data(), mLength + 1);
512 mStorage = newData;
513 }
514}
515
516// ======= FIND =======
517
518fl::size basic_string::find(const char& value) const {
519 for (fl::size i = 0; i < mLength; ++i) {
520 if (c_str()[i] == value) return i;
521 }
522 return npos;
523}
524
525fl::size basic_string::find(const char* substr) const {
526 if (!substr) return npos;
527 auto begin_ptr = c_str();
528 const char* found = fl::strstr(begin_ptr, substr);
529 if (found) return found - begin_ptr;
530 return npos;
531}
532
533fl::size basic_string::find(const char& value, fl::size start_pos) const {
534 if (start_pos >= mLength) return npos;
535 for (fl::size i = start_pos; i < mLength; ++i) {
536 if (c_str()[i] == value) return i;
537 }
538 return npos;
539}
540
541fl::size basic_string::find(const char* substr, fl::size start_pos) const {
542 if (!substr || start_pos >= mLength) return npos;
543 auto begin_ptr = c_str() + start_pos;
544 const char* found = fl::strstr(begin_ptr, substr);
545 if (found) return found - c_str();
546 return npos;
547}
548
549fl::size basic_string::find(const basic_string& other) const { return find(other.c_str()); }
550fl::size basic_string::find(const basic_string& other, fl::size start_pos) const { return find(other.c_str(), start_pos); }
551
552// ======= RFIND =======
553
554fl::size basic_string::rfind(char c, fl::size pos) const {
555 if (mLength == 0) return npos;
556 fl::size searchPos = (pos >= mLength || pos == npos) ? (mLength - 1) : pos;
557 const char* str = c_str();
558 for (fl::size i = searchPos + 1; i > 0; --i) {
559 if (str[i - 1] == c) return i - 1;
560 }
561 return npos;
562}
563
564fl::size basic_string::rfind(const char* s, fl::size pos, fl::size count) const {
565 if (!s || count == 0) {
566 if (count == 0) return (pos > mLength) ? mLength : pos;
567 return npos;
568 }
569 if (count > mLength) return npos;
570 fl::size maxStart = mLength - count;
571 fl::size searchStart = (pos >= mLength || pos == npos) ? maxStart : pos;
572 if (searchStart + count > mLength) searchStart = maxStart;
573 const char* str = c_str();
574 for (fl::size i = searchStart + 1; i > 0; --i) {
575 fl::size idx = i - 1;
576 if (idx + count > mLength) continue;
577 bool match = true;
578 for (fl::size j = 0; j < count; ++j) {
579 if (str[idx + j] != s[j]) { match = false; break; }
580 }
581 if (match) return idx;
582 }
583 return npos;
584}
585
586fl::size basic_string::rfind(const char* s, fl::size pos) const {
587 if (!s) return npos;
588 return rfind(s, pos, fl::strlen(s));
589}
590
591fl::size basic_string::rfind(const basic_string& str, fl::size pos) const { return rfind(str.c_str(), pos, str.size()); }
592
593// ======= FIND_FIRST_OF =======
594
595fl::size basic_string::find_first_of(const char* s, fl::size pos, fl::size count) const {
596 if (!s || count == 0) return npos;
597 if (pos >= mLength) return npos;
598 const char* str = c_str();
599 for (fl::size i = pos; i < mLength; ++i) {
600 for (fl::size j = 0; j < count; ++j) {
601 if (str[i] == s[j]) return i;
602 }
603 }
604 return npos;
605}
606
607fl::size basic_string::find_first_of(const char* s, fl::size pos) const {
608 if (!s) return npos;
609 return find_first_of(s, pos, fl::strlen(s));
610}
611
612fl::size basic_string::find_first_of(char c, fl::size pos) const { return find(c, pos); }
613fl::size basic_string::find_first_of(const basic_string& str, fl::size pos) const { return find_first_of(str.c_str(), pos, str.size()); }
614
615// ======= FIND_LAST_OF =======
616
617fl::size basic_string::find_last_of(const char* s, fl::size pos, fl::size count) const {
618 if (!s || count == 0) return npos;
619 if (mLength == 0) return npos;
620 fl::size searchPos = (pos >= mLength || pos == npos) ? (mLength - 1) : pos;
621 const char* str = c_str();
622 for (fl::size i = searchPos + 1; i > 0; --i) {
623 for (fl::size j = 0; j < count; ++j) {
624 if (str[i - 1] == s[j]) return i - 1;
625 }
626 }
627 return npos;
628}
629
630fl::size basic_string::find_last_of(const char* s, fl::size pos) const {
631 if (!s) return npos;
632 return find_last_of(s, pos, fl::strlen(s));
633}
634
635fl::size basic_string::find_last_of(char c, fl::size pos) const { return rfind(c, pos); }
636fl::size basic_string::find_last_of(const basic_string& str, fl::size pos) const { return find_last_of(str.c_str(), pos, str.size()); }
637
638// ======= FIND_FIRST_NOT_OF =======
639
640fl::size basic_string::find_first_not_of(char c, fl::size pos) const {
641 if (pos >= mLength) return npos;
642 const char* str = c_str();
643 for (fl::size i = pos; i < mLength; ++i) {
644 if (str[i] != c) return i;
645 }
646 return npos;
647}
648
649fl::size basic_string::find_first_not_of(const char* s, fl::size pos, fl::size count) const {
650 if (!s || count == 0) return (pos < mLength) ? pos : npos;
651 if (pos >= mLength) return npos;
652 const char* str = c_str();
653 for (fl::size i = pos; i < mLength; ++i) {
654 bool found_in_set = false;
655 for (fl::size j = 0; j < count; ++j) {
656 if (str[i] == s[j]) { found_in_set = true; break; }
657 }
658 if (!found_in_set) return i;
659 }
660 return npos;
661}
662
663fl::size basic_string::find_first_not_of(const char* s, fl::size pos) const {
664 if (!s) return (pos < mLength) ? pos : npos;
665 return find_first_not_of(s, pos, fl::strlen(s));
666}
667
668fl::size basic_string::find_first_not_of(const basic_string& str, fl::size pos) const { return find_first_not_of(str.c_str(), pos, str.size()); }
669
670// ======= FIND_LAST_NOT_OF =======
671
672fl::size basic_string::find_last_not_of(char c, fl::size pos) const {
673 if (mLength == 0) return npos;
674 fl::size searchPos = (pos >= mLength || pos == npos) ? (mLength - 1) : pos;
675 const char* str = c_str();
676 for (fl::size i = searchPos + 1; i > 0; --i) {
677 if (str[i - 1] != c) return i - 1;
678 }
679 return npos;
680}
681
682fl::size basic_string::find_last_not_of(const char* s, fl::size pos, fl::size count) const {
683 if (!s || count == 0) {
684 if (mLength == 0) return npos;
685 fl::size searchPos = (pos >= mLength || pos == npos) ? (mLength - 1) : pos;
686 return searchPos;
687 }
688 if (mLength == 0) return npos;
689 fl::size searchPos = (pos >= mLength || pos == npos) ? (mLength - 1) : pos;
690 const char* str = c_str();
691 for (fl::size i = searchPos + 1; i > 0; --i) {
692 bool found_in_set = false;
693 for (fl::size j = 0; j < count; ++j) {
694 if (str[i - 1] == s[j]) { found_in_set = true; break; }
695 }
696 if (!found_in_set) return i - 1;
697 }
698 return npos;
699}
700
701fl::size basic_string::find_last_not_of(const char* s, fl::size pos) const {
702 if (!s) {
703 if (mLength == 0) return npos;
704 fl::size searchPos = (pos >= mLength || pos == npos) ? (mLength - 1) : pos;
705 return searchPos;
706 }
707 return find_last_not_of(s, pos, fl::strlen(s));
708}
709
710fl::size basic_string::find_last_not_of(const basic_string& str, fl::size pos) const { return find_last_not_of(str.c_str(), pos, str.size()); }
711
712// ======= CONTAINS =======
713
714bool basic_string::contains(const char* substr) const { return find(substr) != npos; }
715bool basic_string::contains(char c) const { return find(c) != npos; }
716bool basic_string::contains(const basic_string& other) const { return find(other.c_str()) != npos; }
717
718// ======= STARTS_WITH / ENDS_WITH =======
719
720bool basic_string::starts_with(const char* prefix) const {
721 if (!prefix) return true;
722 fl::size prefix_len = fl::strlen(prefix);
723 if (prefix_len > mLength) return false;
724 return fl::strncmp(c_str(), prefix, prefix_len) == 0;
725}
726
727bool basic_string::ends_with(const char* suffix) const {
728 if (!suffix) return true;
729 fl::size suffix_len = fl::strlen(suffix);
730 if (suffix_len > mLength) return false;
731 return fl::strncmp(c_str() + mLength - suffix_len, suffix, suffix_len) == 0;
732}
733
734bool basic_string::starts_with(char c) const { return mLength > 0 && c_str()[0] == c; }
735bool basic_string::starts_with(const basic_string& prefix) const { return starts_with(prefix.c_str()); }
736bool basic_string::ends_with(char c) const { return mLength > 0 && c_str()[mLength - 1] == c; }
737bool basic_string::ends_with(const basic_string& suffix) const { return ends_with(suffix.c_str()); }
738
739// ======= STACK OPERATIONS =======
740
741void basic_string::push_back(char c) { write(c); }
742void basic_string::push_ascii(char c) { write(c); }
743
744// ======= POP_BACK =======
745
747 if (mLength > 0) {
748 mLength--;
749 c_str_mutable()[mLength] = '\0';
750 }
751}
752
753// ======= INSERT =======
754
755basic_string& basic_string::insert(fl::size pos, fl::size count, char ch) {
756 if (pos > mLength) pos = mLength;
757 if (count == 0) return *this;
758
759 // Materialize non-owning storage before modifying
760 if (isNonOwning()) {
761 materialize();
762 }
763
764 fl::size newLen = mLength + count;
765
766 // Handle COW
767 if (hasHeapData() && heapData().get().use_count() > 1) {
768 const NotNullStringHolderPtr& heap = heapData();
770 if (pos > 0) fl::memcpy(newData->data(), heap->data(), pos);
771 for (fl::size i = 0; i < count; ++i) newData->data()[pos + i] = ch;
772 if (pos < mLength) fl::memcpy(newData->data() + pos + count, heap->data() + pos, mLength - pos);
773 newData->data()[newLen] = '\0';
774 mStorage = newData;
775 mLength = newLen;
776 return *this;
777 }
778
779 // Inline buffer
780 if (newLen + 1 <= mInlineCapacity && !hasHeapData()) {
781 if (pos < mLength) {
783 }
784 for (fl::size i = 0; i < count; ++i) inlineBufferPtr()[pos + i] = ch;
785 mLength = newLen;
786 inlineBufferPtr()[mLength] = '\0';
787 return *this;
788 }
789
790 // Heap in-place or new allocation
791 bool canInsertInPlace = hasHeapData();
792 if (canInsertInPlace) {
794 canInsertInPlace = heap.get().use_count() <= 1 && heap->hasCapacity(newLen);
795 if (canInsertInPlace) {
796 char* data = heap->data();
797 if (pos < mLength) fl::memmove(data + pos + count, data + pos, mLength - pos);
798 for (fl::size i = 0; i < count; ++i) data[pos + i] = ch;
799 mLength = newLen;
800 data[mLength] = '\0';
801 }
802 }
803 if (!canInsertInPlace) {
805 const char* src = c_str();
806 if (pos > 0) fl::memcpy(newData->data(), src, pos);
807 for (fl::size i = 0; i < count; ++i) newData->data()[pos + i] = ch;
808 if (pos < mLength) fl::memcpy(newData->data() + pos + count, src + pos, mLength - pos);
809 newData->data()[newLen] = '\0';
810 mStorage = newData;
811 mLength = newLen;
812 }
813 return *this;
814}
815
816basic_string& basic_string::insert(fl::size pos, const char* s) {
817 if (!s) return *this;
818 return insert(pos, s, fl::strlen(s));
819}
820
822 return insert(pos, str.c_str(), str.size());
823}
824
825basic_string& basic_string::insert(fl::size pos, const basic_string& str, fl::size pos2, fl::size count) {
826 if (pos2 >= str.size()) return *this;
827 fl::size actualCount = count;
828 if (actualCount == npos || pos2 + actualCount > str.size()) {
829 actualCount = str.size() - pos2;
830 }
831 return insert(pos, str.c_str() + pos2, actualCount);
832}
833
834basic_string& basic_string::insert(fl::size pos, const char* s, fl::size count) {
835 if (pos > mLength) pos = mLength;
836 if (!s || count == 0) return *this;
837
838 // Materialize non-owning storage before modifying
839 if (isNonOwning()) {
840 materialize();
841 }
842
843 fl::size newLen = mLength + count;
844
845 // Handle COW
846 if (hasHeapData() && heapData().get().use_count() > 1) {
847 const NotNullStringHolderPtr& heap = heapData();
849 if (pos > 0) fl::memcpy(newData->data(), heap->data(), pos);
850 fl::memcpy(newData->data() + pos, s, count);
851 if (pos < mLength) fl::memcpy(newData->data() + pos + count, heap->data() + pos, mLength - pos);
852 newData->data()[newLen] = '\0';
853 mStorage = newData;
854 mLength = newLen;
855 return *this;
856 }
857
858 // Inline buffer
859 if (newLen + 1 <= mInlineCapacity && !hasHeapData()) {
860 if (pos < mLength) {
862 }
863 fl::memcpy(inlineBufferPtr() + pos, s, count);
864 mLength = newLen;
865 inlineBufferPtr()[mLength] = '\0';
866 return *this;
867 }
868
869 // Heap in-place or new allocation
870 bool canInsertInPlace = hasHeapData();
871 if (canInsertInPlace) {
873 canInsertInPlace = heap.get().use_count() <= 1 && heap->hasCapacity(newLen);
874 if (canInsertInPlace) {
875 char* data = heap->data();
876 if (pos < mLength) fl::memmove(data + pos + count, data + pos, mLength - pos);
877 fl::memcpy(data + pos, s, count);
878 mLength = newLen;
879 data[mLength] = '\0';
880 }
881 }
882 if (!canInsertInPlace) {
884 const char* src = c_str();
885 if (pos > 0) fl::memcpy(newData->data(), src, pos);
886 fl::memcpy(newData->data() + pos, s, count);
887 if (pos < mLength) fl::memcpy(newData->data() + pos + count, src + pos, mLength - pos);
888 newData->data()[newLen] = '\0';
889 mStorage = newData;
890 mLength = newLen;
891 }
892 return *this;
893}
894
895// ======= ERASE =======
896
897basic_string& basic_string::erase(fl::size pos, fl::size count) {
898 if (pos >= mLength) return *this;
899
900 fl::size actualCount = count;
901 if (actualCount == npos || pos + actualCount > mLength) {
902 actualCount = mLength - pos;
903 }
904 if (actualCount == 0) return *this;
905
906 // Handle COW
907 if (hasHeapData() && heapData().get().use_count() > 1) {
908 const NotNullStringHolderPtr& heap = heapData();
910 if (pos > 0) fl::memcpy(newData->data(), heap->data(), pos);
911 fl::size remainingLen = mLength - pos - actualCount;
912 if (remainingLen > 0) {
913 fl::memcpy(newData->data() + pos, heap->data() + pos + actualCount, remainingLen);
914 }
915 mLength = mLength - actualCount;
916 newData->data()[mLength] = '\0';
917 mStorage = newData;
918 return *this;
919 }
920
921 fl::size remainingLen = mLength - pos - actualCount;
922 if (remainingLen > 0) {
923 char* data = c_str_mutable();
924 fl::memmove(data + pos, data + pos + actualCount, remainingLen);
925 }
926 mLength -= actualCount;
927 c_str_mutable()[mLength] = '\0';
928 return *this;
929}
930
931// ======= REPLACE =======
932
933basic_string& basic_string::replace(fl::size pos, fl::size count, const basic_string& str) {
934 return replace(pos, count, str.c_str(), str.size());
935}
936
937basic_string& basic_string::replace(fl::size pos, fl::size count, const basic_string& str,
938 fl::size pos2, fl::size count2) {
939 if (pos2 >= str.size()) return erase(pos, count);
940 fl::size actualCount2 = count2;
941 if (actualCount2 == npos || pos2 + actualCount2 > str.size()) {
942 actualCount2 = str.size() - pos2;
943 }
944 return replace(pos, count, str.c_str() + pos2, actualCount2);
945}
946
947basic_string& basic_string::replace(fl::size pos, fl::size count, const char* s, fl::size count2) {
948 if (pos > mLength) return *this;
949 if (!s) return erase(pos, count);
950
951 // Materialize non-owning storage before modifying
952 if (isNonOwning()) {
953 materialize();
954 }
955
956 fl::size actualCount = count;
957 if (actualCount == npos || pos + actualCount > mLength) {
958 actualCount = mLength - pos;
959 }
960 fl::size newLen = mLength - actualCount + count2;
961
962 // Handle COW
963 if (hasHeapData() && heapData().get().use_count() > 1) {
964 const NotNullStringHolderPtr& heap = heapData();
966 if (pos > 0) fl::memcpy(newData->data(), heap->data(), pos);
967 fl::memcpy(newData->data() + pos, s, count2);
968 fl::size remainingLen = mLength - pos - actualCount;
969 if (remainingLen > 0) {
970 fl::memcpy(newData->data() + pos + count2, heap->data() + pos + actualCount, remainingLen);
971 }
972 newData->data()[newLen] = '\0';
973 mStorage = newData;
974 mLength = newLen;
975 return *this;
976 }
977
978 // Inline buffer
979 if (newLen + 1 <= mInlineCapacity && !hasHeapData()) {
980 if (count2 != actualCount) {
981 fl::size remainingLen = mLength - pos - actualCount;
982 if (remainingLen > 0) {
983 fl::memmove(inlineBufferPtr() + pos + count2, inlineBufferPtr() + pos + actualCount, remainingLen);
984 }
985 }
986 fl::memcpy(inlineBufferPtr() + pos, s, count2);
987 mLength = newLen;
988 inlineBufferPtr()[mLength] = '\0';
989 return *this;
990 }
991
992 // Heap in-place or new allocation
993 bool canReplaceInPlace = hasHeapData();
994 if (canReplaceInPlace) {
996 canReplaceInPlace = heap.get().use_count() <= 1 && heap->hasCapacity(newLen);
997 if (canReplaceInPlace) {
998 char* data = heap->data();
999 if (count2 != actualCount) {
1000 fl::size remainingLen = mLength - pos - actualCount;
1001 if (remainingLen > 0) {
1002 fl::memmove(data + pos + count2, data + pos + actualCount, remainingLen);
1003 }
1004 }
1005 fl::memcpy(data + pos, s, count2);
1006 mLength = newLen;
1007 data[mLength] = '\0';
1008 }
1009 }
1010 if (!canReplaceInPlace) {
1012 const char* src = c_str();
1013 if (pos > 0) fl::memcpy(newData->data(), src, pos);
1014 fl::memcpy(newData->data() + pos, s, count2);
1015 fl::size remainingLen = mLength - pos - actualCount;
1016 if (remainingLen > 0) {
1017 fl::memcpy(newData->data() + pos + count2, src + pos + actualCount, remainingLen);
1018 }
1019 newData->data()[newLen] = '\0';
1020 mStorage = newData;
1021 mLength = newLen;
1022 }
1023 return *this;
1024}
1025
1026basic_string& basic_string::replace(fl::size pos, fl::size count, const char* s) {
1027 if (!s) return erase(pos, count);
1028 return replace(pos, count, s, fl::strlen(s));
1029}
1030
1031basic_string& basic_string::replace(fl::size pos, fl::size count, fl::size count2, char ch) {
1032 if (pos > mLength) return *this;
1033
1034 // Materialize non-owning storage before modifying
1035 if (isNonOwning()) {
1036 materialize();
1037 }
1038
1039 fl::size actualCount = count;
1040 if (actualCount == npos || pos + actualCount > mLength) {
1041 actualCount = mLength - pos;
1042 }
1043 fl::size newLen = mLength - actualCount + count2;
1044
1045 // Handle COW
1046 if (hasHeapData() && heapData().get().use_count() > 1) {
1047 const NotNullStringHolderPtr& heap = heapData();
1049 if (pos > 0) fl::memcpy(newData->data(), heap->data(), pos);
1050 for (fl::size i = 0; i < count2; ++i) newData->data()[pos + i] = ch;
1051 fl::size remainingLen = mLength - pos - actualCount;
1052 if (remainingLen > 0) {
1053 fl::memcpy(newData->data() + pos + count2, heap->data() + pos + actualCount, remainingLen);
1054 }
1055 newData->data()[newLen] = '\0';
1056 mStorage = newData;
1057 mLength = newLen;
1058 return *this;
1059 }
1060
1061 // Inline buffer
1062 if (newLen + 1 <= mInlineCapacity && !hasHeapData()) {
1063 if (count2 != actualCount) {
1064 fl::size remainingLen = mLength - pos - actualCount;
1065 if (remainingLen > 0) {
1066 fl::memmove(inlineBufferPtr() + pos + count2, inlineBufferPtr() + pos + actualCount, remainingLen);
1067 }
1068 }
1069 for (fl::size i = 0; i < count2; ++i) inlineBufferPtr()[pos + i] = ch;
1070 mLength = newLen;
1071 inlineBufferPtr()[mLength] = '\0';
1072 return *this;
1073 }
1074
1075 // Heap in-place or new allocation
1076 bool canReplaceInPlace = hasHeapData();
1077 if (canReplaceInPlace) {
1079 canReplaceInPlace = heap.get().use_count() <= 1 && heap->hasCapacity(newLen);
1080 if (canReplaceInPlace) {
1081 char* data = heap->data();
1082 if (count2 != actualCount) {
1083 fl::size remainingLen = mLength - pos - actualCount;
1084 if (remainingLen > 0) {
1085 fl::memmove(data + pos + count2, data + pos + actualCount, remainingLen);
1086 }
1087 }
1088 for (fl::size i = 0; i < count2; ++i) data[pos + i] = ch;
1089 mLength = newLen;
1090 data[mLength] = '\0';
1091 }
1092 }
1093 if (!canReplaceInPlace) {
1095 const char* src = c_str();
1096 if (pos > 0) fl::memcpy(newData->data(), src, pos);
1097 for (fl::size i = 0; i < count2; ++i) newData->data()[pos + i] = ch;
1098 fl::size remainingLen = mLength - pos - actualCount;
1099 if (remainingLen > 0) {
1100 fl::memcpy(newData->data() + pos + count2, src + pos + actualCount, remainingLen);
1101 }
1102 newData->data()[newLen] = '\0';
1103 mStorage = newData;
1104 mLength = newLen;
1105 }
1106 return *this;
1107}
1108
1109// ======= COMPARE =======
1110
1111int basic_string::compare(const basic_string& str) const { return fl::strcmp(c_str(), str.c_str()); }
1112
1113int basic_string::compare(fl::size pos1, fl::size count1, const basic_string& str) const {
1114 if (pos1 > mLength) {
1115 return str.empty() ? 0 : -1;
1116 }
1117 fl::size actualCount1 = count1;
1118 if (actualCount1 == npos || pos1 + actualCount1 > mLength) {
1119 actualCount1 = mLength - pos1;
1120 }
1121 fl::size minLen = (actualCount1 < str.size()) ? actualCount1 : str.size();
1122 int result = fl::strncmp(c_str() + pos1, str.c_str(), minLen);
1123 if (result != 0) return result;
1124 if (actualCount1 < str.size()) return -1;
1125 if (actualCount1 > str.size()) return 1;
1126 return 0;
1127}
1128
1129int basic_string::compare(fl::size pos1, fl::size count1, const basic_string& str,
1130 fl::size pos2, fl::size count2) const {
1131 if (pos1 > mLength || pos2 >= str.size()) {
1132 if (pos1 > mLength && pos2 >= str.size()) return 0;
1133 if (pos1 > mLength) return -1;
1134 return 1;
1135 }
1136 fl::size actualCount1 = count1;
1137 if (actualCount1 == npos || pos1 + actualCount1 > mLength) {
1138 actualCount1 = mLength - pos1;
1139 }
1140 fl::size actualCount2 = count2;
1141 if (actualCount2 == npos || pos2 + actualCount2 > str.size()) {
1142 actualCount2 = str.size() - pos2;
1143 }
1144 fl::size minLen = (actualCount1 < actualCount2) ? actualCount1 : actualCount2;
1145 int result = fl::strncmp(c_str() + pos1, str.c_str() + pos2, minLen);
1146 if (result != 0) return result;
1147 if (actualCount1 < actualCount2) return -1;
1148 if (actualCount1 > actualCount2) return 1;
1149 return 0;
1150}
1151
1152int basic_string::compare(const char* s) const {
1153 if (!s) return mLength > 0 ? 1 : 0;
1154 return fl::strcmp(c_str(), s);
1155}
1156
1157int basic_string::compare(fl::size pos1, fl::size count1, const char* s) const {
1158 if (!s) {
1159 if (pos1 >= mLength) return 0;
1160 fl::size actualCount1 = count1;
1161 if (actualCount1 == npos || pos1 + actualCount1 > mLength) {
1162 actualCount1 = mLength - pos1;
1163 }
1164 return (actualCount1 > 0) ? 1 : 0;
1165 }
1166 if (pos1 > mLength) return (s[0] == '\0') ? 0 : -1;
1167 fl::size actualCount1 = count1;
1168 if (actualCount1 == npos || pos1 + actualCount1 > mLength) {
1169 actualCount1 = mLength - pos1;
1170 }
1171 fl::size sLen = fl::strlen(s);
1172 fl::size minLen = (actualCount1 < sLen) ? actualCount1 : sLen;
1173 int result = fl::strncmp(c_str() + pos1, s, minLen);
1174 if (result != 0) return result;
1175 if (actualCount1 < sLen) return -1;
1176 if (actualCount1 > sLen) return 1;
1177 return 0;
1178}
1179
1180int basic_string::compare(fl::size pos1, fl::size count1, const char* s, fl::size count2) const {
1181 if (!s) {
1182 if (pos1 >= mLength) return (count2 == 0) ? 0 : -1;
1183 fl::size actualCount1 = count1;
1184 if (actualCount1 == npos || pos1 + actualCount1 > mLength) {
1185 actualCount1 = mLength - pos1;
1186 }
1187 return (actualCount1 > 0) ? 1 : ((count2 == 0) ? 0 : -1);
1188 }
1189 if (pos1 > mLength) return (count2 == 0) ? 0 : -1;
1190 fl::size actualCount1 = count1;
1191 if (actualCount1 == npos || pos1 + actualCount1 > mLength) {
1192 actualCount1 = mLength - pos1;
1193 }
1194 fl::size minLen = (actualCount1 < count2) ? actualCount1 : count2;
1195 int result = fl::strncmp(c_str() + pos1, s, minLen);
1196 if (result != 0) return result;
1197 if (actualCount1 < count2) return -1;
1198 if (actualCount1 > count2) return 1;
1199 return 0;
1200}
1201
1202// ======= PROTECTED: MOVE / SWAP / FACTORY HELPERS =======
1203
1205 if (other.isInline()) {
1206 mLength = other.mLength;
1207 fl::memcpy(inlineBufferPtr(), other.inlineBufferPtr(), other.mLength + 1);
1208 // mStorage is already empty (inline mode) from constructor
1209 } else {
1210 mLength = other.mLength;
1211 mStorage = fl::move(other.mStorage);
1212 }
1213 other.mLength = 0;
1214 other.mStorage.reset();
1215 other.inlineBufferPtr()[0] = '\0';
1216}
1217
1219 if (this == &other) return;
1220 if (other.isInline()) {
1221 mLength = other.mLength;
1222 mStorage.reset();
1223 fl::memcpy(inlineBufferPtr(), other.inlineBufferPtr(), other.mLength + 1);
1224 } else {
1225 mLength = other.mLength;
1226 mStorage = fl::move(other.mStorage);
1227 }
1228 other.mLength = 0;
1229 other.mStorage.reset();
1230 other.inlineBufferPtr()[0] = '\0';
1231}
1232
1234 if (this == &other) return;
1235
1236 bool thisInline = isInline();
1237 bool otherInline = other.isInline();
1238
1239 if (!thisInline && !otherInline) {
1240 // Both non-inline: swap variant + length
1241 fl::swap(mStorage, other.mStorage);
1242 fl::swap(mLength, other.mLength);
1243 } else if (thisInline && otherInline) {
1244 // Both inline: check capacity before swapping
1245 bool thisFits = other.mLength + 1 <= mInlineCapacity;
1246 bool otherFits = mLength + 1 <= other.mInlineCapacity;
1247 if (thisFits && otherFits) {
1248 // Both fit: swap buffer contents directly
1249 fl::size maxLen = fl::max(mLength, other.mLength);
1250 for (fl::size i = 0; i <= maxLen; ++i) {
1251 char tmp = inlineBufferPtr()[i];
1252 inlineBufferPtr()[i] = other.inlineBufferPtr()[i];
1253 other.inlineBufferPtr()[i] = tmp;
1254 }
1255 fl::swap(mLength, other.mLength);
1256 } else {
1257 // Capacity mismatch: promote to heap where needed
1258 NotNullStringHolderPtr thisData(
1260 NotNullStringHolderPtr otherData(
1262 fl::size thisLen = mLength;
1263 fl::size otherLen = other.mLength;
1264 if (thisFits) {
1265 mStorage.reset();
1266 fl::memcpy(inlineBufferPtr(), otherData->data(), otherLen + 1);
1267 } else {
1268 mStorage = otherData;
1269 }
1270 mLength = otherLen;
1271 if (otherFits) {
1272 other.mStorage.reset();
1273 fl::memcpy(other.inlineBufferPtr(), thisData->data(), thisLen + 1);
1274 } else {
1275 other.mStorage = thisData;
1276 }
1277 other.mLength = thisLen;
1278 }
1279 } else if (thisInline) {
1280 // this inline, other non-inline
1281 fl::size thisLen = mLength;
1282 // Take other's non-inline storage
1283 mStorage = fl::move(other.mStorage);
1284 mLength = other.mLength;
1285 // Put this's old inline data into other
1286 other.mStorage.reset();
1287 if (thisLen + 1 <= other.mInlineCapacity) {
1288 fl::memcpy(other.inlineBufferPtr(), inlineBufferPtr(), thisLen + 1);
1289 } else {
1292 }
1293 other.mLength = thisLen;
1294 } else {
1295 // this non-inline, other inline — reverse
1296 other.swapWith(*this);
1297 }
1298}
1299
1300void basic_string::setLiteral(const char* literal) {
1301 if (literal) {
1302 mLength = fl::strlen(literal);
1303 mStorage = ConstLiteral(literal);
1304 }
1305}
1306
1307void basic_string::setView(const char* data, fl::size len) {
1308 if (data && len > 0) {
1309 mLength = len;
1310 mStorage = ConstView(data, len);
1311 }
1312}
1313
1315 if (!holder || holder->length() == 0) return;
1316 mLength = holder->length();
1318}
1319
1320// ======= APPEND =======
1321
1323 write(str, fl::strlen(str));
1324 return *this;
1325}
1326
1327basic_string& basic_string::append(const char* str, fl::size len) {
1328 write(str, len);
1329 return *this;
1330}
1331
1333 write(&c, 1);
1334 return *this;
1335}
1336
1338 write(val);
1339 return *this;
1340}
1341
1343 write(static_cast<fl::u16>(val));
1344 return *this;
1345}
1346
1348 if (val) {
1349 write("true", 4);
1350 } else {
1351 write("false", 5);
1352 }
1353 return *this;
1354}
1355
1357 write(static_cast<fl::i32>(val));
1358 return *this;
1359}
1360
1362 write(val);
1363 return *this;
1364}
1365
1367 write(val);
1368 return *this;
1369}
1370
1372 write(val);
1373 return *this;
1374}
1375
1377 write(val);
1378 return *this;
1379}
1380
1382 write(val);
1383 return *this;
1384}
1385
1387 char buf[64] = {0};
1388 fl::ftoa(val, buf, 2);
1389 write(buf, fl::strlen(buf));
1390 return *this;
1391}
1392
1393basic_string& basic_string::append(const float& val, int precision) {
1394 char buf[64] = {0};
1395 fl::ftoa(val, buf, precision);
1396 write(buf, fl::strlen(buf));
1397 return *this;
1398}
1399
1401 return append(static_cast<float>(val));
1402}
1403
1405 write(str.c_str(), str.size());
1406 return *this;
1407}
1408
1409// ======= HEX/OCT APPEND =======
1410
1411basic_string& basic_string::appendHex(i32 val) { char b[64]={0}; int l=fl::itoa(val,b,16); write(b,l); return *this; }
1412basic_string& basic_string::appendHex(u32 val) { char b[64]={0}; int l=fl::utoa32(val,b,16); write(b,l); return *this; }
1413basic_string& basic_string::appendHex(i64 val) { char b[64]={0}; int l=fl::itoa64(val,b,16); write(b,l); return *this; }
1414basic_string& basic_string::appendHex(u64 val) { char b[64]={0}; int l=fl::utoa64(val,b,16); write(b,l); return *this; }
1415basic_string& basic_string::appendHex(i16 val) { return appendHex(static_cast<i32>(val)); }
1416basic_string& basic_string::appendHex(u16 val) { return appendHex(static_cast<u32>(val)); }
1417basic_string& basic_string::appendHex(i8 val) { return appendHex(static_cast<i32>(val)); }
1418basic_string& basic_string::appendHex(u8 val) { return appendHex(static_cast<u32>(val)); }
1419
1420basic_string& basic_string::appendOct(i32 val) { char b[64]={0}; int l=fl::itoa(val,b,8); write(b,l); return *this; }
1421basic_string& basic_string::appendOct(u32 val) { char b[64]={0}; int l=fl::utoa32(val,b,8); write(b,l); return *this; }
1422basic_string& basic_string::appendOct(i64 val) { char b[64]={0}; int l=fl::itoa64(val,b,8); write(b,l); return *this; }
1423basic_string& basic_string::appendOct(u64 val) { char b[64]={0}; int l=fl::utoa64(val,b,8); write(b,l); return *this; }
1424basic_string& basic_string::appendOct(i16 val) { return appendOct(static_cast<i32>(val)); }
1425basic_string& basic_string::appendOct(u16 val) { return appendOct(static_cast<u32>(val)); }
1426basic_string& basic_string::appendOct(i8 val) { return appendOct(static_cast<i32>(val)); }
1427basic_string& basic_string::appendOct(u8 val) { return appendOct(static_cast<u32>(val)); }
1428
1429// ======= OTHER =======
1430
1432
1433// ======= RESIZE =======
1434
1435void basic_string::resize(fl::size count) { resize(count, char()); }
1436
1437void basic_string::resize(fl::size count, char ch) {
1438 if (count < mLength) {
1439 mLength = count;
1440 c_str_mutable()[mLength] = '\0';
1441 } else if (count > mLength) {
1442 fl::size additional_chars = count - mLength;
1443 reserve(count);
1444 char* data_ptr = c_str_mutable();
1445 for (fl::size i = 0; i < additional_chars; ++i) {
1446 data_ptr[mLength + i] = ch;
1447 }
1448 mLength = count;
1449 data_ptr[mLength] = '\0';
1450 }
1451}
1452
1453} // namespace fl
uint8_t pos
Definition Blur.ino:11
Concrete type-erased string class operating on a caller- provided buffer (or fl::span<char>).
bool operator==(const basic_string &other) const FL_NOEXCEPT
basic_string & erase(fl::size pos=0, fl::size count=npos) FL_NOEXCEPT
~basic_string() FL_NOEXCEPT
fl::size find_last_of(char c, fl::size pos=npos) const FL_NOEXCEPT
bool operator>=(const basic_string &other) const FL_NOEXCEPT
void pop_back() FL_NOEXCEPT
bool isNonOwning() const FL_NOEXCEPT
char front() const FL_NOEXCEPT
bool isInline() const FL_NOEXCEPT
bool operator<=(const basic_string &other) const FL_NOEXCEPT
float toFloat() const FL_NOEXCEPT
fl::size write(const fl::u8 *data, fl::size n) FL_NOEXCEPT
bool hasHeapData() const FL_NOEXCEPT
void reserve(fl::size newCapacity) FL_NOEXCEPT
char & at(fl::size pos) FL_NOEXCEPT
bool empty() const FL_NOEXCEPT
void swapWith(basic_string &other) FL_NOEXCEPT
bool operator<(const basic_string &other) const FL_NOEXCEPT
void materialize() FL_NOEXCEPT
void copy(const char *str) FL_NOEXCEPT
fl::size find_first_not_of(char c, fl::size pos=0) const FL_NOEXCEPT
void resize(fl::size count) FL_NOEXCEPT
void push_ascii(char c) FL_NOEXCEPT
fl::size mInlineCapacity
fl::size find_last_not_of(char c, fl::size pos=npos) const FL_NOEXCEPT
void clear(bool freeMemory=false) FL_NOEXCEPT
void assign(const char *str, fl::size len) FL_NOEXCEPT
NotNullStringHolderPtr & heapData() FL_NOEXCEPT
static constexpr fl::size npos
bool starts_with(const char *prefix) const FL_NOEXCEPT
void shrink_to_fit() FL_NOEXCEPT
fl::size find(const char &value) const FL_NOEXCEPT
basic_string & replace(fl::size pos, fl::size count, const basic_string &str) FL_NOEXCEPT
basic_string & insert(fl::size pos, fl::size count, char ch) FL_NOEXCEPT
const char * data() const FL_NOEXCEPT
fl::variant< NotNullStringHolderPtr, ConstLiteral, ConstView > mStorage
char * c_str_mutable() FL_NOEXCEPT
char back() const FL_NOEXCEPT
void setView(const char *data, fl::size len) FL_NOEXCEPT
char * inlineBufferPtr() FL_NOEXCEPT
basic_string & append(const char *str) FL_NOEXCEPT
basic_string & appendHex(i32 val) FL_NOEXCEPT
basic_string(char *inlineBuffer, fl::size inlineCapacity) FL_NOEXCEPT
bool contains(const char *substr) const FL_NOEXCEPT
int compare(const basic_string &str) const FL_NOEXCEPT
void moveFrom(basic_string &&other) FL_NOEXCEPT
char charAt(fl::size index) const FL_NOEXCEPT
fl::size find_first_of(char c, fl::size pos=0) const FL_NOEXCEPT
void setLiteral(const char *literal) FL_NOEXCEPT
void push_back(char c) FL_NOEXCEPT
fl::size capacity() const FL_NOEXCEPT
bool operator!=(const basic_string &other) const FL_NOEXCEPT
void setSharedHolder(const fl::shared_ptr< StringHolder > &holder) FL_NOEXCEPT
const char * constData() const FL_NOEXCEPT
const char * c_str() const FL_NOEXCEPT
void moveAssign(basic_string &&other) FL_NOEXCEPT
char operator[](fl::size index) const FL_NOEXCEPT
fl::size rfind(char c, fl::size pos=npos) const FL_NOEXCEPT
bool operator>(const basic_string &other) const FL_NOEXCEPT
fl::size size() const FL_NOEXCEPT
basic_string & appendOct(i32 val) FL_NOEXCEPT
bool ends_with(const char *suffix) const FL_NOEXCEPT
Concrete type-erased string class.
constexpr const T & get() const FL_NOEXCEPT
Definition not_null.h:223
long use_count() const FL_NOEXCEPT
Definition shared_ptr.h:342
const char * mData
constexpr string_view() FL_NOEXCEPT
Definition string_view.h:39
fl::UISlider offset("Offset", 0.0f, 0.0f, 1.0f, 0.01f)
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
Definition s16x16x4.h:28
void swap(T &a, T &b) FL_NOEXCEPT
Definition s16x16x4.h:877
unsigned char u8
Definition s16x16x4.h:132
signed char i8
Definition s16x16x4.h:131
void * memcpy(void *dest, const void *src, size_t n) FL_NOEXCEPT
int strncmp(const char *s1, const char *s2, size_t n) FL_NOEXCEPT
unsigned char u8
Definition stdint.h:131
constexpr int type_rank< T >::value
constexpr common_type_t< T, U > max(T a, U b) FL_NOEXCEPT
Definition math.h:75
int itoa(i32 value, char *sp, int radix)
Convert signed 32-bit integer to string buffer in given radix.
fl::not_null< StringHolderPtr > NotNullStringHolderPtr
size_t strlen(const char *s) FL_NOEXCEPT
int utoa64(u64 value, char *sp, int radix)
Convert unsigned 64-bit integer to string buffer in given radix.
int utoa32(u32 value, char *sp, int radix)
Convert unsigned 32-bit integer to string buffer in given radix.
const char * strstr(const char *haystack, const char *needle) FL_NOEXCEPT
fl::i64 i64
Definition s16x16x4.h:222
int itoa64(i64 value, char *sp, int radix)
Convert signed 64-bit integer to string buffer in given radix.
void * memmove(void *dest, const void *src, size_t n) FL_NOEXCEPT
shared_ptr< T > make_shared(Args &&... args) FL_NOEXCEPT
Definition shared_ptr.h:414
expected< T, E > result
Alias for expected (Rust-style naming)
Definition result.h:31
signed char i8
Definition stdint.h:130
float parseFloat(const char *str, fl::size len)
Parse a floating point number from a character buffer.
To * bit_cast_ptr(void *storage) FL_NOEXCEPT
Definition bit_cast.h:60
pair_element< I, T1, T2 >::type & get(pair< T1, T2 > &p) FL_NOEXCEPT
Definition pair.h:115
fl::u64 u64
Definition s16x16x4.h:221
void ftoa(float value, char *buffer, int precision)
Convert floating point number to string buffer.
int strcmp(const char *s1, const char *s2) FL_NOEXCEPT
Base definition for an LED controller.
Definition crgb.hpp:179
#define FL_DISABLE_WARNING(warning)
#define FL_DISABLE_WARNING_PUSH
#define FL_DISABLE_WARNING_POP
#define FL_NOEXCEPT