FastLED 3.9.15
Loading...
Searching...
No Matches
string.cpp.hpp
Go to the documentation of this file.
1#include "fl/stl/string.h"
2#include "fl/stl/cstring.h" // For fl::memcpy, fl::strcmp
3#include "fl/stl/string_interner.h" // For global_interner()
4#include "fl/stl/type_traits.h" // for swap
5#include "fl/stl/variant.h" // for variant
6
7#include "fl/audio/fft/fft.h"
8#include "fl/math/geometry.h" // for vec2
9#include "fl/stl/int.h" // for size, u16, u8
10#include "fl/stl/json.h"
11#include "fl/gfx/crgb.h" // for CRGB
12#include "fl/gfx/tile2x2.h"
15#include "fl/math/xymap.h"
16// UI dependency moved to separate compilation unit to break dependency chain
17
18#if FL_STRING_NEEDS_ARDUINO_CONVERSION
19// IWYU pragma: begin_keep
20#include "fl/system/arduino.h"
21#include "fl/stl/noexcept.h"
22// IWYU pragma: end_keep // ok header
23#endif
24
25namespace fl {
26
27// Define static constexpr member for npos (required for ODR-uses)
28const fl::size string::npos;
29
30// ======= STATIC FACTORY METHODS =======
31
32string string::from_literal(const char* literal) FL_NOEXCEPT {
33 string result;
34 result.setLiteral(literal);
35 return result;
36}
37
38string string::from_view(const char* data, fl::size len) FL_NOEXCEPT {
39 string result;
40 result.setView(data, len);
41 return result;
42}
43
45 return from_view(sv.data(), sv.size());
46}
47
48string string::interned(const char* str, fl::size len) FL_NOEXCEPT {
49 if (!str || len == 0) return string();
50 // Route through the global interner so identical content
51 // returns the same shared StringHolder (O(1) average lookup,
52 // matches `string::intern()`'s semantics). Previously this
53 // family wrapped a fresh StringHolder per call with no
54 // deduplication — see #2961 CR thread + the follow-on commit.
55 return global_interner().intern(fl::string_view(str, len));
56}
57
58string string::interned(const char* str) FL_NOEXCEPT {
59 if (!str) return string();
60 return global_interner().intern(str);
61}
62
64 return global_interner().intern(sv);
65}
66
67string string::copy_no_view(const string& str) FL_NOEXCEPT {
68 if (str.is_referencing()) {
69 string result;
70 result.copy(str.c_str(), str.size());
71 return result;
72 }
73 return str;
74}
75
76int string::strcmp(const string& a, const string& b) FL_NOEXCEPT {
77 return fl::strcmp(a.c_str(), b.c_str());
78}
79
80// ======= CONSTRUCTORS =======
81// All forward to string_n<FASTLED_STR_INLINED_SIZE>'s ctors which
82// own the actual initialisation logic. fl::string is just the
83// composite-formatter + factory layer on top.
84
87
90
91string::string(const char* str, fl::size len) FL_NOEXCEPT
93
96
99
102
105
108
111
114
117
118// ======= ASSIGNMENT =======
119
120string& string::operator=(const string& other) FL_NOEXCEPT {
121 copy(static_cast<const basic_string&>(other));
122 return *this;
123}
124
125string& string::operator=(string&& other) FL_NOEXCEPT {
126 moveAssign(fl::move(other));
127 return *this;
128}
129
130string& string::operator=(const char* str) FL_NOEXCEPT {
131 // Match the string(const char*) ctor's contract: nullptr → empty.
132 if (str) {
133 copy(str, fl::strlen(str));
134 } else {
135 clear();
136 }
137 return *this;
138}
139
141 if (sv.empty()) {
142 clear();
143 } else {
144 copy(sv.data(), sv.size());
145 }
146 return *this;
147}
148
149// ======= SUBSTRING =======
150
151string string::substring(fl::size start, fl::size end) const FL_NOEXCEPT {
152 if (start == 0 && end == size()) return *this;
153 if (start >= size()) return string();
154 if (end > size()) end = size();
155 if (start >= end) return string();
156 string out;
157 out.copy(c_str() + start, end - start);
158 return out;
159}
160
161string string::substr(fl::size start, fl::size length) const FL_NOEXCEPT {
162 // Handle `npos` / overflow: when `length == npos` the caller
163 // means "to end of string", and when `length` is large enough
164 // that `start + length` would wrap, we clamp to the end before
165 // the addition can overflow.
166 fl::size end;
167 if (length == npos || length > size() - (start < size() ? start : size())) {
168 end = size();
169 } else {
170 end = start + length;
171 if (end > size()) end = size();
172 }
173 return substring(start, end);
174}
175
176string string::substr(fl::size start) const FL_NOEXCEPT {
177 return substring(start, size());
178}
179
180string string::trim() const FL_NOEXCEPT {
181 fl::size start = 0;
182 fl::size end_pos = size();
183 while (start < size() && fl::isspace(c_str()[start])) start++;
184 while (end_pos > start && fl::isspace(c_str()[end_pos - 1])) end_pos--;
185 return substring(start, end_pos);
186}
187
188#ifdef FL_IS_WASM
189string::string(const std::string& str) // okay std namespace
191 copy(str.c_str(), str.size());
192}
193
194string& string::operator=(const std::string& str) FL_NOEXCEPT { // okay std namespace
195 copy(str.c_str(), str.size());
196 return *this;
197}
198
199string& string::append(const std::string& str) { // okay std namespace
200 write(str.c_str(), str.size());
201 return *this;
202}
203#endif
204
205// ======= COMPARISON OPERATORS =======
206
207// Length-aware lexicographic compare. Doesn't rely on strcmp's
208// NUL-termination, so view-backed strings (`setView`) and any
209// future embedded-NUL content compare correctly. Returns the same
210// sign convention as memcmp / strcmp.
211static inline int string_compare(const string& a, const string& b) FL_NOEXCEPT {
212 fl::size n = (a.size() < b.size()) ? a.size() : b.size();
213 int r = fl::memcmp(a.c_str(), b.c_str(), n);
214 if (r != 0) return r;
215 if (a.size() < b.size()) return -1;
216 if (a.size() > b.size()) return 1;
217 return 0;
218}
219
220bool string::operator>(const string& other) const FL_NOEXCEPT {
221 return string_compare(*this, other) > 0;
222}
223
224bool string::operator>=(const string& other) const FL_NOEXCEPT {
225 return string_compare(*this, other) >= 0;
226}
227
228bool string::operator<(const string& other) const FL_NOEXCEPT {
229 return string_compare(*this, other) < 0;
230}
231
232bool string::operator<=(const string& other) const FL_NOEXCEPT {
233 return string_compare(*this, other) <= 0;
234}
235
236bool string::operator==(const string& other) const FL_NOEXCEPT {
237 if (size() != other.size()) {
238 return false;
239 }
240 return fl::memcmp(c_str(), other.c_str(), size()) == 0;
241}
242
243bool string::operator!=(const string& other) const FL_NOEXCEPT {
244 return !(*this == other);
245}
246
247// ======= CONCATENATION =======
248
249string& string::operator+=(const string& other) FL_NOEXCEPT {
250 append(other.c_str(), other.size());
251 return *this;
252}
253
254string &string::append(const audio::fft::Bins &str) {
255 append("\n Impl Bins:\n ");
256 append(str.raw());
257 append("\n");
258 append(" Impl Bins DB:\n ");
259 append(str.db());
260 append("\n");
261 return *this;
262}
263
264string &string::append(const XYMap &map) {
265 append("XYMap(");
266 append(map.getWidth());
267 append(",");
268 append(map.getHeight());
269 append(")");
270 return *this;
271}
272
273string &string::append(const Tile2x2_u8_wrap &tile) {
275 tile.at(0, 0),
276 tile.at(0, 1),
277 tile.at(1, 0),
278 tile.at(1, 1),
279 };
280
281 append("Tile2x2_u8_wrap(");
282 for (int i = 0; i < 4; i++) {
283 vec2<u16> pos = data[i].first;
284 u8 alpha = data[i].second;
285 append("(");
286 append(pos.x);
287 append(",");
288 append(pos.y);
289 append(",");
290 append(alpha);
291 append(")");
292 if (i < 3) {
293 append(",");
294 }
295 }
296 append(")");
297 return *this;
298}
299
300void string::swap(string &other) {
301 if (this == &other) return;
302 string tmp(fl::move(*this));
303 *this = fl::move(other);
304 other = fl::move(tmp);
305}
306
309 "FASTLED_STR_INLINED_SIZE must be greater than 0");
311 "If you want to change the FASTLED_STR_INLINED_SIZE, then it "
312 "must be through a build define and not an include define.");
313}
314
315string &string::append(const CRGB &rgb) {
316 append("CRGB(");
317 append(rgb.r);
318 append(",");
319 append(rgb.g);
320 append(",");
321 append(rgb.b);
322 append(")");
323 return *this;
324}
325
326string &string::appendCRGB(const CRGB &rgb) {
327 append("CRGB(");
328 append(rgb.r);
329 append(",");
330 append(rgb.g);
331 append(",");
332 append(rgb.b);
333 append(")");
334 return *this;
335}
336
337// JsonUiInternal append implementation moved to str_ui.cpp to break dependency chain
338
339// JSON type append implementations
340// NOTE: These use forward declarations to avoid circular dependency with json.h
341string &string::append(const json_value& val) {
342 // Use the json_value's to_string method if available
343 // For now, just append a placeholder to avoid compilation errors
344 FL_UNUSED(val);
345 append("<json_value>");
346 return *this;
347}
348
349string &string::append(const json& val) {
350 // Use the json's to_string method if available
351 // For now, just append a placeholder to avoid compilation errors
352 //append("<json>");
353 append("json(");
354 append(val.to_string());
355 append(")");
356 return *this;
357}
358
359#if FL_STRING_NEEDS_ARDUINO_CONVERSION
360string::string(const ::String &str)
362 copy(str.c_str(), strlen(str.c_str()));
363}
364
365string &string::operator=(const ::String &str) FL_NOEXCEPT {
366 copy(str.c_str(), strlen(str.c_str()));
367 return *this;
368}
369
370string &string::append(const ::String &str) {
371 write(str.c_str(), strlen(str.c_str()));
372 return *this;
373}
374#endif
375
376// String interning method implementation
377string& string::intern() {
378 // Skip interning if using inline storage (SSO) - already efficient, no heap allocation
379 if (isInline()) {
380 return *this;
381 }
382
383 // Intern via global interner - replaces this string with deduplicated version
384 *this = global_interner().intern(*this);
385 return *this;
386}
387
388} // namespace fl
uint8_t pos
Definition Blur.ino:11
fl::string intern(const string_view &sv)
Entry & at(u16 x, u16 y)
fl::pair< vec2< u16 >, u8 > Entry
Definition tile2x2.h:103
fl::span< const float > db() const FL_NOEXCEPT
Definition fft.cpp.hpp:65
fl::span< const float > raw() const FL_NOEXCEPT
Definition fft.cpp.hpp:63
fl::size length() const FL_NOEXCEPT
bool isInline() const FL_NOEXCEPT
fl::size write(const fl::u8 *data, fl::size n) FL_NOEXCEPT
const char * data() const FL_NOEXCEPT
iterator end() FL_NOEXCEPT
const char * c_str() const FL_NOEXCEPT
void moveAssign(basic_string &&other) FL_NOEXCEPT
fl::size size() const FL_NOEXCEPT
Concrete type-erased string class.
fl::string to_string() const FL_NOEXCEPT
Definition json.h:671
string substr(fl::size start, fl::size length) const FL_NOEXCEPT
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
void swap(string &other) FL_NOEXCEPT
void copy(const char *str) 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
bool operator<(const string &other) const FL_NOEXCEPT
static string copy_no_view(const string &str) FL_NOEXCEPT
static string from_literal(const char *literal) FL_NOEXCEPT
static constexpr fl::size npos
Definition string.h:195
bool operator>(const string &other) const FL_NOEXCEPT
static string from_view(const char *data, fl::size len) FL_NOEXCEPT
static void compileTimeAssertions() FL_NOEXCEPT
string & intern() FL_NOEXCEPT
Defines the 8-bit red, green, and blue (RGB) pixel type in the fl namespace.
FastLED's Elegant JSON Library: fl::json
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
Definition s16x16x4.h:28
unsigned char u8
Definition stdint.h:131
StringInterner & global_interner()
void clear(CRGB(&arr)[N])
Definition clear.h:12
size_t strlen(const char *s) FL_NOEXCEPT
MapRedBlackTree< Key, T, Compare, fl::allocator_slab< char > > map
Definition map.h:283
static int string_compare(const string &a, const string &b) FL_NOEXCEPT
int memcmp(const void *s1, const void *s2, size_t n) FL_NOEXCEPT
expected< T, E > result
Alias for expected (Rust-style naming)
Definition result.h:31
int strcmp(const char *s1, const char *s2) FL_NOEXCEPT
bool isspace(char c) FL_NOEXCEPT
Check if character is whitespace (space, tab, newline, carriage return)
Definition cctype.h:18
Base definition for an LED controller.
Definition crgb.hpp:179
#define FL_STATIC_ASSERT(...)
#define FL_UNUSED(x)
#define FL_NOEXCEPT
Portable compile-time assertion wrapper.
#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