From d975f6e23aac825f89415e12283ce7d0be7d717b Mon Sep 17 00:00:00 2001 From: cschwinne Date: Tue, 15 Sep 2020 21:28:43 +0200 Subject: [PATCH] Update ArduinoJson to 6.16.1 Add fsinfo to JSON info --- platformio.ini | 3 +- wled00/json.cpp | 6 + wled00/src/dependencies/json/ArduinoJson-v6.h | 4842 +++++++++++------ wled00/wled.h | 2 + 4 files changed, 3039 insertions(+), 1814 deletions(-) diff --git a/platformio.ini b/platformio.ini index fbe7dd3b2..77f0bc6e6 100644 --- a/platformio.ini +++ b/platformio.ini @@ -31,7 +31,7 @@ default_envs = travis_esp8266, travis_esp32 ; default_envs = heltec_wifi_kit_8 ; default_envs = h803wf ; default_envs = d1_mini_debug -;default_envs = d1_mini_ota +; default_envs = d1_mini_ota ; default_envs = esp32dev ; default_envs = esp8285_4CH_MagicHome ; default_envs = esp8285_4CH_H801 @@ -177,6 +177,7 @@ lib_deps = #U8g2@~2.27.2 #For Dallas sensor uncomment following 2 lines #OneWire@~2.3.5 + #milesburton/DallasTemperature@^3.9.0 #For BME280 sensor uncomment following #BME280@~3.0.0 lib_ignore = diff --git a/wled00/json.cpp b/wled00/json.cpp index f002a2f2c..8239e0ef0 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -399,6 +399,12 @@ void serializeInfo(JsonObject root) wifi_info["rssi"] = qrssi; wifi_info["signal"] = getSignalQuality(qrssi); wifi_info["channel"] = WiFi.channel(); + + JsonObject fs_info = root.createNestedObject("fs"); + FSInfo fsi; + WLED_FS.info(fsi); + fs_info["u"] = fsi.usedBytes; + fs_info["t"] = fsi.totalBytes; #ifdef ARDUINO_ARCH_ESP32 #ifdef WLED_DEBUG diff --git a/wled00/src/dependencies/json/ArduinoJson-v6.h b/wled00/src/dependencies/json/ArduinoJson-v6.h index 1cd94f604..5d8d40799 100644 --- a/wled00/src/dependencies/json/ArduinoJson-v6.h +++ b/wled00/src/dependencies/json/ArduinoJson-v6.h @@ -1,42 +1,53 @@ // ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2019 +// Copyright Benoit Blanchon 2014-2020 // MIT License #pragma once #ifdef __cplusplus -#ifndef ARDUINOJSON_DEBUG -#ifdef __clang__ -#pragma clang system_header -#elif defined __GNUC__ -#pragma GCC system_header +#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 -#endif -#define ARDUINOJSON_VERSION "6.11.0" -#define ARDUINOJSON_VERSION_MAJOR 6 -#define ARDUINOJSON_VERSION_MINOR 11 -#define ARDUINOJSON_VERSION_REVISION 0 -#if defined(_MSC_VER) +#if defined(_MSC_VER) && !ARDUINOJSON_HAS_LONG_LONG #define ARDUINOJSON_HAS_INT64 1 #else #define ARDUINOJSON_HAS_INT64 0 #endif -#if __cplusplus >= 201103L -#define ARDUINOJSON_HAS_LONG_LONG 1 -#define ARDUINOJSON_HAS_NULLPTR 1 -#else -#define ARDUINOJSON_HAS_LONG_LONG 0 -#define ARDUINOJSON_HAS_NULLPTR 0 -#endif #ifndef ARDUINOJSON_EMBEDDED_MODE -#if defined(ARDUINO) || defined(__IAR_SYSTEMS_ICC__) || defined(__XC) || \ - defined(__ARMCC_VERSION) +#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 @@ -75,6 +86,7 @@ #endif #endif // ARDUINOJSON_EMBEDDED_MODE #ifdef ARDUINO +#include #ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING #define ARDUINOJSON_ENABLE_ARDUINO_STRING 1 #endif @@ -103,7 +115,10 @@ #endif #endif #ifndef ARDUINOJSON_DECODE_UNICODE -#define ARDUINOJSON_DECODE_UNICODE 0 +#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 @@ -126,34 +141,186 @@ #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 -#define ARDUINOJSON_DO_CONCAT(A, B) A##B -#define ARDUINOJSON_CONCAT2(A, B) ARDUINOJSON_DO_CONCAT(A, B) -#define ARDUINOJSON_CONCAT3(A, B, C) \ - ARDUINOJSON_CONCAT2(A, ARDUINOJSON_CONCAT2(B, C)) +#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_DEBUG +#ifdef __clang__ +#pragma clang system_header +#elif defined __GNUC__ +#pragma GCC system_header +#endif +#endif +#define ARDUINOJSON_VERSION "6.16.1" +#define ARDUINOJSON_VERSION_MAJOR 6 +#define ARDUINOJSON_VERSION_MINOR 16 +#define ARDUINOJSON_VERSION_REVISION 1 +#ifndef ARDUINOJSON_NAMESPACE +#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_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_CONCAT8(A, B, C, D, E, F, G, H) \ - ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT4(A, B, C, D), \ - ARDUINOJSON_CONCAT4(E, F, G, H)) -#define ARDUINOJSON_CONCAT10(A, B, C, D, E, F, G, H, I, J) \ - ARDUINOJSON_CONCAT8(A, B, C, D, E, F, G, ARDUINOJSON_CONCAT3(H, I, J)) -#define ARDUINOJSON_NAMESPACE \ - ARDUINOJSON_CONCAT10( \ - ArduinoJson, ARDUINOJSON_VERSION_MAJOR, ARDUINOJSON_VERSION_MINOR, \ - ARDUINOJSON_VERSION_REVISION, _, ARDUINOJSON_USE_LONG_LONG, \ - ARDUINOJSON_USE_DOUBLE, ARDUINOJSON_DECODE_UNICODE, \ - ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY) -#ifdef ARDUINOJSON_DEBUG +#define ARDUINOJSON_NAMESPACE \ + ARDUINOJSON_CONCAT4( \ + ARDUINOJSON_CONCAT4(ArduinoJson, ARDUINOJSON_VERSION_MAJOR, \ + ARDUINOJSON_VERSION_MINOR, \ + ARDUINOJSON_VERSION_REVISION), \ + _, \ + ARDUINOJSON_HEX_DIGIT(0, 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 // for size_t +#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 void arrayAccept(const CollectionData *arr, Visitor &visitor) { + if (arr) + visitor.visitArray(*arr); + else + 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); +} +} // namespace ARDUINOJSON_NAMESPACE +#define JSON_STRING_SIZE(SIZE) (SIZE + 1) +namespace ARDUINOJSON_NAMESPACE { +struct StringSlot { + char *value; + size_t size; +}; template Y)> struct Max {}; template @@ -165,6 +332,7 @@ struct Max { static const size_t value = Y; }; } // namespace ARDUINOJSON_NAMESPACE +#include namespace ARDUINOJSON_NAMESPACE { template class not_null { @@ -184,8 +352,6 @@ not_null make_not_null(T ptr) { ARDUINOJSON_ASSERT(ptr != NULL); return not_null(ptr); } -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template struct conditional { typedef TrueType type; @@ -194,32 +360,24 @@ template struct conditional { typedef FalseType type; }; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template struct enable_if {}; template struct enable_if { typedef T type; }; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template struct integral_constant { static const T value = v; }; typedef integral_constant true_type; typedef integral_constant false_type; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template struct is_array : false_type {}; template struct is_array : true_type {}; template struct is_array : true_type {}; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template class is_base_of { protected: // <- to avoid GCC's "all member functions in class are private" @@ -231,13 +389,50 @@ class is_base_of { static const bool value = sizeof(probe(reinterpret_cast(0))) == sizeof(Yes); }; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { +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 {}; @@ -245,14 +440,10 @@ template <> struct is_floating_point : true_type {}; template <> struct is_floating_point : true_type {}; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template struct is_same : false_type {}; template struct is_same : true_type {}; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template struct is_integral { static const bool value = @@ -268,12 +459,16 @@ struct is_integral { is_same::value || is_same::value || #endif - is_same::value; + is_same::value || is_same::value; }; template struct is_integral : is_integral {}; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { +template +struct is_enum { + static const bool value = is_convertible::value && + !is_class::value && !is_integral::value && + !is_floating_point::value; +}; template struct is_signed : false_type {}; template <> @@ -298,8 +493,6 @@ struct is_signed : true_type {}; template <> struct is_signed : true_type {}; #endif -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template struct is_unsigned : false_type {}; template <> @@ -320,14 +513,10 @@ struct is_unsigned : true_type {}; template <> struct is_unsigned : true_type {}; #endif -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template struct type_identity { typedef T type; }; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template struct make_unsigned; template <> @@ -360,8 +549,6 @@ struct make_unsigned : type_identity {}; template <> struct make_unsigned : type_identity {}; #endif -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template struct remove_const { typedef T type; @@ -370,8 +557,6 @@ template struct remove_const { typedef T type; }; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template struct remove_reference { typedef T type; @@ -380,56 +565,16 @@ template struct remove_reference { typedef T type; }; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { -class MemoryPool; -class VariantData; -class VariantSlot; -class CollectionData { - VariantSlot *_head; - VariantSlot *_tail; - public: - VariantSlot *addSlot(MemoryPool *); - VariantData *add(MemoryPool *pool); - template - VariantData *add(TAdaptedString key, MemoryPool *pool); - void clear(); - template - bool containsKey(const TAdaptedString &key) const; - bool copyFrom(const CollectionData &src, MemoryPool *pool); - bool equalsArray(const CollectionData &other) const; - bool equalsObject(const CollectionData &other) const; - VariantData *get(size_t index) const; - template - VariantData *get(TAdaptedString key) const; - VariantSlot *head() const { - return _head; - } - void remove(size_t index); - template - void remove(TAdaptedString key) { - remove(getSlot(key)); - } - void remove(VariantSlot *slot); - size_t memoryUsage() const; - size_t nesting() const; - size_t size() const; - private: - VariantSlot *getSlot(size_t index) const; - template - VariantSlot *getSlot(TAdaptedString key) const; - VariantSlot *getPreviousSlot(VariantSlot *) const; -}; -} // namespace ARDUINOJSON_NAMESPACE -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 -} // namespace ARDUINOJSON_NAMESPACE -#include // int64_t -namespace ARDUINOJSON_NAMESPACE { #if ARDUINOJSON_USE_LONG_LONG typedef int64_t Integer; typedef uint64_t UInt; @@ -438,18 +583,28 @@ 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 = 0x01, - VALUE_IS_OWNED_RAW = 0x02, - VALUE_IS_LINKED_STRING = 0x03, - VALUE_IS_OWNED_STRING = 0x04, - VALUE_IS_BOOLEAN = 0x05, - VALUE_IS_POSITIVE_INTEGER = 0x06, - VALUE_IS_NEGATIVE_INTEGER = 0x07, - VALUE_IS_FLOAT = 0x08, + 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, @@ -469,8 +624,6 @@ union VariantContent { size_t size; } asRaw; }; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { typedef conditional::type VariantSlotDiff; class VariantSlot { VariantContent _content; @@ -493,7 +646,8 @@ class VariantSlot { VariantSlot* next(size_t distance) { VariantSlot* slot = this; while (distance--) { - if (!slot->_next) return 0; + if (!slot->_next) + return 0; slot += slot->_next; } return slot; @@ -508,13 +662,15 @@ class VariantSlot { ARDUINOJSON_ASSERT(slot != 0); _next = VariantSlotDiff(slot - this); } - void setOwnedKey(not_null k) { + void setKey(const char* k, storage_policies::store_by_copy) { + ARDUINOJSON_ASSERT(k != NULL); _flags |= KEY_IS_OWNED; - _key = k.get(); + _key = k; } - void setLinkedKey(not_null k) { + void setKey(const char* k, storage_policies::store_by_address) { + ARDUINOJSON_ASSERT(k != NULL); _flags &= VALUE_MASK; - _key = k.get(); + _key = k; } const char* key() const { return _key; @@ -527,31 +683,17 @@ class VariantSlot { _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 -namespace ARDUINOJSON_NAMESPACE { -inline bool isAligned(void *ptr) { - const size_t mask = sizeof(void *) - 1; - size_t addr = reinterpret_cast(ptr); - 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; -}; -} // namespace ARDUINOJSON_NAMESPACE -#define JSON_STRING_SIZE(SIZE) (SIZE) -namespace ARDUINOJSON_NAMESPACE { -struct StringSlot { - char *value; - size_t size; -}; -} // namespace ARDUINOJSON_NAMESPACE +#include namespace ARDUINOJSON_NAMESPACE { class MemoryPool { public: @@ -576,25 +718,37 @@ class MemoryPool { VariantSlot* allocVariant() { return allocRight(); } - char* allocFrozenString(size_t n) { - if (!canAlloc(n)) return 0; - char* s = _left; - _left += n; - checkInvariants(); - return s; + 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; } - StringSlot allocExpandableString() { - StringSlot s; - s.value = _left; - s.size = size_t(_right - _left); - _left = _right; - checkInvariants(); - return s; + void getFreeZone(char** zoneStart, size_t* zoneSize) const { + *zoneStart = _left; + *zoneSize = size_t(_right - _left); } - void freezeString(StringSlot& s, size_t newSize) { - _left -= (s.size - newSize); - s.size = newSize; + 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 clear() { _left = _begin; @@ -606,18 +760,26 @@ class MemoryPool { bool owns(void* p) const { return _begin <= p && p < _end; } - template - T* allocRight() { - return reinterpret_cast(allocRight(sizeof(T))); - } - void* allocRight(size_t bytes) { - if (!canAlloc(bytes)) return 0; - _right -= bytes; - return _right; - } 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: StringSlot* allocStringSlot() { return allocRight(); @@ -628,37 +790,68 @@ class MemoryPool { 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)) + 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)) + return 0; + _right -= bytes; + return _right; + } char *_begin, *_left, *_right, *_end; }; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { +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 {}; -} // namespace ARDUINOJSON_NAMESPACE -#include // strcmp -namespace ARDUINOJSON_NAMESPACE { -inline int8_t safe_strcmp(const char* a, const char* b) { - if (a == b) return 0; - if (!a) return -1; - if (!b) return 1; - return static_cast(strcmp(a, b)); -} -inline int8_t 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 static_cast(strncmp(a, b, n)); -} -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { class ConstRamStringAdapter { public: ConstRamStringAdapter(const char* str = 0) : _str(str) {} - int8_t compare(const char* other) const { + int compare(const char* other) const { return safe_strcmp(_str, other); } bool equals(const char* expected) const { @@ -667,41 +860,35 @@ class ConstRamStringAdapter { bool isNull() const { return !_str; } - template - char* save(TMemoryPool*) const { - return 0; - } size_t size() const { - if (!_str) return 0; + if (!_str) + return 0; return strlen(_str); } const char* data() const { return _str; } - bool isStatic() const { - return true; + 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); } -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { class RamStringAdapter : public ConstRamStringAdapter { public: RamStringAdapter(const char* str) : ConstRamStringAdapter(str) {} - char* save(MemoryPool* pool) const { - if (!_str) return NULL; - size_t n = size() + 1; - char* dup = pool->allocFrozenString(n); - if (dup) memcpy(dup, _str, n); - return dup; - } - bool isStatic() const { - return false; + 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) { @@ -718,13 +905,11 @@ template <> struct IsString { static const bool value = false; }; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { class SizedRamStringAdapter { public: SizedRamStringAdapter(const char* str, size_t n) : _str(str), _size(n) {} - int8_t compare(const char* other) const { - return safe_strncmp(_str, other, _size) == 0; + int compare(const char* other) const { + return safe_strncmp(_str, other, _size); } bool equals(const char* expected) const { return compare(expected) == 0; @@ -732,18 +917,16 @@ class SizedRamStringAdapter { bool isNull() const { return !_str; } - char* save(MemoryPool* pool) const { - if (!_str) return NULL; - char* dup = pool->allocFrozenString(_size); - if (dup) memcpy(dup, _str, _size); - return dup; + void copyTo(char* p, size_t n) const { + memcpy(p, _str, n); } size_t size() const { return _size; } - bool isStatic() const { - return false; + const char* begin() const { + return _str; } + typedef storage_policies::store_by_copy storage_policy; private: const char* _str; size_t _size; @@ -756,42 +939,44 @@ inline SizedRamStringAdapter adaptString(const TChar* str, size_t size) { #if ARDUINOJSON_ENABLE_STD_STRING #include namespace ARDUINOJSON_NAMESPACE { +template class StlStringAdapter { public: - StlStringAdapter(const std::string& str) : _str(&str) {} - char* save(MemoryPool* pool) const { - size_t n = _str->length() + 1; - char* dup = pool->allocFrozenString(n); - if (dup) memcpy(dup, _str->c_str(), n); - return dup; + StlStringAdapter(const TString& str) : _str(&str) {} + void copyTo(char* p, size_t n) const { + memcpy(p, _str->c_str(), n); } bool isNull() const { return false; } - int8_t compare(const char* other) const { - if (!other) return 1; - return static_cast(_str->compare(other)); + int compare(const char* other) const { + if (!other) + return 1; + return _str->compare(other); } bool equals(const char* expected) const { - if (!expected) return false; + if (!expected) + return false; return *_str == expected; } - const char* data() const { - return _str->data(); - } size_t size() const { return _str->size(); } - bool isStatic() const { - return false; + const char* begin() const { + return _str->c_str(); } + typedef storage_policies::store_by_copy storage_policy; private: - const std::string* _str; + const TString* _str; }; -template <> -struct IsString : true_type {}; -inline StlStringAdapter adaptString(const std::string& str) { - return StlStringAdapter(str); +template +struct IsString > : true_type { +}; +template +inline StlStringAdapter > +adaptString(const std::basic_string& str) { + return StlStringAdapter >( + str); } } // namespace ARDUINOJSON_NAMESPACE #endif @@ -801,32 +986,26 @@ namespace ARDUINOJSON_NAMESPACE { class ArduinoStringAdapter { public: ArduinoStringAdapter(const ::String& str) : _str(&str) {} - char* save(MemoryPool* pool) const { - if (isNull()) return NULL; - size_t n = _str->length() + 1; - char* dup = pool->allocFrozenString(n); - if (dup) memcpy(dup, _str->c_str(), n); - return dup; + void copyTo(char* p, size_t n) const { + memcpy(p, _str->c_str(), n); } bool isNull() const { return !_str->c_str(); } - int8_t compare(const char* other) const { + 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; } - const char* data() const { - return _str->c_str(); - } size_t size() const { return _str->length(); } - bool isStatic() const { - return false; + const char* begin() const { + return _str->c_str(); } + typedef storage_policies::store_by_copy storage_policy; private: const ::String* _str; }; @@ -841,13 +1020,105 @@ inline ArduinoStringAdapter adaptString(const ::String& str) { #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) {} - int8_t compare(const char* other) const { - if (!other && !_str) return 0; - if (!_str) return -1; - if (!other) return 1; + 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 { @@ -856,23 +1127,18 @@ class FlashStringAdapter { bool isNull() const { return !_str; } - char* save(MemoryPool* pool) const { - if (!_str) return NULL; - size_t n = size() + 1; // copy the terminator - char* dup = pool->allocFrozenString(n); - if (dup) memcpy_P(dup, reinterpret_cast(_str), n); - return dup; - } - const char* data() const { - return 0; + void copyTo(char* p, size_t n) const { + memcpy_P(p, reinterpret_cast(_str), n); } size_t size() const { - if (!_str) return 0; + if (!_str) + return 0; return strlen_P(reinterpret_cast(_str)); } - bool isStatic() const { - return false; + FlashStringIterator begin() const { + return FlashStringIterator(_str); } + typedef storage_policies::store_by_copy storage_policy; private: const __FlashStringHelper* _str; }; @@ -881,16 +1147,17 @@ inline FlashStringAdapter adaptString(const __FlashStringHelper* str) { } template <> struct IsString : true_type {}; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { class SizedFlashStringAdapter { public: SizedFlashStringAdapter(const __FlashStringHelper* str, size_t sz) : _str(str), _size(sz) {} - int8_t compare(const char* other) const { - if (!other && !_str) return 0; - if (!_str) return -1; - if (!other) return 1; + 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 { @@ -899,18 +1166,16 @@ class SizedFlashStringAdapter { bool isNull() const { return !_str; } - char* save(MemoryPool* pool) const { - if (!_str) return NULL; - char* dup = pool->allocFrozenString(_size); - if (dup) memcpy_P(dup, (const char*)_str, _size); - return dup; + void copyTo(char* p, size_t n) const { + memcpy_P(p, reinterpret_cast(_str), n); } size_t size() const { return _size; } - bool isStatic() const { - return false; + FlashStringIterator begin() const { + return FlashStringIterator(_str); } + typedef storage_policies::store_by_copy storage_policy; private: const __FlashStringHelper* _str; size_t _size; @@ -977,37 +1242,7 @@ inline SerializedValue serialized(TChar* p, size_t n) { #endif #pragma GCC diagnostic ignored "-Wconversion" #endif -#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 -#include // for size_t +#include namespace ARDUINOJSON_NAMESPACE { #ifndef isnan template @@ -1021,8 +1256,6 @@ bool isinf(T x) { return x != 0.0 && x * 2 == x; } #endif -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template struct alias_cast_t { union { @@ -1036,8 +1269,6 @@ T alias_cast(F raw_data) { ac.raw = raw_data; return ac.data; } -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template struct FloatTraits {}; template @@ -1052,13 +1283,15 @@ struct FloatTraits { 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); + 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); + if (e & 1) + m *= negativeBinaryPowerOfTen(index); e >>= 1; } } @@ -1134,13 +1367,15 @@ struct FloatTraits { 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); + 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); + if (e & 1) + m *= negativeBinaryPowerOfTen(index); e >>= 1; } } @@ -1175,6 +1410,36 @@ struct FloatTraits { } }; } // 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 { template typename enable_if::value && sizeof(TOut) <= sizeof(TIn), @@ -1247,6 +1512,13 @@ typename enable_if::value, TOut>::type convertFloat( #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 @@ -1302,7 +1574,7 @@ class VariantData { case VALUE_IS_OBJECT: return toObject().copyFrom(src._content.asCollection, pool); case VALUE_IS_OWNED_STRING: - return setOwnedString(RamStringAdapter(src._content.asString), pool); + return setString(RamStringAdapter(src._content.asString), pool); case VALUE_IS_OWNED_RAW: return setOwnedRaw( serialized(src._content.asRaw.data, src._content.asRaw.size), pool); @@ -1312,32 +1584,6 @@ class VariantData { return true; } } - bool equals(const VariantData &other) const { - if (type() != other.type()) return false; - switch (type()) { - case VALUE_IS_LINKED_STRING: - case VALUE_IS_OWNED_STRING: - return !strcmp(_content.asString, other._content.asString); - case VALUE_IS_LINKED_RAW: - case VALUE_IS_OWNED_RAW: - return _content.asRaw.size == other._content.asRaw.size && - !memcmp(_content.asRaw.data, other._content.asRaw.data, - _content.asRaw.size); - case VALUE_IS_BOOLEAN: - case VALUE_IS_POSITIVE_INTEGER: - case VALUE_IS_NEGATIVE_INTEGER: - return _content.asInteger == other._content.asInteger; - case VALUE_IS_ARRAY: - return _content.asCollection.equalsArray(other._content.asCollection); - case VALUE_IS_OBJECT: - return _content.asCollection.equalsObject(other._content.asCollection); - case VALUE_IS_FLOAT: - return _content.asFloat == other._content.asFloat; - case VALUE_IS_NULL: - default: - return true; - } - } bool isArray() const { return (_flags & VALUE_IS_ARRAY) != 0; } @@ -1372,14 +1618,16 @@ class VariantData { return type() == VALUE_IS_NULL; } bool isEnclosed() const { - return isCollection() || isString(); + return !isFloat(); } void remove(size_t index) { - if (isArray()) _content.asCollection.remove(index); + if (isArray()) + _content.asCollection.removeElement(index); } template void remove(TAdaptedString key) { - if (isObject()) _content.asCollection.remove(key); + if (isObject()) + _content.asCollection.removeMember(key); } void setBoolean(bool value) { setType(VALUE_IS_BOOLEAN); @@ -1400,7 +1648,7 @@ class VariantData { } template bool setOwnedRaw(SerializedValue value, MemoryPool *pool) { - char *dup = adaptString(value.data(), value.size()).save(pool); + const char *dup = pool->saveString(adaptString(value.data(), value.size())); if (dup) { setType(VALUE_IS_OWNED_RAW); _content.asRaw.data = dup; @@ -1427,6 +1675,10 @@ class VariantData { 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; @@ -1435,37 +1687,49 @@ class VariantData { setType(VALUE_IS_NEGATIVE_INTEGER); _content.asInteger = value; } - void setLinkedString(const char *value) { - if (value) { - setType(VALUE_IS_LINKED_STRING); - _content.asString = value; - } else { - setType(VALUE_IS_NULL); - } - } void setNull() { setType(VALUE_IS_NULL); } - void setOwnedString(not_null s) { + void setString(not_null s, storage_policies::store_by_copy) { setType(VALUE_IS_OWNED_STRING); _content.asString = s.get(); } - bool setOwnedString(const char *s) { + void setString(not_null s, storage_policies::store_by_address) { + setType(VALUE_IS_LINKED_STRING); + _content.asString = s.get(); + } + template + bool setString(const char *s, TStoragePolicy storage_policy) { if (s) { - setOwnedString(make_not_null(s)); + setString(make_not_null(s), storage_policy); return true; } else { setType(VALUE_IS_NULL); return false; } } - template - bool setOwnedString(T value, MemoryPool *pool) { - return setOwnedString(value.save(pool)); + template + bool setString(TAdaptedString value, MemoryPool *pool) { + return setString(value, pool, typename TAdaptedString::storage_policy()); } - void setUnsignedInteger(UInt value) { - setType(VALUE_IS_POSITIVE_INTEGER); - _content.asInteger = static_cast(value); + 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) { + return setString(value.data(), storage_policies::store_by_address()); + } + template + inline bool setString(TAdaptedString value, MemoryPool *pool, + storage_policies::store_by_copy) { + return setString(pool->saveString(value), + storage_policies::store_by_copy()); } CollectionData &toArray() { setType(VALUE_IS_ARRAY); @@ -1497,24 +1761,39 @@ class VariantData { return isCollection() ? _content.asCollection.size() : 0; } VariantData *addElement(MemoryPool *pool) { - if (isNull()) toArray(); - if (!isArray()) return 0; - return _content.asCollection.add(pool); + if (isNull()) + toArray(); + if (!isArray()) + return 0; + return _content.asCollection.addElement(pool); } VariantData *getElement(size_t index) const { - return isArray() ? _content.asCollection.get(index) : 0; + 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.get(key) : 0; + return isObject() ? _content.asCollection.getMember(key) : 0; } template VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool) { - if (isNull()) toObject(); - if (!isObject()) return 0; - VariantData *var = _content.asCollection.get(key); - if (var) return var; - return _content.asCollection.add(key, 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); } private: uint8_t type() const { @@ -1526,34 +1805,42 @@ class VariantData { } }; } // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { -inline VariantData *arrayAdd(CollectionData *arr, MemoryPool *pool) { - return arr ? arr->add(pool) : 0; -} -template -inline void arrayAccept(const CollectionData *arr, Visitor &visitor) { - if (arr) - visitor.visitArray(*arr); - else - 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); -} -} // 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; + 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()) { - var->setLinkedKey(make_not_null(key.data())); + return slotSetKey(var, key, pool, storage_policies::store_by_address()); } else { - const char* dup = key.save(pool); - if (!dup) return false; - var->setOwnedKey(make_not_null(dup)); + 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) { @@ -1567,8 +1854,6 @@ inline size_t slotSize(const VariantSlot* var) { inline VariantData* slotData(VariantSlot* slot) { return reinterpret_cast(slot); } -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { struct Visitable { }; template @@ -1576,6 +1861,98 @@ 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) @@ -1608,432 +1985,6 @@ struct IsVisitable : IsVisitable {}; #define ARDUINOJSON_NO_SANITIZE(check) #endif namespace ARDUINOJSON_NAMESPACE { -template -class VariantCasts { - public: - template - FORCE_INLINE operator T() const { - return impl()->template as(); - } - private: - const TImpl *impl() const { - return static_cast(this); - } -}; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { -template -struct Comparer; -template -struct Comparer::value>::type> { - T rhs; - int result; - explicit Comparer(T value) : rhs(value), result(1) {} - void visitArray(const CollectionData &) {} - void visitObject(const CollectionData &) {} - void visitFloat(Float) {} - void visitString(const char *lhs) { - result = -adaptString(rhs).compare(lhs); - } - void visitRawJson(const char *, size_t) {} - void visitNegativeInteger(UInt) {} - void visitPositiveInteger(UInt) {} - void visitBoolean(bool) {} - void visitNull() { - result = adaptString(rhs).compare(NULL); - } -}; -template -typename enable_if::value, int>::type sign(const T &value) { - return value < 0 ? -1 : value > 0 ? 1 : 0; -} -template -typename enable_if::value, int>::type sign(const T &value) { - return value > 0 ? 1 : 0; -} -template -struct Comparer::value || - is_floating_point::value>::type> { - T rhs; - int result; - explicit Comparer(T value) : rhs(value), result(1) {} - void visitArray(const CollectionData &) {} - void visitObject(const CollectionData &) {} - void visitFloat(Float lhs) { - result = sign(lhs - static_cast(rhs)); - } - void visitString(const char *) {} - void visitRawJson(const char *, size_t) {} - void visitNegativeInteger(UInt lhs) { - result = -sign(static_cast(lhs) + rhs); - } - void visitPositiveInteger(UInt lhs) { - result = static_cast(lhs) < rhs ? -1 : static_cast(lhs) > rhs ? 1 : 0; - } - void visitBoolean(bool) {} - void visitNull() {} -}; -template <> -struct Comparer { - bool rhs; - int result; - explicit Comparer(bool value) : rhs(value), result(1) {} - void visitArray(const CollectionData &) {} - 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 lhs) { - result = static_cast(lhs - rhs); - } - void visitNull() {} -}; -#if ARDUINOJSON_HAS_NULLPTR -template <> -struct Comparer { - int result; - explicit Comparer(decltype(nullptr)) : result(1) {} - void visitArray(const CollectionData &) {} - 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() { - result = 0; - } -}; -#endif -template -class VariantComparisons { - private: - template - static int compare(TVariant lhs, const T &rhs) { - Comparer comparer(rhs); - lhs.accept(comparer); - return comparer.result; - } - public: - template - friend bool operator==(T *lhs, TVariant rhs) { - return compare(rhs, lhs) == 0; - } - template - friend bool operator==(const T &lhs, TVariant rhs) { - return compare(rhs, lhs) == 0; - } - template - friend bool operator==(TVariant lhs, T *rhs) { - return compare(lhs, rhs) == 0; - } - template - friend bool operator==(TVariant lhs, const T &rhs) { - return compare(lhs, rhs) == 0; - } - template - friend bool operator!=(T *lhs, TVariant rhs) { - return compare(rhs, lhs) != 0; - } - template - friend bool operator!=(const T &lhs, TVariant rhs) { - return compare(rhs, lhs) != 0; - } - template - friend bool operator!=(TVariant lhs, T *rhs) { - return compare(lhs, rhs) != 0; - } - template - friend bool operator!=(TVariant lhs, const T &rhs) { - return compare(lhs, rhs) != 0; - } - template - friend bool operator<(T *lhs, TVariant rhs) { - return compare(rhs, lhs) > 0; - } - template - friend bool operator<(const T &lhs, TVariant rhs) { - return compare(rhs, lhs) > 0; - } - template - friend bool operator<(TVariant lhs, T *rhs) { - return compare(lhs, rhs) < 0; - } - template - friend bool operator<(TVariant lhs, const T &rhs) { - return compare(lhs, rhs) < 0; - } - template - friend bool operator<=(T *lhs, TVariant rhs) { - return compare(rhs, lhs) >= 0; - } - template - friend bool operator<=(const T &lhs, TVariant rhs) { - return compare(rhs, lhs) >= 0; - } - template - friend bool operator<=(TVariant lhs, T *rhs) { - return compare(lhs, rhs) <= 0; - } - template - friend bool operator<=(TVariant lhs, const T &rhs) { - return compare(lhs, rhs) <= 0; - } - template - friend bool operator>(T *lhs, TVariant rhs) { - return compare(rhs, lhs) < 0; - } - template - friend bool operator>(const T &lhs, TVariant rhs) { - return compare(rhs, lhs) < 0; - } - template - friend bool operator>(TVariant lhs, T *rhs) { - return compare(lhs, rhs) > 0; - } - template - friend bool operator>(TVariant lhs, const T &rhs) { - return compare(lhs, rhs) > 0; - } - template - friend bool operator>=(T *lhs, TVariant rhs) { - return compare(rhs, lhs) <= 0; - } - template - friend bool operator>=(const T &lhs, TVariant rhs) { - return compare(rhs, lhs) <= 0; - } - template - friend bool operator>=(TVariant lhs, T *rhs) { - return compare(lhs, rhs) >= 0; - } - template - friend bool operator>=(TVariant lhs, const T &rhs) { - return compare(lhs, rhs) >= 0; - } -}; -} // namespace ARDUINOJSON_NAMESPACE -#if ARDUINOJSON_ENABLE_ARDUINO_STRING -#endif -#if ARDUINOJSON_ENABLE_STD_STRING -#endif -namespace ARDUINOJSON_NAMESPACE { -template -struct IsWriteableString : false_type {}; -template -class DynamicStringWriter {}; -#if ARDUINOJSON_ENABLE_ARDUINO_STRING -template <> -struct IsWriteableString : true_type {}; -template <> -class DynamicStringWriter { - public: - DynamicStringWriter(String &str) : _str(&str) {} - size_t write(uint8_t c) { - _str->operator+=(static_cast(c)); - return 1; - } - size_t write(const uint8_t *s, size_t n) { - _str->reserve(_str->length() + n); - while (n > 0) { - _str->operator+=(static_cast(*s++)); - n--; - } - return n; - } - private: - String *_str; -}; -#endif -#if ARDUINOJSON_ENABLE_STD_STRING -template <> -struct IsWriteableString : true_type {}; -template <> -class DynamicStringWriter { - public: - DynamicStringWriter(std::string &str) : _str(&str) {} - size_t write(uint8_t c) { - _str->operator+=(static_cast(c)); - return 1; - } - size_t write(const uint8_t *s, size_t n) { - _str->append(reinterpret_cast(s), n); - return n; - } - private: - std::string *_str; -}; -#endif -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { -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, T>::type variantAs( - const VariantData* _data) { - return _data != 0 ? _data->asIntegral() : T(0); -} -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 -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 -namespace ARDUINOJSON_NAMESPACE { -template -class VariantOr { - public: - template - T operator|(const T &defaultValue) const { - if (impl()->template is()) - return impl()->template as(); - else - return defaultValue; - } - const char *operator|(const char *defaultValue) const { - const char *value = impl()->template as(); - return value ? value : defaultValue; - } - private: - const TImpl *impl() const { - return static_cast(this); - } -}; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { -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); - } -}; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { -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); - } -}; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { -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[]; -}; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { -template -class VariantOperators : public VariantCasts, - public VariantComparisons, - public VariantOr, - public VariantShortcuts {}; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template inline void variantAccept(const VariantData *var, Visitor &visitor) { if (var != 0) @@ -2052,18 +2003,15 @@ inline CollectionData *variantAsObject(VariantData *var) { } inline bool variantCopyFrom(VariantData *dst, const VariantData *src, MemoryPool *pool) { - if (!dst) return false; + if (!dst) + return false; if (!src) { dst->setNull(); return true; } return dst->copyFrom(*src, pool); } -inline bool variantEquals(const VariantData *a, const VariantData *b) { - if (a == b) return true; - if (!a || !b) return false; - return a->equals(*b); -} +inline int variantCompare(const VariantData *a, const VariantData *b); inline bool variantIsArray(const VariantData *var) { return var && var->isArray(); } @@ -2087,18 +2035,21 @@ inline bool variantIsNull(const VariantData *var) { return var == 0 || var->isNull(); } inline bool variantSetBoolean(VariantData *var, bool value) { - if (!var) return false; + if (!var) + return false; var->setBoolean(value); return true; } inline bool variantSetFloat(VariantData *var, Float value) { - if (!var) return false; + if (!var) + return false; var->setFloat(value); return true; } inline bool variantSetLinkedRaw(VariantData *var, SerializedValue value) { - if (!var) return false; + if (!var) + return false; var->setLinkedRaw(value); return true; } @@ -2107,61 +2058,337 @@ inline bool variantSetOwnedRaw(VariantData *var, SerializedValue value, MemoryPool *pool) { return var != 0 && var->setOwnedRaw(value, pool); } -template -inline bool variantSetSignedInteger(VariantData *var, T value) { - if (!var) return false; - var->setSignedInteger(value); - return true; -} -inline bool variantSetLinkedString(VariantData *var, const char *value) { - if (!var) return false; - var->setLinkedString(value); - return true; -} inline void variantSetNull(VariantData *var) { - if (!var) return; + if (!var) + return; var->setNull(); } -inline bool variantSetOwnedString(VariantData *var, char *value) { - if (!var) return false; - var->setOwnedString(value); - return true; +template +inline bool variantSetString(VariantData *var, TAdaptedString value, + MemoryPool *pool) { + if (!var) + return false; + return var->setString(value, pool); } template -inline bool variantSetOwnedString(VariantData *var, T value, MemoryPool *pool) { - return var != 0 && var->setOwnedString(value, pool); -} -inline bool variantSetUnsignedInteger(VariantData *var, UInt value) { - if (!var) return false; - var->setUnsignedInteger(value); +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; + if (!var) + return 0; return &var->toArray(); } inline CollectionData *variantToObject(VariantData *var) { - if (!var) return 0; + if (!var) + return 0; return &var->toObject(); } -inline NO_INLINE VariantData *variantAdd(VariantData *var, MemoryPool *pool) { +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 *variantGetOrCreate(VariantData *var, TChar *key, - MemoryPool *pool) { +NO_INLINE VariantData *variantGetOrAddMember(VariantData *var, TChar *key, + MemoryPool *pool) { return var != 0 ? var->getOrAddMember(adaptString(key), pool) : 0; } template -NO_INLINE VariantData *variantGetOrCreate(VariantData *var, const TString &key, - MemoryPool *pool) { +NO_INLINE VariantData *variantGetOrAddMember(VariantData *var, + const TString &key, + MemoryPool *pool) { return var != 0 ? var->getOrAddMember(adaptString(key), pool) : 0; } -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { +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); +} +template +CompareResult compare(const T1 &lhs, const T2 &rhs); // VariantCompare.cpp +template +struct VariantOperators { + template + friend T operator|(const TVariant &variant, const T &defaultValue) { + if (variant.template is()) + return variant.template as(); + else + return defaultValue; + } + friend const char *operator|(const TVariant &variant, + const char *defaultValue) { + const char *value = variant.template as(); + return value ? value : 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 @@ -2170,8 +2397,10 @@ template class VariantRefBase { public: template - FORCE_INLINE typename enable_if::value, bool>::type is() - const { + FORCE_INLINE + typename enable_if::value && !is_same::value, + bool>::type + is() const { return variantIsInteger(_data); } template @@ -2204,6 +2433,18 @@ class VariantRefBase { 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); } @@ -2225,6 +2466,7 @@ class VariantRefBase { }; class VariantRef : public VariantRefBase, public VariantOperators, + public VariantShortcuts, public Visitable { typedef VariantRefBase base_type; friend class VariantConstRef; @@ -2235,7 +2477,9 @@ class VariantRef : public VariantRefBase, FORCE_INLINE void clear() const { return variantSetNull(_data); } - FORCE_INLINE bool set(bool value) const { + template + FORCE_INLINE bool set( + T value, typename enable_if::value>::type * = 0) const { return variantSetBoolean(_data, value); } template @@ -2245,17 +2489,10 @@ class VariantRef : public VariantRefBase, return variantSetFloat(_data, static_cast(value)); } template - FORCE_INLINE bool set( - T value, - typename enable_if::value && is_signed::value>::type * = - 0) const { - return variantSetSignedInteger(_data, value); - } - template FORCE_INLINE bool set( T value, typename enable_if::value && - is_unsigned::value>::type * = 0) const { - return variantSetUnsignedInteger(_data, static_cast(value)); + !is_same::value>::type * = 0) const { + return variantSetInteger(_data, value); } FORCE_INLINE bool set(SerializedValue value) const { return variantSetLinkedRaw(_data, value); @@ -2270,48 +2507,39 @@ class VariantRef : public VariantRefBase, FORCE_INLINE bool set( const T &value, typename enable_if::value>::type * = 0) const { - return variantSetOwnedString(_data, adaptString(value), _pool); + return variantSetString(_data, adaptString(value), _pool); } template FORCE_INLINE bool set( T *value, typename enable_if::value>::type * = 0) const { - return variantSetOwnedString(_data, adaptString(value), _pool); - } - FORCE_INLINE bool set(const char *value) const { - return variantSetLinkedString(_data, value); + return variantSetString(_data, adaptString(value), _pool); } template typename enable_if::value, bool>::type set( const TVariant &value) const; template - FORCE_INLINE typename enable_if::value && - !is_same::value && - !is_same::value, - typename VariantAs::type>::type - as() const { - return variantAs(_data); + 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 typename enable_if::value, T>::type as() - const; - template - FORCE_INLINE typename enable_if::value, T>::type as() - const; - template - FORCE_INLINE typename enable_if::value, T>::type as() - const { - return *this; + FORCE_INLINE operator T() const { + return variantAs(_data, _pool); } template void accept(Visitor &visitor) const { variantAccept(_data, visitor); } - FORCE_INLINE bool operator==(VariantRef lhs) const { - return variantEquals(_data, lhs._data); - } - FORCE_INLINE bool operator!=(VariantRef lhs) const { - return !variantEquals(_data, lhs._data); - } template typename enable_if::value, ArrayRef>::type to() const; template @@ -2321,6 +2549,7 @@ class VariantRef : public VariantRefBase, 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 @@ -2331,23 +2560,27 @@ class VariantRef : public VariantRefBase, template FORCE_INLINE VariantRef getOrAddMember(const TString &) const; FORCE_INLINE void remove(size_t index) const { - if (_data) _data->remove(index); + if (_data) + _data->remove(index); } template FORCE_INLINE typename enable_if::value>::type remove( TChar *key) const { - if (_data) _data->remove(adaptString(key)); + 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)); + 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; @@ -2363,23 +2596,37 @@ class VariantConstRef : public VariantRefBase, FORCE_INLINE typename VariantConstAs::type as() const { return variantAs::type>(_data); } - FORCE_INLINE VariantConstRef operator[](size_t index) const; + 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 VariantConstRef(objectGet(variantAsObject(_data), adaptString(key))); + return getMember(key); } template FORCE_INLINE typename enable_if::value, VariantConstRef>::type operator[](TChar *key) const { - const CollectionData *obj = variantAsObject(_data); - return VariantConstRef(obj ? obj->get(adaptString(key)) : 0); + return getMember(key); } }; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { class VariantPtr { public: VariantPtr(MemoryPool *pool, VariantData *data) : _variant(pool, data) {} @@ -2487,6 +2734,9 @@ class ArrayRefBase { 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; } @@ -2507,7 +2757,8 @@ class ArrayConstRef : public ArrayRefBase, public: typedef ArrayConstRefIterator iterator; FORCE_INLINE iterator begin() const { - if (!_data) return iterator(); + if (!_data) + return iterator(); return iterator(_data->head()); } FORCE_INLINE iterator end() const { @@ -2522,7 +2773,7 @@ class ArrayConstRef : public ArrayRefBase, return getElement(index); } FORCE_INLINE VariantConstRef getElement(size_t index) const { - return VariantConstRef(_data ? _data->get(index) : 0); + return VariantConstRef(_data ? _data->getElement(index) : 0); } }; class ArrayRef : public ArrayRefBase, @@ -2545,35 +2796,40 @@ class ArrayRef : public ArrayRefBase, return VariantRef(_pool, arrayAdd(_data, _pool)); } FORCE_INLINE iterator begin() const { - if (!_data) return iterator(); + 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; + 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->get(index) : 0); + return VariantRef(_pool, _data ? _data->getElement(index) : 0); } FORCE_INLINE void remove(iterator it) const { - if (!_data) return; - _data->remove(it.internal()); + if (!_data) + return; + _data->removeSlot(it.internal()); } FORCE_INLINE void remove(size_t index) const { - if (!_data) return; - _data->remove(index); + if (!_data) + return; + _data->removeElement(index); } private: MemoryPool* _pool; }; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template void objectAccept(const CollectionData *obj, Visitor &visitor) { if (obj) @@ -2582,31 +2838,32 @@ void objectAccept(const CollectionData *obj, Visitor &visitor) { visitor.visitNull(); } inline bool objectEquals(const CollectionData *lhs, const CollectionData *rhs) { - if (lhs == rhs) return true; - if (!lhs || !rhs) return false; + if (lhs == rhs) + return true; + if (!lhs || !rhs) + return false; return lhs->equalsObject(*rhs); } template -inline VariantData *objectGet(const CollectionData *obj, TAdaptedString key) { - if (!obj) return 0; - return obj->get(key); +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->remove(key); + if (!obj) + return; + obj->removeMember(key); } template -inline VariantData *objectGetOrCreate(CollectionData *obj, TAdaptedString key, - MemoryPool *pool) { - if (!obj) return 0; - if (key.isNull()) return 0; - VariantData *var = obj->get(key); - if (var) return var; - return obj->add(key, pool); +inline VariantData *objectGetOrAddMember(CollectionData *obj, + TAdaptedString key, MemoryPool *pool) { + if (!obj) + return 0; + return obj->getOrAddMember(key, pool); } -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { class String { public: String() : _data(0), _isStatic(true) {} @@ -2622,11 +2879,23 @@ class String { 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; + 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; @@ -2638,10 +2907,7 @@ class StringAdapter : public RamStringAdapter { bool isStatic() const { return _isStatic; } - /* const char* save(MemoryPool* pool) const { - if (_isStatic) return c_str(); - return RamStringAdapter::save(pool); - }*/ + typedef storage_policies::decide_at_runtime storage_policy; private: bool _isStatic; }; @@ -2650,8 +2916,6 @@ struct IsString : true_type {}; inline StringAdapter adaptString(const String& str) { return StringAdapter(str); } -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { class Pair { public: Pair(MemoryPool* pool, VariantSlot* slot) { @@ -2688,8 +2952,6 @@ class PairConst { String _key; VariantConstRef _value; }; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { class PairPtr { public: PairPtr(MemoryPool *pool, VariantSlot *slot) : _pair(pool, slot) {} @@ -2794,6 +3056,9 @@ class ObjectRefBase { 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; } @@ -2816,7 +3081,8 @@ class ObjectConstRef : public ObjectRefBase, ObjectConstRef() : base_type(0) {} ObjectConstRef(const CollectionData* data) : base_type(data) {} FORCE_INLINE iterator begin() const { - if (!_data) return iterator(); + if (!_data) + return iterator(); return iterator(_data->head()); } FORCE_INLINE iterator end() const { @@ -2856,7 +3122,7 @@ class ObjectConstRef : public ObjectRefBase, private: template FORCE_INLINE VariantConstRef get_impl(TAdaptedString key) const { - return VariantConstRef(objectGet(_data, key)); + return VariantConstRef(objectGetMember(_data, key)); } }; class ObjectRef : public ObjectRefBase, @@ -2876,42 +3142,48 @@ class ObjectRef : public ObjectRefBase, return ObjectConstRef(_data); } FORCE_INLINE iterator begin() const { - if (!_data) return iterator(); + if (!_data) + return iterator(); return iterator(_pool, _data->head()); } FORCE_INLINE iterator end() const { return iterator(); } void clear() const { - if (!_data) return; + if (!_data) + return; _data->clear(); } FORCE_INLINE bool set(ObjectConstRef src) { - if (!_data || !src._data) return false; + if (!_data || !src._data) + return false; return _data->copyFrom(*src._data, _pool); } template FORCE_INLINE VariantRef getMember(const TString& key) const { - return get_impl(adaptString(key)); + return VariantRef(_pool, objectGetMember(_data, adaptString(key))); } template FORCE_INLINE VariantRef getMember(TChar* key) const { - return get_impl(adaptString(key)); + return VariantRef(_pool, objectGetMember(_data, adaptString(key))); } template FORCE_INLINE VariantRef getOrAddMember(const TString& key) const { - return getOrCreate_impl(adaptString(key)); + return VariantRef(_pool, + objectGetOrAddMember(_data, adaptString(key), _pool)); } template FORCE_INLINE VariantRef getOrAddMember(TChar* key) const { - return getOrCreate_impl(adaptString(key)); + 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->remove(it.internal()); + if (!_data) + return; + _data->removeSlot(it.internal()); } template FORCE_INLINE void remove(const TString& key) const { @@ -2922,18 +3194,8 @@ class ObjectRef : public ObjectRefBase, objectRemove(_data, adaptString(key)); } private: - template - FORCE_INLINE VariantRef get_impl(TAdaptedString key) const { - return VariantRef(_pool, objectGet(_data, key)); - } - template - FORCE_INLINE VariantRef getOrCreate_impl(TAdaptedString key) const { - return VariantRef(_pool, objectGetOrCreate(_data, key, _pool)); - } MemoryPool* _pool; }; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { class ArrayRef; class ObjectRef; class VariantRef; @@ -2959,23 +3221,26 @@ struct VariantTo { namespace ARDUINOJSON_NAMESPACE { template class ElementProxy : public VariantOperators >, + public VariantShortcuts >, public Visitable { typedef ElementProxy this_type; public: 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) { - getUpstreamElement().set(src.as()); + getOrAddUpstreamElement().set(src.as()); return *this; } template FORCE_INLINE this_type& operator=(const T& src) { - getUpstreamElement().set(src); + getOrAddUpstreamElement().set(src); return *this; } template FORCE_INLINE this_type& operator=(T* src) { - getUpstreamElement().set(src); + getOrAddUpstreamElement().set(src); return *this; } FORCE_INLINE void clear() const { @@ -2989,20 +3254,24 @@ class ElementProxy : public VariantOperators >, 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 getUpstreamElement().template to(); + return getOrAddUpstreamElement().template to(); } template FORCE_INLINE bool set(const TValue& value) const { - return getUpstreamElement().set(value); + return getOrAddUpstreamElement().set(value); } template FORCE_INLINE bool set(TValue* value) const { - return getUpstreamElement().set(value); + return getOrAddUpstreamElement().set(value); } template void accept(Visitor& visitor) const { @@ -3021,17 +3290,20 @@ class ElementProxy : public VariantOperators >, } template VariantRef getOrAddMember(TNestedKey* key) const { - return getUpstreamElement().getOrAddMember(key); + return getOrAddUpstreamElement().getOrAddMember(key); } template VariantRef getOrAddMember(const TNestedKey& key) const { - return getUpstreamElement().getOrAddMember(key); + return getOrAddUpstreamElement().getOrAddMember(key); } VariantRef addElement() const { - return getUpstreamElement().addElement(); + return getOrAddUpstreamElement().addElement(); } VariantRef getElement(size_t index) const { - return getUpstreamElement().getElement(index); + 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); @@ -3050,14 +3322,12 @@ class ElementProxy : public VariantOperators >, FORCE_INLINE VariantRef getUpstreamElement() const { return _array.getElement(_index); } + FORCE_INLINE VariantRef getOrAddUpstreamElement() const { + return _array.getOrAddElement(_index); + } TArray _array; const size_t _index; }; -template -inline ElementProxy ArrayShortcuts::operator[]( - size_t index) const { - return ElementProxy(*impl(), index); -} } // namespace ARDUINOJSON_NAMESPACE #ifdef _MSC_VER #pragma warning(pop) @@ -3069,11 +3339,14 @@ inline ElementProxy ArrayShortcuts::operator[]( namespace ARDUINOJSON_NAMESPACE { template class MemberProxy : public VariantOperators >, + public VariantShortcuts >, public Visitable { typedef MemberProxy this_type; public: 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(); } @@ -3102,6 +3375,10 @@ class MemberProxy : public VariantOperators >, 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(); @@ -3127,12 +3404,11 @@ class MemberProxy : public VariantOperators >, return getOrAddUpstreamMember().template to(); } template - FORCE_INLINE typename enable_if::value, bool>::type set( - const TValue &value) { + FORCE_INLINE bool set(const TValue &value) { return getOrAddUpstreamMember().set(value); } template - FORCE_INLINE bool set(const TChar *value) { + FORCE_INLINE bool set(TChar *value) { return getOrAddUpstreamMember().set(value); } template @@ -3145,6 +3421,9 @@ class MemberProxy : public VariantOperators >, 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); @@ -3171,20 +3450,6 @@ class MemberProxy : public VariantOperators >, TObject _object; TStringRef _key; }; -template -template -inline typename enable_if::value, - MemberProxy >::type - ObjectShortcuts::operator[](const TString &key) const { - return MemberProxy(*impl(), key); -} -template -template -inline typename enable_if::value, - MemberProxy >::type - ObjectShortcuts::operator[](TString *key) const { - return MemberProxy(*impl(), key); -} } // namespace ARDUINOJSON_NAMESPACE #ifdef _MSC_VER #pragma warning(pop) @@ -3277,11 +3542,10 @@ class JsonDocument : public Visitable { return !getMember(key).isUndefined(); } template - FORCE_INLINE - typename enable_if::value, - MemberProxy >::type - operator[](const TString& key) { - return MemberProxy(*this, key); + FORCE_INLINE typename enable_if::value, + MemberProxy >::type + operator[](const TString& key) { + return MemberProxy(*this, key); } template FORCE_INLINE typename enable_if::value, @@ -3313,6 +3577,9 @@ class JsonDocument : public Visitable { 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))); @@ -3364,7 +3631,19 @@ class JsonDocument : public Visitable { 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(); } @@ -3374,7 +3653,6 @@ class JsonDocument : public Visitable { void replacePool(MemoryPool pool) { _pool = pool; } - private: VariantRef getVariant() { return VariantRef(&_pool, &_data); } @@ -3383,20 +3661,28 @@ class JsonDocument : public Visitable { } MemoryPool _pool; VariantData _data; + private: + JsonDocument(const JsonDocument&); + JsonDocument& operator=(const JsonDocument&); }; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template class AllocatorOwner { - protected: + public: AllocatorOwner() {} AllocatorOwner(const AllocatorOwner& src) : _allocator(src._allocator) {} - AllocatorOwner(TAllocator allocator) : _allocator(allocator) {} - void* allocate(size_t n) { - return _allocator.allocate(n); + AllocatorOwner(TAllocator a) : _allocator(a) {} + void* allocate(size_t size) { + return _allocator.allocate(size); } - void deallocate(void* p) { - _allocator.deallocate(p); + 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; @@ -3404,16 +3690,28 @@ class AllocatorOwner { template class BasicJsonDocument : AllocatorOwner, public JsonDocument { public: - explicit BasicJsonDocument(size_t capa, TAllocator allocator = TAllocator()) - : AllocatorOwner(allocator), JsonDocument(allocPool(capa)) {} + explicit BasicJsonDocument(size_t capa, TAllocator alloc = TAllocator()) + : AllocatorOwner(alloc), JsonDocument(allocPool(capa)) {} BasicJsonDocument(const BasicJsonDocument& src) - : AllocatorOwner(src), - JsonDocument(allocPool(src.memoryUsage())) { - set(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::value>::type* = 0) + 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); } @@ -3425,43 +3723,79 @@ class BasicJsonDocument : AllocatorOwner, public JsonDocument { freePool(); } BasicJsonDocument& operator=(const BasicJsonDocument& src) { - reallocPoolIfTooSmall(src.memoryUsage()); - set(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; + if (requiredSize <= capacity()) + return; freePool(); replacePool(allocPool(addPadding(requiredSize))); } void freePool() { this->deallocate(memoryPool().buffer()); } -}; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { -struct DefaultAllocator { - void* allocate(size_t n) { - return malloc(n); + void copyAssignFrom(const JsonDocument& src) { + reallocPoolIfTooSmall(src.capacity()); + set(src); } - void deallocate(void* p) { - free(p); + 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; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template class StaticJsonDocument : public JsonDocument { static const size_t _capacity = @@ -3490,11 +3824,13 @@ class StaticJsonDocument : public JsonDocument { set(src); return *this; } + void garbageCollect() { + StaticJsonDocument tmp(*this); + set(tmp); + } private: char _buffer[_capacity]; }; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template inline ArrayRef ArrayShortcuts::createNestedArray() const { return impl()->addElement().template to(); @@ -3503,22 +3839,41 @@ template inline ObjectRef ArrayShortcuts::createNestedObject() const { return impl()->addElement().template to(); } -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { -template -inline bool copyArray(T (&src)[N], ArrayRef dst) { +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, size_t len, ArrayRef 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)[N1][N2], ArrayRef dst) { +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(); @@ -3528,31 +3883,86 @@ inline bool copyArray(T (&src)[N1][N2], ArrayRef dst) { } return ok; } -template -inline size_t copyArray(ArrayConstRef src, T (&dst)[N]) { - return copyArray(src, dst, N); +template +inline bool copyArray(T (&src)[N1][N2], JsonDocument& dst) { + return copyArray(src, dst.to()); } template -inline size_t copyArray(ArrayConstRef src, T* dst, size_t len) { - size_t i = 0; - for (ArrayConstRef::iterator it = src.begin(); it != src.end() && i < len; - ++it) - dst[i++] = *it; - return i; -} -template -inline void copyArray(ArrayConstRef src, T (&dst)[N1][N2]) { - size_t i = 0; - for (ArrayConstRef::iterator it = src.begin(); it != src.end() && i < N1; - ++it) { - copyArray(it->as(), dst[i++]); +class ArrayCopier1D { + public: + ArrayCopier1D(T* destination, size_t capacity) + : _destination(destination), _capacity(capacity), _size(0) {} + void visitArray(const CollectionData& array) { + VariantSlot* slot = array.head(); + while (slot != 0 && _size < _capacity) { + _destination[_size++] = variantAs(slot->data()); + 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() {} + size_t result() const { + return _size; + } + private: + T* _destination; + size_t _capacity; + size_t _size; +}; +template +class ArrayCopier2D { + 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); + src.accept(copier); + return copier.result(); +} +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; } -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) { VariantSlot* slot = pool->allocVariant(); - if (!slot) return 0; + if (!slot) + return 0; if (_tail) { _tail->setNextNotNull(slot); _tail = slot; @@ -3563,13 +3973,17 @@ inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) { slot->clear(); return slot; } -inline VariantData* CollectionData::add(MemoryPool* pool) { +inline VariantData* CollectionData::addElement(MemoryPool* pool) { return slotData(addSlot(pool)); } template -inline VariantData* CollectionData::add(TAdaptedString key, MemoryPool* pool) { +inline VariantData* CollectionData::addMember(TAdaptedString key, + MemoryPool* pool) { VariantSlot* slot = addSlot(pool); - if (!slotSetKey(slot, key, pool)) return 0; + if (!slotSetKey(slot, key, pool)) { + removeSlot(slot); + return 0; + } return slot->data(); } inline void CollectionData::clear() { @@ -3587,14 +4001,16 @@ inline bool CollectionData::copyFrom(const CollectionData& src, VariantData* var; if (s->key() != 0) { if (s->ownsKey()) - var = add(RamStringAdapter(s->key()), pool); + var = addMember(RamStringAdapter(s->key()), pool); else - var = add(ConstRamStringAdapter(s->key()), pool); + var = addMember(ConstRamStringAdapter(s->key()), pool); } else { - var = add(pool); + var = addElement(pool); } - if (!var) return false; - if (!var->copyFrom(*s->data(), pool)) return false; + if (!var) + return false; + if (!var->copyFrom(*s->data(), pool)) + return false; } return true; } @@ -3602,8 +4018,9 @@ 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.get(adaptString(slot->key())); - if (!variantEquals(v1, v2)) return false; + VariantData* v2 = other.getMember(adaptString(slot->key())); + if (!variantEquals(v1, v2)) + return false; count++; } return count == other.size(); @@ -3612,9 +4029,12 @@ 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; + if (s1 == s2) + return true; + if (!s1 || !s2) + return false; + if (!variantEquals(s1->data(), s2->data())) + return false; s1 = s1->next(); s2 = s2->next(); } @@ -3623,7 +4043,8 @@ template inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const { VariantSlot* slot = _head; while (slot) { - if (key.equals(slot->key())) break; + if (key.equals(slot->key())) + break; slot = slot->next(); } return slot; @@ -3635,38 +4056,67 @@ inline VariantSlot* CollectionData::getPreviousSlot(VariantSlot* target) const { VariantSlot* current = _head; while (current) { VariantSlot* next = current->next(); - if (next == target) return current; + if (next == target) + return current; current = next; } return 0; } template -inline VariantData* CollectionData::get(TAdaptedString key) const { +inline VariantData* CollectionData::getMember(TAdaptedString key) const { VariantSlot* slot = getSlot(key); return slot ? slot->data() : 0; } -inline VariantData* CollectionData::get(size_t index) const { +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 void CollectionData::remove(VariantSlot* slot) { - if (!slot) return; +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; + if (!next) + _tail = prev; } -inline void CollectionData::remove(size_t index) { - remove(getSlot(index)); +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; + if (s->ownsKey()) + total += strlen(s->key()) + 1; } return total; } @@ -3674,15 +4124,29 @@ 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; + if (childNesting > maxChildNesting) + maxChildNesting = childNesting; } return maxChildNesting + 1; } inline size_t CollectionData::size() const { return slotSize(_head); } -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { +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( @@ -3718,8 +4182,20 @@ inline typename enable_if::value, bool>::type ObjectShortcuts::containsKey(TChar* key) const { return !impl()->getMember(key).isUndefined(); } -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { +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) { @@ -3739,30 +4215,222 @@ 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); + if (cstr) + return T(cstr); T s; serializeJson(VariantConstRef(_data), s); return s; } -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { +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 { + CompareResult result; + ComparerBase() : result(COMPARE_RESULT_DIFFER) {} + void visitArray(const CollectionData &) {} + void visitBoolean(bool) {} + void visitFloat(Float) {} + void visitNegativeInteger(UInt) {} + void visitNull() {} + void visitObject(const CollectionData &) {} + void visitPositiveInteger(UInt) {} + void visitRawJson(const char *, size_t) {} + void visitString(const char *) {} +}; +template +struct Comparer; +template +struct Comparer::value>::type> + : ComparerBase { + T rhs; + explicit Comparer(T value) : rhs(value) {} + void visitString(const char *lhs) { + int i = adaptString(rhs).compare(lhs); + if (i < 0) + result = COMPARE_RESULT_GREATER; + else if (i > 0) + result = COMPARE_RESULT_LESS; + else + result = COMPARE_RESULT_EQUAL; + } + void visitNull() { + if (adaptString(rhs).isNull()) + result = COMPARE_RESULT_EQUAL; + } +}; +template +struct Comparer::value || + is_floating_point::value>::type> + : ComparerBase { + T rhs; + explicit Comparer(T value) : rhs(value) {} + void visitFloat(Float lhs) { + result = arithmeticCompare(lhs, rhs); + } + void visitNegativeInteger(UInt lhs) { + result = arithmeticCompareNegateLeft(lhs, rhs); + } + void visitPositiveInteger(UInt lhs) { + result = arithmeticCompare(lhs, rhs); + } + void visitBoolean(bool lhs) { + visitPositiveInteger(static_cast(lhs)); + } +}; +struct NullComparer : ComparerBase { + void visitNull() { + result = 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) {} + void visitArray(const CollectionData &lhs) { + if (lhs.equalsArray(*_rhs)) + result = COMPARE_RESULT_EQUAL; + } +}; +struct NegativeIntegerComparer : ComparerBase { + UInt _rhs; + explicit NegativeIntegerComparer(UInt rhs) : _rhs(rhs) {} + void visitFloat(Float lhs) { + result = arithmeticCompareNegateRight(lhs, _rhs); + } + void visitNegativeInteger(UInt lhs) { + result = arithmeticCompare(_rhs, lhs); + } + void visitPositiveInteger(UInt) { + result = COMPARE_RESULT_GREATER; + } + void visitBoolean(bool) { + result = COMPARE_RESULT_GREATER; + } +}; +struct ObjectComparer : ComparerBase { + const CollectionData *_rhs; + explicit ObjectComparer(const CollectionData &rhs) : _rhs(&rhs) {} + void visitObject(const CollectionData &lhs) { + if (lhs.equalsObject(*_rhs)) + result = COMPARE_RESULT_EQUAL; + } +}; +struct RawComparer : ComparerBase { + const char *_rhsData; + size_t _rhsSize; + explicit RawComparer(const char *rhsData, size_t rhsSize) + : _rhsData(rhsData), _rhsSize(rhsSize) {} + void visitRawJson(const char *lhsData, size_t lhsSize) { + size_t size = _rhsSize < lhsSize ? _rhsSize : lhsSize; + int n = memcmp(lhsData, _rhsData, size); + if (n < 0) + result = COMPARE_RESULT_LESS; + else if (n > 0) + result = COMPARE_RESULT_GREATER; + else + result = COMPARE_RESULT_EQUAL; + } +}; +template +struct Comparer::value>::type> + : ComparerBase { + T rhs; + explicit Comparer(T value) : rhs(value) {} + void visitArray(const CollectionData &lhs) { + ArrayComparer comparer(lhs); + accept(comparer); + } + void visitObject(const CollectionData &lhs) { + ObjectComparer comparer(lhs); + accept(comparer); + } + void visitFloat(Float lhs) { + Comparer comparer(lhs); + accept(comparer); + } + void visitString(const char *lhs) { + Comparer comparer(lhs); + accept(comparer); + } + void visitRawJson(const char *lhsData, size_t lhsSize) { + RawComparer comparer(lhsData, lhsSize); + accept(comparer); + } + void visitNegativeInteger(UInt lhs) { + NegativeIntegerComparer comparer(lhs); + accept(comparer); + } + void visitPositiveInteger(UInt lhs) { + Comparer comparer(lhs); + accept(comparer); + } + void visitBoolean(bool lhs) { + Comparer comparer(lhs); + accept(comparer); + } + void visitNull() { + NullComparer comparer; + accept(comparer); + } + private: + template + void accept(TComparer &comparer) { + rhs.accept(comparer); + switch (comparer.result) { + case COMPARE_RESULT_GREATER: + result = COMPARE_RESULT_LESS; + break; + case COMPARE_RESULT_LESS: + result = COMPARE_RESULT_GREATER; + break; + default: + result = comparer.result; + break; + } + } +}; +template +CompareResult compare(const T1 &lhs, const T2 &rhs) { + Comparer comparer(rhs); + lhs.accept(comparer); + return comparer.result; +} +inline int variantCompare(const VariantData *a, const VariantData *b) { + return compare(VariantConstRef(a), VariantConstRef(b)); +} inline bool isdigit(char c) { return '0' <= c && c <= '9'; } inline bool issign(char c) { return '-' == c || c == '+'; } -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template struct ParsedNumber { - ParsedNumber() : uintValue(0), floatValue(0), _type(VALUE_IS_NULL) {} - ParsedNumber(TUInt value, bool is_negative) - : uintValue(value), - floatValue(TFloat(value)), - _type(uint8_t(is_negative ? VALUE_IS_NEGATIVE_INTEGER - : VALUE_IS_POSITIVE_INTEGER)) {} - ParsedNumber(TFloat value) : floatValue(value), _type(VALUE_IS_FLOAT) {} + ParsedNumber() : _type(VALUE_IS_NULL) {} + void setInteger(TUInt value, bool is_negative) { + uintValue = value; + _type = uint8_t(is_negative ? VALUE_IS_NEGATIVE_INTEGER + : VALUE_IS_POSITIVE_INTEGER); + } + void setFloat(TFloat value) { + floatValue = value; + _type = VALUE_IS_FLOAT; + } template T as() const { switch (_type) { @@ -3779,19 +4447,20 @@ struct ParsedNumber { uint8_t type() const { return _type; } - TUInt uintValue; - TFloat floatValue; + union { + TUInt uintValue; + TFloat floatValue; + }; uint8_t _type; -}; +}; // namespace ARDUINOJSON_NAMESPACE template struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> {}; template -inline ParsedNumber parseNumber(const char *s) { +inline void parseNumber(const char* s, ParsedNumber& result) { typedef FloatTraits traits; typedef typename choose_largest::type mantissa_t; typedef typename traits::exponent_type exponent_t; - typedef ParsedNumber return_type; ARDUINOJSON_ASSERT(s != 0); bool is_negative = false; switch (*s) { @@ -3804,25 +4473,36 @@ inline ParsedNumber parseNumber(const char *s) { break; } #if ARDUINOJSON_ENABLE_NAN - if (*s == 'n' || *s == 'N') return traits::nan(); + if (*s == 'n' || *s == 'N') { + result.setFloat(traits::nan()); + return; + } #endif #if ARDUINOJSON_ENABLE_INFINITY - if (*s == 'i' || *s == 'I') - return is_negative ? -traits::inf() : traits::inf(); + if (*s == 'i' || *s == 'I') { + result.setFloat(is_negative ? -traits::inf() : traits::inf()); + return; + } #endif - if (!isdigit(*s) && *s != '.') return return_type(); + if (!isdigit(*s) && *s != '.') + return; mantissa_t mantissa = 0; exponent_t exponent_offset = 0; const mantissa_t maxUint = TUInt(-1); while (isdigit(*s)) { uint8_t digit = uint8_t(*s - '0'); - if (mantissa > maxUint / 10) break; + if (mantissa > maxUint / 10) + break; mantissa *= 10; - if (mantissa > maxUint - digit) break; + if (mantissa > maxUint - digit) + break; mantissa += digit; s++; } - if (*s == '\0') return return_type(TUInt(mantissa), is_negative); + if (*s == '\0') { + result.setInteger(TUInt(mantissa), is_negative); + return; + } while (mantissa > traits::mantissa_max) { mantissa /= 10; exponent_offset++; @@ -3855,36 +4535,38 @@ inline ParsedNumber parseNumber(const char *s) { exponent = exponent * 10 + (*s - '0'); if (exponent + exponent_offset > traits::exponent_max) { if (negative_exponent) - return is_negative ? -0.0f : 0.0f; + result.setFloat(is_negative ? -0.0f : 0.0f); else - return is_negative ? -traits::inf() : traits::inf(); + result.setFloat(is_negative ? -traits::inf() : traits::inf()); + return; } s++; } - if (negative_exponent) exponent = -exponent; + if (negative_exponent) + exponent = -exponent; } exponent += exponent_offset; - if (*s != '\0') return return_type(); - TFloat result = traits::make_float(static_cast(mantissa), exponent); - return is_negative ? -result : result; + if (*s != '\0') + return; + TFloat final_result = + traits::make_float(static_cast(mantissa), exponent); + result.setFloat(is_negative ? -final_result : final_result); } -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template inline T parseFloat(const char* s) { typedef typename choose_largest::type TFloat; - return parseNumber(s).template as(); + ParsedNumber value; + parseNumber(s, value); + return value.template as(); } -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template T parseInteger(const char *s) { typedef typename choose_largest::type>::type TUInt; - return parseNumber(s).template as(); + ParsedNumber value; + parseNumber(s, value); + return value.template as(); } -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { template inline T VariantData::asIntegral() const { switch (type()) { @@ -3910,11 +4592,10 @@ inline bool VariantData::asBoolean() const { return _content.asInteger != 0; case VALUE_IS_FLOAT: return _content.asFloat != 0; - case VALUE_IS_LINKED_STRING: - case VALUE_IS_OWNED_STRING: - return strcmp("true", _content.asString) == 0; - default: + case VALUE_IS_NULL: return false; + default: + return true; } } template @@ -3950,16 +4631,6 @@ typename enable_if::value, bool>::type VariantRef::set( return variantCopyFrom(_data, v._data, _pool); } template -inline typename enable_if::value, T>::type VariantRef::as() - const { - return ArrayRef(_pool, _data != 0 ? _data->asArray() : 0); -} -template -inline typename enable_if::value, T>::type -VariantRef::as() const { - return ObjectRef(_pool, variantAsObject(_data)); -} -template inline typename enable_if::value, ArrayRef>::type VariantRef::to() const { return ArrayRef(_pool, variantToArray(_data)); @@ -3975,15 +4646,18 @@ VariantRef::to() const { variantSetNull(_data); return *this; } -inline VariantConstRef VariantConstRef::operator[](size_t index) const { +inline VariantConstRef VariantConstRef::getElement(size_t index) const { return ArrayConstRef(_data != 0 ? _data->asArray() : 0)[index]; } inline VariantRef VariantRef::addElement() const { - return VariantRef(_pool, variantAdd(_data, _pool)); + 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); @@ -3995,176 +4669,13 @@ VariantRef::getMember(const TString &key) const { } template inline VariantRef VariantRef::getOrAddMember(TChar *key) const { - return VariantRef(_pool, variantGetOrCreate(_data, key, _pool)); + return VariantRef(_pool, variantGetOrAddMember(_data, key, _pool)); } template inline VariantRef VariantRef::getOrAddMember(const TString &key) const { - return VariantRef(_pool, variantGetOrCreate(_data, key, _pool)); + return VariantRef(_pool, variantGetOrAddMember(_data, key, _pool)); } } // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { -class StringBuilder { - public: - explicit StringBuilder(MemoryPool* parent) : _parent(parent), _size(0) { - _slot = _parent->allocExpandableString(); - } - 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 (!_slot.value) return; - if (_size >= _slot.size) { - _slot.value = 0; - return; - } - _slot.value[_size++] = c; - } - char* complete() { - append('\0'); - if (_slot.value) { - _parent->freezeString(_slot, _size); - } - return _slot.value; - } - private: - MemoryPool* _parent; - size_t _size; - StringSlot _slot; -}; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { -class StringCopier { - public: - typedef ARDUINOJSON_NAMESPACE::StringBuilder StringBuilder; - StringCopier(MemoryPool* pool) : _pool(pool) {} - StringBuilder startString() { - return StringBuilder(_pool); - } - private: - MemoryPool* _pool; -}; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { -class StringMover { - public: - class StringBuilder { - public: - StringBuilder(char** ptr) : _writePtr(ptr), _startPtr(*ptr) {} - void append(char c) { - *(*_writePtr)++ = char(c); - } - char* complete() const { - *(*_writePtr)++ = 0; - return _startPtr; - } - private: - char** _writePtr; - char* _startPtr; - }; - StringMover(char* ptr) : _ptr(ptr) {} - StringBuilder startString() { - return StringBuilder(&_ptr); - } - private: - char* _ptr; -}; -} // namespace ARDUINOJSON_NAMESPACE -namespace ARDUINOJSON_NAMESPACE { -template -struct StringStorage { - typedef StringCopier type; - static type create(MemoryPool& pool, TInput&) { - return type(&pool); - } -}; -template -struct StringStorage::value>::type> { - typedef StringMover type; - static type create(MemoryPool&, TChar* input) { - return type(reinterpret_cast(input)); - } -}; -template -typename StringStorage::type makeStringStorage(MemoryPool& pool, - TInput& input) { - return StringStorage::create(pool, input); -} -template -typename StringStorage::type makeStringStorage(MemoryPool& pool, - TChar* input) { - return StringStorage::create(pool, input); -} -} // namespace ARDUINOJSON_NAMESPACE -#if ARDUINOJSON_ENABLE_ARDUINO_STREAM -#include -namespace ARDUINOJSON_NAMESPACE { -struct ArduinoStreamReader { - Stream& _stream; - public: - explicit ArduinoStreamReader(Stream& stream) : _stream(stream) {} - int read() { - uint8_t c; - return _stream.readBytes(&c, 1) ? c : -1; - } -}; -inline ArduinoStreamReader makeReader(Stream& input) { - return ArduinoStreamReader(input); -} -} // namespace ARDUINOJSON_NAMESPACE -#endif -namespace ARDUINOJSON_NAMESPACE { -template -struct IsCharOrVoid { - static const bool value = - is_same::value || is_same::value || - is_same::value || is_same::value; -}; -template -struct IsCharOrVoid : IsCharOrVoid {}; -class UnsafeCharPointerReader { - const char* _ptr; - public: - explicit UnsafeCharPointerReader(const char* ptr) - : _ptr(ptr ? ptr : reinterpret_cast("")) {} - int read() { - return static_cast(*_ptr++); - } -}; -class SafeCharPointerReader { - const char* _ptr; - const char* _end; - public: - explicit SafeCharPointerReader(const char* ptr, size_t len) - : _ptr(ptr ? ptr : reinterpret_cast("")), _end(_ptr + len) {} - int read() { - if (_ptr < _end) - return static_cast(*_ptr++); - else - return -1; - } -}; -template -inline typename enable_if::value, - UnsafeCharPointerReader>::type -makeReader(TChar* input) { - return UnsafeCharPointerReader(reinterpret_cast(input)); -} -template -inline - typename enable_if::value, SafeCharPointerReader>::type - makeReader(TChar* input, size_t n) { - return SafeCharPointerReader(reinterpret_cast(input), n); -} -#if ARDUINOJSON_ENABLE_ARDUINO_STRING -inline SafeCharPointerReader makeReader(const ::String& input) { - return SafeCharPointerReader(input.c_str(), input.length()); -} -#endif -} // namespace ARDUINOJSON_NAMESPACE #if ARDUINOJSON_ENABLE_STD_STREAM #include #endif @@ -4253,41 +4764,79 @@ inline std::ostream& operator<<(std::ostream& s, DeserializationError::Code c) { return s; } #endif -} // namespace ARDUINOJSON_NAMESPACE -#if ARDUINOJSON_ENABLE_PROGMEM -namespace ARDUINOJSON_NAMESPACE { -class UnsafeFlashStringReader { - const char* _ptr; +class Filter { public: - explicit UnsafeFlashStringReader(const __FlashStringHelper* ptr) - : _ptr(reinterpret_cast(ptr)) {} - int read() { - return pgm_read_byte_near(_ptr++); + explicit Filter(VariantConstRef v) : _variant(v) {} + bool allow() const { + return _variant; } -}; -class SafeFlashStringReader { - const char* _ptr; - const char* _end; - public: - explicit SafeFlashStringReader(const __FlashStringHelper* ptr, size_t size) - : _ptr(reinterpret_cast(ptr)), _end(_ptr + size) {} - int read() { - if (_ptr < _end) - return pgm_read_byte_near(_ptr++); + 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 -1; + return Filter(_variant[key]); + } + 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(); } }; -inline UnsafeFlashStringReader makeReader(const __FlashStringHelper* input) { - return UnsafeFlashStringReader(input); -} -inline SafeFlashStringReader makeReader(const __FlashStringHelper* input, - size_t size) { - return SafeFlashStringReader(input, size); -} -} // namespace ARDUINOJSON_NAMESPACE -#endif -namespace ARDUINOJSON_NAMESPACE { +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; @@ -4300,344 +4849,829 @@ class IteratorReader { 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()) {} }; -template -inline IteratorReader makeReader( - const TInput& input) { - return IteratorReader(input.begin(), - input.end()); -} } // namespace ARDUINOJSON_NAMESPACE +#if ARDUINOJSON_ENABLE_ARDUINO_STREAM +#include namespace ARDUINOJSON_NAMESPACE { -struct NestingLimit { - NestingLimit() : value(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {} - explicit NestingLimit(uint8_t n) : value(n) {} - uint8_t value; +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 { -class StdStreamReader { - std::istream& _stream; - char _current; +template +struct Reader::value>::type> { public: - explicit StdStreamReader(std::istream& stream) - : _stream(stream), _current(0) {} + explicit Reader(std::istream& stream) : _stream(&stream) {} int read() { - return _stream.get(); + return _stream->get(); + } + size_t readBytes(char* buffer, size_t length) { + _stream->read(buffer, static_cast(length)); + return static_cast(_stream->gcount()); } private: - StdStreamReader& operator=(const StdStreamReader&); // Visual Studio C4512 + std::istream* _stream; }; -inline StdStreamReader makeReader(std::istream& input) { - return StdStreamReader(input); -} } // namespace ARDUINOJSON_NAMESPACE #endif namespace ARDUINOJSON_NAMESPACE { +class StringCopier { + public: + void startString(MemoryPool* pool) { + pool->getFreeZone(&_ptr, &_capacity); + _size = 0; + } + const char* save(MemoryPool* pool) { + 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; + return; + } + _ptr[_size++] = c; + } + bool isValid() { + return _ptr != 0; + } + const char* c_str() { + return _ptr; + } + typedef storage_policies::store_by_copy storage_policy; + private: + char* _ptr; + size_t _size; + size_t _capacity; +}; +class StringMover { + public: + StringMover(char* ptr) : _writePtr(ptr) {} + void startString(MemoryPool*) { + _startPtr = _writePtr; + } + const char* save(MemoryPool*) 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 +struct StringStorage { + typedef StringCopier type; + static type create(TInput&) { + return type(); + } +}; +template +struct StringStorage::value>::type> { + typedef StringMover type; + static type create(TChar* input) { + return type(reinterpret_cast(input)); + } +}; +template +typename StringStorage::type makeStringStorage(TInput& input) { + return StringStorage::create(input); +} +template +typename StringStorage::type makeStringStorage(TChar* input) { + return StringStorage::create(input); +} template