diff --git a/CHANGELOG.md b/CHANGELOG.md index c859dbad..52238413 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,16 @@ ArduinoJson: change log ======================= +HEAD +---- + +* Copy `JsonArray` and `JsonObject`, instead of storing pointers (issue #780) + v6.3.0-beta (2018-08-31) ----------- * Implemented reference semantics for `JsonVariant` -* Replace `JsonPair`'s `key` and `value` with `key()` and `value()` +* Replaced `JsonPair`'s `key` and `value` with `key()` and `value()` * Fixed `serializeJson(obj[key], dst)` (issue #794) > ### BREAKING CHANGES diff --git a/src/ArduinoJson/Data/JsonVariantContent.hpp b/src/ArduinoJson/Data/JsonVariantContent.hpp index 389c5379..e7d6e415 100644 --- a/src/ArduinoJson/Data/JsonVariantContent.hpp +++ b/src/ArduinoJson/Data/JsonVariantContent.hpp @@ -11,22 +11,34 @@ namespace ArduinoJson { namespace Internals { -// Forward declarations -struct JsonArrayData; -struct JsonObjectData; +struct JsonObjectData { + struct Slot* head; + struct Slot* tail; +}; -// A union that defines the actual content of a JsonVariant. +struct JsonArrayData { + struct Slot* head; + struct Slot* tail; +}; + +struct RawData { + const char* data; + size_t size; +}; + +// A union that defines the actual content of a JsonVariantData. // The enum JsonVariantType determines which member is in use. union JsonVariantContent { - JsonFloat asFloat; // used for double and float - JsonUInt asInteger; // used for bool, char, short, int and longs - JsonArrayData* asArray; // asArray cannot be null - JsonObjectData* asObject; // asObject cannot be null - const char* asString; // asString can be null + JsonFloat asFloat; + JsonUInt asInteger; + JsonArrayData asArray; + JsonObjectData asObject; + const char* asString; struct { const char* data; size_t size; } asRaw; }; + } // namespace Internals } // namespace ArduinoJson diff --git a/src/ArduinoJson/Data/JsonVariantData.hpp b/src/ArduinoJson/Data/JsonVariantData.hpp index 81653cc7..79f7b168 100644 --- a/src/ArduinoJson/Data/JsonVariantData.hpp +++ b/src/ArduinoJson/Data/JsonVariantData.hpp @@ -16,6 +16,10 @@ struct JsonVariantData { JsonVariantType type; JsonVariantContent content; + JsonVariantData() { + type = JSON_NULL; + } + void setBoolean(bool value) { type = JSON_BOOLEAN; content.asInteger = static_cast(value); @@ -43,13 +47,24 @@ struct JsonVariantData { content.asInteger = value; } - void setString(const char *value) { - type = JSON_STRING; + void setOwnedString(const char *value) { + type = JSON_OWNED_STRING; content.asString = value; } - void setRaw(const char *data, size_t size) { - type = JSON_RAW; + void setLinkedString(const char *value) { + type = JSON_LINKED_STRING; + content.asString = value; + } + + void setOwnedRaw(const char *data, size_t size) { + type = JSON_OWNED_RAW; + content.asRaw.data = data; + content.asRaw.size = size; + } + + void setLinkedRaw(const char *data, size_t size) { + type = JSON_LINKED_RAW; content.asRaw.data = data; content.asRaw.size = size; } @@ -58,66 +73,70 @@ struct JsonVariantData { type = JSON_NULL; } - void setArray(JsonArrayData &array) { + JsonArrayData *toArray() { type = JSON_ARRAY; - content.asArray = &array; + content.asArray.head = 0; + content.asArray.tail = 0; + return &content.asArray; } - void setObject(JsonObjectData &object) { + JsonObjectData *toObject() { type = JSON_OBJECT; - content.asObject = &object; + content.asObject.head = 0; + content.asObject.tail = 0; + return &content.asObject; } - JsonArrayData *asArray() const { - return type == JSON_ARRAY ? content.asArray : 0; + JsonArrayData *asArray() { + return type == JSON_ARRAY ? &content.asArray : 0; } - JsonObjectData *asObject() const { - return type == JSON_OBJECT ? content.asObject : 0; + JsonObjectData *asObject() { + return type == JSON_OBJECT ? &content.asObject : 0; } template T asInteger() const { switch (type) { - case JSON_NULL: - case JSON_RAW: - return 0; case JSON_POSITIVE_INTEGER: case JSON_BOOLEAN: return T(content.asInteger); case JSON_NEGATIVE_INTEGER: return T(~content.asInteger + 1); - case JSON_STRING: + case JSON_LINKED_STRING: + case JSON_OWNED_STRING: return parseInteger(content.asString); - default: + case JSON_FLOAT: return T(content.asFloat); + default: + return 0; } } template T asFloat() const { switch (type) { - case JSON_NULL: - case JSON_RAW: - return 0; case JSON_POSITIVE_INTEGER: case JSON_BOOLEAN: return static_cast(content.asInteger); case JSON_NEGATIVE_INTEGER: return -static_cast(content.asInteger); - case JSON_STRING: + case JSON_LINKED_STRING: + case JSON_OWNED_STRING: return parseFloat(content.asString); - default: + case JSON_FLOAT: return static_cast(content.asFloat); + default: + return 0; } } const char *asString() const { - return type == JSON_STRING ? content.asString : NULL; + return isString() ? content.asString : NULL; } bool isArray() const { - return type == Internals::JSON_ARRAY; + return type == JSON_ARRAY; } bool isBoolean() const { @@ -138,43 +157,11 @@ struct JsonVariantData { } bool isObject() const { - return type == Internals::JSON_OBJECT; + return type == JSON_OBJECT; } bool isString() const { - return type == Internals::JSON_STRING; - } - - template - void visit(Visitor &visitor) const { - switch (type) { - case JSON_FLOAT: - return visitor.acceptFloat(content.asFloat); - - case JSON_ARRAY: - return visitor.acceptArray(*content.asArray); - - case JSON_OBJECT: - return visitor.acceptObject(*content.asObject); - - case JSON_STRING: - return visitor.acceptString(content.asString); - - case JSON_RAW: - return visitor.acceptRawJson(content.asRaw.data, content.asRaw.size); - - case JSON_NEGATIVE_INTEGER: - return visitor.acceptNegativeInteger(content.asInteger); - - case JSON_POSITIVE_INTEGER: - return visitor.acceptPositiveInteger(content.asInteger); - - case JSON_BOOLEAN: - return visitor.acceptBoolean(content.asInteger != 0); - - default: - return visitor.acceptNull(); - } + return type == JSON_LINKED_STRING || type == JSON_OWNED_STRING; } }; } // namespace Internals diff --git a/src/ArduinoJson/Data/JsonVariantTo.hpp b/src/ArduinoJson/Data/JsonVariantTo.hpp new file mode 100644 index 00000000..cc73dfb6 --- /dev/null +++ b/src/ArduinoJson/Data/JsonVariantTo.hpp @@ -0,0 +1,33 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#pragma once + +namespace ArduinoJson { +class JsonArray; +class JsonObject; +class JsonVariant; + +namespace Internals { + +// A metafunction that returns the type of the value returned by +// JsonVariant::to() +template +struct JsonVariantTo {}; + +template <> +struct JsonVariantTo { + typedef JsonArray type; +}; +template <> +struct JsonVariantTo { + typedef JsonObject type; +}; +template <> +struct JsonVariantTo { + typedef JsonVariant type; +}; + +} // namespace Internals +} // namespace ArduinoJson diff --git a/src/ArduinoJson/Data/JsonVariantType.hpp b/src/ArduinoJson/Data/JsonVariantType.hpp index 43d9e8d9..8cf6df50 100644 --- a/src/ArduinoJson/Data/JsonVariantType.hpp +++ b/src/ArduinoJson/Data/JsonVariantType.hpp @@ -11,15 +11,17 @@ namespace Internals { // Enumerated type to know the current type of a JsonVariant. // The value determines which member of JsonVariantContent is used. enum JsonVariantType { - JSON_NULL, // JsonVariant has not been initialized - JSON_RAW, // JsonVariant contains a raw string that should not be escaped - JSON_STRING, // JsonVariant stores a const char* - JSON_BOOLEAN, // JsonVariant stores a bool - JSON_POSITIVE_INTEGER, // JsonVariant stores an JsonUInt - JSON_NEGATIVE_INTEGER, // JsonVariant stores an JsonUInt that must be negated - JSON_ARRAY, // JsonVariant stores a pointer to a JsonArrayData - JSON_OBJECT, // JsonVariant stores a pointer to a JsonObjectData - JSON_FLOAT // JsonVariant stores a JsonFloat + JSON_NULL, + JSON_LINKED_RAW, + JSON_OWNED_RAW, + JSON_LINKED_STRING, + JSON_OWNED_STRING, + JSON_BOOLEAN, + JSON_POSITIVE_INTEGER, + JSON_NEGATIVE_INTEGER, + JSON_ARRAY, + JSON_OBJECT, + JSON_FLOAT }; } // namespace Internals } // namespace ArduinoJson diff --git a/src/ArduinoJson/Data/List.hpp b/src/ArduinoJson/Data/List.hpp deleted file mode 100644 index e3f2f63d..00000000 --- a/src/ArduinoJson/Data/List.hpp +++ /dev/null @@ -1,83 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2018 -// MIT License - -#pragma once - -#include "../Memory/MemoryPool.hpp" -#include "ListConstIterator.hpp" -#include "ListIterator.hpp" - -namespace ArduinoJson { -namespace Internals { - -// A singly linked list of T. -// The linked list is composed of ListNode. -// It is derived by JsonArrayData and JsonObjectData -template -class List { - public: - typedef T value_type; - typedef ListNode node_type; - typedef ListIterator iterator; - typedef ListConstIterator const_iterator; - - List() : _firstNode(NULL) {} - - // Returns the numbers of elements in the list. - // For a JsonObjectData, it would return the number of key-value pairs - size_t size() const { - size_t nodeCount = 0; - for (node_type *node = _firstNode; node; node = node->next) nodeCount++; - return nodeCount; - } - - iterator add(MemoryPool *memoryPool) { - node_type *newNode = new (memoryPool) node_type(); - - if (_firstNode) { - node_type *lastNode = _firstNode; - while (lastNode->next) lastNode = lastNode->next; - lastNode->next = newNode; - } else { - _firstNode = newNode; - } - - return iterator(newNode); - } - - iterator begin() { - return iterator(_firstNode); - } - iterator end() { - return iterator(NULL); - } - - const_iterator begin() const { - return const_iterator(_firstNode); - } - const_iterator end() const { - return const_iterator(NULL); - } - - void remove(iterator it) { - node_type *nodeToRemove = it._node; - if (!nodeToRemove) return; - if (nodeToRemove == _firstNode) { - _firstNode = nodeToRemove->next; - } else { - for (node_type *node = _firstNode; node; node = node->next) - if (node->next == nodeToRemove) node->next = nodeToRemove->next; - } - } - - protected: - void clear() { - _firstNode = 0; - } - - private: - node_type *_firstNode; -}; -} // namespace Internals -} // namespace ArduinoJson diff --git a/src/ArduinoJson/Data/ListConstIterator.hpp b/src/ArduinoJson/Data/ListConstIterator.hpp deleted file mode 100644 index a6af685e..00000000 --- a/src/ArduinoJson/Data/ListConstIterator.hpp +++ /dev/null @@ -1,50 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2018 -// MIT License - -#pragma once - -#include "ListNode.hpp" - -namespace ArduinoJson { -namespace Internals { - -// A read-only forward itertor for List -template -class ListConstIterator { - public: - explicit ListConstIterator(const ListNode *node = NULL) : _node(node) {} - - const T &operator*() const { - return _node->content; - } - const T *operator->() { - return &_node->content; - } - - bool operator==(const ListConstIterator &other) const { - return _node == other._node; - } - - bool operator!=(const ListConstIterator &other) const { - return _node != other._node; - } - - ListConstIterator &operator++() { - if (_node) _node = _node->next; - return *this; - } - - ListConstIterator &operator+=(size_t distance) { - while (_node && distance) { - _node = _node->next; - --distance; - } - return *this; - } - - private: - const ListNode *_node; -}; -} -} diff --git a/src/ArduinoJson/Data/ListIterator.hpp b/src/ArduinoJson/Data/ListIterator.hpp deleted file mode 100644 index 01fa287f..00000000 --- a/src/ArduinoJson/Data/ListIterator.hpp +++ /dev/null @@ -1,60 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2018 -// MIT License - -#pragma once - -#include "ListConstIterator.hpp" -#include "ListNode.hpp" - -namespace ArduinoJson { -namespace Internals { - -template -class List; - -// A read-write forward iterator for List -template -class ListIterator { - friend class List; - - public: - explicit ListIterator(ListNode *node = NULL) : _node(node) {} - - T &operator*() const { - return _node->content; - } - T *operator->() { - return &_node->content; - } - - bool operator==(const ListIterator &other) const { - return _node == other._node; - } - - bool operator!=(const ListIterator &other) const { - return _node != other._node; - } - - ListIterator &operator++() { - if (_node) _node = _node->next; - return *this; - } - - ListIterator &operator+=(size_t distance) { - while (_node && distance) { - _node = _node->next; - --distance; - } - return *this; - } - - operator ListConstIterator() const { - return ListConstIterator(_node); - } - - private: - ListNode *_node; -}; -} -} diff --git a/src/ArduinoJson/Data/ListNode.hpp b/src/ArduinoJson/Data/ListNode.hpp deleted file mode 100644 index cea708a3..00000000 --- a/src/ArduinoJson/Data/ListNode.hpp +++ /dev/null @@ -1,24 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2018 -// MIT License - -#pragma once - -#include // for NULL - -#include "../Memory/AllocableInMemoryPool.hpp" - -namespace ArduinoJson { -namespace Internals { - -// A node for a singly-linked list. -// Used by List and its iterators. -template -struct ListNode : public Internals::AllocableInMemoryPool { - ListNode() NOEXCEPT : next(NULL) {} - - ListNode *next; - T content; -}; -} // namespace Internals -} // namespace ArduinoJson diff --git a/src/ArduinoJson/Data/Slot.hpp b/src/ArduinoJson/Data/Slot.hpp new file mode 100644 index 00000000..72ce7da9 --- /dev/null +++ b/src/ArduinoJson/Data/Slot.hpp @@ -0,0 +1,21 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#pragma once + +#include "../Memory/AllocableInMemoryPool.hpp" +#include "JsonVariantData.hpp" + +namespace ArduinoJson { +namespace Internals { + +struct Slot : AllocableInMemoryPool { + JsonVariantData value; + struct Slot* next; + struct Slot* prev; + const char* key; +}; + +} // namespace Internals +} // namespace ArduinoJson diff --git a/src/ArduinoJson/Deserialization/deserialize.hpp b/src/ArduinoJson/Deserialization/deserialize.hpp index 3c97364a..a32bbdd3 100644 --- a/src/ArduinoJson/Deserialization/deserialize.hpp +++ b/src/ArduinoJson/Deserialization/deserialize.hpp @@ -36,7 +36,7 @@ deserialize(TDocument &doc, const TString &input) { return makeDeserializer( doc.memoryPool(), makeReader(input), makeStringStorage(doc.memoryPool(), input), doc.nestingLimit) - .parse(doc.template to()); + .parse(doc.template to()); } // // DeserializationError deserialize(TDocument& doc, TChar* input); @@ -49,7 +49,7 @@ DeserializationError deserialize(TDocument &doc, TChar *input) { return makeDeserializer( doc.memoryPool(), makeReader(input), makeStringStorage(doc.memoryPool(), input), doc.nestingLimit) - .parse(doc.template to()); + .parse(doc.template to()); } // // DeserializationError deserialize(TDocument& doc, TChar* input, size_t @@ -64,7 +64,7 @@ DeserializationError deserialize(TDocument &doc, TChar *input, return makeDeserializer( doc.memoryPool(), makeReader(input, inputSize), makeStringStorage(doc.memoryPool(), input), doc.nestingLimit) - .parse(doc.template to()); + .parse(doc.template to()); } // // DeserializationError deserialize(TDocument& doc, TStream input); @@ -77,7 +77,7 @@ DeserializationError deserialize(TDocument &doc, TStream &input) { return makeDeserializer( doc.memoryPool(), makeReader(input), makeStringStorage(doc.memoryPool(), input), doc.nestingLimit) - .parse(doc.template to()); + .parse(doc.template to()); } } // namespace Internals } // namespace ArduinoJson diff --git a/src/ArduinoJson/DynamicJsonDocument.hpp b/src/ArduinoJson/DynamicJsonDocument.hpp index 91620af0..096604ee 100644 --- a/src/ArduinoJson/DynamicJsonDocument.hpp +++ b/src/ArduinoJson/DynamicJsonDocument.hpp @@ -4,8 +4,7 @@ #pragma once -#include "JsonArray.hpp" -#include "JsonObject.hpp" +#include "Data/JsonVariantTo.hpp" #include "JsonVariant.hpp" #include "Memory/DynamicMemoryPool.hpp" @@ -30,49 +29,10 @@ class DynamicJsonDocument { return getVariant().as(); } - // JsonObject to() template - typename Internals::enable_if::value, - JsonObject>::type - to() { - clear(); - JsonObject object(&_memoryPool); - getVariant().set(object); - return object; - } - - // JsonArray to() - template - typename Internals::enable_if::value, - JsonArray>::type - to() { - clear(); - JsonArray array(&_memoryPool); - getVariant().set(array); - return array; - } - - // JsonVariant to() - template - typename Internals::enable_if::value, - JsonVariant>::type - to() { - clear(); - return getVariant(); - } - - // JsonVariantData& to() - template - typename Internals::enable_if< - Internals::is_same::value, - Internals::JsonVariantData&>::type - to() { - clear(); - return _rootData; - } - - Internals::DynamicMemoryPool& memoryPool() { - return _memoryPool; + typename Internals::JsonVariantTo::type to() { + _memoryPool.clear(); + return getVariant().to(); } void clear() { @@ -85,8 +45,12 @@ class DynamicJsonDocument { } template - void visit(Visitor& visitor) const { - return _rootData.visit(visitor); + void accept(Visitor& visitor) const { + return getVariant().accept(visitor); + } + + Internals::DynamicMemoryPool& memoryPool() { + return _memoryPool; } private: diff --git a/src/ArduinoJson/Json/JsonDeserializer.hpp b/src/ArduinoJson/Json/JsonDeserializer.hpp index 38979616..e04cf9c8 100644 --- a/src/ArduinoJson/Json/JsonDeserializer.hpp +++ b/src/ArduinoJson/Json/JsonDeserializer.hpp @@ -25,7 +25,7 @@ class JsonDeserializer { _stringStorage(stringStorage), _nestingLimit(nestingLimit), _loaded(false) {} - DeserializationError parse(JsonVariantData &variant) { + DeserializationError parse(JsonVariant variant) { DeserializationError err = skipSpacesAndComments(); if (err) return err; @@ -65,12 +65,11 @@ class JsonDeserializer { return true; } - DeserializationError parseArray(JsonVariantData &variant) { + DeserializationError parseArray(JsonVariant variant) { if (_nestingLimit == 0) return DeserializationError::TooDeep; - JsonArrayData *array = new (_memoryPool) JsonArrayData; - if (!array) return DeserializationError::NoMemory; - variant.setArray(*array); + JsonArray array = variant.to(); + if (array.isNull()) return DeserializationError::NoMemory; // Check opening braket if (!eat('[')) return DeserializationError::InvalidInput; @@ -85,12 +84,12 @@ class JsonDeserializer { // Read each value for (;;) { // Allocate slot in array - JsonVariantData *value = array->addSlot(_memoryPool); - if (!value) return DeserializationError::NoMemory; + JsonVariant value = array.add(); + if (value.isInvalid()) return DeserializationError::NoMemory; // 1 - Parse value _nestingLimit--; - err = parse(*value); + err = parse(value); _nestingLimit++; if (err) return err; @@ -104,12 +103,11 @@ class JsonDeserializer { } } - DeserializationError parseObject(JsonVariantData &variant) { + DeserializationError parseObject(JsonVariant variant) { if (_nestingLimit == 0) return DeserializationError::TooDeep; - JsonObjectData *object = new (_memoryPool) JsonObjectData; - if (!object) return DeserializationError::NoMemory; - variant.setObject(*object); + JsonObject object = variant.to(); + if (object.isNull()) return DeserializationError::NoMemory; // Check opening brace if (!eat('{')) return DeserializationError::InvalidInput; @@ -134,12 +132,12 @@ class JsonDeserializer { if (!eat(':')) return DeserializationError::InvalidInput; // Allocate slot in object - JsonVariantData *value = object->addSlot(_memoryPool, key); - if (!value) return DeserializationError::NoMemory; + JsonVariant value = object.set(key); + if (value.isInvalid()) return DeserializationError::NoMemory; // Parse value _nestingLimit--; - err = parse(*value); + err = parse(value); _nestingLimit++; if (err) return err; @@ -157,7 +155,7 @@ class JsonDeserializer { } } - DeserializationError parseValue(JsonVariantData &variant) { + DeserializationError parseValue(JsonVariant variant) { if (isQuote(current())) { return parseStringValue(variant); } else { @@ -173,11 +171,11 @@ class JsonDeserializer { } } - DeserializationError parseStringValue(JsonVariantData &variant) { + DeserializationError parseStringValue(JsonVariant variant) { const char *value; DeserializationError err = parseQuotedString(&value); if (err) return err; - variant.setString(value); + variant.set(value); return DeserializationError::Ok; } @@ -235,7 +233,7 @@ class JsonDeserializer { return DeserializationError::Ok; } - DeserializationError parseNumericValue(JsonVariantData &result) { + DeserializationError parseNumericValue(JsonVariant result) { char buffer[64]; uint8_t n = 0; @@ -248,15 +246,15 @@ class JsonDeserializer { buffer[n] = 0; if (isInteger(buffer)) { - result.setInteger(parseInteger(buffer)); + result.set(parseInteger(buffer)); } else if (isFloat(buffer)) { - result.setFloat(parseFloat(buffer)); + result.set(parseFloat(buffer)); } else if (!strcmp(buffer, "true")) { - result.setBoolean(true); + result.set(true); } else if (!strcmp(buffer, "false")) { - result.setBoolean(false); + result.set(false); } else if (!strcmp(buffer, "null")) { - result.setNull(); + // already null } else { return DeserializationError::InvalidInput; } diff --git a/src/ArduinoJson/Json/JsonSerializer.hpp b/src/ArduinoJson/Json/JsonSerializer.hpp index 5891ff69..ba808e02 100644 --- a/src/ArduinoJson/Json/JsonSerializer.hpp +++ b/src/ArduinoJson/Json/JsonSerializer.hpp @@ -16,16 +16,16 @@ class JsonSerializer { public: JsonSerializer(TWriter &writer) : _writer(writer) {} - void acceptFloat(JsonFloat value) { + void visitFloat(JsonFloat value) { _writer.writeFloat(value); } - void acceptArray(const JsonArrayData &array) { + void visitArray(JsonArray array) { _writer.beginArray(); - JsonArrayData::const_iterator it = array.begin(); + JsonArray::iterator it = array.begin(); while (it != array.end()) { - it->visit(*this); + it->accept(*this); ++it; if (it == array.end()) break; @@ -36,14 +36,14 @@ class JsonSerializer { _writer.endArray(); } - void acceptObject(const JsonObjectData &object) { + void visitObject(JsonObject object) { _writer.beginObject(); - JsonObjectData::const_iterator it = object.begin(); + JsonObject::iterator it = object.begin(); while (it != object.end()) { - _writer.writeString(it->key); + _writer.writeString(it->key()); _writer.writeColon(); - it->value.visit(*this); + it->value().accept(*this); ++it; if (it == object.end()) break; @@ -54,29 +54,29 @@ class JsonSerializer { _writer.endObject(); } - void acceptString(const char *value) { + void visitString(const char *value) { _writer.writeString(value); } - void acceptRawJson(const char *data, size_t n) { + void visitRawJson(const char *data, size_t n) { // TODO for (size_t i = 0; i < n; i++) _writer.writeRaw(data[i]); } - void acceptNegativeInteger(JsonUInt value) { + void visitNegativeInteger(JsonUInt value) { _writer.writeRaw('-'); _writer.writeInteger(value); } - void acceptPositiveInteger(JsonUInt value) { + void visitPositiveInteger(JsonUInt value) { _writer.writeInteger(value); } - void acceptBoolean(bool value) { + void visitBoolean(bool value) { _writer.writeBoolean(value); } - void acceptNull() { + void visitNull() { _writer.writeRaw("null"); } diff --git a/src/ArduinoJson/JsonArray.hpp b/src/ArduinoJson/JsonArray.hpp index 92cf64b2..781d801d 100644 --- a/src/ArduinoJson/JsonArray.hpp +++ b/src/ArduinoJson/JsonArray.hpp @@ -4,13 +4,17 @@ #pragma once -#include "JsonArrayData.hpp" +#include "Data/JsonVariantData.hpp" #include "JsonArrayIterator.hpp" +// Returns the size (in bytes) of an array with n elements. +// Can be very handy to determine the size of a StaticMemoryPool. +#define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \ + ((NUMBER_OF_ELEMENTS) * sizeof(ArduinoJson::Internals::Slot)) + namespace ArduinoJson { class JsonObject; - namespace Internals { class JsonArraySubscript; } @@ -25,29 +29,52 @@ class JsonArray { FORCE_INLINE JsonArray(Internals::MemoryPool* buf, Internals::JsonArrayData* arr) : _memoryPool(buf), _data(arr) {} - FORCE_INLINE explicit JsonArray(Internals::MemoryPool* buf) - : _memoryPool(buf), _data(new (buf) Internals::JsonArrayData()) {} // Adds the specified value at the end of the array. // // bool add(TValue); // TValue = bool, long, int, short, float, double, serialized, JsonVariant, - // std::string, String, JsonArrayData, JsonObject + // std::string, String, JsonObject template FORCE_INLINE bool add(const T& value) { - return add_impl(value); + return add().set(value); + } + // Adds the specified value at the end of the array. + FORCE_INLINE bool add(JsonArray value) { + return add().set(value); } // // bool add(TValue); // TValue = char*, const char*, const FlashStringHelper* template FORCE_INLINE bool add(T* value) { - return add_impl(value); + return add().set(value); + } + + JsonVariant add() { + if (!_data) return JsonVariant(); + + Internals::Slot* slot = new (_memoryPool) Internals::Slot(); + if (!slot) return JsonVariant(); + + slot->next = 0; + + if (_data->tail) { + slot->prev = _data->tail; + _data->tail->next = slot; + _data->tail = slot; + } else { + slot->prev = 0; + _data->head = slot; + _data->tail = slot; + } + + return JsonVariant(_memoryPool, &slot->value); } FORCE_INLINE iterator begin() const { if (!_data) return iterator(); - return iterator(_memoryPool, _data->begin()); + return iterator(_memoryPool, _data->head); } FORCE_INLINE iterator end() const { @@ -83,6 +110,15 @@ class JsonArray { return ok; } + // Copy a JsonArray + bool copyFrom(JsonArray src) { + bool ok = _data != 0; + for (iterator it = src.begin(); it != src.end(); ++it) { + ok &= add(*it); + } + return ok; + } + // Exports a 1D array template FORCE_INLINE size_t copyTo(T (&array)[N]) const { @@ -115,8 +151,17 @@ class JsonArray { FORCE_INLINE const Internals::JsonArraySubscript operator[]( size_t index) const; - FORCE_INLINE bool operator==(const JsonArray& rhs) const { - return _data == rhs._data; + FORCE_INLINE bool operator==(JsonArray rhs) const { + iterator it1 = begin(); + iterator it2 = rhs.begin(); + for (;;) { + if (it1 == end() && it2 == rhs.end()) return true; + if (it1 == end()) return false; + if (it2 == end()) return false; + if (*it1 != *it2) return false; + ++it1; + ++it2; + } } // Gets the value at the specified index. @@ -137,7 +182,18 @@ class JsonArray { // Removes element at specified position. FORCE_INLINE void remove(iterator it) { if (!_data) return; - _data->remove(it.internal()); + + Internals::Slot* slot = it.internal(); + if (!slot) return; + + if (slot->prev) + slot->prev->next = slot->next; + else + _data->head = slot->next; + if (slot->next) + slot->next->prev = slot->prev; + else + _data->tail = slot->prev; } // Removes element at specified index. @@ -163,10 +219,24 @@ class JsonArray { if (!_data) return false; return set_impl(index, value); } + // Sets the value at specified index. + // + // bool add(size_t index, JsonArray); + template + FORCE_INLINE bool set(size_t index, JsonArray value) { + if (!_data) return false; + return get(index).set(value); + } FORCE_INLINE size_t size() const { if (!_data) return 0; - return _data->size(); + Internals::Slot* slot = _data->head; + size_t n = 0; + while (slot) { + slot = slot->next; + n++; + } + return n; } FORCE_INLINE bool isNull() const { @@ -174,11 +244,11 @@ class JsonArray { } template - FORCE_INLINE void visit(Visitor& visitor) const { + FORCE_INLINE void accept(Visitor& visitor) const { if (_data) - visitor.acceptArray(*_data); + visitor.visitArray(*this); else - visitor.acceptNull(); + visitor.visitNull(); } private: @@ -191,10 +261,7 @@ class JsonArray { template FORCE_INLINE bool add_impl(TValueRef value) { - if (!_data) return false; - iterator it = iterator(_memoryPool, _data->add(_memoryPool)); - if (it == end()) return false; - return it->set(value); + return add().set(value); } Internals::MemoryPool* _memoryPool; diff --git a/src/ArduinoJson/JsonArrayData.hpp b/src/ArduinoJson/JsonArrayData.hpp deleted file mode 100644 index 7f5ac342..00000000 --- a/src/ArduinoJson/JsonArrayData.hpp +++ /dev/null @@ -1,28 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2018 -// MIT License - -#pragma once - -#include "Data/JsonVariantData.hpp" -#include "Data/List.hpp" -#include "Memory/AllocableInMemoryPool.hpp" -#include "Polyfills/type_traits.hpp" - -// Returns the size (in bytes) of an array with n elements. -// Can be very handy to determine the size of a StaticMemoryPool. -#define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \ - (sizeof(ArduinoJson::Internals::JsonArrayData) + \ - (NUMBER_OF_ELEMENTS) * \ - sizeof(ArduinoJson::Internals::JsonArrayData::node_type)) - -namespace ArduinoJson { -namespace Internals { -struct JsonArrayData : List, AllocableInMemoryPool { - JsonVariantData* addSlot(MemoryPool* memoryPool) { - iterator it = add(memoryPool); - return it != end() ? &*it : 0; - } -}; -} // namespace Internals -} // namespace ArduinoJson diff --git a/src/ArduinoJson/JsonArrayImpl.hpp b/src/ArduinoJson/JsonArrayImpl.hpp index 9bffd904..11d4ea31 100644 --- a/src/ArduinoJson/JsonArrayImpl.hpp +++ b/src/ArduinoJson/JsonArrayImpl.hpp @@ -10,16 +10,10 @@ namespace ArduinoJson { inline JsonArray JsonArray::createNestedArray() { - if (!_data) return JsonArray(); - JsonArray array(_memoryPool); - if (!array.isNull()) add(array); - return array; + return add().to(); } inline JsonObject JsonArray::createNestedObject() { - if (!_data) return JsonObject(); - JsonObject object(_memoryPool); - if (!object.isNull()) add(object); - return object; + return add().to(); } } // namespace ArduinoJson diff --git a/src/ArduinoJson/JsonArrayIterator.hpp b/src/ArduinoJson/JsonArrayIterator.hpp index 7d83fbfa..85c74ee1 100644 --- a/src/ArduinoJson/JsonArrayIterator.hpp +++ b/src/ArduinoJson/JsonArrayIterator.hpp @@ -4,7 +4,7 @@ #pragma once -#include "Data/ListIterator.hpp" +#include "Data/Slot.hpp" #include "JsonVariant.hpp" namespace ArduinoJson { @@ -28,45 +28,46 @@ class JsonVariantPtr { }; class JsonArrayIterator { - typedef Internals::ListIterator internal_iterator; - public: - JsonArrayIterator() {} + JsonArrayIterator() : _slot(0) {} explicit JsonArrayIterator(Internals::MemoryPool *memoryPool, - internal_iterator iterator) - : _iterator(iterator), _memoryPool(memoryPool) {} + Internals::Slot *iterator) + : _memoryPool(memoryPool), _slot(iterator) {} JsonVariant operator*() const { - return JsonVariant(_memoryPool, &*_iterator); + return JsonVariant(_memoryPool, &_slot->value); } JsonVariantPtr operator->() { - return JsonVariantPtr(_memoryPool, &*_iterator); + return JsonVariantPtr(_memoryPool, &_slot->value); } bool operator==(const JsonArrayIterator &other) const { - return _iterator == other._iterator; + return _slot == other._slot; } bool operator!=(const JsonArrayIterator &other) const { - return _iterator != other._iterator; + return _slot != other._slot; } JsonArrayIterator &operator++() { - ++_iterator; + _slot = _slot->next; return *this; } JsonArrayIterator &operator+=(size_t distance) { - _iterator += distance; + while (distance && _slot) { + _slot = _slot->next; + distance--; + } return *this; } - internal_iterator internal() { - return _iterator; + Internals::Slot *internal() { + return _slot; } private: - internal_iterator _iterator; Internals::MemoryPool *_memoryPool; + Internals::Slot *_slot; }; } // namespace ArduinoJson diff --git a/src/ArduinoJson/JsonArraySubscript.hpp b/src/ArduinoJson/JsonArraySubscript.hpp index abd42bc6..125f14ca 100644 --- a/src/ArduinoJson/JsonArraySubscript.hpp +++ b/src/ArduinoJson/JsonArraySubscript.hpp @@ -57,6 +57,11 @@ class JsonArraySubscript : public JsonVariantBase { return _array.is(_index); } + template + FORCE_INLINE typename JsonVariantTo::type to() { + return _array.get(_index).to(); + } + // Replaces the value // // bool set(const TValue&) @@ -75,8 +80,8 @@ class JsonArraySubscript : public JsonVariantBase { } template - void visit(Visitor& visitor) const { - return _array.get(_index).visit(visitor); + void accept(Visitor& visitor) const { + return _array.get(_index).accept(visitor); } private: diff --git a/src/ArduinoJson/JsonObject.hpp b/src/ArduinoJson/JsonObject.hpp index c14026a4..4fdddbe8 100644 --- a/src/ArduinoJson/JsonObject.hpp +++ b/src/ArduinoJson/JsonObject.hpp @@ -4,14 +4,17 @@ #pragma once -#include "./JsonObjectData.hpp" #include "./JsonObjectIterator.hpp" +// Returns the size (in bytes) of an object with n elements. +// Can be very handy to determine the size of a StaticMemoryPool. +#define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \ + ((NUMBER_OF_ELEMENTS) * sizeof(ArduinoJson::Internals::Slot)) + namespace ArduinoJson { class JsonObject { friend class JsonVariant; - typedef Internals::JsonObjectData::iterator internal_iterator; public: typedef JsonObjectIterator iterator; @@ -20,12 +23,15 @@ class JsonObject { FORCE_INLINE JsonObject(Internals::MemoryPool* buf, Internals::JsonObjectData* object) : _memoryPool(buf), _data(object) {} - FORCE_INLINE explicit JsonObject(Internals::MemoryPool* buf) - : _memoryPool(buf), _data(new (buf) Internals::JsonObjectData()) {} FORCE_INLINE iterator begin() const { if (!_data) return iterator(); - return iterator(_memoryPool, _data->begin()); + return iterator(_memoryPool, _data->head); + } + + void clear() { + _data->head = 0; + _data->tail = 0; } // Tells weither the specified key is present and associated with a value. @@ -44,6 +50,15 @@ class JsonObject { return containsKey_impl(key); } + bool copyFrom(JsonObject src) { + bool ok = _data != 0; + clear(); + for (iterator it = src.begin(); it != src.end(); ++it) { + ok &= set(it->key(), it->value()); + } + return ok; + } + FORCE_INLINE iterator end() const { return iterator(); } @@ -155,13 +170,26 @@ class JsonObject { return Internals::JsonObjectSubscript(*this, key); } - FORCE_INLINE bool operator==(const JsonObject& rhs) const { - return _data == rhs._data; + FORCE_INLINE bool operator==(JsonObject rhs) const { + if (size() != rhs.size()) return false; + for (iterator it = begin(); it != end(); ++it) { + if (rhs.get(it->key()) != it->value()) return false; + } + return true; } FORCE_INLINE void remove(iterator it) { if (!_data) return; - _data->remove(it.internal()); + Internals::Slot* slot = it.internal(); + if (!slot) return; + if (slot->prev) + slot->prev->next = slot->next; + else + _data->head = slot->next; + if (slot->next) + slot->next->prev = slot->prev; + else + _data->tail = slot->prev; } // Removes the specified key and the associated value. @@ -188,7 +216,7 @@ class JsonObject { // std::string, String, JsonArray, JsonObject template FORCE_INLINE bool set(const TString& key, const TValue& value) { - return set_impl(key, value); + return set(key).set(value); } // // bool set(TKey, TValue); @@ -196,7 +224,7 @@ class JsonObject { // TValue = char*, const char*, const FlashStringHelper* template FORCE_INLINE bool set(const TString& key, TValue* value) { - return set_impl(key, value); + return set(key).set(value); } // // bool set(TKey, const TValue&); @@ -205,7 +233,7 @@ class JsonObject { // std::string, String, JsonArray, JsonObject template FORCE_INLINE bool set(TString* key, const TValue& value) { - return set_impl(key, value); + return set(key).set(value); } // // bool set(TKey, TValue); @@ -213,12 +241,28 @@ class JsonObject { // TValue = char*, const char*, const FlashStringHelper* template FORCE_INLINE bool set(TString* key, TValue* value) { - return set_impl(key, value); + return set(key).set(value); + } + + template + FORCE_INLINE JsonVariant set(TString* key) { + return set_impl(key); + } + + template + FORCE_INLINE JsonVariant set(const TString& key) { + return set_impl(key); } FORCE_INLINE size_t size() const { if (!_data) return 0; - return _data->size(); + size_t n = 0; + Internals::Slot* slot = _data->head; + while (slot) { + n++; + slot = slot->next; + } + return n; } FORCE_INLINE bool isNull() const { @@ -226,17 +270,17 @@ class JsonObject { } template - FORCE_INLINE void visit(Visitor& visitor) const { + FORCE_INLINE void accept(Visitor& visitor) const { if (_data) - visitor.acceptObject(*_data); + visitor.visitObject(*this); else - visitor.acceptNull(); + visitor.visitNull(); } private: template FORCE_INLINE bool containsKey_impl(TStringRef key) const { - return findKey(key) != _data->end(); + return findSlot(key) != 0; } template @@ -247,77 +291,95 @@ class JsonObject { // Returns the list node that matches the specified key. template - internal_iterator findKey(TStringRef key) { - if (!_data) return internal_iterator(); - internal_iterator it; - for (it = _data->begin(); it != _data->end(); ++it) { - if (Internals::makeString(key).equals(it->key)) break; + Internals::Slot* findSlot(TStringRef key) { + if (!_data) return 0; + Internals::Slot* slot = _data->head; + while (slot) { + if (Internals::makeString(key).equals(slot->key)) break; + slot = slot->next; } - return it; + return slot; } template - FORCE_INLINE internal_iterator findKey(TStringRef key) const { - return const_cast(this)->findKey(key); + FORCE_INLINE Internals::Slot* findSlot(TStringRef key) const { + return const_cast(this)->findSlot(key); } template FORCE_INLINE typename Internals::JsonVariantAs::type get_impl( TStringRef key) const { - internal_iterator it = findKey(key); - return it != _data->end() - ? JsonVariant(_memoryPool, &it->value).as() - : TValue(); + Internals::Slot* slot = findSlot(key); + return slot ? JsonVariant(_memoryPool, &slot->value).as() + : TValue(); } template FORCE_INLINE bool is_impl(TStringRef key) const { - internal_iterator it = findKey(key); - return it != _data->end() - ? JsonVariant(_memoryPool, &it->value).is() - : false; + Internals::Slot* slot = findSlot(key); + return slot ? JsonVariant(_memoryPool, &slot->value).is() : false; } template FORCE_INLINE void remove_impl(TStringRef key) { if (!_data) return; - _data->remove(findKey(key)); + Internals::Slot* slot = findSlot(key); + if (!slot) return; + if (slot->prev) + slot->prev->next = slot->next; + else + _data->head = slot->next; + if (slot->next) + slot->next->prev = slot->prev; + else + _data->tail = slot->prev; } - template - FORCE_INLINE bool set_impl(TStringRef key, TValueRef value) { - if (!_data) return false; + template + FORCE_INLINE JsonVariant set_impl(TStringRef key) { + if (!_data) return JsonVariant(); // ignore null key - if (Internals::makeString(key).is_null()) return false; + if (Internals::makeString(key).is_null()) return JsonVariant(); // search a matching key - internal_iterator it = findKey(key); - if (it == _data->end()) { + Internals::Slot* slot = findSlot(key); + if (!slot) { // add the key - // TODO: use JsonPairData directly, we don't need an iterator - it = _data->add(_memoryPool); - if (it == _data->end()) return false; - if (!set_key(it, key)) return false; + slot = new (_memoryPool) Internals::Slot(); + if (!slot) return JsonVariant(); + + slot->next = 0; + + if (_data->tail) { + slot->prev = _data->tail; + _data->tail->next = slot; + _data->tail = slot; + } else { + slot->prev = 0; + _data->head = slot; + _data->tail = slot; + } + + if (!set_key(slot, key)) return JsonVariant(); } - // save the value - return JsonVariant(_memoryPool, &it->value).set(value); + return JsonVariant(_memoryPool, &slot->value); } - FORCE_INLINE bool set_key(internal_iterator& it, const char* key) { - it->key = key; + FORCE_INLINE bool set_key(Internals::Slot* slot, const char* key) { + slot->key = key; return true; } template - FORCE_INLINE bool set_key(internal_iterator& it, const T& key) { + FORCE_INLINE bool set_key(Internals::Slot* slot, const T& key) { const char* dup = Internals::makeString(key).save(_memoryPool); if (!dup) return false; - it->key = dup; + slot->key = dup; return true; } mutable Internals::MemoryPool* _memoryPool; mutable Internals::JsonObjectData* _data; -}; +}; // namespace ArduinoJson } // namespace ArduinoJson diff --git a/src/ArduinoJson/JsonObjectData.hpp b/src/ArduinoJson/JsonObjectData.hpp deleted file mode 100644 index 6aa2851b..00000000 --- a/src/ArduinoJson/JsonObjectData.hpp +++ /dev/null @@ -1,30 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2018 -// MIT License - -#pragma once - -#include "Data/List.hpp" -#include "JsonPair.hpp" -#include "Memory/AllocableInMemoryPool.hpp" -#include "Polyfills/type_traits.hpp" - -// Returns the size (in bytes) of an object with n elements. -// Can be very handy to determine the size of a StaticMemoryPool. -#define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \ - (sizeof(ArduinoJson::Internals::JsonObjectData) + \ - (NUMBER_OF_ELEMENTS) * \ - sizeof(ArduinoJson::Internals::JsonObjectData::node_type)) - -namespace ArduinoJson { -namespace Internals { -struct JsonObjectData : List, AllocableInMemoryPool { - JsonVariantData* addSlot(MemoryPool* memoryPool, const char* key) { - iterator it = add(memoryPool); - if (it == end()) return 0; - it->key = key; - return &it->value; - } -}; -} // namespace Internals -} // namespace ArduinoJson diff --git a/src/ArduinoJson/JsonObjectImpl.hpp b/src/ArduinoJson/JsonObjectImpl.hpp index 90abcbb5..e04f674c 100644 --- a/src/ArduinoJson/JsonObjectImpl.hpp +++ b/src/ArduinoJson/JsonObjectImpl.hpp @@ -22,16 +22,12 @@ inline JsonArray JsonObject::createNestedArray(TString* key) { template inline JsonArray JsonObject::createNestedArray_impl(TStringRef key) { if (!_data) return JsonArray(); - JsonArray array(_memoryPool); - if (!array.isNull()) set(key, array); - return array; + return set(key).template to(); } template inline JsonObject JsonObject::createNestedObject_impl(TStringRef key) { if (!_data) return JsonObject(); - JsonObject object(_memoryPool); - if (!object.isNull()) set(key, object); - return object; + return set(key).template to(); } } // namespace ArduinoJson diff --git a/src/ArduinoJson/JsonObjectIterator.hpp b/src/ArduinoJson/JsonObjectIterator.hpp index cf61635c..15bf0154 100644 --- a/src/ArduinoJson/JsonObjectIterator.hpp +++ b/src/ArduinoJson/JsonObjectIterator.hpp @@ -4,15 +4,14 @@ #pragma once -#include "Data/ListIterator.hpp" #include "JsonPair.hpp" namespace ArduinoJson { class JsonPairPtr { public: - JsonPairPtr(Internals::MemoryPool *memoryPool, Internals::JsonPairData *data) - : _pair(memoryPool, data) {} + JsonPairPtr(Internals::MemoryPool *memoryPool, Internals::Slot *slot) + : _pair(memoryPool, slot) {} const JsonPair *operator->() const { return &_pair; @@ -26,47 +25,48 @@ class JsonPairPtr { JsonPair _pair; }; -// A read-write forward iterator for JsonArray class JsonObjectIterator { - typedef Internals::ListIterator internal_iterator; - public: - JsonObjectIterator() {} + JsonObjectIterator() : _slot(0) {} + explicit JsonObjectIterator(Internals::MemoryPool *memoryPool, - internal_iterator iterator) - : _memoryPool(memoryPool), _iterator(iterator) {} + Internals::Slot *slot) + : _memoryPool(memoryPool), _slot(slot) {} JsonPair operator*() const { - return JsonPair(_memoryPool, &*_iterator); + return JsonPair(_memoryPool, _slot); } JsonPairPtr operator->() { - return JsonPairPtr(_memoryPool, &*_iterator); + return JsonPairPtr(_memoryPool, _slot); } bool operator==(const JsonObjectIterator &other) const { - return _iterator == other._iterator; + return _slot == other._slot; } bool operator!=(const JsonObjectIterator &other) const { - return _iterator != other._iterator; + return _slot != other._slot; } JsonObjectIterator &operator++() { - ++_iterator; + if (_slot) _slot = _slot->next; return *this; } JsonObjectIterator &operator+=(size_t distance) { - _iterator += distance; + while (_slot && distance > 0) { + _slot = _slot->next; + distance--; + } return *this; } - internal_iterator internal() { - return _iterator; + Internals::Slot *internal() { + return _slot; } private: Internals::MemoryPool *_memoryPool; - internal_iterator _iterator; + Internals::Slot *_slot; }; } // namespace ArduinoJson diff --git a/src/ArduinoJson/JsonObjectSubscript.hpp b/src/ArduinoJson/JsonObjectSubscript.hpp index fba6e6d4..088a021c 100644 --- a/src/ArduinoJson/JsonObjectSubscript.hpp +++ b/src/ArduinoJson/JsonObjectSubscript.hpp @@ -64,6 +64,11 @@ class JsonObjectSubscript return _object.is(_key); } + template + FORCE_INLINE typename JsonVariantTo::type to() { + return _object.set(_key).template to(); + } + // Sets the specified value. // // bool set(const TValue&); @@ -84,8 +89,8 @@ class JsonObjectSubscript } template - void visit(Visitor &visitor) const { - return _object.get(_key).visit(visitor); + void accept(Visitor &visitor) const { + return _object.get(_key).accept(visitor); } private: diff --git a/src/ArduinoJson/JsonPair.hpp b/src/ArduinoJson/JsonPair.hpp index 71596abf..9e85c81b 100644 --- a/src/ArduinoJson/JsonPair.hpp +++ b/src/ArduinoJson/JsonPair.hpp @@ -8,19 +8,17 @@ namespace ArduinoJson { -namespace Internals { - -struct JsonPairData { - const char* key; - JsonVariantData value; -}; -} // namespace Internals - // A key value pair for JsonObjectData. class JsonPair { public: - JsonPair(Internals::MemoryPool* memoryPool, Internals::JsonPairData* data) - : _key(data->key), _value(memoryPool, &data->value) {} + JsonPair(Internals::MemoryPool* memoryPool, Internals::Slot* slot) { + if (slot) { + _key = slot->key; + _value = JsonVariant(memoryPool, &slot->value); + } else { + _key = 0; + } + } const char* key() const { return _key; diff --git a/src/ArduinoJson/JsonVariant.hpp b/src/ArduinoJson/JsonVariant.hpp index d35b49a5..30f7e56e 100644 --- a/src/ArduinoJson/JsonVariant.hpp +++ b/src/ArduinoJson/JsonVariant.hpp @@ -92,7 +92,7 @@ class JsonVariant : public Internals::JsonVariantBase { // set(SerializedValue) FORCE_INLINE bool set(Internals::SerializedValue value) { if (!_data) return false; - _data->setRaw(value.data(), value.size()); + _data->setLinkedRaw(value.data(), value.size()); return true; } @@ -108,7 +108,7 @@ class JsonVariant : public Internals::JsonVariantBase { const char *dup = Internals::makeString(value.data(), value.size()).save(_memoryPool); if (dup) - _data->setRaw(dup, value.size()); + _data->setOwnedRaw(dup, value.size()); else _data->setNull(); return true; @@ -124,7 +124,7 @@ class JsonVariant : public Internals::JsonVariantBase { if (!_data) return false; const char *dup = Internals::makeString(value).save(_memoryPool); if (dup) { - _data->setString(dup); + _data->setOwnedString(dup); return true; } else { _data->setNull(); @@ -141,7 +141,7 @@ class JsonVariant : public Internals::JsonVariantBase { if (!_data) return false; const char *dup = Internals::makeString(value).save(_memoryPool); if (dup) { - _data->setString(dup); + _data->setOwnedString(dup); return true; } else { _data->setNull(); @@ -152,22 +152,15 @@ class JsonVariant : public Internals::JsonVariantBase { // set(const char*); FORCE_INLINE bool set(const char *value) { if (!_data) return false; - _data->setString(value); + _data->setLinkedString(value); return true; } - FORCE_INLINE bool set(const JsonVariant &value) { - if (!_data) return false; - if (value._data) - *_data = *value._data; - else - _data->setNull(); - return true; - } + bool set(const JsonVariant &value); - FORCE_INLINE bool set(const JsonArray &array); + FORCE_INLINE bool set(JsonArray array); FORCE_INLINE bool set(const Internals::JsonArraySubscript &); - FORCE_INLINE bool set(const JsonObject &object); + FORCE_INLINE bool set(JsonObject object); template FORCE_INLINE bool set(const Internals::JsonObjectSubscript &); @@ -327,19 +320,37 @@ class JsonVariant : public Internals::JsonVariantBase { return _data && _data->isObject(); } - // Returns true if the variant has a value FORCE_INLINE bool isNull() const { return _data == 0 || _data->isNull(); } - template - FORCE_INLINE void visit(Visitor &visitor) const { - if (_data) - _data->visit(visitor); - else - visitor.acceptNull(); + FORCE_INLINE bool isInvalid() const { + return _data == 0; } + template + void accept(Visitor &visitor) const; + + // Change the type of the variant + // + // JsonArray to() + template + typename Internals::enable_if::value, + JsonArray>::type + to(); + // + // JsonObject to() + template + typename Internals::enable_if::value, + JsonObject>::type + to(); + // + // JsonObject to() + template + typename Internals::enable_if::value, + JsonVariant>::type + to(); + private: Internals::MemoryPool *_memoryPool; Internals::JsonVariantData *_data; diff --git a/src/ArduinoJson/JsonVariantImpl.hpp b/src/ArduinoJson/JsonVariantImpl.hpp index 02ea3fbf..42dfebd9 100644 --- a/src/ArduinoJson/JsonVariantImpl.hpp +++ b/src/ArduinoJson/JsonVariantImpl.hpp @@ -5,8 +5,6 @@ #pragma once #include "Configuration.hpp" -#include "JsonArrayData.hpp" -#include "JsonObjectData.hpp" #include "JsonVariant.hpp" #include "Numbers/parseFloat.hpp" #include "Numbers/parseInteger.hpp" @@ -15,26 +13,16 @@ namespace ArduinoJson { -inline bool JsonVariant::set(const JsonArray& array) { - if (!_data) return false; - if (array._data) - _data->setArray(*array._data); - else - _data->setNull(); - return true; +inline bool JsonVariant::set(JsonArray array) { + return to().copyFrom(array); } inline bool JsonVariant::set(const Internals::JsonArraySubscript& value) { return set(value.as()); } -inline bool JsonVariant::set(const JsonObject& object) { - if (!_data) return false; - if (object._data) - _data->setObject(*object._data); - else - _data->setNull(); - return true; +inline bool JsonVariant::set(JsonObject object) { + return to().copyFrom(object); } template @@ -43,6 +31,28 @@ inline bool JsonVariant::set( return set(value.template as()); } +inline bool JsonVariant::set(const JsonVariant& value) { + if (!_data) return false; + if (!value._data) { + _data->setNull(); + return true; + } + switch (value._data->type) { + case Internals::JSON_ARRAY: + return set(value.as()); + case Internals::JSON_OBJECT: + return set(value.as()); + case Internals::JSON_OWNED_STRING: + return set(const_cast(value._data->content.asString)); + case Internals::JSON_OWNED_RAW: + return set(serialized(const_cast(value._data->content.asRaw.data), + value._data->content.asRaw.size)); + default: + *_data = *value._data; + return true; + } +} + template inline typename Internals::enable_if< Internals::is_same::type, @@ -60,4 +70,69 @@ inline typename Internals::enable_if< JsonVariant::as() const { return _data ? JsonObject(_memoryPool, _data->asObject()) : JsonObject(); } + +template +inline typename Internals::enable_if::value, + JsonArray>::type +JsonVariant::to() { + if (!_data) return JsonArray(); + return JsonArray(_memoryPool, _data->toArray()); +} + +template +typename Internals::enable_if::value, + JsonObject>::type +JsonVariant::to() { + if (!_data) return JsonObject(); + return JsonObject(_memoryPool, _data->toObject()); +} + +template +typename Internals::enable_if::value, + JsonVariant>::type +JsonVariant::to() { + if (!_data) return JsonVariant(); + _data->setNull(); + return *this; +} + +template +inline void JsonVariant::accept(Visitor& visitor) const { + using namespace Internals; + if (!_data) return visitor.visitNull(); + + switch (_data->type) { + case JSON_FLOAT: + return visitor.visitFloat(_data->content.asFloat); + + case JSON_ARRAY: + return visitor.visitArray( + JsonArray(_memoryPool, &_data->content.asArray)); + + case JSON_OBJECT: + return visitor.visitObject( + JsonObject(_memoryPool, &_data->content.asObject)); + + case JSON_LINKED_STRING: + case JSON_OWNED_STRING: + return visitor.visitString(_data->content.asString); + + case JSON_LINKED_RAW: + case JSON_OWNED_RAW: + return visitor.visitRawJson(_data->content.asRaw.data, + _data->content.asRaw.size); + + case JSON_NEGATIVE_INTEGER: + return visitor.visitNegativeInteger(_data->content.asInteger); + + case JSON_POSITIVE_INTEGER: + return visitor.visitPositiveInteger(_data->content.asInteger); + + case JSON_BOOLEAN: + return visitor.visitBoolean(_data->content.asInteger != 0); + + default: + return visitor.visitNull(); + } +} } // namespace ArduinoJson diff --git a/src/ArduinoJson/Memory/AllocableInMemoryPool.hpp b/src/ArduinoJson/Memory/AllocableInMemoryPool.hpp index a8b414f4..fff91e83 100644 --- a/src/ArduinoJson/Memory/AllocableInMemoryPool.hpp +++ b/src/ArduinoJson/Memory/AllocableInMemoryPool.hpp @@ -12,7 +12,6 @@ namespace Internals { class AllocableInMemoryPool { public: void *operator new(size_t n, MemoryPool *memoryPool) NOEXCEPT { - if (!memoryPool) return NULL; return memoryPool->alloc(n); } diff --git a/src/ArduinoJson/Memory/DynamicMemoryPool.hpp b/src/ArduinoJson/Memory/DynamicMemoryPool.hpp index 3c775426..ff99e9d6 100644 --- a/src/ArduinoJson/Memory/DynamicMemoryPool.hpp +++ b/src/ArduinoJson/Memory/DynamicMemoryPool.hpp @@ -155,9 +155,9 @@ class DynamicMemoryPoolBase : public MemoryPool { // Implements a MemoryPool with dynamic memory allocation. // You are strongly encouraged to consider using StaticMemoryPool which is much // more suitable for embedded systems. -typedef Internals::DynamicMemoryPoolBase - DynamicMemoryPool; +typedef DynamicMemoryPoolBase DynamicMemoryPool; } // namespace Internals +} // namespace ArduinoJson #if defined(__clang__) #pragma clang diagnostic pop @@ -166,4 +166,3 @@ typedef Internals::DynamicMemoryPoolBase #pragma GCC diagnostic pop #endif #endif -} // namespace ArduinoJson diff --git a/src/ArduinoJson/Memory/StaticMemoryPool.hpp b/src/ArduinoJson/Memory/StaticMemoryPool.hpp index 16492799..a5de4e9d 100644 --- a/src/ArduinoJson/Memory/StaticMemoryPool.hpp +++ b/src/ArduinoJson/Memory/StaticMemoryPool.hpp @@ -107,12 +107,12 @@ class StaticMemoryPoolBase : public MemoryPool { // The template paramenter CAPACITY specifies the capacity of the memoryPool in // bytes. template -class StaticMemoryPool : public Internals::StaticMemoryPoolBase { - static const size_t ACTUAL_CAPACITY = Internals::Max<1, CAPACITY>::value; +class StaticMemoryPool : public StaticMemoryPoolBase { + static const size_t ACTUAL_CAPACITY = Max<1, CAPACITY>::value; public: explicit StaticMemoryPool() - : Internals::StaticMemoryPoolBase(_buffer, ACTUAL_CAPACITY) {} + : StaticMemoryPoolBase(_buffer, ACTUAL_CAPACITY) {} private: char _buffer[ACTUAL_CAPACITY]; diff --git a/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp b/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp index ecce8717..c1cd3182 100644 --- a/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp +++ b/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp @@ -24,17 +24,17 @@ class MsgPackDeserializer { _stringStorage(stringStorage), _nestingLimit(nestingLimit) {} - DeserializationError parse(JsonVariantData &variant) { + DeserializationError parse(JsonVariant variant) { uint8_t code; if (!readByte(code)) return DeserializationError::IncompleteInput; if ((code & 0x80) == 0) { - variant.setInteger(code); + variant.set(code); return DeserializationError::Ok; } if ((code & 0xe0) == 0xe0) { - variant.setInteger(static_cast(code)); + variant.set(static_cast(code)); return DeserializationError::Ok; } @@ -48,15 +48,15 @@ class MsgPackDeserializer { switch (code) { case 0xc0: - variant.setNull(); + // already null return DeserializationError::Ok; case 0xc2: - variant.setBoolean(false); + variant.set(false); return DeserializationError::Ok; case 0xc3: - variant.setBoolean(true); + variant.set(true); return DeserializationError::Ok; case 0xcc: @@ -171,54 +171,54 @@ class MsgPackDeserializer { } template - DeserializationError readInteger(JsonVariantData &variant) { + DeserializationError readInteger(JsonVariant variant) { T value; if (!readInteger(value)) return DeserializationError::IncompleteInput; - variant.setInteger(value); + variant.set(value); return DeserializationError::Ok; } template typename enable_if::type readFloat( - JsonVariantData &variant) { + JsonVariant variant) { T value; if (!readBytes(value)) return DeserializationError::IncompleteInput; fixEndianess(value); - variant.setFloat(value); + variant.set(value); return DeserializationError::Ok; } template typename enable_if::type readDouble( - JsonVariantData &variant) { + JsonVariant variant) { T value; if (!readBytes(value)) return DeserializationError::IncompleteInput; fixEndianess(value); - variant.setFloat(value); + variant.set(value); return DeserializationError::Ok; } template typename enable_if::type readDouble( - JsonVariantData &variant) { + JsonVariant variant) { uint8_t i[8]; // input is 8 bytes T value; // output is 4 bytes uint8_t *o = reinterpret_cast(&value); if (!readBytes(i, 8)) return DeserializationError::IncompleteInput; doubleToFloat(i, o); fixEndianess(value); - variant.setFloat(value); + variant.set(value); return DeserializationError::Ok; } template - DeserializationError readString(JsonVariantData &variant) { + DeserializationError readString(JsonVariant variant) { T size; if (!readInteger(size)) return DeserializationError::IncompleteInput; return readString(variant, size); } - DeserializationError readString(JsonVariantData &variant, size_t n) { + DeserializationError readString(JsonVariant variant, size_t n) { typename remove_reference::type::String str = _stringStorage.startString(); for (; n; --n) { @@ -228,33 +228,31 @@ class MsgPackDeserializer { } const char *s = str.c_str(); if (s == NULL) return DeserializationError::NoMemory; - variant.setString(s); + variant.set(s); return DeserializationError::Ok; } template - DeserializationError readArray(JsonVariantData &variant) { + DeserializationError readArray(JsonVariant variant) { TSize size; if (!readInteger(size)) return DeserializationError::IncompleteInput; return readArray(variant, size); } - DeserializationError readArray(JsonVariantData &variant, size_t n) { - JsonArrayData *array = new (_memoryPool) JsonArrayData; - if (!array) return DeserializationError::NoMemory; - - variant.setArray(*array); - return readArray(*array, n); + DeserializationError readArray(JsonVariant variant, size_t n) { + JsonArray array = variant.to(); + if (array.isNull()) return DeserializationError::NoMemory; + return readArray(array, n); } - DeserializationError readArray(JsonArrayData &array, size_t n) { + DeserializationError readArray(JsonArray array, size_t n) { if (_nestingLimit == 0) return DeserializationError::TooDeep; --_nestingLimit; for (; n; --n) { - JsonVariantData *value = array.addSlot(_memoryPool); - if (!value) return DeserializationError::NoMemory; + JsonVariant value = array.add(); + if (value.isInvalid()) return DeserializationError::NoMemory; - DeserializationError err = parse(*value); + DeserializationError err = parse(value); if (err) return err; } ++_nestingLimit; @@ -262,33 +260,33 @@ class MsgPackDeserializer { } template - DeserializationError readObject(JsonVariantData &variant) { + DeserializationError readObject(JsonVariant variant) { TSize size; if (!readInteger(size)) return DeserializationError::IncompleteInput; return readObject(variant, size); } - DeserializationError readObject(JsonVariantData &variant, size_t n) { - JsonObjectData *object = new (_memoryPool) JsonObjectData; - if (!object) return DeserializationError::NoMemory; - variant.setObject(*object); + DeserializationError readObject(JsonVariant variant, size_t n) { + JsonObject object = variant.to(); + if (object.isNull()) return DeserializationError::NoMemory; - return readObject(*object, n); + return readObject(object, n); } - DeserializationError readObject(JsonObjectData &object, size_t n) { + DeserializationError readObject(JsonObject object, size_t n) { if (_nestingLimit == 0) return DeserializationError::TooDeep; --_nestingLimit; for (; n; --n) { - JsonVariantData key; + JsonVariantData keyData; + JsonVariant key(_memoryPool, &keyData); DeserializationError err = parse(key); if (err) return err; - if (!key.isString()) return DeserializationError::NotSupported; + if (!keyData.isString()) return DeserializationError::NotSupported; - JsonVariantData *value = object.addSlot(_memoryPool, key.asString()); - if (!value) return DeserializationError::NoMemory; + JsonVariant value = object.set(keyData.asString()); + if (value.isInvalid()) return DeserializationError::NoMemory; - err = parse(*value); + err = parse(value); if (err) return err; } ++_nestingLimit; diff --git a/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp b/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp index 7162599a..109674dc 100644 --- a/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp +++ b/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp @@ -19,13 +19,13 @@ class MsgPackSerializer { MsgPackSerializer(TWriter& writer) : _writer(&writer), _bytesWritten(0) {} template - typename enable_if::type acceptFloat(T value32) { + typename enable_if::type visitFloat(T value32) { writeByte(0xCA); writeInteger(value32); } template - typename enable_if::type acceptFloat(T value64) { + typename enable_if::type visitFloat(T value64) { float value32 = float(value64); if (value32 == value64) { writeByte(0xCA); @@ -36,7 +36,7 @@ class MsgPackSerializer { } } - void acceptArray(const JsonArrayData& array) { + void visitArray(JsonArray array) { size_t n = array.size(); if (n < 0x10) { writeByte(uint8_t(0x90 + array.size())); @@ -47,13 +47,12 @@ class MsgPackSerializer { writeByte(0xDD); writeInteger(uint32_t(n)); } - for (JsonArrayData::const_iterator it = array.begin(); it != array.end(); - ++it) { - it->visit(*this); + for (JsonArray::iterator it = array.begin(); it != array.end(); ++it) { + it->accept(*this); } } - void acceptObject(const JsonObjectData& object) { + void visitObject(JsonObject object) { size_t n = object.size(); if (n < 0x10) { writeByte(uint8_t(0x80 + n)); @@ -64,14 +63,13 @@ class MsgPackSerializer { writeByte(0xDF); writeInteger(uint32_t(n)); } - for (JsonObjectData::const_iterator it = object.begin(); it != object.end(); - ++it) { - acceptString(it->key); - it->value.visit(*this); + for (JsonObject::iterator it = object.begin(); it != object.end(); ++it) { + visitString(it->key()); + it->value().accept(*this); } } - void acceptString(const char* value) { + void visitString(const char* value) { if (!value) return writeByte(0xC0); // nil size_t n = strlen(value); @@ -91,11 +89,11 @@ class MsgPackSerializer { writeBytes(reinterpret_cast(value), n); } - void acceptRawJson(const char* data, size_t size) { + void visitRawJson(const char* data, size_t size) { writeBytes(reinterpret_cast(data), size); } - void acceptNegativeInteger(JsonUInt value) { + void visitNegativeInteger(JsonUInt value) { JsonUInt negated = JsonUInt(~value + 1); if (value <= 0x20) { writeInteger(int8_t(negated)); @@ -117,7 +115,7 @@ class MsgPackSerializer { #endif } - void acceptPositiveInteger(JsonUInt value) { + void visitPositiveInteger(JsonUInt value) { if (value <= 0x7F) { writeInteger(uint8_t(value)); } else if (value <= 0xFF) { @@ -138,11 +136,11 @@ class MsgPackSerializer { #endif } - void acceptBoolean(bool value) { + void visitBoolean(bool value) { writeByte(value ? 0xC3 : 0xC2); } - void acceptNull() { + void visitNull() { writeByte(0xC0); } diff --git a/src/ArduinoJson/Serialization/measure.hpp b/src/ArduinoJson/Serialization/measure.hpp index 395e8c3b..77c24d2d 100644 --- a/src/ArduinoJson/Serialization/measure.hpp +++ b/src/ArduinoJson/Serialization/measure.hpp @@ -13,7 +13,7 @@ template