FastLED 3.9.3
Loading...
Searching...
No Matches
str.h
1#pragma once
2
3#include <string.h>
4#include <stdint.h>
5
6#include "ref.h"
7#include "template_magic.h"
8#include "namespace.h"
9
10#ifndef FASTLED_STR_INLINED_SIZE
11#define FASTLED_STR_INLINED_SIZE 64
12#endif
13
14FASTLED_NAMESPACE_BEGIN
15
16template <size_t N> class StrN;
17
18// A copy on write string class. Fast to copy from another
19// Str object as read only pointers are shared. If the size
20// of the string is below FASTLED_STR_INLINED_SIZE then the
21// the entire string fits in the object and no heap allocation occurs.
22// When the string is large enough it will overflow into heap
23// allocated memory. Copy on write means that if the Str has
24// a heap buffer that is shared with another Str object, then
25// a copy is made and then modified in place.
26// If write() or append() is called then the internal data structure
27// will grow to accomodate the new data with extra space for future,
28// like a vector.
29class Str;
30
32// Implementation details.
33
34FASTLED_SMART_REF(StringHolder);
35
37 public:
38 static void append(int val, StrN<64> *dst);
39};
40
41class StringHolder : public Referent {
42 public:
43 StringHolder(const char *str);
44 StringHolder(size_t length);
46 bool isShared() const { return ref_count() > 1; }
47 void grow(size_t newLength);
48 bool hasCapacity(size_t newLength) const { return newLength <= mCapacity; }
49 const char *data() const { return mData; }
50 char *data() { return mData; }
51 size_t length() const { return mLength; }
52 size_t capacity() const { return mCapacity; }
53 bool copy(const char *str, size_t len) {
54 if ((len+1) > mCapacity) {
55 return false;
56 }
57 memcpy(mData, str, len);
58 mData[len] = '\0';
59 mLength = len;
60 return true;
61 }
62
63 private:
64 char *mData = nullptr;
65 size_t mLength = 0;
66 size_t mCapacity = 0;
67};
68
69template <size_t SIZE = 64> class StrN {
70 private:
71 size_t mLength = 0;
72 char mInlineData[SIZE] = {0};
73 StringHolderRef mHeapData;
74
75 public:
76 // Constructors
77 StrN() = default;
78
79 // cppcheck-suppress-begin [operatorEqVarError]
80 template <size_t M> StrN(const StrN<M> &other) { copy(other); }
81 StrN(const char *str) {
82 size_t len = strlen(str);
83 mLength = len;
84 if (len + 1 <= SIZE) {
85 memcpy(mInlineData, str, len + 1);
86 mHeapData.reset();
87 } else {
88 mHeapData = StringHolderRef::New(str);
89 }
90 }
91 StrN(const StrN &other) { copy(other); }
92 void copy(const char *str) {
93 size_t len = strlen(str);
94 mLength = len;
95 if (len + 1 <= SIZE) {
96 memcpy(mInlineData, str, len + 1);
97 mHeapData.reset();
98 } else {
99 if (mHeapData && !mHeapData->isShared()) {
100 // We are the sole owners of this data so we can modify it
101 mHeapData->copy(str, len);
102 return;
103 }
104 mHeapData.reset();
105 mHeapData = StringHolderRef::New(str);
106 }
107 }
108 StrN &operator=(const StrN &other) {
109 copy(other);
110 return *this;
111 }
112 template <size_t M> StrN &operator=(const StrN<M> &other) {
113 copy(other);
114 return *this;
115 }
116 // cppcheck-suppress-end
117
118 bool operator==(const StrN &other) const {
119 return strcmp(c_str(), other.c_str()) == 0;
120 }
121
122 bool operator!=(const StrN &other) const {
123 return strcmp(c_str(), other.c_str()) != 0;
124 }
125
126 template <size_t M> void copy(const StrN<M> &other) {
127 size_t len = other.size();
128 if (len + 1 <= SIZE) {
129 memcpy(mInlineData, other.c_str(), len + 1);
130 mHeapData.reset();
131 } else {
132 if (other.mHeapData) {
133 mHeapData = other.mHeapData;
134 } else {
135 mHeapData = StringHolderRef::New(other.c_str());
136 }
137 }
138 mLength = len;
139 }
140
141 size_t write(int n) {
142 StrN<64> dst;
143 StringFormatter::append(n, &dst); // Inlined size should suffice
144 return write(dst.c_str(), dst.size());
145 }
146
147 size_t write(const uint8_t *data, size_t n) {
148 const char *str = reinterpret_cast<const char *>(data);
149 return write(str, n);
150 }
151
152 size_t write(const char *str, size_t n) {
153 size_t newLen = mLength + n;
154 if (newLen + 1 <= SIZE) {
155 memcpy(mInlineData + mLength, str, n);
156 mLength = newLen;
157 mInlineData[mLength] = '\0';
158 return mLength;
159 }
160 if (mHeapData && !mHeapData->isShared()) {
161 if (!mHeapData->hasCapacity(newLen)) {
162 mHeapData->grow(newLen * 3 / 2); // Grow by 50%
163 }
164 memcpy(mHeapData->data() + mLength, str, n);
165 mLength = newLen;
166 mHeapData->data()[mLength] = '\0';
167 return mLength;
168 }
169 mHeapData.reset();
170 StringHolderRef newData = StringHolderRef::New(newLen);
171 if (newData) {
172 memcpy(newData->data(), c_str(), mLength);
173 memcpy(newData->data() + mLength, str, n);
174 newData->data()[newLen] = '\0';
175 mHeapData = newData;
176 mLength = newLen;
177 }
178 mHeapData = newData;
179 return mLength;
180 }
181
182 size_t write(char c) { return write(&c, 1); }
183
184 size_t write(uint8_t c) {
185 const char *str = reinterpret_cast<const char *>(&c);
186 return write(str, 1);
187 }
188
189 // Destructor
190 ~StrN() {}
191
192 // Accessors
193 size_t size() const { return mLength; }
194 size_t length() const { return mLength; }
195 const char *c_str() const {
196 return mHeapData ? mHeapData->data() : mInlineData;
197 }
198
199 char *c_str_mutable() {
200 return mHeapData ? mHeapData->data() : mInlineData;
201 }
202
203 char &operator[](size_t index) {
204 if (index >= mLength) {
205 static char dummy = '\0';
206 return dummy;
207 }
208 return c_str_mutable()[index];
209 }
210
211 const char &operator[](size_t index) const {
212 if (index >= mLength) {
213 static char dummy = '\0';
214 return dummy;
215 }
216 return c_str()[index];
217 }
218
219 // Append method
220 void append(const char *str) { write(str, strlen(str)); }
221
222 bool operator<(const StrN &other) const {
223 return strcmp(c_str(), other.c_str()) < 0;
224 }
225
226 template<size_t M> bool operator<(const StrN<M> &other) const {
227 return strcmp(c_str(), other.c_str()) < 0;
228 }
229
230 private:
231 StringHolderRef mData;
232};
233
234class Str : public StrN<FASTLED_STR_INLINED_SIZE> {
235 public:
237 Str(const char *str) : StrN<FASTLED_STR_INLINED_SIZE>(str) {}
238 Str(const Str &other) : StrN<FASTLED_STR_INLINED_SIZE>(other) {}
239 template <size_t M>
240 Str(const StrN<M> &other) : StrN<FASTLED_STR_INLINED_SIZE>(other) {}
241 Str &operator=(const Str &other) {
242 copy(other);
243 return *this;
244 }
245};
246
247// Make compatible with std::ostream and other ostream-like objects
248FASTLED_DEFINE_OUTPUT_OPERATOR(Str) {
249 os << obj.c_str();
250 return os;
251}
252
253FASTLED_NAMESPACE_END
Definition str.h:234
Definition str.h:69