// ArduinoJson - https://arduinojson.org // Copyright © 2014-2022, Benoit BLANCHON // MIT License #pragma once #define ARDUINOJSON_USE_DOUBLE 0 #define ARDUINOJSON_USE_LONG_LONG 0 #define ARDUINOJSON_ENABLE_STD_STREAM 0 #ifdef __cplusplus #if __cplusplus >= 201103L # define ARDUINOJSON_HAS_LONG_LONG 1 # define ARDUINOJSON_HAS_RVALUE_REFERENCES 1 #else # define ARDUINOJSON_HAS_LONG_LONG 0 # define ARDUINOJSON_HAS_RVALUE_REFERENCES 0 #endif #ifndef ARDUINOJSON_HAS_NULLPTR # if __cplusplus >= 201103L # define ARDUINOJSON_HAS_NULLPTR 1 # else # define ARDUINOJSON_HAS_NULLPTR 0 # endif #endif #if defined(_MSC_VER) && !ARDUINOJSON_HAS_LONG_LONG # define ARDUINOJSON_HAS_INT64 1 #else # define ARDUINOJSON_HAS_INT64 0 #endif #ifndef ARDUINOJSON_ENABLE_STD_STREAM # ifdef __has_include # if __has_include() && \ __has_include() && \ !defined(min) && \ !defined(max) # define ARDUINOJSON_ENABLE_STD_STREAM 1 # else # define ARDUINOJSON_ENABLE_STD_STREAM 0 # endif # else # ifdef ARDUINO # define ARDUINOJSON_ENABLE_STD_STREAM 0 # else # define ARDUINOJSON_ENABLE_STD_STREAM 1 # endif # endif #endif #ifndef ARDUINOJSON_ENABLE_STD_STRING # ifdef __has_include # if __has_include() && !defined(min) && !defined(max) # define ARDUINOJSON_ENABLE_STD_STRING 1 # else # define ARDUINOJSON_ENABLE_STD_STRING 0 # endif # else # ifdef ARDUINO # define ARDUINOJSON_ENABLE_STD_STRING 0 # else # define ARDUINOJSON_ENABLE_STD_STRING 1 # endif # endif #endif #ifndef ARDUINOJSON_ENABLE_STRING_VIEW # ifdef __has_include # if __has_include() && __cplusplus >= 201703L # define ARDUINOJSON_ENABLE_STRING_VIEW 1 # else # define ARDUINOJSON_ENABLE_STRING_VIEW 0 # endif # else # define ARDUINOJSON_ENABLE_STRING_VIEW 0 # endif #endif #ifndef ARDUINOJSON_USE_DOUBLE # define ARDUINOJSON_USE_DOUBLE 1 #endif #ifndef ARDUINOJSON_USE_LONG_LONG # if ARDUINOJSON_HAS_LONG_LONG && defined(__SIZEOF_POINTER__) && \ __SIZEOF_POINTER__ >= 4 || \ defined(_MSC_VER) # define ARDUINOJSON_USE_LONG_LONG 1 # endif #endif #ifndef ARDUINOJSON_USE_LONG_LONG # define ARDUINOJSON_USE_LONG_LONG 0 #endif #ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT # define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10 #endif #ifndef ARDUINOJSON_SLOT_OFFSET_SIZE # if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ <= 2 # define ARDUINOJSON_SLOT_OFFSET_SIZE 1 # elif defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ >= 8 || \ defined(_WIN64) && _WIN64 # define ARDUINOJSON_SLOT_OFFSET_SIZE 4 # else # define ARDUINOJSON_SLOT_OFFSET_SIZE 2 # endif #endif #ifdef ARDUINO # ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING # define ARDUINOJSON_ENABLE_ARDUINO_STRING 1 # endif # ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM # define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1 # endif # ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT # define ARDUINOJSON_ENABLE_ARDUINO_PRINT 1 # endif # ifndef ARDUINOJSON_ENABLE_PROGMEM # define ARDUINOJSON_ENABLE_PROGMEM 1 # endif #else // ARDUINO # ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING # define ARDUINOJSON_ENABLE_ARDUINO_STRING 0 # endif # ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM # define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0 # endif # ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT # define ARDUINOJSON_ENABLE_ARDUINO_PRINT 0 # endif # ifndef ARDUINOJSON_ENABLE_PROGMEM # define ARDUINOJSON_ENABLE_PROGMEM 0 # endif #endif // ARDUINO #ifndef ARDUINOJSON_DECODE_UNICODE # define ARDUINOJSON_DECODE_UNICODE 1 #endif #ifndef ARDUINOJSON_ENABLE_COMMENTS # define ARDUINOJSON_ENABLE_COMMENTS 0 #endif #ifndef ARDUINOJSON_ENABLE_NAN # define ARDUINOJSON_ENABLE_NAN 0 #endif #ifndef ARDUINOJSON_ENABLE_INFINITY # define ARDUINOJSON_ENABLE_INFINITY 0 #endif #ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD # define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e7 #endif #ifndef ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD # define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5 #endif #ifndef ARDUINOJSON_LITTLE_ENDIAN # if defined(_MSC_VER) || \ (defined(__BYTE_ORDER__) && \ __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \ defined(__LITTLE_ENDIAN__) || defined(__i386) || defined(__x86_64) # define ARDUINOJSON_LITTLE_ENDIAN 1 # else # define ARDUINOJSON_LITTLE_ENDIAN 0 # endif #endif #ifndef ARDUINOJSON_ENABLE_ALIGNMENT # if defined(__AVR) # define ARDUINOJSON_ENABLE_ALIGNMENT 0 # else # define ARDUINOJSON_ENABLE_ALIGNMENT 1 # endif #endif #ifndef ARDUINOJSON_TAB # define ARDUINOJSON_TAB " " #endif #ifndef ARDUINOJSON_ENABLE_STRING_DEDUPLICATION # define ARDUINOJSON_ENABLE_STRING_DEDUPLICATION 1 #endif #ifndef ARDUINOJSON_STRING_BUFFER_SIZE # define ARDUINOJSON_STRING_BUFFER_SIZE 32 #endif #ifndef ARDUINOJSON_DEBUG # ifdef __PLATFORMIO_BUILD_DEBUG__ # define ARDUINOJSON_DEBUG 1 # else # define ARDUINOJSON_DEBUG 0 # endif #endif #if ARDUINOJSON_HAS_NULLPTR && defined(nullptr) # error nullptr is defined as a macro. Remove the faulty #define or #undef nullptr #endif #if ARDUINOJSON_ENABLE_ARDUINO_STRING || ARDUINOJSON_ENABLE_ARDUINO_STREAM || \ ARDUINOJSON_ENABLE_ARDUINO_PRINT || ARDUINOJSON_ENABLE_PROGMEM #include #endif #if !ARDUINOJSON_DEBUG # ifdef __clang__ # pragma clang system_header # elif defined __GNUC__ # pragma GCC system_header # endif #endif #define ARDUINOJSON_EXPAND6(a, b, c, d, e, f) a, b, c, d, e, f #define ARDUINOJSON_EXPAND9(a, b, c, d, e, f, g, h, i) a, b, c, d, e, f, g, h, i #define ARDUINOJSON_EXPAND18(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, \ q, r) \ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r #define ARDUINOJSON_CONCAT_(A, B) A##B #define ARDUINOJSON_CONCAT2(A, B) ARDUINOJSON_CONCAT_(A, B) #define ARDUINOJSON_CONCAT4(A, B, C, D) \ ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT2(A, B), ARDUINOJSON_CONCAT2(C, D)) #define ARDUINOJSON_HEX_DIGIT_0000() 0 #define ARDUINOJSON_HEX_DIGIT_0001() 1 #define ARDUINOJSON_HEX_DIGIT_0010() 2 #define ARDUINOJSON_HEX_DIGIT_0011() 3 #define ARDUINOJSON_HEX_DIGIT_0100() 4 #define ARDUINOJSON_HEX_DIGIT_0101() 5 #define ARDUINOJSON_HEX_DIGIT_0110() 6 #define ARDUINOJSON_HEX_DIGIT_0111() 7 #define ARDUINOJSON_HEX_DIGIT_1000() 8 #define ARDUINOJSON_HEX_DIGIT_1001() 9 #define ARDUINOJSON_HEX_DIGIT_1010() A #define ARDUINOJSON_HEX_DIGIT_1011() B #define ARDUINOJSON_HEX_DIGIT_1100() C #define ARDUINOJSON_HEX_DIGIT_1101() D #define ARDUINOJSON_HEX_DIGIT_1110() E #define ARDUINOJSON_HEX_DIGIT_1111() F #define ARDUINOJSON_HEX_DIGIT_(A, B, C, D) ARDUINOJSON_HEX_DIGIT_##A##B##C##D() #define ARDUINOJSON_HEX_DIGIT(A, B, C, D) ARDUINOJSON_HEX_DIGIT_(A, B, C, D) #define ARDUINOJSON_VERSION "6.20.1" #define ARDUINOJSON_VERSION_MAJOR 6 #define ARDUINOJSON_VERSION_MINOR 20 #define ARDUINOJSON_VERSION_REVISION 1 #ifndef ARDUINOJSON_NAMESPACE # define ARDUINOJSON_NAMESPACE \ ARDUINOJSON_CONCAT4( \ ARDUINOJSON_CONCAT4(ArduinoJson, ARDUINOJSON_VERSION_MAJOR, \ ARDUINOJSON_VERSION_MINOR, \ ARDUINOJSON_VERSION_REVISION), \ _, \ ARDUINOJSON_HEX_DIGIT( \ ARDUINOJSON_ENABLE_PROGMEM, ARDUINOJSON_USE_LONG_LONG, \ ARDUINOJSON_USE_DOUBLE, ARDUINOJSON_ENABLE_STRING_DEDUPLICATION), \ ARDUINOJSON_HEX_DIGIT( \ ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY, \ ARDUINOJSON_ENABLE_COMMENTS, ARDUINOJSON_DECODE_UNICODE)) #endif namespace ARDUINOJSON_NAMESPACE { template struct Converter; template class InvalidConversion; // Error here? See https://arduinojson.org/v6/invalid-conversion/ template struct ConverterNeedsWriteableRef; } // namespace ARDUINOJSON_NAMESPACE #include #include namespace ARDUINOJSON_NAMESPACE { #if ARDUINOJSON_ENABLE_ALIGNMENT inline bool isAligned(size_t value) { const size_t mask = sizeof(void*) - 1; size_t addr = value; return (addr & mask) == 0; } inline size_t addPadding(size_t bytes) { const size_t mask = sizeof(void*) - 1; return (bytes + mask) & ~mask; } template struct AddPadding { static const size_t mask = sizeof(void*) - 1; static const size_t value = (bytes + mask) & ~mask; }; #else inline bool isAligned(size_t) { return true; } inline size_t addPadding(size_t bytes) { return bytes; } template struct AddPadding { static const size_t value = bytes; }; #endif template inline bool isAligned(T* ptr) { return isAligned(reinterpret_cast(ptr)); } template inline T* addPadding(T* p) { size_t address = addPadding(reinterpret_cast(p)); return reinterpret_cast(address); } } // namespace ARDUINOJSON_NAMESPACE #if ARDUINOJSON_DEBUG #include # define ARDUINOJSON_ASSERT(X) assert(X) #else # define ARDUINOJSON_ASSERT(X) ((void)0) #endif namespace ARDUINOJSON_NAMESPACE { template Y)> struct Max {}; template struct Max { static const size_t value = X; }; template struct Max { static const size_t value = Y; }; template struct conditional { typedef TrueType type; }; template struct conditional { typedef FalseType type; }; template struct enable_if {}; template struct enable_if { typedef T type; }; template struct integral_constant { static const T value = v; }; typedef integral_constant true_type; typedef integral_constant false_type; template struct is_array : false_type {}; template struct is_array : true_type {}; template struct is_array : true_type {}; template class is_base_of { protected: // <- to avoid GCC's "all member functions in class are private" static int probe(const TBase*); static char probe(...); public: static const bool value = sizeof(probe(reinterpret_cast(0))) == sizeof(int); }; template T declval(); template struct is_class { protected: // <- to avoid GCC's "all member functions in class are private" template static int probe(void (U::*)(void)); template static char probe(...); public: static const bool value = sizeof(probe(0)) == sizeof(int); }; template struct is_const : false_type {}; template struct is_const : true_type {}; } // namespace ARDUINOJSON_NAMESPACE #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable : 4244) #endif #ifdef __ICCARM__ #pragma diag_suppress=Pa093 #endif namespace ARDUINOJSON_NAMESPACE { template struct is_convertible { protected: // <- to avoid GCC's "all member functions in class are private" static int probe(To); static char probe(...); static From& _from; public: static const bool value = sizeof(probe(_from)) == sizeof(int); }; } // namespace ARDUINOJSON_NAMESPACE #ifdef _MSC_VER # pragma warning(pop) #endif #ifdef __ICCARM__ #pragma diag_default=Pa093 #endif namespace ARDUINOJSON_NAMESPACE { template struct is_same : false_type {}; template struct is_same : true_type {}; template struct remove_cv { typedef T type; }; template struct remove_cv { typedef T type; }; template struct remove_cv { typedef T type; }; template struct remove_cv { typedef T type; }; template struct is_floating_point : integral_constant< bool, // is_same::type>::value || is_same::type>::value> {}; template struct is_integral : integral_constant::type, signed char>::value || is_same::type, unsigned char>::value || is_same::type, signed short>::value || is_same::type, unsigned short>::value || is_same::type, signed int>::value || is_same::type, unsigned int>::value || is_same::type, signed long>::value || is_same::type, unsigned long>::value || #if ARDUINOJSON_HAS_LONG_LONG is_same::type, signed long long>::value || is_same::type, unsigned long long>::value || #endif #if ARDUINOJSON_HAS_INT64 is_same::type, signed __int64>::value || is_same::type, unsigned __int64>::value || #endif is_same::type, char>::value || is_same::type, bool>::value> {}; template struct is_enum { static const bool value = is_convertible::value && !is_class::value && !is_integral::value && !is_floating_point::value; }; template struct is_pointer : false_type {}; template struct is_pointer : true_type {}; template struct is_signed : integral_constant::type, char>::value || is_same::type, signed char>::value || is_same::type, signed short>::value || is_same::type, signed int>::value || is_same::type, signed long>::value || #if ARDUINOJSON_HAS_LONG_LONG is_same::type, signed long long>::value || #endif #if ARDUINOJSON_HAS_INT64 is_same::type, signed __int64>::value || #endif is_same::type, float>::value || is_same::type, double>::value> {}; template struct is_unsigned : integral_constant::type, unsigned char>::value || is_same::type, unsigned short>::value || is_same::type, unsigned int>::value || is_same::type, unsigned long>::value || #if ARDUINOJSON_HAS_INT64 is_same::type, unsigned __int64>::value || #endif #if ARDUINOJSON_HAS_LONG_LONG is_same::type, unsigned long long>::value || #endif is_same::type, bool>::value> {}; template struct type_identity { typedef T type; }; template struct make_unsigned; template <> struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; #if ARDUINOJSON_HAS_LONG_LONG template <> struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; #endif #if ARDUINOJSON_HAS_INT64 template <> struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; #endif template struct make_void { typedef void type; }; template struct remove_const { typedef T type; }; template struct remove_const { typedef T type; }; template struct remove_reference { typedef T type; }; template struct remove_reference { typedef T type; }; } // namespace ARDUINOJSON_NAMESPACE #include namespace ARDUINOJSON_NAMESPACE { namespace StringStoragePolicy { struct Link {}; struct Copy {}; struct LinkOrCopy { bool link; }; } // namespace StringStoragePolicy template struct StringAdapter; template struct SizedStringAdapter; template typename StringAdapter::AdaptedString adaptString(const TString& s) { return StringAdapter::adapt(s); } template typename StringAdapter::AdaptedString adaptString(TChar* p) { return StringAdapter::adapt(p); } template typename SizedStringAdapter::AdaptedString adaptString(TChar* p, size_t n) { return SizedStringAdapter::adapt(p, n); } template struct IsChar : integral_constant::value && sizeof(T) == 1> {}; class ZeroTerminatedRamString { public: static const size_t typeSortKey = 3; ZeroTerminatedRamString(const char* str) : _str(str) {} bool isNull() const { return !_str; } size_t size() const { return _str ? ::strlen(_str) : 0; } char operator[](size_t i) const { ARDUINOJSON_ASSERT(_str != 0); ARDUINOJSON_ASSERT(i <= size()); return _str[i]; } const char* data() const { return _str; } friend int stringCompare(ZeroTerminatedRamString a, ZeroTerminatedRamString b) { ARDUINOJSON_ASSERT(!a.isNull()); ARDUINOJSON_ASSERT(!b.isNull()); return ::strcmp(a._str, b._str); } friend bool stringEquals(ZeroTerminatedRamString a, ZeroTerminatedRamString b) { return stringCompare(a, b) == 0; } StringStoragePolicy::Copy storagePolicy() const { return StringStoragePolicy::Copy(); } protected: const char* _str; }; template struct StringAdapter::value>::type> { typedef ZeroTerminatedRamString AdaptedString; static AdaptedString adapt(const TChar* p) { return AdaptedString(reinterpret_cast(p)); } }; template struct StringAdapter::value>::type> { typedef ZeroTerminatedRamString AdaptedString; static AdaptedString adapt(const TChar* p) { return AdaptedString(reinterpret_cast(p)); } }; class StaticStringAdapter : public ZeroTerminatedRamString { public: StaticStringAdapter(const char* str) : ZeroTerminatedRamString(str) {} StringStoragePolicy::Link storagePolicy() const { return StringStoragePolicy::Link(); } }; template <> struct StringAdapter { typedef StaticStringAdapter AdaptedString; static AdaptedString adapt(const char* p) { return AdaptedString(p); } }; class SizedRamString { public: static const size_t typeSortKey = 2; SizedRamString(const char* str, size_t sz) : _str(str), _size(sz) {} bool isNull() const { return !_str; } size_t size() const { return _size; } char operator[](size_t i) const { ARDUINOJSON_ASSERT(_str != 0); ARDUINOJSON_ASSERT(i <= size()); return _str[i]; } const char* data() const { return _str; } StringStoragePolicy::Copy storagePolicy() const { return StringStoragePolicy::Copy(); } protected: const char* _str; size_t _size; }; template struct SizedStringAdapter::value>::type> { typedef SizedRamString AdaptedString; static AdaptedString adapt(const TChar* p, size_t n) { return AdaptedString(reinterpret_cast(p), n); } }; template class SafeBoolIdom { protected: typedef void (T::*bool_type)() const; void safeBoolHelper() const {} static bool_type safe_true() { return &SafeBoolIdom::safeBoolHelper; } static bool_type safe_false() { return 0; } }; } // namespace ARDUINOJSON_NAMESPACE #if ARDUINOJSON_ENABLE_STD_STREAM #include #endif namespace ARDUINOJSON_NAMESPACE { class JsonString : public SafeBoolIdom { public: enum Ownership { Copied, Linked }; JsonString() : _data(0), _size(0), _ownership(Linked) {} JsonString(const char* data, Ownership ownership = Linked) : _data(data), _size(data ? ::strlen(data) : 0), _ownership(ownership) {} JsonString(const char* data, size_t sz, Ownership ownership = Linked) : _data(data), _size(sz), _ownership(ownership) {} const char* c_str() const { return _data; } bool isNull() const { return !_data; } bool isLinked() const { return _ownership == Linked; } size_t size() const { return _size; } operator bool_type() const { return _data ? safe_true() : safe_false(); } friend bool operator==(JsonString lhs, JsonString rhs) { if (lhs._size != rhs._size) return false; if (lhs._data == rhs._data) return true; if (!lhs._data) return false; if (!rhs._data) return false; return memcmp(lhs._data, rhs._data, lhs._size) == 0; } friend bool operator!=(JsonString lhs, JsonString rhs) { return !(lhs == rhs); } #if ARDUINOJSON_ENABLE_STD_STREAM friend std::ostream& operator<<(std::ostream& lhs, const JsonString& rhs) { lhs.write(rhs.c_str(), static_cast(rhs.size())); return lhs; } #endif private: const char* _data; size_t _size; Ownership _ownership; }; class JsonStringAdapter : public SizedRamString { public: JsonStringAdapter(const JsonString& s) : SizedRamString(s.c_str(), s.size()), _linked(s.isLinked()) {} StringStoragePolicy::LinkOrCopy storagePolicy() const { StringStoragePolicy::LinkOrCopy policy = {_linked}; return policy; } private: bool _linked; }; template <> struct StringAdapter { typedef JsonStringAdapter AdaptedString; static AdaptedString adapt(const JsonString& s) { return AdaptedString(s); } }; } // namespace ARDUINOJSON_NAMESPACE #if ARDUINOJSON_ENABLE_STD_STRING #include namespace ARDUINOJSON_NAMESPACE { template struct StringAdapter, void> { typedef SizedRamString AdaptedString; static AdaptedString adapt( const std::basic_string& s) { return AdaptedString(s.c_str(), s.size()); } }; } // namespace ARDUINOJSON_NAMESPACE #endif #if ARDUINOJSON_ENABLE_STRING_VIEW #include namespace ARDUINOJSON_NAMESPACE { template <> struct StringAdapter { typedef SizedRamString AdaptedString; static AdaptedString adapt(const std::string_view& s) { return AdaptedString(s.data(), s.size()); } }; } // namespace ARDUINOJSON_NAMESPACE #endif #if ARDUINOJSON_ENABLE_ARDUINO_STRING namespace ARDUINOJSON_NAMESPACE { template struct StringAdapter< T, typename enable_if::value || is_same::value>::type> { typedef SizedRamString AdaptedString; static AdaptedString adapt(const ::String& s) { return AdaptedString(s.c_str(), s.length()); } }; } // namespace ARDUINOJSON_NAMESPACE #endif #if ARDUINOJSON_ENABLE_PROGMEM namespace ARDUINOJSON_NAMESPACE { struct pgm_p { pgm_p(const void* p) : address(reinterpret_cast(p)) {} const char* address; }; } // namespace ARDUINOJSON_NAMESPACE #ifndef strlen_P inline size_t strlen_P(ARDUINOJSON_NAMESPACE::pgm_p s) { const char* p = s.address; ARDUINOJSON_ASSERT(p != NULL); while (pgm_read_byte(p)) p++; return size_t(p - s.address); } #endif #ifndef strncmp_P inline int strncmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b, size_t n) { const char* s1 = a; const char* s2 = b.address; ARDUINOJSON_ASSERT(s1 != NULL); ARDUINOJSON_ASSERT(s2 != NULL); while (n-- > 0) { char c1 = *s1++; char c2 = static_cast(pgm_read_byte(s2++)); if (c1 < c2) return -1; if (c1 > c2) return 1; if (c1 == 0 /* and c2 as well */) return 0; } return 0; } #endif #ifndef strcmp_P inline int strcmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b) { const char* s1 = a; const char* s2 = b.address; ARDUINOJSON_ASSERT(s1 != NULL); ARDUINOJSON_ASSERT(s2 != NULL); for (;;) { char c1 = *s1++; char c2 = static_cast(pgm_read_byte(s2++)); if (c1 < c2) return -1; if (c1 > c2) return 1; if (c1 == 0 /* and c2 as well */) return 0; } } #endif #ifndef memcmp_P inline int memcmp_P(const void* a, ARDUINOJSON_NAMESPACE::pgm_p b, size_t n) { const uint8_t* p1 = reinterpret_cast(a); const char* p2 = b.address; ARDUINOJSON_ASSERT(p1 != NULL); ARDUINOJSON_ASSERT(p2 != NULL); while (n-- > 0) { uint8_t v1 = *p1++; uint8_t v2 = pgm_read_byte(p2++); if (v1 != v2) return v1 - v2; } return 0; } #endif #ifndef memcpy_P inline void* memcpy_P(void* dst, ARDUINOJSON_NAMESPACE::pgm_p src, size_t n) { uint8_t* d = reinterpret_cast(dst); const char* s = src.address; ARDUINOJSON_ASSERT(d != NULL); ARDUINOJSON_ASSERT(s != NULL); while (n-- > 0) { *d++ = pgm_read_byte(s++); } return dst; } #endif #ifndef pgm_read_dword inline uint32_t pgm_read_dword(ARDUINOJSON_NAMESPACE::pgm_p p) { uint32_t result; memcpy_P(&result, p.address, 4); return result; } #endif #ifndef pgm_read_ptr inline void* pgm_read_ptr(ARDUINOJSON_NAMESPACE::pgm_p p) { void* result; memcpy_P(&result, p.address, sizeof(result)); return result; } #endif namespace ARDUINOJSON_NAMESPACE { class FlashString { public: static const size_t typeSortKey = 1; FlashString(const __FlashStringHelper* str, size_t sz) : _str(reinterpret_cast(str)), _size(sz) {} bool isNull() const { return !_str; } char operator[](size_t i) const { ARDUINOJSON_ASSERT(_str != 0); ARDUINOJSON_ASSERT(i <= _size); return static_cast(pgm_read_byte(_str + i)); } size_t size() const { return _size; } friend bool stringEquals(FlashString a, SizedRamString b) { ARDUINOJSON_ASSERT(a.typeSortKey < b.typeSortKey); ARDUINOJSON_ASSERT(!a.isNull()); ARDUINOJSON_ASSERT(!b.isNull()); if (a.size() != b.size()) return false; return ::memcmp_P(b.data(), a._str, a._size) == 0; } friend int stringCompare(FlashString a, SizedRamString b) { ARDUINOJSON_ASSERT(a.typeSortKey < b.typeSortKey); ARDUINOJSON_ASSERT(!a.isNull()); ARDUINOJSON_ASSERT(!b.isNull()); size_t minsize = a.size() < b.size() ? a.size() : b.size(); int res = ::memcmp_P(b.data(), a._str, minsize); if (res) return -res; if (a.size() < b.size()) return -1; if (a.size() > b.size()) return 1; return 0; } friend void stringGetChars(FlashString s, char* p, size_t n) { ARDUINOJSON_ASSERT(s.size() <= n); ::memcpy_P(p, s._str, n); } StringStoragePolicy::Copy storagePolicy() const { return StringStoragePolicy::Copy(); } private: const char* _str; size_t _size; }; template <> struct StringAdapter { typedef FlashString AdaptedString; static AdaptedString adapt(const __FlashStringHelper* s) { return AdaptedString(s, s ? strlen_P(reinterpret_cast(s)) : 0); } }; template <> struct SizedStringAdapter { typedef FlashString AdaptedString; static AdaptedString adapt(const __FlashStringHelper* s, size_t n) { return AdaptedString(s, n); } }; } // namespace ARDUINOJSON_NAMESPACE #endif namespace ARDUINOJSON_NAMESPACE { template typename enable_if::type stringCompare(TAdaptedString1 s1, TAdaptedString2 s2) { ARDUINOJSON_ASSERT(!s1.isNull()); ARDUINOJSON_ASSERT(!s2.isNull()); size_t size1 = s1.size(); size_t size2 = s2.size(); size_t n = size1 < size2 ? size1 : size2; for (size_t i = 0; i < n; i++) { if (s1[i] != s2[i]) return s1[i] - s2[i]; } if (size1 < size2) return -1; if (size1 > size2) return 1; return 0; } template typename enable_if< (TAdaptedString1::typeSortKey > TAdaptedString2::typeSortKey), int>::type stringCompare(TAdaptedString1 s1, TAdaptedString2 s2) { return -stringCompare(s2, s1); } template typename enable_if::type stringEquals(TAdaptedString1 s1, TAdaptedString2 s2) { ARDUINOJSON_ASSERT(!s1.isNull()); ARDUINOJSON_ASSERT(!s2.isNull()); size_t size1 = s1.size(); size_t size2 = s2.size(); if (size1 != size2) return false; for (size_t i = 0; i < size1; i++) { if (s1[i] != s2[i]) return false; } return true; } template typename enable_if< (TAdaptedString1::typeSortKey > TAdaptedString2::typeSortKey), bool>::type stringEquals(TAdaptedString1 s1, TAdaptedString2 s2) { return stringEquals(s2, s1); } template static void stringGetChars(TAdaptedString s, char* p, size_t n) { ARDUINOJSON_ASSERT(s.size() <= n); for (size_t i = 0; i < n; i++) { p[i] = s[i]; } } template struct int_t; template <> struct int_t<8> { typedef int8_t type; }; template <> struct int_t<16> { typedef int16_t type; }; template <> struct int_t<32> { typedef int32_t type; }; } // namespace ARDUINOJSON_NAMESPACE #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable : 4310) #endif namespace ARDUINOJSON_NAMESPACE { template struct numeric_limits; template struct numeric_limits::value>::type> { static T lowest() { return 0; } static T highest() { return T(-1); } }; template struct numeric_limits< T, typename enable_if::value && is_signed::value>::type> { static T lowest() { return T(T(1) << (sizeof(T) * 8 - 1)); } static T highest() { return T(~lowest()); } }; } // namespace ARDUINOJSON_NAMESPACE #ifdef _MSC_VER # pragma warning(pop) #endif namespace ARDUINOJSON_NAMESPACE { class MemoryPool; class VariantData; class VariantSlot; class CollectionData { VariantSlot* _head; VariantSlot* _tail; public: VariantData* addElement(MemoryPool* pool); VariantData* getElement(size_t index) const; VariantData* getOrAddElement(size_t index, MemoryPool* pool); void removeElement(size_t index); template VariantData* addMember(TAdaptedString key, MemoryPool* pool); template VariantData* getMember(TAdaptedString key) const; template VariantData* getOrAddMember(TAdaptedString key, MemoryPool* pool); template void removeMember(TAdaptedString key) { removeSlot(getSlot(key)); } template bool containsKey(const TAdaptedString& key) const; void clear(); size_t memoryUsage() const; size_t size() const; VariantSlot* addSlot(MemoryPool*); void removeSlot(VariantSlot* slot); bool copyFrom(const CollectionData& src, MemoryPool* pool); VariantSlot* head() const { return _head; } void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance); private: VariantSlot* getSlot(size_t index) const; template VariantSlot* getSlot(TAdaptedString key) const; VariantSlot* getPreviousSlot(VariantSlot*) const; }; inline const VariantData* collectionToVariant( const CollectionData* collection) { const void* data = collection; // prevent warning cast-align return reinterpret_cast(data); } inline VariantData* collectionToVariant(CollectionData* collection) { void* data = collection; // prevent warning cast-align return reinterpret_cast(data); } #if ARDUINOJSON_USE_DOUBLE typedef double JsonFloat; #else typedef float JsonFloat; #endif #if ARDUINOJSON_USE_LONG_LONG typedef int64_t JsonInteger; typedef uint64_t JsonUInt; #else typedef long JsonInteger; typedef unsigned long JsonUInt; #endif } // namespace ARDUINOJSON_NAMESPACE #if ARDUINOJSON_HAS_LONG_LONG && !ARDUINOJSON_USE_LONG_LONG # define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) \ static_assert(sizeof(T) <= sizeof(ARDUINOJSON_NAMESPACE::JsonInteger), \ "To use 64-bit integers with ArduinoJson, you must set " \ "ARDUINOJSON_USE_LONG_LONG to 1. See " \ "https://arduinojson.org/v6/api/config/use_long_long/"); #else # define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) #endif namespace ARDUINOJSON_NAMESPACE { enum { VALUE_MASK = 0x7F, OWNED_VALUE_BIT = 0x01, VALUE_IS_NULL = 0, VALUE_IS_LINKED_RAW = 0x02, VALUE_IS_OWNED_RAW = 0x03, VALUE_IS_LINKED_STRING = 0x04, VALUE_IS_OWNED_STRING = 0x05, VALUE_IS_BOOLEAN = 0x06, NUMBER_BIT = 0x08, VALUE_IS_UNSIGNED_INTEGER = 0x08, VALUE_IS_SIGNED_INTEGER = 0x0A, VALUE_IS_FLOAT = 0x0C, COLLECTION_MASK = 0x60, VALUE_IS_OBJECT = 0x20, VALUE_IS_ARRAY = 0x40, OWNED_KEY_BIT = 0x80 }; struct RawData { const char* data; size_t size; }; union VariantContent { JsonFloat asFloat; bool asBoolean; JsonUInt asUnsignedInteger; JsonInteger asSignedInteger; CollectionData asCollection; struct { const char* data; size_t size; } asString; }; typedef int_t::type VariantSlotDiff; class VariantSlot { VariantContent _content; uint8_t _flags; VariantSlotDiff _next; const char* _key; public: VariantData* data() { return reinterpret_cast(&_content); } const VariantData* data() const { return reinterpret_cast(&_content); } VariantSlot* next() { return _next ? this + _next : 0; } const VariantSlot* next() const { return const_cast(this)->next(); } VariantSlot* next(size_t distance) { VariantSlot* slot = this; while (distance--) { if (!slot->_next) return 0; slot += slot->_next; } return slot; } const VariantSlot* next(size_t distance) const { return const_cast(this)->next(distance); } void setNext(VariantSlot* slot) { ARDUINOJSON_ASSERT(!slot || slot - this >= numeric_limits::lowest()); ARDUINOJSON_ASSERT(!slot || slot - this <= numeric_limits::highest()); _next = VariantSlotDiff(slot ? slot - this : 0); } void setNextNotNull(VariantSlot* slot) { ARDUINOJSON_ASSERT(slot != 0); ARDUINOJSON_ASSERT(slot - this >= numeric_limits::lowest()); ARDUINOJSON_ASSERT(slot - this <= numeric_limits::highest()); _next = VariantSlotDiff(slot - this); } void setKey(JsonString k) { ARDUINOJSON_ASSERT(k); if (k.isLinked()) _flags &= VALUE_MASK; else _flags |= OWNED_KEY_BIT; _key = k.c_str(); } const char* key() const { return _key; } bool ownsKey() const { return (_flags & OWNED_KEY_BIT) != 0; } void clear() { _next = 0; _flags = 0; _key = 0; } void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) { if (_flags & OWNED_KEY_BIT) _key += stringDistance; if (_flags & OWNED_VALUE_BIT) _content.asString.data += stringDistance; if (_flags & COLLECTION_MASK) _content.asCollection.movePointers(stringDistance, variantDistance); } }; } // namespace ARDUINOJSON_NAMESPACE #define JSON_STRING_SIZE(SIZE) (SIZE + 1) #define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \ ((NUMBER_OF_ELEMENTS) * sizeof(ARDUINOJSON_NAMESPACE::VariantSlot)) #define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \ ((NUMBER_OF_ELEMENTS) * sizeof(ARDUINOJSON_NAMESPACE::VariantSlot)) namespace ARDUINOJSON_NAMESPACE { class MemoryPool { public: MemoryPool(char* buf, size_t capa) : _begin(buf), _left(buf), _right(buf ? buf + capa : 0), _end(buf ? buf + capa : 0), _overflowed(false) { ARDUINOJSON_ASSERT(isAligned(_begin)); ARDUINOJSON_ASSERT(isAligned(_right)); ARDUINOJSON_ASSERT(isAligned(_end)); } void* buffer() { return _begin; // NOLINT(clang-analyzer-unix.Malloc) } size_t capacity() const { return size_t(_end - _begin); } size_t size() const { return size_t(_left - _begin + _end - _right); } bool overflowed() const { return _overflowed; } VariantSlot* allocVariant() { return allocRight(); } template const char* saveString(TAdaptedString str) { if (str.isNull()) return 0; #if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION const char* existingCopy = findString(str); if (existingCopy) return existingCopy; #endif size_t n = str.size(); char* newCopy = allocString(n + 1); if (newCopy) { stringGetChars(str, newCopy, n); newCopy[n] = 0; // force null-terminator } return newCopy; } void getFreeZone(char** zoneStart, size_t* zoneSize) const { *zoneStart = _left; *zoneSize = size_t(_right - _left); } const char* saveStringFromFreeZone(size_t len) { #if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION const char* dup = findString(adaptString(_left, len)); if (dup) return dup; #endif const char* str = _left; _left += len; *_left++ = 0; checkInvariants(); return str; } void markAsOverflowed() { _overflowed = true; } void clear() { _left = _begin; _right = _end; _overflowed = false; } bool canAlloc(size_t bytes) const { return _left + bytes <= _right; } bool owns(void* p) const { return _begin <= p && p < _end; } void* operator new(size_t, void* p) { return p; } ptrdiff_t squash() { char* new_right = addPadding(_left); if (new_right >= _right) return 0; size_t right_size = static_cast(_end - _right); memmove(new_right, _right, right_size); ptrdiff_t bytes_reclaimed = _right - new_right; _right = new_right; _end = new_right + right_size; return bytes_reclaimed; } void movePointers(ptrdiff_t offset) { _begin += offset; _left += offset; _right += offset; _end += offset; } private: void checkInvariants() { ARDUINOJSON_ASSERT(_begin <= _left); ARDUINOJSON_ASSERT(_left <= _right); ARDUINOJSON_ASSERT(_right <= _end); ARDUINOJSON_ASSERT(isAligned(_right)); } #if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION template const char* findString(const TAdaptedString& str) const { size_t n = str.size(); for (char* next = _begin; next + n < _left; ++next) { if (next[n] == '\0' && stringEquals(str, adaptString(next, n))) return next; while (*next) ++next; } return 0; } #endif char* allocString(size_t n) { if (!canAlloc(n)) { _overflowed = true; return 0; } char* s = _left; _left += n; checkInvariants(); return s; } template T* allocRight() { return reinterpret_cast(allocRight(sizeof(T))); } void* allocRight(size_t bytes) { if (!canAlloc(bytes)) { _overflowed = true; return 0; } _right -= bytes; return _right; } char *_begin, *_left, *_right, *_end; bool _overflowed; }; template bool storeString(MemoryPool* pool, TAdaptedString str, StringStoragePolicy::Copy, TCallback callback) { const char* copy = pool->saveString(str); JsonString storedString(copy, str.size(), JsonString::Copied); callback(storedString); return copy != 0; } template bool storeString(MemoryPool*, TAdaptedString str, StringStoragePolicy::Link, TCallback callback) { JsonString storedString(str.data(), str.size(), JsonString::Linked); callback(storedString); return !str.isNull(); } template bool storeString(MemoryPool* pool, TAdaptedString str, StringStoragePolicy::LinkOrCopy policy, TCallback callback) { if (policy.link) return storeString(pool, str, StringStoragePolicy::Link(), callback); else return storeString(pool, str, StringStoragePolicy::Copy(), callback); } template bool storeString(MemoryPool* pool, TAdaptedString str, TCallback callback) { return storeString(pool, str, str.storagePolicy(), callback); } template struct IsString : false_type {}; template struct IsString< T, typename make_void::AdaptedString>::type> : true_type {}; } // namespace ARDUINOJSON_NAMESPACE #ifdef _MSC_VER // Visual Studio # define FORCE_INLINE // __forceinline causes C4714 when returning std::string # define NO_INLINE __declspec(noinline) #elif defined(__GNUC__) // GCC or Clang # define FORCE_INLINE __attribute__((always_inline)) # define NO_INLINE __attribute__((noinline)) #else // Other compilers # define FORCE_INLINE # define NO_INLINE #endif #if __cplusplus >= 201103L # define NOEXCEPT noexcept #else # define NOEXCEPT throw() #endif #if defined(__has_attribute) # if __has_attribute(no_sanitize) # define ARDUINOJSON_NO_SANITIZE(check) __attribute__((no_sanitize(check))) # else # define ARDUINOJSON_NO_SANITIZE(check) # endif #else # define ARDUINOJSON_NO_SANITIZE(check) #endif namespace ARDUINOJSON_NAMESPACE { class JsonArray; class JsonObject; class JsonVariant; template struct VariantTo {}; template <> struct VariantTo { typedef JsonArray type; }; template <> struct VariantTo { typedef JsonObject type; }; template <> struct VariantTo { typedef JsonVariant type; }; class VariantAttorney { template struct ResultOfGetData { protected: // <- to avoid GCC's "all member functions in class are private" static int probe(const VariantData*); static char probe(VariantData*); static TClient& client; public: typedef typename conditional::type type; }; public: template FORCE_INLINE static MemoryPool* getPool(TClient& client) { return client.getPool(); } template FORCE_INLINE static typename ResultOfGetData::type getData( TClient& client) { return client.getData(); } template FORCE_INLINE static VariantData* getOrCreateData(TClient& client) { return client.getOrCreateData(); } }; template class SerializedValue { public: explicit SerializedValue(T str) : _str(str) {} operator T() const { return _str; } const char* data() const { return _str.c_str(); } size_t size() const { return _str.length(); } private: T _str; }; template class SerializedValue { public: explicit SerializedValue(TChar* p, size_t n) : _data(p), _size(n) {} operator TChar*() const { return _data; } TChar* data() const { return _data; } size_t size() const { return _size; } private: TChar* _data; size_t _size; }; template inline SerializedValue serialized(T str) { return SerializedValue(str); } template inline SerializedValue serialized(TChar* p) { return SerializedValue(p, adaptString(p).size()); } template inline SerializedValue serialized(TChar* p, size_t n) { return SerializedValue(p, n); } } // namespace ARDUINOJSON_NAMESPACE #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wconversion" #elif defined(__GNUC__) # if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) # pragma GCC diagnostic push # endif # pragma GCC diagnostic ignored "-Wconversion" #endif #include namespace ARDUINOJSON_NAMESPACE { #ifndef isnan template bool isnan(T x) { return x != x; } #endif #ifndef isinf template bool isinf(T x) { return x != 0.0 && x * 2 == x; } #endif template struct alias_cast_t { union { F raw; T data; }; }; template T alias_cast(F raw_data) { alias_cast_t ac; ac.raw = raw_data; return ac.data; } } // namespace ARDUINOJSON_NAMESPACE #if ARDUINOJSON_ENABLE_PROGMEM #endif namespace ARDUINOJSON_NAMESPACE { #if ARDUINOJSON_ENABLE_PROGMEM # ifndef ARDUINOJSON_DEFINE_PROGMEM_ARRAY # define ARDUINOJSON_DEFINE_PROGMEM_ARRAY(type, name, value) \ static type const name[] PROGMEM = value; # endif template inline const T* pgm_read(const T* const* p) { return reinterpret_cast(pgm_read_ptr(p)); } inline uint32_t pgm_read(const uint32_t* p) { return pgm_read_dword(p); } #else # ifndef ARDUINOJSON_DEFINE_PROGMEM_ARRAY # define ARDUINOJSON_DEFINE_PROGMEM_ARRAY(type, name, value) \ static type const name[] = value; # endif template inline T pgm_read(const T* p) { return *p; } #endif template struct FloatTraits {}; template struct FloatTraits { typedef uint64_t mantissa_type; static const short mantissa_bits = 52; static const mantissa_type mantissa_max = (mantissa_type(1) << mantissa_bits) - 1; typedef int16_t exponent_type; static const exponent_type exponent_max = 308; template static T make_float(T m, TExponent e) { if (e > 0) { for (uint8_t index = 0; e != 0; index++) { if (e & 1) m *= positiveBinaryPowerOfTen(index); e >>= 1; } } else { e = TExponent(-e); for (uint8_t index = 0; e != 0; index++) { if (e & 1) m *= negativeBinaryPowerOfTen(index); e >>= 1; } } return m; } static T positiveBinaryPowerOfTen(int index) { ARDUINOJSON_DEFINE_PROGMEM_ARRAY( // uint32_t, factors, ARDUINOJSON_EXPAND18({ 0x40240000, 0x00000000, // 1e1 0x40590000, 0x00000000, // 1e2 0x40C38800, 0x00000000, // 1e4 0x4197D784, 0x00000000, // 1e8 0x4341C379, 0x37E08000, // 1e16 0x4693B8B5, 0xB5056E17, // 1e32 0x4D384F03, 0xE93FF9F5, // 1e64 0x5A827748, 0xF9301D32, // 1e128 0x75154FDD, 0x7F73BF3C // 1e256 })); return forge(pgm_read(factors + 2 * index), pgm_read(factors + 2 * index + 1)); } static T negativeBinaryPowerOfTen(int index) { ARDUINOJSON_DEFINE_PROGMEM_ARRAY( // uint32_t, factors, ARDUINOJSON_EXPAND18({ 0x3FB99999, 0x9999999A, // 1e-1 0x3F847AE1, 0x47AE147B, // 1e-2 0x3F1A36E2, 0xEB1C432D, // 1e-4 0x3E45798E, 0xE2308C3A, // 1e-8 0x3C9CD2B2, 0x97D889BC, // 1e-16 0x3949F623, 0xD5A8A733, // 1e-32 0x32A50FFD, 0x44F4A73D, // 1e-64 0x255BBA08, 0xCF8C979D, // 1e-128 0x0AC80628, 0x64AC6F43 // 1e-256 })); return forge(pgm_read(factors + 2 * index), pgm_read(factors + 2 * index + 1)); } static T negativeBinaryPowerOfTenPlusOne(int index) { ARDUINOJSON_DEFINE_PROGMEM_ARRAY( // uint32_t, factors, ARDUINOJSON_EXPAND18({ 0x3FF00000, 0x00000000, // 1e0 0x3FB99999, 0x9999999A, // 1e-1 0x3F50624D, 0xD2F1A9FC, // 1e-3 0x3E7AD7F2, 0x9ABCAF48, // 1e-7 0x3CD203AF, 0x9EE75616, // 1e-15 0x398039D6, 0x65896880, // 1e-31 0x32DA53FC, 0x9631D10D, // 1e-63 0x25915445, 0x81B7DEC2, // 1e-127 0x0AFE07B2, 0x7DD78B14 // 1e-255 })); return forge(pgm_read(factors + 2 * index), pgm_read(factors + 2 * index + 1)); } static T nan() { return forge(0x7ff80000, 0x00000000); } static T inf() { return forge(0x7ff00000, 0x00000000); } static T highest() { return forge(0x7FEFFFFF, 0xFFFFFFFF); } template // int64_t static T highest_for( typename enable_if::value && is_signed::value && sizeof(TOut) == 8, signed>::type* = 0) { return forge(0x43DFFFFF, 0xFFFFFFFF); // 9.2233720368547748e+18 } template // uint64_t static T highest_for( typename enable_if::value && is_unsigned::value && sizeof(TOut) == 8, unsigned>::type* = 0) { return forge(0x43EFFFFF, 0xFFFFFFFF); // 1.8446744073709549568e+19 } static T lowest() { return forge(0xFFEFFFFF, 0xFFFFFFFF); } static T forge(uint32_t msb, uint32_t lsb) { return alias_cast((uint64_t(msb) << 32) | lsb); } }; template struct FloatTraits { typedef uint32_t mantissa_type; static const short mantissa_bits = 23; static const mantissa_type mantissa_max = (mantissa_type(1) << mantissa_bits) - 1; typedef int8_t exponent_type; static const exponent_type exponent_max = 38; template static T make_float(T m, TExponent e) { if (e > 0) { for (uint8_t index = 0; e != 0; index++) { if (e & 1) m *= positiveBinaryPowerOfTen(index); e >>= 1; } } else { e = -e; for (uint8_t index = 0; e != 0; index++) { if (e & 1) m *= negativeBinaryPowerOfTen(index); e >>= 1; } } return m; } static T positiveBinaryPowerOfTen(int index) { ARDUINOJSON_DEFINE_PROGMEM_ARRAY(uint32_t, factors, ARDUINOJSON_EXPAND6({ 0x41200000, // 1e1f 0x42c80000, // 1e2f 0x461c4000, // 1e4f 0x4cbebc20, // 1e8f 0x5a0e1bca, // 1e16f 0x749dc5ae // 1e32f })); return forge(pgm_read(factors + index)); } static T negativeBinaryPowerOfTen(int index) { ARDUINOJSON_DEFINE_PROGMEM_ARRAY(uint32_t, factors, ARDUINOJSON_EXPAND6({ 0x3dcccccd, // 1e-1f 0x3c23d70a, // 1e-2f 0x38d1b717, // 1e-4f 0x322bcc77, // 1e-8f 0x24e69595, // 1e-16f 0x0a4fb11f // 1e-32f })); return forge(pgm_read(factors + index)); } static T negativeBinaryPowerOfTenPlusOne(int index) { ARDUINOJSON_DEFINE_PROGMEM_ARRAY(uint32_t, factors, ARDUINOJSON_EXPAND6({ 0x3f800000, // 1e0f 0x3dcccccd, // 1e-1f 0x3a83126f, // 1e-3f 0x33d6bf95, // 1e-7f 0x26901d7d, // 1e-15f 0x0c01ceb3 // 1e-31f })); return forge(pgm_read(factors + index)); } static T forge(uint32_t bits) { return alias_cast(bits); } static T nan() { return forge(0x7fc00000); } static T inf() { return forge(0x7f800000); } static T highest() { return forge(0x7f7fffff); } template // int32_t static T highest_for( typename enable_if::value && is_signed::value && sizeof(TOut) == 4, signed>::type* = 0) { return forge(0x4EFFFFFF); // 2.14748352E9 } template // uint32_t static T highest_for( typename enable_if::value && is_unsigned::value && sizeof(TOut) == 4, unsigned>::type* = 0) { return forge(0x4F7FFFFF); // 4.29496704E9 } template // int64_t static T highest_for( typename enable_if::value && is_signed::value && sizeof(TOut) == 8, signed>::type* = 0) { return forge(0x5EFFFFFF); // 9.22337148709896192E18 } template // uint64_t static T highest_for( typename enable_if::value && is_unsigned::value && sizeof(TOut) == 8, unsigned>::type* = 0) { return forge(0x5F7FFFFF); // 1.844674297419792384E19 } static T lowest() { return forge(0xFf7fffff); } }; template typename enable_if::value && is_unsigned::value && is_integral::value && sizeof(TOut) <= sizeof(TIn), bool>::type canConvertNumber(TIn value) { return value <= TIn(numeric_limits::highest()); } template typename enable_if::value && is_unsigned::value && is_integral::value && sizeof(TIn) < sizeof(TOut), bool>::type canConvertNumber(TIn) { return true; } template typename enable_if::value && is_floating_point::value, bool>::type canConvertNumber(TIn) { return true; } template typename enable_if::value && is_signed::value && is_integral::value && is_signed::value && sizeof(TOut) < sizeof(TIn), bool>::type canConvertNumber(TIn value) { return value >= TIn(numeric_limits::lowest()) && value <= TIn(numeric_limits::highest()); } template typename enable_if::value && is_signed::value && is_integral::value && is_signed::value && sizeof(TIn) <= sizeof(TOut), bool>::type canConvertNumber(TIn) { return true; } template typename enable_if::value && is_signed::value && is_integral::value && is_unsigned::value && sizeof(TOut) >= sizeof(TIn), bool>::type canConvertNumber(TIn value) { if (value < 0) return false; return TOut(value) <= numeric_limits::highest(); } template typename enable_if::value && is_signed::value && is_integral::value && is_unsigned::value && sizeof(TOut) < sizeof(TIn), bool>::type canConvertNumber(TIn value) { if (value < 0) return false; return value <= TIn(numeric_limits::highest()); } template typename enable_if::value && is_integral::value && sizeof(TOut) < sizeof(TIn), bool>::type canConvertNumber(TIn value) { return value >= numeric_limits::lowest() && value <= numeric_limits::highest(); } template typename enable_if::value && is_integral::value && sizeof(TOut) >= sizeof(TIn), bool>::type canConvertNumber(TIn value) { return value >= numeric_limits::lowest() && value <= FloatTraits::template highest_for(); } template TOut convertNumber(TIn value) { return canConvertNumber(value) ? TOut(value) : 0; } } // namespace ARDUINOJSON_NAMESPACE #if defined(__clang__) # pragma clang diagnostic pop #elif defined(__GNUC__) # if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) # pragma GCC diagnostic pop # endif #endif #if defined(__GNUC__) # if __GNUC__ >= 7 # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" # pragma GCC diagnostic ignored "-Wuninitialized" # endif #endif namespace ARDUINOJSON_NAMESPACE { class VariantData { VariantContent _content; // must be first to allow cast from array to variant uint8_t _flags; public: void init() { _flags = VALUE_IS_NULL; } void operator=(const VariantData& src) { _content = src._content; _flags = uint8_t((_flags & OWNED_KEY_BIT) | (src._flags & ~OWNED_KEY_BIT)); } template typename TVisitor::result_type accept(TVisitor& visitor) const { switch (type()) { case VALUE_IS_FLOAT: return visitor.visitFloat(_content.asFloat); case VALUE_IS_ARRAY: return visitor.visitArray(_content.asCollection); case VALUE_IS_OBJECT: return visitor.visitObject(_content.asCollection); case VALUE_IS_LINKED_STRING: case VALUE_IS_OWNED_STRING: return visitor.visitString(_content.asString.data, _content.asString.size); case VALUE_IS_OWNED_RAW: case VALUE_IS_LINKED_RAW: return visitor.visitRawJson(_content.asString.data, _content.asString.size); case VALUE_IS_SIGNED_INTEGER: return visitor.visitSignedInteger(_content.asSignedInteger); case VALUE_IS_UNSIGNED_INTEGER: return visitor.visitUnsignedInteger(_content.asUnsignedInteger); case VALUE_IS_BOOLEAN: return visitor.visitBoolean(_content.asBoolean != 0); default: return visitor.visitNull(); } } template T asIntegral() const; template T asFloat() const; JsonString asString() const; bool asBoolean() const; CollectionData* asArray() { return isArray() ? &_content.asCollection : 0; } const CollectionData* asArray() const { return const_cast(this)->asArray(); } const CollectionData* asCollection() const { return isCollection() ? &_content.asCollection : 0; } CollectionData* asObject() { return isObject() ? &_content.asCollection : 0; } const CollectionData* asObject() const { return const_cast(this)->asObject(); } bool copyFrom(const VariantData& src, MemoryPool* pool); bool isArray() const { return (_flags & VALUE_IS_ARRAY) != 0; } bool isBoolean() const { return type() == VALUE_IS_BOOLEAN; } bool isCollection() const { return (_flags & COLLECTION_MASK) != 0; } template bool isInteger() const { switch (type()) { case VALUE_IS_UNSIGNED_INTEGER: return canConvertNumber(_content.asUnsignedInteger); case VALUE_IS_SIGNED_INTEGER: return canConvertNumber(_content.asSignedInteger); default: return false; } } bool isFloat() const { return (_flags & NUMBER_BIT) != 0; } bool isString() const { return type() == VALUE_IS_LINKED_STRING || type() == VALUE_IS_OWNED_STRING; } bool isObject() const { return (_flags & VALUE_IS_OBJECT) != 0; } bool isNull() const { return type() == VALUE_IS_NULL; } bool isEnclosed() const { return !isFloat(); } void remove(size_t index) { if (isArray()) _content.asCollection.removeElement(index); } template void remove(TAdaptedString key) { if (isObject()) _content.asCollection.removeMember(key); } void setBoolean(bool value) { setType(VALUE_IS_BOOLEAN); _content.asBoolean = value; } void setFloat(JsonFloat value) { setType(VALUE_IS_FLOAT); _content.asFloat = value; } void setLinkedRaw(SerializedValue value) { if (value.data()) { setType(VALUE_IS_LINKED_RAW); _content.asString.data = value.data(); _content.asString.size = value.size(); } else { setType(VALUE_IS_NULL); } } template bool storeOwnedRaw(SerializedValue value, MemoryPool* pool) { const char* dup = pool->saveString(adaptString(value.data(), value.size())); if (dup) { setType(VALUE_IS_OWNED_RAW); _content.asString.data = dup; _content.asString.size = value.size(); return true; } else { setType(VALUE_IS_NULL); return false; } } template typename enable_if::value>::type setInteger(T value) { setType(VALUE_IS_UNSIGNED_INTEGER); _content.asUnsignedInteger = static_cast(value); } template typename enable_if::value>::type setInteger(T value) { setType(VALUE_IS_SIGNED_INTEGER); _content.asSignedInteger = value; } void setNull() { setType(VALUE_IS_NULL); } void setString(JsonString s) { ARDUINOJSON_ASSERT(s); if (s.isLinked()) setType(VALUE_IS_LINKED_STRING); else setType(VALUE_IS_OWNED_STRING); _content.asString.data = s.c_str(); _content.asString.size = s.size(); } CollectionData& toArray() { setType(VALUE_IS_ARRAY); _content.asCollection.clear(); return _content.asCollection; } CollectionData& toObject() { setType(VALUE_IS_OBJECT); _content.asCollection.clear(); return _content.asCollection; } size_t memoryUsage() const { switch (type()) { case VALUE_IS_OWNED_STRING: case VALUE_IS_OWNED_RAW: return _content.asString.size + 1; case VALUE_IS_OBJECT: case VALUE_IS_ARRAY: return _content.asCollection.memoryUsage(); default: return 0; } } size_t size() const { return isCollection() ? _content.asCollection.size() : 0; } VariantData* addElement(MemoryPool* pool) { if (isNull()) toArray(); if (!isArray()) return 0; return _content.asCollection.addElement(pool); } VariantData* getElement(size_t index) const { const CollectionData* col = asArray(); return col ? col->getElement(index) : 0; } VariantData* getOrAddElement(size_t index, MemoryPool* pool) { if (isNull()) toArray(); if (!isArray()) return 0; return _content.asCollection.getOrAddElement(index, pool); } template VariantData* getMember(TAdaptedString key) const { const CollectionData* col = asObject(); return col ? col->getMember(key) : 0; } template VariantData* getOrAddMember(TAdaptedString key, MemoryPool* pool) { if (isNull()) toObject(); if (!isObject()) return 0; return _content.asCollection.getOrAddMember(key, pool); } void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) { if (_flags & OWNED_VALUE_BIT) _content.asString.data += stringDistance; if (_flags & COLLECTION_MASK) _content.asCollection.movePointers(stringDistance, variantDistance); } uint8_t type() const { return _flags & VALUE_MASK; } template inline bool setString(TAdaptedString value, MemoryPool* pool) { if (value.isNull()) { setNull(); return true; } return storeString(pool, value, VariantStringSetter(this)); } private: void setType(uint8_t t) { _flags &= OWNED_KEY_BIT; _flags |= t; } struct VariantStringSetter { VariantStringSetter(VariantData* instance) : _instance(instance) {} template void operator()(TStoredString s) { if (s) _instance->setString(s); else _instance->setNull(); } VariantData* _instance; }; }; } // namespace ARDUINOJSON_NAMESPACE #if defined(__GNUC__) # if __GNUC__ >= 8 # pragma GCC diagnostic pop # endif #endif namespace ARDUINOJSON_NAMESPACE { template struct Visitor { typedef TResult result_type; TResult visitArray(const CollectionData&) { return TResult(); } TResult visitBoolean(bool) { return TResult(); } TResult visitFloat(JsonFloat) { return TResult(); } TResult visitSignedInteger(JsonInteger) { return TResult(); } TResult visitNull() { return TResult(); } TResult visitObject(const CollectionData&) { return TResult(); } TResult visitUnsignedInteger(JsonUInt) { return TResult(); } TResult visitRawJson(const char*, size_t) { return TResult(); } TResult visitString(const char*, size_t) { return TResult(); } }; template inline typename TVisitor::result_type variantAccept(const VariantData* var, TVisitor& visitor) { if (var != 0) return var->accept(visitor); else return visitor.visitNull(); } inline bool variantCopyFrom(VariantData* dst, const VariantData* src, MemoryPool* pool) { if (!dst) return false; if (!src) { dst->setNull(); return true; } return dst->copyFrom(*src, pool); } inline void variantSetNull(VariantData* var) { if (!var) return; var->setNull(); } template inline bool variantSetString(VariantData* var, TAdaptedString value, MemoryPool* pool) { return var != 0 ? var->setString(value, pool) : 0; } inline size_t variantSize(const VariantData* var) { return var != 0 ? var->size() : 0; } inline CollectionData* variantToArray(VariantData* var) { if (!var) return 0; return &var->toArray(); } inline CollectionData* variantToObject(VariantData* var) { if (!var) return 0; return &var->toObject(); } inline VariantData* variantGetElement(const VariantData* var, size_t index) { return var != 0 ? var->getElement(index) : 0; } inline NO_INLINE VariantData* variantAddElement(VariantData* var, MemoryPool* pool) { return var != 0 ? var->addElement(pool) : 0; } inline NO_INLINE VariantData* variantGetOrAddElement(VariantData* var, size_t index, MemoryPool* pool) { return var != 0 ? var->getOrAddElement(index, pool) : 0; } template VariantData* variantGetMember(const VariantData* var, TAdaptedString key) { if (!var) return 0; return var->getMember(key); } template VariantData* variantGetOrAddMember(VariantData* var, TAdaptedString key, MemoryPool* pool) { if (!var) return 0; return var->getOrAddMember(key, pool); } inline bool variantIsNull(const VariantData* var) { return var == 0 || var->isNull(); } inline size_t variantNesting(const VariantData* var) { if (!var) return 0; const CollectionData* collection = var->asCollection(); if (!collection) return 0; size_t maxChildNesting = 0; for (const VariantSlot* s = collection->head(); s; s = s->next()) { size_t childNesting = variantNesting(s->data()); if (childNesting > maxChildNesting) maxChildNesting = childNesting; } return maxChildNesting + 1; } enum CompareResult { COMPARE_RESULT_DIFFER = 0, COMPARE_RESULT_EQUAL = 1, COMPARE_RESULT_GREATER = 2, COMPARE_RESULT_LESS = 4, COMPARE_RESULT_GREATER_OR_EQUAL = 3, COMPARE_RESULT_LESS_OR_EQUAL = 5 }; template CompareResult arithmeticCompare(const T& lhs, const T& rhs) { if (lhs < rhs) return COMPARE_RESULT_LESS; else if (lhs > rhs) return COMPARE_RESULT_GREATER; else return COMPARE_RESULT_EQUAL; } template CompareResult arithmeticCompare( const T1& lhs, const T2& rhs, typename enable_if::value && is_integral::value && sizeof(T1) < sizeof(T2), int // Using int instead of void to avoid C2572 on >::type* = 0) { return arithmeticCompare(static_cast(lhs), rhs); } template CompareResult arithmeticCompare( const T1& lhs, const T2& rhs, typename enable_if::value && is_integral::value && sizeof(T2) < sizeof(T1)>::type* = 0) { return arithmeticCompare(lhs, static_cast(rhs)); } template CompareResult arithmeticCompare( const T1& lhs, const T2& rhs, typename enable_if::value && is_integral::value && is_signed::value == is_signed::value && sizeof(T2) == sizeof(T1)>::type* = 0) { return arithmeticCompare(lhs, static_cast(rhs)); } template CompareResult arithmeticCompare( const T1& lhs, const T2& rhs, typename enable_if::value && is_integral::value && is_unsigned::value && is_signed::value && sizeof(T2) == sizeof(T1)>::type* = 0) { if (rhs < 0) return COMPARE_RESULT_GREATER; return arithmeticCompare(lhs, static_cast(rhs)); } template CompareResult arithmeticCompare( const T1& lhs, const T2& rhs, typename enable_if::value && is_integral::value && is_signed::value && is_unsigned::value && sizeof(T2) == sizeof(T1)>::type* = 0) { if (lhs < 0) return COMPARE_RESULT_LESS; return arithmeticCompare(static_cast(lhs), rhs); } template CompareResult arithmeticCompare( const T1& lhs, const T2& rhs, typename enable_if::value || is_floating_point::value>::type* = 0) { return arithmeticCompare(static_cast(lhs), static_cast(rhs)); } template CompareResult arithmeticCompareNegateLeft( JsonUInt, const T2&, typename enable_if::value>::type* = 0) { return COMPARE_RESULT_LESS; } template CompareResult arithmeticCompareNegateLeft( JsonUInt lhs, const T2& rhs, typename enable_if::value>::type* = 0) { if (rhs > 0) return COMPARE_RESULT_LESS; return arithmeticCompare(-rhs, static_cast(lhs)); } template CompareResult arithmeticCompareNegateRight( const T1&, JsonUInt, typename enable_if::value>::type* = 0) { return COMPARE_RESULT_GREATER; } template CompareResult arithmeticCompareNegateRight( const T1& lhs, JsonUInt rhs, typename enable_if::value>::type* = 0) { if (lhs > 0) return COMPARE_RESULT_GREATER; return arithmeticCompare(static_cast(rhs), -lhs); } struct VariantTag {}; template struct IsVariant : is_base_of {}; class JsonVariantConst; template CompareResult compare(JsonVariantConst lhs, const T& rhs); // VariantCompare.cpp struct VariantOperatorTag {}; template struct VariantOperators : VariantOperatorTag { template friend typename enable_if::value && !is_array::value, T>::type operator|(const TVariant& variant, const T& defaultValue) { if (variant.template is()) return variant.template as(); else return defaultValue; } friend const char* operator|(const TVariant& variant, const char* defaultValue) { if (variant.template is()) return variant.template as(); else return defaultValue; } template friend typename enable_if::value, JsonVariantConst>::type operator|(const TVariant& variant, T defaultValue) { if (variant) return variant; else return defaultValue; } template friend bool operator==(T* lhs, TVariant rhs) { return compare(rhs, lhs) == COMPARE_RESULT_EQUAL; } template friend bool operator==(const T& lhs, TVariant rhs) { return compare(rhs, lhs) == COMPARE_RESULT_EQUAL; } template friend bool operator==(TVariant lhs, T* rhs) { return compare(lhs, rhs) == COMPARE_RESULT_EQUAL; } template friend typename enable_if::value, bool>::type operator==(TVariant lhs, const T& rhs) { return compare(lhs, rhs) == COMPARE_RESULT_EQUAL; } template friend bool operator!=(T* lhs, TVariant rhs) { return compare(rhs, lhs) != COMPARE_RESULT_EQUAL; } template friend bool operator!=(const T& lhs, TVariant rhs) { return compare(rhs, lhs) != COMPARE_RESULT_EQUAL; } template friend bool operator!=(TVariant lhs, T* rhs) { return compare(lhs, rhs) != COMPARE_RESULT_EQUAL; } template friend typename enable_if::value, bool>::type operator!=(TVariant lhs, const T& rhs) { return compare(lhs, rhs) != COMPARE_RESULT_EQUAL; } template friend bool operator<(T* lhs, TVariant rhs) { return compare(rhs, lhs) == COMPARE_RESULT_GREATER; } template friend bool operator<(const T& lhs, TVariant rhs) { return compare(rhs, lhs) == COMPARE_RESULT_GREATER; } template friend bool operator<(TVariant lhs, T* rhs) { return compare(lhs, rhs) == COMPARE_RESULT_LESS; } template friend typename enable_if::value, bool>::type operator<(TVariant lhs, const T& rhs) { return compare(lhs, rhs) == COMPARE_RESULT_LESS; } template friend bool operator<=(T* lhs, TVariant rhs) { return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; } template friend bool operator<=(const T& lhs, TVariant rhs) { return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; } template friend bool operator<=(TVariant lhs, T* rhs) { return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; } template friend typename enable_if::value, bool>::type operator<=(TVariant lhs, const T& rhs) { return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; } template friend bool operator>(T* lhs, TVariant rhs) { return compare(rhs, lhs) == COMPARE_RESULT_LESS; } template friend bool operator>(const T& lhs, TVariant rhs) { return compare(rhs, lhs) == COMPARE_RESULT_LESS; } template friend bool operator>(TVariant lhs, T* rhs) { return compare(lhs, rhs) == COMPARE_RESULT_GREATER; } template friend typename enable_if::value, bool>::type operator>(TVariant lhs, const T& rhs) { return compare(lhs, rhs) == COMPARE_RESULT_GREATER; } template friend bool operator>=(T* lhs, TVariant rhs) { return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; } template friend bool operator>=(const T& lhs, TVariant rhs) { return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; } template friend bool operator>=(TVariant lhs, T* rhs) { return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; } template friend typename enable_if::value, bool>::type operator>=(TVariant lhs, const T& rhs) { return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; } }; class JsonArray; class JsonObject; class JsonVariantConst : public VariantTag, public VariantOperators { friend class VariantAttorney; public: JsonVariantConst() : _data(0) {} explicit JsonVariantConst(const VariantData* data) : _data(data) {} FORCE_INLINE bool isNull() const { return variantIsNull(_data); } FORCE_INLINE bool isUnbound() const { return !_data; } FORCE_INLINE size_t memoryUsage() const { return _data ? _data->memoryUsage() : 0; } FORCE_INLINE size_t nesting() const { return variantNesting(_data); } size_t size() const { return variantSize(_data); } template FORCE_INLINE typename enable_if::value && !is_same::value, T>::type as() const { return Converter::fromJson(*this); } template FORCE_INLINE typename enable_if::value && !is_same::value, bool>::type is() const { return Converter::checkJson(*this); } template FORCE_INLINE operator T() const { return as(); } FORCE_INLINE JsonVariantConst operator[](size_t index) const { return JsonVariantConst(variantGetElement(_data, index)); } template FORCE_INLINE typename enable_if::value, JsonVariantConst>::type operator[](const TString& key) const { return JsonVariantConst(variantGetMember(_data, adaptString(key))); } template FORCE_INLINE typename enable_if::value, JsonVariantConst>::type operator[](TChar* key) const { return JsonVariantConst(variantGetMember(_data, adaptString(key))); } template FORCE_INLINE typename enable_if::value, bool>::type containsKey(const TString& key) const { return variantGetMember(getData(), adaptString(key)) != 0; } template FORCE_INLINE typename enable_if::value, bool>::type containsKey(TChar* key) const { return variantGetMember(getData(), adaptString(key)) != 0; } protected: const VariantData* getData() const { return _data; } private: const VariantData* _data; }; class JsonVariant; template class ElementProxy; template class MemberProxy; template class VariantRefBase : public VariantTag { friend class VariantAttorney; public: FORCE_INLINE void clear() const { variantSetNull(getData()); } FORCE_INLINE bool isNull() const { return variantIsNull(getData()); } FORCE_INLINE bool isUnbound() const { return !getData(); } template FORCE_INLINE typename enable_if::value, T>::type as() const { return Converter::fromJson(getVariantConst()); } template FORCE_INLINE typename enable_if::value, T>::type as() const { return Converter::fromJson(getVariant()); } template FORCE_INLINE operator T() const { return as(); } template typename enable_if::value, JsonArray>::type to() const; template typename enable_if::value, JsonObject>::type to() const; template typename enable_if::value, JsonVariant>::type to() const; template FORCE_INLINE typename enable_if::value, bool>::type is() const { return Converter::checkJson(getVariant()); } template FORCE_INLINE typename enable_if::value && !is_same::value && !is_same::value, bool>::type is() const { return Converter::checkJson(getVariantConst()); } FORCE_INLINE void shallowCopy(JsonVariantConst target) { VariantData* data = getOrCreateData(); if (!data) return; const VariantData* targetData = VariantAttorney::getData(target); if (targetData) *data = *targetData; else data->setNull(); } template FORCE_INLINE bool set(const T& value) const { Converter::toJson(value, getOrCreateVariant()); MemoryPool* pool = getPool(); return pool && !pool->overflowed(); } template FORCE_INLINE bool set(T* value) const { Converter::toJson(value, getOrCreateVariant()); MemoryPool* pool = getPool(); return pool && !pool->overflowed(); } FORCE_INLINE size_t size() const { return variantSize(getData()); } FORCE_INLINE size_t memoryUsage() const { VariantData* data = getData(); return data ? data->memoryUsage() : 0; } FORCE_INLINE size_t nesting() const { return variantNesting(getData()); } FORCE_INLINE JsonVariant add() const; template FORCE_INLINE bool add(const T& value) const { return add().set(value); } template FORCE_INLINE bool add(T* value) const { return add().set(value); } FORCE_INLINE void remove(size_t index) const { VariantData* data = getData(); if (data) data->remove(index); } template FORCE_INLINE typename enable_if::value>::type remove( TChar* key) const { VariantData* data = getData(); if (data) data->remove(adaptString(key)); } template FORCE_INLINE typename enable_if::value>::type remove( const TString& key) const { VariantData* data = getData(); if (data) data->remove(adaptString(key)); } FORCE_INLINE JsonArray createNestedArray() const; FORCE_INLINE JsonObject createNestedObject() const; FORCE_INLINE ElementProxy operator[](size_t index) const; template FORCE_INLINE typename enable_if::value, bool>::type containsKey(const TString& key) const; template FORCE_INLINE typename enable_if::value, bool>::type containsKey(TChar* key) const; template FORCE_INLINE typename enable_if::value, MemberProxy >::type operator[](const TString& key) const; template FORCE_INLINE typename enable_if::value, MemberProxy >::type operator[](TChar* key) const; template FORCE_INLINE JsonArray createNestedArray(const TString& key) const; template FORCE_INLINE JsonArray createNestedArray(TChar* key) const; template JsonObject createNestedObject(const TString& key) const; template JsonObject createNestedObject(TChar* key) const; private: TDerived& derived() { return static_cast(*this); } const TDerived& derived() const { return static_cast(*this); } FORCE_INLINE MemoryPool* getPool() const { return VariantAttorney::getPool(derived()); } FORCE_INLINE VariantData* getData() const { return VariantAttorney::getData(derived()); } FORCE_INLINE VariantData* getOrCreateData() const { return VariantAttorney::getOrCreateData(derived()); } private: FORCE_INLINE JsonVariant getVariant() const; FORCE_INLINE JsonVariantConst getVariantConst() const { return JsonVariantConst(getData()); } FORCE_INLINE JsonVariant getOrCreateVariant() const; }; template class ElementProxy : public VariantRefBase >, public VariantOperators > { friend class VariantAttorney; public: ElementProxy(TUpstream upstream, size_t index) : _upstream(upstream), _index(index) {} ElementProxy(const ElementProxy& src) : _upstream(src._upstream), _index(src._index) {} FORCE_INLINE ElementProxy& operator=(const ElementProxy& src) { this->set(src); return *this; } template FORCE_INLINE ElementProxy& operator=(const T& src) { this->set(src); return *this; } template FORCE_INLINE ElementProxy& operator=(T* src) { this->set(src); return *this; } private: FORCE_INLINE MemoryPool* getPool() const { return VariantAttorney::getPool(_upstream); } FORCE_INLINE VariantData* getData() const { return variantGetElement(VariantAttorney::getData(_upstream), _index); } FORCE_INLINE VariantData* getOrCreateData() const { return variantGetOrAddElement(VariantAttorney::getOrCreateData(_upstream), _index, VariantAttorney::getPool(_upstream)); } TUpstream _upstream; size_t _index; }; class JsonVariant : public VariantRefBase, public VariantOperators { friend class VariantAttorney; public: JsonVariant() : _data(0), _pool(0) {} JsonVariant(MemoryPool* pool, VariantData* data) : _data(data), _pool(pool) {} private: FORCE_INLINE MemoryPool* getPool() const { return _pool; } FORCE_INLINE VariantData* getData() const { return _data; } FORCE_INLINE VariantData* getOrCreateData() const { return _data; } VariantData* _data; MemoryPool* _pool; }; template <> struct Converter : private VariantAttorney { static void toJson(JsonVariant src, JsonVariant dst) { variantCopyFrom(getData(dst), getData(src), getPool(dst)); } static JsonVariant fromJson(JsonVariant src) { return src; } static InvalidConversion fromJson( JsonVariantConst); static bool checkJson(JsonVariant src) { VariantData* data = getData(src); return !!data; } static bool checkJson(JsonVariantConst) { return false; } }; template <> struct Converter : private VariantAttorney { static void toJson(JsonVariantConst src, JsonVariant dst) { variantCopyFrom(getData(dst), getData(src), getPool(dst)); } static JsonVariantConst fromJson(JsonVariantConst src) { return JsonVariantConst(getData(src)); } static bool checkJson(JsonVariantConst src) { const VariantData* data = getData(src); return !!data; } }; struct SlotKeySetter { SlotKeySetter(VariantSlot* instance) : _instance(instance) {} template void operator()(TStoredString s) { if (!s) return; ARDUINOJSON_ASSERT(_instance != 0); _instance->setKey(s); } VariantSlot* _instance; }; template inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool) { if (!var) return false; return storeString(pool, key, SlotKeySetter(var)); } inline size_t slotSize(const VariantSlot* var) { size_t n = 0; while (var) { n++; var = var->next(); } return n; } inline VariantData* slotData(VariantSlot* slot) { return reinterpret_cast(slot); } class VariantPtr { public: VariantPtr(MemoryPool* pool, VariantData* data) : _variant(pool, data) {} JsonVariant* operator->() { return &_variant; } JsonVariant& operator*() { return _variant; } private: JsonVariant _variant; }; class JsonArrayIterator { friend class JsonArray; public: JsonArrayIterator() : _slot(0) {} explicit JsonArrayIterator(MemoryPool* pool, VariantSlot* slot) : _pool(pool), _slot(slot) {} JsonVariant operator*() const { return JsonVariant(_pool, _slot->data()); } VariantPtr operator->() { return VariantPtr(_pool, _slot->data()); } bool operator==(const JsonArrayIterator& other) const { return _slot == other._slot; } bool operator!=(const JsonArrayIterator& other) const { return _slot != other._slot; } JsonArrayIterator& operator++() { _slot = _slot->next(); return *this; } JsonArrayIterator& operator+=(size_t distance) { _slot = _slot->next(distance); return *this; } private: MemoryPool* _pool; VariantSlot* _slot; }; class VariantConstPtr { public: VariantConstPtr(const VariantData* data) : _variant(data) {} JsonVariantConst* operator->() { return &_variant; } JsonVariantConst& operator*() { return _variant; } private: JsonVariantConst _variant; }; class JsonArrayConstIterator { friend class JsonArray; public: JsonArrayConstIterator() : _slot(0) {} explicit JsonArrayConstIterator(const VariantSlot* slot) : _slot(slot) {} JsonVariantConst operator*() const { return JsonVariantConst(_slot->data()); } VariantConstPtr operator->() { return VariantConstPtr(_slot->data()); } bool operator==(const JsonArrayConstIterator& other) const { return _slot == other._slot; } bool operator!=(const JsonArrayConstIterator& other) const { return _slot != other._slot; } JsonArrayConstIterator& operator++() { _slot = _slot->next(); return *this; } JsonArrayConstIterator& operator+=(size_t distance) { _slot = _slot->next(distance); return *this; } private: const VariantSlot* _slot; }; class JsonObject; class JsonArrayConst : public VariantOperators { friend class JsonArray; friend class VariantAttorney; public: typedef JsonArrayConstIterator iterator; FORCE_INLINE iterator begin() const { if (!_data) return iterator(); return iterator(_data->head()); } FORCE_INLINE iterator end() const { return iterator(); } FORCE_INLINE JsonArrayConst() : _data(0) {} FORCE_INLINE JsonArrayConst(const CollectionData* data) : _data(data) {} FORCE_INLINE bool operator==(JsonArrayConst rhs) const { if (_data == rhs._data) return true; if (!_data || !rhs._data) return false; iterator it1 = begin(); iterator it2 = rhs.begin(); for (;;) { bool end1 = it1 == end(); bool end2 = it2 == rhs.end(); if (end1 && end2) return true; if (end1 || end2) return false; if (*it1 != *it2) return false; ++it1; ++it2; } } FORCE_INLINE JsonVariantConst operator[](size_t index) const { return JsonVariantConst(_data ? _data->getElement(index) : 0); } operator JsonVariantConst() const { return JsonVariantConst(collectionToVariant(_data)); } FORCE_INLINE bool isNull() const { return _data == 0; } FORCE_INLINE operator bool() const { return _data != 0; } FORCE_INLINE size_t memoryUsage() const { return _data ? _data->memoryUsage() : 0; } FORCE_INLINE size_t nesting() const { return variantNesting(collectionToVariant(_data)); } FORCE_INLINE size_t size() const { return _data ? _data->size() : 0; } private: const VariantData* getData() const { return collectionToVariant(_data); } const CollectionData* _data; }; template <> struct Converter : private VariantAttorney { static void toJson(JsonVariantConst src, JsonVariant dst) { variantCopyFrom(getData(dst), getData(src), getPool(dst)); } static JsonArrayConst fromJson(JsonVariantConst src) { const VariantData* data = getData(src); return data ? data->asArray() : 0; } static bool checkJson(JsonVariantConst src) { const VariantData* data = getData(src); return data && data->isArray(); } }; class JsonObject; class JsonArray : public VariantOperators { friend class VariantAttorney; public: typedef JsonArrayIterator iterator; FORCE_INLINE JsonArray() : _data(0), _pool(0) {} FORCE_INLINE JsonArray(MemoryPool* pool, CollectionData* data) : _data(data), _pool(pool) {} operator JsonVariant() { void* data = _data; // prevent warning cast-align return JsonVariant(_pool, reinterpret_cast(data)); } operator JsonArrayConst() const { return JsonArrayConst(_data); } JsonVariant add() const { if (!_data) return JsonVariant(); return JsonVariant(_pool, _data->addElement(_pool)); } template FORCE_INLINE bool add(const T& value) const { return add().set(value); } template FORCE_INLINE bool add(T* value) const { return add().set(value); } FORCE_INLINE iterator begin() const { if (!_data) return iterator(); return iterator(_pool, _data->head()); } FORCE_INLINE iterator end() const { return iterator(); } FORCE_INLINE bool set(JsonArrayConst src) const { if (!_data || !src._data) return false; return _data->copyFrom(*src._data, _pool); } FORCE_INLINE bool operator==(JsonArray rhs) const { return JsonArrayConst(_data) == JsonArrayConst(rhs._data); } FORCE_INLINE void remove(iterator it) const { if (!_data) return; _data->removeSlot(it._slot); } FORCE_INLINE void remove(size_t index) const { if (!_data) return; _data->removeElement(index); } void clear() const { if (!_data) return; _data->clear(); } FORCE_INLINE ElementProxy operator[](size_t index) const { return ElementProxy(*this, index); } FORCE_INLINE JsonObject createNestedObject() const; FORCE_INLINE JsonArray createNestedArray() const { return add().to(); } operator JsonVariantConst() const { return JsonVariantConst(collectionToVariant(_data)); } FORCE_INLINE bool isNull() const { return _data == 0; } FORCE_INLINE operator bool() const { return _data != 0; } FORCE_INLINE size_t memoryUsage() const { return _data ? _data->memoryUsage() : 0; } FORCE_INLINE size_t nesting() const { return variantNesting(collectionToVariant(_data)); } FORCE_INLINE size_t size() const { return _data ? _data->size() : 0; } private: MemoryPool* getPool() const { return _pool; } VariantData* getData() const { return collectionToVariant(_data); } VariantData* getOrCreateData() const { return collectionToVariant(_data); } CollectionData* _data; MemoryPool* _pool; }; template <> struct Converter : private VariantAttorney { static void toJson(JsonVariantConst src, JsonVariant dst) { variantCopyFrom(getData(dst), getData(src), getPool(dst)); } static JsonArray fromJson(JsonVariant src) { VariantData* data = getData(src); MemoryPool* pool = getPool(src); return JsonArray(pool, data != 0 ? data->asArray() : 0); } static InvalidConversion fromJson( JsonVariantConst); static bool checkJson(JsonVariantConst) { return false; } static bool checkJson(JsonVariant src) { VariantData* data = getData(src); return data && data->isArray(); } }; class JsonPair { public: JsonPair(MemoryPool* pool, VariantSlot* slot) { if (slot) { _key = JsonString(slot->key(), slot->ownsKey() ? JsonString::Copied : JsonString::Linked); _value = JsonVariant(pool, slot->data()); } } JsonString key() const { return _key; } JsonVariant value() const { return _value; } private: JsonString _key; JsonVariant _value; }; class JsonPairConst { public: JsonPairConst(const VariantSlot* slot) { if (slot) { _key = JsonString(slot->key(), slot->ownsKey() ? JsonString::Copied : JsonString::Linked); _value = JsonVariantConst(slot->data()); } } JsonString key() const { return _key; } JsonVariantConst value() const { return _value; } private: JsonString _key; JsonVariantConst _value; }; class JsonPairPtr { public: JsonPairPtr(MemoryPool* pool, VariantSlot* slot) : _pair(pool, slot) {} const JsonPair* operator->() const { return &_pair; } const JsonPair& operator*() const { return _pair; } private: JsonPair _pair; }; class JsonObjectIterator { friend class JsonObject; public: JsonObjectIterator() : _slot(0) {} explicit JsonObjectIterator(MemoryPool* pool, VariantSlot* slot) : _pool(pool), _slot(slot) {} JsonPair operator*() const { return JsonPair(_pool, _slot); } JsonPairPtr operator->() { return JsonPairPtr(_pool, _slot); } bool operator==(const JsonObjectIterator& other) const { return _slot == other._slot; } bool operator!=(const JsonObjectIterator& other) const { return _slot != other._slot; } JsonObjectIterator& operator++() { _slot = _slot->next(); return *this; } JsonObjectIterator& operator+=(size_t distance) { _slot = _slot->next(distance); return *this; } private: MemoryPool* _pool; VariantSlot* _slot; }; class JsonPairConstPtr { public: JsonPairConstPtr(const VariantSlot* slot) : _pair(slot) {} const JsonPairConst* operator->() const { return &_pair; } const JsonPairConst& operator*() const { return _pair; } private: JsonPairConst _pair; }; class JsonObjectConstIterator { friend class JsonObject; public: JsonObjectConstIterator() : _slot(0) {} explicit JsonObjectConstIterator(const VariantSlot* slot) : _slot(slot) {} JsonPairConst operator*() const { return JsonPairConst(_slot); } JsonPairConstPtr operator->() { return JsonPairConstPtr(_slot); } bool operator==(const JsonObjectConstIterator& other) const { return _slot == other._slot; } bool operator!=(const JsonObjectConstIterator& other) const { return _slot != other._slot; } JsonObjectConstIterator& operator++() { _slot = _slot->next(); return *this; } JsonObjectConstIterator& operator+=(size_t distance) { _slot = _slot->next(distance); return *this; } private: const VariantSlot* _slot; }; class JsonObjectConst : public VariantOperators { friend class JsonObject; friend class VariantAttorney; public: typedef JsonObjectConstIterator iterator; JsonObjectConst() : _data(0) {} JsonObjectConst(const CollectionData* data) : _data(data) {} operator JsonVariantConst() const { return JsonVariantConst(collectionToVariant(_data)); } FORCE_INLINE bool isNull() const { return _data == 0; } FORCE_INLINE operator bool() const { return _data != 0; } FORCE_INLINE size_t memoryUsage() const { return _data ? _data->memoryUsage() : 0; } FORCE_INLINE size_t nesting() const { return variantNesting(collectionToVariant(_data)); } FORCE_INLINE size_t size() const { return _data ? _data->size() : 0; } FORCE_INLINE iterator begin() const { if (!_data) return iterator(); return iterator(_data->head()); } FORCE_INLINE iterator end() const { return iterator(); } template FORCE_INLINE bool containsKey(const TString& key) const { return getMember(adaptString(key)) != 0; } template FORCE_INLINE bool containsKey(TChar* key) const { return getMember(adaptString(key)) != 0; } template FORCE_INLINE typename enable_if::value, JsonVariantConst>::type operator[](const TString& key) const { return JsonVariantConst(getMember(adaptString(key))); } template FORCE_INLINE typename enable_if::value, JsonVariantConst>::type operator[](TChar* key) const { return JsonVariantConst(getMember(adaptString(key))); } FORCE_INLINE bool operator==(JsonObjectConst rhs) const { if (_data == rhs._data) return true; if (!_data || !rhs._data) return false; size_t count = 0; for (iterator it = begin(); it != end(); ++it) { if (it->value() != rhs[it->key()]) return false; count++; } return count == rhs.size(); } private: const VariantData* getData() const { return collectionToVariant(_data); } template const VariantData* getMember(TAdaptedString key) const { if (!_data) return 0; return _data->getMember(key); } const CollectionData* _data; }; template <> struct Converter : private VariantAttorney { static void toJson(JsonVariantConst src, JsonVariant dst) { variantCopyFrom(getData(dst), getData(src), getPool(dst)); } static JsonObjectConst fromJson(JsonVariantConst src) { const VariantData* data = getData(src); return data != 0 ? data->asObject() : 0; } static bool checkJson(JsonVariantConst src) { const VariantData* data = getData(src); return data && data->isObject(); } }; template class MemberProxy : public VariantRefBase >, public VariantOperators > { friend class VariantAttorney; public: FORCE_INLINE MemberProxy(TUpstream upstream, TStringRef key) : _upstream(upstream), _key(key) {} MemberProxy(const MemberProxy& src) : _upstream(src._upstream), _key(src._key) {} FORCE_INLINE MemberProxy& operator=(const MemberProxy& src) { this->set(src); return *this; } template FORCE_INLINE MemberProxy& operator=(const T& src) { this->set(src); return *this; } template FORCE_INLINE MemberProxy& operator=(T* src) { this->set(src); return *this; } private: FORCE_INLINE MemoryPool* getPool() const { return VariantAttorney::getPool(_upstream); } FORCE_INLINE VariantData* getData() const { return variantGetMember(VariantAttorney::getData(_upstream), adaptString(_key)); } FORCE_INLINE VariantData* getOrCreateData() const { return variantGetOrAddMember(VariantAttorney::getOrCreateData(_upstream), adaptString(_key), VariantAttorney::getPool(_upstream)); } private: TUpstream _upstream; TStringRef _key; }; class JsonArray; class JsonObject : public VariantOperators { friend class VariantAttorney; public: typedef JsonObjectIterator iterator; FORCE_INLINE JsonObject() : _data(0), _pool(0) {} FORCE_INLINE JsonObject(MemoryPool* buf, CollectionData* data) : _data(data), _pool(buf) {} operator JsonVariant() const { void* data = _data; // prevent warning cast-align return JsonVariant(_pool, reinterpret_cast(data)); } operator JsonObjectConst() const { return JsonObjectConst(_data); } operator JsonVariantConst() const { return JsonVariantConst(collectionToVariant(_data)); } FORCE_INLINE bool isNull() const { return _data == 0; } FORCE_INLINE operator bool() const { return _data != 0; } FORCE_INLINE size_t memoryUsage() const { return _data ? _data->memoryUsage() : 0; } FORCE_INLINE size_t nesting() const { return variantNesting(collectionToVariant(_data)); } FORCE_INLINE size_t size() const { return _data ? _data->size() : 0; } FORCE_INLINE iterator begin() const { if (!_data) return iterator(); return iterator(_pool, _data->head()); } FORCE_INLINE iterator end() const { return iterator(); } void clear() const { if (!_data) return; _data->clear(); } FORCE_INLINE bool set(JsonObjectConst src) { if (!_data || !src._data) return false; return _data->copyFrom(*src._data, _pool); } FORCE_INLINE bool operator==(JsonObject rhs) const { return JsonObjectConst(_data) == JsonObjectConst(rhs._data); } template FORCE_INLINE typename enable_if::value, MemberProxy >::type operator[](const TString& key) const { return MemberProxy(*this, key); } template FORCE_INLINE typename enable_if::value, MemberProxy >::type operator[](TChar* key) const { return MemberProxy(*this, key); } FORCE_INLINE void remove(iterator it) const { if (!_data) return; _data->removeSlot(it._slot); } template FORCE_INLINE void remove(const TString& key) const { removeMember(adaptString(key)); } template FORCE_INLINE void remove(TChar* key) const { removeMember(adaptString(key)); } template FORCE_INLINE typename enable_if::value, bool>::type containsKey(const TString& key) const { return getMember(adaptString(key)) != 0; } template FORCE_INLINE typename enable_if::value, bool>::type containsKey(TChar* key) const { return getMember(adaptString(key)) != 0; } template FORCE_INLINE JsonArray createNestedArray(const TString& key) const; template FORCE_INLINE JsonArray createNestedArray(TChar* key) const; template JsonObject createNestedObject(const TString& key) const { return operator[](key).template to(); } template JsonObject createNestedObject(TChar* key) const { return operator[](key).template to(); } private: MemoryPool* getPool() const { return _pool; } VariantData* getData() const { return collectionToVariant(_data); } VariantData* getOrCreateData() const { return collectionToVariant(_data); } template inline VariantData* getMember(TAdaptedString key) const { if (!_data) return 0; return _data->getMember(key); } template void removeMember(TAdaptedString key) const { if (!_data) return; _data->removeMember(key); } CollectionData* _data; MemoryPool* _pool; }; template <> struct Converter : private VariantAttorney { static void toJson(JsonVariantConst src, JsonVariant dst) { variantCopyFrom(getData(dst), getData(src), getPool(dst)); } static JsonObject fromJson(JsonVariant src) { VariantData* data = getData(src); MemoryPool* pool = getPool(src); return JsonObject(pool, data != 0 ? data->asObject() : 0); } static InvalidConversion fromJson( JsonVariantConst); static bool checkJson(JsonVariantConst) { return false; } static bool checkJson(JsonVariant src) { VariantData* data = getData(src); return data && data->isObject(); } }; class JsonDocument : public VariantOperators { friend class VariantAttorney; public: template T as() { return getVariant().template as(); } template T as() const { return getVariant().template as(); } void clear() { _pool.clear(); _data.init(); } template bool is() { return getVariant().template is(); } template bool is() const { return getVariant().template is(); } bool isNull() const { return getVariant().isNull(); } size_t memoryUsage() const { return _pool.size(); } bool overflowed() const { return _pool.overflowed(); } size_t nesting() const { return variantNesting(&_data); } size_t capacity() const { return _pool.capacity(); } size_t size() const { return _data.size(); } bool set(const JsonDocument& src) { return to().set(src.as()); } template typename enable_if::value, bool>::type set( const T& src) { return to().set(src); } template typename VariantTo::type to() { clear(); return getVariant().template to(); } JsonArray createNestedArray() { return add().to(); } template JsonArray createNestedArray(TChar* key) { return operator[](key).template to(); } template JsonArray createNestedArray(const TString& key) { return operator[](key).template to(); } JsonObject createNestedObject() { return add().to(); } template JsonObject createNestedObject(TChar* key) { return operator[](key).template to(); } template JsonObject createNestedObject(const TString& key) { return operator[](key).template to(); } template bool containsKey(TChar* key) const { return _data.getMember(adaptString(key)) != 0; } template bool containsKey(const TString& key) const { return _data.getMember(adaptString(key)) != 0; } template FORCE_INLINE typename enable_if::value, MemberProxy >::type operator[](const TString& key) { return MemberProxy(*this, key); } template FORCE_INLINE typename enable_if::value, MemberProxy >::type operator[](TChar* key) { return MemberProxy(*this, key); } template FORCE_INLINE typename enable_if::value, JsonVariantConst>::type operator[](const TString& key) const { return JsonVariantConst(_data.getMember(adaptString(key))); } template FORCE_INLINE typename enable_if::value, JsonVariantConst>::type operator[](TChar* key) const { return JsonVariantConst(_data.getMember(adaptString(key))); } FORCE_INLINE ElementProxy operator[](size_t index) { return ElementProxy(*this, index); } FORCE_INLINE JsonVariantConst operator[](size_t index) const { return JsonVariantConst(_data.getElement(index)); } FORCE_INLINE JsonVariant add() { return JsonVariant(&_pool, _data.addElement(&_pool)); } template FORCE_INLINE bool add(const TValue& value) { return add().set(value); } template FORCE_INLINE bool add(TChar* value) { return add().set(value); } FORCE_INLINE void remove(size_t index) { _data.remove(index); } template FORCE_INLINE typename enable_if::value>::type remove( TChar* key) { _data.remove(adaptString(key)); } template FORCE_INLINE typename enable_if::value>::type remove( const TString& key) { _data.remove(adaptString(key)); } FORCE_INLINE operator JsonVariant() { return getVariant(); } FORCE_INLINE operator JsonVariantConst() const { return getVariant(); } protected: JsonDocument() : _pool(0, 0) { _data.init(); } JsonDocument(MemoryPool pool) : _pool(pool) { _data.init(); } JsonDocument(char* buf, size_t capa) : _pool(buf, capa) { _data.init(); } ~JsonDocument() {} void replacePool(MemoryPool pool) { _pool = pool; } JsonVariant getVariant() { return JsonVariant(&_pool, &_data); } JsonVariantConst getVariant() const { return JsonVariantConst(&_data); } MemoryPool _pool; VariantData _data; private: JsonDocument(const JsonDocument&); JsonDocument& operator=(const JsonDocument&); protected: MemoryPool* getPool() { return &_pool; } VariantData* getData() { return &_data; } const VariantData* getData() const { return &_data; } VariantData* getOrCreateData() { return &_data; } }; inline void convertToJson(const JsonDocument& src, JsonVariant dst) { dst.set(src.as()); } template class AllocatorOwner { public: AllocatorOwner() {} AllocatorOwner(TAllocator a) : _allocator(a) {} void* allocate(size_t size) { return _allocator.allocate(size); } void deallocate(void* ptr) { if (ptr) _allocator.deallocate(ptr); } void* reallocate(void* ptr, size_t new_size) { return _allocator.reallocate(ptr, new_size); } TAllocator& allocator() { return _allocator; } private: TAllocator _allocator; }; template class BasicJsonDocument : AllocatorOwner, public JsonDocument { public: explicit BasicJsonDocument(size_t capa, TAllocator alloc = TAllocator()) : AllocatorOwner(alloc), JsonDocument(allocPool(capa)) {} BasicJsonDocument(const BasicJsonDocument& src) : AllocatorOwner(src), JsonDocument() { copyAssignFrom(src); } #if ARDUINOJSON_HAS_RVALUE_REFERENCES BasicJsonDocument(BasicJsonDocument&& src) : AllocatorOwner(src) { moveAssignFrom(src); } #endif BasicJsonDocument(const JsonDocument& src) { copyAssignFrom(src); } template BasicJsonDocument( const T& src, typename enable_if< is_same::value || is_same::value || is_same::value || is_same::value || is_same::value || is_same::value>::type* = 0) : JsonDocument(allocPool(src.memoryUsage())) { set(src); } BasicJsonDocument(JsonVariant src) : JsonDocument(allocPool(src.memoryUsage())) { set(src); } ~BasicJsonDocument() { freePool(); } BasicJsonDocument& operator=(const BasicJsonDocument& src) { copyAssignFrom(src); return *this; } #if ARDUINOJSON_HAS_RVALUE_REFERENCES BasicJsonDocument& operator=(BasicJsonDocument&& src) { moveAssignFrom(src); return *this; } #endif template BasicJsonDocument& operator=(const T& src) { size_t requiredSize = src.memoryUsage(); if (requiredSize > capacity()) reallocPool(requiredSize); set(src); return *this; } void shrinkToFit() { ptrdiff_t bytes_reclaimed = _pool.squash(); if (bytes_reclaimed == 0) return; void* old_ptr = _pool.buffer(); void* new_ptr = this->reallocate(old_ptr, _pool.capacity()); ptrdiff_t ptr_offset = static_cast(new_ptr) - static_cast(old_ptr); _pool.movePointers(ptr_offset); _data.movePointers(ptr_offset, ptr_offset - bytes_reclaimed); } bool garbageCollect() { BasicJsonDocument tmp(*this); if (!tmp.capacity()) return false; tmp.set(*this); moveAssignFrom(tmp); return true; } using AllocatorOwner::allocator; private: MemoryPool allocPool(size_t requiredSize) { size_t capa = addPadding(requiredSize); return MemoryPool(reinterpret_cast(this->allocate(capa)), capa); } void reallocPool(size_t requiredSize) { size_t capa = addPadding(requiredSize); if (capa == _pool.capacity()) return; freePool(); replacePool(allocPool(addPadding(requiredSize))); } void freePool() { this->deallocate(getPool()->buffer()); } void copyAssignFrom(const JsonDocument& src) { reallocPool(src.capacity()); set(src); } void moveAssignFrom(BasicJsonDocument& src) { freePool(); _data = src._data; _pool = src._pool; src._data.setNull(); src._pool = MemoryPool(0, 0); } }; struct DefaultAllocator { void* allocate(size_t size) { return malloc(size); } void deallocate(void* ptr) { free(ptr); } void* reallocate(void* ptr, size_t new_size) { return realloc(ptr, new_size); } }; typedef BasicJsonDocument DynamicJsonDocument; template class StaticJsonDocument : public JsonDocument { static const size_t _capacity = AddPadding::value>::value; public: StaticJsonDocument() : JsonDocument(_buffer, _capacity) {} StaticJsonDocument(const StaticJsonDocument& src) : JsonDocument(_buffer, _capacity) { set(src); } template StaticJsonDocument( const T& src, typename enable_if::value>::type* = 0) : JsonDocument(_buffer, _capacity) { set(src); } StaticJsonDocument(JsonVariant src) : JsonDocument(_buffer, _capacity) { set(src); } StaticJsonDocument& operator=(const StaticJsonDocument& src) { set(src); return *this; } template StaticJsonDocument& operator=(const T& src) { set(src); return *this; } void garbageCollect() { StaticJsonDocument tmp(*this); set(tmp); } private: char _buffer[_capacity]; }; inline JsonObject JsonArray::createNestedObject() const { return add().to(); } template inline JsonArray VariantRefBase::createNestedArray() const { return add().template to(); } template inline JsonObject VariantRefBase::createNestedObject() const { return add().template to(); } template inline ElementProxy VariantRefBase::operator[]( size_t index) const { return ElementProxy(derived(), index); } template inline typename enable_if::value, bool>::type copyArray( const T& src, JsonVariant dst) { return dst.set(src); } template inline typename enable_if::value, bool>::type copyArray(T (&src)[N], const TDestination& dst) { return copyArray(src, N, dst); } template inline typename enable_if::value, bool>::type copyArray(const T* src, size_t len, const TDestination& dst) { bool ok = true; for (size_t i = 0; i < len; i++) { ok &= copyArray(src[i], dst.add()); } return ok; } template inline bool copyArray(const char* src, size_t, const TDestination& dst) { return dst.set(src); } template inline bool copyArray(const T& src, JsonDocument& dst) { return copyArray(src, dst.to()); } template inline bool copyArray(const T* src, size_t len, JsonDocument& dst) { return copyArray(src, len, dst.to()); } template inline typename enable_if::value, size_t>::type copyArray( JsonVariantConst src, T& dst) { dst = src.as(); return 1; } template inline size_t copyArray(JsonArrayConst src, T (&dst)[N]) { return copyArray(src, dst, N); } template inline size_t copyArray(JsonArrayConst src, T* dst, size_t len) { size_t i = 0; for (JsonArrayConst::iterator it = src.begin(); it != src.end() && i < len; ++it) copyArray(*it, dst[i++]); return i; } template inline size_t copyArray(JsonVariantConst src, char (&dst)[N]) { JsonString s = src; size_t len = N - 1; if (len > s.size()) len = s.size(); memcpy(dst, s.c_str(), len); dst[len] = 0; return 1; } template inline typename enable_if::value && is_base_of::value, size_t>::type copyArray(const TSource& src, T& dst) { return copyArray(src.template as(), dst); } inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) { VariantSlot* slot = pool->allocVariant(); if (!slot) return 0; if (_tail) { ARDUINOJSON_ASSERT(pool->owns(_tail)); // Can't alter a linked array/object _tail->setNextNotNull(slot); _tail = slot; } else { _head = slot; _tail = slot; } slot->clear(); return slot; } inline VariantData* CollectionData::addElement(MemoryPool* pool) { return slotData(addSlot(pool)); } template inline VariantData* CollectionData::addMember(TAdaptedString key, MemoryPool* pool) { VariantSlot* slot = addSlot(pool); if (!slotSetKey(slot, key, pool)) { removeSlot(slot); return 0; } return slot->data(); } inline void CollectionData::clear() { _head = 0; _tail = 0; } template inline bool CollectionData::containsKey(const TAdaptedString& key) const { return getSlot(key) != 0; } inline bool CollectionData::copyFrom(const CollectionData& src, MemoryPool* pool) { clear(); for (VariantSlot* s = src._head; s; s = s->next()) { VariantData* var; if (s->key() != 0) { JsonString key(s->key(), s->ownsKey() ? JsonString::Copied : JsonString::Linked); var = addMember(adaptString(key), pool); } else { var = addElement(pool); } if (!var) return false; if (!var->copyFrom(*s->data(), pool)) return false; } return true; } template inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const { if (key.isNull()) return 0; VariantSlot* slot = _head; while (slot) { if (stringEquals(key, adaptString(slot->key()))) break; slot = slot->next(); } return slot; } inline VariantSlot* CollectionData::getSlot(size_t index) const { if (!_head) return 0; return _head->next(index); } inline VariantSlot* CollectionData::getPreviousSlot(VariantSlot* target) const { VariantSlot* current = _head; while (current) { VariantSlot* next = current->next(); if (next == target) return current; current = next; } return 0; } template inline VariantData* CollectionData::getMember(TAdaptedString key) const { VariantSlot* slot = getSlot(key); return slot ? slot->data() : 0; } template inline VariantData* CollectionData::getOrAddMember(TAdaptedString key, MemoryPool* pool) { if (key.isNull()) return 0; VariantSlot* slot = getSlot(key); if (slot) return slot->data(); return addMember(key, pool); } inline VariantData* CollectionData::getElement(size_t index) const { VariantSlot* slot = getSlot(index); return slot ? slot->data() : 0; } inline VariantData* CollectionData::getOrAddElement(size_t index, MemoryPool* pool) { VariantSlot* slot = _head; while (slot && index > 0) { slot = slot->next(); index--; } if (!slot) index++; while (index > 0) { slot = addSlot(pool); index--; } return slotData(slot); } inline void CollectionData::removeSlot(VariantSlot* slot) { if (!slot) return; VariantSlot* prev = getPreviousSlot(slot); VariantSlot* next = slot->next(); if (prev) prev->setNext(next); else _head = next; if (!next) _tail = prev; } inline void CollectionData::removeElement(size_t index) { removeSlot(getSlot(index)); } inline size_t CollectionData::memoryUsage() const { size_t total = 0; for (VariantSlot* s = _head; s; s = s->next()) { total += sizeof(VariantSlot) + s->data()->memoryUsage(); if (s->ownsKey()) total += strlen(s->key()) + 1; } return total; } inline size_t CollectionData::size() const { return slotSize(_head); } template inline void movePointer(T*& p, ptrdiff_t offset) { if (!p) return; p = reinterpret_cast( reinterpret_cast(reinterpret_cast(p) + offset)); ARDUINOJSON_ASSERT(isAligned(p)); } inline void CollectionData::movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) { movePointer(_head, variantDistance); movePointer(_tail, variantDistance); for (VariantSlot* slot = _head; slot; slot = slot->next()) slot->movePointers(stringDistance, variantDistance); } template inline JsonArray JsonObject::createNestedArray(const TString& key) const { return operator[](key).template to(); } template inline JsonArray JsonObject::createNestedArray(TChar* key) const { return operator[](key).template to(); } template template inline JsonArray VariantRefBase::createNestedArray( const TString& key) const { return operator[](key).template to(); } template template inline JsonArray VariantRefBase::createNestedArray(TChar* key) const { return operator[](key).template to(); } template template inline JsonObject VariantRefBase::createNestedObject( const TString& key) const { return operator[](key).template to(); } template template inline JsonObject VariantRefBase::createNestedObject( TChar* key) const { return operator[](key).template to(); } template template inline typename enable_if::value, bool>::type VariantRefBase::containsKey(const TString& key) const { return variantGetMember(VariantAttorney::getData(derived()), adaptString(key)) != 0; } template template inline typename enable_if::value, bool>::type VariantRefBase::containsKey(TChar* key) const { return variantGetMember(VariantAttorney::getData(derived()), adaptString(key)) != 0; } template template inline typename enable_if::value, MemberProxy >::type VariantRefBase::operator[](TString* key) const { return MemberProxy(derived(), key); } template template inline typename enable_if::value, MemberProxy >::type VariantRefBase::operator[](const TString& key) const { return MemberProxy(derived(), key); } class EscapeSequence { public: static char escapeChar(char c) { const char* p = escapeTable(true); while (p[0] && p[1] != c) { p += 2; } return p[0]; } static char unescapeChar(char c) { const char* p = escapeTable(false); for (;;) { if (p[0] == '\0') return 0; if (p[0] == c) return p[1]; p += 2; } } private: static const char* escapeTable(bool excludeSolidus) { return &"//\"\"\\\\b\bf\fn\nr\rt\t"[excludeSolidus ? 2 : 0]; } }; template struct FloatParts { uint32_t integral; uint32_t decimal; int16_t exponent; int8_t decimalPlaces; FloatParts(TFloat value) { uint32_t maxDecimalPart = sizeof(TFloat) >= 8 ? 1000000000 : 1000000; decimalPlaces = sizeof(TFloat) >= 8 ? 9 : 6; exponent = normalize(value); integral = uint32_t(value); for (uint32_t tmp = integral; tmp >= 10; tmp /= 10) { maxDecimalPart /= 10; decimalPlaces--; } TFloat remainder = (value - TFloat(integral)) * TFloat(maxDecimalPart); decimal = uint32_t(remainder); remainder = remainder - TFloat(decimal); decimal += uint32_t(remainder * 2); if (decimal >= maxDecimalPart) { decimal = 0; integral++; if (exponent && integral >= 10) { exponent++; integral = 1; } } while (decimal % 10 == 0 && decimalPlaces > 0) { decimal /= 10; decimalPlaces--; } } static int16_t normalize(TFloat& value) { typedef FloatTraits traits; int16_t powersOf10 = 0; int8_t index = sizeof(TFloat) == 8 ? 8 : 5; int bit = 1 << index; if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) { for (; index >= 0; index--) { if (value >= traits::positiveBinaryPowerOfTen(index)) { value *= traits::negativeBinaryPowerOfTen(index); powersOf10 = int16_t(powersOf10 + bit); } bit >>= 1; } } if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) { for (; index >= 0; index--) { if (value < traits::negativeBinaryPowerOfTenPlusOne(index)) { value *= traits::positiveBinaryPowerOfTen(index); powersOf10 = int16_t(powersOf10 - bit); } bit >>= 1; } } return powersOf10; } }; template class CountingDecorator { public: explicit CountingDecorator(TWriter& writer) : _writer(writer), _count(0) {} void write(uint8_t c) { _count += _writer.write(c); } void write(const uint8_t* s, size_t n) { _count += _writer.write(s, n); } size_t count() const { return _count; } private: TWriter _writer; size_t _count; }; template class TextFormatter { public: explicit TextFormatter(TWriter writer) : _writer(writer) {} size_t bytesWritten() const { return _writer.count(); } void writeBoolean(bool value) { if (value) writeRaw("true"); else writeRaw("false"); } void writeString(const char* value) { ARDUINOJSON_ASSERT(value != NULL); writeRaw('\"'); while (*value) writeChar(*value++); writeRaw('\"'); } void writeString(const char* value, size_t n) { ARDUINOJSON_ASSERT(value != NULL); writeRaw('\"'); while (n--) writeChar(*value++); writeRaw('\"'); } void writeChar(char c) { char specialChar = EscapeSequence::escapeChar(c); if (specialChar) { writeRaw('\\'); writeRaw(specialChar); } else if (c) { writeRaw(c); } else { writeRaw("\\u0000"); } } template void writeFloat(T value) { if (isnan(value)) return writeRaw(ARDUINOJSON_ENABLE_NAN ? "NaN" : "null"); #if ARDUINOJSON_ENABLE_INFINITY if (value < 0.0) { writeRaw('-'); value = -value; } if (isinf(value)) return writeRaw("Infinity"); #else if (isinf(value)) return writeRaw("null"); if (value < 0.0) { writeRaw('-'); value = -value; } #endif FloatParts parts(value); writeInteger(parts.integral); if (parts.decimalPlaces) writeDecimals(parts.decimal, parts.decimalPlaces); if (parts.exponent) { writeRaw('e'); writeInteger(parts.exponent); } } template typename enable_if::value>::type writeInteger(T value) { typedef typename make_unsigned::type unsigned_type; unsigned_type unsigned_value; if (value < 0) { writeRaw('-'); unsigned_value = unsigned_type(unsigned_type(~value) + 1); } else { unsigned_value = unsigned_type(value); } writeInteger(unsigned_value); } template typename enable_if::value>::type writeInteger(T value) { char buffer[22]; char* end = buffer + sizeof(buffer); char* begin = end; do { *--begin = char(value % 10 + '0'); value = T(value / 10); } while (value); writeRaw(begin, end); } void writeDecimals(uint32_t value, int8_t width) { char buffer[16]; char* end = buffer + sizeof(buffer); char* begin = end; while (width--) { *--begin = char(value % 10 + '0'); value /= 10; } *--begin = '.'; writeRaw(begin, end); } void writeRaw(const char* s) { _writer.write(reinterpret_cast(s), strlen(s)); } void writeRaw(const char* s, size_t n) { _writer.write(reinterpret_cast(s), n); } void writeRaw(const char* begin, const char* end) { _writer.write(reinterpret_cast(begin), static_cast(end - begin)); } template void writeRaw(const char (&s)[N]) { _writer.write(reinterpret_cast(s), N - 1); } void writeRaw(char c) { _writer.write(static_cast(c)); } protected: CountingDecorator _writer; private: TextFormatter& operator=(const TextFormatter&); // cannot be assigned }; class DummyWriter { public: size_t write(uint8_t) { return 1; } size_t write(const uint8_t*, size_t n) { return n; } }; template