FastLED 3.9.15
Loading...
Searching...
No Matches
str.cpp
Go to the documentation of this file.
1#include <stdlib.h>
2
3#include "fl/str.h"
4
5#include "crgb.h"
6#include "fl/fft.h"
7#include "fl/namespace.h"
8#include "fl/unused.h"
9#include "fl/xymap.h"
10
11#ifdef FASTLED_TESTING
12#include <cstdio> // ok include
13#endif
14
15namespace fl {
16
18
19static void ftoa(float value, char *buffer, int precision = 2) {
20
21 FASTLED_UNUSED(precision);
22
23#ifdef FASTLED_TESTING
24 // use sprintf during testing
25 sprintf(buffer, "%f", value);
26 return;
27
28#else
29 // Handle negative values
30 if (value < 0) {
31 *buffer++ = '-';
32 value = -value;
33 }
34
35 // Extract integer part
36 uint32_t intPart = (uint32_t)value;
37
38 // Convert integer part to string (reversed)
39 char intBuf[12]; // Enough for 32-bit integers
40 int i = 0;
41 do {
42 intBuf[i++] = '0' + (intPart % 10);
43 intPart /= 10;
44 } while (intPart);
45
46 // Write integer part in correct order
47 while (i--) {
48 *buffer++ = intBuf[i];
49 }
50
51 *buffer++ = '.'; // Decimal point
52
53 // Extract fractional part
54 float fracPart = value - (uint32_t)value;
55 for (int j = 0; j < precision; ++j) {
56 fracPart *= 10.0f;
57 int digit = (int)fracPart;
58 *buffer++ = '0' + digit;
59 fracPart -= digit;
60 }
61
62 *buffer = '\0'; // Null-terminate
63#endif
64}
65
66static int itoa(int value, char *sp, int radix) {
67 char tmp[16]; // be careful with the length of the buffer
68 char *tp = tmp;
69 int i;
70 unsigned v;
71
72 int sign = (radix == 10 && value < 0);
73 if (sign)
74 v = -value;
75 else
76 v = (unsigned)value;
77
78 while (v || tp == tmp) {
79 i = v % radix;
80 v = radix ? v / radix : 0;
81 if (i < 10)
82 *tp++ = i + '0';
83 else
84 *tp++ = i + 'a' - 10;
85 }
86
87 int len = tp - tmp;
88
89 if (sign) {
90 *sp++ = '-';
91 len++;
92 }
93
94 while (tp > tmp)
95 *sp++ = *--tp;
96
97 return len;
98}
99
100static float atoff(const char *str, size_t len) {
101 float result = 0.0f; // The resulting number
102 float sign = 1.0f; // Positive or negative
103 float fraction = 0.0f; // Fractional part
104 float divisor = 1.0f; // Divisor for the fractional part
105 int isFractional = 0; // Whether the current part is fractional
106
107 size_t pos = 0; // Current position in the string
108
109 // Handle empty input
110 if (len == 0) {
111 return 0.0f;
112 }
113
114 // Skip leading whitespace (manual check instead of isspace)
115 while (pos < len &&
116 (str[pos] == ' ' || str[pos] == '\t' || str[pos] == '\n' ||
117 str[pos] == '\r' || str[pos] == '\f' || str[pos] == '\v')) {
118 pos++;
119 }
120
121 // Handle optional sign
122 if (pos < len && str[pos] == '-') {
123 sign = -1.0f;
124 pos++;
125 } else if (pos < len && str[pos] == '+') {
126 pos++;
127 }
128
129 // Main parsing loop
130 while (pos < len) {
131 if (str[pos] >= '0' && str[pos] <= '9') {
132 if (isFractional) {
133 divisor *= 10.0f;
134 fraction += (str[pos] - '0') / divisor;
135 } else {
136 result = result * 10.0f + (str[pos] - '0');
137 }
138 } else if (str[pos] == '.' && !isFractional) {
139 isFractional = 1;
140 } else {
141 // Stop parsing at invalid characters
142 break;
143 }
144 pos++;
145 }
146
147 // Combine integer and fractional parts
148 result = result + fraction;
149
150 // Apply the sign
151 return sign * result;
152}
153
154} // namespace string_functions
155
156void StringFormatter::append(int32_t val, StrN<64> *dst) {
157 char buf[63] = {0};
158 string_functions::itoa(val, buf, 10);
159 dst->write(buf, strlen(buf));
160}
162 mLength = strlen(str); // Don't include null terminator in length
163 mCapacity = mLength + 1; // Capacity includes null terminator
164 mData = new char[mCapacity];
165 memcpy(mData, str, mLength);
166 mData[mLength] = '\0';
167}
169 mData = (char *)malloc(length + 1);
170 if (mData) {
171 mLength = length;
172 mData[mLength] = '\0';
173 } else {
174 mLength = 0;
175 }
177}
178
179StringHolder::StringHolder(const char *str, size_t length) {
180 mData = (char *)malloc(length + 1);
181 if (mData) {
182 mLength = length;
183 memcpy(mData, str, mLength);
184 mData[mLength] = '\0';
185 } else {
186 mLength = 0;
187 }
189}
190
192 free(mData); // Release the memory
193}
194
195void StringHolder::grow(size_t newLength) {
196 if (newLength <= mCapacity) {
197 // New length must be greater than current length
198 mLength = newLength;
199 return;
200 }
201 char *newData = (char *)realloc(mData, newLength + 1);
202 if (newData) {
203 mData = newData;
204 mLength = newLength;
205 mCapacity = newLength;
206 mData[mLength] = '\0'; // Ensure null-termination
207 } else {
208 // handle re-allocation failure.
209 char *newData = (char *)malloc(newLength + 1);
210 if (newData) {
211 memcpy(newData, mData, mLength + 1);
212 free(mData);
213 mData = newData;
214 mLength = newLength;
216 } else {
217 // memory failure.
218 }
219 }
220}
221
222float StringFormatter::parseFloat(const char *str, size_t len) {
223 return string_functions::atoff(str, len);
224}
225
226Str &Str::append(const FFTBins &str) {
227 append("\n FFTImpl Bins:\n ");
228 append(str.bins_raw);
229 append("\n");
230 append(" FFTImpl Bins DB:\n ");
231 append(str.bins_db);
232 append("\n");
233 return *this;
234}
235
236Str &Str::append(const XYMap &map) {
237 append("XYMap(");
238 append(map.getWidth());
239 append(",");
240 append(map.getHeight());
241 append(")");
242 return *this;
243}
244
245void Str::swap(Str &other) {
246 if (this != &other) {
247 fl::swap(mLength, other.mLength);
248 char temp[FASTLED_STR_INLINED_SIZE];
249 memcpy(temp, mInlineData, FASTLED_STR_INLINED_SIZE);
250 memcpy(mInlineData, other.mInlineData, FASTLED_STR_INLINED_SIZE);
251 memcpy(other.mInlineData, temp, FASTLED_STR_INLINED_SIZE);
253 }
254}
255
257 static_assert(FASTLED_STR_INLINED_SIZE > 0,
258 "FASTLED_STR_INLINED_SIZE must be greater than 0");
259 static_assert(FASTLED_STR_INLINED_SIZE == kStrInlineSize,
260 "If you want to change the FASTLED_STR_INLINED_SIZE, then it "
261 "must be through a build define and not an include define.");
262}
263
264Str &Str::append(const CRGB &rgb) {
265 append("CRGB(");
266 append(rgb.r);
267 append(",");
268 append(rgb.g);
269 append(",");
270 append(rgb.b);
271 append(")");
272 return *this;
273}
274
275void StringFormatter::appendFloat(const float &val, StrN<64> *dst) {
276 char buf[64] = {0};
277 string_functions::ftoa(val, buf);
278 dst->write(buf, strlen(buf));
279}
280
281} // namespace fl
uint8_t pos
Definition Blur.ino:11
static void compileTimeAssertions()
Definition str.cpp:256
@ kStrInlineSize
Definition str.h:584
void swap(Str &other)
Definition str.cpp:245
Str & append(const T &val)
Definition str.h:439
Str()
Definition str.h:390
size_t write(const uint8_t *data, size_t n)
Definition str.h:198
static float parseFloat(const char *str, size_t len)
Definition str.cpp:222
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
char * mData
Definition str.h:101
StringHolder(const char *str)
Definition str.cpp:161
size_t length() const
Definition str.h:88
size_t mLength
Definition str.h:102
size_t mCapacity
Definition str.h:103
void grow(size_t newLength)
Definition str.cpp:195
Defines the red, green, and blue (RGB) pixel struct.
Implements the FastLED namespace macros.
static float atoff(const char *str, size_t len)
Definition str.cpp:100
static void ftoa(float value, char *buffer, int precision=2)
Definition str.cpp:19
static int itoa(int value, char *sp, int radix)
Definition str.cpp:66
void swap(array< T, N > &lhs, array< T, N > &rhs) noexcept(noexcept(lhs.swap(rhs)))
Definition array.h:140
Implements a simple red square effect for 2D LED grids.
Definition crgb.h:16
Representation of an RGB pixel (Red, Green, Blue)
Definition crgb.h:55
fl::vector< float > bins_raw
Definition fft.h:27
fl::vector< float > bins_db
Definition fft.h:29
#define FASTLED_UNUSED(x)
Definition unused.h:3