// ArduinoJson - arduinojson.org // Copyright Benoit Blanchon 2014-2021 // MIT License #pragma once #ifdef __cplusplus #if __cplusplus >= 201103L #define ARDUINOJSON_HAS_LONG_LONG 1 #define ARDUINOJSON_HAS_NULLPTR 1 #define ARDUINOJSON_HAS_RVALUE_REFERENCES 1 #else #define ARDUINOJSON_HAS_LONG_LONG 0 #define ARDUINOJSON_HAS_NULLPTR 0 #define ARDUINOJSON_HAS_RVALUE_REFERENCES 0 #endif #if defined(_MSC_VER) && !ARDUINOJSON_HAS_LONG_LONG #define ARDUINOJSON_HAS_INT64 1 #else #define ARDUINOJSON_HAS_INT64 0 #endif #ifndef ARDUINOJSON_EMBEDDED_MODE #if defined(ARDUINO) /* Arduino*/ \ || defined(__IAR_SYSTEMS_ICC__) /* IAR Embedded Workbench */ \ || defined(__XC) /* MPLAB XC compiler */ \ || defined(__ARMCC_VERSION) /* Keil ARM Compiler */ \ || defined(__AVR) /* Atmel AVR8/GNU C Compiler */ #define ARDUINOJSON_EMBEDDED_MODE 1 #else #define ARDUINOJSON_EMBEDDED_MODE 0 #endif #endif #if !defined(ARDUINOJSON_ENABLE_STD_STREAM) && defined(__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 #endif #if !defined(ARDUINOJSON_ENABLE_STD_STRING) && defined(__has_include) #if __has_include() && !defined(min) && !defined(max) #define ARDUINOJSON_ENABLE_STD_STRING 1 #else #define ARDUINOJSON_ENABLE_STD_STRING 0 #endif #endif #if ARDUINOJSON_EMBEDDED_MODE #ifndef ARDUINOJSON_USE_DOUBLE #define ARDUINOJSON_USE_DOUBLE 0 #endif #ifndef ARDUINOJSON_USE_LONG_LONG #define ARDUINOJSON_USE_LONG_LONG 0 #endif #ifndef ARDUINOJSON_ENABLE_STD_STRING #define ARDUINOJSON_ENABLE_STD_STRING 0 #endif #ifndef ARDUINOJSON_ENABLE_STD_STREAM #define ARDUINOJSON_ENABLE_STD_STREAM 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 #else #define ARDUINOJSON_SLOT_OFFSET_SIZE 2 #endif #endif #else // ARDUINOJSON_EMBEDDED_MODE #ifndef ARDUINOJSON_USE_DOUBLE #define ARDUINOJSON_USE_DOUBLE 1 #endif #ifndef ARDUINOJSON_USE_LONG_LONG #if ARDUINOJSON_HAS_LONG_LONG || ARDUINOJSON_HAS_INT64 #define ARDUINOJSON_USE_LONG_LONG 1 #else #define ARDUINOJSON_USE_LONG_LONG 0 #endif #endif #ifndef ARDUINOJSON_ENABLE_STD_STRING #define ARDUINOJSON_ENABLE_STD_STRING 1 #endif #ifndef ARDUINOJSON_ENABLE_STD_STREAM #define ARDUINOJSON_ENABLE_STD_STREAM 1 #endif #ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT #define ARDUINOJSON_DEFAULT_NESTING_LIMIT 50 #endif #ifndef ARDUINOJSON_SLOT_OFFSET_SIZE #define ARDUINOJSON_SLOT_OFFSET_SIZE 4 #endif #endif // ARDUINOJSON_EMBEDDED_MODE #ifdef ARDUINO #include #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 #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 #endif // ARDUINO #ifndef ARDUINOJSON_ENABLE_PROGMEM #if defined(PROGMEM) && defined(pgm_read_byte) && defined(pgm_read_dword) && \ defined(pgm_read_ptr) && defined(pgm_read_float) #define ARDUINOJSON_ENABLE_PROGMEM 1 #else #define ARDUINOJSON_ENABLE_PROGMEM 0 #endif #endif #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_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_EXPAND7(a, b, c, d, e, f, g) a, b, c, d, e, f, g #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.17.3" #define ARDUINOJSON_VERSION_MAJOR 6 #define ARDUINOJSON_VERSION_MINOR 17 #define ARDUINOJSON_VERSION_REVISION 3 #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 #if ARDUINOJSON_DEBUG #include #define ARDUINOJSON_ASSERT(X) assert(X) #else #define ARDUINOJSON_ASSERT(X) ((void)0) #endif #include 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); bool equalsArray(const CollectionData &other) const; 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; bool equalsObject(const CollectionData &other) const; void clear(); size_t memoryUsage() const; size_t nesting() 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 VariantData *arrayAdd(CollectionData *arr, MemoryPool *pool) { return arr ? arr->addElement(pool) : 0; } template inline typename TVisitor::result_type arrayAccept(const CollectionData *arr, TVisitor &visitor) { if (arr) return visitor.visitArray(*arr); else return visitor.visitNull(); } inline bool arrayEquals(const CollectionData *lhs, const CollectionData *rhs) { if (lhs == rhs) return true; if (!lhs || !rhs) return false; return lhs->equalsArray(*rhs); } #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); } template Y)> struct Max {}; template struct Max { static const size_t value = X; }; template struct Max { static const size_t value = Y; }; } // namespace ARDUINOJSON_NAMESPACE #include namespace ARDUINOJSON_NAMESPACE { 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; }; 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" typedef char Yes[1]; typedef char No[2]; static Yes &probe(const TBase *); static No &probe(...); public: static const bool value = sizeof(probe(reinterpret_cast(0))) == sizeof(Yes); }; template T declval(); template struct is_class { protected: // <- to avoid GCC's "all member functions in class are private" typedef char Yes[1]; typedef char No[2]; template static Yes &probe(void (U::*)(void)); template static No &probe(...); public: static const bool value = sizeof(probe(0)) == sizeof(Yes); }; 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" typedef char Yes[1]; typedef char No[2]; static Yes &probe(To); static No &probe(...); public: static const bool value = sizeof(probe(declval())) == sizeof(Yes); }; } // namespace ARDUINOJSON_NAMESPACE #ifdef _MSC_VER #pragma warning(pop) #endif #ifdef __ICCARM__ #pragma diag_default=Pa093 #endif namespace ARDUINOJSON_NAMESPACE { template struct is_floating_point : false_type {}; template <> struct is_floating_point : true_type {}; template <> struct is_floating_point : true_type {}; template struct is_same : false_type {}; template struct is_same : true_type {}; template struct is_integral { static const bool value = is_same::value || is_same::value || is_same::value || is_same::value || is_same::value || is_same::value || is_same::value || is_same::value || #if ARDUINOJSON_HAS_LONG_LONG is_same::value || is_same::value || #endif #if ARDUINOJSON_HAS_INT64 is_same::value || is_same::value || #endif is_same::value || is_same::value; }; template struct is_integral : is_integral {}; 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 : false_type {}; template <> struct is_signed : true_type {}; template <> struct is_signed : true_type {}; template <> struct is_signed : true_type {}; template <> struct is_signed : true_type {}; template <> struct is_signed : true_type {}; template <> struct is_signed : true_type {}; template <> struct is_signed : true_type {}; #if ARDUINOJSON_HAS_LONG_LONG template <> struct is_signed : true_type {}; #endif #if ARDUINOJSON_HAS_INT64 template <> struct is_signed : true_type {}; #endif template struct is_unsigned : false_type {}; template <> struct is_unsigned : true_type {}; template <> struct is_unsigned : true_type {}; template <> struct is_unsigned : true_type {}; template <> struct is_unsigned : true_type {}; template <> struct is_unsigned : true_type {}; #if ARDUINOJSON_HAS_INT64 template <> struct is_unsigned : true_type {}; #endif #if ARDUINOJSON_HAS_LONG_LONG template <> struct is_unsigned : true_type {}; #endif 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 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 #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 { namespace storage_policies { struct store_by_address {}; struct store_by_copy {}; struct decide_at_runtime {}; } // namespace storage_policies #if ARDUINOJSON_USE_DOUBLE typedef double Float; #else typedef float Float; #endif #if ARDUINOJSON_USE_LONG_LONG typedef int64_t Integer; typedef uint64_t UInt; #else typedef long Integer; typedef unsigned long UInt; #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::Integer), \ "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, VALUE_IS_OWNED = 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, VALUE_IS_POSITIVE_INTEGER = 0x08, VALUE_IS_NEGATIVE_INTEGER = 0x0A, VALUE_IS_FLOAT = 0x0C, COLLECTION_MASK = 0x60, VALUE_IS_OBJECT = 0x20, VALUE_IS_ARRAY = 0x40, KEY_IS_OWNED = 0x80 }; struct RawData { const char *data; size_t size; }; union VariantContent { Float asFloat; UInt asInteger; CollectionData asCollection; const char *asString; struct { const char *data; size_t size; } asRaw; }; 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(const char* k, storage_policies::store_by_copy) { ARDUINOJSON_ASSERT(k != NULL); _flags |= KEY_IS_OWNED; _key = k; } void setKey(const char* k, storage_policies::store_by_address) { ARDUINOJSON_ASSERT(k != NULL); _flags &= VALUE_MASK; _key = k; } const char* key() const { return _key; } bool ownsKey() const { return (_flags & KEY_IS_OWNED) != 0; } void clear() { _next = 0; _flags = 0; _key = 0; } void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) { if (_flags & KEY_IS_OWNED) _key += stringDistance; if (_flags & VALUE_IS_OWNED) _content.asString += stringDistance; if (_flags & COLLECTION_MASK) _content.asCollection.movePointers(stringDistance, variantDistance); } }; } // namespace ARDUINOJSON_NAMESPACE #include #define JSON_STRING_SIZE(SIZE) (SIZE + 1) 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; } 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(const TAdaptedString& str) { if (str.isNull()) return 0; #if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION const char* existingCopy = findString(str.begin()); if (existingCopy) return existingCopy; #endif size_t n = str.size(); char* newCopy = allocString(n + 1); if (newCopy) { str.copyTo(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(_left); if (dup) return dup; #endif const char* str = _left; _left += len; 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(TIterator str) { for (char* next = _begin; next < _left; ++next) { char* begin = next; for (TIterator it = str; *it == *next; ++it) { if (*next++ == 0) return begin; } 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; }; inline int safe_strcmp(const char* a, const char* b) { if (a == b) return 0; if (!a) return -1; if (!b) return 1; return strcmp(a, b); } inline int safe_strncmp(const char* a, const char* b, size_t n) { if (a == b) return 0; if (!a) return -1; if (!b) return 1; return strncmp(a, b, n); } template struct IsString : false_type {}; template struct IsString : IsString {}; template struct IsString : IsString {}; class ConstRamStringAdapter { public: ConstRamStringAdapter(const char* str = 0) : _str(str) {} int compare(const char* other) const { return safe_strcmp(_str, other); } bool equals(const char* expected) const { return compare(expected) == 0; } bool isNull() const { return !_str; } size_t size() const { if (!_str) return 0; return strlen(_str); } const char* data() const { return _str; } const char* begin() const { return _str; } typedef storage_policies::store_by_address storage_policy; protected: const char* _str; }; template <> struct IsString : true_type {}; template struct IsString : true_type {}; inline ConstRamStringAdapter adaptString(const char* str) { return ConstRamStringAdapter(str); } class RamStringAdapter : public ConstRamStringAdapter { public: RamStringAdapter(const char* str) : ConstRamStringAdapter(str) {} void copyTo(char* p, size_t n) const { memcpy(p, _str, n); } typedef ARDUINOJSON_NAMESPACE::storage_policies::store_by_copy storage_policy; }; template inline RamStringAdapter adaptString(const TChar* str) { return RamStringAdapter(reinterpret_cast(str)); } inline RamStringAdapter adaptString(char* str) { return RamStringAdapter(str); } template struct IsString { static const bool value = sizeof(TChar) == 1; }; template <> struct IsString { static const bool value = false; }; class SizedRamStringAdapter { public: SizedRamStringAdapter(const char* str, size_t n) : _str(str), _size(n) {} int compare(const char* other) const { return safe_strncmp(_str, other, _size); } bool equals(const char* expected) const { return compare(expected) == 0; } bool isNull() const { return !_str; } void copyTo(char* p, size_t n) const { memcpy(p, _str, n); } size_t size() const { return _size; } const char* begin() const { return _str; } typedef storage_policies::store_by_copy storage_policy; private: const char* _str; size_t _size; }; template inline SizedRamStringAdapter adaptString(const TChar* str, size_t size) { return SizedRamStringAdapter(reinterpret_cast(str), size); } } // namespace ARDUINOJSON_NAMESPACE #if ARDUINOJSON_ENABLE_STD_STRING #include namespace ARDUINOJSON_NAMESPACE { template class StdStringAdapter { public: StdStringAdapter(const TString& str) : _str(&str) {} void copyTo(char* p, size_t n) const { memcpy(p, _str->c_str(), n); } bool isNull() const { return false; } int compare(const char* other) const { if (!other) return 1; return _str->compare(other); } bool equals(const char* expected) const { if (!expected) return false; return *_str == expected; } size_t size() const { return _str->size(); } const char* begin() const { return _str->c_str(); } typedef storage_policies::store_by_copy storage_policy; private: const TString* _str; }; template struct IsString > : true_type { }; template inline StdStringAdapter > adaptString(const std::basic_string& str) { return StdStringAdapter >( str); } } // namespace ARDUINOJSON_NAMESPACE #endif #if ARDUINOJSON_ENABLE_ARDUINO_STRING namespace ARDUINOJSON_NAMESPACE { class ArduinoStringAdapter { public: ArduinoStringAdapter(const ::String& str) : _str(&str) {} void copyTo(char* p, size_t n) const { memcpy(p, _str->c_str(), n); } bool isNull() const { return !_str->c_str(); } int compare(const char* other) const { const char* me = _str->c_str(); return safe_strcmp(me, other); } bool equals(const char* expected) const { return compare(expected) == 0; } size_t size() const { return _str->length(); } const char* begin() const { return _str->c_str(); } typedef storage_policies::store_by_copy storage_policy; private: const ::String* _str; }; template <> struct IsString< ::String> : true_type {}; template <> struct IsString< ::StringSumHelper> : true_type {}; inline ArduinoStringAdapter adaptString(const ::String& str) { return ArduinoStringAdapter(str); } } // namespace ARDUINOJSON_NAMESPACE #endif #if ARDUINOJSON_ENABLE_PROGMEM namespace ARDUINOJSON_NAMESPACE { struct pgm_p { pgm_p(const char* p) : address(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 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 namespace ARDUINOJSON_NAMESPACE { class FlashStringIterator { public: explicit FlashStringIterator(const __FlashStringHelper* ptr) : _ptr(reinterpret_cast(ptr)) {} explicit FlashStringIterator(const char* ptr) : _ptr(ptr) {} FlashStringIterator operator+(ptrdiff_t d) const { return FlashStringIterator(_ptr + d); } ptrdiff_t operator-(FlashStringIterator other) const { return _ptr - other._ptr; } FlashStringIterator operator++(int) { return FlashStringIterator(_ptr++); } FlashStringIterator operator++() { return FlashStringIterator(++_ptr); } bool operator!=(FlashStringIterator other) const { return _ptr != other._ptr; } char operator*() const { return char(pgm_read_byte(_ptr)); } private: const char* _ptr; }; class FlashStringAdapter { public: FlashStringAdapter(const __FlashStringHelper* str) : _str(str) {} int compare(const char* other) const { if (!other && !_str) return 0; if (!_str) return -1; if (!other) return 1; return -strcmp_P(other, reinterpret_cast(_str)); } bool equals(const char* expected) const { return compare(expected) == 0; } bool isNull() const { return !_str; } void copyTo(char* p, size_t n) const { memcpy_P(p, reinterpret_cast(_str), n); } size_t size() const { if (!_str) return 0; return strlen_P(reinterpret_cast(_str)); } FlashStringIterator begin() const { return FlashStringIterator(_str); } typedef storage_policies::store_by_copy storage_policy; private: const __FlashStringHelper* _str; }; inline FlashStringAdapter adaptString(const __FlashStringHelper* str) { return FlashStringAdapter(str); } template <> struct IsString : true_type {}; class SizedFlashStringAdapter { public: SizedFlashStringAdapter(const __FlashStringHelper* str, size_t sz) : _str(str), _size(sz) {} int compare(const char* other) const { if (!other && !_str) return 0; if (!_str) return -1; if (!other) return 1; return -strncmp_P(other, reinterpret_cast(_str), _size); } bool equals(const char* expected) const { return compare(expected) == 0; } bool isNull() const { return !_str; } void copyTo(char* p, size_t n) const { memcpy_P(p, reinterpret_cast(_str), n); } size_t size() const { return _size; } FlashStringIterator begin() const { return FlashStringIterator(_str); } typedef storage_policies::store_by_copy storage_policy; private: const __FlashStringHelper* _str; size_t _size; }; inline SizedFlashStringAdapter adaptString(const __FlashStringHelper* str, size_t sz) { return SizedFlashStringAdapter(str, sz); } } // namespace ARDUINOJSON_NAMESPACE #endif namespace ARDUINOJSON_NAMESPACE { 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 namespace ARDUINOJSON_NAMESPACE { template typename enable_if::value, T>::type pgm_read(const void* p) { return reinterpret_cast(pgm_read_ptr(p)); } template typename enable_if::value && sizeof(T) == sizeof(float), // on AVR sizeof(double) == T>::type pgm_read(const void* p) { return pgm_read_float(p); } template typename enable_if::value, T>::type pgm_read( const void* p) { return pgm_read_dword(p); } } // namespace ARDUINOJSON_NAMESPACE #ifndef ARDUINOJSON_DEFINE_STATIC_ARRAY #define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) \ static type const name[] PROGMEM = value; #endif #ifndef ARDUINOJSON_READ_STATIC_ARRAY #define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) \ pgm_read(name + index) #endif #else // i.e. ARDUINOJSON_ENABLE_PROGMEM == 0 #ifndef ARDUINOJSON_DEFINE_STATIC_ARRAY #define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) \ static type const name[] = value; #endif #ifndef ARDUINOJSON_READ_STATIC_ARRAY #define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) name[index] #endif #endif namespace ARDUINOJSON_NAMESPACE { 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_STATIC_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( ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); } static T negativeBinaryPowerOfTen(int index) { ARDUINOJSON_DEFINE_STATIC_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( ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); } static T negativeBinaryPowerOfTenPlusOne(int index) { ARDUINOJSON_DEFINE_STATIC_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( ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, 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); } 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_STATIC_ARRAY( T, factors, ARDUINOJSON_EXPAND6({1e1f, 1e2f, 1e4f, 1e8f, 1e16f, 1e32f})); return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); } static T negativeBinaryPowerOfTen(int index) { ARDUINOJSON_DEFINE_STATIC_ARRAY( T, factors, ARDUINOJSON_EXPAND6({1e-1f, 1e-2f, 1e-4f, 1e-8f, 1e-16f, 1e-32f})); return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); } static T negativeBinaryPowerOfTenPlusOne(int index) { ARDUINOJSON_DEFINE_STATIC_ARRAY( T, factors, ARDUINOJSON_EXPAND6({1e0f, 1e-1f, 1e-3f, 1e-7f, 1e-15f, 1e-31f})); return ARDUINOJSON_READ_STATIC_ARRAY(T, 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); } static T lowest() { return forge(0xFf7fffff); } }; template typename enable_if::value && sizeof(TOut) <= sizeof(TIn), bool>::type canStorePositiveInteger(TIn value) { return value <= TIn(numeric_limits::highest()); } template typename enable_if::value && sizeof(TIn) < sizeof(TOut), bool>::type canStorePositiveInteger(TIn) { return true; } template typename enable_if::value, bool>::type canStorePositiveInteger(TIn) { return true; } template typename enable_if::value, bool>::type canStoreNegativeInteger(TIn) { return true; } template typename enable_if::value && is_signed::value && sizeof(TOut) <= sizeof(TIn), bool>::type canStoreNegativeInteger(TIn value) { return value <= TIn(numeric_limits::highest()) + 1; } template typename enable_if::value && is_signed::value && sizeof(TIn) < sizeof(TOut), bool>::type canStoreNegativeInteger(TIn) { return true; } template typename enable_if::value && is_unsigned::value, bool>::type canStoreNegativeInteger(TIn) { return false; } template TOut convertPositiveInteger(TIn value) { return canStorePositiveInteger(value) ? TOut(value) : 0; } template TOut convertNegativeInteger(TIn value) { return canStoreNegativeInteger(value) ? TOut(~value + 1) : 0; } template typename enable_if::value, TOut>::type convertFloat( TIn value) { return TOut(value); } template typename enable_if::value, TOut>::type convertFloat( TIn value) { return value >= numeric_limits::lowest() && value <= numeric_limits::highest() ? 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 = 0; } 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); case VALUE_IS_OWNED_RAW: case VALUE_IS_LINKED_RAW: return visitor.visitRawJson(_content.asRaw.data, _content.asRaw.size); case VALUE_IS_NEGATIVE_INTEGER: return visitor.visitNegativeInteger(_content.asInteger); case VALUE_IS_POSITIVE_INTEGER: return visitor.visitPositiveInteger(_content.asInteger); case VALUE_IS_BOOLEAN: return visitor.visitBoolean(_content.asInteger != 0); default: return visitor.visitNull(); } } template T asIntegral() const; template T asFloat() const; const char *asString() const; bool asBoolean() const; CollectionData *asArray() { return isArray() ? &_content.asCollection : 0; } const CollectionData *asArray() const { return const_cast(this)->asArray(); } CollectionData *asObject() { return isObject() ? &_content.asCollection : 0; } const CollectionData *asObject() const { return const_cast(this)->asObject(); } bool copyFrom(const VariantData &src, MemoryPool *pool) { switch (src.type()) { case VALUE_IS_ARRAY: return toArray().copyFrom(src._content.asCollection, pool); case VALUE_IS_OBJECT: return toObject().copyFrom(src._content.asCollection, pool); case VALUE_IS_OWNED_STRING: return setString(RamStringAdapter(src._content.asString), pool); case VALUE_IS_OWNED_RAW: return setOwnedRaw( serialized(src._content.asRaw.data, src._content.asRaw.size), pool); default: setType(src.type()); _content = src._content; return true; } } 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_POSITIVE_INTEGER: return canStorePositiveInteger(_content.asInteger); case VALUE_IS_NEGATIVE_INTEGER: return canStoreNegativeInteger(_content.asInteger); default: return false; } } bool isFloat() const { return type() == VALUE_IS_FLOAT || type() == VALUE_IS_POSITIVE_INTEGER || type() == VALUE_IS_NEGATIVE_INTEGER; } 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.asInteger = static_cast(value); } void setFloat(Float value) { setType(VALUE_IS_FLOAT); _content.asFloat = value; } void setLinkedRaw(SerializedValue value) { if (value.data()) { setType(VALUE_IS_LINKED_RAW); _content.asRaw.data = value.data(); _content.asRaw.size = value.size(); } else { setType(VALUE_IS_NULL); } } template bool setOwnedRaw(SerializedValue value, MemoryPool *pool) { const char *dup = pool->saveString(adaptString(value.data(), value.size())); if (dup) { setType(VALUE_IS_OWNED_RAW); _content.asRaw.data = dup; _content.asRaw.size = value.size(); return true; } else { setType(VALUE_IS_NULL); return false; } } template typename enable_if::value>::type setInteger(T value) { setUnsignedInteger(value); } template typename enable_if::value>::type setInteger(T value) { setSignedInteger(value); } template void setSignedInteger(T value) { if (value >= 0) { setPositiveInteger(static_cast(value)); } else { setNegativeInteger(~static_cast(value) + 1); } } void setUnsignedInteger(UInt value) { setType(VALUE_IS_POSITIVE_INTEGER); _content.asInteger = static_cast(value); } void setPositiveInteger(UInt value) { setType(VALUE_IS_POSITIVE_INTEGER); _content.asInteger = value; } void setNegativeInteger(UInt value) { setType(VALUE_IS_NEGATIVE_INTEGER); _content.asInteger = value; } void setNull() { setType(VALUE_IS_NULL); } void setStringPointer(const char *s, storage_policies::store_by_copy) { setType(VALUE_IS_OWNED_STRING); _content.asString = s; } void setStringPointer(const char *s, storage_policies::store_by_address) { setType(VALUE_IS_LINKED_STRING); _content.asString = s; } template bool setString(TAdaptedString value, MemoryPool *pool) { return setString(value, pool, typename TAdaptedString::storage_policy()); } template inline bool setString(TAdaptedString value, MemoryPool *pool, storage_policies::decide_at_runtime) { if (value.isStatic()) return setString(value, pool, storage_policies::store_by_address()); else return setString(value, pool, storage_policies::store_by_copy()); } template inline bool setString(TAdaptedString value, MemoryPool *, storage_policies::store_by_address) { if (value.isNull()) setNull(); else setStringPointer(value.data(), storage_policies::store_by_address()); return true; } template inline bool setString(TAdaptedString value, MemoryPool *pool, storage_policies::store_by_copy) { if (value.isNull()) { setNull(); return true; } const char *copy = pool->saveString(value); if (!copy) { setNull(); return false; } setStringPointer(copy, storage_policies::store_by_copy()); return true; } 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: return strlen(_content.asString) + 1; case VALUE_IS_OWNED_RAW: return _content.asRaw.size; case VALUE_IS_OBJECT: case VALUE_IS_ARRAY: return _content.asCollection.memoryUsage(); default: return 0; } } size_t nesting() const { return isCollection() ? _content.asCollection.nesting() : 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 { return isArray() ? _content.asCollection.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 { return isObject() ? _content.asCollection.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 & VALUE_IS_OWNED) _content.asString += stringDistance; if (_flags & COLLECTION_MASK) _content.asCollection.movePointers(stringDistance, variantDistance); } uint8_t type() const { return _flags & VALUE_MASK; } private: void setType(uint8_t t) { _flags &= KEY_IS_OWNED; _flags |= t; } }; } // namespace ARDUINOJSON_NAMESPACE #if defined(__GNUC__) #if __GNUC__ >= 8 #pragma GCC diagnostic pop #endif #endif namespace ARDUINOJSON_NAMESPACE { template inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool) { if (!var) return false; return slotSetKey(var, key, pool, typename TAdaptedString::storage_policy()); } template inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool, storage_policies::decide_at_runtime) { if (key.isStatic()) { return slotSetKey(var, key, pool, storage_policies::store_by_address()); } else { return slotSetKey(var, key, pool, storage_policies::store_by_copy()); } } template inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool*, storage_policies::store_by_address) { ARDUINOJSON_ASSERT(var); var->setKey(key.data(), storage_policies::store_by_address()); return true; } template inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool, storage_policies::store_by_copy) { const char* dup = pool->saveString(key); if (!dup) return false; ARDUINOJSON_ASSERT(var); var->setKey(dup, storage_policies::store_by_copy()); return true; } 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); } template struct Visitor { typedef TResult result_type; }; struct Visitable { }; template struct IsVisitable : is_base_of {}; template struct IsVisitable : IsVisitable {}; } // namespace ARDUINOJSON_NAMESPACE #if ARDUINOJSON_ENABLE_ARDUINO_STRING #endif #if ARDUINOJSON_ENABLE_STD_STRING #endif namespace ARDUINOJSON_NAMESPACE { template struct IsWriteableString : false_type {}; #if ARDUINOJSON_ENABLE_ARDUINO_STRING template <> struct IsWriteableString< ::String> : true_type {}; #endif #if ARDUINOJSON_ENABLE_STD_STRING template struct IsWriteableString > : true_type {}; #endif class ArrayRef; class ArrayConstRef; class ObjectRef; class ObjectConstRef; class VariantRef; class VariantConstRef; template struct VariantAs { typedef T type; }; template <> struct VariantAs { typedef const char* type; }; template struct VariantConstAs { typedef typename VariantAs::type type; }; template <> struct VariantConstAs { typedef VariantConstRef type; }; template <> struct VariantConstAs { typedef ObjectConstRef type; }; template <> struct VariantConstAs { typedef ArrayConstRef type; }; template inline typename enable_if::value && !is_same::value, T>::type variantAs(const VariantData* data) { ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); return data != 0 ? data->asIntegral() : T(0); } template inline typename enable_if::value, T>::type variantAs( const VariantData* data) { return data != 0 ? static_cast(data->asIntegral()) : T(); } template inline typename enable_if::value, T>::type variantAs( const VariantData* data) { return data != 0 ? data->asBoolean() : false; } template inline typename enable_if::value, T>::type variantAs( const VariantData* data) { return data != 0 ? data->asFloat() : T(0); } template inline typename enable_if::value || is_same::value, const char*>::type variantAs(const VariantData* data) { return data != 0 ? data->asString() : 0; } template T variantAs(VariantData* data, MemoryPool*) { return variantAs(data); } template inline typename enable_if::value, T>::type variantAs( const VariantData* data); template inline typename enable_if::value, T>::type variantAs( const VariantData* data); template inline typename enable_if::value, T>::type variantAs(const VariantData* data); template inline typename enable_if::value, T>::type variantAs( const VariantData* data); } // namespace ARDUINOJSON_NAMESPACE #ifdef _MSC_VER // Visual Studio #define FORCE_INLINE // __forceinline causes C4714 when returning std::string #define NO_INLINE __declspec(noinline) #define DEPRECATED(msg) __declspec(deprecated(msg)) #elif defined(__GNUC__) // GCC or Clang #define FORCE_INLINE __attribute__((always_inline)) #define NO_INLINE __attribute__((noinline)) #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) #define DEPRECATED(msg) __attribute__((deprecated(msg))) #else #define DEPRECATED(msg) __attribute__((deprecated)) #endif #else // Other compilers #define FORCE_INLINE #define NO_INLINE #define DEPRECATED(msg) #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 { template inline typename TVisitor::result_type variantAccept(const VariantData *var, TVisitor &visitor) { if (var != 0) return var->accept(visitor); else return visitor.visitNull(); } inline const CollectionData *variantAsArray(const VariantData *var) { return var != 0 ? var->asArray() : 0; } inline const CollectionData *variantAsObject(const VariantData *var) { return var != 0 ? var->asObject() : 0; } inline CollectionData *variantAsObject(VariantData *var) { return var != 0 ? var->asObject() : 0; } 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 int variantCompare(const VariantData *a, const VariantData *b); inline bool variantIsArray(const VariantData *var) { return var && var->isArray(); } inline bool variantIsBoolean(const VariantData *var) { return var && var->isBoolean(); } template inline bool variantIsInteger(const VariantData *var) { return var && var->isInteger(); } inline bool variantIsFloat(const VariantData *var) { return var && var->isFloat(); } inline bool variantIsString(const VariantData *var) { return var && var->isString(); } inline bool variantIsObject(const VariantData *var) { return var && var->isObject(); } inline bool variantIsNull(const VariantData *var) { return var == 0 || var->isNull(); } inline bool variantSetBoolean(VariantData *var, bool value) { if (!var) return false; var->setBoolean(value); return true; } inline bool variantSetFloat(VariantData *var, Float value) { if (!var) return false; var->setFloat(value); return true; } inline bool variantSetLinkedRaw(VariantData *var, SerializedValue value) { if (!var) return false; var->setLinkedRaw(value); return true; } template inline bool variantSetOwnedRaw(VariantData *var, SerializedValue value, MemoryPool *pool) { return var != 0 && var->setOwnedRaw(value, pool); } inline void variantSetNull(VariantData *var) { if (!var) return; var->setNull(); } template inline bool variantSetString(VariantData *var, TAdaptedString value, MemoryPool *pool) { if (!var) return false; return var->setString(value, pool); } template inline bool variantSetInteger(VariantData *var, T value) { ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); if (!var) return false; var->setInteger(value); return true; } 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 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 NO_INLINE VariantData *variantGetOrAddMember(VariantData *var, TChar *key, MemoryPool *pool) { return var != 0 ? var->getOrAddMember(adaptString(key), pool) : 0; } template NO_INLINE VariantData *variantGetOrAddMember(VariantData *var, const TString &key, MemoryPool *pool) { return var != 0 ? var->getOrAddMember(adaptString(key), pool) : 0; } 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( UInt, const T2 &, typename enable_if::value>::type * = 0) { return COMPARE_RESULT_LESS; } template CompareResult arithmeticCompareNegateLeft( UInt 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 &, UInt, typename enable_if::value>::type * = 0) { return COMPARE_RESULT_GREATER; } template CompareResult arithmeticCompareNegateRight( const T1 &lhs, UInt 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 {}; template CompareResult compare(const T1 &lhs, const T2 &rhs); // VariantCompare.cpp template struct VariantOperators { template friend typename enable_if::value, typename VariantAs::type>::type operator|(const TVariant &variant, T defaultValue) { if (variant.template is()) return variant.template as(); else return defaultValue; } template friend typename enable_if::value, typename T::variant_type>::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; } }; template class ElementProxy; template class ArrayShortcuts { public: FORCE_INLINE ElementProxy operator[](size_t index) const; FORCE_INLINE ObjectRef createNestedObject() const; FORCE_INLINE ArrayRef createNestedArray() const; template FORCE_INLINE bool add(const T &value) const { return impl()->addElement().set(value); } template FORCE_INLINE bool add(T *value) const { return impl()->addElement().set(value); } private: const TArray *impl() const { return static_cast(this); } }; template class MemberProxy; template class ObjectShortcuts { public: 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 ArrayRef createNestedArray(const TString &key) const; template FORCE_INLINE ArrayRef createNestedArray(TChar *key) const; template ObjectRef createNestedObject(const TString &key) const; template ObjectRef createNestedObject(TChar *key) const; private: const TObject *impl() const { return static_cast(this); } }; template class VariantShortcuts : public ObjectShortcuts, public ArrayShortcuts { public: using ArrayShortcuts::createNestedArray; using ArrayShortcuts::createNestedObject; using ArrayShortcuts::operator[]; using ObjectShortcuts::createNestedArray; using ObjectShortcuts::createNestedObject; using ObjectShortcuts::operator[]; }; class ArrayRef; class ObjectRef; template class VariantRefBase : public VariantTag { public: template FORCE_INLINE typename enable_if::value && !is_same::value, bool>::type is() const { return variantIsInteger(_data); } template FORCE_INLINE typename enable_if::value, bool>::type is() const { return variantIsFloat(_data); } template FORCE_INLINE typename enable_if::value, bool>::type is() const { return variantIsBoolean(_data); } template FORCE_INLINE typename enable_if::value || is_same::value || IsWriteableString::value, bool>::type is() const { return variantIsString(_data); } template FORCE_INLINE typename enable_if< is_same::type, ArrayRef>::value, bool>::type is() const { return variantIsArray(_data); } template FORCE_INLINE typename enable_if< is_same::type, ObjectRef>::value, bool>::type is() const { return variantIsObject(_data); } #if ARDUINOJSON_HAS_NULLPTR template FORCE_INLINE typename enable_if::value, bool>::type is() const { return variantIsNull(_data); } #endif template FORCE_INLINE typename enable_if::value, bool>::type is() const { return variantIsInteger(_data); } FORCE_INLINE bool isNull() const { return variantIsNull(_data); } FORCE_INLINE bool isUndefined() const { return !_data; } FORCE_INLINE size_t memoryUsage() const { return _data ? _data->memoryUsage() : 0; } FORCE_INLINE size_t nesting() const { return _data ? _data->nesting() : 0; } size_t size() const { return variantSize(_data); } protected: VariantRefBase(TData *data) : _data(data) {} TData *_data; }; class VariantRef : public VariantRefBase, public VariantOperators, public VariantShortcuts, public Visitable { typedef VariantRefBase base_type; friend class VariantConstRef; public: FORCE_INLINE VariantRef(MemoryPool *pool, VariantData *data) : base_type(data), _pool(pool) {} FORCE_INLINE VariantRef() : base_type(0), _pool(0) {} FORCE_INLINE void clear() const { return variantSetNull(_data); } template FORCE_INLINE bool set( T value, typename enable_if::value>::type * = 0) const { return variantSetBoolean(_data, value); } template FORCE_INLINE bool set( T value, typename enable_if::value>::type * = 0) const { return variantSetFloat(_data, static_cast(value)); } template FORCE_INLINE bool set( T value, typename enable_if::value && !is_same::value>::type * = 0) const { return variantSetInteger(_data, value); } FORCE_INLINE bool set(SerializedValue value) const { return variantSetLinkedRaw(_data, value); } template FORCE_INLINE bool set( SerializedValue value, typename enable_if::value>::type * = 0) const { return variantSetOwnedRaw(_data, value, _pool); } template FORCE_INLINE bool set( const T &value, typename enable_if::value>::type * = 0) const { return variantSetString(_data, adaptString(value), _pool); } template FORCE_INLINE bool set( T *value, typename enable_if::value>::type * = 0) const { return variantSetString(_data, adaptString(value), _pool); } template typename enable_if::value, bool>::type set( const TVariant &value) const; template FORCE_INLINE bool set( T value, typename enable_if::value>::type * = 0) const { return variantSetInteger(_data, static_cast(value)); } #if ARDUINOJSON_HAS_NULLPTR FORCE_INLINE bool set(decltype(nullptr)) const { variantSetNull(_data); return true; } #endif template FORCE_INLINE typename VariantAs::type as() const { return variantAs::type>(_data, _pool); } template FORCE_INLINE operator T() const { return variantAs(_data, _pool); } template typename TVisitor::result_type accept(TVisitor &visitor) const { return variantAccept(_data, visitor); } template typename enable_if::value, ArrayRef>::type to() const; template typename enable_if::value, ObjectRef>::type to() const; template typename enable_if::value, VariantRef>::type to() const; VariantRef addElement() const; FORCE_INLINE VariantRef getElement(size_t) const; FORCE_INLINE VariantRef getOrAddElement(size_t) const; template FORCE_INLINE VariantRef getMember(TChar *) const; template FORCE_INLINE typename enable_if::value, VariantRef>::type getMember(const TString &) const; template FORCE_INLINE VariantRef getOrAddMember(TChar *) const; template FORCE_INLINE VariantRef getOrAddMember(const TString &) const; FORCE_INLINE void remove(size_t index) const { if (_data) _data->remove(index); } template FORCE_INLINE typename enable_if::value>::type remove( TChar *key) const { if (_data) _data->remove(adaptString(key)); } template FORCE_INLINE typename enable_if::value>::type remove( const TString &key) const { if (_data) _data->remove(adaptString(key)); } private: MemoryPool *_pool; }; // namespace ARDUINOJSON_NAMESPACE class VariantConstRef : public VariantRefBase, public VariantOperators, public VariantShortcuts, public Visitable { typedef VariantRefBase base_type; friend class VariantRef; public: VariantConstRef() : base_type(0) {} VariantConstRef(const VariantData *data) : base_type(data) {} VariantConstRef(VariantRef var) : base_type(var._data) {} template typename TVisitor::result_type accept(TVisitor &visitor) const { return variantAccept(_data, visitor); } template FORCE_INLINE typename VariantConstAs::type as() const { return variantAs::type>(_data); } template FORCE_INLINE operator T() const { return variantAs(_data); } FORCE_INLINE VariantConstRef getElement(size_t) const; FORCE_INLINE VariantConstRef operator[](size_t index) const { return getElement(index); } template FORCE_INLINE VariantConstRef getMember(const TString &key) const { return VariantConstRef( objectGetMember(variantAsObject(_data), adaptString(key))); } template FORCE_INLINE VariantConstRef getMember(TChar *key) const { const CollectionData *obj = variantAsObject(_data); return VariantConstRef(obj ? obj->getMember(adaptString(key)) : 0); } template FORCE_INLINE typename enable_if::value, VariantConstRef>::type operator[](const TString &key) const { return getMember(key); } template FORCE_INLINE typename enable_if::value, VariantConstRef>::type operator[](TChar *key) const { return getMember(key); } }; class VariantPtr { public: VariantPtr(MemoryPool *pool, VariantData *data) : _variant(pool, data) {} VariantRef *operator->() { return &_variant; } VariantRef &operator*() { return _variant; } private: VariantRef _variant; }; class ArrayIterator { public: ArrayIterator() : _slot(0) {} explicit ArrayIterator(MemoryPool *pool, VariantSlot *slot) : _pool(pool), _slot(slot) {} VariantRef operator*() const { return VariantRef(_pool, _slot->data()); } VariantPtr operator->() { return VariantPtr(_pool, _slot->data()); } bool operator==(const ArrayIterator &other) const { return _slot == other._slot; } bool operator!=(const ArrayIterator &other) const { return _slot != other._slot; } ArrayIterator &operator++() { _slot = _slot->next(); return *this; } ArrayIterator &operator+=(size_t distance) { _slot = _slot->next(distance); return *this; } VariantSlot *internal() { return _slot; } private: MemoryPool *_pool; VariantSlot *_slot; }; class VariantConstPtr { public: VariantConstPtr(const VariantData *data) : _variant(data) {} VariantConstRef *operator->() { return &_variant; } VariantConstRef &operator*() { return _variant; } private: VariantConstRef _variant; }; class ArrayConstRefIterator { public: ArrayConstRefIterator() : _slot(0) {} explicit ArrayConstRefIterator(const VariantSlot *slot) : _slot(slot) {} VariantConstRef operator*() const { return VariantConstRef(_slot->data()); } VariantConstPtr operator->() { return VariantConstPtr(_slot->data()); } bool operator==(const ArrayConstRefIterator &other) const { return _slot == other._slot; } bool operator!=(const ArrayConstRefIterator &other) const { return _slot != other._slot; } ArrayConstRefIterator &operator++() { _slot = _slot->next(); return *this; } ArrayConstRefIterator &operator+=(size_t distance) { _slot = _slot->next(distance); return *this; } const VariantSlot *internal() { return _slot; } private: const VariantSlot *_slot; }; } // namespace ARDUINOJSON_NAMESPACE #define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \ ((NUMBER_OF_ELEMENTS) * sizeof(ARDUINOJSON_NAMESPACE::VariantSlot)) namespace ARDUINOJSON_NAMESPACE { class ObjectRef; template class ElementProxy; template class ArrayRefBase { public: operator VariantConstRef() const { const void* data = _data; // prevent warning cast-align return VariantConstRef(reinterpret_cast(data)); } template FORCE_INLINE typename TVisitor::result_type accept(TVisitor& visitor) const { return arrayAccept(_data, visitor); } 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 _data ? _data->nesting() : 0; } FORCE_INLINE size_t size() const { return _data ? _data->size() : 0; } protected: ArrayRefBase(TData* data) : _data(data) {} TData* _data; }; class ArrayConstRef : public ArrayRefBase, public Visitable { friend class ArrayRef; typedef ArrayRefBase base_type; public: typedef ArrayConstRefIterator iterator; FORCE_INLINE iterator begin() const { if (!_data) return iterator(); return iterator(_data->head()); } FORCE_INLINE iterator end() const { return iterator(); } FORCE_INLINE ArrayConstRef() : base_type(0) {} FORCE_INLINE ArrayConstRef(const CollectionData* data) : base_type(data) {} FORCE_INLINE bool operator==(ArrayConstRef rhs) const { return arrayEquals(_data, rhs._data); } FORCE_INLINE VariantConstRef operator[](size_t index) const { return getElement(index); } FORCE_INLINE VariantConstRef getElement(size_t index) const { return VariantConstRef(_data ? _data->getElement(index) : 0); } }; class ArrayRef : public ArrayRefBase, public ArrayShortcuts, public Visitable { typedef ArrayRefBase base_type; public: typedef ArrayIterator iterator; FORCE_INLINE ArrayRef() : base_type(0), _pool(0) {} FORCE_INLINE ArrayRef(MemoryPool* pool, CollectionData* data) : base_type(data), _pool(pool) {} operator VariantRef() { void* data = _data; // prevent warning cast-align return VariantRef(_pool, reinterpret_cast(data)); } operator ArrayConstRef() const { return ArrayConstRef(_data); } VariantRef addElement() const { return VariantRef(_pool, arrayAdd(_data, _pool)); } 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(ArrayConstRef src) const { if (!_data || !src._data) return false; return _data->copyFrom(*src._data, _pool); } FORCE_INLINE bool operator==(ArrayRef rhs) const { return arrayEquals(_data, rhs._data); } FORCE_INLINE VariantRef getOrAddElement(size_t index) const { return VariantRef(_pool, _data ? _data->getOrAddElement(index, _pool) : 0); } FORCE_INLINE VariantRef getElement(size_t index) const { return VariantRef(_pool, _data ? _data->getElement(index) : 0); } FORCE_INLINE void remove(iterator it) const { if (!_data) return; _data->removeSlot(it.internal()); } FORCE_INLINE void remove(size_t index) const { if (!_data) return; _data->removeElement(index); } private: MemoryPool* _pool; }; template typename TVisitor::result_type objectAccept(const CollectionData *obj, TVisitor &visitor) { if (obj) return visitor.visitObject(*obj); else return visitor.visitNull(); } inline bool objectEquals(const CollectionData *lhs, const CollectionData *rhs) { if (lhs == rhs) return true; if (!lhs || !rhs) return false; return lhs->equalsObject(*rhs); } template inline VariantData *objectGetMember(const CollectionData *obj, TAdaptedString key) { if (!obj) return 0; return obj->getMember(key); } template void objectRemove(CollectionData *obj, TAdaptedString key) { if (!obj) return; obj->removeMember(key); } template inline VariantData *objectGetOrAddMember(CollectionData *obj, TAdaptedString key, MemoryPool *pool) { if (!obj) return 0; return obj->getOrAddMember(key, pool); } class String { public: String() : _data(0), _isStatic(true) {} String(const char* data, bool isStaticData = true) : _data(data), _isStatic(isStaticData) {} const char* c_str() const { return _data; } bool isNull() const { return !_data; } bool isStatic() const { return _isStatic; } friend bool operator==(String lhs, String rhs) { if (lhs._data == rhs._data) return true; if (!lhs._data) return false; if (!rhs._data) return false; return strcmp(lhs._data, rhs._data) == 0; } friend bool operator!=(String lhs, String rhs) { if (lhs._data == rhs._data) return false; if (!lhs._data) return true; if (!rhs._data) return true; return strcmp(lhs._data, rhs._data) != 0; } private: const char* _data; bool _isStatic; }; class StringAdapter : public RamStringAdapter { public: StringAdapter(const String& str) : RamStringAdapter(str.c_str()), _isStatic(str.isStatic()) {} bool isStatic() const { return _isStatic; } typedef storage_policies::decide_at_runtime storage_policy; private: bool _isStatic; }; template <> struct IsString : true_type {}; inline StringAdapter adaptString(const String& str) { return StringAdapter(str); } class Pair { public: Pair(MemoryPool* pool, VariantSlot* slot) { if (slot) { _key = String(slot->key(), !slot->ownsKey()); _value = VariantRef(pool, slot->data()); } } String key() const { return _key; } VariantRef value() const { return _value; } private: String _key; VariantRef _value; }; class PairConst { public: PairConst(const VariantSlot* slot) { if (slot) { _key = String(slot->key(), !slot->ownsKey()); _value = VariantConstRef(slot->data()); } } String key() const { return _key; } VariantConstRef value() const { return _value; } private: String _key; VariantConstRef _value; }; class PairPtr { public: PairPtr(MemoryPool *pool, VariantSlot *slot) : _pair(pool, slot) {} const Pair *operator->() const { return &_pair; } const Pair &operator*() const { return _pair; } private: Pair _pair; }; class ObjectIterator { public: ObjectIterator() : _slot(0) {} explicit ObjectIterator(MemoryPool *pool, VariantSlot *slot) : _pool(pool), _slot(slot) {} Pair operator*() const { return Pair(_pool, _slot); } PairPtr operator->() { return PairPtr(_pool, _slot); } bool operator==(const ObjectIterator &other) const { return _slot == other._slot; } bool operator!=(const ObjectIterator &other) const { return _slot != other._slot; } ObjectIterator &operator++() { _slot = _slot->next(); return *this; } ObjectIterator &operator+=(size_t distance) { _slot = _slot->next(distance); return *this; } VariantSlot *internal() { return _slot; } private: MemoryPool *_pool; VariantSlot *_slot; }; class PairConstPtr { public: PairConstPtr(const VariantSlot *slot) : _pair(slot) {} const PairConst *operator->() const { return &_pair; } const PairConst &operator*() const { return _pair; } private: PairConst _pair; }; class ObjectConstIterator { public: ObjectConstIterator() : _slot(0) {} explicit ObjectConstIterator(const VariantSlot *slot) : _slot(slot) {} PairConst operator*() const { return PairConst(_slot); } PairConstPtr operator->() { return PairConstPtr(_slot); } bool operator==(const ObjectConstIterator &other) const { return _slot == other._slot; } bool operator!=(const ObjectConstIterator &other) const { return _slot != other._slot; } ObjectConstIterator &operator++() { _slot = _slot->next(); return *this; } ObjectConstIterator &operator+=(size_t distance) { _slot = _slot->next(distance); return *this; } const VariantSlot *internal() { return _slot; } private: const VariantSlot *_slot; }; } // namespace ARDUINOJSON_NAMESPACE #define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \ ((NUMBER_OF_ELEMENTS) * sizeof(ARDUINOJSON_NAMESPACE::VariantSlot)) namespace ARDUINOJSON_NAMESPACE { template class ObjectRefBase { public: operator VariantConstRef() const { const void* data = _data; // prevent warning cast-align return VariantConstRef(reinterpret_cast(data)); } template typename TVisitor::result_type accept(TVisitor& visitor) const { return objectAccept(_data, visitor); } 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 _data ? _data->nesting() : 0; } FORCE_INLINE size_t size() const { return _data ? _data->size() : 0; } protected: ObjectRefBase(TData* data) : _data(data) {} TData* _data; }; class ObjectConstRef : public ObjectRefBase, public Visitable { friend class ObjectRef; typedef ObjectRefBase base_type; public: typedef ObjectConstIterator iterator; ObjectConstRef() : base_type(0) {} ObjectConstRef(const CollectionData* data) : base_type(data) {} 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(key).isUndefined(); } template FORCE_INLINE bool containsKey(TChar* key) const { return !getMember(key).isUndefined(); } template FORCE_INLINE VariantConstRef getMember(const TString& key) const { return get_impl(adaptString(key)); } template FORCE_INLINE VariantConstRef getMember(TChar* key) const { return get_impl(adaptString(key)); } template FORCE_INLINE typename enable_if::value, VariantConstRef>::type operator[](const TString& key) const { return get_impl(adaptString(key)); } template FORCE_INLINE typename enable_if::value, VariantConstRef>::type operator[](TChar* key) const { return get_impl(adaptString(key)); } FORCE_INLINE bool operator==(ObjectConstRef rhs) const { return objectEquals(_data, rhs._data); } private: template FORCE_INLINE VariantConstRef get_impl(TAdaptedString key) const { return VariantConstRef(objectGetMember(_data, key)); } }; class ObjectRef : public ObjectRefBase, public ObjectShortcuts, public Visitable { typedef ObjectRefBase base_type; public: typedef ObjectIterator iterator; FORCE_INLINE ObjectRef() : base_type(0), _pool(0) {} FORCE_INLINE ObjectRef(MemoryPool* buf, CollectionData* data) : base_type(data), _pool(buf) {} operator VariantRef() const { void* data = _data; // prevent warning cast-align return VariantRef(_pool, reinterpret_cast(data)); } operator ObjectConstRef() const { return ObjectConstRef(_data); } 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(ObjectConstRef src) { if (!_data || !src._data) return false; return _data->copyFrom(*src._data, _pool); } template FORCE_INLINE VariantRef getMember(const TString& key) const { return VariantRef(_pool, objectGetMember(_data, adaptString(key))); } template FORCE_INLINE VariantRef getMember(TChar* key) const { return VariantRef(_pool, objectGetMember(_data, adaptString(key))); } template FORCE_INLINE VariantRef getOrAddMember(const TString& key) const { return VariantRef(_pool, objectGetOrAddMember(_data, adaptString(key), _pool)); } template FORCE_INLINE VariantRef getOrAddMember(TChar* key) const { return VariantRef(_pool, objectGetOrAddMember(_data, adaptString(key), _pool)); } FORCE_INLINE bool operator==(ObjectRef rhs) const { return objectEquals(_data, rhs._data); } FORCE_INLINE void remove(iterator it) const { if (!_data) return; _data->removeSlot(it.internal()); } template FORCE_INLINE void remove(const TString& key) const { objectRemove(_data, adaptString(key)); } template FORCE_INLINE void remove(TChar* key) const { objectRemove(_data, adaptString(key)); } private: MemoryPool* _pool; }; class ArrayRef; class ObjectRef; class VariantRef; template struct VariantTo {}; template <> struct VariantTo { typedef ArrayRef type; }; template <> struct VariantTo { typedef ObjectRef type; }; template <> struct VariantTo { typedef VariantRef type; }; } // namespace ARDUINOJSON_NAMESPACE #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4522) #endif namespace ARDUINOJSON_NAMESPACE { template class ElementProxy : public VariantOperators >, public VariantShortcuts >, public Visitable, public VariantTag { typedef ElementProxy this_type; public: typedef VariantRef variant_type; FORCE_INLINE ElementProxy(TArray array, size_t index) : _array(array), _index(index) {} FORCE_INLINE ElementProxy(const ElementProxy& src) : _array(src._array), _index(src._index) {} FORCE_INLINE this_type& operator=(const this_type& src) { getOrAddUpstreamElement().set(src.as()); return *this; } template FORCE_INLINE this_type& operator=(const T& src) { getOrAddUpstreamElement().set(src); return *this; } template FORCE_INLINE this_type& operator=(T* src) { getOrAddUpstreamElement().set(src); return *this; } FORCE_INLINE void clear() const { getUpstreamElement().clear(); } FORCE_INLINE bool isNull() const { return getUpstreamElement().isNull(); } template FORCE_INLINE typename VariantAs::type as() const { return getUpstreamElement().template as(); } template FORCE_INLINE operator T() const { return getUpstreamElement(); } template FORCE_INLINE bool is() const { return getUpstreamElement().template is(); } template FORCE_INLINE typename VariantTo::type to() const { return getOrAddUpstreamElement().template to(); } template FORCE_INLINE bool set(const TValue& value) const { return getOrAddUpstreamElement().set(value); } template FORCE_INLINE bool set(TValue* value) const { return getOrAddUpstreamElement().set(value); } template typename TVisitor::result_type accept(TVisitor& visitor) const { return getUpstreamElement().accept(visitor); } FORCE_INLINE size_t size() const { return getUpstreamElement().size(); } template VariantRef getMember(TNestedKey* key) const { return getUpstreamElement().getMember(key); } template VariantRef getMember(const TNestedKey& key) const { return getUpstreamElement().getMember(key); } template VariantRef getOrAddMember(TNestedKey* key) const { return getOrAddUpstreamElement().getOrAddMember(key); } template VariantRef getOrAddMember(const TNestedKey& key) const { return getOrAddUpstreamElement().getOrAddMember(key); } VariantRef addElement() const { return getOrAddUpstreamElement().addElement(); } VariantRef getElement(size_t index) const { return getOrAddUpstreamElement().getElement(index); } VariantRef getOrAddElement(size_t index) const { return getOrAddUpstreamElement().getOrAddElement(index); } FORCE_INLINE void remove(size_t index) const { getUpstreamElement().remove(index); } template FORCE_INLINE typename enable_if::value>::type remove( TChar* key) const { getUpstreamElement().remove(key); } template FORCE_INLINE typename enable_if::value>::type remove( const TString& key) const { getUpstreamElement().remove(key); } private: FORCE_INLINE VariantRef getUpstreamElement() const { return _array.getElement(_index); } FORCE_INLINE VariantRef getOrAddUpstreamElement() const { return _array.getOrAddElement(_index); } TArray _array; const size_t _index; }; } // namespace ARDUINOJSON_NAMESPACE #ifdef _MSC_VER #pragma warning(pop) #endif #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4522) #endif namespace ARDUINOJSON_NAMESPACE { template class MemberProxy : public VariantOperators >, public VariantShortcuts >, public Visitable, public VariantTag { typedef MemberProxy this_type; public: typedef VariantRef variant_type; FORCE_INLINE MemberProxy(TObject variant, TStringRef key) : _object(variant), _key(key) {} FORCE_INLINE MemberProxy(const MemberProxy &src) : _object(src._object), _key(src._key) {} FORCE_INLINE operator VariantConstRef() const { return getUpstreamMember(); } FORCE_INLINE this_type &operator=(const this_type &src) { getOrAddUpstreamMember().set(src); return *this; } template FORCE_INLINE typename enable_if::value, this_type &>::type operator=(const TValue &src) { getOrAddUpstreamMember().set(src); return *this; } template FORCE_INLINE this_type &operator=(TChar *src) { getOrAddUpstreamMember().set(src); return *this; } FORCE_INLINE void clear() const { getUpstreamMember().clear(); } FORCE_INLINE bool isNull() const { return getUpstreamMember().isNull(); } template FORCE_INLINE typename VariantAs::type as() const { return getUpstreamMember().template as(); } template FORCE_INLINE operator T() const { return getUpstreamMember(); } template FORCE_INLINE bool is() const { return getUpstreamMember().template is(); } FORCE_INLINE size_t size() const { return getUpstreamMember().size(); } FORCE_INLINE void remove(size_t index) const { getUpstreamMember().remove(index); } template FORCE_INLINE typename enable_if::value>::type remove( TChar *key) const { getUpstreamMember().remove(key); } template FORCE_INLINE typename enable_if::value>::type remove( const TString &key) const { getUpstreamMember().remove(key); } template FORCE_INLINE typename VariantTo::type to() { return getOrAddUpstreamMember().template to(); } template FORCE_INLINE bool set(const TValue &value) { return getOrAddUpstreamMember().set(value); } template FORCE_INLINE bool set(TChar *value) { return getOrAddUpstreamMember().set(value); } template typename TVisitor::result_type accept(TVisitor &visitor) const { return getUpstreamMember().accept(visitor); } FORCE_INLINE VariantRef addElement() const { return getOrAddUpstreamMember().addElement(); } FORCE_INLINE VariantRef getElement(size_t index) const { return getUpstreamMember().getElement(index); } FORCE_INLINE VariantRef getOrAddElement(size_t index) const { return getOrAddUpstreamMember().getOrAddElement(index); } template FORCE_INLINE VariantRef getMember(TChar *key) const { return getUpstreamMember().getMember(key); } template FORCE_INLINE VariantRef getMember(const TString &key) const { return getUpstreamMember().getMember(key); } template FORCE_INLINE VariantRef getOrAddMember(TChar *key) const { return getOrAddUpstreamMember().getOrAddMember(key); } template FORCE_INLINE VariantRef getOrAddMember(const TString &key) const { return getOrAddUpstreamMember().getOrAddMember(key); } private: FORCE_INLINE VariantRef getUpstreamMember() const { return _object.getMember(_key); } FORCE_INLINE VariantRef getOrAddUpstreamMember() const { return _object.getOrAddMember(_key); } TObject _object; TStringRef _key; }; } // namespace ARDUINOJSON_NAMESPACE #ifdef _MSC_VER #pragma warning(pop) #endif namespace ARDUINOJSON_NAMESPACE { class JsonDocument : public Visitable { public: template typename TVisitor::result_type accept(TVisitor& visitor) const { return getVariant().accept(visitor); } template typename VariantAs::type as() { return getVariant().template as(); } template typename VariantConstAs::type as() const { return getVariant().template as(); } void clear() { _pool.clear(); _data.setNull(); } 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 _data.nesting(); } 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(); } MemoryPool& memoryPool() { return _pool; } VariantData& data() { return _data; } ArrayRef createNestedArray() { return addElement().to(); } template ArrayRef createNestedArray(TChar* key) { return getOrAddMember(key).template to(); } template ArrayRef createNestedArray(const TString& key) { return getOrAddMember(key).template to(); } ObjectRef createNestedObject() { return addElement().to(); } template ObjectRef createNestedObject(TChar* key) { return getOrAddMember(key).template to(); } template ObjectRef createNestedObject(const TString& key) { return getOrAddMember(key).template to(); } template bool containsKey(TChar* key) const { return !getMember(key).isUndefined(); } template bool containsKey(const TString& key) const { return !getMember(key).isUndefined(); } 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, VariantConstRef>::type operator[](const TString& key) const { return getMember(key); } template FORCE_INLINE typename enable_if::value, VariantConstRef>::type operator[](TChar* key) const { return getMember(key); } FORCE_INLINE ElementProxy operator[](size_t index) { return ElementProxy(*this, index); } FORCE_INLINE VariantConstRef operator[](size_t index) const { return getElement(index); } FORCE_INLINE VariantRef getElement(size_t index) { return VariantRef(&_pool, _data.getElement(index)); } FORCE_INLINE VariantConstRef getElement(size_t index) const { return VariantConstRef(_data.getElement(index)); } FORCE_INLINE VariantRef getOrAddElement(size_t index) { return VariantRef(&_pool, _data.getOrAddElement(index, &_pool)); } template FORCE_INLINE VariantConstRef getMember(TChar* key) const { return VariantConstRef(_data.getMember(adaptString(key))); } template FORCE_INLINE typename enable_if::value, VariantConstRef>::type getMember(const TString& key) const { return VariantConstRef(_data.getMember(adaptString(key))); } template FORCE_INLINE VariantRef getMember(TChar* key) { return VariantRef(&_pool, _data.getMember(adaptString(key))); } template FORCE_INLINE typename enable_if::value, VariantRef>::type getMember(const TString& key) { return VariantRef(&_pool, _data.getMember(adaptString(key))); } template FORCE_INLINE VariantRef getOrAddMember(TChar* key) { return VariantRef(&_pool, _data.getOrAddMember(adaptString(key), &_pool)); } template FORCE_INLINE VariantRef getOrAddMember(const TString& key) { return VariantRef(&_pool, _data.getOrAddMember(adaptString(key), &_pool)); } FORCE_INLINE VariantRef addElement() { return VariantRef(&_pool, _data.addElement(&_pool)); } template FORCE_INLINE bool add(const TValue& value) { return addElement().set(value); } template FORCE_INLINE bool add(TChar* value) { return addElement().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 VariantConstRef() const { return VariantConstRef(&_data); } bool operator==(VariantConstRef rhs) const { return getVariant() == rhs; } bool operator!=(VariantConstRef rhs) const { return getVariant() != rhs; } protected: JsonDocument() : _pool(0, 0) { _data.setNull(); } JsonDocument(MemoryPool pool) : _pool(pool) { _data.setNull(); } JsonDocument(char* buf, size_t capa) : _pool(buf, capa) { _data.setNull(); } ~JsonDocument() {} void replacePool(MemoryPool pool) { _pool = pool; } VariantRef getVariant() { return VariantRef(&_pool, &_data); } VariantConstRef getVariant() const { return VariantConstRef(&_data); } MemoryPool _pool; VariantData _data; private: JsonDocument(const JsonDocument&); JsonDocument& operator=(const JsonDocument&); }; template class AllocatorOwner { public: AllocatorOwner() {} AllocatorOwner(const AllocatorOwner& src) : _allocator(src._allocator) {} 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(VariantRef 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) { reallocPoolIfTooSmall(src.memoryUsage()); 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 reallocPoolIfTooSmall(size_t requiredSize) { if (requiredSize <= capacity()) return; freePool(); replacePool(allocPool(addPadding(requiredSize))); } void freePool() { this->deallocate(memoryPool().buffer()); } void copyAssignFrom(const JsonDocument& src) { reallocPoolIfTooSmall(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(VariantRef 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]; }; template inline ArrayRef ArrayShortcuts::createNestedArray() const { return impl()->addElement().template to(); } template inline ObjectRef ArrayShortcuts::createNestedObject() const { return impl()->addElement().template to(); } template inline ElementProxy ArrayShortcuts::operator[]( size_t index) const { return ElementProxy(*impl(), index); } template inline typename enable_if::value && !is_base_of::value, bool>::type copyArray(T (&src)[N], const TDestination& dst) { return copyArray(src, N, dst); } template inline bool copyArray(T (&src)[N], JsonDocument& dst) { return copyArray(src, dst.to()); } template inline typename enable_if::value && !is_base_of::value, bool>::type copyArray(T* src, size_t len, const TDestination& dst) { bool ok = true; for (size_t i = 0; i < len; i++) { ok &= dst.add(src[i]); } return ok; } template inline bool copyArray(T* src, size_t len, JsonDocument& dst) { return copyArray(src, len, dst.to()); } template inline typename enable_if::value, bool>::type copyArray(T (&src)[N1][N2], const TDestination& dst) { bool ok = true; for (size_t i = 0; i < N1; i++) { ArrayRef nestedArray = dst.createNestedArray(); for (size_t j = 0; j < N2; j++) { ok &= nestedArray.add(src[i][j]); } } return ok; } template inline bool copyArray(T (&src)[N1][N2], JsonDocument& dst) { return copyArray(src, dst.to()); } template class ArrayCopier1D : public Visitor { public: ArrayCopier1D(T* destination, size_t capacity) : _destination(destination), _capacity(capacity) {} size_t visitArray(const CollectionData& array) { size_t size = 0; VariantSlot* slot = array.head(); while (slot != 0 && size < _capacity) { _destination[size++] = variantAs(slot->data()); slot = slot->next(); } return size; } size_t visitObject(const CollectionData&) { return 0; } size_t visitFloat(Float) { return 0; } size_t visitString(const char*) { return 0; } size_t visitRawJson(const char*, size_t) { return 0; } size_t visitNegativeInteger(UInt) { return 0; } size_t visitPositiveInteger(UInt) { return 0; } size_t visitBoolean(bool) { return 0; } size_t visitNull() { return 0; } private: T* _destination; size_t _capacity; }; template class ArrayCopier2D : public Visitor { public: ArrayCopier2D(T (*destination)[N1][N2]) : _destination(destination) {} void visitArray(const CollectionData& array) { VariantSlot* slot = array.head(); size_t n = 0; while (slot != 0 && n < N1) { ArrayCopier1D copier((*_destination)[n++], N2); variantAccept(slot->data(), copier); slot = slot->next(); } } void visitObject(const CollectionData&) {} void visitFloat(Float) {} void visitString(const char*) {} void visitRawJson(const char*, size_t) {} void visitNegativeInteger(UInt) {} void visitPositiveInteger(UInt) {} void visitBoolean(bool) {} void visitNull() {} private: T (*_destination)[N1][N2]; size_t _capacity1, _capacity2; }; template inline typename enable_if::value, size_t>::type copyArray( const TSource& src, T (&dst)[N]) { return copyArray(src, dst, N); } template inline size_t copyArray(const TSource& src, T* dst, size_t len) { ArrayCopier1D copier(dst, len); return src.accept(copier); } template inline void copyArray(const TSource& src, T (&dst)[N1][N2]) { ArrayCopier2D copier(&dst); src.accept(copier); } inline bool variantEquals(const VariantData* a, const VariantData* b) { return variantCompare(a, b) == COMPARE_RESULT_EQUAL; } inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) { VariantSlot* slot = pool->allocVariant(); if (!slot) return 0; if (_tail) { _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) { if (s->ownsKey()) var = addMember(RamStringAdapter(s->key()), pool); else var = addMember(ConstRamStringAdapter(s->key()), pool); } else { var = addElement(pool); } if (!var) return false; if (!var->copyFrom(*s->data(), pool)) return false; } return true; } inline bool CollectionData::equalsObject(const CollectionData& other) const { size_t count = 0; for (VariantSlot* slot = _head; slot; slot = slot->next()) { VariantData* v1 = slot->data(); VariantData* v2 = other.getMember(adaptString(slot->key())); if (!variantEquals(v1, v2)) return false; count++; } return count == other.size(); } inline bool CollectionData::equalsArray(const CollectionData& other) const { VariantSlot* s1 = _head; VariantSlot* s2 = other._head; for (;;) { if (s1 == s2) return true; if (!s1 || !s2) return false; if (!variantEquals(s1->data(), s2->data())) return false; s1 = s1->next(); s2 = s2->next(); } } template inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const { VariantSlot* slot = _head; while (slot) { if (key.equals(slot->key())) break; slot = slot->next(); } return slot; } inline VariantSlot* CollectionData::getSlot(size_t index) const { 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::nesting() const { size_t maxChildNesting = 0; for (VariantSlot* s = _head; s; s = s->next()) { size_t childNesting = s->data()->nesting(); if (childNesting > maxChildNesting) maxChildNesting = childNesting; } return maxChildNesting + 1; } 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 template inline ArrayRef ObjectShortcuts::createNestedArray( const TString& key) const { return impl()->getOrAddMember(key).template to(); } template template inline ArrayRef ObjectShortcuts::createNestedArray(TChar* key) const { return impl()->getOrAddMember(key).template to(); } template template inline ObjectRef ObjectShortcuts::createNestedObject( const TString& key) const { return impl()->getOrAddMember(key).template to(); } template template inline ObjectRef ObjectShortcuts::createNestedObject( TChar* key) const { return impl()->getOrAddMember(key).template to(); } template template inline typename enable_if::value, bool>::type ObjectShortcuts::containsKey(const TString& key) const { return !impl()->getMember(key).isUndefined(); } template template inline typename enable_if::value, bool>::type ObjectShortcuts::containsKey(TChar* key) const { return !impl()->getMember(key).isUndefined(); } template template inline typename enable_if::value, MemberProxy >::type ObjectShortcuts::operator[](TString* key) const { return MemberProxy(*impl(), key); } template template inline typename enable_if::value, MemberProxy >::type ObjectShortcuts::operator[](const TString& key) const { return MemberProxy(*impl(), key); } template inline typename enable_if::value, T>::type variantAs( const VariantData* _data) { return ArrayConstRef(variantAsArray(_data)); } template inline typename enable_if::value, T>::type variantAs( const VariantData* _data) { return ObjectConstRef(variantAsObject(_data)); } template inline typename enable_if::value, T>::type variantAs(const VariantData* _data) { return VariantConstRef(_data); } template inline typename enable_if::value, T>::type variantAs( const VariantData* _data) { const char* cstr = _data != 0 ? _data->asString() : 0; if (cstr) return T(cstr); T s; serializeJson(VariantConstRef(_data), s); return s; } template <> inline ArrayRef variantAs(VariantData* data, MemoryPool* pool) { return ArrayRef(pool, data != 0 ? data->asArray() : 0); } template <> inline ObjectRef variantAs(VariantData* data, MemoryPool* pool) { return ObjectRef(pool, data != 0 ? data->asObject() : 0); } template <> inline VariantRef variantAs(VariantData* data, MemoryPool* pool) { return VariantRef(pool, data); } class CollectionData; struct ComparerBase : Visitor { CompareResult visitArray(const CollectionData &) { return COMPARE_RESULT_DIFFER; } CompareResult visitBoolean(bool) { return COMPARE_RESULT_DIFFER; } CompareResult visitFloat(Float) { return COMPARE_RESULT_DIFFER; } CompareResult visitNegativeInteger(UInt) { return COMPARE_RESULT_DIFFER; } CompareResult visitNull() { return COMPARE_RESULT_DIFFER; } CompareResult visitObject(const CollectionData &) { return COMPARE_RESULT_DIFFER; } CompareResult visitPositiveInteger(UInt) { return COMPARE_RESULT_DIFFER; } CompareResult visitRawJson(const char *, size_t) { return COMPARE_RESULT_DIFFER; } CompareResult visitString(const char *) { return COMPARE_RESULT_DIFFER; } }; template struct Comparer; template struct Comparer::value>::type> : ComparerBase { T rhs; explicit Comparer(T value) : rhs(value) {} CompareResult visitString(const char *lhs) { int i = adaptString(rhs).compare(lhs); if (i < 0) return COMPARE_RESULT_GREATER; else if (i > 0) return COMPARE_RESULT_LESS; else return COMPARE_RESULT_EQUAL; } CompareResult visitNull() { if (adaptString(rhs).isNull()) return COMPARE_RESULT_EQUAL; else return COMPARE_RESULT_DIFFER; } }; template struct Comparer::value || is_floating_point::value>::type> : ComparerBase { T rhs; explicit Comparer(T value) : rhs(value) {} CompareResult visitFloat(Float lhs) { return arithmeticCompare(lhs, rhs); } CompareResult visitNegativeInteger(UInt lhs) { return arithmeticCompareNegateLeft(lhs, rhs); } CompareResult visitPositiveInteger(UInt lhs) { return arithmeticCompare(lhs, rhs); } CompareResult visitBoolean(bool lhs) { return visitPositiveInteger(static_cast(lhs)); } }; struct NullComparer : ComparerBase { CompareResult visitNull() { return COMPARE_RESULT_EQUAL; } }; #if ARDUINOJSON_HAS_NULLPTR template <> struct Comparer : NullComparer { explicit Comparer(decltype(nullptr)) : NullComparer() {} }; #endif struct ArrayComparer : ComparerBase { const CollectionData *_rhs; explicit ArrayComparer(const CollectionData &rhs) : _rhs(&rhs) {} CompareResult visitArray(const CollectionData &lhs) { if (lhs.equalsArray(*_rhs)) return COMPARE_RESULT_EQUAL; else return COMPARE_RESULT_DIFFER; } }; struct NegativeIntegerComparer : ComparerBase { UInt _rhs; explicit NegativeIntegerComparer(UInt rhs) : _rhs(rhs) {} CompareResult visitFloat(Float lhs) { return arithmeticCompareNegateRight(lhs, _rhs); } CompareResult visitNegativeInteger(UInt lhs) { return arithmeticCompare(_rhs, lhs); } CompareResult visitPositiveInteger(UInt) { return COMPARE_RESULT_GREATER; } CompareResult visitBoolean(bool) { return COMPARE_RESULT_GREATER; } }; struct ObjectComparer : ComparerBase { const CollectionData *_rhs; explicit ObjectComparer(const CollectionData &rhs) : _rhs(&rhs) {} CompareResult visitObject(const CollectionData &lhs) { if (lhs.equalsObject(*_rhs)) return COMPARE_RESULT_EQUAL; else return COMPARE_RESULT_DIFFER; } }; struct RawComparer : ComparerBase { const char *_rhsData; size_t _rhsSize; explicit RawComparer(const char *rhsData, size_t rhsSize) : _rhsData(rhsData), _rhsSize(rhsSize) {} CompareResult visitRawJson(const char *lhsData, size_t lhsSize) { size_t size = _rhsSize < lhsSize ? _rhsSize : lhsSize; int n = memcmp(lhsData, _rhsData, size); if (n < 0) return COMPARE_RESULT_LESS; else if (n > 0) return COMPARE_RESULT_GREATER; else return COMPARE_RESULT_EQUAL; } }; template struct Comparer::value>::type> : ComparerBase { T rhs; explicit Comparer(T value) : rhs(value) {} CompareResult visitArray(const CollectionData &lhs) { ArrayComparer comparer(lhs); return accept(comparer); } CompareResult visitObject(const CollectionData &lhs) { ObjectComparer comparer(lhs); return accept(comparer); } CompareResult visitFloat(Float lhs) { Comparer comparer(lhs); return accept(comparer); } CompareResult visitString(const char *lhs) { Comparer comparer(lhs); return accept(comparer); } CompareResult visitRawJson(const char *lhsData, size_t lhsSize) { RawComparer comparer(lhsData, lhsSize); return accept(comparer); } CompareResult visitNegativeInteger(UInt lhs) { NegativeIntegerComparer comparer(lhs); return accept(comparer); } CompareResult visitPositiveInteger(UInt lhs) { Comparer comparer(lhs); return accept(comparer); } CompareResult visitBoolean(bool lhs) { Comparer comparer(lhs); return accept(comparer); } CompareResult visitNull() { NullComparer comparer; return accept(comparer); } private: template CompareResult accept(TComparer &comparer) { CompareResult reversedResult = rhs.accept(comparer); switch (reversedResult) { case COMPARE_RESULT_GREATER: return COMPARE_RESULT_LESS; case COMPARE_RESULT_LESS: return COMPARE_RESULT_GREATER; default: return reversedResult; } } }; template CompareResult compare(const T1 &lhs, const T2 &rhs) { Comparer comparer(rhs); return lhs.accept(comparer); } inline int variantCompare(const VariantData *a, const VariantData *b) { return compare(VariantConstRef(a), VariantConstRef(b)); } #ifndef isdigit inline bool isdigit(char c) { return '0' <= c && c <= '9'; } #endif inline bool issign(char c) { return '-' == c || c == '+'; } template struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> {}; inline bool parseNumber(const char* s, VariantData& result) { typedef FloatTraits traits; typedef choose_largest::type mantissa_t; typedef traits::exponent_type exponent_t; ARDUINOJSON_ASSERT(s != 0); bool is_negative = false; switch (*s) { case '-': is_negative = true; s++; break; case '+': s++; break; } #if ARDUINOJSON_ENABLE_NAN if (*s == 'n' || *s == 'N') { result.setFloat(traits::nan()); return true; } #endif #if ARDUINOJSON_ENABLE_INFINITY if (*s == 'i' || *s == 'I') { result.setFloat(is_negative ? -traits::inf() : traits::inf()); return true; } #endif if (!isdigit(*s) && *s != '.') return false; mantissa_t mantissa = 0; exponent_t exponent_offset = 0; const mantissa_t maxUint = UInt(-1); while (isdigit(*s)) { uint8_t digit = uint8_t(*s - '0'); if (mantissa > maxUint / 10) break; mantissa *= 10; if (mantissa > maxUint - digit) break; mantissa += digit; s++; } if (*s == '\0') { if (is_negative) result.setNegativeInteger(UInt(mantissa)); else result.setPositiveInteger(UInt(mantissa)); return true; } while (mantissa > traits::mantissa_max) { mantissa /= 10; exponent_offset++; } while (isdigit(*s)) { exponent_offset++; s++; } if (*s == '.') { s++; while (isdigit(*s)) { if (mantissa < traits::mantissa_max / 10) { mantissa = mantissa * 10 + uint8_t(*s - '0'); exponent_offset--; } s++; } } int exponent = 0; if (*s == 'e' || *s == 'E') { s++; bool negative_exponent = false; if (*s == '-') { negative_exponent = true; s++; } else if (*s == '+') { s++; } while (isdigit(*s)) { exponent = exponent * 10 + (*s - '0'); if (exponent + exponent_offset > traits::exponent_max) { if (negative_exponent) result.setFloat(is_negative ? -0.0f : 0.0f); else result.setFloat(is_negative ? -traits::inf() : traits::inf()); return true; } s++; } if (negative_exponent) exponent = -exponent; } exponent += exponent_offset; if (*s != '\0') return false; Float final_result = traits::make_float(static_cast(mantissa), exponent); result.setFloat(is_negative ? -final_result : final_result); return true; } template inline T parseNumber(const char* s) { VariantData value; value.init(); // VariantData is a POD, so it has no constructor parseNumber(s, value); return variantAs(&value); } template inline T VariantData::asIntegral() const { switch (type()) { case VALUE_IS_POSITIVE_INTEGER: case VALUE_IS_BOOLEAN: return convertPositiveInteger(_content.asInteger); case VALUE_IS_NEGATIVE_INTEGER: return convertNegativeInteger(_content.asInteger); case VALUE_IS_LINKED_STRING: case VALUE_IS_OWNED_STRING: return parseNumber(_content.asString); case VALUE_IS_FLOAT: return convertFloat(_content.asFloat); default: return 0; } } inline bool VariantData::asBoolean() const { switch (type()) { case VALUE_IS_POSITIVE_INTEGER: case VALUE_IS_BOOLEAN: case VALUE_IS_NEGATIVE_INTEGER: return _content.asInteger != 0; case VALUE_IS_FLOAT: return _content.asFloat != 0; case VALUE_IS_NULL: return false; default: return true; } } template inline T VariantData::asFloat() const { switch (type()) { case VALUE_IS_POSITIVE_INTEGER: case VALUE_IS_BOOLEAN: return static_cast(_content.asInteger); case VALUE_IS_NEGATIVE_INTEGER: return -static_cast(_content.asInteger); case VALUE_IS_LINKED_STRING: case VALUE_IS_OWNED_STRING: return parseNumber(_content.asString); case VALUE_IS_FLOAT: return static_cast(_content.asFloat); default: return 0; } } inline const char *VariantData::asString() const { switch (type()) { case VALUE_IS_LINKED_STRING: case VALUE_IS_OWNED_STRING: return _content.asString; default: return 0; } } template typename enable_if::value, bool>::type VariantRef::set( const TVariant &value) const { VariantConstRef v = value; return variantCopyFrom(_data, v._data, _pool); } template inline typename enable_if::value, ArrayRef>::type VariantRef::to() const { return ArrayRef(_pool, variantToArray(_data)); } template typename enable_if::value, ObjectRef>::type VariantRef::to() const { return ObjectRef(_pool, variantToObject(_data)); } template typename enable_if::value, VariantRef>::type VariantRef::to() const { variantSetNull(_data); return *this; } inline VariantConstRef VariantConstRef::getElement(size_t index) const { return ArrayConstRef(_data != 0 ? _data->asArray() : 0)[index]; } inline VariantRef VariantRef::addElement() const { return VariantRef(_pool, variantAddElement(_data, _pool)); } inline VariantRef VariantRef::getElement(size_t index) const { return VariantRef(_pool, _data != 0 ? _data->getElement(index) : 0); } inline VariantRef VariantRef::getOrAddElement(size_t index) const { return VariantRef(_pool, variantGetOrAddElement(_data, index, _pool)); } template inline VariantRef VariantRef::getMember(TChar *key) const { return VariantRef(_pool, _data != 0 ? _data->getMember(adaptString(key)) : 0); } template inline typename enable_if::value, VariantRef>::type VariantRef::getMember(const TString &key) const { return VariantRef(_pool, _data != 0 ? _data->getMember(adaptString(key)) : 0); } template inline VariantRef VariantRef::getOrAddMember(TChar *key) const { return VariantRef(_pool, variantGetOrAddMember(_data, key, _pool)); } template inline VariantRef VariantRef::getOrAddMember(const TString &key) const { return VariantRef(_pool, variantGetOrAddMember(_data, key, _pool)); } inline VariantConstRef operator|(VariantConstRef preferedValue, VariantConstRef defaultValue) { return preferedValue ? preferedValue : defaultValue; } } // namespace ARDUINOJSON_NAMESPACE #if ARDUINOJSON_ENABLE_STD_STREAM #include #endif namespace ARDUINOJSON_NAMESPACE { class DeserializationError { typedef void (DeserializationError::*bool_type)() const; void safeBoolHelper() const {} public: enum Code { Ok, EmptyInput, IncompleteInput, InvalidInput, NoMemory, NotSupported, TooDeep }; DeserializationError() {} DeserializationError(Code c) : _code(c) {} friend bool operator==(const DeserializationError& lhs, const DeserializationError& rhs) { return lhs._code == rhs._code; } friend bool operator!=(const DeserializationError& lhs, const DeserializationError& rhs) { return lhs._code != rhs._code; } friend bool operator==(const DeserializationError& lhs, Code rhs) { return lhs._code == rhs; } friend bool operator==(Code lhs, const DeserializationError& rhs) { return lhs == rhs._code; } friend bool operator!=(const DeserializationError& lhs, Code rhs) { return lhs._code != rhs; } friend bool operator!=(Code lhs, const DeserializationError& rhs) { return lhs != rhs._code; } operator bool_type() const { return _code != Ok ? &DeserializationError::safeBoolHelper : 0; } friend bool operator==(bool value, const DeserializationError& err) { return static_cast(err) == value; } friend bool operator==(const DeserializationError& err, bool value) { return static_cast(err) == value; } friend bool operator!=(bool value, const DeserializationError& err) { return static_cast(err) != value; } friend bool operator!=(const DeserializationError& err, bool value) { return static_cast(err) != value; } Code code() const { return _code; } const char* c_str() const { static const char* messages[] = { "Ok", "EmptyInput", "IncompleteInput", "InvalidInput", "NoMemory", "NotSupported", "TooDeep"}; ARDUINOJSON_ASSERT(static_cast(_code) < sizeof(messages) / sizeof(messages[0])); return messages[_code]; } #if ARDUINOJSON_ENABLE_PROGMEM const __FlashStringHelper* f_str() const { ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s0, "Ok"); ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s1, "EmptyInput"); ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s2, "IncompleteInput"); ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s3, "InvalidInput"); ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s4, "NoMemory"); ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s5, "NotSupported"); ARDUINOJSON_DEFINE_STATIC_ARRAY(char, s6, "TooDeep"); ARDUINOJSON_DEFINE_STATIC_ARRAY( const char*, messages, ARDUINOJSON_EXPAND7({s0, s1, s2, s3, s4, s5, s6})); return ARDUINOJSON_READ_STATIC_ARRAY(const __FlashStringHelper*, messages, _code); } #endif private: Code _code; }; #if ARDUINOJSON_ENABLE_STD_STREAM inline std::ostream& operator<<(std::ostream& s, const DeserializationError& e) { s << e.c_str(); return s; } inline std::ostream& operator<<(std::ostream& s, DeserializationError::Code c) { s << DeserializationError(c).c_str(); return s; } #endif class Filter { public: explicit Filter(VariantConstRef v) : _variant(v) {} bool allow() const { return _variant; } bool allowArray() const { return _variant == true || _variant.is(); } bool allowObject() const { return _variant == true || _variant.is(); } bool allowValue() const { return _variant == true; } template Filter operator[](const TKey& key) const { if (_variant == true) // "true" means "allow recursively" return *this; else return Filter(_variant[key] | _variant["*"]); } private: VariantConstRef _variant; }; struct AllowAllFilter { bool allow() const { return true; } bool allowArray() const { return true; } bool allowObject() const { return true; } bool allowValue() const { return true; } template AllowAllFilter operator[](const TKey&) const { return AllowAllFilter(); } }; class NestingLimit { public: NestingLimit() : _value(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {} explicit NestingLimit(uint8_t n) : _value(n) {} NestingLimit decrement() const { ARDUINOJSON_ASSERT(_value > 0); return NestingLimit(static_cast(_value - 1)); } bool reached() const { return _value == 0; } private: uint8_t _value; }; template struct Reader { public: Reader(TSource& source) : _source(&source) {} int read() { return _source->read(); } size_t readBytes(char* buffer, size_t length) { return _source->readBytes(buffer, length); } private: TSource* _source; }; template struct BoundedReader { }; template class IteratorReader { TIterator _ptr, _end; public: explicit IteratorReader(TIterator begin, TIterator end) : _ptr(begin), _end(end) {} int read() { if (_ptr < _end) return static_cast(*_ptr++); else return -1; } size_t readBytes(char* buffer, size_t length) { size_t i = 0; while (i < length && _ptr < _end) buffer[i++] = *_ptr++; return i; } }; template struct void_ { typedef void type; }; template struct Reader::type> : IteratorReader { explicit Reader(const TSource& source) : IteratorReader(source.begin(), source.end()) {} }; template struct IsCharOrVoid { static const bool value = is_same::value || is_same::value || is_same::value || is_same::value; }; template struct IsCharOrVoid : IsCharOrVoid {}; template struct Reader::value>::type> { const char* _ptr; public: explicit Reader(const void* ptr) : _ptr(ptr ? reinterpret_cast(ptr) : "") {} int read() { return static_cast(*_ptr++); } size_t readBytes(char* buffer, size_t length) { for (size_t i = 0; i < length; i++) buffer[i] = *_ptr++; return length; } }; template struct BoundedReader::value>::type> : public IteratorReader { public: explicit BoundedReader(const void* ptr, size_t len) : IteratorReader(reinterpret_cast(ptr), reinterpret_cast(ptr) + len) {} }; template struct Reader, void> : Reader { explicit Reader(const ElementProxy& x) : Reader(x.template as()) {} }; template struct Reader, void> : Reader { explicit Reader(const MemberProxy& x) : Reader(x.template as()) {} }; template <> struct Reader : Reader { explicit Reader(VariantRef x) : Reader(x.as()) {} }; template <> struct Reader : Reader { explicit Reader(VariantConstRef x) : Reader(x.as()) {} }; } // namespace ARDUINOJSON_NAMESPACE #if ARDUINOJSON_ENABLE_ARDUINO_STREAM namespace ARDUINOJSON_NAMESPACE { template struct Reader::value>::type> { public: explicit Reader(Stream& stream) : _stream(&stream) {} int read() { char c; return _stream->readBytes(&c, 1) ? static_cast(c) : -1; } size_t readBytes(char* buffer, size_t length) { return _stream->readBytes(buffer, length); } private: Stream* _stream; }; } // namespace ARDUINOJSON_NAMESPACE #endif #if ARDUINOJSON_ENABLE_ARDUINO_STRING namespace ARDUINOJSON_NAMESPACE { template struct Reader::value>::type> : BoundedReader { explicit Reader(const ::String& s) : BoundedReader(s.c_str(), s.length()) {} }; } // namespace ARDUINOJSON_NAMESPACE #endif #if ARDUINOJSON_ENABLE_PROGMEM namespace ARDUINOJSON_NAMESPACE { template <> struct Reader { const char* _ptr; public: explicit Reader(const __FlashStringHelper* ptr) : _ptr(reinterpret_cast(ptr)) {} int read() { return pgm_read_byte(_ptr++); } size_t readBytes(char* buffer, size_t length) { memcpy_P(buffer, _ptr, length); _ptr += length; return length; } }; template <> struct BoundedReader { const char* _ptr; const char* _end; public: explicit BoundedReader(const __FlashStringHelper* ptr, size_t size) : _ptr(reinterpret_cast(ptr)), _end(_ptr + size) {} int read() { if (_ptr < _end) return pgm_read_byte(_ptr++); else return -1; } size_t readBytes(char* buffer, size_t length) { size_t available = static_cast(_end - _ptr); if (available < length) length = available; memcpy_P(buffer, _ptr, length); _ptr += length; return length; } }; } // namespace ARDUINOJSON_NAMESPACE #endif #if ARDUINOJSON_ENABLE_STD_STREAM #include namespace ARDUINOJSON_NAMESPACE { template struct Reader::value>::type> { public: explicit Reader(std::istream& stream) : _stream(&stream) {} int read() { return _stream->get(); } size_t readBytes(char* buffer, size_t length) { _stream->read(buffer, static_cast(length)); return static_cast(_stream->gcount()); } private: std::istream* _stream; }; } // namespace ARDUINOJSON_NAMESPACE #endif namespace ARDUINOJSON_NAMESPACE { class StringCopier { public: StringCopier(MemoryPool& pool) : _pool(&pool) {} void startString() { _pool->getFreeZone(&_ptr, &_capacity); _size = 0; } const char* save() { ARDUINOJSON_ASSERT(_ptr); return _pool->saveStringFromFreeZone(_size); } void append(const char* s) { while (*s) append(*s++); } void append(const char* s, size_t n) { while (n-- > 0) append(*s++); } void append(char c) { if (!_ptr) return; if (_size >= _capacity) { _ptr = 0; _pool->markAsOverflowed(); return; } _ptr[_size++] = c; } bool isValid() { return _ptr != 0; } const char* c_str() { return _ptr; } typedef storage_policies::store_by_copy storage_policy; private: MemoryPool* _pool; char* _ptr; size_t _size; size_t _capacity; }; class StringMover { public: StringMover(char* ptr) : _writePtr(ptr) {} void startString() { _startPtr = _writePtr; } const char* save() const { return _startPtr; } void append(char c) { *_writePtr++ = c; } bool isValid() const { return true; } const char* c_str() const { return _startPtr; } typedef storage_policies::store_by_address storage_policy; private: char* _writePtr; char* _startPtr; }; template StringCopier makeStringStorage(TInput&, MemoryPool& pool) { return StringCopier(pool); } template StringMover makeStringStorage( TChar* input, MemoryPool&, typename enable_if::value>::type* = 0) { return StringMover(reinterpret_cast(input)); } template