From f5d2e4601584debf430c143a4816b3a34d901257 Mon Sep 17 00:00:00 2001 From: Drath Date: Sun, 28 Dec 2025 13:07:22 +0100 Subject: [PATCH] switch to nlohmann json --- README.md | 1 - include/ArduinoJson.hpp | 8331 --------------------------------------- src/hass.cpp | 21 +- 3 files changed, 11 insertions(+), 8342 deletions(-) delete mode 100644 include/ArduinoJson.hpp diff --git a/README.md b/README.md index 1641ea8..ad7ffbb 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,6 @@ Same as plugins. Just write in more features scrub, learn some C++, damn ## TODOs - LOOK AT WHAT CLANG SAYS, tweak .clang-format, we really dont need all deez libs in headers, move them out to cpp files, remove unused - also use clang-tidy -- move away from ArduinoJson. This ain't an arduino, be fr. Switch to nlohmann/json libs. - Use `std::string_view` or `const std::string &` when possible, its faster, no copy - Extra screens support perhaps? just halt sensors monitoring thread and print another struct on display if needed, have a semaphore or sth - Maybe not even screens, keep the 1st line and change lines 2-4 diff --git a/include/ArduinoJson.hpp b/include/ArduinoJson.hpp deleted file mode 100644 index b07c9cd..0000000 --- a/include/ArduinoJson.hpp +++ /dev/null @@ -1,8331 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright © 2014-2025, Benoit BLANCHON -// MIT License - -#pragma once - -#if __cplusplus < 201103L && (!defined(_MSC_VER) || _MSC_VER < 1910) -# error ArduinoJson requires C++11 or newer. Configure your compiler for C++11 or downgrade ArduinoJson to 6.20. -#endif - -#ifndef ARDUINOJSON_ENABLE_STD_STREAM -# ifdef __has_include -# if __has_include() && \ - __has_include() && \ - !defined(min) && \ - !defined(max) -# define ARDUINOJSON_ENABLE_STD_STREAM 1 -# else -# define ARDUINOJSON_ENABLE_STD_STREAM 0 -# endif -# else -# ifdef ARDUINO -# define ARDUINOJSON_ENABLE_STD_STREAM 0 -# else -# define ARDUINOJSON_ENABLE_STD_STREAM 1 -# endif -# endif -#endif -#ifndef ARDUINOJSON_ENABLE_STD_STRING -# ifdef __has_include -# if __has_include() && !defined(min) && !defined(max) -# define ARDUINOJSON_ENABLE_STD_STRING 1 -# else -# define ARDUINOJSON_ENABLE_STD_STRING 0 -# endif -# else -# ifdef ARDUINO -# define ARDUINOJSON_ENABLE_STD_STRING 0 -# else -# define ARDUINOJSON_ENABLE_STD_STRING 1 -# endif -# endif -#endif -#ifndef ARDUINOJSON_ENABLE_STRING_VIEW -# ifdef __has_include -# if __has_include() && __cplusplus >= 201703L -# define ARDUINOJSON_ENABLE_STRING_VIEW 1 -# else -# define ARDUINOJSON_ENABLE_STRING_VIEW 0 -# endif -# else -# define ARDUINOJSON_ENABLE_STRING_VIEW 0 -# endif -#endif -#ifndef ARDUINOJSON_SIZEOF_POINTER -# if defined(__SIZEOF_POINTER__) -# define ARDUINOJSON_SIZEOF_POINTER __SIZEOF_POINTER__ -# elif defined(_WIN64) && _WIN64 -# define ARDUINOJSON_SIZEOF_POINTER 8 // 64 bits -# else -# define ARDUINOJSON_SIZEOF_POINTER 4 // assume 32 bits otherwise -# endif -#endif -#ifndef ARDUINOJSON_USE_DOUBLE -# if ARDUINOJSON_SIZEOF_POINTER >= 4 // 32 & 64 bits systems -# define ARDUINOJSON_USE_DOUBLE 1 -# else -# define ARDUINOJSON_USE_DOUBLE 0 -# endif -#endif -#ifndef ARDUINOJSON_USE_LONG_LONG -# if ARDUINOJSON_SIZEOF_POINTER >= 4 // 32 & 64 bits systems -# define ARDUINOJSON_USE_LONG_LONG 1 -# else -# define ARDUINOJSON_USE_LONG_LONG 0 -# endif -#endif -#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT -# define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10 -#endif -#ifndef ARDUINOJSON_SLOT_ID_SIZE -# if ARDUINOJSON_SIZEOF_POINTER <= 2 -# define ARDUINOJSON_SLOT_ID_SIZE 1 -# elif ARDUINOJSON_SIZEOF_POINTER == 4 -# define ARDUINOJSON_SLOT_ID_SIZE 2 -# else -# define ARDUINOJSON_SLOT_ID_SIZE 4 -# endif -#endif -#ifndef ARDUINOJSON_POOL_CAPACITY -# if ARDUINOJSON_SLOT_ID_SIZE == 1 -# define ARDUINOJSON_POOL_CAPACITY 16 // 96 bytes -# elif ARDUINOJSON_SLOT_ID_SIZE == 2 -# define ARDUINOJSON_POOL_CAPACITY 128 // 1024 bytes -# else -# define ARDUINOJSON_POOL_CAPACITY 256 // 4096 bytes -# endif -#endif -#ifndef ARDUINOJSON_INITIAL_POOL_COUNT -# define ARDUINOJSON_INITIAL_POOL_COUNT 4 -#endif -#ifndef ARDUINOJSON_AUTO_SHRINK -# if ARDUINOJSON_SIZEOF_POINTER <= 2 -# define ARDUINOJSON_AUTO_SHRINK 0 -# else -# define ARDUINOJSON_AUTO_SHRINK 1 -# endif -#endif -#ifndef ARDUINOJSON_STRING_LENGTH_SIZE -# if ARDUINOJSON_SIZEOF_POINTER <= 2 -# define ARDUINOJSON_STRING_LENGTH_SIZE 1 // up to 255 characters -# else -# define ARDUINOJSON_STRING_LENGTH_SIZE 2 // up to 65535 characters -# endif -#endif -#ifdef ARDUINO -# ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING -# define ARDUINOJSON_ENABLE_ARDUINO_STRING 1 -# endif -# ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM -# define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1 -# endif -# ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT -# define ARDUINOJSON_ENABLE_ARDUINO_PRINT 1 -# endif -# ifndef ARDUINOJSON_ENABLE_PROGMEM -# define ARDUINOJSON_ENABLE_PROGMEM 1 -# endif -#else // ARDUINO -# ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING -# define ARDUINOJSON_ENABLE_ARDUINO_STRING 0 -# endif -# ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM -# define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0 -# endif -# ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT -# define ARDUINOJSON_ENABLE_ARDUINO_PRINT 0 -# endif -# ifndef ARDUINOJSON_ENABLE_PROGMEM -# ifdef __AVR__ -# define ARDUINOJSON_ENABLE_PROGMEM 1 -# else -# define ARDUINOJSON_ENABLE_PROGMEM 0 -# endif -# endif -#endif // ARDUINO -#ifndef ARDUINOJSON_DECODE_UNICODE -# define ARDUINOJSON_DECODE_UNICODE 1 -#endif -#ifndef ARDUINOJSON_ENABLE_COMMENTS -# define ARDUINOJSON_ENABLE_COMMENTS 0 -#endif -#ifndef ARDUINOJSON_ENABLE_NAN -# define ARDUINOJSON_ENABLE_NAN 0 -#endif -#ifndef ARDUINOJSON_ENABLE_INFINITY -# define ARDUINOJSON_ENABLE_INFINITY 0 -#endif -#ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD -# define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e7 -#endif -#ifndef ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD -# define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5 -#endif -#ifndef ARDUINOJSON_LITTLE_ENDIAN -# if defined(_MSC_VER) || \ - (defined(__BYTE_ORDER__) && \ - __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \ - defined(__LITTLE_ENDIAN__) || defined(__i386) || defined(__x86_64) -# define ARDUINOJSON_LITTLE_ENDIAN 1 -# else -# define ARDUINOJSON_LITTLE_ENDIAN 0 -# endif -#endif -#ifndef ARDUINOJSON_ENABLE_ALIGNMENT -# if defined(__AVR) -# define ARDUINOJSON_ENABLE_ALIGNMENT 0 -# else -# define ARDUINOJSON_ENABLE_ALIGNMENT 1 -# endif -#endif -#ifndef ARDUINOJSON_TAB -# define ARDUINOJSON_TAB " " -#endif -#ifndef ARDUINOJSON_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_USE_LONG_LONG || ARDUINOJSON_USE_DOUBLE -# define ARDUINOJSON_USE_EXTENSIONS 1 -#else -# define ARDUINOJSON_USE_EXTENSIONS 0 -#endif -#if defined(nullptr) -# error nullptr is defined as a macro. Remove the faulty #define or #undef nullptr -#endif - -// Include Arduino.h before stdlib.h to avoid conflict with atexit() -// https://github.com/bblanchon/ArduinoJson/pull/1693#issuecomment-1001060240 -#if ARDUINOJSON_ENABLE_ARDUINO_STRING || ARDUINOJSON_ENABLE_ARDUINO_STREAM || \ - ARDUINOJSON_ENABLE_ARDUINO_PRINT || \ - (ARDUINOJSON_ENABLE_PROGMEM && defined(ARDUINO)) -#include -#endif - -#if !ARDUINOJSON_DEBUG -# ifdef __clang__ -# pragma clang system_header -# elif defined __GNUC__ -# pragma GCC system_header -# endif -#endif - -// Remove true and false macros defined by some cores, such as Arduino Due's -// See issues #2181 and arduino/ArduinoCore-sam#50 -#ifdef true -# undef true -#endif -#ifdef false -# undef false -#endif - -#define ARDUINOJSON_CONCAT_(A, B) A##B -#define ARDUINOJSON_CONCAT2(A, B) ARDUINOJSON_CONCAT_(A, B) -#define ARDUINOJSON_CONCAT3(A, B, C) \ - ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT2(A, B), C) -#define ARDUINOJSON_CONCAT4(A, B, C, D) \ - ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT3(A, B, C), D) -#define ARDUINOJSON_CONCAT5(A, B, C, D, E) \ - ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT4(A, B, C, D), E) -#define ARDUINOJSON_BIN2ALPHA_0000() A -#define ARDUINOJSON_BIN2ALPHA_0001() B -#define ARDUINOJSON_BIN2ALPHA_0010() C -#define ARDUINOJSON_BIN2ALPHA_0011() D -#define ARDUINOJSON_BIN2ALPHA_0100() E -#define ARDUINOJSON_BIN2ALPHA_0101() F -#define ARDUINOJSON_BIN2ALPHA_0110() G -#define ARDUINOJSON_BIN2ALPHA_0111() H -#define ARDUINOJSON_BIN2ALPHA_1000() I -#define ARDUINOJSON_BIN2ALPHA_1001() J -#define ARDUINOJSON_BIN2ALPHA_1010() K -#define ARDUINOJSON_BIN2ALPHA_1011() L -#define ARDUINOJSON_BIN2ALPHA_1100() M -#define ARDUINOJSON_BIN2ALPHA_1101() N -#define ARDUINOJSON_BIN2ALPHA_1110() O -#define ARDUINOJSON_BIN2ALPHA_1111() P -#define ARDUINOJSON_BIN2ALPHA_(A, B, C, D) ARDUINOJSON_BIN2ALPHA_##A##B##C##D() -#define ARDUINOJSON_BIN2ALPHA(A, B, C, D) ARDUINOJSON_BIN2ALPHA_(A, B, C, D) -#define ARDUINOJSON_VERSION "7.4.2" -#define ARDUINOJSON_VERSION_MAJOR 7 -#define ARDUINOJSON_VERSION_MINOR 4 -#define ARDUINOJSON_VERSION_REVISION 2 -#define ARDUINOJSON_VERSION_MACRO V742 -#ifndef ARDUINOJSON_VERSION_NAMESPACE -# define ARDUINOJSON_VERSION_NAMESPACE \ - ARDUINOJSON_CONCAT5( \ - ARDUINOJSON_VERSION_MACRO, \ - ARDUINOJSON_BIN2ALPHA(ARDUINOJSON_ENABLE_PROGMEM, \ - ARDUINOJSON_USE_LONG_LONG, \ - ARDUINOJSON_USE_DOUBLE, 1), \ - ARDUINOJSON_BIN2ALPHA( \ - ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY, \ - ARDUINOJSON_ENABLE_COMMENTS, ARDUINOJSON_DECODE_UNICODE), \ - ARDUINOJSON_SLOT_ID_SIZE, ARDUINOJSON_STRING_LENGTH_SIZE) -#endif -#define ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE \ - namespace ArduinoJson { \ - inline namespace ARDUINOJSON_VERSION_NAMESPACE { -#define ARDUINOJSON_END_PUBLIC_NAMESPACE \ - } \ - } -#define ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE \ - namespace ArduinoJson { \ - inline namespace ARDUINOJSON_VERSION_NAMESPACE { \ - namespace detail { -#define ARDUINOJSON_END_PRIVATE_NAMESPACE \ - } \ - } \ - } -ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE -template -struct Converter; -ARDUINOJSON_END_PUBLIC_NAMESPACE -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -template -class InvalidConversion; // Error here? See https://arduinojson.org/v7/invalid-conversion/ -ARDUINOJSON_END_PRIVATE_NAMESPACE -#include -#include -#include -ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE -class Allocator { - public: - virtual void* allocate(size_t size) = 0; - virtual void deallocate(void* ptr) = 0; - virtual void* reallocate(void* ptr, size_t new_size) = 0; - protected: - ~Allocator() = default; -}; -namespace detail { -class DefaultAllocator : public Allocator { - public: - void* allocate(size_t size) override { - return malloc(size); - } - void deallocate(void* ptr) override { - free(ptr); - } - void* reallocate(void* ptr, size_t new_size) override { - return realloc(ptr, new_size); - } - static Allocator* instance() { - static DefaultAllocator allocator; - return &allocator; - } - private: - DefaultAllocator() = default; - ~DefaultAllocator() = default; -}; -} // namespace detail -ARDUINOJSON_END_PUBLIC_NAMESPACE -#if ARDUINOJSON_DEBUG -#include -# define ARDUINOJSON_ASSERT(X) assert(X) -#else -# define ARDUINOJSON_ASSERT(X) ((void)0) -#endif -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -template -struct uint_; -template <> -struct uint_<8> { - using type = uint8_t; -}; -template <> -struct uint_<16> { - using type = uint16_t; -}; -template <> -struct uint_<32> { - using type = uint32_t; -}; -template -using uint_t = typename uint_::type; -using SlotId = uint_t; -using SlotCount = SlotId; -const SlotId NULL_SLOT = SlotId(-1); -template -class Slot { - public: - Slot() : ptr_(nullptr), id_(NULL_SLOT) {} - Slot(T* p, SlotId id) : ptr_(p), id_(id) { - ARDUINOJSON_ASSERT((p == nullptr) == (id == NULL_SLOT)); - } - explicit operator bool() const { - return ptr_ != nullptr; - } - SlotId id() const { - return id_; - } - T* ptr() const { - return ptr_; - } - T* operator->() const { - ARDUINOJSON_ASSERT(ptr_ != nullptr); - return ptr_; - } - private: - T* ptr_; - SlotId id_; -}; -template -class MemoryPool { - public: - void create(SlotCount cap, Allocator* allocator) { - ARDUINOJSON_ASSERT(cap > 0); - slots_ = reinterpret_cast(allocator->allocate(slotsToBytes(cap))); - capacity_ = slots_ ? cap : 0; - usage_ = 0; - } - void destroy(Allocator* allocator) { - if (slots_) - allocator->deallocate(slots_); - slots_ = nullptr; - capacity_ = 0; - usage_ = 0; - } - Slot allocSlot() { - if (!slots_) - return {}; - if (usage_ >= capacity_) - return {}; - auto index = usage_++; - return {slots_ + index, SlotId(index)}; - } - T* getSlot(SlotId id) const { - ARDUINOJSON_ASSERT(id < usage_); - return slots_ + id; - } - void clear() { - usage_ = 0; - } - void shrinkToFit(Allocator* allocator) { - auto newSlots = reinterpret_cast( - allocator->reallocate(slots_, slotsToBytes(usage_))); - if (newSlots) { - slots_ = newSlots; - capacity_ = usage_; - } - } - SlotCount usage() const { - return usage_; - } - static SlotCount bytesToSlots(size_t n) { - return static_cast(n / sizeof(T)); - } - static size_t slotsToBytes(SlotCount n) { - return n * sizeof(T); - } - private: - SlotCount capacity_; - SlotCount usage_; - T* slots_; -}; -template -struct conditional { - using type = TrueType; -}; -template -struct conditional { - using type = FalseType; -}; -template -using conditional_t = - typename conditional::type; -template -struct decay { - using type = T; -}; -template -struct decay : decay {}; -template -struct decay : decay {}; -template -struct decay : decay {}; -template -struct decay : decay {}; -template -using decay_t = typename decay::type; -template -struct enable_if {}; -template -struct enable_if { - using type = T; -}; -template -using enable_if_t = typename enable_if::type; -template -struct function_traits; -template -struct function_traits { - using return_type = ReturnType; - using arg1_type = Arg1; -}; -template -struct function_traits { - using return_type = ReturnType; - using arg1_type = Arg1; - using arg2_type = Arg2; -}; -template -struct integral_constant { - static const T value = v; -}; -template -using bool_constant = integral_constant; -using true_type = bool_constant; -using false_type = bool_constant; -template -struct is_array : false_type {}; -template -struct is_array : true_type {}; -template -struct is_array : true_type {}; -template -struct remove_reference { - using type = T; -}; -template -struct remove_reference { - using type = T; -}; -template -using remove_reference_t = typename remove_reference::type; -template -class is_base_of { - protected: // <- to avoid GCC's "all member functions in class are private" - static int probe(const TBase*); - static char probe(...); - public: - static const bool value = - sizeof(probe(reinterpret_cast*>(0))) == - sizeof(int); -}; -template -T&& declval(); -template -struct is_class { - protected: // <- to avoid GCC's "all member functions in class are private" - template - static int probe(void (U::*)(void)); - template - static char probe(...); - public: - static const bool value = sizeof(probe(0)) == sizeof(int); -}; -template -struct is_const : false_type {}; -template -struct is_const : true_type {}; -ARDUINOJSON_END_PRIVATE_NAMESPACE -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable : 4244) -#endif -#ifdef __ICCARM__ -#pragma diag_suppress=Pa093 -#endif -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -template -struct is_convertible { - protected: // <- to avoid GCC's "all member functions in class are private" - static int probe(To); - static char probe(...); - static const From& from_; - public: - static const bool value = sizeof(probe(from_)) == sizeof(int); -}; -ARDUINOJSON_END_PRIVATE_NAMESPACE -#ifdef _MSC_VER -# pragma warning(pop) -#endif -#ifdef __ICCARM__ -#pragma diag_default=Pa093 -#endif -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -template -struct is_same : false_type {}; -template -struct is_same : true_type {}; -template -struct remove_cv { - using type = T; -}; -template -struct remove_cv { - using type = T; -}; -template -struct remove_cv { - using type = T; -}; -template -struct remove_cv { - using type = T; -}; -template -using remove_cv_t = typename remove_cv::type; -template -struct is_floating_point - : integral_constant>::value || - is_same>::value> {}; -template -struct is_integral : integral_constant, signed char>::value || - is_same, unsigned char>::value || - is_same, signed short>::value || - is_same, unsigned short>::value || - is_same, signed int>::value || - is_same, unsigned int>::value || - is_same, signed long>::value || - is_same, unsigned long>::value || - is_same, signed long long>::value || - is_same, unsigned long long>::value || - is_same, char>::value || - is_same, bool>::value> {}; -template -struct is_enum { - static const bool value = is_convertible::value && - !is_class::value && !is_integral::value && - !is_floating_point::value; -}; -template -struct is_pointer : false_type {}; -template -struct is_pointer : true_type {}; -template -struct is_signed : integral_constant, char>::value || - is_same, signed char>::value || - is_same, signed short>::value || - is_same, signed int>::value || - is_same, signed long>::value || - is_same, signed long long>::value || - is_same, float>::value || - is_same, double>::value> {}; -template -struct is_unsigned : integral_constant, unsigned char>::value || - is_same, unsigned short>::value || - is_same, unsigned int>::value || - is_same, unsigned long>::value || - is_same, unsigned long long>::value || - is_same, bool>::value> {}; -template -struct type_identity { - using type = T; -}; -template -struct make_unsigned; -template <> -struct make_unsigned : type_identity {}; -template <> -struct make_unsigned : type_identity {}; -template <> -struct make_unsigned : type_identity {}; -template <> -struct make_unsigned : type_identity {}; -template <> -struct make_unsigned : type_identity {}; -template <> -struct make_unsigned : type_identity {}; -template <> -struct make_unsigned : type_identity {}; -template <> -struct make_unsigned : type_identity {}; -template <> -struct make_unsigned : type_identity {}; -template <> -struct make_unsigned : type_identity {}; -template <> -struct make_unsigned : type_identity {}; -template -using make_unsigned_t = typename make_unsigned::type; -template -struct remove_const { - using type = T; -}; -template -struct remove_const { - using type = T; -}; -template -using remove_const_t = typename remove_const::type; -template -struct make_void { - using type = void; -}; -template -using void_t = typename make_void::type; -using nullptr_t = decltype(nullptr); -template -T&& forward(remove_reference_t& t) noexcept { - return static_cast(t); -} -template -remove_reference_t&& move(T&& t) { - return static_cast&&>(t); -} -template -void swap_(T& a, T& b) { - T tmp = move(a); - a = move(b); - b = move(tmp); -} -ARDUINOJSON_END_PRIVATE_NAMESPACE -#include -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -using PoolCount = SlotId; -template -class MemoryPoolList { - struct FreeSlot { - SlotId next; - }; - static_assert(sizeof(FreeSlot) <= sizeof(T), "T is too small"); - public: - using Pool = MemoryPool; - MemoryPoolList() = default; - ~MemoryPoolList() { - ARDUINOJSON_ASSERT(count_ == 0); - } - friend void swap(MemoryPoolList& a, MemoryPoolList& b) { - bool aUsedPreallocated = a.pools_ == a.preallocatedPools_; - bool bUsedPreallocated = b.pools_ == b.preallocatedPools_; - if (aUsedPreallocated && bUsedPreallocated) { - for (PoolCount i = 0; i < ARDUINOJSON_INITIAL_POOL_COUNT; i++) - swap_(a.preallocatedPools_[i], b.preallocatedPools_[i]); - } else if (bUsedPreallocated) { - for (PoolCount i = 0; i < b.count_; i++) - a.preallocatedPools_[i] = b.preallocatedPools_[i]; - b.pools_ = a.pools_; - a.pools_ = a.preallocatedPools_; - } else if (aUsedPreallocated) { - for (PoolCount i = 0; i < a.count_; i++) - b.preallocatedPools_[i] = a.preallocatedPools_[i]; - a.pools_ = b.pools_; - b.pools_ = b.preallocatedPools_; - } else { - swap_(a.pools_, b.pools_); - } - swap_(a.count_, b.count_); - swap_(a.capacity_, b.capacity_); - swap_(a.freeList_, b.freeList_); - } - MemoryPoolList& operator=(MemoryPoolList&& src) { - ARDUINOJSON_ASSERT(count_ == 0); - if (src.pools_ == src.preallocatedPools_) { - memcpy(preallocatedPools_, src.preallocatedPools_, - sizeof(preallocatedPools_)); - pools_ = preallocatedPools_; - } else { - pools_ = src.pools_; - src.pools_ = nullptr; - } - count_ = src.count_; - capacity_ = src.capacity_; - src.count_ = 0; - src.capacity_ = 0; - return *this; - } - Slot allocSlot(Allocator* allocator) { - if (freeList_ != NULL_SLOT) { - return allocFromFreeList(); - } - if (count_) { - auto slot = allocFromLastPool(); - if (slot) - return slot; - } - auto pool = addPool(allocator); - if (!pool) - return {}; - return allocFromLastPool(); - } - void freeSlot(Slot slot) { - reinterpret_cast(slot.ptr())->next = freeList_; - freeList_ = slot.id(); - } - T* getSlot(SlotId id) const { - if (id == NULL_SLOT) - return nullptr; - auto poolIndex = SlotId(id / ARDUINOJSON_POOL_CAPACITY); - auto indexInPool = SlotId(id % ARDUINOJSON_POOL_CAPACITY); - ARDUINOJSON_ASSERT(poolIndex < count_); - return pools_[poolIndex].getSlot(indexInPool); - } - void clear(Allocator* allocator) { - for (PoolCount i = 0; i < count_; i++) - pools_[i].destroy(allocator); - count_ = 0; - freeList_ = NULL_SLOT; - if (pools_ != preallocatedPools_) { - allocator->deallocate(pools_); - pools_ = preallocatedPools_; - capacity_ = ARDUINOJSON_INITIAL_POOL_COUNT; - } - } - SlotCount usage() const { - SlotCount total = 0; - for (PoolCount i = 0; i < count_; i++) - total = SlotCount(total + pools_[i].usage()); - return total; - } - size_t size() const { - return Pool::slotsToBytes(usage()); - } - void shrinkToFit(Allocator* allocator) { - if (count_ > 0) - pools_[count_ - 1].shrinkToFit(allocator); - if (pools_ != preallocatedPools_ && count_ != capacity_) { - pools_ = static_cast( - allocator->reallocate(pools_, count_ * sizeof(Pool))); - ARDUINOJSON_ASSERT(pools_ != nullptr); // realloc to smaller can't fail - capacity_ = count_; - } - } - private: - Slot allocFromFreeList() { - ARDUINOJSON_ASSERT(freeList_ != NULL_SLOT); - auto id = freeList_; - auto slot = getSlot(freeList_); - freeList_ = reinterpret_cast(slot)->next; - return {slot, id}; - } - Slot allocFromLastPool() { - ARDUINOJSON_ASSERT(count_ > 0); - auto poolIndex = SlotId(count_ - 1); - auto slot = pools_[poolIndex].allocSlot(); - if (!slot) - return {}; - return {slot.ptr(), - SlotId(poolIndex * ARDUINOJSON_POOL_CAPACITY + slot.id())}; - } - Pool* addPool(Allocator* allocator) { - if (count_ == capacity_ && !increaseCapacity(allocator)) - return nullptr; - auto pool = &pools_[count_++]; - SlotCount poolCapacity = ARDUINOJSON_POOL_CAPACITY; - if (count_ == maxPools) // last pool is smaller because of NULL_SLOT - poolCapacity--; - pool->create(poolCapacity, allocator); - return pool; - } - bool increaseCapacity(Allocator* allocator) { - if (capacity_ == maxPools) - return false; - void* newPools; - auto newCapacity = PoolCount(capacity_ * 2); - if (pools_ == preallocatedPools_) { - newPools = allocator->allocate(newCapacity * sizeof(Pool)); - if (!newPools) - return false; - memcpy(newPools, preallocatedPools_, sizeof(preallocatedPools_)); - } else { - newPools = allocator->reallocate(pools_, newCapacity * sizeof(Pool)); - if (!newPools) - return false; - } - pools_ = static_cast(newPools); - capacity_ = newCapacity; - return true; - } - Pool preallocatedPools_[ARDUINOJSON_INITIAL_POOL_COUNT]; - Pool* pools_ = preallocatedPools_; - PoolCount count_ = 0; - PoolCount capacity_ = ARDUINOJSON_INITIAL_POOL_COUNT; - SlotId freeList_ = NULL_SLOT; - public: - static const PoolCount maxPools = - PoolCount(NULL_SLOT / ARDUINOJSON_POOL_CAPACITY + 1); -}; -ARDUINOJSON_END_PRIVATE_NAMESPACE -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable : 4310) -#endif -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -template -struct numeric_limits; -template -struct numeric_limits::value>> { - static constexpr T lowest() { - return 0; - } - static constexpr T highest() { - return T(-1); - } -}; -template -struct numeric_limits< - T, enable_if_t::value && is_signed::value>> { - static constexpr T lowest() { - return T(T(1) << (sizeof(T) * 8 - 1)); - } - static constexpr T highest() { - return T(~lowest()); - } -}; -ARDUINOJSON_END_PRIVATE_NAMESPACE -#ifdef _MSC_VER -# pragma warning(pop) -#endif -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -struct StringNode { - using references_type = uint_t; - using length_type = uint_t; - struct StringNode* next; - references_type references; - length_type length; - char data[1]; - static constexpr size_t maxLength = numeric_limits::highest(); - static constexpr size_t sizeForLength(size_t n) { - return n + 1 + offsetof(StringNode, data); - } - static StringNode* create(size_t length, Allocator* allocator) { - if (length > maxLength) - return nullptr; - auto size = sizeForLength(length); - if (size < length) // integer overflow - return nullptr; // (not testable on 64-bit) - auto node = reinterpret_cast(allocator->allocate(size)); - if (node) { - node->length = length_type(length); - node->references = 1; - } - return node; - } - static StringNode* resize(StringNode* node, size_t length, - Allocator* allocator) { - ARDUINOJSON_ASSERT(node != nullptr); - StringNode* newNode; - if (length <= maxLength) - newNode = reinterpret_cast( - allocator->reallocate(node, sizeForLength(length))); - else - newNode = nullptr; - if (newNode) - newNode->length = length_type(length); - else - allocator->deallocate(node); - return newNode; - } - static void destroy(StringNode* node, Allocator* allocator) { - allocator->deallocate(node); - } -}; -constexpr size_t sizeofString(size_t n) { - return StringNode::sizeForLength(n); -} -ARDUINOJSON_END_PRIVATE_NAMESPACE -#ifdef _MSC_VER // Visual Studio -# define FORCE_INLINE // __forceinline causes C4714 when returning std::string -# ifndef ARDUINOJSON_DEPRECATED -# define ARDUINOJSON_DEPRECATED(msg) __declspec(deprecated(msg)) -# endif -#elif defined(__GNUC__) // GCC or Clang -# define FORCE_INLINE __attribute__((always_inline)) -# ifndef ARDUINOJSON_DEPRECATED -# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) -# define ARDUINOJSON_DEPRECATED(msg) __attribute__((deprecated(msg))) -# else -# define ARDUINOJSON_DEPRECATED(msg) __attribute__((deprecated)) -# endif -# endif -#else // Other compilers -# define FORCE_INLINE -# ifndef ARDUINOJSON_DEPRECATED -# define ARDUINOJSON_DEPRECATED(msg) -# endif -#endif -#if defined(__has_attribute) -# if __has_attribute(no_sanitize) -# define ARDUINOJSON_NO_SANITIZE(check) __attribute__((no_sanitize(check))) -# else -# define ARDUINOJSON_NO_SANITIZE(check) -# endif -#else -# define ARDUINOJSON_NO_SANITIZE(check) -#endif -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -template -struct IsStringLiteral : false_type {}; -template -struct IsStringLiteral : true_type {}; -template -struct StringAdapter; -template -struct SizedStringAdapter; -template -using StringAdapterFor = - StringAdapter::value, TString, - remove_cv_t>>>; -template -using AdaptedString = typename StringAdapterFor::AdaptedString; -template -AdaptedString adaptString(TString&& s) { - return StringAdapterFor::adapt(detail::forward(s)); -} -template ::value, int> = 0> -AdaptedString adaptString(TChar* p) { - return StringAdapter::adapt(p); -} -template -AdaptedString adaptString(TChar* p, size_t n) { - return SizedStringAdapter::adapt(p, n); -} -template -struct IsChar - : integral_constant::value && sizeof(T) == 1> {}; -class RamString { - public: - static const size_t typeSortKey = 2; -#if ARDUINOJSON_SIZEOF_POINTER <= 2 - static constexpr size_t sizeMask = size_t(-1) >> 1; -#else - static constexpr size_t sizeMask = size_t(-1); -#endif - RamString(const char* str, size_t sz, bool isStatic = false) - : str_(str), size_(sz & sizeMask), static_(isStatic) { - ARDUINOJSON_ASSERT(size_ == sz); - } - bool isNull() const { - return !str_; - } - size_t size() const { - return size_; - } - char operator[](size_t i) const { - ARDUINOJSON_ASSERT(str_ != 0); - ARDUINOJSON_ASSERT(i <= size()); - return str_[i]; - } - const char* data() const { - return str_; - } - bool isStatic() const { - return static_; - } - protected: - const char* str_; -#if ARDUINOJSON_SIZEOF_POINTER <= 2 - size_t size_ : sizeof(size_t) * 8 - 1; - bool static_ : 1; -#else - size_t size_; - bool static_; -#endif -}; -template -struct StringAdapter::value>> { - using AdaptedString = RamString; - static AdaptedString adapt(const TChar* p) { - auto str = reinterpret_cast(p); - return AdaptedString(str, str ? ::strlen(str) : 0); - } -}; -template -struct StringAdapter::value>> { - using AdaptedString = RamString; - static AdaptedString adapt(const TChar* p) { - auto str = reinterpret_cast(p); - return AdaptedString(str, str ? ::strlen(str) : 0); - } -}; -template -struct StringAdapter { - using AdaptedString = RamString; - static AdaptedString adapt(const char (&p)[N]) { - return RamString(p, N - 1, true); - } -}; -template -struct StringAdapter::value>> { - using AdaptedString = RamString; - static AdaptedString adapt(const TChar* p) { - ARDUINOJSON_ASSERT(p); - auto str = reinterpret_cast(p); - return AdaptedString(str, ::strlen(str)); - } -}; -template -struct SizedStringAdapter::value>> { - using AdaptedString = RamString; - static AdaptedString adapt(const TChar* p, size_t n) { - return AdaptedString(reinterpret_cast(p), n); - } -}; -namespace string_traits_impl { -template -struct has_cstr : false_type {}; -template -struct has_cstr().c_str()), - const char*>::value>> : true_type {}; -template -struct has_data : false_type {}; -template -struct has_data().data()), - const char*>::value>> : true_type {}; -template -struct has_length : false_type {}; -template -struct has_length< - T, enable_if_t().length())>::value>> - : true_type {}; -template -struct has_size : false_type {}; -template -struct has_size< - T, enable_if_t().size()), size_t>::value>> - : true_type {}; -} // namespace string_traits_impl -template -struct string_traits { - enum { - has_cstr = string_traits_impl::has_cstr::value, - has_length = string_traits_impl::has_length::value, - has_data = string_traits_impl::has_data::value, - has_size = string_traits_impl::has_size::value - }; -}; -template -struct StringAdapter< - T, - enable_if_t<(string_traits::has_cstr || string_traits::has_data) && - (string_traits::has_length || string_traits::has_size)>> { - using AdaptedString = RamString; - static AdaptedString adapt(const T& s) { - return AdaptedString(get_data(s), get_size(s)); - } - private: - template - static enable_if_t::has_size, size_t> get_size(const U& s) { - return s.size(); - } - template - static enable_if_t::has_size, size_t> get_size(const U& s) { - return s.length(); - } - template - static enable_if_t::has_data, const char*> get_data( - const U& s) { - return s.data(); - } - template - static enable_if_t::has_data, const char*> get_data( - const U& s) { - return s.c_str(); - } -}; -ARDUINOJSON_END_PRIVATE_NAMESPACE -#if ARDUINOJSON_ENABLE_PROGMEM -#ifdef ARDUINO -#else -class __FlashStringHelper; -#include -#endif -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -struct pgm_p { - pgm_p(const void* p) : address(reinterpret_cast(p)) {} - const char* address; -}; -ARDUINOJSON_END_PRIVATE_NAMESPACE -#ifndef strlen_P -inline size_t strlen_P(ArduinoJson::detail::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::detail::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::detail::pgm_p b) { - const char* s1 = a; - const char* s2 = b.address; - ARDUINOJSON_ASSERT(s1 != NULL); - ARDUINOJSON_ASSERT(s2 != NULL); - for (;;) { - char c1 = *s1++; - char c2 = static_cast(pgm_read_byte(s2++)); - if (c1 < c2) - return -1; - if (c1 > c2) - return 1; - if (c1 == 0 /* and c2 as well */) - return 0; - } -} -#endif -#ifndef memcmp_P -inline int memcmp_P(const void* a, ArduinoJson::detail::pgm_p b, size_t n) { - const uint8_t* p1 = reinterpret_cast(a); - const char* p2 = b.address; - ARDUINOJSON_ASSERT(p1 != NULL); - ARDUINOJSON_ASSERT(p2 != NULL); - while (n-- > 0) { - uint8_t v1 = *p1++; - uint8_t v2 = pgm_read_byte(p2++); - if (v1 != v2) - return v1 - v2; - } - return 0; -} -#endif -#ifndef memcpy_P -inline void* memcpy_P(void* dst, ArduinoJson::detail::pgm_p src, size_t n) { - uint8_t* d = reinterpret_cast(dst); - const char* s = src.address; - ARDUINOJSON_ASSERT(d != NULL); - ARDUINOJSON_ASSERT(s != NULL); - while (n-- > 0) { - *d++ = pgm_read_byte(s++); - } - return dst; -} -#endif -#ifndef pgm_read_dword -inline uint32_t pgm_read_dword(ArduinoJson::detail::pgm_p p) { - uint32_t result; - memcpy_P(&result, p.address, 4); - return result; -} -#endif -#ifndef pgm_read_float -inline float pgm_read_float(ArduinoJson::detail::pgm_p p) { - float result; - memcpy_P(&result, p.address, sizeof(float)); - return result; -} -#endif -#ifndef pgm_read_double -# if defined(__SIZEOF_DOUBLE__) && defined(__SIZEOF_FLOAT__) && \ - __SIZEOF_DOUBLE__ == __SIZEOF_FLOAT__ -inline double pgm_read_double(ArduinoJson::detail::pgm_p p) { - return pgm_read_float(p.address); -} -# else -inline double pgm_read_double(ArduinoJson::detail::pgm_p p) { - double result; - memcpy_P(&result, p.address, sizeof(double)); - return result; -} -# endif -#endif -#ifndef pgm_read_ptr -inline void* pgm_read_ptr(ArduinoJson::detail::pgm_p p) { - void* result; - memcpy_P(&result, p.address, sizeof(result)); - return result; -} -#endif -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -class FlashString { - public: - static const size_t typeSortKey = 1; - FlashString(const __FlashStringHelper* str, size_t sz) - : str_(reinterpret_cast(str)), size_(sz) {} - bool isNull() const { - return !str_; - } - char operator[](size_t i) const { - ARDUINOJSON_ASSERT(str_ != 0); - ARDUINOJSON_ASSERT(i <= size_); - return static_cast(pgm_read_byte(str_ + i)); - } - const char* data() const { - return nullptr; - } - size_t size() const { - return size_; - } - friend bool stringEquals(FlashString a, RamString b) { - ARDUINOJSON_ASSERT(a.typeSortKey < b.typeSortKey); - ARDUINOJSON_ASSERT(!a.isNull()); - ARDUINOJSON_ASSERT(!b.isNull()); - if (a.size() != b.size()) - return false; - return ::memcmp_P(b.data(), a.str_, a.size_) == 0; - } - friend int stringCompare(FlashString a, RamString b) { - ARDUINOJSON_ASSERT(a.typeSortKey < b.typeSortKey); - ARDUINOJSON_ASSERT(!a.isNull()); - ARDUINOJSON_ASSERT(!b.isNull()); - size_t minsize = a.size() < b.size() ? a.size() : b.size(); - int res = ::memcmp_P(b.data(), a.str_, minsize); - if (res) - return -res; - if (a.size() < b.size()) - return -1; - if (a.size() > b.size()) - return 1; - return 0; - } - friend void stringGetChars(FlashString s, char* p, size_t n) { - ARDUINOJSON_ASSERT(s.size() <= n); - ::memcpy_P(p, s.str_, n); - } - bool isStatic() const { - return false; - } - private: - const char* str_; - size_t size_; -}; -template <> -struct StringAdapter { - using AdaptedString = FlashString; - static AdaptedString adapt(const __FlashStringHelper* s) { - return AdaptedString(s, s ? strlen_P(reinterpret_cast(s)) : 0); - } -}; -template <> -struct SizedStringAdapter { - using AdaptedString = FlashString; - static AdaptedString adapt(const __FlashStringHelper* s, size_t n) { - return AdaptedString(s, n); - } -}; -ARDUINOJSON_END_PRIVATE_NAMESPACE -#endif -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -template -enable_if_t -stringCompare(TAdaptedString1 s1, TAdaptedString2 s2) { - ARDUINOJSON_ASSERT(!s1.isNull()); - ARDUINOJSON_ASSERT(!s2.isNull()); - size_t size1 = s1.size(); - size_t size2 = s2.size(); - size_t n = size1 < size2 ? size1 : size2; - for (size_t i = 0; i < n; i++) { - if (s1[i] != s2[i]) - return s1[i] - s2[i]; - } - if (size1 < size2) - return -1; - if (size1 > size2) - return 1; - return 0; -} -template -enable_if_t<(TAdaptedString1::typeSortKey > TAdaptedString2::typeSortKey), int> -stringCompare(TAdaptedString1 s1, TAdaptedString2 s2) { - return -stringCompare(s2, s1); -} -template -enable_if_t -stringEquals(TAdaptedString1 s1, TAdaptedString2 s2) { - ARDUINOJSON_ASSERT(!s1.isNull()); - ARDUINOJSON_ASSERT(!s2.isNull()); - size_t size1 = s1.size(); - size_t size2 = s2.size(); - if (size1 != size2) - return false; - for (size_t i = 0; i < size1; i++) { - if (s1[i] != s2[i]) - return false; - } - return true; -} -template -enable_if_t<(TAdaptedString1::typeSortKey > TAdaptedString2::typeSortKey), bool> -stringEquals(TAdaptedString1 s1, TAdaptedString2 s2) { - return stringEquals(s2, s1); -} -template -static void stringGetChars(TAdaptedString s, char* p, size_t n) { - ARDUINOJSON_ASSERT(s.size() <= n); - for (size_t i = 0; i < n; i++) { - p[i] = s[i]; - } -} -class StringPool { - public: - StringPool() = default; - StringPool(const StringPool&) = delete; - void operator=(StringPool&& src) = delete; - ~StringPool() { - ARDUINOJSON_ASSERT(strings_ == nullptr); - } - friend void swap(StringPool& a, StringPool& b) { - swap_(a.strings_, b.strings_); - } - void clear(Allocator* allocator) { - while (strings_) { - auto node = strings_; - strings_ = node->next; - StringNode::destroy(node, allocator); - } - } - size_t size() const { - size_t total = 0; - for (auto node = strings_; node; node = node->next) - total += sizeofString(node->length); - return total; - } - template - StringNode* add(TAdaptedString str, Allocator* allocator) { - ARDUINOJSON_ASSERT(str.isNull() == false); - auto node = get(str); - if (node) { - node->references++; - return node; - } - size_t n = str.size(); - node = StringNode::create(n, allocator); - if (!node) - return nullptr; - stringGetChars(str, node->data, n); - node->data[n] = 0; // force NUL terminator - add(node); - return node; - } - void add(StringNode* node) { - ARDUINOJSON_ASSERT(node != nullptr); - node->next = strings_; - strings_ = node; - } - template - StringNode* get(const TAdaptedString& str) const { - for (auto node = strings_; node; node = node->next) { - if (stringEquals(str, adaptString(node->data, node->length))) - return node; - } - return nullptr; - } - void dereference(const char* s, Allocator* allocator) { - StringNode* prev = nullptr; - for (auto node = strings_; node; node = node->next) { - if (node->data == s) { - if (--node->references == 0) { - if (prev) - prev->next = node->next; - else - strings_ = node->next; - StringNode::destroy(node, allocator); - } - return; - } - prev = node; - } - } - private: - StringNode* strings_ = nullptr; -}; -ARDUINOJSON_END_PRIVATE_NAMESPACE -ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE -template -class SerializedValue { - public: - explicit SerializedValue(T str) : str_(str) {} - operator T() const { - return str_; - } - const char* data() const { - return str_.c_str(); - } - size_t size() const { - return str_.length(); - } - private: - T str_; -}; -template -class SerializedValue { - public: - explicit SerializedValue(TChar* p, size_t n) : data_(p), size_(n) {} - operator TChar*() const { - return data_; - } - TChar* data() const { - return data_; - } - size_t size() const { - return size_; - } - private: - TChar* data_; - size_t size_; -}; -using RawString = SerializedValue; -template -inline SerializedValue serialized(T str) { - return SerializedValue(str); -} -template -inline SerializedValue serialized(TChar* p) { - return SerializedValue(p, detail::adaptString(p).size()); -} -template -inline SerializedValue serialized(TChar* p, size_t n) { - return SerializedValue(p, n); -} -ARDUINOJSON_END_PUBLIC_NAMESPACE -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wconversion" -#elif defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wconversion" -#endif -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -#ifndef isnan -template -bool isnan(T x) { - return x != x; -} -#endif -#ifndef isinf -template -bool isinf(T x) { - return x != 0.0 && x * 2 == x; -} -#endif -template -struct alias_cast_t { - union { - F raw; - T data; - }; -}; -template -T alias_cast(F raw_data) { - alias_cast_t ac; - ac.raw = raw_data; - return ac.data; -} -ARDUINOJSON_END_PRIVATE_NAMESPACE -#if ARDUINOJSON_ENABLE_PROGMEM -#endif -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -#if ARDUINOJSON_ENABLE_PROGMEM -# ifndef ARDUINOJSON_DEFINE_PROGMEM_ARRAY -# define ARDUINOJSON_DEFINE_PROGMEM_ARRAY(type, name, ...) \ - static type const name[] PROGMEM = __VA_ARGS__; -# endif -template -inline const T* pgm_read(const T* const* p) { - return reinterpret_cast(pgm_read_ptr(p)); -} -inline uint32_t pgm_read(const uint32_t* p) { - return pgm_read_dword(p); -} -inline double pgm_read(const double* p) { - return pgm_read_double(p); -} -inline float pgm_read(const float* p) { - return pgm_read_float(p); -} -#else -# ifndef ARDUINOJSON_DEFINE_PROGMEM_ARRAY -# define ARDUINOJSON_DEFINE_PROGMEM_ARRAY(type, name, ...) \ - static type const name[] = __VA_ARGS__; -# endif -template -inline T pgm_read(const T* p) { - return *p; -} -#endif -template -class pgm_ptr { - public: - explicit pgm_ptr(const T* ptr) : ptr_(ptr) {} - T operator[](intptr_t index) const { - return pgm_read(ptr_ + index); - } - private: - const T* ptr_; -}; -template -struct FloatTraits {}; -template -struct FloatTraits { - using mantissa_type = uint64_t; - static const short mantissa_bits = 52; - static const mantissa_type mantissa_max = - (mantissa_type(1) << mantissa_bits) - 1; - using exponent_type = int16_t; - static const exponent_type exponent_max = 308; - static pgm_ptr positiveBinaryPowersOfTen() { - ARDUINOJSON_DEFINE_PROGMEM_ARRAY( // - uint64_t, factors, - { - 0x4024000000000000, // 1e1 - 0x4059000000000000, // 1e2 - 0x40C3880000000000, // 1e4 - 0x4197D78400000000, // 1e8 - 0x4341C37937E08000, // 1e16 - 0x4693B8B5B5056E17, // 1e32 - 0x4D384F03E93FF9F5, // 1e64 - 0x5A827748F9301D32, // 1e128 - 0x75154FDD7F73BF3C, // 1e256 - }); - return pgm_ptr(reinterpret_cast(factors)); - } - static pgm_ptr negativeBinaryPowersOfTen() { - ARDUINOJSON_DEFINE_PROGMEM_ARRAY( // - uint64_t, factors, - { - 0x3FB999999999999A, // 1e-1 - 0x3F847AE147AE147B, // 1e-2 - 0x3F1A36E2EB1C432D, // 1e-4 - 0x3E45798EE2308C3A, // 1e-8 - 0x3C9CD2B297D889BC, // 1e-16 - 0x3949F623D5A8A733, // 1e-32 - 0x32A50FFD44F4A73D, // 1e-64 - 0x255BBA08CF8C979D, // 1e-128 - 0x0AC8062864AC6F43 // 1e-256 - }); - return pgm_ptr(reinterpret_cast(factors)); - } - static T nan() { - return forge(0x7ff8000000000000); - } - static T inf() { - return forge(0x7ff0000000000000); - } - static T highest() { - return forge(0x7FEFFFFFFFFFFFFF); - } - template // int64_t - static T highest_for( - enable_if_t::value && is_signed::value && - sizeof(TOut) == 8, - signed>* = 0) { - return forge(0x43DFFFFFFFFFFFFF); // 9.2233720368547748e+18 - } - template // uint64_t - static T highest_for( - enable_if_t::value && is_unsigned::value && - sizeof(TOut) == 8, - unsigned>* = 0) { - return forge(0x43EFFFFFFFFFFFFF); // 1.8446744073709549568e+19 - } - static T lowest() { - return forge(0xFFEFFFFFFFFFFFFF); - } - static T forge(uint64_t bits) { - return alias_cast(bits); - } -}; -template -struct FloatTraits { - using mantissa_type = uint32_t; - static const short mantissa_bits = 23; - static const mantissa_type mantissa_max = - (mantissa_type(1) << mantissa_bits) - 1; - using exponent_type = int8_t; - static const exponent_type exponent_max = 38; - static pgm_ptr positiveBinaryPowersOfTen() { - ARDUINOJSON_DEFINE_PROGMEM_ARRAY(uint32_t, factors, - { - 0x41200000, // 1e1f - 0x42c80000, // 1e2f - 0x461c4000, // 1e4f - 0x4cbebc20, // 1e8f - 0x5a0e1bca, // 1e16f - 0x749dc5ae // 1e32f - }); - return pgm_ptr(reinterpret_cast(factors)); - } - static pgm_ptr negativeBinaryPowersOfTen() { - ARDUINOJSON_DEFINE_PROGMEM_ARRAY(uint32_t, factors, - { - 0x3dcccccd, // 1e-1f - 0x3c23d70a, // 1e-2f - 0x38d1b717, // 1e-4f - 0x322bcc77, // 1e-8f - 0x24e69595, // 1e-16f - 0x0a4fb11f // 1e-32f - }); - return pgm_ptr(reinterpret_cast(factors)); - } - static T forge(uint32_t bits) { - return alias_cast(bits); - } - static T nan() { - return forge(0x7fc00000); - } - static T inf() { - return forge(0x7f800000); - } - static T highest() { - return forge(0x7f7fffff); - } - template // int32_t - static T highest_for( - enable_if_t::value && is_signed::value && - sizeof(TOut) == 4, - signed>* = 0) { - return forge(0x4EFFFFFF); // 2.14748352E9 - } - template // uint32_t - static T highest_for( - enable_if_t::value && is_unsigned::value && - sizeof(TOut) == 4, - unsigned>* = 0) { - return forge(0x4F7FFFFF); // 4.29496704E9 - } - template // int64_t - static T highest_for( - enable_if_t::value && is_signed::value && - sizeof(TOut) == 8, - signed>* = 0) { - return forge(0x5EFFFFFF); // 9.22337148709896192E18 - } - template // uint64_t - static T highest_for( - enable_if_t::value && is_unsigned::value && - sizeof(TOut) == 8, - unsigned>* = 0) { - return forge(0x5F7FFFFF); // 1.844674297419792384E19 - } - static T lowest() { - return forge(0xFf7fffff); - } -}; -template -inline TFloat make_float(TFloat m, TExponent e) { - using traits = FloatTraits; - auto powersOfTen = e > 0 ? traits::positiveBinaryPowersOfTen() - : traits::negativeBinaryPowersOfTen(); - if (e <= 0) - e = TExponent(-e); - for (uint8_t index = 0; e != 0; index++) { - if (e & 1) - m *= powersOfTen[index]; - e >>= 1; - } - return m; -} -ARDUINOJSON_END_PRIVATE_NAMESPACE -ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE -#if ARDUINOJSON_USE_DOUBLE -using JsonFloat = double; -#else -using JsonFloat = float; -#endif -ARDUINOJSON_END_PUBLIC_NAMESPACE -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -template -enable_if_t::value && is_unsigned::value && - is_integral::value && sizeof(TOut) <= sizeof(TIn), - bool> -canConvertNumber(TIn value) { - return value <= TIn(numeric_limits::highest()); -} -template -enable_if_t::value && is_unsigned::value && - is_integral::value && sizeof(TIn) < sizeof(TOut), - bool> -canConvertNumber(TIn) { - return true; -} -template -enable_if_t::value && is_floating_point::value, bool> -canConvertNumber(TIn) { - return true; -} -template -enable_if_t::value && is_signed::value && - is_integral::value && is_signed::value && - sizeof(TOut) < sizeof(TIn), - bool> -canConvertNumber(TIn value) { - return value >= TIn(numeric_limits::lowest()) && - value <= TIn(numeric_limits::highest()); -} -template -enable_if_t::value && is_signed::value && - is_integral::value && is_signed::value && - sizeof(TIn) <= sizeof(TOut), - bool> -canConvertNumber(TIn) { - return true; -} -template -enable_if_t::value && is_signed::value && - is_integral::value && is_unsigned::value && - sizeof(TOut) >= sizeof(TIn), - bool> -canConvertNumber(TIn value) { - if (value < 0) - return false; - return TOut(value) <= numeric_limits::highest(); -} -template -enable_if_t::value && is_signed::value && - is_integral::value && is_unsigned::value && - sizeof(TOut) < sizeof(TIn), - bool> -canConvertNumber(TIn value) { - if (value < 0) - return false; - return value <= TIn(numeric_limits::highest()); -} -template -enable_if_t::value && is_integral::value && - sizeof(TOut) < sizeof(TIn), - bool> -canConvertNumber(TIn value) { - return value >= numeric_limits::lowest() && - value <= numeric_limits::highest(); -} -template -enable_if_t::value && is_integral::value && - sizeof(TOut) >= sizeof(TIn), - bool> -canConvertNumber(TIn value) { - return value >= numeric_limits::lowest() && - value <= FloatTraits::template highest_for(); -} -template -enable_if_t::value && is_floating_point::value, - bool> -canConvertNumber(TIn) { - return true; -} -template -TOut convertNumber(TIn value) { - return canConvertNumber(value) ? TOut(value) : 0; -} -ARDUINOJSON_END_PRIVATE_NAMESPACE -#if defined(__clang__) -# pragma clang diagnostic pop -#elif defined(__GNUC__) -# pragma GCC diagnostic pop -#endif -#if ARDUINOJSON_ENABLE_STD_STREAM -#include -#endif -ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE -class JsonString { - friend struct detail::StringAdapter; - public: - JsonString() : str_(nullptr, 0, true) {} - JsonString(const char* data, bool isStatic = false) - : str_(data, data ? ::strlen(data) : 0, isStatic) {} - template ::value && - !detail::is_same::value, - int> = 0> - JsonString(const char* data, TSize sz, bool isStatic = false) - : str_(data, size_t(sz), isStatic) {} - const char* c_str() const { - return str_.data(); - } - bool isNull() const { - return str_.isNull(); - } - bool isStatic() const { - return str_.isStatic(); - } - size_t size() const { - return str_.size(); - } - explicit operator bool() const { - return str_.data() != 0; - } - friend bool operator==(JsonString lhs, JsonString rhs) { - if (lhs.size() != rhs.size()) - return false; - if (lhs.c_str() == rhs.c_str()) - return true; - if (!lhs.c_str()) - return false; - if (!rhs.c_str()) - return false; - return memcmp(lhs.c_str(), rhs.c_str(), lhs.size()) == 0; - } - friend bool operator!=(JsonString lhs, JsonString rhs) { - return !(lhs == rhs); - } -#if ARDUINOJSON_ENABLE_STD_STREAM - friend std::ostream& operator<<(std::ostream& lhs, const JsonString& rhs) { - lhs.write(rhs.c_str(), static_cast(rhs.size())); - return lhs; - } -#endif - private: - detail::RamString str_; -}; -namespace detail { -template <> -struct StringAdapter { - using AdaptedString = RamString; - static const AdaptedString& adapt(const JsonString& s) { - return s.str_; - } -}; -} // namespace detail -ARDUINOJSON_END_PUBLIC_NAMESPACE -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -class VariantData; -class ResourceManager; -class CollectionIterator { - friend class CollectionData; - public: - CollectionIterator() : slot_(nullptr), currentId_(NULL_SLOT) {} - void next(const ResourceManager* resources); - bool done() const { - return slot_ == nullptr; - } - bool operator==(const CollectionIterator& other) const { - return slot_ == other.slot_; - } - bool operator!=(const CollectionIterator& other) const { - return slot_ != other.slot_; - } - VariantData* operator->() { - ARDUINOJSON_ASSERT(slot_ != nullptr); - return data(); - } - VariantData& operator*() { - ARDUINOJSON_ASSERT(slot_ != nullptr); - return *data(); - } - const VariantData& operator*() const { - ARDUINOJSON_ASSERT(slot_ != nullptr); - return *data(); - } - VariantData* data() { - return reinterpret_cast(slot_); - } - const VariantData* data() const { - return reinterpret_cast(slot_); - } - private: - CollectionIterator(VariantData* slot, SlotId slotId); - VariantData* slot_; - SlotId currentId_, nextId_; -}; -class CollectionData { - SlotId head_ = NULL_SLOT; - SlotId tail_ = NULL_SLOT; - public: - static void* operator new(size_t, void* p) noexcept { - return p; - } - static void operator delete(void*, void*) noexcept {} - using iterator = CollectionIterator; - iterator createIterator(const ResourceManager* resources) const; - size_t size(const ResourceManager*) const; - size_t nesting(const ResourceManager*) const; - void clear(ResourceManager* resources); - static void clear(CollectionData* collection, ResourceManager* resources) { - if (!collection) - return; - collection->clear(resources); - } - SlotId head() const { - return head_; - } - protected: - void appendOne(Slot slot, const ResourceManager* resources); - void appendPair(Slot key, Slot value, - const ResourceManager* resources); - void removeOne(iterator it, ResourceManager* resources); - void removePair(iterator it, ResourceManager* resources); - private: - Slot getPreviousSlot(VariantData*, const ResourceManager*) const; -}; -inline const VariantData* collectionToVariant( - const CollectionData* collection) { - const void* data = collection; // prevent warning cast-align - return reinterpret_cast(data); -} -inline VariantData* collectionToVariant(CollectionData* collection) { - void* data = collection; // prevent warning cast-align - return reinterpret_cast(data); -} -class ArrayData : public CollectionData { - public: - VariantData* addElement(ResourceManager* resources); - static VariantData* addElement(ArrayData* array, ResourceManager* resources) { - if (!array) - return nullptr; - return array->addElement(resources); - } - template - bool addValue(const T& value, ResourceManager* resources); - template - static bool addValue(ArrayData* array, const T& value, - ResourceManager* resources) { - if (!array) - return false; - return array->addValue(value, resources); - } - VariantData* getOrAddElement(size_t index, ResourceManager* resources); - VariantData* getElement(size_t index, const ResourceManager* resources) const; - static VariantData* getElement(const ArrayData* array, size_t index, - const ResourceManager* resources) { - if (!array) - return nullptr; - return array->getElement(index, resources); - } - void removeElement(size_t index, ResourceManager* resources); - static void removeElement(ArrayData* array, size_t index, - ResourceManager* resources) { - if (!array) - return; - array->removeElement(index, resources); - } - void remove(iterator it, ResourceManager* resources) { - CollectionData::removeOne(it, resources); - } - static void remove(ArrayData* array, iterator it, - ResourceManager* resources) { - if (array) - return array->remove(it, resources); - } - private: - iterator at(size_t index, const ResourceManager* resources) const; -}; -ARDUINOJSON_END_PRIVATE_NAMESPACE -ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE -#if ARDUINOJSON_USE_LONG_LONG -using JsonInteger = int64_t; -using JsonUInt = uint64_t; -#else -using JsonInteger = long; -using JsonUInt = unsigned long; -#endif -ARDUINOJSON_END_PUBLIC_NAMESPACE -#define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) \ - static_assert(sizeof(T) <= sizeof(ArduinoJson::JsonInteger), \ - "To use 64-bit integers with ArduinoJson, you must set " \ - "ARDUINOJSON_USE_LONG_LONG to 1. See " \ - "https://arduinojson.org/v7/api/config/use_long_long/"); -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -class ObjectData : public CollectionData { - public: - template - VariantData* addMember(TAdaptedString key, ResourceManager* resources); - VariantData* addPair(VariantData** value, ResourceManager* resources); - template - VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources); - template - VariantData* getMember(TAdaptedString key, - const ResourceManager* resources) const; - template - static VariantData* getMember(const ObjectData* object, TAdaptedString key, - const ResourceManager* resources) { - if (!object) - return nullptr; - return object->getMember(key, resources); - } - template - void removeMember(TAdaptedString key, ResourceManager* resources); - template - static void removeMember(ObjectData* obj, TAdaptedString key, - ResourceManager* resources) { - if (!obj) - return; - obj->removeMember(key, resources); - } - void remove(iterator it, ResourceManager* resources) { - CollectionData::removePair(it, resources); - } - static void remove(ObjectData* obj, ObjectData::iterator it, - ResourceManager* resources) { - if (!obj) - return; - obj->remove(it, resources); - } - size_t size(const ResourceManager* resources) const { - return CollectionData::size(resources) / 2; - } - static size_t size(const ObjectData* obj, const ResourceManager* resources) { - if (!obj) - return 0; - return obj->size(resources); - } - private: - template - iterator findKey(TAdaptedString key, const ResourceManager* resources) const; -}; -enum class VariantTypeBits : uint8_t { - OwnedStringBit = 0x01, // 0000 0001 - NumberBit = 0x08, // 0000 1000 -#if ARDUINOJSON_USE_EXTENSIONS - ExtensionBit = 0x10, // 0001 0000 -#endif - CollectionMask = 0x60, -}; -enum class VariantType : uint8_t { - Null = 0, // 0000 0000 - TinyString = 0x02, // 0000 0010 - RawString = 0x03, // 0000 0011 - LinkedString = 0x04, // 0000 0100 - OwnedString = 0x05, // 0000 0101 - Boolean = 0x06, // 0000 0110 - Uint32 = 0x0A, // 0000 1010 - Int32 = 0x0C, // 0000 1100 - Float = 0x0E, // 0000 1110 -#if ARDUINOJSON_USE_LONG_LONG - Uint64 = 0x1A, // 0001 1010 - Int64 = 0x1C, // 0001 1100 -#endif -#if ARDUINOJSON_USE_DOUBLE - Double = 0x1E, // 0001 1110 -#endif - Object = 0x20, - Array = 0x40, -}; -inline bool operator&(VariantType type, VariantTypeBits bit) { - return (uint8_t(type) & uint8_t(bit)) != 0; -} -const size_t tinyStringMaxLength = 3; -union VariantContent { - VariantContent() {} - float asFloat; - bool asBoolean; - uint32_t asUint32; - int32_t asInt32; -#if ARDUINOJSON_USE_EXTENSIONS - SlotId asSlotId; -#endif - ArrayData asArray; - ObjectData asObject; - CollectionData asCollection; - const char* asLinkedString; - struct StringNode* asOwnedString; - char asTinyString[tinyStringMaxLength + 1]; -}; -#if ARDUINOJSON_USE_EXTENSIONS -union VariantExtension { -# if ARDUINOJSON_USE_LONG_LONG - uint64_t asUint64; - int64_t asInt64; -# endif -# if ARDUINOJSON_USE_DOUBLE - double asDouble; -# endif -}; -#endif -template -T parseNumber(const char* s); -template -static bool isTinyString(const T& s, size_t n) { - if (n > tinyStringMaxLength) - return false; - bool containsNul = false; - for (uint8_t i = 0; i < uint8_t(n); i++) - containsNul |= !s[i]; - return !containsNul; -} -class VariantData { - VariantContent content_; // must be first to allow cast from array to variant - VariantType type_; - SlotId next_; - public: - static void* operator new(size_t, void* p) noexcept { - return p; - } - static void operator delete(void*, void*) noexcept {} - VariantData() : type_(VariantType::Null), next_(NULL_SLOT) {} - SlotId next() const { - return next_; - } - void setNext(SlotId slot) { - next_ = slot; - } - template - typename TVisitor::result_type accept( - TVisitor& visit, const ResourceManager* resources) const { -#if ARDUINOJSON_USE_EXTENSIONS - auto extension = getExtension(resources); -#else - (void)resources; // silence warning -#endif - switch (type_) { - case VariantType::Float: - return visit.visit(content_.asFloat); -#if ARDUINOJSON_USE_DOUBLE - case VariantType::Double: - return visit.visit(extension->asDouble); -#endif - case VariantType::Array: - return visit.visit(content_.asArray); - case VariantType::Object: - return visit.visit(content_.asObject); - case VariantType::TinyString: - return visit.visit(JsonString(content_.asTinyString)); - case VariantType::LinkedString: - return visit.visit(JsonString(content_.asLinkedString, true)); - case VariantType::OwnedString: - return visit.visit(JsonString(content_.asOwnedString->data, - content_.asOwnedString->length)); - case VariantType::RawString: - return visit.visit(RawString(content_.asOwnedString->data, - content_.asOwnedString->length)); - case VariantType::Int32: - return visit.visit(static_cast(content_.asInt32)); - case VariantType::Uint32: - return visit.visit(static_cast(content_.asUint32)); -#if ARDUINOJSON_USE_LONG_LONG - case VariantType::Int64: - return visit.visit(extension->asInt64); - case VariantType::Uint64: - return visit.visit(extension->asUint64); -#endif - case VariantType::Boolean: - return visit.visit(content_.asBoolean != 0); - default: - return visit.visit(nullptr); - } - } - template - static typename TVisitor::result_type accept(const VariantData* var, - const ResourceManager* resources, - TVisitor& visit) { - if (var != 0) - return var->accept(visit, resources); - else - return visit.visit(nullptr); - } - VariantData* addElement(ResourceManager* resources) { - auto array = isNull() ? &toArray() : asArray(); - return detail::ArrayData::addElement(array, resources); - } - static VariantData* addElement(VariantData* var, ResourceManager* resources) { - if (!var) - return nullptr; - return var->addElement(resources); - } - template - bool addValue(const T& value, ResourceManager* resources) { - auto array = isNull() ? &toArray() : asArray(); - return detail::ArrayData::addValue(array, value, resources); - } - template - static bool addValue(VariantData* var, const T& value, - ResourceManager* resources) { - if (!var) - return false; - return var->addValue(value, resources); - } - bool asBoolean(const ResourceManager* resources) const { -#if ARDUINOJSON_USE_EXTENSIONS - auto extension = getExtension(resources); -#else - (void)resources; // silence warning -#endif - switch (type_) { - case VariantType::Boolean: - return content_.asBoolean; - case VariantType::Uint32: - case VariantType::Int32: - return content_.asUint32 != 0; - case VariantType::Float: - return content_.asFloat != 0; -#if ARDUINOJSON_USE_DOUBLE - case VariantType::Double: - return extension->asDouble != 0; -#endif - case VariantType::Null: - return false; -#if ARDUINOJSON_USE_LONG_LONG - case VariantType::Uint64: - case VariantType::Int64: - return extension->asUint64 != 0; -#endif - default: - return true; - } - } - ArrayData* asArray() { - return isArray() ? &content_.asArray : 0; - } - const ArrayData* asArray() const { - return const_cast(this)->asArray(); - } - CollectionData* asCollection() { - return isCollection() ? &content_.asCollection : 0; - } - const CollectionData* asCollection() const { - return const_cast(this)->asCollection(); - } - template - T asFloat(const ResourceManager* resources) const { - static_assert(is_floating_point::value, "T must be a floating point"); -#if ARDUINOJSON_USE_EXTENSIONS - auto extension = getExtension(resources); -#else - (void)resources; // silence warning -#endif - const char* str = nullptr; - switch (type_) { - case VariantType::Boolean: - return static_cast(content_.asBoolean); - case VariantType::Uint32: - return static_cast(content_.asUint32); - case VariantType::Int32: - return static_cast(content_.asInt32); -#if ARDUINOJSON_USE_LONG_LONG - case VariantType::Uint64: - return static_cast(extension->asUint64); - case VariantType::Int64: - return static_cast(extension->asInt64); -#endif - case VariantType::TinyString: - str = content_.asTinyString; - break; - case VariantType::LinkedString: - str = content_.asLinkedString; - break; - case VariantType::OwnedString: - str = content_.asOwnedString->data; - break; - case VariantType::Float: - return static_cast(content_.asFloat); -#if ARDUINOJSON_USE_DOUBLE - case VariantType::Double: - return static_cast(extension->asDouble); -#endif - default: - return 0.0; - } - ARDUINOJSON_ASSERT(str != nullptr); - return parseNumber(str); - } - template - T asIntegral(const ResourceManager* resources) const { - static_assert(is_integral::value, "T must be an integral type"); -#if ARDUINOJSON_USE_EXTENSIONS - auto extension = getExtension(resources); -#else - (void)resources; // silence warning -#endif - const char* str = nullptr; - switch (type_) { - case VariantType::Boolean: - return content_.asBoolean; - case VariantType::Uint32: - return convertNumber(content_.asUint32); - case VariantType::Int32: - return convertNumber(content_.asInt32); -#if ARDUINOJSON_USE_LONG_LONG - case VariantType::Uint64: - return convertNumber(extension->asUint64); - case VariantType::Int64: - return convertNumber(extension->asInt64); -#endif - case VariantType::TinyString: - str = content_.asTinyString; - break; - case VariantType::LinkedString: - str = content_.asLinkedString; - break; - case VariantType::OwnedString: - str = content_.asOwnedString->data; - break; - case VariantType::Float: - return convertNumber(content_.asFloat); -#if ARDUINOJSON_USE_DOUBLE - case VariantType::Double: - return convertNumber(extension->asDouble); -#endif - default: - return 0; - } - ARDUINOJSON_ASSERT(str != nullptr); - return parseNumber(str); - } - ObjectData* asObject() { - return isObject() ? &content_.asObject : 0; - } - const ObjectData* asObject() const { - return const_cast(this)->asObject(); - } - JsonString asRawString() const { - switch (type_) { - case VariantType::RawString: - return JsonString(content_.asOwnedString->data, - content_.asOwnedString->length); - default: - return JsonString(); - } - } - JsonString asString() const { - switch (type_) { - case VariantType::TinyString: - return JsonString(content_.asTinyString); - case VariantType::LinkedString: - return JsonString(content_.asLinkedString, true); - case VariantType::OwnedString: - return JsonString(content_.asOwnedString->data, - content_.asOwnedString->length); - default: - return JsonString(); - } - } -#if ARDUINOJSON_USE_EXTENSIONS - const VariantExtension* getExtension(const ResourceManager* resources) const; -#endif - VariantData* getElement(size_t index, - const ResourceManager* resources) const { - return ArrayData::getElement(asArray(), index, resources); - } - static VariantData* getElement(const VariantData* var, size_t index, - const ResourceManager* resources) { - return var != 0 ? var->getElement(index, resources) : 0; - } - template - VariantData* getMember(TAdaptedString key, - const ResourceManager* resources) const { - return ObjectData::getMember(asObject(), key, resources); - } - template - static VariantData* getMember(const VariantData* var, TAdaptedString key, - const ResourceManager* resources) { - if (!var) - return 0; - return var->getMember(key, resources); - } - VariantData* getOrAddElement(size_t index, ResourceManager* resources) { - auto array = isNull() ? &toArray() : asArray(); - if (!array) - return nullptr; - return array->getOrAddElement(index, resources); - } - template - VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources) { - if (key.isNull()) - return nullptr; - auto obj = isNull() ? &toObject() : asObject(); - if (!obj) - return nullptr; - return obj->getOrAddMember(key, resources); - } - bool isArray() const { - return type_ == VariantType::Array; - } - bool isBoolean() const { - return type_ == VariantType::Boolean; - } - bool isCollection() const { - return type_ & VariantTypeBits::CollectionMask; - } - bool isFloat() const { - return type_ & VariantTypeBits::NumberBit; - } - template - bool isInteger(const ResourceManager* resources) const { -#if ARDUINOJSON_USE_LONG_LONG - auto extension = getExtension(resources); -#else - (void)resources; // silence warning -#endif - switch (type_) { - case VariantType::Uint32: - return canConvertNumber(content_.asUint32); - case VariantType::Int32: - return canConvertNumber(content_.asInt32); -#if ARDUINOJSON_USE_LONG_LONG - case VariantType::Uint64: - return canConvertNumber(extension->asUint64); - case VariantType::Int64: - return canConvertNumber(extension->asInt64); -#endif - default: - return false; - } - } - bool isNull() const { - return type_ == VariantType::Null; - } - static bool isNull(const VariantData* var) { - if (!var) - return true; - return var->isNull(); - } - bool isObject() const { - return type_ == VariantType::Object; - } - bool isString() const { - return type_ == VariantType::LinkedString || - type_ == VariantType::OwnedString || - type_ == VariantType::TinyString; - } - size_t nesting(const ResourceManager* resources) const { - auto collection = asCollection(); - if (collection) - return collection->nesting(resources); - else - return 0; - } - static size_t nesting(const VariantData* var, - const ResourceManager* resources) { - if (!var) - return 0; - return var->nesting(resources); - } - void removeElement(size_t index, ResourceManager* resources) { - ArrayData::removeElement(asArray(), index, resources); - } - static void removeElement(VariantData* var, size_t index, - ResourceManager* resources) { - if (!var) - return; - var->removeElement(index, resources); - } - template - void removeMember(TAdaptedString key, ResourceManager* resources) { - ObjectData::removeMember(asObject(), key, resources); - } - template - static void removeMember(VariantData* var, TAdaptedString key, - ResourceManager* resources) { - if (!var) - return; - var->removeMember(key, resources); - } - void reset() { // TODO: remove - type_ = VariantType::Null; - } - void setBoolean(bool value) { - ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first - type_ = VariantType::Boolean; - content_.asBoolean = value; - } - template - enable_if_t setFloat(T value, ResourceManager*) { - ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first - type_ = VariantType::Float; - content_.asFloat = value; - return true; - } - template - enable_if_t setFloat(T value, ResourceManager*); - template - enable_if_t::value, bool> setInteger(T value, - ResourceManager* resources); - template - enable_if_t::value, bool> setInteger( - T value, ResourceManager* resources); - void setRawString(StringNode* s) { - ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first - ARDUINOJSON_ASSERT(s); - type_ = VariantType::RawString; - content_.asOwnedString = s; - } - template - void setRawString(SerializedValue value, ResourceManager* resources); - template - static void setRawString(VariantData* var, SerializedValue value, - ResourceManager* resources) { - if (!var) - return; - var->clear(resources); - var->setRawString(value, resources); - } - template - bool setString(TAdaptedString value, ResourceManager* resources); - template - static void setString(VariantData* var, TAdaptedString value, - ResourceManager* resources) { - if (!var) - return; - var->clear(resources); - var->setString(value, resources); - } - void setLinkedString(const char* s) { - ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first - ARDUINOJSON_ASSERT(s); - type_ = VariantType::LinkedString; - content_.asLinkedString = s; - } - template - void setTinyString(const TAdaptedString& s) { - ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first - ARDUINOJSON_ASSERT(s.size() <= tinyStringMaxLength); - type_ = VariantType::TinyString; - auto n = uint8_t(s.size()); - for (uint8_t i = 0; i < n; i++) { - char c = s[i]; - ARDUINOJSON_ASSERT(c != 0); // no NUL in tiny string - content_.asTinyString[i] = c; - } - content_.asTinyString[n] = 0; - } - void setOwnedString(StringNode* s) { - ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first - ARDUINOJSON_ASSERT(s); - type_ = VariantType::OwnedString; - content_.asOwnedString = s; - } - size_t size(const ResourceManager* resources) const { - if (isObject()) - return content_.asObject.size(resources); - if (isArray()) - return content_.asArray.size(resources); - return 0; - } - static size_t size(const VariantData* var, const ResourceManager* resources) { - return var != 0 ? var->size(resources) : 0; - } - ArrayData& toArray() { - ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first - type_ = VariantType::Array; - new (&content_.asArray) ArrayData(); - return content_.asArray; - } - static ArrayData* toArray(VariantData* var, ResourceManager* resources) { - if (!var) - return 0; - var->clear(resources); - return &var->toArray(); - } - ObjectData& toObject() { - ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first - type_ = VariantType::Object; - new (&content_.asObject) ObjectData(); - return content_.asObject; - } - static ObjectData* toObject(VariantData* var, ResourceManager* resources) { - if (!var) - return 0; - var->clear(resources); - return &var->toObject(); - } - VariantType type() const { - return type_; - } - void clear(ResourceManager* resources); - static void clear(VariantData* var, ResourceManager* resources) { - if (!var) - return; - var->clear(resources); - } -}; -class VariantData; -class VariantWithId; -class ResourceManager { - union SlotData { - VariantData variant; -#if ARDUINOJSON_USE_EXTENSIONS - VariantExtension extension; -#endif - }; - public: - constexpr static size_t slotSize = sizeof(SlotData); - ResourceManager(Allocator* allocator = DefaultAllocator::instance()) - : allocator_(allocator), overflowed_(false) {} - ~ResourceManager() { - stringPool_.clear(allocator_); - variantPools_.clear(allocator_); - } - ResourceManager(const ResourceManager&) = delete; - ResourceManager& operator=(const ResourceManager& src) = delete; - friend void swap(ResourceManager& a, ResourceManager& b) { - swap(a.stringPool_, b.stringPool_); - swap(a.variantPools_, b.variantPools_); - swap_(a.allocator_, b.allocator_); - swap_(a.overflowed_, b.overflowed_); - } - Allocator* allocator() const { - return allocator_; - } - size_t size() const { - return variantPools_.size() + stringPool_.size(); - } - bool overflowed() const { - return overflowed_; - } - Slot allocVariant(); - void freeVariant(Slot slot); - VariantData* getVariant(SlotId id) const; -#if ARDUINOJSON_USE_EXTENSIONS - Slot allocExtension(); - void freeExtension(SlotId slot); - VariantExtension* getExtension(SlotId id) const; -#endif - template - StringNode* saveString(TAdaptedString str) { - if (str.isNull()) - return 0; - auto node = stringPool_.add(str, allocator_); - if (!node) - overflowed_ = true; - return node; - } - void saveString(StringNode* node) { - stringPool_.add(node); - } - template - StringNode* getString(const TAdaptedString& str) const { - return stringPool_.get(str); - } - StringNode* createString(size_t length) { - auto node = StringNode::create(length, allocator_); - if (!node) - overflowed_ = true; - return node; - } - StringNode* resizeString(StringNode* node, size_t length) { - node = StringNode::resize(node, length, allocator_); - if (!node) - overflowed_ = true; - return node; - } - void destroyString(StringNode* node) { - StringNode::destroy(node, allocator_); - } - void dereferenceString(const char* s) { - stringPool_.dereference(s, allocator_); - } - void clear() { - variantPools_.clear(allocator_); - overflowed_ = false; - stringPool_.clear(allocator_); - } - void shrinkToFit() { - variantPools_.shrinkToFit(allocator_); - } - private: - Allocator* allocator_; - bool overflowed_; - StringPool stringPool_; - MemoryPoolList variantPools_; -}; -template -struct IsString : false_type {}; -template -struct IsString::AdaptedString>> - : true_type {}; -ARDUINOJSON_END_PRIVATE_NAMESPACE -ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE -class JsonArray; -class JsonObject; -class JsonVariant; -ARDUINOJSON_END_PUBLIC_NAMESPACE -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -template -struct VariantTo {}; -template <> -struct VariantTo { - using type = JsonArray; -}; -template <> -struct VariantTo { - using type = JsonObject; -}; -template <> -struct VariantTo { - using type = JsonVariant; -}; -class VariantAttorney { - public: - template - static auto getResourceManager(TClient& client) - -> decltype(client.getResourceManager()) { - return client.getResourceManager(); - } - template - static auto getData(TClient& client) -> decltype(client.getData()) { - return client.getData(); - } - template - static VariantData* getOrCreateData(TClient& client) { - return client.getOrCreateData(); - } -}; -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, - enable_if_t::value && is_integral::value && - sizeof(T1) < sizeof(T2)>* = 0) { - return arithmeticCompare(static_cast(lhs), rhs); -} -template -CompareResult arithmeticCompare( - const T1& lhs, const T2& rhs, - enable_if_t::value && is_integral::value && - sizeof(T2) < sizeof(T1)>* = 0) { - return arithmeticCompare(lhs, static_cast(rhs)); -} -template -CompareResult arithmeticCompare( - const T1& lhs, const T2& rhs, - enable_if_t::value && is_integral::value && - is_signed::value == is_signed::value && - sizeof(T2) == sizeof(T1)>* = 0) { - return arithmeticCompare(lhs, static_cast(rhs)); -} -template -CompareResult arithmeticCompare( - const T1& lhs, const T2& rhs, - enable_if_t::value && is_integral::value && - is_unsigned::value && is_signed::value && - sizeof(T2) == sizeof(T1)>* = 0) { - if (rhs < 0) - return COMPARE_RESULT_GREATER; - return arithmeticCompare(lhs, static_cast(rhs)); -} -template -CompareResult arithmeticCompare( - const T1& lhs, const T2& rhs, - enable_if_t::value && is_integral::value && - is_signed::value && is_unsigned::value && - sizeof(T2) == sizeof(T1)>* = 0) { - if (lhs < 0) - return COMPARE_RESULT_LESS; - return arithmeticCompare(static_cast(lhs), rhs); -} -template -CompareResult arithmeticCompare( - const T1& lhs, const T2& rhs, - enable_if_t::value || is_floating_point::value>* = - 0) { - return arithmeticCompare(static_cast(lhs), - static_cast(rhs)); -} -template -CompareResult arithmeticCompareNegateLeft( - JsonUInt, const T2&, enable_if_t::value>* = 0) { - return COMPARE_RESULT_LESS; -} -template -CompareResult arithmeticCompareNegateLeft( - JsonUInt lhs, const T2& rhs, enable_if_t::value>* = 0) { - if (rhs > 0) - return COMPARE_RESULT_LESS; - return arithmeticCompare(-rhs, static_cast(lhs)); -} -template -CompareResult arithmeticCompareNegateRight( - const T1&, JsonUInt, enable_if_t::value>* = 0) { - return COMPARE_RESULT_GREATER; -} -template -CompareResult arithmeticCompareNegateRight( - const T1& lhs, JsonUInt rhs, enable_if_t::value>* = 0) { - if (lhs > 0) - return COMPARE_RESULT_GREATER; - return arithmeticCompare(static_cast(rhs), -lhs); -} -struct VariantTag {}; -template -struct IsVariant : is_base_of {}; -ARDUINOJSON_END_PRIVATE_NAMESPACE -ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE -class JsonVariantConst; -ARDUINOJSON_END_PUBLIC_NAMESPACE -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -template -CompareResult compare(JsonVariantConst lhs, - const T& rhs); // VariantCompare.cpp -struct VariantOperatorTag {}; -template -struct VariantOperators : VariantOperatorTag { - template ::value && !is_array::value, int> = 0> - 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) { - if (variant.template is()) - return variant.template as(); - else - return defaultValue; - } - template - friend enable_if_t::value, JsonVariantConst> operator|( - const TVariant& variant, const T& defaultValue) { - if (variant) - return variant; - else - return defaultValue; - } - template - friend bool operator==(T* lhs, const TVariant& rhs) { - return compare(rhs, lhs) == COMPARE_RESULT_EQUAL; - } - template - friend bool operator==(const T& lhs, const TVariant& rhs) { - return compare(rhs, lhs) == COMPARE_RESULT_EQUAL; - } - template - friend bool operator==(const TVariant& lhs, T* rhs) { - return compare(lhs, rhs) == COMPARE_RESULT_EQUAL; - } - template ::value, int> = 0> - friend bool operator==(const TVariant& lhs, const T& rhs) { - return compare(lhs, rhs) == COMPARE_RESULT_EQUAL; - } - template - friend bool operator!=(T* lhs, const TVariant& rhs) { - return compare(rhs, lhs) != COMPARE_RESULT_EQUAL; - } - template - friend bool operator!=(const T& lhs, const TVariant& rhs) { - return compare(rhs, lhs) != COMPARE_RESULT_EQUAL; - } - template - friend bool operator!=(const TVariant& lhs, T* rhs) { - return compare(lhs, rhs) != COMPARE_RESULT_EQUAL; - } - template ::value, int> = 0> - friend bool operator!=(TVariant lhs, const T& rhs) { - return compare(lhs, rhs) != COMPARE_RESULT_EQUAL; - } - template - friend bool operator<(T* lhs, const TVariant& rhs) { - return compare(rhs, lhs) == COMPARE_RESULT_GREATER; - } - template - friend bool operator<(const T& lhs, const TVariant& rhs) { - return compare(rhs, lhs) == COMPARE_RESULT_GREATER; - } - template - friend bool operator<(const TVariant& lhs, T* rhs) { - return compare(lhs, rhs) == COMPARE_RESULT_LESS; - } - template ::value, int> = 0> - friend bool operator<(TVariant lhs, const T& rhs) { - return compare(lhs, rhs) == COMPARE_RESULT_LESS; - } - template - friend bool operator<=(T* lhs, const TVariant& rhs) { - return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; - } - template - friend bool operator<=(const T& lhs, const TVariant& rhs) { - return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; - } - template - friend bool operator<=(const TVariant& lhs, T* rhs) { - return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; - } - template ::value, int> = 0> - friend bool operator<=(TVariant lhs, const T& rhs) { - return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; - } - template - friend bool operator>(T* lhs, const TVariant& rhs) { - return compare(rhs, lhs) == COMPARE_RESULT_LESS; - } - template - friend bool operator>(const T& lhs, const TVariant& rhs) { - return compare(rhs, lhs) == COMPARE_RESULT_LESS; - } - template - friend bool operator>(const TVariant& lhs, T* rhs) { - return compare(lhs, rhs) == COMPARE_RESULT_GREATER; - } - template ::value, int> = 0> - friend bool operator>(TVariant lhs, const T& rhs) { - return compare(lhs, rhs) == COMPARE_RESULT_GREATER; - } - template - friend bool operator>=(T* lhs, const TVariant& rhs) { - return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; - } - template - friend bool operator>=(const T& lhs, const TVariant& rhs) { - return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; - } - template - friend bool operator>=(const TVariant& lhs, T* rhs) { - return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; - } - template ::value, int> = 0> - friend bool operator>=(const TVariant& lhs, const T& rhs) { - return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; - } -}; -ARDUINOJSON_END_PRIVATE_NAMESPACE -ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE -class JsonArray; -class JsonObject; -class JsonVariantConst : public detail::VariantTag, - public detail::VariantOperators { - friend class detail::VariantAttorney; - template - using ConversionSupported = - detail::is_same::fromJson)>::arg1_type, - JsonVariantConst>; - public: - JsonVariantConst() : data_(nullptr), resources_(nullptr) {} - explicit JsonVariantConst(const detail::VariantData* data, - const detail::ResourceManager* resources) - : data_(data), resources_(resources) {} - bool isNull() const { - return detail::VariantData::isNull(data_); - } - bool isUnbound() const { - return !data_; - } - size_t nesting() const { - return detail::VariantData::nesting(data_, resources_); - } - size_t size() const { - return detail::VariantData::size(data_, resources_); - } - template ::value, int> = 0> - T as() const { - return Converter::fromJson(*this); - } - template ::value, int> = 0> - detail::InvalidConversion as() const; - template ::value, int> = 0> - bool is() const { - return Converter::checkJson(*this); - } - template ::value, int> = 0> - bool is() const { - return false; - } - template - operator T() const { - return as(); - } - template ::value, int> = 0> - JsonVariantConst operator[](T index) const { - return JsonVariantConst( - detail::VariantData::getElement(data_, size_t(index), resources_), - resources_); - } - template ::value, int> = 0> - JsonVariantConst operator[](const TString& key) const { - return JsonVariantConst(detail::VariantData::getMember( - data_, detail::adaptString(key), resources_), - resources_); - } - template ::value && - !detail::is_const::value, - int> = 0> - JsonVariantConst operator[](TChar* key) const { - return JsonVariantConst(detail::VariantData::getMember( - data_, detail::adaptString(key), resources_), - resources_); - } - template ::value, int> = 0> - JsonVariantConst operator[](const TVariant& key) const { - if (key.template is()) - return operator[](key.template as()); - else - return operator[](key.template as()); - } - template ::value, int> = 0> - ARDUINOJSON_DEPRECATED("use var[key].is() instead") - bool containsKey(const TString& key) const { - return detail::VariantData::getMember(getData(), detail::adaptString(key), - resources_) != 0; - } - template ::value && - !detail::is_const::value, - int> = 0> - ARDUINOJSON_DEPRECATED("use obj[\"key\"].is() instead") - bool containsKey(TChar* key) const { - return detail::VariantData::getMember(getData(), detail::adaptString(key), - resources_) != 0; - } - template ::value, int> = 0> - ARDUINOJSON_DEPRECATED("use var[key].is() instead") - bool containsKey(const TVariant& key) const { - return containsKey(key.template as()); - } - ARDUINOJSON_DEPRECATED("always returns zero") - size_t memoryUsage() const { - return 0; - } - protected: - const detail::VariantData* getData() const { - return data_; - } - const detail::ResourceManager* getResourceManager() const { - return resources_; - } - private: - const detail::VariantData* data_; - const detail::ResourceManager* resources_; -}; -class JsonVariant; -ARDUINOJSON_END_PUBLIC_NAMESPACE -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -template -class ElementProxy; -template -class MemberProxy; -template -class VariantRefBase : public VariantTag { - friend class VariantAttorney; - public: - void clear() const { - VariantData::clear(getOrCreateData(), getResourceManager()); - } - bool isNull() const { - return VariantData::isNull(getData()); - } - bool isUnbound() const { - return !getData(); - } - template - T as() const; - template ::value, int> = 0> - operator T() const { - return as(); - } - template ::value, int> = 0> - JsonArray to() const; - template ::value, int> = 0> - JsonObject to() const; - template ::value, int> = 0> - JsonVariant to() const; - template - FORCE_INLINE bool is() const; - template - bool set(const T& value) const { - using TypeForConverter = conditional_t::value, T, - remove_cv_t>>; - return doSet>(value); - } - template ::value, int> = 0> - bool set(T* value) const { - return doSet>(value); - } - size_t size() const { - return VariantData::size(getData(), getResourceManager()); - } - size_t nesting() const { - return VariantData::nesting(getData(), getResourceManager()); - } - template ::value, int> = 0> - T add() const { - return add().template to(); - } - template ::value, int> = 0> - T add() const; - template - bool add(const T& value) const { - return detail::VariantData::addValue(getOrCreateData(), value, - getResourceManager()); - } - template ::value, int> = 0> - bool add(T* value) const { - return detail::VariantData::addValue(getOrCreateData(), value, - getResourceManager()); - } - void remove(size_t index) const { - VariantData::removeElement(getData(), index, getResourceManager()); - } - template ::value, int> = 0> - void remove(TChar* key) const { - VariantData::removeMember(getData(), adaptString(key), - getResourceManager()); - } - template ::value, int> = 0> - void remove(const TString& key) const { - VariantData::removeMember(getData(), adaptString(key), - getResourceManager()); - } - template ::value, int> = 0> - void remove(const TVariant& key) const { - if (key.template is()) - remove(key.template as()); - else - remove(key.template as()); - } - ElementProxy operator[](size_t index) const; - template ::value, int> = 0> - ARDUINOJSON_DEPRECATED("use obj[key].is() instead") - bool containsKey(const TString& key) const; - template ::value, int> = 0> - ARDUINOJSON_DEPRECATED("use obj[\"key\"].is() instead") - bool containsKey(TChar* key) const; - template ::value, int> = 0> - ARDUINOJSON_DEPRECATED("use obj[key].is() instead") - bool containsKey(const TVariant& key) const; - template ::value, int> = 0> - FORCE_INLINE MemberProxy> operator[]( - const TString& key) const; - template < - typename TChar, - enable_if_t::value && !is_const::value, int> = 0> - FORCE_INLINE MemberProxy> operator[]( - TChar* key) const; - template ::value, int> = 0> - JsonVariantConst operator[](const TVariant& key) const { - if (key.template is()) - return operator[](key.template as()); - else - return operator[](key.template as()); - } - ARDUINOJSON_DEPRECATED("use add() instead") - JsonVariant add() const; - ARDUINOJSON_DEPRECATED("use add() instead") - JsonArray createNestedArray() const; - template - ARDUINOJSON_DEPRECATED("use var[key].to() instead") - JsonArray createNestedArray(TChar* key) const; - template - ARDUINOJSON_DEPRECATED("use var[key].to() instead") - JsonArray createNestedArray(const TString& key) const; - ARDUINOJSON_DEPRECATED("use add() instead") - JsonObject createNestedObject() const; - template - ARDUINOJSON_DEPRECATED("use var[key].to() instead") - JsonObject createNestedObject(TChar* key) const; - template - ARDUINOJSON_DEPRECATED("use var[key].to() instead") - JsonObject createNestedObject(const TString& key) const; - ARDUINOJSON_DEPRECATED("always returns zero") - size_t memoryUsage() const { - return 0; - } - ARDUINOJSON_DEPRECATED("performs a deep copy") - void shallowCopy(JsonVariantConst src) const { - set(src); - } - private: - TDerived& derived() { - return static_cast(*this); - } - const TDerived& derived() const { - return static_cast(*this); - } - ResourceManager* getResourceManager() const { - return VariantAttorney::getResourceManager(derived()); - } - VariantData* getData() const { - return VariantAttorney::getData(derived()); - } - VariantData* getOrCreateData() const { - return VariantAttorney::getOrCreateData(derived()); - } - FORCE_INLINE ArduinoJson::JsonVariant getVariant() const; - FORCE_INLINE ArduinoJson::JsonVariantConst getVariantConst() const { - return ArduinoJson::JsonVariantConst(getData(), getResourceManager()); - } - template - FORCE_INLINE enable_if_t::value, T> getVariant() - const { - return getVariantConst(); - } - template - FORCE_INLINE enable_if_t::value, T> getVariant() - const { - return getVariant(); - } - template - bool doSet(const T& value) const { - return doSet( - value, is_same::return_type, - bool>{}); - } - template - bool doSet(const T& value, false_type) const; - template - bool doSet(const T& value, true_type) const; - ArduinoJson::JsonVariant getOrCreateVariant() const; -}; -template -class ElementProxy : public VariantRefBase>, - public VariantOperators> { - friend class VariantAttorney; - friend class VariantRefBase>; - template - friend class MemberProxy; - template - friend class ElementProxy; - public: - ElementProxy(TUpstream upstream, size_t index) - : upstream_(upstream), index_(index) {} - ElementProxy& operator=(const ElementProxy& src) { - this->set(src); - return *this; - } - template - ElementProxy& operator=(const T& src) { - this->set(src); - return *this; - } - template - ElementProxy& operator=(T* src) { - this->set(src); - return *this; - } - private: - ElementProxy(const ElementProxy& src) // Error here? See https://arduinojson.org/v7/proxy-non-copyable/ - : upstream_(src.upstream_), index_(src.index_) {} - ResourceManager* getResourceManager() const { - return VariantAttorney::getResourceManager(upstream_); - } - FORCE_INLINE VariantData* getData() const { - return VariantData::getElement( - VariantAttorney::getData(upstream_), index_, - VariantAttorney::getResourceManager(upstream_)); - } - VariantData* getOrCreateData() const { - auto data = VariantAttorney::getOrCreateData(upstream_); - if (!data) - return nullptr; - return data->getOrAddElement( - index_, VariantAttorney::getResourceManager(upstream_)); - } - TUpstream upstream_; - size_t index_; -}; -ARDUINOJSON_END_PRIVATE_NAMESPACE -ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE -class JsonVariant : public detail::VariantRefBase, - public detail::VariantOperators { - friend class detail::VariantAttorney; - public: - JsonVariant() : data_(0), resources_(0) {} - JsonVariant(detail::VariantData* data, detail::ResourceManager* resources) - : data_(data), resources_(resources) {} - private: - detail::ResourceManager* getResourceManager() const { - return resources_; - } - detail::VariantData* getData() const { - return data_; - } - detail::VariantData* getOrCreateData() const { - return data_; - } - detail::VariantData* data_; - detail::ResourceManager* resources_; -}; -namespace detail { -bool copyVariant(JsonVariant dst, JsonVariantConst src); -} -template <> -struct Converter : private detail::VariantAttorney { - static void toJson(JsonVariantConst src, JsonVariant dst) { - copyVariant(dst, src); - } - static JsonVariant fromJson(JsonVariant src) { - return src; - } - static bool checkJson(JsonVariant src) { - auto data = getData(src); - return !!data; - } -}; -template <> -struct Converter : private detail::VariantAttorney { - static void toJson(JsonVariantConst src, JsonVariant dst) { - copyVariant(dst, src); - } - static JsonVariantConst fromJson(JsonVariantConst src) { - return JsonVariantConst(getData(src), getResourceManager(src)); - } - static bool checkJson(JsonVariantConst src) { - auto data = getData(src); - return !!data; - } -}; -template -class Ptr { - public: - Ptr(T value) : value_(value) {} - T* operator->() { - return &value_; - } - T& operator*() { - return value_; - } - private: - T value_; -}; -class JsonArrayIterator { - friend class JsonArray; - public: - JsonArrayIterator() {} - explicit JsonArrayIterator(detail::ArrayData::iterator iterator, - detail::ResourceManager* resources) - : iterator_(iterator), resources_(resources) {} - JsonVariant operator*() { - return JsonVariant(iterator_.data(), resources_); - } - Ptr operator->() { - return operator*(); - } - bool operator==(const JsonArrayIterator& other) const { - return iterator_ == other.iterator_; - } - bool operator!=(const JsonArrayIterator& other) const { - return iterator_ != other.iterator_; - } - JsonArrayIterator& operator++() { - iterator_.next(resources_); - return *this; - } - private: - detail::ArrayData::iterator iterator_; - detail::ResourceManager* resources_; -}; -class JsonArrayConstIterator { - friend class JsonArray; - public: - JsonArrayConstIterator() {} - explicit JsonArrayConstIterator(detail::ArrayData::iterator iterator, - const detail::ResourceManager* resources) - : iterator_(iterator), resources_(resources) {} - JsonVariantConst operator*() const { - return JsonVariantConst(iterator_.data(), resources_); - } - Ptr operator->() { - return operator*(); - } - bool operator==(const JsonArrayConstIterator& other) const { - return iterator_ == other.iterator_; - } - bool operator!=(const JsonArrayConstIterator& other) const { - return iterator_ != other.iterator_; - } - JsonArrayConstIterator& operator++() { - iterator_.next(resources_); - return *this; - } - private: - detail::ArrayData::iterator iterator_; - const detail::ResourceManager* resources_; -}; -class JsonObject; -class JsonArrayConst : public detail::VariantOperators { - friend class JsonArray; - friend class detail::VariantAttorney; - public: - using iterator = JsonArrayConstIterator; - iterator begin() const { - if (!data_) - return iterator(); - return iterator(data_->createIterator(resources_), resources_); - } - iterator end() const { - return iterator(); - } - JsonArrayConst() : data_(0), resources_(0) {} - JsonArrayConst(const detail::ArrayData* data, - const detail::ResourceManager* resources) - : data_(data), resources_(resources) {} - template ::value, int> = 0> - JsonVariantConst operator[](T index) const { - return JsonVariantConst( - detail::ArrayData::getElement(data_, size_t(index), resources_), - resources_); - } - template ::value, int> = 0> - JsonVariantConst operator[](const TVariant& variant) const { - if (variant.template is()) - return operator[](variant.template as()); - else - return JsonVariantConst(); - } - operator JsonVariantConst() const { - return JsonVariantConst(getData(), resources_); - } - bool isNull() const { - return data_ == 0; - } - operator bool() const { - return data_ != 0; - } - size_t nesting() const { - return detail::VariantData::nesting(getData(), resources_); - } - size_t size() const { - return data_ ? data_->size(resources_) : 0; - } - ARDUINOJSON_DEPRECATED("always returns zero") - size_t memoryUsage() const { - return 0; - } - private: - const detail::VariantData* getData() const { - return collectionToVariant(data_); - } - const detail::ArrayData* data_; - const detail::ResourceManager* resources_; -}; -inline bool operator==(JsonArrayConst lhs, JsonArrayConst rhs) { - if (!lhs && !rhs) - return true; - if (!lhs || !rhs) - return false; - auto a = lhs.begin(); - auto b = rhs.begin(); - for (;;) { - if (a == b) // same pointer or both null - return true; - if (a == lhs.end() || b == rhs.end()) - return false; - if (*a != *b) - return false; - ++a; - ++b; - } -} -class JsonObject; -class JsonArray : public detail::VariantOperators { - friend class detail::VariantAttorney; - public: - using iterator = JsonArrayIterator; - JsonArray() : data_(0), resources_(0) {} - JsonArray(detail::ArrayData* data, detail::ResourceManager* resources) - : data_(data), resources_(resources) {} - operator JsonVariant() { - void* data = data_; // prevent warning cast-align - return JsonVariant(reinterpret_cast(data), - resources_); - } - operator JsonArrayConst() const { - return JsonArrayConst(data_, resources_); - } - template ::value, int> = 0> - T add() const { - return add().to(); - } - template ::value, int> = 0> - JsonVariant add() const { - return JsonVariant(detail::ArrayData::addElement(data_, resources_), - resources_); - } - template - bool add(const T& value) const { - return detail::ArrayData::addValue(data_, value, resources_); - } - template ::value, int> = 0> - bool add(T* value) const { - return detail::ArrayData::addValue(data_, value, resources_); - } - iterator begin() const { - if (!data_) - return iterator(); - return iterator(data_->createIterator(resources_), resources_); - } - iterator end() const { - return iterator(); - } - bool set(JsonArrayConst src) const { - if (!data_) - return false; - clear(); - for (auto element : src) { - if (!add(element)) - return false; - } - return true; - } - void remove(iterator it) const { - detail::ArrayData::remove(data_, it.iterator_, resources_); - } - void remove(size_t index) const { - detail::ArrayData::removeElement(data_, index, resources_); - } - template ::value, int> = 0> - void remove(const TVariant& variant) const { - if (variant.template is()) - remove(variant.template as()); - } - void clear() const { - detail::ArrayData::clear(data_, resources_); - } - template ::value, int> = 0> - detail::ElementProxy operator[](T index) const { - return {*this, size_t(index)}; - } - template ::value, int> = 0> - detail::ElementProxy operator[](const TVariant& variant) const { - if (variant.template is()) - return {*this, variant.template as()}; - else - return {*this, size_t(-1)}; - } - operator JsonVariantConst() const { - return JsonVariantConst(collectionToVariant(data_), resources_); - } - bool isNull() const { - return data_ == 0; - } - operator bool() const { - return data_ != 0; - } - size_t nesting() const { - return detail::VariantData::nesting(collectionToVariant(data_), resources_); - } - size_t size() const { - return data_ ? data_->size(resources_) : 0; - } - ARDUINOJSON_DEPRECATED("use add() instead") - JsonVariant add() const { - return add(); - } - ARDUINOJSON_DEPRECATED("use add() instead") - JsonArray createNestedArray() const { - return add(); - } - ARDUINOJSON_DEPRECATED("use add() instead") - JsonObject createNestedObject() const; - ARDUINOJSON_DEPRECATED("always returns zero") - size_t memoryUsage() const { - return 0; - } - private: - detail::ResourceManager* getResourceManager() const { - return resources_; - } - detail::VariantData* getData() const { - return collectionToVariant(data_); - } - detail::VariantData* getOrCreateData() const { - return collectionToVariant(data_); - } - detail::ArrayData* data_; - detail::ResourceManager* resources_; -}; -class JsonPair { - public: - JsonPair(detail::ObjectData::iterator iterator, - detail::ResourceManager* resources) { - if (!iterator.done()) { - key_ = iterator->asString(); - iterator.next(resources); - value_ = JsonVariant(iterator.data(), resources); - } - } - JsonString key() const { - return key_; - } - JsonVariant value() { - return value_; - } - private: - JsonString key_; - JsonVariant value_; -}; -class JsonPairConst { - public: - JsonPairConst(detail::ObjectData::iterator iterator, - const detail::ResourceManager* resources) { - if (!iterator.done()) { - key_ = iterator->asString(); - iterator.next(resources); - value_ = JsonVariantConst(iterator.data(), resources); - } - } - JsonString key() const { - return key_; - } - JsonVariantConst value() const { - return value_; - } - private: - JsonString key_; - JsonVariantConst value_; -}; -class JsonObjectIterator { - friend class JsonObject; - public: - JsonObjectIterator() {} - explicit JsonObjectIterator(detail::ObjectData::iterator iterator, - detail::ResourceManager* resources) - : iterator_(iterator), resources_(resources) {} - JsonPair operator*() const { - return JsonPair(iterator_, resources_); - } - Ptr operator->() { - return operator*(); - } - bool operator==(const JsonObjectIterator& other) const { - return iterator_ == other.iterator_; - } - bool operator!=(const JsonObjectIterator& other) const { - return iterator_ != other.iterator_; - } - JsonObjectIterator& operator++() { - iterator_.next(resources_); // key - iterator_.next(resources_); // value - return *this; - } - private: - detail::ObjectData::iterator iterator_; - detail::ResourceManager* resources_; -}; -class JsonObjectConstIterator { - friend class JsonObject; - public: - JsonObjectConstIterator() {} - explicit JsonObjectConstIterator(detail::ObjectData::iterator iterator, - const detail::ResourceManager* resources) - : iterator_(iterator), resources_(resources) {} - JsonPairConst operator*() const { - return JsonPairConst(iterator_, resources_); - } - Ptr operator->() { - return operator*(); - } - bool operator==(const JsonObjectConstIterator& other) const { - return iterator_ == other.iterator_; - } - bool operator!=(const JsonObjectConstIterator& other) const { - return iterator_ != other.iterator_; - } - JsonObjectConstIterator& operator++() { - iterator_.next(resources_); // key - iterator_.next(resources_); // value - return *this; - } - private: - detail::ObjectData::iterator iterator_; - const detail::ResourceManager* resources_; -}; -class JsonObjectConst : public detail::VariantOperators { - friend class JsonObject; - friend class detail::VariantAttorney; - public: - using iterator = JsonObjectConstIterator; - JsonObjectConst() : data_(0), resources_(0) {} - JsonObjectConst(const detail::ObjectData* data, - const detail::ResourceManager* resources) - : data_(data), resources_(resources) {} - operator JsonVariantConst() const { - return JsonVariantConst(getData(), resources_); - } - bool isNull() const { - return data_ == 0; - } - operator bool() const { - return data_ != 0; - } - size_t nesting() const { - return detail::VariantData::nesting(getData(), resources_); - } - size_t size() const { - return data_ ? data_->size(resources_) : 0; - } - iterator begin() const { - if (!data_) - return iterator(); - return iterator(data_->createIterator(resources_), resources_); - } - iterator end() const { - return iterator(); - } - template ::value, int> = 0> - ARDUINOJSON_DEPRECATED("use obj[key].is() instead") - bool containsKey(const TString& key) const { - return detail::ObjectData::getMember(data_, detail::adaptString(key), - resources_) != 0; - } - template - ARDUINOJSON_DEPRECATED("use obj[\"key\"].is() instead") - bool containsKey(TChar* key) const { - return detail::ObjectData::getMember(data_, detail::adaptString(key), - resources_) != 0; - } - template ::value, int> = 0> - ARDUINOJSON_DEPRECATED("use obj[key].is() instead") - bool containsKey(const TVariant& key) const { - return containsKey(key.template as()); - } - template ::value, int> = 0> - JsonVariantConst operator[](const TString& key) const { - return JsonVariantConst(detail::ObjectData::getMember( - data_, detail::adaptString(key), resources_), - resources_); - } - template ::value && - !detail::is_const::value, - int> = 0> - JsonVariantConst operator[](TChar* key) const { - return JsonVariantConst(detail::ObjectData::getMember( - data_, detail::adaptString(key), resources_), - resources_); - } - template ::value, int> = 0> - JsonVariantConst operator[](const TVariant& key) const { - if (key.template is()) - return operator[](key.template as()); - else - return JsonVariantConst(); - } - ARDUINOJSON_DEPRECATED("always returns zero") - size_t memoryUsage() const { - return 0; - } - private: - const detail::VariantData* getData() const { - return collectionToVariant(data_); - } - const detail::ObjectData* data_; - const detail::ResourceManager* resources_; -}; -inline bool operator==(JsonObjectConst lhs, JsonObjectConst rhs) { - if (!lhs && !rhs) // both are null - return true; - if (!lhs || !rhs) // only one is null - return false; - size_t count = 0; - for (auto kvp : lhs) { - auto rhsValue = rhs[kvp.key()]; - if (rhsValue.isUnbound()) - return false; - if (kvp.value() != rhsValue) - return false; - count++; - } - return count == rhs.size(); -} -ARDUINOJSON_END_PUBLIC_NAMESPACE -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -template -class MemberProxy - : public VariantRefBase>, - public VariantOperators> { - friend class VariantAttorney; - friend class VariantRefBase>; - template - friend class MemberProxy; - template - friend class ElementProxy; - public: - MemberProxy(TUpstream upstream, AdaptedString key) - : upstream_(upstream), key_(key) {} - MemberProxy& operator=(const MemberProxy& src) { - this->set(src); - return *this; - } - template - MemberProxy& operator=(const T& src) { - this->set(src); - return *this; - } - template ::value, int> = 0> - MemberProxy& operator=(T* src) { - this->set(src); - return *this; - } - private: - MemberProxy(const MemberProxy& src) // Error here? See https://arduinojson.org/v7/proxy-non-copyable/ - : upstream_(src.upstream_), key_(src.key_) {} - ResourceManager* getResourceManager() const { - return VariantAttorney::getResourceManager(upstream_); - } - VariantData* getData() const { - return VariantData::getMember( - VariantAttorney::getData(upstream_), key_, - VariantAttorney::getResourceManager(upstream_)); - } - VariantData* getOrCreateData() const { - auto data = VariantAttorney::getOrCreateData(upstream_); - if (!data) - return nullptr; - return data->getOrAddMember(key_, - VariantAttorney::getResourceManager(upstream_)); - } - private: - TUpstream upstream_; - AdaptedString key_; -}; -ARDUINOJSON_END_PRIVATE_NAMESPACE -ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE -class JsonArray; -class JsonObject : public detail::VariantOperators { - friend class detail::VariantAttorney; - public: - using iterator = JsonObjectIterator; - JsonObject() : data_(0), resources_(0) {} - JsonObject(detail::ObjectData* data, detail::ResourceManager* resource) - : data_(data), resources_(resource) {} - operator JsonVariant() const { - void* data = data_; // prevent warning cast-align - return JsonVariant(reinterpret_cast(data), - resources_); - } - operator JsonObjectConst() const { - return JsonObjectConst(data_, resources_); - } - operator JsonVariantConst() const { - return JsonVariantConst(collectionToVariant(data_), resources_); - } - bool isNull() const { - return data_ == 0; - } - operator bool() const { - return data_ != 0; - } - size_t nesting() const { - return detail::VariantData::nesting(collectionToVariant(data_), resources_); - } - size_t size() const { - return data_ ? data_->size(resources_) : 0; - } - iterator begin() const { - if (!data_) - return iterator(); - return iterator(data_->createIterator(resources_), resources_); - } - iterator end() const { - return iterator(); - } - void clear() const { - detail::ObjectData::clear(data_, resources_); - } - bool set(JsonObjectConst src) { - if (!data_ || !src.data_) - return false; - clear(); - for (auto kvp : src) { - if (!operator[](kvp.key()).set(kvp.value())) - return false; - } - return true; - } - template ::value, int> = 0> - detail::MemberProxy> operator[]( - const TString& key) const { - return {*this, detail::adaptString(key)}; - } - template ::value && - !detail::is_const::value, - int> = 0> - detail::MemberProxy> operator[]( - TChar* key) const { - return {*this, detail::adaptString(key)}; - } - template ::value, int> = 0> - detail::MemberProxy> operator[]( - const TVariant& key) const { - return {*this, detail::adaptString(key.template as())}; - } - FORCE_INLINE void remove(iterator it) const { - detail::ObjectData::remove(data_, it.iterator_, resources_); - } - template ::value, int> = 0> - void remove(const TString& key) const { - detail::ObjectData::removeMember(data_, detail::adaptString(key), - resources_); - } - template ::value, int> = 0> - void remove(const TVariant& key) const { - if (key.template is()) - remove(key.template as()); - } - template - FORCE_INLINE void remove(TChar* key) const { - detail::ObjectData::removeMember(data_, detail::adaptString(key), - resources_); - } - template ::value, int> = 0> - ARDUINOJSON_DEPRECATED("use obj[key].is() instead") - bool containsKey(const TString& key) const { - return detail::ObjectData::getMember(data_, detail::adaptString(key), - resources_) != 0; - } - template ::value && - !detail::is_const::value, - int> = 0> - ARDUINOJSON_DEPRECATED("use obj[\"key\"].is() instead") - bool containsKey(TChar* key) const { - return detail::ObjectData::getMember(data_, detail::adaptString(key), - resources_) != 0; - } - template ::value, int> = 0> - ARDUINOJSON_DEPRECATED("use obj[key].is() instead") - bool containsKey(const TVariant& key) const { - return containsKey(key.template as()); - } - template - ARDUINOJSON_DEPRECATED("use obj[key].to() instead") - JsonArray createNestedArray(TChar* key) const { - return operator[](key).template to(); - } - template - ARDUINOJSON_DEPRECATED("use obj[key].to() instead") - JsonArray createNestedArray(const TString& key) const { - return operator[](key).template to(); - } - template - ARDUINOJSON_DEPRECATED("use obj[key].to() instead") - JsonObject createNestedObject(TChar* key) { - return operator[](key).template to(); - } - template - ARDUINOJSON_DEPRECATED("use obj[key].to() instead") - JsonObject createNestedObject(const TString& key) { - return operator[](key).template to(); - } - ARDUINOJSON_DEPRECATED("always returns zero") - size_t memoryUsage() const { - return 0; - } - private: - detail::ResourceManager* getResourceManager() const { - return resources_; - } - detail::VariantData* getData() const { - return detail::collectionToVariant(data_); - } - detail::VariantData* getOrCreateData() const { - return detail::collectionToVariant(data_); - } - detail::ObjectData* data_; - detail::ResourceManager* resources_; -}; -ARDUINOJSON_END_PUBLIC_NAMESPACE - -ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE -class JsonDocument : public detail::VariantOperators { - friend class detail::VariantAttorney; - public: - explicit JsonDocument(Allocator* alloc = detail::DefaultAllocator::instance()) - : resources_(alloc) {} - JsonDocument(const JsonDocument& src) : JsonDocument(src.allocator()) { - set(src); - } - JsonDocument(JsonDocument&& src) - : JsonDocument(detail::DefaultAllocator::instance()) { - swap(*this, src); - } - template ::value || - detail::is_same::value || - detail::is_same::value || - detail::is_same::value || - detail::is_same::value, - int> = 0> - JsonDocument(const T& src, - Allocator* alloc = detail::DefaultAllocator::instance()) - : JsonDocument(alloc) { - set(src); - } - JsonDocument& operator=(JsonDocument src) { - swap(*this, src); - return *this; - } - template - JsonDocument& operator=(const T& src) { - set(src); - return *this; - } - Allocator* allocator() const { - return resources_.allocator(); - } - void shrinkToFit() { - resources_.shrinkToFit(); - } - template - T as() { - return getVariant().template as(); - } - template - T as() const { - return getVariant().template as(); - } - void clear() { - resources_.clear(); - data_.reset(); - } - template - bool is() { - return getVariant().template is(); - } - template - bool is() const { - return getVariant().template is(); - } - bool isNull() const { - return getVariant().isNull(); - } - bool overflowed() const { - return resources_.overflowed(); - } - size_t nesting() const { - return data_.nesting(&resources_); - } - size_t size() const { - return data_.size(&resources_); - } - bool set(const JsonDocument& src) { - return to().set(src.as()); - } - template < - typename T, - detail::enable_if_t::value, int> = 0> - bool set(const T& src) { - return to().set(src); - } - template ::value, int> = 0> - bool set(TChar* src) { - return to().set(src); - } - template - typename detail::VariantTo::type to() { - clear(); - return getVariant().template to(); - } - template - ARDUINOJSON_DEPRECATED("use doc[\"key\"].is() instead") - bool containsKey(TChar* key) const { - return data_.getMember(detail::adaptString(key), &resources_) != 0; - } - template ::value, int> = 0> - ARDUINOJSON_DEPRECATED("use doc[key].is() instead") - bool containsKey(const TString& key) const { - return data_.getMember(detail::adaptString(key), &resources_) != 0; - } - template ::value, int> = 0> - ARDUINOJSON_DEPRECATED("use doc[key].is() instead") - bool containsKey(const TVariant& key) const { - return containsKey(key.template as()); - } - template ::value, int> = 0> - detail::MemberProxy> operator[]( - const TString& key) { - return {*this, detail::adaptString(key)}; - } - template ::value && - !detail::is_const::value, - int> = 0> - detail::MemberProxy> operator[]( - TChar* key) { - return {*this, detail::adaptString(key)}; - } - template ::value, int> = 0> - JsonVariantConst operator[](const TString& key) const { - return JsonVariantConst( - data_.getMember(detail::adaptString(key), &resources_), &resources_); - } - template ::value && - !detail::is_const::value, - int> = 0> - JsonVariantConst operator[](TChar* key) const { - return JsonVariantConst( - data_.getMember(detail::adaptString(key), &resources_), &resources_); - } - template ::value, int> = 0> - detail::ElementProxy operator[](T index) { - return {*this, size_t(index)}; - } - JsonVariantConst operator[](size_t index) const { - return JsonVariantConst(data_.getElement(index, &resources_), &resources_); - } - template ::value, int> = 0> - JsonVariantConst operator[](const TVariant& key) const { - if (key.template is()) - return operator[](key.template as()); - if (key.template is()) - return operator[](key.template as()); - return {}; - } - template ::value, int> = 0> - T add() { - return add().to(); - } - template ::value, int> = 0> - JsonVariant add() { - return JsonVariant(data_.addElement(&resources_), &resources_); - } - template - bool add(const TValue& value) { - return data_.addValue(value, &resources_); - } - template ::value, int> = 0> - bool add(TChar* value) { - return data_.addValue(value, &resources_); - } - template ::value, int> = 0> - void remove(T index) { - detail::VariantData::removeElement(getData(), size_t(index), - getResourceManager()); - } - template ::value && - !detail::is_const::value, - int> = 0> - void remove(TChar* key) { - detail::VariantData::removeMember(getData(), detail::adaptString(key), - getResourceManager()); - } - template ::value, int> = 0> - void remove(const TString& key) { - detail::VariantData::removeMember(getData(), detail::adaptString(key), - getResourceManager()); - } - template ::value, int> = 0> - void remove(const TVariant& key) { - if (key.template is()) - remove(key.template as()); - if (key.template is()) - remove(key.template as()); - } - operator JsonVariant() { - return getVariant(); - } - operator JsonVariantConst() const { - return getVariant(); - } - friend void swap(JsonDocument& a, JsonDocument& b) { - swap(a.resources_, b.resources_); - swap_(a.data_, b.data_); - } - ARDUINOJSON_DEPRECATED("use add() instead") - JsonVariant add() { - return add(); - } - ARDUINOJSON_DEPRECATED("use add() instead") - JsonArray createNestedArray() { - return add(); - } - template - ARDUINOJSON_DEPRECATED("use doc[key].to() instead") - JsonArray createNestedArray(TChar* key) { - return operator[](key).template to(); - } - template - ARDUINOJSON_DEPRECATED("use doc[key].to() instead") - JsonArray createNestedArray(const TString& key) { - return operator[](key).template to(); - } - ARDUINOJSON_DEPRECATED("use add() instead") - JsonObject createNestedObject() { - return add(); - } - template - ARDUINOJSON_DEPRECATED("use doc[key].to() instead") - JsonObject createNestedObject(TChar* key) { - return operator[](key).template to(); - } - template - ARDUINOJSON_DEPRECATED("use doc[key].to() instead") - JsonObject createNestedObject(const TString& key) { - return operator[](key).template to(); - } - ARDUINOJSON_DEPRECATED("always returns zero") - size_t memoryUsage() const { - return 0; - } - private: - JsonVariant getVariant() { - return JsonVariant(&data_, &resources_); - } - JsonVariantConst getVariant() const { - return JsonVariantConst(&data_, &resources_); - } - detail::ResourceManager* getResourceManager() { - return &resources_; - } - detail::VariantData* getData() { - return &data_; - } - const detail::VariantData* getData() const { - return &data_; - } - detail::VariantData* getOrCreateData() { - return &data_; - } - detail::ResourceManager resources_; - detail::VariantData data_; -}; -inline void convertToJson(const JsonDocument& src, JsonVariant dst) { - dst.set(src.as()); -} -ARDUINOJSON_END_PUBLIC_NAMESPACE - -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -template -struct VariantDataVisitor { - using result_type = TResult; - template - TResult visit(const T&) { - return TResult(); - } -}; -template -struct JsonVariantVisitor { - using result_type = TResult; - template - TResult visit(const T&) { - return TResult(); - } -}; -template -class VisitorAdapter { - public: - using result_type = typename TVisitor::result_type; - VisitorAdapter(TVisitor& visitor, const ResourceManager* resources) - : visitor_(&visitor), resources_(resources) {} - result_type visit(const ArrayData& value) { - return visitor_->visit(JsonArrayConst(&value, resources_)); - } - result_type visit(const ObjectData& value) { - return visitor_->visit(JsonObjectConst(&value, resources_)); - } - template - result_type visit(const T& value) { - return visitor_->visit(value); - } - private: - TVisitor* visitor_; - const ResourceManager* resources_; -}; -template -typename TVisitor::result_type accept(JsonVariantConst variant, - TVisitor& visit) { - auto data = VariantAttorney::getData(variant); - if (!data) - return visit.visit(nullptr); - auto resources = VariantAttorney::getResourceManager(variant); - VisitorAdapter adapter(visit, resources); - return data->accept(adapter, resources); -} -struct ComparerBase : JsonVariantVisitor {}; -template -struct Comparer; -template -struct Comparer::value>> : ComparerBase { - T rhs; // TODO: store adapted string? - explicit Comparer(T value) : rhs(value) {} - CompareResult visit(JsonString lhs) { - int i = stringCompare(adaptString(rhs), adaptString(lhs)); - if (i < 0) - return COMPARE_RESULT_GREATER; - else if (i > 0) - return COMPARE_RESULT_LESS; - else - return COMPARE_RESULT_EQUAL; - } - CompareResult visit(nullptr_t) { - if (adaptString(rhs).isNull()) - return COMPARE_RESULT_EQUAL; - else - return COMPARE_RESULT_DIFFER; - } - using ComparerBase::visit; -}; -template -struct Comparer< - T, enable_if_t::value || is_floating_point::value>> - : ComparerBase { - T rhs; - explicit Comparer(T value) : rhs(value) {} - template - enable_if_t::value || is_integral::value, - CompareResult> - visit(const U& lhs) { - return arithmeticCompare(lhs, rhs); - } - template - enable_if_t::value && !is_integral::value, - CompareResult> - visit(const U& lhs) { - return ComparerBase::visit(lhs); - } -}; -struct NullComparer : ComparerBase { - CompareResult visit(nullptr_t) { - return COMPARE_RESULT_EQUAL; - } - using ComparerBase::visit; -}; -template <> -struct Comparer : NullComparer { - explicit Comparer(nullptr_t) : NullComparer() {} -}; -struct ArrayComparer : ComparerBase { - JsonArrayConst rhs_; - explicit ArrayComparer(JsonArrayConst rhs) : rhs_(rhs) {} - CompareResult visit(JsonArrayConst lhs) { - if (rhs_ == lhs) - return COMPARE_RESULT_EQUAL; - else - return COMPARE_RESULT_DIFFER; - } - using ComparerBase::visit; -}; -struct ObjectComparer : ComparerBase { - JsonObjectConst rhs_; - explicit ObjectComparer(JsonObjectConst rhs) : rhs_(rhs) {} - CompareResult visit(JsonObjectConst lhs) { - if (lhs == rhs_) - return COMPARE_RESULT_EQUAL; - else - return COMPARE_RESULT_DIFFER; - } - using ComparerBase::visit; -}; -struct RawComparer : ComparerBase { - RawString rhs_; - explicit RawComparer(RawString rhs) : rhs_(rhs) {} - CompareResult visit(RawString lhs) { - size_t size = rhs_.size() < lhs.size() ? rhs_.size() : lhs.size(); - int n = memcmp(lhs.data(), rhs_.data(), size); - if (n < 0) - return COMPARE_RESULT_LESS; - else if (n > 0) - return COMPARE_RESULT_GREATER; - else - return COMPARE_RESULT_EQUAL; - } - using ComparerBase::visit; -}; -struct VariantComparer : ComparerBase { - JsonVariantConst rhs; - explicit VariantComparer(JsonVariantConst value) : rhs(value) {} - CompareResult visit(JsonArrayConst lhs) { - ArrayComparer comparer(lhs); - return reverseResult(comparer); - } - CompareResult visit(JsonObjectConst lhs) { - ObjectComparer comparer(lhs); - return reverseResult(comparer); - } - CompareResult visit(JsonFloat lhs) { - Comparer comparer(lhs); - return reverseResult(comparer); - } - CompareResult visit(JsonString lhs) { - Comparer comparer(lhs); - return reverseResult(comparer); - } - CompareResult visit(RawString value) { - RawComparer comparer(value); - return reverseResult(comparer); - } - CompareResult visit(JsonInteger lhs) { - Comparer comparer(lhs); - return reverseResult(comparer); - } - CompareResult visit(JsonUInt lhs) { - Comparer comparer(lhs); - return reverseResult(comparer); - } - CompareResult visit(bool lhs) { - Comparer comparer(lhs); - return reverseResult(comparer); - } - CompareResult visit(nullptr_t) { - NullComparer comparer; - return reverseResult(comparer); - } - private: - template - CompareResult reverseResult(TComparer& comparer) { - CompareResult reversedResult = accept(rhs, comparer); - switch (reversedResult) { - case COMPARE_RESULT_GREATER: - return COMPARE_RESULT_LESS; - case COMPARE_RESULT_LESS: - return COMPARE_RESULT_GREATER; - default: - return reversedResult; - } - } -}; -template -struct Comparer< - T, enable_if_t::value>> - : VariantComparer { - explicit Comparer(const T& value) - : VariantComparer(static_cast(value)) {} -}; -template -CompareResult compare(ArduinoJson::JsonVariantConst lhs, const T& rhs) { - Comparer comparer(rhs); - return accept(lhs, comparer); -} -inline ArrayData::iterator ArrayData::at( - size_t index, const ResourceManager* resources) const { - auto it = createIterator(resources); - while (!it.done() && index) { - it.next(resources); - --index; - } - return it; -} -inline VariantData* ArrayData::addElement(ResourceManager* resources) { - auto slot = resources->allocVariant(); - if (!slot) - return nullptr; - CollectionData::appendOne(slot, resources); - return slot.ptr(); -} -inline VariantData* ArrayData::getOrAddElement(size_t index, - ResourceManager* resources) { - auto it = createIterator(resources); - while (!it.done() && index > 0) { - it.next(resources); - index--; - } - if (it.done()) - index++; - VariantData* element = it.data(); - while (index > 0) { - element = addElement(resources); - if (!element) - return nullptr; - index--; - } - return element; -} -inline VariantData* ArrayData::getElement( - size_t index, const ResourceManager* resources) const { - return at(index, resources).data(); -} -inline void ArrayData::removeElement(size_t index, ResourceManager* resources) { - remove(at(index, resources), resources); -} -template -inline bool ArrayData::addValue(const T& value, ResourceManager* resources) { - ARDUINOJSON_ASSERT(resources != nullptr); - auto slot = resources->allocVariant(); - if (!slot) - return false; - JsonVariant variant(slot.ptr(), resources); - if (!variant.set(value)) { - resources->freeVariant(slot); - return false; - } - CollectionData::appendOne(slot, resources); - return true; -} -constexpr size_t sizeofArray(size_t n) { - return n * ResourceManager::slotSize; -} -ARDUINOJSON_END_PRIVATE_NAMESPACE -ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE -template ::value, int> = 0> -inline bool copyArray(const T& src, JsonVariant dst) { - return dst.set(src); -} -template ::value, int> = 0> -inline bool copyArray(T (&src)[N], const TDestination& dst) { - return copyArray(src, N, dst); -} -template ::value, int> = 0> -inline bool copyArray(const T* src, size_t len, const TDestination& dst) { - bool ok = true; - for (size_t i = 0; i < len; i++) { - ok &= copyArray(src[i], dst.template add()); - } - return ok; -} -template -inline bool copyArray(const char* src, size_t, const TDestination& dst) { - return dst.set(src); -} -template -inline bool copyArray(const T& src, JsonDocument& dst) { - return copyArray(src, dst.to()); -} -template -inline bool copyArray(const T* src, size_t len, JsonDocument& dst) { - return copyArray(src, len, dst.to()); -} -template ::value, int> = 0> -inline size_t copyArray(JsonVariantConst src, T& dst) { - dst = src.as(); - return 1; -} -template -inline size_t copyArray(JsonArrayConst src, T (&dst)[N]) { - return copyArray(src, dst, N); -} -template -inline size_t copyArray(JsonArrayConst src, T* dst, size_t len) { - size_t i = 0; - for (JsonArrayConst::iterator it = src.begin(); it != src.end() && i < len; - ++it) - copyArray(*it, dst[i++]); - return i; -} -template -inline size_t copyArray(JsonVariantConst src, char (&dst)[N]) { - JsonString s = src; - size_t len = N - 1; - if (len > s.size()) - len = s.size(); - memcpy(dst, s.c_str(), len); - dst[len] = 0; - return 1; -} -template < - typename TSource, typename T, - detail::enable_if_t::value && - detail::is_base_of::value, - int> = 0> -inline size_t copyArray(const TSource& src, T& dst) { - return copyArray(src.template as(), dst); -} -ARDUINOJSON_END_PUBLIC_NAMESPACE -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -#if ARDUINOJSON_ENABLE_ALIGNMENT -inline bool isAligned(size_t value) { - const size_t mask = sizeof(void*) - 1; - size_t addr = value; - return (addr & mask) == 0; -} -inline size_t addPadding(size_t bytes) { - const size_t mask = sizeof(void*) - 1; - return (bytes + mask) & ~mask; -} -template -struct AddPadding { - static const size_t mask = sizeof(void*) - 1; - static const size_t value = (bytes + mask) & ~mask; -}; -#else -inline bool isAligned(size_t) { - return true; -} -inline size_t addPadding(size_t bytes) { - return bytes; -} -template -struct AddPadding { - static const size_t value = bytes; -}; -#endif -template -inline bool isAligned(T* ptr) { - return isAligned(reinterpret_cast(ptr)); -} -template -inline T* addPadding(T* p) { - size_t address = addPadding(reinterpret_cast(p)); - return reinterpret_cast(address); -} -inline CollectionIterator::CollectionIterator(VariantData* slot, SlotId slotId) - : slot_(slot), currentId_(slotId) { - nextId_ = slot_ ? slot_->next() : NULL_SLOT; -} -inline void CollectionIterator::next(const ResourceManager* resources) { - ARDUINOJSON_ASSERT(currentId_ != NULL_SLOT); - slot_ = resources->getVariant(nextId_); - currentId_ = nextId_; - if (slot_) - nextId_ = slot_->next(); -} -inline CollectionData::iterator CollectionData::createIterator( - const ResourceManager* resources) const { - return iterator(resources->getVariant(head_), head_); -} -inline void CollectionData::appendOne(Slot slot, - const ResourceManager* resources) { - if (tail_ != NULL_SLOT) { - auto tail = resources->getVariant(tail_); - tail->setNext(slot.id()); - tail_ = slot.id(); - } else { - head_ = slot.id(); - tail_ = slot.id(); - } -} -inline void CollectionData::appendPair(Slot key, - Slot value, - const ResourceManager* resources) { - key->setNext(value.id()); - if (tail_ != NULL_SLOT) { - auto tail = resources->getVariant(tail_); - tail->setNext(key.id()); - tail_ = value.id(); - } else { - head_ = key.id(); - tail_ = value.id(); - } -} -inline void CollectionData::clear(ResourceManager* resources) { - auto next = head_; - while (next != NULL_SLOT) { - auto currId = next; - auto slot = resources->getVariant(next); - next = slot->next(); - resources->freeVariant({slot, currId}); - } - head_ = NULL_SLOT; - tail_ = NULL_SLOT; -} -inline Slot CollectionData::getPreviousSlot( - VariantData* target, const ResourceManager* resources) const { - auto prev = Slot(); - auto currentId = head_; - while (currentId != NULL_SLOT) { - auto currentSlot = resources->getVariant(currentId); - if (currentSlot == target) - break; - prev = Slot(currentSlot, currentId); - currentId = currentSlot->next(); - } - return prev; -} -inline void CollectionData::removeOne(iterator it, ResourceManager* resources) { - if (it.done()) - return; - auto curr = it.slot_; - auto prev = getPreviousSlot(curr, resources); - auto next = curr->next(); - if (prev) - prev->setNext(next); - else - head_ = next; - if (next == NULL_SLOT) - tail_ = prev.id(); - resources->freeVariant({it.slot_, it.currentId_}); -} -inline void CollectionData::removePair(ObjectData::iterator it, - ResourceManager* resources) { - if (it.done()) - return; - auto keySlot = it.slot_; - auto valueId = it.nextId_; - auto valueSlot = resources->getVariant(valueId); - keySlot->setNext(valueSlot->next()); - resources->freeVariant({valueSlot, valueId}); - removeOne(it, resources); -} -inline size_t CollectionData::nesting(const ResourceManager* resources) const { - size_t maxChildNesting = 0; - for (auto it = createIterator(resources); !it.done(); it.next(resources)) { - size_t childNesting = it->nesting(resources); - if (childNesting > maxChildNesting) - maxChildNesting = childNesting; - } - return maxChildNesting + 1; -} -inline size_t CollectionData::size(const ResourceManager* resources) const { - size_t count = 0; - for (auto it = createIterator(resources); !it.done(); it.next(resources)) - count++; - return count; -} -inline Slot ResourceManager::allocVariant() { - auto p = variantPools_.allocSlot(allocator_); - if (!p) { - overflowed_ = true; - return {}; - } - return {new (&p->variant) VariantData, p.id()}; -} -inline void ResourceManager::freeVariant(Slot variant) { - variant->clear(this); - variantPools_.freeSlot({alias_cast(variant.ptr()), variant.id()}); -} -inline VariantData* ResourceManager::getVariant(SlotId id) const { - return reinterpret_cast(variantPools_.getSlot(id)); -} -#if ARDUINOJSON_USE_EXTENSIONS -inline Slot ResourceManager::allocExtension() { - auto p = variantPools_.allocSlot(allocator_); - if (!p) { - overflowed_ = true; - return {}; - } - return {&p->extension, p.id()}; -} -inline void ResourceManager::freeExtension(SlotId id) { - auto p = getExtension(id); - variantPools_.freeSlot({reinterpret_cast(p), id}); -} -inline VariantExtension* ResourceManager::getExtension(SlotId id) const { - return &variantPools_.getSlot(id)->extension; -} -#endif -template -inline VariantData* ObjectData::getMember( - TAdaptedString key, const ResourceManager* resources) const { - auto it = findKey(key, resources); - if (it.done()) - return nullptr; - it.next(resources); - return it.data(); -} -template -VariantData* ObjectData::getOrAddMember(TAdaptedString key, - ResourceManager* resources) { - auto data = getMember(key, resources); - if (data) - return data; - return addMember(key, resources); -} -template -inline ObjectData::iterator ObjectData::findKey( - TAdaptedString key, const ResourceManager* resources) const { - if (key.isNull()) - return iterator(); - bool isKey = true; - for (auto it = createIterator(resources); !it.done(); it.next(resources)) { - if (isKey && stringEquals(key, adaptString(it->asString()))) - return it; - isKey = !isKey; - } - return iterator(); -} -template -inline void ObjectData::removeMember(TAdaptedString key, - ResourceManager* resources) { - remove(findKey(key, resources), resources); -} -template -inline VariantData* ObjectData::addMember(TAdaptedString key, - ResourceManager* resources) { - auto keySlot = resources->allocVariant(); - if (!keySlot) - return nullptr; - auto valueSlot = resources->allocVariant(); - if (!valueSlot) - return nullptr; - if (!keySlot->setString(key, resources)) - return nullptr; - CollectionData::appendPair(keySlot, valueSlot, resources); - return valueSlot.ptr(); -} -inline VariantData* ObjectData::addPair(VariantData** value, - ResourceManager* resources) { - auto keySlot = resources->allocVariant(); - if (!keySlot) - return nullptr; - auto valueSlot = resources->allocVariant(); - if (!valueSlot) - return nullptr; - *value = valueSlot.ptr(); - CollectionData::appendPair(keySlot, valueSlot, resources); - return keySlot.ptr(); -} -constexpr size_t sizeofObject(size_t n) { - return 2 * n * ResourceManager::slotSize; -} -class EscapeSequence { - public: - static char escapeChar(char c) { - const char* p = escapeTable(true); - while (p[0] && p[1] != c) { - p += 2; - } - return p[0]; - } - static char unescapeChar(char c) { - const char* p = escapeTable(false); - for (;;) { - if (p[0] == '\0') - return 0; - if (p[0] == c) - return p[1]; - p += 2; - } - } - private: - static const char* escapeTable(bool isSerializing) { - return &"//''\"\"\\\\b\bf\fn\nr\rt\t"[isSerializing ? 4 : 0]; - } -}; -struct FloatParts { - uint32_t integral; - uint32_t decimal; - int16_t exponent; - int8_t decimalPlaces; -}; -template -inline int16_t normalize(TFloat& value) { - using traits = FloatTraits; - int16_t powersOf10 = 0; - int8_t index = sizeof(TFloat) == 8 ? 8 : 5; - int bit = 1 << index; - if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) { - for (; index >= 0; index--) { - if (value >= traits::positiveBinaryPowersOfTen()[index]) { - value *= traits::negativeBinaryPowersOfTen()[index]; - powersOf10 = int16_t(powersOf10 + bit); - } - bit >>= 1; - } - } - if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) { - for (; index >= 0; index--) { - if (value < traits::negativeBinaryPowersOfTen()[index] * 10) { - value *= traits::positiveBinaryPowersOfTen()[index]; - powersOf10 = int16_t(powersOf10 - bit); - } - bit >>= 1; - } - } - return powersOf10; -} -constexpr uint32_t pow10(int exponent) { - return (exponent == 0) ? 1 : 10 * pow10(exponent - 1); -} -inline FloatParts decomposeFloat(JsonFloat value, int8_t decimalPlaces) { - uint32_t maxDecimalPart = pow10(decimalPlaces); - int16_t exponent = normalize(value); - uint32_t integral = uint32_t(value); - for (uint32_t tmp = integral; tmp >= 10; tmp /= 10) { - maxDecimalPart /= 10; - decimalPlaces--; - } - JsonFloat remainder = - (value - JsonFloat(integral)) * JsonFloat(maxDecimalPart); - uint32_t decimal = uint32_t(remainder); - remainder = remainder - JsonFloat(decimal); - decimal += uint32_t(remainder * 2); - if (decimal >= maxDecimalPart) { - decimal = 0; - integral++; - if (exponent && integral >= 10) { - exponent++; - integral = 1; - } - } - while (decimal % 10 == 0 && decimalPlaces > 0) { - decimal /= 10; - decimalPlaces--; - } - return {integral, decimal, exponent, decimalPlaces}; -} -template -class CountingDecorator { - public: - explicit CountingDecorator(TWriter& writer) : writer_(writer), count_(0) {} - void write(uint8_t c) { - count_ += writer_.write(c); - } - void write(const uint8_t* s, size_t n) { - count_ += writer_.write(s, n); - } - size_t count() const { - return count_; - } - private: - TWriter writer_; - size_t count_; -}; -template -class TextFormatter { - public: - explicit TextFormatter(TWriter writer) : writer_(writer) {} - TextFormatter& operator=(const TextFormatter&) = delete; - size_t bytesWritten() const { - return writer_.count(); - } - void writeBoolean(bool value) { - if (value) - writeRaw("true"); - else - writeRaw("false"); - } - void writeString(const char* value) { - ARDUINOJSON_ASSERT(value != NULL); - writeRaw('\"'); - while (*value) - writeChar(*value++); - writeRaw('\"'); - } - void writeString(const char* value, size_t n) { - ARDUINOJSON_ASSERT(value != NULL); - writeRaw('\"'); - while (n--) - writeChar(*value++); - writeRaw('\"'); - } - void writeChar(char c) { - char specialChar = EscapeSequence::escapeChar(c); - if (specialChar) { - writeRaw('\\'); - writeRaw(specialChar); - } else if (c) { - writeRaw(c); - } else { - writeRaw("\\u0000"); - } - } - template - void writeFloat(T value) { - writeFloat(JsonFloat(value), sizeof(T) >= 8 ? 9 : 6); - } - void writeFloat(JsonFloat value, int8_t decimalPlaces) { - if (isnan(value)) - return writeRaw(ARDUINOJSON_ENABLE_NAN ? "NaN" : "null"); -#if ARDUINOJSON_ENABLE_INFINITY - if (value < 0.0) { - writeRaw('-'); - value = -value; - } - if (isinf(value)) - return writeRaw("Infinity"); -#else - if (isinf(value)) - return writeRaw("null"); - if (value < 0.0) { - writeRaw('-'); - value = -value; - } -#endif - auto parts = decomposeFloat(value, decimalPlaces); - writeInteger(parts.integral); - if (parts.decimalPlaces) - writeDecimals(parts.decimal, parts.decimalPlaces); - if (parts.exponent) { - writeRaw('e'); - writeInteger(parts.exponent); - } - } - template - enable_if_t::value> writeInteger(T value) { - using unsigned_type = make_unsigned_t; - unsigned_type unsigned_value; - if (value < 0) { - writeRaw('-'); - unsigned_value = unsigned_type(unsigned_type(~value) + 1); - } else { - unsigned_value = unsigned_type(value); - } - writeInteger(unsigned_value); - } - template - enable_if_t::value> writeInteger(T value) { - char buffer[22]; - char* end = buffer + sizeof(buffer); - char* begin = end; - do { - *--begin = char(value % 10 + '0'); - value = T(value / 10); - } while (value); - writeRaw(begin, end); - } - void writeDecimals(uint32_t value, int8_t width) { - char buffer[16]; - char* end = buffer + sizeof(buffer); - char* begin = end; - while (width--) { - *--begin = char(value % 10 + '0'); - value /= 10; - } - *--begin = '.'; - writeRaw(begin, end); - } - void writeRaw(const char* s) { - writer_.write(reinterpret_cast(s), strlen(s)); - } - void writeRaw(const char* s, size_t n) { - writer_.write(reinterpret_cast(s), n); - } - void writeRaw(const char* begin, const char* end) { - writer_.write(reinterpret_cast(begin), - static_cast(end - begin)); - } - template - void writeRaw(const char (&s)[N]) { - writer_.write(reinterpret_cast(s), N - 1); - } - void writeRaw(char c) { - writer_.write(static_cast(c)); - } - protected: - CountingDecorator writer_; -}; -class DummyWriter { - public: - size_t write(uint8_t) { - return 1; - } - size_t write(const uint8_t*, size_t n) { - return n; - } -}; -template