initial commit

This commit is contained in:
2026-02-12 00:45:31 -08:00
commit 5f168f370b
3024 changed files with 804889 additions and 0 deletions

View File

@@ -0,0 +1,423 @@
#include <stdlib.h>
#include <string.h> // ok include - for strcmp
#include "fl/str.h"
#include "crgb.h"
#include "fl/fft.h"
#include "fl/namespace.h"
#include "fl/unused.h"
#include "fl/xymap.h"
#include "fl/json.h"
#include "fl/tile2x2.h"
#include "fl/compiler_control.h"
// UI dependency moved to separate compilation unit to break dependency chain
#ifdef FASTLED_TESTING
#include <cstdio> // ok include
#endif
namespace fl {
// Define static const member for npos (only for string class)
const fl::size string::npos;
// Explicit template instantiations for commonly used sizes
template class StrN<64>;
namespace string_functions {
static void ftoa(float value, char *buffer, int precision = 2) {
#ifdef FASTLED_TESTING
// use snprintf during testing with precision
snprintf(buffer, 64, "%.*f", precision, value);
return;
#else
// Handle negative values
if (value < 0) {
*buffer++ = '-';
value = -value;
}
// Extract integer part
u32 intPart = (u32)value;
// Convert integer part to string (reversed)
char intBuf[12]; // Enough for 32-bit integers
int i = 0;
do {
intBuf[i++] = '0' + (intPart % 10);
intPart /= 10;
} while (intPart);
// Write integer part in correct order
while (i--) {
*buffer++ = intBuf[i];
}
*buffer++ = '.'; // Decimal point
// Extract fractional part
float fracPart = value - (u32)value;
for (int j = 0; j < precision; ++j) {
fracPart *= 10.0f;
int digit = (int)fracPart;
*buffer++ = '0' + digit;
fracPart -= digit;
}
*buffer = '\0'; // Null-terminate
#endif
}
static int itoa(int value, char *sp, int radix) {
char tmp[16]; // be careful with the length of the buffer
char *tp = tmp;
int i;
unsigned v;
int sign = (radix == 10 && value < 0);
if (sign)
v = -value;
else
v = (unsigned)value;
while (v || tp == tmp) {
i = v % radix;
v = radix ? v / radix : 0;
if (i < 10)
*tp++ = i + '0';
else
*tp++ = i + 'a' - 10;
}
int len = tp - tmp;
if (sign) {
*sp++ = '-';
len++;
}
while (tp > tmp)
*sp++ = *--tp;
return len;
}
static int utoa32(uint32_t value, char *sp, int radix) {
char tmp[16]; // be careful with the length of the buffer
char *tp = tmp;
int i;
uint32_t v = value;
while (v || tp == tmp) {
i = v % radix;
v = radix ? v / radix : 0;
if (i < 10)
*tp++ = i + '0';
else
*tp++ = i + 'a' - 10;
}
int len = tp - tmp;
while (tp > tmp)
*sp++ = *--tp;
return len;
}
static int utoa64(uint64_t value, char *sp, int radix) {
char tmp[32]; // larger buffer for 64-bit values
char *tp = tmp;
int i;
uint64_t v = value;
while (v || tp == tmp) {
i = v % radix;
v = radix ? v / radix : 0;
if (i < 10)
*tp++ = i + '0';
else
*tp++ = i + 'a' - 10;
}
int len = tp - tmp;
while (tp > tmp)
*sp++ = *--tp;
return len;
}
static float atoff(const char *str, fl::size len) {
float result = 0.0f; // The resulting number
float sign = 1.0f; // Positive or negative
float fraction = 0.0f; // Fractional part
float divisor = 1.0f; // Divisor for the fractional part
int isFractional = 0; // Whether the current part is fractional
fl::size pos = 0; // Current position in the string
// Handle empty input
if (len == 0) {
return 0.0f;
}
// Skip leading whitespace (manual check instead of isspace)
while (pos < len &&
(str[pos] == ' ' || str[pos] == '\t' || str[pos] == '\n' ||
str[pos] == '\r' || str[pos] == '\f' || str[pos] == '\v')) {
pos++;
}
// Handle optional sign
if (pos < len && str[pos] == '-') {
sign = -1.0f;
pos++;
} else if (pos < len && str[pos] == '+') {
pos++;
}
// Main parsing loop
while (pos < len) {
if (str[pos] >= '0' && str[pos] <= '9') {
if (isFractional) {
divisor *= 10.0f;
fraction += (str[pos] - '0') / divisor;
} else {
result = result * 10.0f + (str[pos] - '0');
}
} else if (str[pos] == '.' && !isFractional) {
isFractional = 1;
} else {
// Stop parsing at invalid characters
break;
}
pos++;
}
// Combine integer and fractional parts
result = result + fraction;
// Apply the sign
return sign * result;
}
} // namespace string_functions
void StringFormatter::append(i32 val, StrN<64> *dst) {
char buf[63] = {0};
string_functions::itoa(val, buf, 10);
dst->write(buf, strlen(buf));
}
void StringFormatter::append(u32 val, StrN<64> *dst) {
char buf[63] = {0};
string_functions::utoa32(val, buf, 10);
dst->write(buf, strlen(buf));
}
void StringFormatter::append(uint64_t val, StrN<64> *dst) {
char buf[63] = {0};
string_functions::utoa64(val, buf, 10);
dst->write(buf, strlen(buf));
}
void StringFormatter::append(i16 val, StrN<64> *dst) {
append(static_cast<i32>(val), dst);
}
void StringFormatter::append(u16 val, StrN<64> *dst) {
append(static_cast<u32>(val), dst);
}
StringHolder::StringHolder(const char *str) {
mLength = strlen(str); // Don't include null terminator in length
mCapacity = mLength + 1; // Capacity includes null terminator
mData = new char[mCapacity];
memcpy(mData, str, mLength);
mData[mLength] = '\0';
}
StringHolder::StringHolder(fl::size length) {
mData = (char *)malloc(length + 1);
if (mData) {
mLength = length;
mData[mLength] = '\0';
} else {
mLength = 0;
}
mCapacity = mLength;
}
StringHolder::StringHolder(const char *str, fl::size length) {
mData = (char *)malloc(length + 1);
if (mData) {
mLength = length;
memcpy(mData, str, mLength);
mData[mLength] = '\0';
} else {
mLength = 0;
}
mCapacity = mLength;
}
StringHolder::~StringHolder() {
free(mData); // Release the memory
}
void StringHolder::grow(fl::size newLength) {
if (newLength <= mCapacity) {
// New length must be greater than current length
mLength = newLength;
return;
}
char *newData = (char *)realloc(mData, newLength + 1);
if (newData) {
mData = newData;
mLength = newLength;
mCapacity = newLength;
mData[mLength] = '\0'; // Ensure null-termination
} else {
// handle re-allocation failure.
char *newData = (char *)malloc(newLength + 1);
if (newData) {
memcpy(newData, mData, mLength + 1);
free(mData);
mData = newData;
mLength = newLength;
mCapacity = mLength;
} else {
// memory failure.
}
}
}
float StringFormatter::parseFloat(const char *str, fl::size len) {
return string_functions::atoff(str, len);
}
int StringFormatter::parseInt(const char *str, fl::size len) {
float f = parseFloat(str, len);
return static_cast<int>(f);
}
int StringFormatter::parseInt(const char *str) {
return parseInt(str, strlen(str));
}
int string::strcmp(const string& a, const string& b) {
return ::strcmp(a.c_str(), b.c_str());
}
string &string::append(const FFTBins &str) {
append("\n FFTImpl Bins:\n ");
append(str.bins_raw);
append("\n");
append(" FFTImpl Bins DB:\n ");
append(str.bins_db);
append("\n");
return *this;
}
string &string::append(const XYMap &map) {
append("XYMap(");
append(map.getWidth());
append(",");
append(map.getHeight());
append(")");
return *this;
}
string &string::append(const Tile2x2_u8_wrap &tile) {
Tile2x2_u8_wrap::Entry data[4] = {
tile.at(0, 0),
tile.at(0, 1),
tile.at(1, 0),
tile.at(1, 1),
};
append("Tile2x2_u8_wrap(");
for (int i = 0; i < 4; i++) {
vec2<u16> pos = data[i].first;
u8 alpha = data[i].second;
append("(");
append(pos.x);
append(",");
append(pos.y);
append(",");
append(alpha);
append(")");
if (i < 3) {
append(",");
}
}
append(")");
return *this;
}
void string::swap(string &other) {
if (this != &other) {
fl::swap(mLength, other.mLength);
char temp[FASTLED_STR_INLINED_SIZE];
memcpy(temp, mInlineData, FASTLED_STR_INLINED_SIZE);
memcpy(mInlineData, other.mInlineData, FASTLED_STR_INLINED_SIZE);
memcpy(other.mInlineData, temp, FASTLED_STR_INLINED_SIZE);
fl::swap(mHeapData, other.mHeapData);
}
}
void string::compileTimeAssertions() {
static_assert(FASTLED_STR_INLINED_SIZE > 0,
"FASTLED_STR_INLINED_SIZE must be greater than 0");
static_assert(FASTLED_STR_INLINED_SIZE == kStrInlineSize,
"If you want to change the FASTLED_STR_INLINED_SIZE, then it "
"must be through a build define and not an include define.");
}
string &string::append(const CRGB &rgb) {
append("CRGB(");
append(rgb.r);
append(",");
append(rgb.g);
append(",");
append(rgb.b);
append(")");
return *this;
}
void StringFormatter::appendFloat(const float &val, StrN<64> *dst) {
char buf[64] = {0};
string_functions::ftoa(val, buf);
dst->write(buf, strlen(buf));
}
void StringFormatter::appendFloat(const float &val, StrN<64> *dst, int precision) {
char buf[64] = {0};
string_functions::ftoa(val, buf, precision);
dst->write(buf, strlen(buf));
}
// JsonUiInternal append implementation moved to str_ui.cpp to break dependency chain
// JSON type append implementations
// NOTE: These use forward declarations to avoid circular dependency with json.h
string &string::append(const JsonValue& val) {
// Use the JsonValue's to_string method if available
// For now, just append a placeholder to avoid compilation errors
FL_UNUSED(val);
append("<JsonValue>");
return *this;
}
string &string::append(const Json& val) {
// Use the Json's to_string method if available
// For now, just append a placeholder to avoid compilation errors
//append("<Json>");
append("Json(");
append(val.to_string());
append(")");
return *this;
}
} // namespace fl