diff options
Diffstat (limited to 'include/lib/ArduinoJson/Variant')
-rw-r--r-- | include/lib/ArduinoJson/Variant/Converter.hpp | 12 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Variant/ConverterImpl.hpp | 268 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Variant/SlotFunctions.hpp | 60 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Variant/VariantCompare.hpp | 208 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Variant/VariantContent.hpp | 59 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Variant/VariantData.hpp | 368 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Variant/VariantFunctions.hpp | 104 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Variant/VariantImpl.hpp | 143 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Variant/VariantOperators.hpp | 180 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Variant/VariantRef.hpp | 375 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Variant/VariantShortcuts.hpp | 23 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Variant/VariantSlot.hpp | 116 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Variant/VariantTag.hpp | 16 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Variant/VariantTo.hpp | 32 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Variant/Visitor.hpp | 54 |
15 files changed, 2018 insertions, 0 deletions
diff --git a/include/lib/ArduinoJson/Variant/Converter.hpp b/include/lib/ArduinoJson/Variant/Converter.hpp new file mode 100644 index 0000000..476ca8f --- /dev/null +++ b/include/lib/ArduinoJson/Variant/Converter.hpp @@ -0,0 +1,12 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +namespace ARDUINOJSON_NAMESPACE { + +template <typename T, typename Enable = void> +struct Converter; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/ConverterImpl.hpp b/include/lib/ArduinoJson/Variant/ConverterImpl.hpp new file mode 100644 index 0000000..34e12bb --- /dev/null +++ b/include/lib/ArduinoJson/Variant/ConverterImpl.hpp @@ -0,0 +1,268 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Strings/IsWriteableString.hpp> +#include <ArduinoJson/Variant/VariantFunctions.hpp> +#include <ArduinoJson/Variant/VariantRef.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename T, typename Enable> +struct Converter { + static bool toJson(const T& src, VariantRef dst) { + // clang-format off + return convertToJson(src, dst); // Error here? See https://arduinojson.org/v6/unsupported-set/ + // clang-format on + } + + static T fromJson(VariantConstRef src) { + // clang-format off + T result; // Error here? See https://arduinojson.org/v6/non-default-constructible/ + convertFromJson(src, result); // Error here? See https://arduinojson.org/v6/unsupported-as/ + // clang-format on + return result; + } + + static bool checkJson(VariantConstRef src) { + T dummy; + // clang-format off + return canConvertFromJson(src, dummy); // Error here? See https://arduinojson.org/v6/unsupported-is/ + // clang-format on + } +}; + +template <typename T> +struct Converter< + T, typename enable_if<is_integral<T>::value && !is_same<bool, T>::value && + !is_same<char, T>::value>::type> { + static bool toJson(T src, VariantRef dst) { + VariantData* data = getData(dst); + ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); + if (!data) + return false; + data->setInteger(src); + return true; + } + + static T fromJson(VariantConstRef src) { + ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); + const VariantData* data = getData(src); + return data ? data->asIntegral<T>() : T(); + } + + static bool checkJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data && data->isInteger<T>(); + } +}; + +template <typename T> +struct Converter<T, typename enable_if<is_enum<T>::value>::type> { + static bool toJson(T src, VariantRef dst) { + return dst.set(static_cast<Integer>(src)); + } + + static T fromJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data ? static_cast<T>(data->asIntegral<int>()) : T(); + } + + static bool checkJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data && data->isInteger<int>(); + } +}; + +template <> +struct Converter<bool> { + static bool toJson(bool src, VariantRef dst) { + VariantData* data = getData(dst); + if (!data) + return false; + data->setBoolean(src); + return true; + } + + static bool fromJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data ? data->asBoolean() : false; + } + + static bool checkJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data && data->isBoolean(); + } +}; + +template <typename T> +struct Converter<T, typename enable_if<is_floating_point<T>::value>::type> { + static bool toJson(T src, VariantRef dst) { + VariantData* data = getData(dst); + if (!data) + return false; + data->setFloat(static_cast<Float>(src)); + return true; + } + + static T fromJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data ? data->asFloat<T>() : false; + } + + static bool checkJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data && data->isFloat(); + } +}; + +template <> +struct Converter<const char*> { + static bool toJson(const char* src, VariantRef dst) { + return variantSetString(getData(dst), adaptString(src), getPool(dst)); + } + + static const char* fromJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data ? data->asString() : 0; + } + + static bool checkJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data && data->isString(); + } +}; + +template <typename T> +inline typename enable_if<IsString<T>::value, bool>::type convertToJson( + const T& src, VariantRef dst) { + VariantData* data = getData(dst); + MemoryPool* pool = getPool(dst); + return variantSetString(data, adaptString(src), pool); +} + +template <typename T> +inline typename enable_if<IsWriteableString<T>::value>::type convertFromJson( + VariantConstRef src, T& dst) { + const VariantData* data = getData(src); + const char* cstr = data != 0 ? data->asString() : 0; + if (cstr) + dst = cstr; + else + serializeJson(src, dst); +} + +template <typename T> +inline typename enable_if<IsWriteableString<T>::value, bool>::type +canConvertFromJson(VariantConstRef src, const T&) { + const VariantData* data = getData(src); + return data && data->isString(); +} + +template <> +struct Converter<SerializedValue<const char*> > { + static bool toJson(SerializedValue<const char*> src, VariantRef dst) { + VariantData* data = getData(dst); + if (!data) + return false; + data->setLinkedRaw(src); + return true; + } +}; + +// SerializedValue<std::string> +// SerializedValue<String> +// SerializedValue<const __FlashStringHelper*> +template <typename T> +struct Converter<SerializedValue<T>, + typename enable_if<!is_same<const char*, T>::value>::type> { + static bool toJson(SerializedValue<T> src, VariantRef dst) { + VariantData* data = getData(dst); + MemoryPool* pool = getPool(dst); + return data != 0 && data->setOwnedRaw(src, pool); + } +}; + +#if ARDUINOJSON_HAS_NULLPTR + +template <> +struct Converter<decltype(nullptr)> { + static bool toJson(decltype(nullptr), VariantRef dst) { + variantSetNull(getData(dst)); + return true; + } + static decltype(nullptr) fromJson(VariantConstRef) { + return nullptr; + } + static bool checkJson(VariantConstRef src) { + const VariantData* data = getData(src); + return data == 0 || data->isNull(); + } +}; + +#endif + +#if ARDUINOJSON_ENABLE_ARDUINO_STREAM + +class MemoryPoolPrint : public Print { + public: + MemoryPoolPrint(MemoryPool* pool) : _pool(pool), _size(0) { + pool->getFreeZone(&_string, &_capacity); + } + + const char* c_str() { + _string[_size++] = 0; + ARDUINOJSON_ASSERT(_size <= _capacity); + return _pool->saveStringFromFreeZone(_size); + } + + size_t write(uint8_t c) { + if (_size >= _capacity) + return 0; + + _string[_size++] = char(c); + return 1; + } + + size_t write(const uint8_t* buffer, size_t size) { + if (_size + size >= _capacity) { + _size = _capacity; // mark as overflowed + return 0; + } + memcpy(&_string[_size], buffer, size); + _size += size; + return size; + } + + bool overflowed() const { + return _size >= _capacity; + } + + private: + MemoryPool* _pool; + size_t _size; + char* _string; + size_t _capacity; +}; + +inline bool convertToJson(const ::Printable& src, VariantRef dst) { + MemoryPool* pool = getPool(dst); + VariantData* data = getData(dst); + if (!pool || !data) + return false; + MemoryPoolPrint print(pool); + src.printTo(print); + if (print.overflowed()) { + pool->markAsOverflowed(); + data->setNull(); + return false; + } + data->setStringPointer(print.c_str(), storage_policies::store_by_copy()); + return true; +} + +#endif + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/SlotFunctions.hpp b/include/lib/ArduinoJson/Variant/SlotFunctions.hpp new file mode 100644 index 0000000..74ac5a7 --- /dev/null +++ b/include/lib/ArduinoJson/Variant/SlotFunctions.hpp @@ -0,0 +1,60 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/assert.hpp> +#include <ArduinoJson/Variant/VariantData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TAdaptedString> +inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool) { + if (!var) + return false; + return slotSetKey(var, key, pool, typename TAdaptedString::storage_policy()); +} + +template <typename TAdaptedString> +inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool, + storage_policies::decide_at_runtime) { + if (key.isStatic()) { + return slotSetKey(var, key, pool, storage_policies::store_by_address()); + } else { + return slotSetKey(var, key, pool, storage_policies::store_by_copy()); + } +} + +template <typename TAdaptedString> +inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool*, + storage_policies::store_by_address) { + ARDUINOJSON_ASSERT(var); + var->setKey(key.data(), storage_policies::store_by_address()); + return true; +} + +template <typename TAdaptedString> +inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool, + storage_policies::store_by_copy) { + const char* dup = pool->saveString(key); + if (!dup) + return false; + ARDUINOJSON_ASSERT(var); + var->setKey(dup, storage_policies::store_by_copy()); + return true; +} + +inline size_t slotSize(const VariantSlot* var) { + size_t n = 0; + while (var) { + n++; + var = var->next(); + } + return n; +} + +inline VariantData* slotData(VariantSlot* slot) { + return reinterpret_cast<VariantData*>(slot); +} +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/VariantCompare.hpp b/include/lib/ArduinoJson/Variant/VariantCompare.hpp new file mode 100644 index 0000000..025ef90 --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantCompare.hpp @@ -0,0 +1,208 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Misc/Visitable.hpp> +#include <ArduinoJson/Numbers/arithmeticCompare.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Strings/IsString.hpp> +#include <ArduinoJson/Variant/Visitor.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +class CollectionData; + +struct ComparerBase : Visitor<CompareResult> {}; + +template <typename T, typename Enable = void> +struct Comparer; + +template <typename T> +struct Comparer<T, typename enable_if<IsString<T>::value>::type> + : ComparerBase { + T rhs; + + explicit Comparer(T value) : rhs(value) {} + + CompareResult visitString(const char *lhs) { + int i = adaptString(rhs).compare(lhs); + if (i < 0) + return COMPARE_RESULT_GREATER; + else if (i > 0) + return COMPARE_RESULT_LESS; + else + return COMPARE_RESULT_EQUAL; + } + + CompareResult visitNull() { + if (adaptString(rhs).isNull()) + return COMPARE_RESULT_EQUAL; + else + return COMPARE_RESULT_DIFFER; + } +}; + +template <typename T> +struct Comparer<T, typename enable_if<is_integral<T>::value || + is_floating_point<T>::value>::type> + : ComparerBase { + T rhs; + + explicit Comparer(T value) : rhs(value) {} + + CompareResult visitFloat(Float lhs) { + return arithmeticCompare(lhs, rhs); + } + + CompareResult visitSignedInteger(Integer lhs) { + return arithmeticCompare(lhs, rhs); + } + + CompareResult visitUnsignedInteger(UInt lhs) { + return arithmeticCompare(lhs, rhs); + } + + CompareResult visitBoolean(bool lhs) { + return visitUnsignedInteger(static_cast<UInt>(lhs)); + } +}; + +struct NullComparer : ComparerBase { + CompareResult visitNull() { + return COMPARE_RESULT_EQUAL; + } +}; + +#if ARDUINOJSON_HAS_NULLPTR +template <> +struct Comparer<decltype(nullptr), void> : NullComparer { + explicit Comparer(decltype(nullptr)) : NullComparer() {} +}; +#endif + +struct ArrayComparer : ComparerBase { + const CollectionData *_rhs; + + explicit ArrayComparer(const CollectionData &rhs) : _rhs(&rhs) {} + + CompareResult visitArray(const CollectionData &lhs) { + if (lhs.equalsArray(*_rhs)) + return COMPARE_RESULT_EQUAL; + else + return COMPARE_RESULT_DIFFER; + } +}; + +struct ObjectComparer : ComparerBase { + const CollectionData *_rhs; + + explicit ObjectComparer(const CollectionData &rhs) : _rhs(&rhs) {} + + CompareResult visitObject(const CollectionData &lhs) { + if (lhs.equalsObject(*_rhs)) + return COMPARE_RESULT_EQUAL; + else + return COMPARE_RESULT_DIFFER; + } +}; + +struct RawComparer : ComparerBase { + const char *_rhsData; + size_t _rhsSize; + + explicit RawComparer(const char *rhsData, size_t rhsSize) + : _rhsData(rhsData), _rhsSize(rhsSize) {} + + CompareResult visitRawJson(const char *lhsData, size_t lhsSize) { + size_t size = _rhsSize < lhsSize ? _rhsSize : lhsSize; + int n = memcmp(lhsData, _rhsData, size); + if (n < 0) + return COMPARE_RESULT_LESS; + else if (n > 0) + return COMPARE_RESULT_GREATER; + else + return COMPARE_RESULT_EQUAL; + } +}; + +template <typename T> +struct Comparer<T, typename enable_if<IsVisitable<T>::value>::type> + : ComparerBase { + T rhs; + + explicit Comparer(T value) : rhs(value) {} + + CompareResult visitArray(const CollectionData &lhs) { + ArrayComparer comparer(lhs); + return accept(comparer); + } + + CompareResult visitObject(const CollectionData &lhs) { + ObjectComparer comparer(lhs); + return accept(comparer); + } + + CompareResult visitFloat(Float lhs) { + Comparer<Float> comparer(lhs); + return accept(comparer); + } + + CompareResult visitString(const char *lhs) { + Comparer<const char *> comparer(lhs); + return accept(comparer); + } + + CompareResult visitRawJson(const char *lhsData, size_t lhsSize) { + RawComparer comparer(lhsData, lhsSize); + return accept(comparer); + } + + CompareResult visitSignedInteger(Integer lhs) { + Comparer<Integer> comparer(lhs); + return accept(comparer); + } + + CompareResult visitUnsignedInteger(UInt lhs) { + Comparer<UInt> comparer(lhs); + return accept(comparer); + } + + CompareResult visitBoolean(bool lhs) { + Comparer<bool> comparer(lhs); + return accept(comparer); + } + + CompareResult visitNull() { + NullComparer comparer; + return accept(comparer); + } + + private: + template <typename TComparer> + CompareResult accept(TComparer &comparer) { + CompareResult reversedResult = rhs.accept(comparer); + switch (reversedResult) { + case COMPARE_RESULT_GREATER: + return COMPARE_RESULT_LESS; + case COMPARE_RESULT_LESS: + return COMPARE_RESULT_GREATER; + default: + return reversedResult; + } + } +}; + +template <typename T1, typename T2> +CompareResult compare(const T1 &lhs, const T2 &rhs) { + Comparer<T2> comparer(rhs); + return lhs.accept(comparer); +} + +inline int variantCompare(const VariantData *a, const VariantData *b) { + return compare(VariantConstRef(a), VariantConstRef(b)); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/VariantContent.hpp b/include/lib/ArduinoJson/Variant/VariantContent.hpp new file mode 100644 index 0000000..47bf09c --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantContent.hpp @@ -0,0 +1,59 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <stddef.h> // size_t + +#include <ArduinoJson/Collection/CollectionData.hpp> +#include <ArduinoJson/Numbers/Float.hpp> +#include <ArduinoJson/Numbers/Integer.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +// +enum { + VALUE_MASK = 0x7F, + + OWNED_VALUE_BIT = 0x01, + VALUE_IS_NULL = 0, + VALUE_IS_LINKED_RAW = 0x02, + VALUE_IS_OWNED_RAW = 0x03, + VALUE_IS_LINKED_STRING = 0x04, + VALUE_IS_OWNED_STRING = 0x05, + + // CAUTION: no OWNED_VALUE_BIT below + + VALUE_IS_BOOLEAN = 0x06, + + NUMBER_BIT = 0x08, + VALUE_IS_UNSIGNED_INTEGER = 0x08, + VALUE_IS_SIGNED_INTEGER = 0x0A, + VALUE_IS_FLOAT = 0x0C, + + COLLECTION_MASK = 0x60, + VALUE_IS_OBJECT = 0x20, + VALUE_IS_ARRAY = 0x40, + + OWNED_KEY_BIT = 0x80 +}; + +struct RawData { + const char *data; + size_t size; +}; + +union VariantContent { + Float asFloat; + bool asBoolean; + UInt asUnsignedInteger; + Integer asSignedInteger; + CollectionData asCollection; + const char *asString; + struct { + const char *data; + size_t size; + } asRaw; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/VariantData.hpp b/include/lib/ArduinoJson/Variant/VariantData.hpp new file mode 100644 index 0000000..82ae745 --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantData.hpp @@ -0,0 +1,368 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Memory/MemoryPool.hpp> +#include <ArduinoJson/Misc/SerializedValue.hpp> +#include <ArduinoJson/Numbers/convertNumber.hpp> +#include <ArduinoJson/Strings/RamStringAdapter.hpp> +#include <ArduinoJson/Variant/VariantContent.hpp> + +// VariantData can't have a constructor (to be a POD), so we have no way to fix +// this warning +#if defined(__GNUC__) +#if __GNUC__ >= 7 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#pragma GCC diagnostic ignored "-Wuninitialized" +#endif +#endif + +namespace ARDUINOJSON_NAMESPACE { + +class VariantData { + VariantContent _content; // must be first to allow cast from array to variant + uint8_t _flags; + + public: + // Must be a POD! + // - no constructor + // - no destructor + // - no virtual + // - no inheritance + void init() { + _flags = 0; + } + + template <typename TVisitor> + typename TVisitor::result_type accept(TVisitor &visitor) const { + switch (type()) { + case VALUE_IS_FLOAT: + return visitor.visitFloat(_content.asFloat); + + case VALUE_IS_ARRAY: + return visitor.visitArray(_content.asCollection); + + case VALUE_IS_OBJECT: + return visitor.visitObject(_content.asCollection); + + case VALUE_IS_LINKED_STRING: + case VALUE_IS_OWNED_STRING: + return visitor.visitString(_content.asString); + + case VALUE_IS_OWNED_RAW: + case VALUE_IS_LINKED_RAW: + return visitor.visitRawJson(_content.asRaw.data, _content.asRaw.size); + + case VALUE_IS_SIGNED_INTEGER: + return visitor.visitSignedInteger(_content.asSignedInteger); + + case VALUE_IS_UNSIGNED_INTEGER: + return visitor.visitUnsignedInteger(_content.asUnsignedInteger); + + case VALUE_IS_BOOLEAN: + return visitor.visitBoolean(_content.asBoolean != 0); + + default: + return visitor.visitNull(); + } + } + + template <typename T> + T asIntegral() const; + + template <typename T> + T asFloat() const; + + const char *asString() const; + + bool asBoolean() const; + + CollectionData *asArray() { + return isArray() ? &_content.asCollection : 0; + } + + const CollectionData *asArray() const { + return const_cast<VariantData *>(this)->asArray(); + } + + CollectionData *asObject() { + return isObject() ? &_content.asCollection : 0; + } + + const CollectionData *asObject() const { + return const_cast<VariantData *>(this)->asObject(); + } + + bool copyFrom(const VariantData &src, MemoryPool *pool) { + switch (src.type()) { + case VALUE_IS_ARRAY: + return toArray().copyFrom(src._content.asCollection, pool); + case VALUE_IS_OBJECT: + return toObject().copyFrom(src._content.asCollection, pool); + case VALUE_IS_OWNED_STRING: + return setString(RamStringAdapter(src._content.asString), pool); + case VALUE_IS_OWNED_RAW: + return setOwnedRaw( + serialized(src._content.asRaw.data, src._content.asRaw.size), pool); + default: + setType(src.type()); + _content = src._content; + return true; + } + } + + bool isArray() const { + return (_flags & VALUE_IS_ARRAY) != 0; + } + + bool isBoolean() const { + return type() == VALUE_IS_BOOLEAN; + } + + bool isCollection() const { + return (_flags & COLLECTION_MASK) != 0; + } + + template <typename T> + bool isInteger() const { + switch (type()) { + case VALUE_IS_UNSIGNED_INTEGER: + return canConvertNumber<T>(_content.asUnsignedInteger); + + case VALUE_IS_SIGNED_INTEGER: + return canConvertNumber<T>(_content.asSignedInteger); + + default: + return false; + } + } + + bool isFloat() const { + return (_flags & NUMBER_BIT) != 0; + } + + bool isString() const { + return type() == VALUE_IS_LINKED_STRING || type() == VALUE_IS_OWNED_STRING; + } + + bool isObject() const { + return (_flags & VALUE_IS_OBJECT) != 0; + } + + bool isNull() const { + return type() == VALUE_IS_NULL; + } + + bool isEnclosed() const { + return !isFloat(); + } + + void remove(size_t index) { + if (isArray()) + _content.asCollection.removeElement(index); + } + + template <typename TAdaptedString> + void remove(TAdaptedString key) { + if (isObject()) + _content.asCollection.removeMember(key); + } + + void setBoolean(bool value) { + setType(VALUE_IS_BOOLEAN); + _content.asBoolean = value; + } + + void setFloat(Float value) { + setType(VALUE_IS_FLOAT); + _content.asFloat = value; + } + + void setLinkedRaw(SerializedValue<const char *> value) { + if (value.data()) { + setType(VALUE_IS_LINKED_RAW); + _content.asRaw.data = value.data(); + _content.asRaw.size = value.size(); + } else { + setType(VALUE_IS_NULL); + } + } + + template <typename T> + bool setOwnedRaw(SerializedValue<T> value, MemoryPool *pool) { + const char *dup = pool->saveString(adaptString(value.data(), value.size())); + if (dup) { + setType(VALUE_IS_OWNED_RAW); + _content.asRaw.data = dup; + _content.asRaw.size = value.size(); + return true; + } else { + setType(VALUE_IS_NULL); + return false; + } + } + + template <typename T> + typename enable_if<is_unsigned<T>::value>::type setInteger(T value) { + setType(VALUE_IS_UNSIGNED_INTEGER); + _content.asUnsignedInteger = static_cast<UInt>(value); + } + + template <typename T> + typename enable_if<is_signed<T>::value>::type setInteger(T value) { + setType(VALUE_IS_SIGNED_INTEGER); + _content.asSignedInteger = value; + } + + void setNull() { + setType(VALUE_IS_NULL); + } + + void setStringPointer(const char *s, storage_policies::store_by_copy) { + ARDUINOJSON_ASSERT(s != 0); + setType(VALUE_IS_OWNED_STRING); + _content.asString = s; + } + + void setStringPointer(const char *s, storage_policies::store_by_address) { + ARDUINOJSON_ASSERT(s != 0); + setType(VALUE_IS_LINKED_STRING); + _content.asString = s; + } + + template <typename TAdaptedString> + bool setString(TAdaptedString value, MemoryPool *pool) { + return storeString(value, pool, typename TAdaptedString::storage_policy()); + } + + CollectionData &toArray() { + setType(VALUE_IS_ARRAY); + _content.asCollection.clear(); + return _content.asCollection; + } + + CollectionData &toObject() { + setType(VALUE_IS_OBJECT); + _content.asCollection.clear(); + return _content.asCollection; + } + + size_t memoryUsage() const { + switch (type()) { + case VALUE_IS_OWNED_STRING: + return strlen(_content.asString) + 1; + case VALUE_IS_OWNED_RAW: + return _content.asRaw.size; + case VALUE_IS_OBJECT: + case VALUE_IS_ARRAY: + return _content.asCollection.memoryUsage(); + default: + return 0; + } + } + + size_t nesting() const { + return isCollection() ? _content.asCollection.nesting() : 0; + } + + size_t size() const { + return isCollection() ? _content.asCollection.size() : 0; + } + + VariantData *addElement(MemoryPool *pool) { + if (isNull()) + toArray(); + if (!isArray()) + return 0; + return _content.asCollection.addElement(pool); + } + + VariantData *getElement(size_t index) const { + return isArray() ? _content.asCollection.getElement(index) : 0; + } + + VariantData *getOrAddElement(size_t index, MemoryPool *pool) { + if (isNull()) + toArray(); + if (!isArray()) + return 0; + return _content.asCollection.getOrAddElement(index, pool); + } + + template <typename TAdaptedString> + VariantData *getMember(TAdaptedString key) const { + return isObject() ? _content.asCollection.getMember(key) : 0; + } + + template <typename TAdaptedString> + VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool) { + if (isNull()) + toObject(); + if (!isObject()) + return 0; + return _content.asCollection.getOrAddMember(key, pool); + } + + void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) { + if (_flags & OWNED_VALUE_BIT) + _content.asString += stringDistance; + if (_flags & COLLECTION_MASK) + _content.asCollection.movePointers(stringDistance, variantDistance); + } + + uint8_t type() const { + return _flags & VALUE_MASK; + } + + private: + void setType(uint8_t t) { + _flags &= OWNED_KEY_BIT; + _flags |= t; + } + + template <typename TAdaptedString> + inline bool storeString(TAdaptedString value, MemoryPool *pool, + storage_policies::decide_at_runtime) { + if (value.isStatic()) + return storeString(value, pool, storage_policies::store_by_address()); + else + return storeString(value, pool, storage_policies::store_by_copy()); + } + + template <typename TAdaptedString> + inline bool storeString(TAdaptedString value, MemoryPool *, + storage_policies::store_by_address) { + if (value.isNull()) + setNull(); + else + setStringPointer(value.data(), storage_policies::store_by_address()); + return true; + } + + template <typename TAdaptedString> + inline bool storeString(TAdaptedString value, MemoryPool *pool, + storage_policies::store_by_copy) { + if (value.isNull()) { + setNull(); + return true; + } + const char *copy = pool->saveString(value); + if (!copy) { + setNull(); + return false; + } + setStringPointer(copy, storage_policies::store_by_copy()); + return true; + } +}; + +} // namespace ARDUINOJSON_NAMESPACE + +#if defined(__GNUC__) +#if __GNUC__ >= 8 +#pragma GCC diagnostic pop +#endif +#endif diff --git a/include/lib/ArduinoJson/Variant/VariantFunctions.hpp b/include/lib/ArduinoJson/Variant/VariantFunctions.hpp new file mode 100644 index 0000000..3fc9cbb --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantFunctions.hpp @@ -0,0 +1,104 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/attributes.hpp> +#include <ArduinoJson/Variant/VariantData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TVisitor> +inline typename TVisitor::result_type variantAccept(const VariantData *var, + TVisitor &visitor) { + if (var != 0) + return var->accept(visitor); + else + return visitor.visitNull(); +} + +inline const CollectionData *variantAsArray(const VariantData *var) { + return var != 0 ? var->asArray() : 0; +} + +inline const CollectionData *variantAsObject(const VariantData *var) { + return var != 0 ? var->asObject() : 0; +} + +inline CollectionData *variantAsObject(VariantData *var) { + return var != 0 ? var->asObject() : 0; +} + +inline bool variantCopyFrom(VariantData *dst, const VariantData *src, + MemoryPool *pool) { + if (!dst) + return false; + if (!src) { + dst->setNull(); + return true; + } + return dst->copyFrom(*src, pool); +} + +inline int variantCompare(const VariantData *a, const VariantData *b); + +inline void variantSetNull(VariantData *var) { + if (!var) + return; + var->setNull(); +} + +template <typename TAdaptedString> +inline bool variantSetString(VariantData *var, TAdaptedString value, + MemoryPool *pool) { + if (!var) + return false; + return var->setString(value, pool); +} + +inline size_t variantSize(const VariantData *var) { + return var != 0 ? var->size() : 0; +} + +inline CollectionData *variantToArray(VariantData *var) { + if (!var) + return 0; + return &var->toArray(); +} + +inline CollectionData *variantToObject(VariantData *var) { + if (!var) + return 0; + return &var->toObject(); +} + +inline NO_INLINE VariantData *variantAddElement(VariantData *var, + MemoryPool *pool) { + return var != 0 ? var->addElement(pool) : 0; +} + +inline NO_INLINE VariantData *variantGetOrAddElement(VariantData *var, + size_t index, + MemoryPool *pool) { + return var != 0 ? var->getOrAddElement(index, pool) : 0; +} + +template <typename TChar> +NO_INLINE VariantData *variantGetOrAddMember(VariantData *var, TChar *key, + MemoryPool *pool) { + return var != 0 ? var->getOrAddMember(adaptString(key), pool) : 0; +} + +template <typename TString> +NO_INLINE VariantData *variantGetOrAddMember(VariantData *var, + const TString &key, + MemoryPool *pool) { + return var != 0 ? var->getOrAddMember(adaptString(key), pool) : 0; +} + +inline bool variantIsNull(const VariantData *var) { + return var == 0 || var->isNull(); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/VariantImpl.hpp b/include/lib/ArduinoJson/Variant/VariantImpl.hpp new file mode 100644 index 0000000..b91e584 --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantImpl.hpp @@ -0,0 +1,143 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Array/ArrayRef.hpp> +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Numbers/convertNumber.hpp> +#include <ArduinoJson/Numbers/parseNumber.hpp> +#include <ArduinoJson/Object/ObjectRef.hpp> +#include <ArduinoJson/Variant/VariantRef.hpp> + +#include <string.h> // for strcmp + +namespace ARDUINOJSON_NAMESPACE { + +template <typename T> +inline T VariantData::asIntegral() const { + switch (type()) { + case VALUE_IS_BOOLEAN: + return _content.asBoolean; + case VALUE_IS_UNSIGNED_INTEGER: + return convertNumber<T>(_content.asUnsignedInteger); + case VALUE_IS_SIGNED_INTEGER: + return convertNumber<T>(_content.asSignedInteger); + case VALUE_IS_LINKED_STRING: + case VALUE_IS_OWNED_STRING: + return parseNumber<T>(_content.asString); + case VALUE_IS_FLOAT: + return convertNumber<T>(_content.asFloat); + default: + return 0; + } +} + +inline bool VariantData::asBoolean() const { + switch (type()) { + case VALUE_IS_BOOLEAN: + return _content.asBoolean; + case VALUE_IS_SIGNED_INTEGER: + case VALUE_IS_UNSIGNED_INTEGER: + return _content.asUnsignedInteger != 0; + case VALUE_IS_FLOAT: + return _content.asFloat != 0; + case VALUE_IS_NULL: + return false; + default: + return true; + } +} + +// T = float/double +template <typename T> +inline T VariantData::asFloat() const { + switch (type()) { + case VALUE_IS_BOOLEAN: + return static_cast<T>(_content.asBoolean); + case VALUE_IS_UNSIGNED_INTEGER: + return static_cast<T>(_content.asUnsignedInteger); + case VALUE_IS_SIGNED_INTEGER: + return static_cast<T>(_content.asSignedInteger); + case VALUE_IS_LINKED_STRING: + case VALUE_IS_OWNED_STRING: + return parseNumber<T>(_content.asString); + case VALUE_IS_FLOAT: + return static_cast<T>(_content.asFloat); + default: + return 0; + } +} + +inline const char *VariantData::asString() const { + switch (type()) { + case VALUE_IS_LINKED_STRING: + case VALUE_IS_OWNED_STRING: + return _content.asString; + default: + return 0; + } +} + +template <typename T> +inline typename enable_if<is_same<T, ArrayRef>::value, ArrayRef>::type +VariantRef::to() const { + return ArrayRef(_pool, variantToArray(_data)); +} + +template <typename T> +typename enable_if<is_same<T, ObjectRef>::value, ObjectRef>::type +VariantRef::to() const { + return ObjectRef(_pool, variantToObject(_data)); +} + +template <typename T> +typename enable_if<is_same<T, VariantRef>::value, VariantRef>::type +VariantRef::to() const { + variantSetNull(_data); + return *this; +} + +inline VariantConstRef VariantConstRef::getElement(size_t index) const { + return ArrayConstRef(_data != 0 ? _data->asArray() : 0)[index]; +} + +inline VariantRef VariantRef::addElement() const { + return VariantRef(_pool, variantAddElement(_data, _pool)); +} + +inline VariantRef VariantRef::getElement(size_t index) const { + return VariantRef(_pool, _data != 0 ? _data->getElement(index) : 0); +} + +inline VariantRef VariantRef::getOrAddElement(size_t index) const { + return VariantRef(_pool, variantGetOrAddElement(_data, index, _pool)); +} + +template <typename TChar> +inline VariantRef VariantRef::getMember(TChar *key) const { + return VariantRef(_pool, _data != 0 ? _data->getMember(adaptString(key)) : 0); +} + +template <typename TString> +inline typename enable_if<IsString<TString>::value, VariantRef>::type +VariantRef::getMember(const TString &key) const { + return VariantRef(_pool, _data != 0 ? _data->getMember(adaptString(key)) : 0); +} + +template <typename TChar> +inline VariantRef VariantRef::getOrAddMember(TChar *key) const { + return VariantRef(_pool, variantGetOrAddMember(_data, key, _pool)); +} + +template <typename TString> +inline VariantRef VariantRef::getOrAddMember(const TString &key) const { + return VariantRef(_pool, variantGetOrAddMember(_data, key, _pool)); +} + +inline VariantConstRef operator|(VariantConstRef preferedValue, + VariantConstRef defaultValue) { + return preferedValue ? preferedValue : defaultValue; +} +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/VariantOperators.hpp b/include/lib/ArduinoJson/Variant/VariantOperators.hpp new file mode 100644 index 0000000..54174a4 --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantOperators.hpp @@ -0,0 +1,180 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Misc/Visitable.hpp> +#include <ArduinoJson/Numbers/arithmeticCompare.hpp> +#include <ArduinoJson/Polyfills/attributes.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Variant/VariantTag.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename T1, typename T2> +CompareResult compare(const T1 &lhs, const T2 &rhs); // VariantCompare.cpp + +template <typename TVariant> +struct VariantOperators { + // Returns the default value if the VariantRef is undefined or incompatible + // + // int operator|(JsonVariant, int) + // float operator|(JsonVariant, float) + // bool operator|(JsonVariant, bool) + template <typename T> + friend + typename enable_if<!IsVariant<T>::value && !is_array<T>::value, T>::type + operator|(const TVariant &variant, const T &defaultValue) { + if (variant.template is<T>()) + return variant.template as<T>(); + else + return defaultValue; + } + // + // const char* operator|(JsonVariant, const char*) + friend const char *operator|(const TVariant &variant, + const char *defaultValue) { + if (variant.template is<const char *>()) + return variant.template as<const char *>(); + else + return defaultValue; + } + // + // JsonVariant operator|(JsonVariant, JsonVariant) + template <typename T> + friend typename enable_if<IsVariant<T>::value, typename T::variant_type>::type + operator|(const TVariant &variant, T defaultValue) { + if (variant) + return variant; + else + return defaultValue; + } + + // value == TVariant + template <typename T> + friend bool operator==(T *lhs, TVariant rhs) { + return compare(rhs, lhs) == COMPARE_RESULT_EQUAL; + } + template <typename T> + friend bool operator==(const T &lhs, TVariant rhs) { + return compare(rhs, lhs) == COMPARE_RESULT_EQUAL; + } + + // TVariant == value + template <typename T> + friend bool operator==(TVariant lhs, T *rhs) { + return compare(lhs, rhs) == COMPARE_RESULT_EQUAL; + } + template <typename T> + friend typename enable_if<!IsVisitable<T>::value, bool>::type operator==( + TVariant lhs, const T &rhs) { + return compare(lhs, rhs) == COMPARE_RESULT_EQUAL; + } + + // value != TVariant + template <typename T> + friend bool operator!=(T *lhs, TVariant rhs) { + return compare(rhs, lhs) != COMPARE_RESULT_EQUAL; + } + template <typename T> + friend bool operator!=(const T &lhs, TVariant rhs) { + return compare(rhs, lhs) != COMPARE_RESULT_EQUAL; + } + + // TVariant != value + template <typename T> + friend bool operator!=(TVariant lhs, T *rhs) { + return compare(lhs, rhs) != COMPARE_RESULT_EQUAL; + } + template <typename T> + friend typename enable_if<!IsVisitable<T>::value, bool>::type operator!=( + TVariant lhs, const T &rhs) { + return compare(lhs, rhs) != COMPARE_RESULT_EQUAL; + } + + // value < TVariant + template <typename T> + friend bool operator<(T *lhs, TVariant rhs) { + return compare(rhs, lhs) == COMPARE_RESULT_GREATER; + } + template <typename T> + friend bool operator<(const T &lhs, TVariant rhs) { + return compare(rhs, lhs) == COMPARE_RESULT_GREATER; + } + + // TVariant < value + template <typename T> + friend bool operator<(TVariant lhs, T *rhs) { + return compare(lhs, rhs) == COMPARE_RESULT_LESS; + } + template <typename T> + friend typename enable_if<!IsVisitable<T>::value, bool>::type operator<( + TVariant lhs, const T &rhs) { + return compare(lhs, rhs) == COMPARE_RESULT_LESS; + } + + // value <= TVariant + template <typename T> + friend bool operator<=(T *lhs, TVariant rhs) { + return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; + } + template <typename T> + friend bool operator<=(const T &lhs, TVariant rhs) { + return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; + } + + // TVariant <= value + template <typename T> + friend bool operator<=(TVariant lhs, T *rhs) { + return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; + } + template <typename T> + friend typename enable_if<!IsVisitable<T>::value, bool>::type operator<=( + TVariant lhs, const T &rhs) { + return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; + } + + // value > TVariant + template <typename T> + friend bool operator>(T *lhs, TVariant rhs) { + return compare(rhs, lhs) == COMPARE_RESULT_LESS; + } + template <typename T> + friend bool operator>(const T &lhs, TVariant rhs) { + return compare(rhs, lhs) == COMPARE_RESULT_LESS; + } + + // TVariant > value + template <typename T> + friend bool operator>(TVariant lhs, T *rhs) { + return compare(lhs, rhs) == COMPARE_RESULT_GREATER; + } + template <typename T> + friend typename enable_if<!IsVisitable<T>::value, bool>::type operator>( + TVariant lhs, const T &rhs) { + return compare(lhs, rhs) == COMPARE_RESULT_GREATER; + } + + // value >= TVariant + template <typename T> + friend bool operator>=(T *lhs, TVariant rhs) { + return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; + } + template <typename T> + friend bool operator>=(const T &lhs, TVariant rhs) { + return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; + } + + // TVariant >= value + template <typename T> + friend bool operator>=(TVariant lhs, T *rhs) { + return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; + } + template <typename T> + friend typename enable_if<!IsVisitable<T>::value, bool>::type operator>=( + TVariant lhs, const T &rhs) { + return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; + } +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/VariantRef.hpp b/include/lib/ArduinoJson/Variant/VariantRef.hpp new file mode 100644 index 0000000..8d4c410 --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantRef.hpp @@ -0,0 +1,375 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <stddef.h> +#include <stdint.h> // for uint8_t + +#include <ArduinoJson/Memory/MemoryPool.hpp> +#include <ArduinoJson/Misc/Visitable.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Strings/StringAdapters.hpp> +#include <ArduinoJson/Variant/Converter.hpp> +#include <ArduinoJson/Variant/VariantFunctions.hpp> +#include <ArduinoJson/Variant/VariantOperators.hpp> +#include <ArduinoJson/Variant/VariantRef.hpp> +#include <ArduinoJson/Variant/VariantShortcuts.hpp> +#include <ArduinoJson/Variant/VariantTag.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +// Forward declarations. +class ArrayRef; +class ObjectRef; + +// Contains the methods shared by VariantRef and VariantConstRef +template <typename TData> +class VariantRefBase : public VariantTag { + public: + FORCE_INLINE bool isNull() const { + return variantIsNull(_data); + } + + FORCE_INLINE bool isUndefined() const { + return !_data; + } + + FORCE_INLINE size_t memoryUsage() const { + return _data ? _data->memoryUsage() : 0; + } + + FORCE_INLINE size_t nesting() const { + return _data ? _data->nesting() : 0; + } + + size_t size() const { + return variantSize(_data); + } + + protected: + VariantRefBase(TData *data) : _data(data) {} + TData *_data; + + friend TData *getData(const VariantRefBase &variant) { + return variant._data; + } +}; + +// A variant that can be a any value serializable to a JSON value. +// +// It can be set to: +// - a boolean +// - a char, short, int or a long (signed or unsigned) +// - a string (const char*) +// - a reference to a ArrayRef or ObjectRef +class VariantRef : public VariantRefBase<VariantData>, + public VariantOperators<VariantRef>, + public VariantShortcuts<VariantRef>, + public Visitable { + typedef VariantRefBase<VariantData> base_type; + friend class VariantConstRef; + + public: + // Intenal use only + FORCE_INLINE VariantRef(MemoryPool *pool, VariantData *data) + : base_type(data), _pool(pool) {} + + // Creates an uninitialized VariantRef + FORCE_INLINE VariantRef() : base_type(0), _pool(0) {} + + FORCE_INLINE void clear() const { + return variantSetNull(_data); + } + + template <typename T> + FORCE_INLINE bool set(const T &value) const { + return Converter<T>::toJson(value, *this); + } + + FORCE_INLINE bool ARDUINOJSON_DEPRECATED( + "Support for char is deprecated, use int8_t or uint8_t instead") + set(char value) const { + return set<signed char>(value); + } + + template <typename T> + FORCE_INLINE bool set(T *value) const { + return Converter<T *>::toJson(value, *this); + } + + template <typename T> + FORCE_INLINE + typename enable_if<!is_same<T, char *>::value && !is_same<T, char>::value, + T>::type + as() const { + return Converter<T>::fromJson(*this); + } + + template <typename T> + FORCE_INLINE typename enable_if<is_same<T, char *>::value, const char *>::type + ARDUINOJSON_DEPRECATED("Replace as<char*>() with as<const char*>()") + as() const { + return as<const char *>(); + } + + template <typename T> + FORCE_INLINE typename enable_if<is_same<T, char>::value, char>::type + ARDUINOJSON_DEPRECATED( + "Support for char is deprecated, use int8_t or uint8_t instead") + as() const { + return as<signed char>(); + } + + template <typename T> + FORCE_INLINE + typename enable_if<!is_same<T, char *>::value && !is_same<T, char>::value, + bool>::type + is() const { + return Converter<T>::checkJson(*this); + } + + template <typename T> + FORCE_INLINE typename enable_if<is_same<T, char *>::value, bool>::type + ARDUINOJSON_DEPRECATED("Replace is<char*>() with is<const char*>()") + is() const { + return is<const char *>(); + } + + template <typename T> + FORCE_INLINE typename enable_if<is_same<T, char>::value, bool>::type + ARDUINOJSON_DEPRECATED( + "Support for char is deprecated, use int8_t or uint8_t instead") + is() const { + return is<signed char>(); + } + + template <typename T> + FORCE_INLINE operator T() const { + return as<T>(); + } + + template <typename TVisitor> + typename TVisitor::result_type accept(TVisitor &visitor) const { + return variantAccept(_data, visitor); + } + + // Change the type of the variant + // + // ArrayRef to<ArrayRef>() + template <typename T> + typename enable_if<is_same<T, ArrayRef>::value, ArrayRef>::type to() const; + // + // ObjectRef to<ObjectRef>() + template <typename T> + typename enable_if<is_same<T, ObjectRef>::value, ObjectRef>::type to() const; + // + // ObjectRef to<VariantRef>() + template <typename T> + typename enable_if<is_same<T, VariantRef>::value, VariantRef>::type to() + const; + + VariantRef addElement() const; + + FORCE_INLINE VariantRef getElement(size_t) const; + + FORCE_INLINE VariantRef getOrAddElement(size_t) const; + + // getMember(const char*) const + // getMember(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE VariantRef getMember(TChar *) const; + + // getMember(const std::string&) const + // getMember(const String&) const + template <typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value, VariantRef>::type + getMember(const TString &) const; + + // getOrAddMember(char*) const + // getOrAddMember(const char*) const + // getOrAddMember(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE VariantRef getOrAddMember(TChar *) const; + + // getOrAddMember(const std::string&) const + // getOrAddMember(const String&) const + template <typename TString> + FORCE_INLINE VariantRef getOrAddMember(const TString &) const; + + FORCE_INLINE void remove(size_t index) const { + if (_data) + _data->remove(index); + } + // remove(char*) const + // remove(const char*) const + // remove(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE typename enable_if<IsString<TChar *>::value>::type remove( + TChar *key) const { + if (_data) + _data->remove(adaptString(key)); + } + // remove(const std::string&) const + // remove(const String&) const + template <typename TString> + FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove( + const TString &key) const { + if (_data) + _data->remove(adaptString(key)); + } + + private: + MemoryPool *_pool; + + friend MemoryPool *getPool(const VariantRef &variant) { + return variant._pool; + } +}; + +class VariantConstRef : public VariantRefBase<const VariantData>, + public VariantOperators<VariantConstRef>, + public VariantShortcuts<VariantConstRef>, + public Visitable { + typedef VariantRefBase<const VariantData> base_type; + friend class VariantRef; + + public: + VariantConstRef() : base_type(0) {} + VariantConstRef(const VariantData *data) : base_type(data) {} + VariantConstRef(VariantRef var) : base_type(var._data) {} + + template <typename TVisitor> + typename TVisitor::result_type accept(TVisitor &visitor) const { + return variantAccept(_data, visitor); + } + + template <typename T> + FORCE_INLINE + typename enable_if<!is_same<T, char *>::value && !is_same<T, char>::value, + T>::type + as() const { + return Converter<T>::fromJson(*this); + } + + template <typename T> + FORCE_INLINE typename enable_if<is_same<T, char *>::value, const char *>::type + ARDUINOJSON_DEPRECATED("Replace as<char*>() with as<const char*>()") + as() const { + return as<const char *>(); + } + + template <typename T> + FORCE_INLINE typename enable_if<is_same<T, char>::value, char>::type + ARDUINOJSON_DEPRECATED( + "Support for char is deprecated, use int8_t or uint8_t instead") + as() const { + return as<signed char>(); + } + + template <typename T> + FORCE_INLINE + typename enable_if<!is_same<T, char *>::value && !is_same<T, char>::value, + bool>::type + is() const { + return Converter<T>::checkJson(*this); + } + + template <typename T> + FORCE_INLINE typename enable_if<is_same<T, char *>::value, bool>::type + ARDUINOJSON_DEPRECATED("Replace is<char*>() with is<const char*>()") + is() const { + return is<const char *>(); + } + + template <typename T> + FORCE_INLINE typename enable_if<is_same<T, char>::value, bool>::type + ARDUINOJSON_DEPRECATED( + "Support for char is deprecated, use int8_t or uint8_t instead") + is() const { + return is<signed char>(); + } + + template <typename T> + FORCE_INLINE operator T() const { + return as<T>(); + } + + FORCE_INLINE VariantConstRef getElement(size_t) const; + + FORCE_INLINE VariantConstRef operator[](size_t index) const { + return getElement(index); + } + + // getMember(const std::string&) const + // getMember(const String&) const + template <typename TString> + FORCE_INLINE VariantConstRef getMember(const TString &key) const { + return VariantConstRef( + objectGetMember(variantAsObject(_data), adaptString(key))); + } + + // getMember(char*) const + // getMember(const char*) const + // getMember(const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE VariantConstRef getMember(TChar *key) const { + const CollectionData *obj = variantAsObject(_data); + return VariantConstRef(obj ? obj->getMember(adaptString(key)) : 0); + } + + // operator[](const std::string&) const + // operator[](const String&) const + template <typename TString> + FORCE_INLINE + typename enable_if<IsString<TString>::value, VariantConstRef>::type + operator[](const TString &key) const { + return getMember(key); + } + + // operator[](char*) const + // operator[](const char*) const + // operator[](const __FlashStringHelper*) const + template <typename TChar> + FORCE_INLINE + typename enable_if<IsString<TChar *>::value, VariantConstRef>::type + operator[](TChar *key) const { + return getMember(key); + } +}; + +template <> +struct Converter<VariantRef> { + static bool toJson(VariantRef src, VariantRef dst) { + return variantCopyFrom(getData(dst), getData(src), getPool(dst)); + } + static VariantRef fromJson(VariantRef src) { + return src; + } + static bool checkJson(VariantRef src) { + VariantData *data = getData(src); + return !!data; + } + static bool checkJson(VariantConstRef) { + return false; + } +}; + +template <> +struct Converter<VariantConstRef> { + static bool toJson(VariantConstRef src, VariantRef dst) { + return variantCopyFrom(getData(dst), getData(src), getPool(dst)); + } + + static VariantConstRef fromJson(VariantConstRef src) { + return VariantConstRef(getData(src)); + } + + static bool checkJson(VariantConstRef src) { + const VariantData *data = getData(src); + return !!data; + } +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/VariantShortcuts.hpp b/include/lib/ArduinoJson/Variant/VariantShortcuts.hpp new file mode 100644 index 0000000..e62847f --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantShortcuts.hpp @@ -0,0 +1,23 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Array/ArrayShortcuts.hpp> +#include <ArduinoJson/Object/ObjectShortcuts.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TVariant> +class VariantShortcuts : public ObjectShortcuts<TVariant>, + public ArrayShortcuts<TVariant> { + public: + using ArrayShortcuts<TVariant>::createNestedArray; + using ArrayShortcuts<TVariant>::createNestedObject; + using ArrayShortcuts<TVariant>::operator[]; + using ObjectShortcuts<TVariant>::createNestedArray; + using ObjectShortcuts<TVariant>::createNestedObject; + using ObjectShortcuts<TVariant>::operator[]; +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/VariantSlot.hpp b/include/lib/ArduinoJson/Variant/VariantSlot.hpp new file mode 100644 index 0000000..a271c1e --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantSlot.hpp @@ -0,0 +1,116 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Polyfills/integer.hpp> +#include <ArduinoJson/Polyfills/limits.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Strings/StoragePolicy.hpp> +#include <ArduinoJson/Variant/VariantContent.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +typedef int_t<ARDUINOJSON_SLOT_OFFSET_SIZE * 8>::type VariantSlotDiff; + +class VariantSlot { + // CAUTION: same layout as VariantData + // we cannot use composition because it adds padding + // (+20% on ESP8266 for example) + VariantContent _content; + uint8_t _flags; + VariantSlotDiff _next; + const char* _key; + + public: + // Must be a POD! + // - no constructor + // - no destructor + // - no virtual + // - no inheritance + + VariantData* data() { + return reinterpret_cast<VariantData*>(&_content); + } + + const VariantData* data() const { + return reinterpret_cast<const VariantData*>(&_content); + } + + VariantSlot* next() { + return _next ? this + _next : 0; + } + + const VariantSlot* next() const { + return const_cast<VariantSlot*>(this)->next(); + } + + VariantSlot* next(size_t distance) { + VariantSlot* slot = this; + while (distance--) { + if (!slot->_next) + return 0; + slot += slot->_next; + } + return slot; + } + + const VariantSlot* next(size_t distance) const { + return const_cast<VariantSlot*>(this)->next(distance); + } + + void setNext(VariantSlot* slot) { + ARDUINOJSON_ASSERT(!slot || slot - this >= + numeric_limits<VariantSlotDiff>::lowest()); + ARDUINOJSON_ASSERT(!slot || slot - this <= + numeric_limits<VariantSlotDiff>::highest()); + _next = VariantSlotDiff(slot ? slot - this : 0); + } + + void setNextNotNull(VariantSlot* slot) { + ARDUINOJSON_ASSERT(slot != 0); + ARDUINOJSON_ASSERT(slot - this >= + numeric_limits<VariantSlotDiff>::lowest()); + ARDUINOJSON_ASSERT(slot - this <= + numeric_limits<VariantSlotDiff>::highest()); + _next = VariantSlotDiff(slot - this); + } + + void setKey(const char* k, storage_policies::store_by_copy) { + ARDUINOJSON_ASSERT(k != NULL); + _flags |= OWNED_KEY_BIT; + _key = k; + } + + void setKey(const char* k, storage_policies::store_by_address) { + ARDUINOJSON_ASSERT(k != NULL); + _flags &= VALUE_MASK; + _key = k; + } + + const char* key() const { + return _key; + } + + bool ownsKey() const { + return (_flags & OWNED_KEY_BIT) != 0; + } + + void clear() { + _next = 0; + _flags = 0; + _key = 0; + } + + void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) { + if (_flags & OWNED_KEY_BIT) + _key += stringDistance; + if (_flags & OWNED_VALUE_BIT) + _content.asString += stringDistance; + if (_flags & COLLECTION_MASK) + _content.asCollection.movePointers(stringDistance, variantDistance); + } +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/VariantTag.hpp b/include/lib/ArduinoJson/Variant/VariantTag.hpp new file mode 100644 index 0000000..7164164 --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantTag.hpp @@ -0,0 +1,16 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +struct VariantTag {}; + +template <typename T> +struct IsVariant : is_base_of<VariantTag, T> {}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/VariantTo.hpp b/include/lib/ArduinoJson/Variant/VariantTo.hpp new file mode 100644 index 0000000..352ecba --- /dev/null +++ b/include/lib/ArduinoJson/Variant/VariantTo.hpp @@ -0,0 +1,32 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { +class ArrayRef; +class ObjectRef; +class VariantRef; + +// A metafunction that returns the type of the value returned by +// VariantRef::to<T>() +template <typename T> +struct VariantTo {}; + +template <> +struct VariantTo<ArrayRef> { + typedef ArrayRef type; +}; +template <> +struct VariantTo<ObjectRef> { + typedef ObjectRef type; +}; +template <> +struct VariantTo<VariantRef> { + typedef VariantRef type; +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Variant/Visitor.hpp b/include/lib/ArduinoJson/Variant/Visitor.hpp new file mode 100644 index 0000000..33237dd --- /dev/null +++ b/include/lib/ArduinoJson/Variant/Visitor.hpp @@ -0,0 +1,54 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Collection/CollectionData.hpp> +#include <ArduinoJson/Numbers/Float.hpp> +#include <ArduinoJson/Numbers/Integer.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TResult> +struct Visitor { + typedef TResult result_type; + + TResult visitArray(const CollectionData &) { + return TResult(); + } + + TResult visitBoolean(bool) { + return TResult(); + } + + TResult visitFloat(Float) { + return TResult(); + } + + TResult visitSignedInteger(Integer) { + return TResult(); + } + + TResult visitNull() { + return TResult(); + } + + TResult visitObject(const CollectionData &) { + return TResult(); + } + + TResult visitUnsignedInteger(UInt) { + return TResult(); + } + + TResult visitRawJson(const char *, size_t) { + return TResult(); + } + + TResult visitString(const char *) { + return TResult(); + } +}; + +} // namespace ARDUINOJSON_NAMESPACE |