FastLED 3.9.15
Loading...
Searching...
No Matches
str.h
Go to the documentation of this file.
1#pragma once
2
3#include <stdint.h>
4#include <string.h>
5
6#include "fl/geometry.h"
7#include "fl/math_macros.h"
8#include "fl/namespace.h"
9#include "fl/ptr.h"
10#include "fl/template_magic.h"
11#include "fl/vector.h"
12
13#ifndef FASTLED_STR_INLINED_SIZE
14#define FASTLED_STR_INLINED_SIZE 64
15#endif
16
18struct CRGB;
20
21namespace fl { // Mandatory namespace for this class since it has name
22 // collisions.
23
24class Str;
25using string = fl::Str; // std-like string
26
27template <typename T> struct rect;
28template <typename T> struct vec2;
29template <typename T> struct vec3;
30template <typename T> class Slice;
31template <typename T, typename Allocator> class HeapVector;
32template <typename T, size_t N> class InlinedVector;
33template <typename T, size_t N> class FixedVector;
34template <size_t N> class StrN;
35
36template <typename T> struct Hash;
37
38template <typename T> struct EqualTo;
39
40template <typename Key, typename Hash, typename KeyEqual> class HashSet;
41
42class XYMap;
43
44struct FFTBins;
45
46// A copy on write string class. Fast to copy from another
47// Str object as read only pointers are shared. If the size
48// of the string is below FASTLED_STR_INLINED_SIZE then the
49// the entire string fits in the object and no heap allocation occurs.
50// When the string is large enough it will overflow into heap
51// allocated memory. Copy on write means that if the Str has
52// a heap buffer that is shared with another Str object, then
53// a copy is made and then modified in place.
54// If write() or append() is called then the internal data structure
55// will grow to accomodate the new data with extra space for future,
56// like a vector.
57class Str;
58
60// Implementation details.
61
63
65 public:
66 static void append(int32_t val, StrN<64> *dst);
67 static bool isSpace(char c) {
68 return c == ' ' || c == '\t' || c == '\n' || c == '\r';
69 }
70 static float parseFloat(const char *str, size_t len);
71 static bool isDigit(char c) { return c >= '0' && c <= '9'; }
72 static void appendFloat(const float &val, StrN<64> *dst);
73};
74
75class StringHolder : public fl::Referent {
76 public:
77 StringHolder(const char *str);
78 StringHolder(size_t length);
79 StringHolder(const char *str, size_t length);
80 StringHolder(const StringHolder &other) = delete;
81 StringHolder &operator=(const StringHolder &other) = delete;
83
84 bool isShared() const { return ref_count() > 1; }
85 void grow(size_t newLength);
86 bool hasCapacity(size_t newLength) const { return newLength <= mCapacity; }
87 const char *data() const { return mData; }
88 char *data() { return mData; }
89 size_t length() const { return mLength; }
90 size_t capacity() const { return mCapacity; }
91 bool copy(const char *str, size_t len) {
92 if ((len + 1) > mCapacity) {
93 return false;
94 }
95 memcpy(mData, str, len);
96 mData[len] = '\0';
97 mLength = len;
98 return true;
99 }
100
101 private:
102 char *mData = nullptr;
103 size_t mLength = 0;
104 size_t mCapacity = 0;
105};
106
107template <size_t SIZE = 64> class StrN {
108 protected:
109 size_t mLength = 0;
110 char mInlineData[SIZE] = {0};
111 StringHolderPtr mHeapData;
112
113 public:
114 // Constructors
115 StrN() = default;
116
117 // cppcheck-suppress-begin [operatorEqVarError]
118 template <size_t M> StrN(const StrN<M> &other) { copy(other); }
119 StrN(const char *str) {
120 size_t len = strlen(str);
121 mLength = len; // Length is without null terminator
122 if (len + 1 <= SIZE) { // Check capacity including null
123 memcpy(mInlineData, str, len + 1); // Copy including null
124 mHeapData.reset();
125 } else {
126 mHeapData = StringHolderPtr::New(str);
127 }
128 }
129 StrN(const StrN &other) { copy(other); }
130 void copy(const char *str) {
131 size_t len = strlen(str);
132 mLength = len;
133 if (len + 1 <= SIZE) {
134 memcpy(mInlineData, str, len + 1);
135 mHeapData.reset();
136 } else {
137 if (mHeapData && !mHeapData->isShared()) {
138 // We are the sole owners of this data so we can modify it
139 mHeapData->copy(str, len);
140 return;
141 }
142 mHeapData.reset();
143 mHeapData = StringHolderPtr::New(str);
144 }
145 }
146
147 template <int N> StrN(const char (&str)[N]) {
148 copy(str, N - 1); // Subtract 1 to not count null terminator
149 }
150 template <int N> StrN &operator=(const char (&str)[N]) {
151 assign(str, N);
152 return *this;
153 }
154 StrN &operator=(const StrN &other) {
155 copy(other);
156 return *this;
157 }
158 template <size_t M> StrN &operator=(const StrN<M> &other) {
159 copy(other);
160 return *this;
161 }
162 // cppcheck-suppress-end
163
164 bool operator==(const StrN &other) const {
165 return strcmp(c_str(), other.c_str()) == 0;
166 }
167
168 bool operator!=(const StrN &other) const {
169 return strcmp(c_str(), other.c_str()) != 0;
170 }
171
172 void copy(const char *str, size_t len) {
173 mLength = len;
174 if (len + 1 <= SIZE) {
175 memcpy(mInlineData, str, len + 1);
176 mHeapData.reset();
177 } else {
178 mHeapData = StringHolderPtr::New(str, len);
179 }
180 }
181
182 template <size_t M> void copy(const StrN<M> &other) {
183 size_t len = other.size();
184 if (len + 1 <= SIZE) {
185 memcpy(mInlineData, other.c_str(), len + 1);
186 mHeapData.reset();
187 } else {
188 if (other.mHeapData) {
189 mHeapData = other.mHeapData;
190 } else {
191 mHeapData = StringHolderPtr::New(other.c_str());
192 }
193 }
194 mLength = len;
195 }
196
197 size_t capacity() const { return mHeapData ? mHeapData->capacity() : SIZE; }
198
199 size_t write(const uint8_t *data, size_t n) {
200 const char *str = reinterpret_cast<const char *>(data);
201 return write(str, n);
202 }
203
204 size_t write(const char *str, size_t n) {
205 size_t newLen = mLength + n;
206 if (mHeapData && !mHeapData->isShared()) {
207 if (!mHeapData->hasCapacity(newLen)) {
208 size_t grow_length = MAX(3, newLen * 3 / 2);
209 mHeapData->grow(grow_length); // Grow by 50%
210 }
211 memcpy(mHeapData->data() + mLength, str, n);
212 mLength = newLen;
213 mHeapData->data()[mLength] = '\0';
214 return mLength;
215 }
216 if (newLen + 1 <= SIZE) {
217 memcpy(mInlineData + mLength, str, n);
218 mLength = newLen;
219 mInlineData[mLength] = '\0';
220 return mLength;
221 }
222 mHeapData.reset();
223 StringHolderPtr newData = StringHolderPtr::New(newLen);
224 if (newData) {
225 memcpy(newData->data(), c_str(), mLength);
226 memcpy(newData->data() + mLength, str, n);
227 newData->data()[newLen] = '\0';
228 mHeapData = newData;
229 mLength = newLen;
230 }
231 mHeapData = newData;
232 return mLength;
233 }
234
235 size_t write(char c) { return write(&c, 1); }
236
237 size_t write(uint8_t c) {
238 const char *str = reinterpret_cast<const char *>(&c);
239 return write(str, 1);
240 }
241
242 size_t write(const uint16_t &n) {
243 StrN<64> dst;
244 StringFormatter::append(n, &dst); // Inlined size should suffice
245 return write(dst.c_str(), dst.size());
246 }
247
248 size_t write(const uint32_t &val) {
249 StrN<64> dst;
250 StringFormatter::append(val, &dst); // Inlined size should suffice
251 return write(dst.c_str(), dst.size());
252 }
253
254 size_t write(const int32_t &val) {
255 StrN<64> dst;
256 StringFormatter::append(val, &dst); // Inlined size should suffice
257 return write(dst.c_str(), dst.size());
258 }
259
260 size_t write(const int8_t val) {
261 StrN<64> dst;
262 StringFormatter::append(int16_t(val),
263 &dst); // Inlined size should suffice
264 return write(dst.c_str(), dst.size());
265 }
266
267 // Destructor
268 ~StrN() {}
269
270 // Accessors
271 size_t size() const { return mLength; }
272 size_t length() const { return size(); }
273 const char *c_str() const {
274 return mHeapData ? mHeapData->data() : mInlineData;
275 }
276
278 return mHeapData ? mHeapData->data() : mInlineData;
279 }
280
281 char &operator[](size_t index) {
282 if (index >= mLength) {
283 static char dummy = '\0';
284 return dummy;
285 }
286 return c_str_mutable()[index];
287 }
288
289 const char &operator[](size_t index) const {
290 if (index >= mLength) {
291 static char dummy = '\0';
292 return dummy;
293 }
294 return c_str()[index];
295 }
296
297 bool empty() const { return mLength == 0; }
298
299 // Append method
300
301 bool operator<(const StrN &other) const {
302 return strcmp(c_str(), other.c_str()) < 0;
303 }
304
305 template <size_t M> bool operator<(const StrN<M> &other) const {
306 return strcmp(c_str(), other.c_str()) < 0;
307 }
308
309 void reserve(size_t newCapacity) {
310 // If capacity is less than current length, do nothing
311 if (newCapacity <= mLength) {
312 return;
313 }
314
315 // If new capacity fits in inline buffer, no need to allocate
316 if (newCapacity + 1 <= SIZE) {
317 return;
318 }
319
320 // If we already have unshared heap data with sufficient capacity, do
321 // nothing
322 if (mHeapData && !mHeapData->isShared() &&
323 mHeapData->hasCapacity(newCapacity)) {
324 return;
325 }
326
327 // Need to allocate new storage
328 StringHolderPtr newData = StringHolderPtr::New(newCapacity);
329 if (newData) {
330 // Copy existing content
331 memcpy(newData->data(), c_str(), mLength);
332 newData->data()[mLength] = '\0';
333 mHeapData = newData;
334 }
335 }
336
337 void clear(bool freeMemory = false) {
338 mLength = 0;
339 if (freeMemory && mHeapData) {
340 mHeapData.reset();
341 }
342 }
343
344 int16_t find(const char &value) const {
345 for (size_t i = 0; i < mLength; ++i) {
346 if (c_str()[i] == value) {
347 return i;
348 }
349 }
350 return -1;
351 }
352
353 StrN substring(size_t start, size_t end) const {
354 if (start >= mLength) {
355 return StrN();
356 }
357 if (end > mLength) {
358 end = mLength;
359 }
360 if (start >= end) {
361 return StrN();
362 }
363 StrN out;
364 out.copy(c_str() + start, end - start);
365 return out;
366 }
367
368 StrN trim() const {
369 StrN out;
370 size_t start = 0;
371 size_t end = mLength;
372 while (start < mLength && StringFormatter::isSpace(c_str()[start])) {
373 start++;
374 }
375 while (end > start && StringFormatter::isSpace(c_str()[end - 1])) {
376 end--;
377 }
378 return substring(start, end);
379 }
380
381 float toFloat() const {
383 }
384
385 private:
386 StringHolderPtr mData;
387};
388
389class Str : public StrN<FASTLED_STR_INLINED_SIZE> {
390 public:
391 Str() : StrN<FASTLED_STR_INLINED_SIZE>() {}
392 Str(const char *str) : StrN<FASTLED_STR_INLINED_SIZE>(str) {}
393 Str(const Str &other) : StrN<FASTLED_STR_INLINED_SIZE>(other) {}
394 template <size_t M>
395 Str(const StrN<M> &other) : StrN<FASTLED_STR_INLINED_SIZE>(other) {}
396 Str &operator=(const Str &other) {
397 copy(other);
398 return *this;
399 }
400
401 bool operator>(const Str &other) const {
402 return strcmp(c_str(), other.c_str()) > 0;
403 }
404
405 bool operator>=(const Str &other) const {
406 return strcmp(c_str(), other.c_str()) >= 0;
407 }
408
409 bool operator<(const Str &other) const {
410 return strcmp(c_str(), other.c_str()) < 0;
411 }
412
413 bool operator<=(const Str &other) const {
414 return strcmp(c_str(), other.c_str()) <= 0;
415 }
416
417 bool operator==(const Str &other) const {
418 return strcmp(c_str(), other.c_str()) == 0;
419 }
420
421 bool operator!=(const Str &other) const {
422 return strcmp(c_str(), other.c_str()) != 0;
423 }
424
425 Str &operator+=(const Str &other) {
426 append(other.c_str(), other.size());
427 return *this;
428 }
429
430 template <typename T> Str &operator+=(const T &val) {
431 append(val);
432 return *this;
433 }
434
435 // Generic integral append: only enabled if T is an integral type. This is
436 // needed because on some platforms type(int) is not one of the integral
437 // types like int8_t, int16_t, int32_t, int64_t etc. In such a has just case
438 // the value to int32_t and then append it.
439 template <typename T, typename = fl::enable_if_t<fl::is_integral<T>::value>>
440 Str &append(const T &val) {
441 write(int32_t(val));
442 return *this;
443 }
444
445 template <typename T> Str &append(const Slice<T> &slice) {
446 append("[");
447 for (size_t i = 0; i < slice.size(); ++i) {
448 if (i > 0) {
449 append(", ");
450 }
451 append(slice[i]);
452 }
453 append("]");
454 return *this;
455 }
456
457 template <typename T> Str &append(const fl::HeapVector<T> &vec) {
458 Slice<const T> slice(vec.data(), vec.size());
459 append(slice);
460 return *this;
461 }
462
463 template <typename T, size_t N>
465 Slice<const T> slice(vec.data(), vec.size());
466 append(slice);
467 return *this;
468 }
469
470 Str &append(const char *str) {
471 write(str, strlen(str));
472 return *this;
473 }
474 Str &append(const char *str, size_t len) {
475 write(str, len);
476 return *this;
477 }
478 // Str& append(char c) { write(&c, 1); return *this; }
479 Str &append(const int8_t &c) {
480 const char *str = reinterpret_cast<const char *>(&c);
481 write(str, 1);
482 return *this;
483 }
484 Str &append(const uint8_t &c) {
485 write(uint16_t(c));
486 return *this;
487 }
488 Str &append(const uint16_t &val) {
489 write(val);
490 return *this;
491 }
492 Str &append(const int16_t &val) {
493 write(int32_t(val));
494 return *this;
495 }
496 Str &append(const uint32_t &val) {
497 write(val);
498 return *this;
499 }
500 Str &append(const int32_t &c) {
501 write(c);
502 return *this;
503 }
504
505 Str &append(const bool &val) {
506 if (val) {
507 return append("true");
508 } else {
509 return append("false");
510 }
511 }
512
513 template <typename T> Str &append(const rect<T> &rect) {
514 append(rect.mMin.x);
515 append(",");
516 append(rect.mMin.y);
517 append(",");
518 append(rect.mMax.x);
519 append(",");
520 append(rect.mMax.y);
521 return *this;
522 }
523
524 template <typename T> Str &append(const vec2<T> &pt) {
525 append("(");
526 append(pt.x);
527 append(",");
528 append(pt.y);
529 append(")");
530 return *this;
531 }
532
533 template <typename T> Str &append(const vec3<T> &pt) {
534 append("(");
535 append(pt.x);
536 append(",");
537 append(pt.y);
538 append(",");
539 append(pt.z);
540 append(")");
541 return *this;
542 }
543
544
545 template <typename T, size_t N>
547 Slice<const T> slice(vec.data(), vec.size());
548 append(slice);
549 return *this;
550 }
551
552 Str &append(const CRGB &c);
553
554 Str &append(const float &_val) {
555 // round to nearest hundredth
557 return *this;
558 }
559
560 Str &append(const double &val) { return append(float(val)); }
561
562 Str &append(const StrN &str) {
563 write(str.c_str(), str.size());
564 return *this;
565 }
566
567 Str &append(const FFTBins &str);
568
569 Str &append(const XYMap &map);
570
571 template <typename Key, typename Hash, typename KeyEqual>
573 append("{");
574 for (auto it = set.begin(); it != set.end(); ++it) {
575 if (it != set.begin()) {
576 append(", ");
577 }
578 auto p = *it;
579 append(p.first);
580 }
581 append("}");
582 return *this;
583 }
584
585 const char *data() const { return c_str(); }
586
587 void swap(Str &other);
588
589 private:
590 enum {
591 // Bake the size into the string class so we can issue a compile time
592 // check
593 // to make sure the user doesn't do something funny like try to change
594 // the
595 // size of the inlined string via an included defined instead of a build
596 // define.
597 kStrInlineSize = FASTLED_STR_INLINED_SIZE,
598 };
599
600 static void compileTimeAssertions();
601};
602
603} // namespace fl
constexpr size_t size() const
Definition vector.h:134
iterator data()
Definition vector.h:267
iterator end()
Definition hash_map.h:177
iterator begin()
Definition hash_map.h:176
size_t size() const
Definition vector.h:486
size_t size() const
Definition vector.h:912
virtual int ref_count() const
Definition ptr.cpp:11
size_t size() const
Definition slice.h:92
static void compileTimeAssertions()
Definition str.cpp:256
@ kStrInlineSize
Definition str.h:597
Str & append(const uint32_t &val)
Definition str.h:496
Str & append(const Slice< T > &slice)
Definition str.h:445
Str & append(const int8_t &c)
Definition str.h:479
Str & append(const fl::FixedVector< T, N > &vec)
Definition str.h:546
Str(const char *str)
Definition str.h:392
bool operator==(const Str &other) const
Definition str.h:417
Str & append(const uint8_t &c)
Definition str.h:484
Str & operator+=(const Str &other)
Definition str.h:425
Str & append(const char *str, size_t len)
Definition str.h:474
Str & append(const fl::InlinedVector< T, N > &vec)
Definition str.h:464
Str & append(const fl::HeapVector< T > &vec)
Definition str.h:457
bool operator!=(const Str &other) const
Definition str.h:421
Str & append(const bool &val)
Definition str.h:505
Str & append(const float &_val)
Definition str.h:554
bool operator<(const Str &other) const
Definition str.h:409
void swap(Str &other)
Definition str.cpp:245
Str & append(const vec3< T > &pt)
Definition str.h:533
Str(const StrN< M > &other)
Definition str.h:395
Str & append(const T &val)
Definition str.h:440
Str & append(const uint16_t &val)
Definition str.h:488
Str & append(const int32_t &c)
Definition str.h:500
Str & operator+=(const T &val)
Definition str.h:430
bool operator>(const Str &other) const
Definition str.h:401
Str & append(const char *str)
Definition str.h:470
Str & append(const int16_t &val)
Definition str.h:492
Str(const Str &other)
Definition str.h:393
bool operator<=(const Str &other) const
Definition str.h:413
bool operator>=(const Str &other) const
Definition str.h:405
Str & append(const StrN &str)
Definition str.h:562
Str & append(const HashSet< Key, Hash, KeyEqual > &set)
Definition str.h:572
Str & append(const vec2< T > &pt)
Definition str.h:524
const char * data() const
Definition str.h:585
Str()
Definition str.h:391
Str & operator=(const Str &other)
Definition str.h:396
Str & append(const double &val)
Definition str.h:560
Str & append(const rect< T > &rect)
Definition str.h:513
Definition str.h:389
StrN & operator=(const StrN &other)
Definition str.h:154
StrN & operator=(const StrN< M > &other)
Definition str.h:158
size_t mLength
Definition str.h:109
StrN substring(size_t start, size_t end) const
Definition str.h:353
void copy(const StrN< M > &other)
Definition str.h:182
StrN(const StrN &other)
Definition str.h:129
bool operator<(const StrN &other) const
Definition str.h:301
char & operator[](size_t index)
Definition str.h:281
bool empty() const
Definition str.h:297
StrN & operator=(const char(&str)[N])
Definition str.h:150
char * c_str_mutable()
Definition str.h:277
size_t write(const uint8_t *data, size_t n)
Definition str.h:199
StringHolderPtr mData
Definition str.h:386
void copy(const char *str, size_t len)
Definition str.h:172
size_t write(const uint16_t &n)
Definition str.h:242
~StrN()
Definition str.h:268
size_t write(const int8_t val)
Definition str.h:260
int16_t find(const char &value) const
Definition str.h:344
bool operator!=(const StrN &other) const
Definition str.h:168
size_t write(char c)
Definition str.h:235
const char * c_str() const
Definition str.h:273
StrN(const char *str)
Definition str.h:119
void clear(bool freeMemory=false)
Definition str.h:337
size_t length() const
Definition str.h:272
size_t size() const
Definition str.h:271
StringHolderPtr mHeapData
Definition str.h:111
StrN(const char(&str)[N])
Definition str.h:147
StrN(const StrN< M > &other)
Definition str.h:118
const char & operator[](size_t index) const
Definition str.h:289
StrN trim() const
Definition str.h:368
void copy(const char *str)
Definition str.h:130
size_t write(uint8_t c)
Definition str.h:237
size_t write(const int32_t &val)
Definition str.h:254
char mInlineData[SIZE]
Definition str.h:110
size_t write(const uint32_t &val)
Definition str.h:248
bool operator==(const StrN &other) const
Definition str.h:164
void reserve(size_t newCapacity)
Definition str.h:309
float toFloat() const
Definition str.h:381
StrN()=default
size_t write(const char *str, size_t n)
Definition str.h:204
bool operator<(const StrN< M > &other) const
Definition str.h:305
size_t capacity() const
Definition str.h:197
static float parseFloat(const char *str, size_t len)
Definition str.cpp:222
static bool isSpace(char c)
Definition str.h:67
static void appendFloat(const float &val, StrN< 64 > *dst)
Definition str.cpp:275
static void append(int32_t val, StrN< 64 > *dst)
Definition str.cpp:156
static bool isDigit(char c)
Definition str.h:71
char * mData
Definition str.h:102
StringHolder(const StringHolder &other)=delete
bool hasCapacity(size_t newLength) const
Definition str.h:86
bool copy(const char *str, size_t len)
Definition str.h:91
size_t capacity() const
Definition str.h:90
StringHolder(const char *str)
Definition str.cpp:161
const char * data() const
Definition str.h:87
size_t length() const
Definition str.h:89
bool isShared() const
Definition str.h:84
size_t mLength
Definition str.h:103
size_t mCapacity
Definition str.h:104
StringHolder & operator=(const StringHolder &other)=delete
char * data()
Definition str.h:88
void grow(size_t newLength)
Definition str.cpp:195
#define MAX(a, b)
Definition math_macros.h:11
#define FASTLED_NAMESPACE_END
Definition namespace.h:23
Implements the FastLED namespace macros.
fl::Str string
Definition str.h:25
constexpr T * end(T(&array)[N]) noexcept
Implements a simple red square effect for 2D LED grids.
Definition crgb.h:16
static FASTLED_NAMESPACE_BEGIN uint8_t const p[]
Definition noise.cpp:30
#define FASTLED_SMART_PTR(type)
Definition ptr.h:31
Representation of an RGB pixel (Red, Green, Blue)
Definition crgb.h:55
vec2< T > mMax
Definition geometry.h:400
vec2< T > mMin
Definition geometry.h:399