FastLED 3.10.8
Loading...
Searching...
No Matches
json.h
Go to the documentation of this file.
1#pragma once
2
123
124// Implementation details - users should not rely on these directly
125#include "fl/stl/json/types.h"
126#include "fl/stl/bit_cast.h"
127#include "fl/stl/noexcept.h"
128#include "fl/stl/static_assert.h"
129
130namespace fl {
131
132namespace detail {
134template <typename T, typename = void>
137template <typename T>
138struct is_fl_fixed_point<T, decltype(
139 static_cast<void>(T::INT_BITS),
140 static_cast<void>(T::FRAC_BITS),
141 static_cast<void>(fl::declval<const T&>().raw()),
142 static_cast<void>(T::from_raw(fl::declval<const T&>().raw())),
143 void()
145
146inline u32 round_shift_right_u64(u64 value, int shift) FL_NO_EXCEPT {
147 if (shift <= 0) {
148 return static_cast<u32>(value);
149 }
150 if (shift >= 64) {
151 return 0;
152 }
153 const u64 half = u64(1) << (shift - 1);
154 const u64 mask = (u64(1) << shift) - 1;
155 const u64 truncated = value >> shift;
156 const u64 remainder = value & mask;
157 const bool round_up = remainder > half || (remainder == half && (truncated & 1));
158 return static_cast<u32>(truncated + (round_up ? 1 : 0));
160
162 u32 sign, u64 magnitude, int binary_exp) FL_NO_EXCEPT {
163 if (magnitude == 0) {
164 return sign;
165 }
166
167 const int top_bit = json_floor_log2_u64(magnitude);
168 int exponent = top_bit + binary_exp;
169 if (exponent > 127) {
170 return sign | 0x7F800000u;
171 }
172
173 if (exponent >= -126) {
174 const int shift = top_bit - 23;
175 u32 significand = 0;
176 if (shift > 0) {
177 significand = round_shift_right_u64(magnitude, shift);
178 } else {
179 significand = static_cast<u32>(magnitude << -shift);
180 }
181 if (significand >= 0x01000000u) {
182 significand >>= 1;
183 ++exponent;
184 if (exponent > 127) {
185 return sign | 0x7F800000u;
186 }
187 }
188 return sign | (static_cast<u32>(exponent + 127) << 23) |
189 (significand & 0x007FFFFFu);
190 }
191
192 const int subnormal_shift = -(binary_exp + 149);
193 u32 mantissa = 0;
194 if (subnormal_shift > 0) {
195 mantissa = round_shift_right_u64(magnitude, subnormal_shift);
196 } else {
197 const int left_shift = -subnormal_shift;
198 if (left_shift >= 64 || magnitude > (u64(-1) >> left_shift)) {
199 return sign | 0x7F800000u;
200 }
201 const u64 shifted = magnitude << left_shift;
202 mantissa = shifted > 0x007FFFFFu ? 0x00800000u : static_cast<u32>(shifted);
203 }
204 if (mantissa >= 0x00800000u) {
205 return sign | 0x00800000u;
206 }
207 return sign | mantissa;
209
210inline u32 ieee754_bits_from_fixed_raw(i64 raw, int frac_bits) FL_NO_EXCEPT {
211 const u32 sign = raw < 0 ? 0x80000000u : 0u;
212 const u64 magnitude = raw < 0
213 ? static_cast<u64>(-(raw + 1)) + 1u
214 : static_cast<u64>(raw);
215 return ieee754_bits_from_scaled_u64(sign, magnitude, -frac_bits);
217
218inline bool fixed_raw_from_ieee754_bits(u32 bits, int frac_bits, i64* out) FL_NO_EXCEPT {
219 const bool negative = (bits & 0x80000000u) != 0;
220 const u32 exp_bits = (bits >> 23) & 0xFFu;
221 const u32 mantissa_bits = bits & 0x007FFFFFu;
222 if (exp_bits == 0xFFu) {
223 return false;
224 }
225
226 u64 significand = mantissa_bits;
227 int exponent = -126;
228 if (exp_bits != 0) {
229 significand |= 0x00800000u;
230 exponent = static_cast<int>(exp_bits) - 127;
231 }
232
233 const int shift = exponent + frac_bits - 23;
234 u64 magnitude = 0;
235 if (shift >= 0) {
236 if (shift >= 63 || significand > (u64(0x7FFFFFFFFFFFFFFF) >> shift)) {
237 return false;
238 }
239 magnitude = significand << shift;
240 } else {
241 magnitude = round_shift_right_u64(significand, -shift);
242 }
243 if ((!negative && magnitude > u64(0x7FFFFFFFFFFFFFFF)) ||
244 (negative && magnitude > (u64(0x7FFFFFFFFFFFFFFF) + 1u))) {
245 return false;
246 }
247 *out = negative
248 ? (magnitude == (u64(0x7FFFFFFFFFFFFFFF) + 1u)
249 ? static_cast<i64>(0x8000000000000000ull)
250 : -static_cast<i64>(magnitude))
251 : static_cast<i64>(magnitude);
252 return true;
253}
255template <typename FP>
257 return fl::bit_cast<float>(
258 ieee754_bits_from_fixed_raw(static_cast<i64>(value.raw()), FP::FRAC_BITS));
259}
260
261} // namespace detail
262
263class json {
264private:
266
267public:
268 // Constructors
269 json() FL_NO_EXCEPT : mValue() {} // Default initialize to nullptr
274 json(float f) FL_NO_EXCEPT : mValue(fl::make_shared<json_value>(f)) {} // Use float directly
276 template <typename FP, typename fl::enable_if<detail::is_fl_fixed_point<FP>::value, int>::type = 0>
279 json(const char* s) FL_NO_EXCEPT : json(fl::string(s)) {}
282 // Constructor from shared_ptr<json_value>
285 // Factory method to create a json from a json_value
287 json result;
289 return result;
290 }
292 // Constructor for fl::vector<float> - converts to JSON array
294 if (!mValue) { return; } // FastLED#3588: OOM-degraded empty
295 auto ptr = mValue->data.ptr<json_array>();
296 if (ptr) {
297 for (const auto& item : vec) {
298 ptr->push_back(fl::make_shared<json_value>(item)); // Use float directly
299 }
300 }
301 }
303 // Special constructor for char values
304 static json from_char(char c) FL_NO_EXCEPT {
305 json result;
307 //FL_WARN("Created json_value with string: " << value->is_string() << ", int: " << value->is_int());
308 result.mValue = value;
309 //FL_WARN("json has string: " << result.is_string() << ", int: " << result.is_int());
310 return result;
311 }
313 // Copy constructor
314 json(const json& other) FL_NO_EXCEPT : mValue(other.mValue) {}
316 // Assignment operator
317 json& operator=(const json& other) FL_NO_EXCEPT {
318 //FL_WARN("json& operator=(const json& other): " << (other.mValue ? other.mValue.get() : 0));
319 if (this != &other) {
320 mValue = other.mValue;
321 }
322 return *this;
324
325 json& operator=(json&& other) FL_NO_EXCEPT {
326 if (this != &other) {
327 mValue = fl::move(other.mValue);
328 }
329 return *this;
330 }
332 // Assignment operators for primitive types to avoid ambiguity
335 return *this;
340 return *this;
345 return *this;
350 return *this;
351 }
353 template <typename FP, typename fl::enable_if<detail::is_fl_fixed_point<FP>::value, int>::type = 0>
356 return *this;
361 return *this;
366 return *this;
367 }
369 // Assignment operator for fl::vector<float>
372 if (!mValue) { return *this; } // FastLED#3588: OOM-degraded empty
373 auto ptr = mValue->data.ptr<json_array>();
374 if (ptr) {
375 for (const auto& item : vec) {
376 ptr->push_back(fl::make_shared<json_value>(item)); // Use float directly
377 }
378 }
379 return *this;
380 }
382 // Type queries
383 bool is_null() const FL_NO_EXCEPT { return mValue ? mValue->is_null() : true; }
384 bool is_bool() const FL_NO_EXCEPT { return mValue && mValue->is_bool(); }
385 bool is_int() const FL_NO_EXCEPT { return mValue && (mValue->is_int() || mValue->is_bool()); }
386 bool is_float() const FL_NO_EXCEPT { return mValue && mValue->is_float(); }
387 bool is_double() const FL_NO_EXCEPT { return mValue && mValue->is_double(); }
388 // is_number() returns true if the value is any numeric type (int or float)
389 bool is_number() const FL_NO_EXCEPT { return mValue && mValue->is_number(); }
390 bool is_string() const FL_NO_EXCEPT { return mValue && mValue->is_string(); }
391 bool is_array() const FL_NO_EXCEPT { return mValue && mValue->is_array(); }
392 bool is_generic_array() const FL_NO_EXCEPT { return mValue && mValue->is_generic_array(); }
393 bool is_object() const FL_NO_EXCEPT { return mValue && mValue->is_object(); }
394 bool is_audio() const FL_NO_EXCEPT { return mValue && mValue->is_audio(); }
395 bool is_bytes() const FL_NO_EXCEPT { return mValue && mValue->is_bytes(); }
396 bool is_floats() const FL_NO_EXCEPT { return mValue && mValue->is_floats(); }
398 // Safe extractors
399 fl::optional<bool> as_bool() const FL_NO_EXCEPT { return mValue ? mValue->as_bool() : fl::nullopt; }
401 if (!mValue) return fl::nullopt;
402 return mValue->as_int();
403 }
405 template<typename IntType>
407 if (!mValue) return fl::nullopt;
408 return mValue->template as_int<IntType>();
410
412 if (!mValue) return fl::nullopt;
413 return mValue->as_float();
415
417 if (!mValue) return fl::nullopt;
418 return mValue->as_double();
419 }
421 template<typename FloatType>
423 if (!mValue) return fl::nullopt;
424 return mValue->template as_float<FloatType>();
425 }
426
427 template <typename FP>
430 if (!mValue) return fl::nullopt;
431 if (auto raw = mValue->data.template ptr<i64>()) {
432 return FP::from_raw(static_cast<decltype(FP().raw())>(*raw));
433 }
434 if (auto f = mValue->data.template ptr<float>()) {
435 i64 raw = 0;
437 fl::bit_cast<u32>(*f), FP::FRAC_BITS, &raw)) {
438 return fl::nullopt;
439 }
440 return FP::from_raw(static_cast<decltype(FP().raw())>(raw));
441 }
442 return fl::nullopt;
444
446 if (!mValue) return fl::nullopt;
447 return mValue->as_string();
449 // Zero-copy pointer accessors
450 const json_array* as_array() const FL_NO_EXCEPT { return mValue ? mValue->as_array() : nullptr; }
451 const json_object* as_object() const FL_NO_EXCEPT { return mValue ? mValue->as_object() : nullptr; }
453 // Explicit copy methods - use when you need an owned copy or type conversion
454 fl::optional<json_array> clone_array() const FL_NO_EXCEPT { return mValue ? mValue->clone_array() : fl::nullopt; }
455 fl::optional<json_object> clone_object() const FL_NO_EXCEPT { return mValue ? mValue->clone_object() : fl::nullopt; }
456
457 // Copy packed-array elements into a caller-owned span with type conversion.
458 // Returns number of elements copied (min of array size and span size).
459 // Returns 0 if not a numeric array or json is null.
460 template<typename T>
461 size_t copy_to(fl::span<T> out) const FL_NO_EXCEPT {
462 return mValue ? mValue->copy_to(out) : 0;
463 }
464
465 // Stream packed-array elements into an output iterator with type conversion.
466 // Use with fl::back_inserter(container) to append to any container.
467 // Returns number of elements written. Returns 0 if not a numeric array.
468 template<typename T, typename OutputIt>
469 size_t copy_to_output_iterator(OutputIt out) const FL_NO_EXCEPT {
470 return mValue ? mValue->template copy_to_output_iterator<T, OutputIt>(out) : 0;
471 }
472
473 // Overload for back_insert_iterator: T deduced from container's value_type
474 template<typename Container>
476 return mValue ? mValue->copy_to_output_iterator(out) : 0;
477 }
478
479 // NEW ERGONOMIC API: try_as<T>() - Explicit optional handling
480 // Use when you need to explicitly handle conversion failure
481 template<typename T>
483 if (!mValue) {
484 return fl::nullopt;
485 }
486 return as_impl<T>();
487 }
488
489 // BACKWARD COMPATIBILITY: Keep existing as<T>() that returns fl::optional<T>
490 // This maintains compatibility with existing code
491 template<typename T>
493 return try_as<T>();
494 }
495
496 // NEW ERGONOMIC API: value<T>() - Direct conversion with sensible defaults
497 // Use when you want a value immediately with reasonable defaults on failure
498 template<typename T>
499 T value() const FL_NO_EXCEPT {
500 auto result = try_as<T>();
501 return result.has_value() ? *result : get_default_value<T>();
502 }
503
504private:
505 // Integer types (excluding bool)
509 return mValue->template as_int<T>();
510 }
511
512 // Boolean type
516 return mValue->as_bool();
517 }
518
519 // Floating point types
520 template<typename T>
522 as_impl() const FL_NO_EXCEPT {
523 // Force template call by explicitly using the templated method
524 return mValue->template as_float<T>();
525 }
526
527 // String type
531 return mValue->as_string();
532 }
533
534 // Array type - clone_array() provides packed-array conversion for try_as
538 return mValue->clone_array();
539 }
540
541 // Object type
542 template<typename T>
544 as_impl() const FL_NO_EXCEPT {
545 auto ptr = mValue->as_object();
546 return ptr ? fl::optional<T>(*ptr) : fl::nullopt;
547 }
548
549 // Specialized vector types - use copy_to_output_iterator for cross-type conversion
550 // e.g., try_as<vector<float>>() works on u8/i16/float packed arrays
551 template<typename T>
553 as_impl() const FL_NO_EXCEPT {
554 if (!mValue->is_array()) return fl::nullopt;
555 T result;
556 size_t n = mValue->copy_to_output_iterator(fl::back_inserter(result));
557 return n > 0 ? fl::optional<T>(fl::move(result)) : fl::nullopt;
558 }
559
560 template<typename T>
562 as_impl() const FL_NO_EXCEPT {
563 if (!mValue->is_array()) return fl::nullopt;
564 T result;
565 size_t n = mValue->copy_to_output_iterator(fl::back_inserter(result));
566 return n > 0 ? fl::optional<T>(fl::move(result)) : fl::nullopt;
567 }
568
569 template<typename T>
571 as_impl() const FL_NO_EXCEPT {
572 if (!mValue->is_array()) return fl::nullopt;
573 T result;
574 size_t n = mValue->copy_to_output_iterator(fl::back_inserter(result));
575 return n > 0 ? fl::optional<T>(fl::move(result)) : fl::nullopt;
576 }
577
578 // Helper methods for getting default values for each type
582 return T(0); // All integer types default to 0
583 }
584
585 template<typename T>
588 return false; // Boolean defaults to false
589 }
590
591 template<typename T>
594 return T(0.0); // Floating point types default to 0.0
595 }
596
600 return fl::string(); // String defaults to empty string
601 }
602
606 return json_array(); // Array defaults to empty array
607 }
608
612 return json_object(); // Object defaults to empty object
613 }
614
618 return fl::vector<i16>(); // Audio vector defaults to empty
619 }
620
624 return fl::vector<u8>(); // Bytes vector defaults to empty
625 }
626
630 return fl::vector<float>(); // Float vector defaults to empty
631 }
632
633public:
635 // Iterator support for objects
638 return mValue->begin();
639 }
641 if (!mValue) return json_value::iterator(json_object().end());
651 }
652
653 // Iterator support for arrays with type conversion
654 template<typename T>
655 typename json_value::template array_iterator<T> begin_array() FL_NO_EXCEPT {
656 if (!mValue) return typename json_value::template array_iterator<T>();
657 return mValue->template begin_array<T>();
658 }
660 template<typename T>
661 typename json_value::template array_iterator<T> end_array() FL_NO_EXCEPT {
662 if (!mValue) return typename json_value::template array_iterator<T>();
663 return mValue->template end_array<T>();
664 }
666 template<typename T>
667 typename json_value::template array_iterator<T> begin_array() const FL_NO_EXCEPT {
668 if (!mValue) return typename json_value::template array_iterator<T>();
669 return mValue->template begin_array<T>();
670 }
672 template<typename T>
673 typename json_value::template array_iterator<T> end_array() const FL_NO_EXCEPT {
674 if (!mValue) return typename json_value::template array_iterator<T>();
675 return mValue->template end_array<T>();
676 }
678 // Free functions for range-based for loops
679 friend json_value::iterator begin(json& j) FL_NO_EXCEPT { return j.begin(); }
680 friend json_value::iterator end(json& j) FL_NO_EXCEPT { return j.end(); }
681 friend json_value::const_iterator begin(const json& j) FL_NO_EXCEPT { return j.begin(); }
682 friend json_value::const_iterator end(const json& j) FL_NO_EXCEPT { return j.end(); }
684 // Object iteration support (needed for screenmap conversion)
687 if (mValue && mValue->is_object()) {
688 for (auto it = begin(); it != end(); ++it) {
689 auto keyValue = *it;
690 result.push_back(keyValue.first);
691 }
692 }
693 return result;
694 }
696 // Backward compatibility methods
700 // Indexing for fluid chaining
701 json operator[](size_t idx) FL_NO_EXCEPT {
702 if (!mValue) {
704 }
705 // FastLED#3588: make_shared may degrade to empty under OOM.
706 if (!mValue) { return json(nullptr); }
707 // If we're indexing into a specialized array, convert it to regular json_array first
708 if (mValue->data.is<fl::vector<i16>>() ||
709 mValue->data.is<fl::vector<u8>>() ||
710 mValue->data.is<fl::vector<float>>()) {
711 // Convert to regular json_array (needs a copy/conversion)
712 auto arr = mValue->clone_array();
713 if (arr) {
715 }
716 }
717 // Get pointer directly to avoid copying - fixes silent mutation bug
718 auto arrPtr = mValue->as_array();
719 if (arrPtr) {
720 // Ensure the array is large enough
721 if (idx >= arrPtr->size()) {
722 for (size_t i = arrPtr->size(); i <= idx; i++) {
723 arrPtr->push_back(fl::make_shared<json_value>(nullptr));
724 }
725 }
726 return json((*arrPtr)[idx]);
727 }
728 return json(nullptr);
730
731 const json operator[](size_t idx) const FL_NO_EXCEPT {
732 if (!mValue) {
733 return json(nullptr);
734 }
735 // Handle regular json_array - zero-copy pointer access
736 auto arrPtr = mValue->as_array();
737 if (arrPtr) {
738 if (idx < arrPtr->size()) {
739 return json((*arrPtr)[idx]);
740 }
741 return json(nullptr);
742 }
743 // For packed arrays, extract element directly without converting the whole array
744 if (auto p = mValue->data.ptr<fl::vector<i16>>()) {
745 if (idx < p->size()) return json(static_cast<i64>((*p)[idx]));
746 } else if (auto p = mValue->data.ptr<fl::vector<u8>>()) {
747 if (idx < p->size()) return json(static_cast<i64>((*p)[idx]));
748 } else if (auto p = mValue->data.ptr<fl::vector<float>>()) {
749 if (idx < p->size()) return json((*p)[idx]);
750 }
751 return json(nullptr);
753
755 if (!mValue || !mValue->is_object()) {
757 }
758 // FastLED#3588: make_shared may degrade to empty under OOM.
759 if (!mValue) { return json(nullptr); }
760 // Get reference to the json_value
761 auto objPtr = mValue->data.ptr<json_object>();
762 if (objPtr) {
763 // If key doesn't exist, create a new json_value and insert it
764 if (objPtr->find(key) == objPtr->end()) {
765 (*objPtr)[key] = fl::make_shared<json_value>(nullptr);
766 }
767 // Return a new json object that wraps the shared_ptr to the json_value
768 return json((*objPtr)[key]);
769 }
770 // Should not happen if mValue is properly initialized as an object
771 //return *reinterpret_cast<json*>(&get_null_value());
772 return json(nullptr);
774
775 const json operator[](const fl::string &key) const FL_NO_EXCEPT {
776 if (!mValue || !mValue->is_object()) {
777 return json(nullptr);
778 }
779 // Use ptr<> directly to avoid copying the entire map via as_object().
780 // The variant stores json_object (not const), so use ptr<json_object>().
781 // The const overload of ptr<T>() returns const T*, which is what we want.
782 auto objPtr = mValue->data.ptr<json_object>();
783 if (!objPtr) return json(nullptr);
784 auto it = objPtr->find(key);
785 if (it != objPtr->end()) {
786 return json(it->second);
787 }
788 return json(nullptr);
789 }
791 // Contains methods for checking existence
792 bool contains(size_t idx) const FL_NO_EXCEPT {
793 return mValue && mValue->contains(idx);
794 }
795 bool contains(const fl::string &key) const FL_NO_EXCEPT {
796 return mValue && mValue->contains(key);
797 }
799 // Size method
800 size_t size() const FL_NO_EXCEPT {
801 return mValue ? mValue->size() : 0;
802 }
803
804 // Default-value operator (pipe)
805 template<typename T>
806 T operator|(const T& fallback) const FL_NO_EXCEPT {
807 if (!mValue) return fallback;
808 return (*mValue) | fallback;
809 }
810
811 // NEW ERGONOMIC API: as_or<T>(default) - Conversion with custom defaults
812 // Use when you want to specify your own default value
813 // This method uses try_as<T>() for proper string-to-number conversion
814 template<typename T>
815 T as_or(const T& fallback) const FL_NO_EXCEPT {
816 auto result = try_as<T>();
817 return result.has_value() ? *result : fallback;
818 }
820 // has_value method for compatibility
821 bool has_value() const FL_NO_EXCEPT {
822 return mValue && !mValue->is_null();
823 }
824
825 // Get access to the internal json_value for direct variant visiting
826 // Returns nullptr if no value is set
827 const json_value* internal_value() const FL_NO_EXCEPT { return mValue.get(); }
829 // Method to set the internal value (for json_value::to_string())
831 mValue = value;
832 }
834 // Public method to access to_string_native for json_value::to_string()
837 // Serialization - now delegates to native implementation
839
840 // Native serialization (without external libraries)
843 // Parsing factory method - uses native parser
844 static json parse(const fl::string &txt) FL_NO_EXCEPT {
845 auto parsed = json_value::parse2(txt);
846 if (parsed) {
847 json result;
848 result.mValue = parsed;
849 return result;
850 }
851 return json(nullptr);
852 }
854 // Convenience methods for creating arrays and objects
855 static json array() FL_NO_EXCEPT {
856 return json(json_array{});
858
859 static json object() FL_NO_EXCEPT {
860 return json(json_object{});
861 }
863 // Compatibility with existing API for array/object access
864 size_t get_size() const FL_NO_EXCEPT { return size(); }
865 size_t getSize() const FL_NO_EXCEPT { return size(); }
867 // Set methods for building objects
868 void set(const fl::string& key, const json& value) FL_NO_EXCEPT {
869 if (!mValue || !mValue->is_object()) {
871 }
872 // FastLED#3588: make_shared degrades to an empty shared_ptr under
873 // OOM, so mValue can be null here — dereferencing it would read
874 // through null. Degrade gracefully (the set becomes a no-op).
875 if (!mValue) {
876 return;
877 }
878 // Directly assign the value to the object without going through json::operator[]
879 auto objPtr = mValue->data.ptr<json_object>();
880 if (objPtr) {
881 // Create or update the entry directly
882 if (value.mValue) {
883 (*objPtr)[key] = value.mValue;
884 } else {
885 // If value has null mValue, create a null json_value
886 (*objPtr)[key] = fl::make_shared<json_value>(nullptr);
887 }
888 }
891 void set(const fl::string& key, bool value) FL_NO_EXCEPT { set(key, json(value)); }
892 void set(const fl::string& key, int value) FL_NO_EXCEPT { set(key, json(value)); }
893 void set(const fl::string& key, i64 value) FL_NO_EXCEPT { set(key, json(value)); }
894 void set(const fl::string& key, float value) FL_NO_EXCEPT { set(key, json(value)); }
895 void set(const fl::string& key, double value) FL_NO_EXCEPT { set(key, json(value)); }
896 template <typename FP, typename fl::enable_if<detail::is_fl_fixed_point<FP>::value, int>::type = 0>
897 void set(const fl::string& key, FP value) FL_NO_EXCEPT { set(key, json(value)); }
898 void set(const fl::string& key, const fl::string& value) FL_NO_EXCEPT { set(key, json(value)); }
899 void set(const fl::string& key, const char* value) FL_NO_EXCEPT { set(key, json(value)); }
900 template<typename T, typename = fl::enable_if_t<fl::is_same<T, char>::value>>
901 void set(const fl::string& key, T value) FL_NO_EXCEPT { set(key, json(value)); }
902
903 // Generic setter for all integer types (excluding bool, int, and i64 which have explicit overloads)
904 // Converts to i64 for internal storage
905 template<typename IntType>
906 typename fl::enable_if<
912 void
913 >::type
914 set(const fl::string& key, IntType value) FL_NO_EXCEPT {
915 // Convert to i64 for storage
916 set(key, json(static_cast<i64>(value)));
917 }
919 // Array push_back methods
920 void push_back(const json& value) FL_NO_EXCEPT {
921 if (!mValue || !mValue->is_array()) {
923 }
924 // FastLED#3588: make_shared may degrade to empty under OOM.
925 if (!mValue) { return; }
926 // If we're pushing to a packed array, convert it to regular json_array first
927 if (mValue->is_array() &&
928 (mValue->data.is<fl::vector<i16>>() ||
929 mValue->data.is<fl::vector<u8>>() ||
930 mValue->data.is<fl::vector<float>>())) {
931 // Convert to regular json_array (needs a copy/conversion)
932 auto arr = mValue->clone_array();
933 if (arr) {
935 }
936 }
937 // For arrays, we need to manually handle the insertion since our indexing
938 // mechanism auto-creates elements
939 auto ptr = mValue->data.ptr<json_array>();
940 if (ptr) {
941 ptr->push_back(value.mValue);
942 }
943 }
945 // Create methods for compatibility
948 static json createArray() FL_NO_EXCEPT { return json::array(); }
949 static json createObject() FL_NO_EXCEPT { return json::object(); }
951 // Serialize method for compatibility
952 fl::string serialize() const FL_NO_EXCEPT { return to_string(); }
953
954 // Helper function to normalize JSON string (remove whitespace)
955 static fl::string normalize_json_string(const char* jsonStr) FL_NO_EXCEPT;
956 static fl::string normalizeJsonString(const char* jsonStr) FL_NO_EXCEPT { return normalize_json_string(jsonStr); }
957};
958
959// JSON memory profiling support - defined in json.cpp.hpp
960// Set g_json_stack_base to a stack address to enable stack depth tracking
961extern volatile size_t g_json_stack_base; // cast address to size_t
962extern volatile size_t g_json_max_stack_depth;
963
964
965} // namespace fl
Back insert iterator - an output iterator that inserts elements at the end of a container.
Definition iterator.h:75
static const_iterator from_iterator(json_object::const_iterator iter) FL_NO_EXCEPT
Definition types.h:1605
static const_iterator from_object_iterator(const iterator &other) FL_NO_EXCEPT
Definition types.h:1599
void set_value(const fl::shared_ptr< json_value > &value) FL_NO_EXCEPT
Definition json.h:828
static fl::string normalizeJsonString(const char *jsonStr) FL_NO_EXCEPT
Definition json.h:954
bool is_object() const FL_NO_EXCEPT
Definition json.h:391
friend json_value::const_iterator begin(const json &j) FL_NO_EXCEPT
Definition json.h:679
T operator|(const T &fallback) const FL_NO_EXCEPT
Definition json.h:804
fl::string to_string_native_public() const FL_NO_EXCEPT
Definition json.h:833
fl::string to_string() const FL_NO_EXCEPT
Definition json.h:836
size_t copy_to(fl::span< T > out) const FL_NO_EXCEPT
Definition json.h:459
fl::enable_if< detail::is_fl_fixed_point< FP >::value, fl::optional< FP > >::type as_fixed_point() const FL_NO_EXCEPT
Definition json.h:427
size_t size() const FL_NO_EXCEPT
Definition json.h:798
json(FP v) FL_NO_EXCEPT
Definition json.h:275
T as_or(const T &fallback) const FL_NO_EXCEPT
Definition json.h:813
fl::optional< fl::string > as_string() const FL_NO_EXCEPT
Definition json.h:443
fl::shared_ptr< json_value > mValue
Definition json.h:263
const json_object * as_object() const FL_NO_EXCEPT
Definition json.h:449
fl::optional< i64 > as_int() const FL_NO_EXCEPT
Definition json.h:398
json(double d) FL_NO_EXCEPT
Definition json.h:273
bool is_generic_array() const FL_NO_EXCEPT
Definition json.h:390
void set(const fl::string &key, const char *value) FL_NO_EXCEPT
Definition json.h:897
fl::vector< fl::string > getObjectKeys() const FL_NO_EXCEPT
Definition json.h:696
void set(const fl::string &key, const json &value) FL_NO_EXCEPT
Definition json.h:866
static json createObject() FL_NO_EXCEPT
Definition json.h:947
bool is_int() const FL_NO_EXCEPT
Definition json.h:383
json(json_object o) FL_NO_EXCEPT
Definition json.h:279
void set(const fl::string &key, double value) FL_NO_EXCEPT
Definition json.h:893
T value() const FL_NO_EXCEPT
Definition json.h:497
json & operator=(const json &other) FL_NO_EXCEPT
Definition json.h:315
static json create_array() FL_NO_EXCEPT
Definition json.h:944
json_value::iterator begin() FL_NO_EXCEPT
Definition json.h:634
json operator[](size_t idx) FL_NO_EXCEPT
Definition json.h:699
json(int i) FL_NO_EXCEPT
Definition json.h:270
void set(const fl::string &key, T value) FL_NO_EXCEPT
Definition json.h:899
fl::enable_if< fl::is_integral< T >::value &&!fl::is_same< T, bool >::value, T >::type get_default_value() const FL_NO_EXCEPT
Definition json.h:579
fl::optional< json_object > clone_object() const FL_NO_EXCEPT
Definition json.h:453
fl::vector< fl::string > get_object_keys() const FL_NO_EXCEPT
Definition json.h:695
static json createArray() FL_NO_EXCEPT
Definition json.h:946
bool is_number() const FL_NO_EXCEPT
Definition json.h:387
bool has_value() const FL_NO_EXCEPT
Definition json.h:819
json() FL_NO_EXCEPT
Definition json.h:267
bool is_floats() const FL_NO_EXCEPT
Definition json.h:394
json_value::template array_iterator< T > end_array() FL_NO_EXCEPT
Definition json.h:659
fl::string serialize() const FL_NO_EXCEPT
Definition json.h:950
fl::optional< float > as_float() const FL_NO_EXCEPT
Definition json.h:409
fl::enable_if< fl::is_integral< T >::value &&!fl::is_same< T, bool >::value, fl::optional< T > >::type as_impl() const FL_NO_EXCEPT
Definition json.h:506
fl::optional< T > try_as() const FL_NO_EXCEPT
Definition json.h:480
fl::string to_string_native() const FL_NO_EXCEPT
fl::vector< fl::string > keys() const FL_NO_EXCEPT
Definition json.h:683
bool is_array() const FL_NO_EXCEPT
Definition json.h:389
json(bool b) FL_NO_EXCEPT
Definition json.h:269
bool is_null() const FL_NO_EXCEPT
Definition json.h:381
size_t get_size() const FL_NO_EXCEPT
Definition json.h:862
static json create_object() FL_NO_EXCEPT
Definition json.h:945
void set(const fl::string &key, FP value) FL_NO_EXCEPT
Definition json.h:895
fl::optional< bool > as_bool() const FL_NO_EXCEPT
Definition json.h:397
const json_array * as_array() const FL_NO_EXCEPT
Definition json.h:448
void push_back(const json &value) FL_NO_EXCEPT
Definition json.h:918
void set(const fl::string &key, float value) FL_NO_EXCEPT
Definition json.h:892
static fl::string normalize_json_string(const char *jsonStr) FL_NO_EXCEPT
json_value::iterator end() FL_NO_EXCEPT
Definition json.h:638
json(const fl::shared_ptr< json_value > &value) FL_NO_EXCEPT
Definition json.h:281
const json_value * internal_value() const FL_NO_EXCEPT
Definition json.h:825
json(json_array a) FL_NO_EXCEPT
Definition json.h:278
bool contains(size_t idx) const FL_NO_EXCEPT
Definition json.h:790
static json from_char(char c) FL_NO_EXCEPT
Definition json.h:302
bool is_double() const FL_NO_EXCEPT
Definition json.h:385
size_t getSize() const FL_NO_EXCEPT
Definition json.h:863
json(float f) FL_NO_EXCEPT
Definition json.h:272
json(const char *s) FL_NO_EXCEPT
Definition json.h:277
static json parse(const fl::string &txt) FL_NO_EXCEPT
Definition json.h:842
static json fromValue(const json_value &value) FL_NO_EXCEPT
Definition json.h:284
bool is_float() const FL_NO_EXCEPT
Definition json.h:384
bool is_bool() const FL_NO_EXCEPT
Definition json.h:382
bool is_bytes() const FL_NO_EXCEPT
Definition json.h:393
fl::optional< T > as() const FL_NO_EXCEPT
Definition json.h:490
bool is_string() const FL_NO_EXCEPT
Definition json.h:388
void set(const fl::string &key, i64 value) FL_NO_EXCEPT
Definition json.h:891
friend json_value::const_iterator end(const json &j) FL_NO_EXCEPT
Definition json.h:680
static json object() FL_NO_EXCEPT
Definition json.h:857
fl::optional< double > as_double() const FL_NO_EXCEPT
Definition json.h:414
fl::optional< json_array > clone_array() const FL_NO_EXCEPT
Definition json.h:452
bool is_audio() const FL_NO_EXCEPT
Definition json.h:392
json(i64 i) FL_NO_EXCEPT
Definition json.h:271
static json array() FL_NO_EXCEPT
Definition json.h:853
size_t copy_to_output_iterator(OutputIt out) const FL_NO_EXCEPT
Definition json.h:467
json_value::template array_iterator< T > begin_array() FL_NO_EXCEPT
Definition json.h:653
constexpr remove_reference< T >::type && move(T &&t) FL_NO_EXCEPT
Definition move.h:30
shared_ptr< T > make_shared(Args &&... args) FL_NO_EXCEPT
Definition shared_ptr.h:423
bool fixed_raw_from_ieee754_bits(u32 bits, int frac_bits, i64 *out) FL_NO_EXCEPT
Definition json.h:216
u32 ieee754_bits_from_fixed_raw(i64 raw, int frac_bits) FL_NO_EXCEPT
Definition json.h:208
u32 ieee754_bits_from_scaled_u64(u32 sign, u64 magnitude, int binary_exp) FL_NO_EXCEPT
Definition json.h:159
u32 round_shift_right_u64(u64 value, int shift) FL_NO_EXCEPT
Definition json.h:144
float fixed_point_to_float(FP value) FL_NO_EXCEPT
Definition json.h:254
int json_floor_log2_u64(u64 value) FL_NO_EXCEPT
Definition types_impl.h:18
float json_double_to_float(double value) FL_NO_EXCEPT
Definition types_impl.h:40
Compile-time linker keep-alive hook for a single fl::Bus.
Definition bus_info.h:57
decltype(nullptr) nullptr_t
Definition s16x16x4.h:13
back_insert_iterator< Container > back_inserter(Container &c) FL_NO_EXCEPT
Helper function to create a back_insert_iterator.
Definition iterator.h:139
u8 u8 fract8 blur_amount FL_NO_EXCEPT
Definition blur.h:186
volatile size_t g_json_stack_base
constexpr int type_rank< T >::value
volatile size_t g_json_max_stack_depth
Optional< T > optional
Definition optional.h:16
integral_constant< bool, false > false_type
Definition type_traits.h:29
fl::vector< fl::shared_ptr< json_value > > json_array
Definition types.h:54
expected< T, E > result
Alias for expected (Rust-style naming)
Definition result.h:31
constexpr nullopt_t nullopt
Definition optional.h:13
To bit_cast(const From &from) FL_NO_EXCEPT
Definition bit_cast.h:48
fl::flat_map< fl::string, fl::shared_ptr< json_value >, fl::StringFastLess > json_object
Definition types.h:55
constexpr enable_if< is_fixed_point< T >::value, int >::type sign(T x) FL_NO_EXCEPT
integral_constant< bool, true > true_type
Definition type_traits.h:28
Base definition for an LED controller.
Definition crgb.hpp:179
#define FL_NO_EXCEPT
Portable compile-time assertion wrapper.
fl::u64 u64
Definition stdint.h:220
fl::i64 i64
Definition stdint.h:221
static fl::shared_ptr< json_value > parse2(const fl::string &txt) FL_NO_EXCEPT
json_value::iterator iterator
Definition types.h:757
json_value::const_iterator const_iterator
Definition types.h:758