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