79template <
size_t SIZE = 64>
class StrN {
82 char mInlineData[SIZE] = {0};
83 StringHolderPtr mHeapData;
90 template <
size_t M>
StrN(
const StrN<M> &other) { copy(other); }
91 StrN(
const char *str) {
92 size_t len = strlen(str);
94 if (len + 1 <= SIZE) {
95 memcpy(mInlineData, str, len + 1);
98 mHeapData = StringHolderPtr::New(str);
101 StrN(
const StrN &other) { copy(other); }
102 void copy(
const char *str) {
103 size_t len = strlen(str);
105 if (len + 1 <= SIZE) {
106 memcpy(mInlineData, str, len + 1);
109 if (mHeapData && !mHeapData->isShared()) {
111 mHeapData->copy(str, len);
115 mHeapData = StringHolderPtr::New(str);
119 template<
int N>
StrN(
const char (&str)[N]) {
122 template<
int N>
StrN &operator=(
const char (&str)[N]) {
126 StrN &operator=(
const StrN &other) {
130 template <
size_t M>
StrN &operator=(
const StrN<M> &other) {
136 bool operator==(
const StrN &other)
const {
137 return strcmp(c_str(), other.c_str()) == 0;
140 bool operator!=(
const StrN &other)
const {
141 return strcmp(c_str(), other.c_str()) != 0;
144 void copy(
const char* str,
size_t len) {
146 if (len + 1 <= SIZE) {
147 memcpy(mInlineData, str, len + 1);
150 mHeapData = StringHolderPtr::New(str, len);
154 template <
size_t M>
void copy(
const StrN<M> &other) {
155 size_t len = other.size();
156 if (len + 1 <= SIZE) {
157 memcpy(mInlineData, other.c_str(), len + 1);
160 if (other.mHeapData) {
161 mHeapData = other.mHeapData;
163 mHeapData = StringHolderPtr::New(other.c_str());
169 size_t capacity()
const {
170 return mHeapData ? mHeapData->capacity() : SIZE;
174 size_t write(
const uint8_t *data,
size_t n) {
175 const char *str =
reinterpret_cast<const char *
>(data);
176 return write(str, n);
179 size_t write(
const char *str,
size_t n) {
180 size_t newLen = mLength + n;
181 if (mHeapData && !mHeapData->isShared()) {
182 if (!mHeapData->hasCapacity(newLen)) {
183 size_t grow_length = MAX(3, newLen * 3 / 2);
184 mHeapData->grow(grow_length);
186 memcpy(mHeapData->data() + mLength, str, n);
188 mHeapData->data()[mLength] =
'\0';
191 if (newLen + 1 <= SIZE) {
192 memcpy(mInlineData + mLength, str, n);
194 mInlineData[mLength] =
'\0';
198 StringHolderPtr newData = StringHolderPtr::New(newLen);
200 memcpy(newData->data(), c_str(), mLength);
201 memcpy(newData->data() + mLength, str, n);
202 newData->data()[newLen] =
'\0';
210 size_t write(
char c) {
return write(&c, 1); }
212 size_t write(uint8_t c) {
213 const char *str =
reinterpret_cast<const char *
>(&c);
214 return write(str, 1);
217 size_t write(
const uint16_t& n) {
219 StringFormatter::append(n, &dst);
220 return write(dst.c_str(), dst.size());
223 size_t write(
const uint32_t& val) {
225 StringFormatter::append(val, &dst);
226 return write(dst.c_str(), dst.size());
229 size_t write(
const int32_t& val) {
231 StringFormatter::append(val, &dst);
232 return write(dst.c_str(), dst.size());
235 size_t write(
const int8_t val) {
237 StringFormatter::append(int16_t(val), &dst);
238 return write(dst.c_str(), dst.size());
245 size_t size()
const {
return mLength; }
246 size_t length()
const {
return size(); }
247 const char *c_str()
const {
248 return mHeapData ? mHeapData->data() : mInlineData;
251 char *c_str_mutable() {
252 return mHeapData ? mHeapData->data() : mInlineData;
255 char &operator[](
size_t index) {
256 if (index >= mLength) {
257 static char dummy =
'\0';
260 return c_str_mutable()[index];
263 const char &operator[](
size_t index)
const {
264 if (index >= mLength) {
265 static char dummy =
'\0';
268 return c_str()[index];
271 bool empty()
const {
return mLength == 0; }
276 bool operator<(
const StrN &other)
const {
277 return strcmp(c_str(), other.c_str()) < 0;
280 template<
size_t M>
bool operator<(
const StrN<M> &other)
const {
281 return strcmp(c_str(), other.c_str()) < 0;
284 void reserve(
size_t newCapacity) {
286 if (newCapacity <= mLength) {
291 if (newCapacity + 1 <= SIZE) {
296 if (mHeapData && !mHeapData->isShared() && mHeapData->hasCapacity(newCapacity)) {
301 StringHolderPtr newData = StringHolderPtr::New(newCapacity);
304 memcpy(newData->data(), c_str(), mLength);
305 newData->data()[mLength] =
'\0';
310 void clear(
bool freeMemory =
false) {
312 if (freeMemory && mHeapData) {
319 int16_t find(
const char &value)
const {
320 for (
size_t i = 0; i < mLength; ++i) {
321 if (c_str()[i] == value) {
328 StrN substring(
size_t start,
size_t end)
const {
329 if (start >= mLength) {
339 out.copy(c_str() + start, end - start);
348 size_t end = mLength;
349 while (start < mLength && StringFormatter::isSpace(c_str()[start])) {
352 while (end > start && StringFormatter::isSpace(c_str()[end - 1])) {
355 return substring(start, end);
358 float toFloat()
const {
359 return StringFormatter::parseFloat(c_str(), mLength);
365 StringHolderPtr mData;
368class Str :
public StrN<FASTLED_STR_INLINED_SIZE> {
375 Str &operator=(
const Str &other) {
380 bool operator>(
const Str &other)
const {
381 return strcmp(c_str(), other.c_str()) > 0;
384 bool operator>=(
const Str &other)
const {
385 return strcmp(c_str(), other.c_str()) >= 0;
388 bool operator<(
const Str &other)
const {
389 return strcmp(c_str(), other.c_str()) < 0;
392 bool operator<=(
const Str &other)
const {
393 return strcmp(c_str(), other.c_str()) <= 0;
396 bool operator==(
const Str &other)
const {
397 return strcmp(c_str(), other.c_str()) == 0;
400 bool operator!=(
const Str &other)
const {
401 return strcmp(c_str(), other.c_str()) != 0;
404 Str& append(
const char *str) { write(str, strlen(str));
return *
this; }
405 Str& append(
const char *str,
size_t len) { write(str, len);
return *
this; }
407 Str& append(
const int8_t& c) {
408 const char* str =
reinterpret_cast<const char*
>(&c);
409 write(str, 1);
return *
this;
411 Str& append(
const uint8_t& c) { write(uint16_t(c));
return *
this; }
412 Str& append(
const uint16_t& val) { write(val);
return *
this; }
413 Str& append(
const int16_t& val) { write(uint32_t(val));
return *
this; }
414 Str& append(
const uint32_t& val) { write(val);
return *
this; }
415 Str& append(
const int32_t& c) { write(c);
return *
this; }
417 Str& append(
const StrN &str) { write(str.c_str(), str.size());
return *
this; }