FastLED 3.9.15
Loading...
Searching...
No Matches
string.h
Go to the documentation of this file.
1#pragma once
2
4// fl::string has inlined memory and copy on write semantics.
5
6
8#include "fl/stl/int.h"
9#include "fl/stl/cstring.h"
11#include "platforms/is_platform.h" // IWYU pragma: keep (for FL_IS_WASM)
12
13#ifdef FL_IS_WASM
14// IWYU pragma: begin_keep
15#include <string>
16// IWYU pragma: end_keep
17#endif
18
19#include "fl/stl/shared_ptr.h"
20#include "fl/stl/optional.h"
21#include "fl/stl/type_traits.h"
22#include "fl/stl/span.h"
23#include "fl/stl/vector.h" // IWYU pragma: keep
24#include "fl/stl/variant.h"
25#include "fl/stl/string_view.h"
27#include "fl/stl/bitset.h"
28#include "fl/stl/move.h"
29#include "fl/stl/noexcept.h"
30
31#ifndef FASTLED_STR_INLINED_SIZE
32#define FASTLED_STR_INLINED_SIZE 64
33#endif
34
35
36// Test for Arduino String class (must be after includes)
37#if defined(String_class_h)
38#define FL_STRING_NEEDS_ARDUINO_CONVERSION 1
39#else
40#define FL_STRING_NEEDS_ARDUINO_CONVERSION 0
41#endif
42
43#if FL_STRING_NEEDS_ARDUINO_CONVERSION
44class String; // Arduino String class
45#endif
46
47namespace fl {
48
49class Tile2x2_u8_wrap;
50class JsonUiInternal;
51
52struct json_value;
53class json;
54
55template <typename T> struct rect;
56template <typename T> struct vec2;
57template <typename T> struct vec3;
58
59template <typename T> class WeakPtr;
60
61template <typename Key, typename Hash, typename KeyEqual> class HashSet;
62
63class XYMap;
64
65namespace audio { namespace fft { class Bins; } }
66struct CRGB;
67
68} // namespace fl
69
70namespace fl {
71
72// `fl::string_n<N>` is the templated inline-buffer storage policy
73// over `fl::basic_string`. It co-locates a `char[N]` buffer with
74// the basic_string state and passes that buffer to the base ctor.
75// Every operation (write, append, find, replace, …) lives in
76// `basic_string` and is compiled exactly once; per-N instantiations
77// of `string_n<N>` are thin constructor stubs that only differ in
78// the literal `N` they hand to the base. The compiler / linker
79// folds identical instantiations under COMDAT, and the non-shared
80// bytes are tiny (each ctor is `: basic_string(mBuf, N) {}` plus a
81// short body that calls `copy()`/`setLiteral()`/etc.).
82//
83// Convenience aliases:
84// - `fl::string_small` — 32-byte inline buffer (constrained MCUs)
85// - `fl::string` — `FASTLED_STR_INLINED_SIZE` (default 64)
86// - `fl::string_large` — 256-byte inline buffer (text-heavy paths)
87//
88// All three are layout-compatible; copy/move between sizes works
89// because the underlying `basic_string` storage policy is uniform.
90//
91// See `agents/docs/string-architecture.md`.
92template <fl::size N>
93class string_n : public basic_string {
94 protected:
95 char mInlineBuffer[N] = {0};
96
97 public:
98 // Default + content-population constructors. All delegate to
99 // `basic_string(mInlineBuffer, N)` and then call the
100 // non-template population helpers on the base.
102
104 if (str) copy(str);
105 }
106
107 string_n(const char* str, fl::size len) FL_NOEXCEPT : basic_string(mInlineBuffer, N) {
108 copy(str, len);
109 }
110
111 string_n(fl::size len, char c) FL_NOEXCEPT : basic_string(mInlineBuffer, N) {
112 resize(len, c);
113 }
114
116 copy(static_cast<const basic_string&>(other));
117 }
118
119 template <fl::size M>
121 copy(static_cast<const basic_string&>(other));
122 }
123
127
129 copy(other);
130 }
131
133 if (!sv.empty()) {
134 copy(sv.data(), sv.size());
135 }
136 }
137
139 copy(s.data(), s.size());
140 }
141
143 copy(s.data(), s.size());
144 }
145
149
150 template <typename InputIt>
151 string_n(InputIt first, InputIt last) FL_NOEXCEPT : basic_string(mInlineBuffer, N) {
152 assign(first, last);
153 }
154
155 template <int M>
156 string_n(const char (&str)[M]) FL_NOEXCEPT : basic_string(mInlineBuffer, N) {
157 copy(str, M - 1);
158 }
159
161 copy(static_cast<const basic_string&>(other));
162 return *this;
163 }
164
165 template <fl::size M>
167 copy(static_cast<const basic_string&>(other));
168 return *this;
169 }
170
172 moveAssign(fl::move(other));
173 return *this;
174 }
175};
176
177// Convenience aliases. `fl::string` is the default; `string_small`
178// trades inline capacity for object size on constrained targets,
179// `string_large` trades the other way for text-heavy paths.
182
183// `fl::string` extends `string_n<FASTLED_STR_INLINED_SIZE>` with
184// the composite-type formatter overloads (CRGB, vec2, span,
185// vector, optional, …), the `substring()` / `trim()` family
186// (returning `string` so callers chain naturally), and the static
187// factory + comparison methods. The trampoline pattern is:
188//
189// fl::string -> fl::string_n<N> -> fl::basic_string
190//
191// where only `basic_string` carries the real bytes; the upper
192// layers are thin wrappers that get folded out by the optimizer.
193class string : public string_n<FASTLED_STR_INLINED_SIZE> {
194 public:
195 static constexpr fl::size npos = static_cast<fl::size>(-1);
196
197 using basic_string::copy;
202
203 // ======= STATIC FACTORY METHODS =======
204 static string from_literal(const char* literal) FL_NOEXCEPT;
205 static string from_view(const char* data, fl::size len) FL_NOEXCEPT;
206 static string from_view(const string_view& sv) FL_NOEXCEPT;
207 static string interned(const char* str, fl::size len) FL_NOEXCEPT;
208 static string interned(const char* str) FL_NOEXCEPT;
209 static string interned(const string_view& sv) FL_NOEXCEPT;
210 static string copy_no_view(const string& str) FL_NOEXCEPT;
211 static int strcmp(const string& a, const string& b) FL_NOEXCEPT;
212
213 // ======= CONSTRUCTORS =======
214 // All non-template ctors delegate to string_n<N>'s ctors —
215 // defined in string.cpp.hpp as one-line forwarders for header
216 // hygiene. Template ctors stay inline (they're parameterised
217 // on caller types and can't be split out).
219 string(const char* str) FL_NOEXCEPT;
220 string(const char* str, fl::size len) FL_NOEXCEPT;
221 string(fl::size len, char c) FL_NOEXCEPT;
222 string(const string& other) FL_NOEXCEPT;
223 string(string&& other) FL_NOEXCEPT;
224 string(const basic_string& other) FL_NOEXCEPT;
225 string(const string_view& sv) FL_NOEXCEPT;
226 string(const fl::span<const char>& s) FL_NOEXCEPT;
227 string(const fl::span<char>& s) FL_NOEXCEPT;
228 string(const fl::shared_ptr<StringHolder>& holder) FL_NOEXCEPT;
229 template <typename InputIt>
230 string(InputIt first, InputIt last) FL_NOEXCEPT
231 : string_n<FASTLED_STR_INLINED_SIZE>(first, last) {}
232 template <int N>
233 string(const char (&str)[N]) FL_NOEXCEPT
235
236 // ======= ASSIGNMENT =======
237 string& operator=(const string& other) FL_NOEXCEPT;
238 string& operator=(string&& other) FL_NOEXCEPT;
239 string& operator=(const char* str) FL_NOEXCEPT;
240 template <int N> string& operator=(const char (&str)[N]) FL_NOEXCEPT {
241 assign(str, N - 1);
242 return *this;
243 }
244
245 string& assign(string_view sv) FL_NOEXCEPT;
246
247 // ======= SUBSTRING (returns string, so must live here) =======
248 string substring(fl::size start, fl::size end) const FL_NOEXCEPT;
249 string substr(fl::size start, fl::size length) const FL_NOEXCEPT;
250 string substr(fl::size start) const FL_NOEXCEPT;
251 string trim() const FL_NOEXCEPT;
252
253#ifdef FL_IS_WASM
254 string(const std::string& str); // okay std namespace; defined in string.cpp.hpp
255 string& operator=(const std::string& str) FL_NOEXCEPT; // okay std namespace
256 string& append(const std::string& str); // okay std namespace
257#endif
258
259#if FL_STRING_NEEDS_ARDUINO_CONVERSION
260 string(const ::String& str);
261 string& operator=(const ::String& str) FL_NOEXCEPT;
262 string& append(const ::String& str);
263#endif
264
265
266
267 bool operator>(const string &other) const FL_NOEXCEPT;
268 bool operator>=(const string &other) const FL_NOEXCEPT;
269 bool operator<(const string &other) const FL_NOEXCEPT;
270 bool operator<=(const string &other) const FL_NOEXCEPT;
271 bool operator==(const string &other) const FL_NOEXCEPT;
272 bool operator!=(const string &other) const FL_NOEXCEPT;
273
274 // ======= CONCATENATION =======
275 string& operator+=(const string& other) FL_NOEXCEPT;
276
277 template <typename T> string& operator+=(const T& val) FL_NOEXCEPT {
278 append(val);
279 return *this;
280 }
281
282 // ======= APPEND OVERLOADS =======
283 template <fl::u32 N>
284 string& append(const bitset_fixed<N>& bs) FL_NOEXCEPT {
285 bs.to_string(this);
286 return *this;
287 }
288
289 string& append(const bitset_dynamic& bs) FL_NOEXCEPT {
290 bs.to_string(this);
291 return *this;
292 }
293
294 template <fl::u32 N>
296 bs.to_string(this);
297 return *this;
298 }
299
300 template <typename T> string& append(const fl::span<T>& slice) FL_NOEXCEPT {
301 append("[");
302 for (fl::size i = 0; i < slice.size(); ++i) {
303 if (i > 0) append(", ");
304 append(slice[i]);
305 }
306 append("]");
307 return *this;
308 }
309
310 template <typename T> string& append(const fl::vector<T>& vec) FL_NOEXCEPT {
311 fl::span<const T> slice(vec.data(), vec.size());
312 append(slice);
313 return *this;
314 }
315
316 template <typename T, fl::size N>
318 fl::span<const T> slice(vec.data(), vec.size());
319 append(slice);
320 return *this;
321 }
322
323 template <typename T>
324 string& append(const rect<T>& rect) FL_NOEXCEPT {
325 append("rect(");
326 append(rect.mMin.x);
327 append(",");
328 append(rect.mMin.y);
329 append(",");
330 append(rect.mMax.x);
331 append(",");
332 append(rect.mMax.y);
333 append(")");
334 return *this;
335 }
336
337 template <typename T>
338 string& append(const vec2<T>& pt) FL_NOEXCEPT {
339 append("vec2(");
340 append(pt.x);
341 append(",");
342 append(pt.y);
343 append(")");
344 return *this;
345 }
346
347 template <typename T>
348 string& append(const vec3<T>& pt) FL_NOEXCEPT {
349 append("vec3(");
350 append(pt.x);
351 append(",");
352 append(pt.y);
353 append(",");
354 append(pt.z);
355 append(")");
356 return *this;
357 }
358
359 template <typename T>
360 string& append(const WeakPtr<T>& val) FL_NOEXCEPT {
361 write("WeakPtr(use_count=", 18);
362 write(static_cast<fl::u32>(val.use_count()));
363 write(")", 1);
364 return *this;
365 }
366
367 template <typename T>
369 if (!val) {
370 write("nullptr", 7);
371 } else {
372 write("shared_ptr(use_count=", 21);
373 write(static_cast<fl::u32>(val.use_count()));
374 write(")", 1);
375 }
376 return *this;
377 }
378
379 string& append(const JsonUiInternal& val) FL_NOEXCEPT;
380 string& append(const json_value& val) FL_NOEXCEPT;
381 string& append(const json& val) FL_NOEXCEPT;
382
383 template <typename T, fl::size N>
385 append("[");
386 for (fl::size i = 0; i < vec.size(); ++i) {
387 if (i > 0) append(",");
388 append(vec[i]);
389 }
390 append("]");
391 return *this;
392 }
393
394 string& append(const CRGB& c) FL_NOEXCEPT;
395 string& appendCRGB(const CRGB& c) FL_NOEXCEPT;
396
397 // Any type with a to_float() method (e.g., fixed_point types)
398 template <typename T>
399 typename fl::enable_if<
400 fl::is_same<decltype(static_cast<const T*>(nullptr)->to_float()), float>::value
402 string&>::type
403 append(const T& val) FL_NOEXCEPT {
404 basic_string::append(val.to_float());
405 return *this;
406 }
407
408 string& append(const audio::fft::Bins& str) FL_NOEXCEPT;
409 string& append(const XYMap& map) FL_NOEXCEPT;
410 string& append(const Tile2x2_u8_wrap& tile) FL_NOEXCEPT;
411
412 template <typename Key, typename Hash, typename KeyEqual>
414 append("{");
415 fl::size i = 0;
416 for (auto it = set.begin(); it != set.end(); ++it) {
417 if (i > 0) append(",");
418 append(*it);
419 ++i;
420 }
421 append("}");
422 return *this;
423 }
424
425 template <typename T>
426 string& append(const fl::optional<T>& opt) FL_NOEXCEPT {
427 if (opt.has_value()) {
428 append(opt.value());
429 } else {
430 write("nullopt", 7);
431 }
432 return *this;
433 }
434
435 void swap(string& other) FL_NOEXCEPT;
436
437 string& intern() FL_NOEXCEPT;
438
439 private:
440 enum {
442 };
443
445};
446
447// ======= FREE FUNCTIONS =======
448
449template<typename T>
450inline string to_string(T value) FL_NOEXCEPT {
451 string result;
452 result.append(value);
453 return result;
454}
455
456inline string to_string(float value, int precision) FL_NOEXCEPT {
457 string result;
458 result.append(value, precision);
459 return result;
460}
461
462inline string operator+(const char* lhs, const string& rhs) FL_NOEXCEPT {
463 string result(lhs);
464 result += rhs;
465 return result;
466}
467
468inline string operator+(const string& lhs, const char* rhs) FL_NOEXCEPT {
469 string result(lhs);
470 result += rhs;
471 return result;
472}
473
474inline string operator+(const string& lhs, const string& rhs) FL_NOEXCEPT {
475 string result(lhs);
476 result += rhs;
477 return result;
478}
479
480template<typename T>
481inline typename fl::enable_if<!fl::is_arithmetic<T>::value, string>::type
482operator+(const char* lhs, const T& rhs) FL_NOEXCEPT {
483 string result(lhs);
484 result += rhs;
485 return result;
486}
487
488template<typename T>
489inline typename fl::enable_if<!fl::is_arithmetic<T>::value, string>::type
490operator+(const T& lhs, const char* rhs) FL_NOEXCEPT {
491 string result;
492 result.append(lhs);
493 result += rhs;
494 return result;
495}
496
497template<typename T>
498inline string operator+(const string& lhs, const T& rhs) FL_NOEXCEPT {
499 string result(lhs);
500 result += rhs;
501 return result;
502}
503
504template<typename T>
505inline string operator+(const T& lhs, const string& rhs) FL_NOEXCEPT {
506 string result;
507 result.append(lhs);
508 result += rhs;
509 return result;
510}
511
513// Template Implementation for charconv.h
515
516template<typename T>
517fl::string to_hex(T value, bool uppercase, bool pad_to_width) FL_NOEXCEPT {
519 bool is_negative = false;
520 u64 unsigned_value;
521 if (static_cast<i64>(value) < 0 && sizeof(T) <= 8) {
522 is_negative = true;
523 unsigned_value = static_cast<u64>(-static_cast<i64>(value));
524 } else {
525 unsigned_value = static_cast<u64>(value);
526 }
527 return detail::hex(unsigned_value, width, is_negative, uppercase, pad_to_width);
528}
529
530// Comparator that orders strings by size first, then by content.
531// Not lexicographic — use only for associative containers (flat_map, etc.)
532// where you need fast lookup and don't care about alphabetical order.
534 bool operator()(const string &a, const string &b) const FL_NOEXCEPT {
535 fl::size al = a.size(), bl = b.size();
536 if (al != bl) {
537 return al < bl;
538 }
539 return fl::memcmp(a.c_str(), b.c_str(), al) < 0;
540 }
541};
542
543} // namespace fl
AudioAnalyzeFFT1024 fft
Concrete type-erased string class operating on a caller- provided buffer (or fl::span<char>).
fl::size write(const fl::u8 *data, fl::size n) FL_NOEXCEPT
void copy(const char *str) FL_NOEXCEPT
void resize(fl::size count) FL_NOEXCEPT
void assign(const char *str, fl::size len) FL_NOEXCEPT
const char * data() const 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
void moveFrom(basic_string &&other) FL_NOEXCEPT
void setSharedHolder(const fl::shared_ptr< StringHolder > &holder) FL_NOEXCEPT
void moveAssign(basic_string &&other) FL_NOEXCEPT
fl::size size() const FL_NOEXCEPT
basic_string & appendOct(i32 val) FL_NOEXCEPT
Concrete type-erased string class.
A dynamic bitset implementation that can be resized at runtime.
const_iterator begin() const
Definition set.h:415
const_iterator end() const
Definition set.h:416
Definition set.h:367
string_n & operator=(const string_n &other) FL_NOEXCEPT
Definition string.h:160
string_n(const fl::shared_ptr< StringHolder > &holder) FL_NOEXCEPT
Definition string.h:146
string_n(const char *str) FL_NOEXCEPT
Definition string.h:103
string_n(const char(&str)[M]) FL_NOEXCEPT
Definition string.h:156
string_n(const basic_string &other) FL_NOEXCEPT
Definition string.h:128
string_n(string_n &&other) FL_NOEXCEPT
Definition string.h:124
string_n(const fl::span< const char > &s) FL_NOEXCEPT
Definition string.h:138
string_n(const char *str, fl::size len) FL_NOEXCEPT
Definition string.h:107
string_n & operator=(const string_n< M > &other) FL_NOEXCEPT
Definition string.h:166
string_n() FL_NOEXCEPT
Definition string.h:101
string_n(const string_n< M > &other) FL_NOEXCEPT
Definition string.h:120
string_n(fl::size len, char c) FL_NOEXCEPT
Definition string.h:111
string_n(const fl::span< char > &s) FL_NOEXCEPT
Definition string.h:142
string_n(const string_view &sv) FL_NOEXCEPT
Definition string.h:132
string_n(const string_n &other) FL_NOEXCEPT
Definition string.h:115
string_n(InputIt first, InputIt last) FL_NOEXCEPT
Definition string.h:151
string_n & operator=(string_n &&other) FL_NOEXCEPT
Definition string.h:171
char mInlineBuffer[N]
Definition string.h:95
string & append(const bitset_inlined< N > &bs) FL_NOEXCEPT
Definition string.h:295
string substr(fl::size start, fl::size length) const FL_NOEXCEPT
string & append(const fl::span< T > &slice) FL_NOEXCEPT
Definition string.h:300
static string interned(const char *str, fl::size len) FL_NOEXCEPT
string & appendCRGB(const CRGB &c) FL_NOEXCEPT
string trim() const FL_NOEXCEPT
bool operator<=(const string &other) const FL_NOEXCEPT
string & operator+=(const string &other) FL_NOEXCEPT
fl::enable_if< fl::is_same< decltype(static_cast< constT * >(nullptr) ->to_float()), float >::value &&!fl::is_floating_point< T >::value, string & >::type append(const T &val) FL_NOEXCEPT
Definition string.h:403
void swap(string &other) FL_NOEXCEPT
static int strcmp(const string &a, const string &b) FL_NOEXCEPT
bool operator!=(const string &other) const FL_NOEXCEPT
string & assign(string_view sv) FL_NOEXCEPT
@ kStrInlineSize
Definition string.h:441
bool operator==(const string &other) const FL_NOEXCEPT
string & append(const bitset_fixed< N > &bs) FL_NOEXCEPT
Definition string.h:284
string substring(fl::size start, fl::size end) const FL_NOEXCEPT
string & operator=(const string &other) FL_NOEXCEPT
string() FL_NOEXCEPT
bool operator>=(const string &other) const FL_NOEXCEPT
string & append(const fl::shared_ptr< T > &val) FL_NOEXCEPT
Definition string.h:368
string & append(const vec2< T > &pt) FL_NOEXCEPT
Definition string.h:338
string(const char(&str)[N]) FL_NOEXCEPT
Definition string.h:233
string & append(const fl::optional< T > &opt) FL_NOEXCEPT
Definition string.h:426
bool operator<(const string &other) const FL_NOEXCEPT
string & operator=(const char(&str)[N]) FL_NOEXCEPT
Definition string.h:240
string & append(const bitset_dynamic &bs) FL_NOEXCEPT
Definition string.h:289
string & append(const fl::InlinedVector< T, N > &vec) FL_NOEXCEPT
Definition string.h:317
static string copy_no_view(const string &str) FL_NOEXCEPT
string & append(const vec3< T > &pt) FL_NOEXCEPT
Definition string.h:348
static string from_literal(const char *literal) FL_NOEXCEPT
static constexpr fl::size npos
Definition string.h:195
string & append(const fl::vector< T > &vec) FL_NOEXCEPT
Definition string.h:310
string & append(const WeakPtr< T > &val) FL_NOEXCEPT
Definition string.h:360
string & append(const HashSet< Key, Hash, KeyEqual > &set) FL_NOEXCEPT
Definition string.h:413
bool operator>(const string &other) const FL_NOEXCEPT
static string from_view(const char *data, fl::size len) FL_NOEXCEPT
string & append(const fl::FixedVector< T, N > &vec) FL_NOEXCEPT
Definition string.h:384
string & append(const rect< T > &rect) FL_NOEXCEPT
Definition string.h:324
string & operator+=(const T &val) FL_NOEXCEPT
Definition string.h:277
static void compileTimeAssertions() FL_NOEXCEPT
string & intern() FL_NOEXCEPT
fl::UISlider length("Length", 1.0f, 0.0f, 1.0f, 0.01f)
fl::CRGB CRGB
Definition crgb.h:25
fl::string hex(u64 value, HexIntWidth width, bool is_negative, bool uppercase, bool pad_to_width)
Internal hex conversion function (implementation in charconv.cpp)
constexpr HexIntWidth get_hex_int_width() FL_NOEXCEPT
Compile-time integer width determination (default - triggers error)
Definition charconv.h:60
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
Definition s16x16x4.h:28
string to_string(T value) FL_NOEXCEPT
Definition string.h:450
constexpr int type_rank< T >::value
VectorN< T, INLINED_SIZE > InlinedVector
Definition span.h:21
MapRedBlackTree< Key, T, Compare, fl::allocator_slab< char > > map
Definition map.h:283
constexpr T * end(T(&array)[N]) FL_NOEXCEPT
Optional< T > optional
Definition optional.h:16
FASTLED_FORCE_INLINE CRGB operator+(const CRGB &p1, const CRGB &p2) FL_NOEXCEPT
Add one CRGB to another, saturating at 0xFF for each channel.
Definition crgb.hpp:182
int memcmp(const void *s1, const void *s2, size_t n) FL_NOEXCEPT
fl::string to_hex(T value, bool uppercase=false, bool pad_to_width=false) FL_NOEXCEPT
Convert an integer value to hexadecimal string representation.
Definition string.h:517
fl::i64 i64
Definition s16x16x4.h:222
u8 width
Definition blur.h:186
string_n< 256 > string_large
Definition string.h:181
expected< T, E > result
Alias for expected (Rust-style naming)
Definition result.h:31
string_n< 32 > string_small
Definition string.h:180
fl::u64 u64
Definition s16x16x4.h:221
Base definition for an LED controller.
Definition crgb.hpp:179
#define FL_NOEXCEPT
#define FASTLED_STR_INLINED_SIZE
std::string compatible string class.
Definition string.h:32
Representation of an 8-bit RGB pixel (Red, Green, Blue)
Definition crgb.h:38
bool operator()(const string &a, const string &b) const FL_NOEXCEPT
Definition string.h:534
vec2< T > mMax
Definition geometry.h:438
vec2< T > mMin
Definition geometry.h:437