From f62d6f26e054985a80296f6cd50dc55cea4d3b85 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Fri, 4 Jul 2025 09:57:02 +0200 Subject: [PATCH] Merge `ArrayImpl`, `CollectionImpl`, and `ObjectImpl` into `VariantImpl` --- src/ArduinoJson/Array/ArrayData.hpp | 41 ----- src/ArduinoJson/Array/ArrayImpl.hpp | 27 ++-- src/ArduinoJson/Array/ElementProxy.hpp | 8 +- src/ArduinoJson/Array/JsonArray.hpp | 16 +- src/ArduinoJson/Array/JsonArrayConst.hpp | 6 +- src/ArduinoJson/Array/JsonArrayIterator.hpp | 8 +- src/ArduinoJson/Collection/CollectionData.hpp | 74 +-------- src/ArduinoJson/Collection/CollectionImpl.hpp | 42 +---- src/ArduinoJson/Document/JsonDocument.hpp | 14 +- src/ArduinoJson/Json/JsonDeserializer.hpp | 4 +- src/ArduinoJson/Json/JsonSerializer.hpp | 4 +- src/ArduinoJson/Json/PrettyJsonSerializer.hpp | 4 +- .../MsgPack/MsgPackDeserializer.hpp | 8 +- src/ArduinoJson/MsgPack/MsgPackSerializer.hpp | 4 +- src/ArduinoJson/Object/JsonObject.hpp | 20 ++- src/ArduinoJson/Object/JsonObjectConst.hpp | 6 +- src/ArduinoJson/Object/JsonObjectIterator.hpp | 8 +- src/ArduinoJson/Object/JsonPair.hpp | 4 +- src/ArduinoJson/Object/MemberProxy.hpp | 8 +- src/ArduinoJson/Object/ObjectData.hpp | 51 ------ src/ArduinoJson/Object/ObjectImpl.hpp | 27 ++-- src/ArduinoJson/Variant/JsonVariantConst.hpp | 3 + .../Variant/JsonVariantVisitor.hpp | 4 +- src/ArduinoJson/Variant/VariantAttorney.hpp | 5 - .../Variant/VariantDataVisitor.hpp | 10 +- src/ArduinoJson/Variant/VariantImpl.hpp | 148 ++++++++++++------ src/ArduinoJson/Variant/VariantRefBase.hpp | 16 +- .../Variant/VariantRefBaseImpl.hpp | 2 +- 28 files changed, 235 insertions(+), 337 deletions(-) delete mode 100644 src/ArduinoJson/Array/ArrayData.hpp delete mode 100644 src/ArduinoJson/Object/ObjectData.hpp diff --git a/src/ArduinoJson/Array/ArrayData.hpp b/src/ArduinoJson/Array/ArrayData.hpp deleted file mode 100644 index b6330476..00000000 --- a/src/ArduinoJson/Array/ArrayData.hpp +++ /dev/null @@ -1,41 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright © 2014-2025, Benoit BLANCHON -// MIT License - -#pragma once - -#include - -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE - -class ArrayImpl : public CollectionImpl { - public: - ArrayImpl() {} - - ArrayImpl(VariantData* data, ResourceManager* resources) - : CollectionImpl(data, resources) {} - - bool isNull() const { - return !data_ || data_->type != VariantType::Array; - } - - VariantData* addElement(); - - template - bool addValue(const T& value); - - VariantData* getOrAddElement(size_t index); - - VariantData* getElement(size_t index) const; - - void removeElement(size_t index); - - void remove(iterator it) { - CollectionImpl::removeOne(it); - } - - private: - iterator at(size_t index) const; -}; - -ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/src/ArduinoJson/Array/ArrayImpl.hpp b/src/ArduinoJson/Array/ArrayImpl.hpp index c73d5ccd..9bc66915 100644 --- a/src/ArduinoJson/Array/ArrayImpl.hpp +++ b/src/ArduinoJson/Array/ArrayImpl.hpp @@ -4,14 +4,13 @@ #pragma once -#include #include -#include +#include ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -inline ArrayImpl::iterator ArrayImpl::at(size_t index) const { - if (isNull()) +inline VariantImpl::iterator VariantImpl::at(size_t index) const { + if (!isArray()) return iterator(); auto it = createIterator(); @@ -22,17 +21,17 @@ inline ArrayImpl::iterator ArrayImpl::at(size_t index) const { return it; } -inline VariantData* ArrayImpl::addElement() { - if (isNull()) +inline VariantData* VariantImpl::addElement() { + if (!isArray()) return nullptr; auto slot = allocVariant(); if (!slot) return nullptr; - CollectionImpl::appendOne(slot); + VariantImpl::appendOne(slot); return slot.ptr(); } -inline VariantData* ArrayImpl::getOrAddElement(size_t index) { +inline VariantData* VariantImpl::getOrAddElement(size_t index) { auto it = createIterator(); while (!it.done() && index > 0) { it.next(resources_); @@ -50,17 +49,17 @@ inline VariantData* ArrayImpl::getOrAddElement(size_t index) { return element; } -inline VariantData* ArrayImpl::getElement(size_t index) const { +inline VariantData* VariantImpl::getElement(size_t index) const { return at(index).data(); } -inline void ArrayImpl::removeElement(size_t index) { - remove(at(index)); +inline void VariantImpl::removeElement(size_t index) { + removeElement(at(index)); } template -inline bool ArrayImpl::addValue(const T& value) { - if (isNull()) +inline bool VariantImpl::addValue(const T& value) { + if (!isArray()) return false; auto slot = allocVariant(); if (!slot) @@ -70,7 +69,7 @@ inline bool ArrayImpl::addValue(const T& value) { freeVariant(slot); return false; } - CollectionImpl::appendOne(slot); + appendOne(slot); return true; } diff --git a/src/ArduinoJson/Array/ElementProxy.hpp b/src/ArduinoJson/Array/ElementProxy.hpp index c42c2432..dab97388 100644 --- a/src/ArduinoJson/Array/ElementProxy.hpp +++ b/src/ArduinoJson/Array/ElementProxy.hpp @@ -59,8 +59,12 @@ class ElementProxy : public VariantRefBase>, } VariantData* getOrCreateData() const { - return VariantAttorney::getOrCreateVariantImpl(upstream_).getOrAddElement( - index_); + auto data = VariantAttorney::getOrCreateData(upstream_); + auto resources = VariantAttorney::getResourceManager(upstream_); + if (!data) + return nullptr; + data->getOrCreateArray(); + return VariantImpl(data, resources).getOrAddElement(index_); } TUpstream upstream_; diff --git a/src/ArduinoJson/Array/JsonArray.hpp b/src/ArduinoJson/Array/JsonArray.hpp index 74f1caf4..d3cc2a59 100644 --- a/src/ArduinoJson/Array/JsonArray.hpp +++ b/src/ArduinoJson/Array/JsonArray.hpp @@ -26,16 +26,19 @@ class JsonArray : public detail::VariantOperators { JsonArray(detail::VariantData* data, detail::ResourceManager* resources) : impl_(data, resources) {} + // INTERNAL USE ONLY + JsonArray(detail::VariantImpl impl) : impl_(impl) {} + // Returns a JsonVariant pointing to the array. // https://arduinojson.org/v7/api/jsonvariant/ operator JsonVariant() { - return JsonVariant(getData(), getResourceManager()); + return JsonVariant(impl_); } // Returns a read-only reference to the array. // https://arduinojson.org/v7/api/jsonarrayconst/ operator JsonArrayConst() const { - return JsonArrayConst(getData(), getResourceManager()); + return JsonArrayConst(impl_); } // Appends a new (empty) element to the array. @@ -101,7 +104,7 @@ class JsonArray : public detail::VariantOperators { // Removes the element at the specified iterator. // https://arduinojson.org/v7/api/jsonarray/remove/ void remove(iterator it) const { - impl_.remove(it.iterator_); + impl_.removeElement(it.iterator_); } // Removes the element at the specified index. @@ -122,7 +125,8 @@ class JsonArray : public detail::VariantOperators { // Removes all the elements of the array. // https://arduinojson.org/v7/api/jsonarray/clear/ void clear() const { - impl_.clear(); + if (impl_.isArray()) + impl_.empty(); } // Gets or sets the element at the specified index. @@ -145,7 +149,7 @@ class JsonArray : public detail::VariantOperators { } operator JsonVariantConst() const { - return JsonVariantConst(getData(), getResourceManager()); + return JsonVariantConst(impl_); } // Returns true if the reference is unbound. @@ -207,7 +211,7 @@ class JsonArray : public detail::VariantOperators { return impl_.getData(); } - mutable detail::ArrayImpl impl_; + mutable detail::VariantImpl impl_; }; ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/src/ArduinoJson/Array/JsonArrayConst.hpp b/src/ArduinoJson/Array/JsonArrayConst.hpp index feae9ab1..92463509 100644 --- a/src/ArduinoJson/Array/JsonArrayConst.hpp +++ b/src/ArduinoJson/Array/JsonArrayConst.hpp @@ -41,7 +41,7 @@ class JsonArrayConst : public detail::VariantOperators { : impl_(data, resources) {} // INTERNAL USE ONLY - JsonArrayConst(const detail::ArrayImpl& impl) : impl_(impl) {} + JsonArrayConst(const detail::VariantImpl& impl) : impl_(impl) {} // Returns the element at the specified index. // https://arduinojson.org/v7/api/jsonarrayconst/subscript/ @@ -64,7 +64,7 @@ class JsonArrayConst : public detail::VariantOperators { } operator JsonVariantConst() const { - return JsonVariantConst(impl_.getData(), impl_.getResourceManager()); + return JsonVariantConst(impl_); } // Returns true if the reference is unbound. @@ -102,7 +102,7 @@ class JsonArrayConst : public detail::VariantOperators { return impl_.getData(); } - detail::ArrayImpl impl_; + detail::VariantImpl impl_; }; // Compares the content of two arrays. diff --git a/src/ArduinoJson/Array/JsonArrayIterator.hpp b/src/ArduinoJson/Array/JsonArrayIterator.hpp index 1cc92647..b6aac521 100644 --- a/src/ArduinoJson/Array/JsonArrayIterator.hpp +++ b/src/ArduinoJson/Array/JsonArrayIterator.hpp @@ -30,7 +30,7 @@ class JsonArrayIterator { public: JsonArrayIterator() {} - explicit JsonArrayIterator(detail::ArrayImpl::iterator iterator, + explicit JsonArrayIterator(detail::VariantImpl::iterator iterator, detail::ResourceManager* resources) : iterator_(iterator), resources_(resources) {} @@ -55,7 +55,7 @@ class JsonArrayIterator { } private: - detail::ArrayImpl::iterator iterator_; + detail::VariantImpl::iterator iterator_; detail::ResourceManager* resources_; }; @@ -64,7 +64,7 @@ class JsonArrayConstIterator { public: JsonArrayConstIterator() {} - explicit JsonArrayConstIterator(detail::ArrayImpl::iterator iterator, + explicit JsonArrayConstIterator(detail::VariantImpl::iterator iterator, detail::ResourceManager* resources) : iterator_(iterator), resources_(resources) {} @@ -89,7 +89,7 @@ class JsonArrayConstIterator { } private: - mutable detail::ArrayImpl::iterator iterator_; + mutable detail::VariantImpl::iterator iterator_; mutable detail::ResourceManager* resources_; }; diff --git a/src/ArduinoJson/Collection/CollectionData.hpp b/src/ArduinoJson/Collection/CollectionData.hpp index f6a8451d..d8c1403b 100644 --- a/src/ArduinoJson/Collection/CollectionData.hpp +++ b/src/ArduinoJson/Collection/CollectionData.hpp @@ -15,7 +15,7 @@ struct VariantData; class ResourceManager; class CollectionIterator { - friend class CollectionImpl; + friend class VariantImpl; public: CollectionIterator() : slot_(nullptr), currentId_(NULL_SLOT) {} @@ -65,76 +65,4 @@ class CollectionIterator { SlotId currentId_; }; -class CollectionImpl { - protected: - VariantData* data_; - ResourceManager* resources_; - - public: - using iterator = CollectionIterator; - - CollectionImpl() : data_(nullptr), resources_(nullptr) {} - - CollectionImpl(VariantData* data, ResourceManager* resources) - : data_(data), resources_(resources) {} - - explicit operator bool() const { - return data_ && data_->isCollection(); - } - - bool isNull() const { - return !operator bool(); - } - - VariantData* getData() const { - return data_; - } - - ResourceManager* getResourceManager() const { - return resources_; - } - - iterator createIterator() const; - - size_t size() const; - size_t nesting() const; - - void clear(); - - SlotId head() const { - return getCollectionData()->head; - } - - protected: - void appendOne(Slot slot); - void appendPair(Slot key, Slot value); - - void removeOne(iterator it); - void removePair(iterator it); - - VariantData* getVariant(SlotId id) const { - ARDUINOJSON_ASSERT(resources_ != nullptr); - return resources_->getVariant(id); - } - - void freeVariant(Slot slot) { - ARDUINOJSON_ASSERT(resources_ != nullptr); - resources_->freeVariant(slot); - } - - Slot allocVariant() { - ARDUINOJSON_ASSERT(resources_ != nullptr); - return resources_->allocVariant(); - } - - private: - Slot getPreviousSlot(VariantData*) const; - - CollectionData* getCollectionData() const { - ARDUINOJSON_ASSERT(data_ != nullptr); - ARDUINOJSON_ASSERT(data_->isCollection()); - return &data_->content.asCollection; - } -}; - ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/src/ArduinoJson/Collection/CollectionImpl.hpp b/src/ArduinoJson/Collection/CollectionImpl.hpp index 42dc2c5e..d501c447 100644 --- a/src/ArduinoJson/Collection/CollectionImpl.hpp +++ b/src/ArduinoJson/Collection/CollectionImpl.hpp @@ -19,14 +19,14 @@ inline void CollectionIterator::next(const ResourceManager* resources) { currentId_ = nextId; } -inline CollectionImpl::iterator CollectionImpl::createIterator() const { +inline VariantImpl::iterator VariantImpl::createIterator() const { if (!data_ || !data_->isCollection()) return iterator(); auto coll = getCollectionData(); return iterator(getVariant(coll->head), coll->head); } -inline void CollectionImpl::appendOne(Slot slot) { +inline void VariantImpl::appendOne(Slot slot) { auto coll = getCollectionData(); if (coll->tail != NULL_SLOT) { @@ -39,8 +39,8 @@ inline void CollectionImpl::appendOne(Slot slot) { } } -inline void CollectionImpl::appendPair(Slot key, - Slot value) { +inline void VariantImpl::appendPair(Slot key, + Slot value) { auto coll = getCollectionData(); key->next = value.id(); @@ -54,26 +54,7 @@ inline void CollectionImpl::appendPair(Slot key, coll->tail = value.id(); } } - -inline void CollectionImpl::clear() { - if (!data_ || !data_->isCollection()) - return; - - auto coll = getCollectionData(); - - auto next = coll->head; - while (next != NULL_SLOT) { - auto currId = next; - auto slot = getVariant(next); - next = slot->next; - freeVariant({slot, currId}); - } - - coll->head = NULL_SLOT; - coll->tail = NULL_SLOT; -} - -inline Slot CollectionImpl::getPreviousSlot( +inline Slot VariantImpl::getPreviousSlot( VariantData* target) const { auto coll = getCollectionData(); auto prev = Slot(); @@ -88,7 +69,7 @@ inline Slot CollectionImpl::getPreviousSlot( return prev; } -inline void CollectionImpl::removeOne(iterator it) { +inline void VariantImpl::removeOne(iterator it) { if (it.done()) return; auto coll = getCollectionData(); @@ -104,7 +85,7 @@ inline void CollectionImpl::removeOne(iterator it) { freeVariant({it.slot_, it.currentId_}); } -inline void CollectionImpl::removePair(ObjectImpl::iterator it) { +inline void VariantImpl::removePair(VariantImpl::iterator it) { if (it.done()) return; @@ -121,7 +102,7 @@ inline void CollectionImpl::removePair(ObjectImpl::iterator it) { removeOne(it); } -inline size_t CollectionImpl::nesting() const { +inline size_t VariantImpl::nesting() const { if (!data_ || !data_->isCollection()) return 0; size_t maxChildNesting = 0; @@ -134,11 +115,4 @@ inline size_t CollectionImpl::nesting() const { return maxChildNesting + 1; } -inline size_t CollectionImpl::size() const { - size_t count = 0; - for (auto it = createIterator(); !it.done(); it.next(resources_)) - count++; - return count; -} - ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/src/ArduinoJson/Document/JsonDocument.hpp b/src/ArduinoJson/Document/JsonDocument.hpp index 5da7b0a6..4e2ed0eb 100644 --- a/src/ArduinoJson/Document/JsonDocument.hpp +++ b/src/ArduinoJson/Document/JsonDocument.hpp @@ -267,14 +267,14 @@ class JsonDocument : public detail::VariantOperators { template ::value, int> = 0> JsonVariant add() { - return JsonVariant(getVariantImpl().addElement(), &resources_); + return JsonVariant(getOrCreateArray().addElement(), &resources_); } // Appends a value to the root array. // https://arduinojson.org/v7/api/jsondocument/add/ template bool add(const TValue& value) { - return getVariantImpl().addValue(value); + return getOrCreateArray().addValue(value); } // Appends a value to the root array. @@ -282,7 +282,7 @@ class JsonDocument : public detail::VariantOperators { template ::value, int> = 0> bool add(TChar* value) { - return getVariantImpl().addValue(value); + return getOrCreateArray().addValue(value); } // Removes an element of the root array. @@ -392,6 +392,14 @@ class JsonDocument : public detail::VariantOperators { return detail::VariantImpl(&data_, &resources_); } + detail::VariantImpl getOrCreateArray() { + return detail::VariantImpl(data_.getOrCreateArray(), &resources_); + } + + detail::VariantImpl getOrCreateObject() { + return detail::VariantImpl(data_.getOrCreateObject(), &resources_); + } + JsonVariant getVariant() { return JsonVariant(&data_, &resources_); } diff --git a/src/ArduinoJson/Json/JsonDeserializer.hpp b/src/ArduinoJson/Json/JsonDeserializer.hpp index 1f29535e..27df53c8 100644 --- a/src/ArduinoJson/Json/JsonDeserializer.hpp +++ b/src/ArduinoJson/Json/JsonDeserializer.hpp @@ -173,7 +173,7 @@ class JsonDeserializer { // Read each value for (;;) { if (elementFilter.allow()) { - ArrayImpl array(arrayData, resources_); + VariantImpl array(arrayData, resources_); // Allocate slot in array VariantData* value = array.addElement(); @@ -277,7 +277,7 @@ class JsonDeserializer { TFilter memberFilter = filter[key]; if (memberFilter.allow()) { - ObjectImpl object(objectData, resources_); + VariantImpl object(objectData, resources_); auto member = object.getMember(adaptString(key)); if (!member) { auto keyVariant = object.addPair(&member); diff --git a/src/ArduinoJson/Json/JsonSerializer.hpp b/src/ArduinoJson/Json/JsonSerializer.hpp index 2c32d0e7..30b67cb4 100644 --- a/src/ArduinoJson/Json/JsonSerializer.hpp +++ b/src/ArduinoJson/Json/JsonSerializer.hpp @@ -19,7 +19,7 @@ class JsonSerializer : public VariantDataVisitor { JsonSerializer(TWriter writer, ResourceManager* resources) : formatter_(writer), resources_(resources) {} - size_t visit(const ArrayImpl& array) { + size_t visitArray(const VariantImpl& array) { write('['); auto slotId = array.head(); @@ -39,7 +39,7 @@ class JsonSerializer : public VariantDataVisitor { return bytesWritten(); } - size_t visit(const ObjectImpl& object) { + size_t visitObject(const VariantImpl& object) { write('{'); auto slotId = object.head(); diff --git a/src/ArduinoJson/Json/PrettyJsonSerializer.hpp b/src/ArduinoJson/Json/PrettyJsonSerializer.hpp index de6e1b1e..f8d01792 100644 --- a/src/ArduinoJson/Json/PrettyJsonSerializer.hpp +++ b/src/ArduinoJson/Json/PrettyJsonSerializer.hpp @@ -19,7 +19,7 @@ class PrettyJsonSerializer : public JsonSerializer { PrettyJsonSerializer(TWriter writer, ResourceManager* resources) : base(writer, resources), nesting_(0) {} - size_t visit(const ArrayImpl& array) { + size_t visitArray(const VariantImpl& array) { auto it = array.createIterator(); if (!it.done()) { base::write("[\r\n"); @@ -40,7 +40,7 @@ class PrettyJsonSerializer : public JsonSerializer { return this->bytesWritten(); } - size_t visit(const ObjectImpl& object) { + size_t visitObject(const VariantImpl& object) { auto it = object.createIterator(); if (!it.done()) { base::write("{\r\n"); diff --git a/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp b/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp index b423bdc2..f89e691d 100644 --- a/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp +++ b/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp @@ -349,10 +349,10 @@ class MsgPackDeserializer { bool allowArray = filter.allowArray(); - ArrayImpl array; + VariantImpl array; if (allowArray) { ARDUINOJSON_ASSERT(variant != 0); - array = ArrayImpl(variant->toArray(), resources_); + array = VariantImpl(variant->toArray(), resources_); } TFilter elementFilter = filter[0U]; @@ -385,10 +385,10 @@ class MsgPackDeserializer { if (nestingLimit.reached()) return DeserializationError::TooDeep; - ObjectImpl object; + VariantImpl object; if (filter.allowObject()) { ARDUINOJSON_ASSERT(variant != 0); - object = ObjectImpl(variant->toObject(), resources_); + object = VariantImpl(variant->toObject(), resources_); } for (; n; --n) { diff --git a/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp b/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp index 6b0122eb..41063e79 100644 --- a/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp +++ b/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp @@ -47,7 +47,7 @@ class MsgPackSerializer : public VariantDataVisitor { return bytesWritten(); } - size_t visit(const ArrayImpl& array) { + size_t visitArray(const VariantImpl& array) { size_t n = array.size(); if (n < 0x10) { writeByte(uint8_t(0x90 + n)); @@ -69,7 +69,7 @@ class MsgPackSerializer : public VariantDataVisitor { return bytesWritten(); } - size_t visit(const ObjectImpl& object) { + size_t visitObject(const VariantImpl& object) { size_t n = object.size(); if (n < 0x10) { writeByte(uint8_t(0x80 + n)); diff --git a/src/ArduinoJson/Object/JsonObject.hpp b/src/ArduinoJson/Object/JsonObject.hpp index b1fc5b2b..4c340e9b 100644 --- a/src/ArduinoJson/Object/JsonObject.hpp +++ b/src/ArduinoJson/Object/JsonObject.hpp @@ -26,28 +26,31 @@ class JsonObject : public detail::VariantOperators { JsonObject(detail::VariantData* data, detail::ResourceManager* resource) : impl_(data, resource) {} + // INTERNAL USE ONLY + JsonObject(detail::VariantImpl impl) : impl_(impl) {} + operator JsonVariant() const { - return JsonVariant(getData(), getResourceManager()); + return JsonVariant(impl_); } operator JsonObjectConst() const { - return JsonObjectConst(getData(), getResourceManager()); + return JsonObjectConst(impl_); } operator JsonVariantConst() const { - return JsonVariantConst(getData(), getResourceManager()); + return JsonVariantConst(impl_); } // Returns true if the reference is unbound. // https://arduinojson.org/v7/api/jsonobject/isnull/ bool isNull() const { - return impl_.isNull(); + return !operator bool(); } // Returns true if the reference is bound. // https://arduinojson.org/v7/api/jsonobject/isnull/ operator bool() const { - return !isNull(); + return impl_.isObject(); } // Returns the depth (nesting level) of the object. @@ -77,7 +80,8 @@ class JsonObject : public detail::VariantOperators { // Removes all the members of the object. // https://arduinojson.org/v7/api/jsonobject/clear/ void clear() const { - impl_.clear(); + if (impl_.isObject()) + impl_.empty(); } // Copies an object. @@ -127,7 +131,7 @@ class JsonObject : public detail::VariantOperators { // Removes the member at the specified iterator. // https://arduinojson.org/v7/api/jsonobject/remove/ FORCE_INLINE void remove(iterator it) const { - impl_.remove(it.iterator_); + impl_.removeMember(it.iterator_); } // Removes the member with the specified key. @@ -230,7 +234,7 @@ class JsonObject : public detail::VariantOperators { return impl_.getData(); } - mutable detail::ObjectImpl impl_; + mutable detail::VariantImpl impl_; }; ARDUINOJSON_END_PUBLIC_NAMESPACE diff --git a/src/ArduinoJson/Object/JsonObjectConst.hpp b/src/ArduinoJson/Object/JsonObjectConst.hpp index 9c4586eb..adec787e 100644 --- a/src/ArduinoJson/Object/JsonObjectConst.hpp +++ b/src/ArduinoJson/Object/JsonObjectConst.hpp @@ -26,10 +26,10 @@ class JsonObjectConst : public detail::VariantOperators { : impl_(data, resources) {} // INTERNAL USE ONLY - JsonObjectConst(const detail::ObjectImpl& impl) : impl_(impl) {} + JsonObjectConst(const detail::VariantImpl& impl) : impl_(impl) {} operator JsonVariantConst() const { - return JsonVariantConst(impl_.getData(), impl_.getResourceManager()); + return JsonVariantConst(impl_); } // Returns true if the reference is unbound. @@ -136,7 +136,7 @@ class JsonObjectConst : public detail::VariantOperators { return impl_.getData(); } - detail::ObjectImpl impl_; + detail::VariantImpl impl_; }; inline bool operator==(JsonObjectConst lhs, JsonObjectConst rhs) { diff --git a/src/ArduinoJson/Object/JsonObjectIterator.hpp b/src/ArduinoJson/Object/JsonObjectIterator.hpp index bf29930d..3adb25a5 100644 --- a/src/ArduinoJson/Object/JsonObjectIterator.hpp +++ b/src/ArduinoJson/Object/JsonObjectIterator.hpp @@ -14,7 +14,7 @@ class JsonObjectIterator { public: JsonObjectIterator() {} - explicit JsonObjectIterator(detail::ObjectImpl::iterator iterator, + explicit JsonObjectIterator(detail::VariantImpl::iterator iterator, detail::ResourceManager* resources) : iterator_(iterator), resources_(resources) {} @@ -40,7 +40,7 @@ class JsonObjectIterator { } private: - detail::ObjectImpl::iterator iterator_; + detail::VariantImpl::iterator iterator_; detail::ResourceManager* resources_; }; @@ -50,7 +50,7 @@ class JsonObjectConstIterator { public: JsonObjectConstIterator() {} - explicit JsonObjectConstIterator(detail::ObjectImpl::iterator iterator, + explicit JsonObjectConstIterator(detail::VariantImpl::iterator iterator, detail::ResourceManager* resources) : iterator_(iterator), resources_(resources) {} @@ -76,7 +76,7 @@ class JsonObjectConstIterator { } private: - detail::ObjectImpl::iterator iterator_; + detail::VariantImpl::iterator iterator_; detail::ResourceManager* resources_; }; diff --git a/src/ArduinoJson/Object/JsonPair.hpp b/src/ArduinoJson/Object/JsonPair.hpp index 1dcbd94e..ee310259 100644 --- a/src/ArduinoJson/Object/JsonPair.hpp +++ b/src/ArduinoJson/Object/JsonPair.hpp @@ -15,7 +15,7 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE class JsonPair { public: // INTERNAL USE ONLY - JsonPair(detail::ObjectImpl::iterator iterator, + JsonPair(detail::VariantImpl::iterator iterator, detail::ResourceManager* resources) { if (!iterator.done()) { detail::VariantImpl variant(iterator.data(), resources); @@ -44,7 +44,7 @@ class JsonPair { // https://arduinojson.org/v7/api/jsonobjectconst/begin_end/ class JsonPairConst { public: - JsonPairConst(detail::ObjectImpl::iterator iterator, + JsonPairConst(detail::VariantImpl::iterator iterator, detail::ResourceManager* resources) { if (!iterator.done()) { detail::VariantImpl variant(iterator.data(), resources); diff --git a/src/ArduinoJson/Object/MemberProxy.hpp b/src/ArduinoJson/Object/MemberProxy.hpp index 7bdd642b..693c1f72 100644 --- a/src/ArduinoJson/Object/MemberProxy.hpp +++ b/src/ArduinoJson/Object/MemberProxy.hpp @@ -60,8 +60,12 @@ class MemberProxy } VariantData* getOrCreateData() const { - return VariantAttorney::getOrCreateVariantImpl(upstream_).getOrAddMember( - key_); + auto data = VariantAttorney::getOrCreateData(upstream_); + auto resources = VariantAttorney::getResourceManager(upstream_); + if (!data) + return nullptr; + data->getOrCreateObject(); + return VariantImpl(data, resources).getOrAddMember(key_); } private: diff --git a/src/ArduinoJson/Object/ObjectData.hpp b/src/ArduinoJson/Object/ObjectData.hpp deleted file mode 100644 index 6e8ece08..00000000 --- a/src/ArduinoJson/Object/ObjectData.hpp +++ /dev/null @@ -1,51 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright © 2014-2025, Benoit BLANCHON -// MIT License - -#pragma once - -#include - -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE - -class VariantImpl; - -class ObjectImpl : public CollectionImpl { - public: - ObjectImpl() {} - - ObjectImpl(VariantData* data, ResourceManager* resources) - : CollectionImpl(data, resources) {} - - bool isNull() const { - return !data_ || data_->type != VariantType::Object; - } - - template - VariantData* addMember(TAdaptedString key); - - VariantData* addPair(VariantData** value); - - template - VariantData* getOrAddMember(TAdaptedString key); - - template - VariantData* getMember(TAdaptedString key) const; - - template - void removeMember(TAdaptedString key); - - void remove(iterator it) { - CollectionImpl::removePair(it); - } - - size_t size() const { - return CollectionImpl::size() / 2; - } - - private: - template - iterator findKey(TAdaptedString key) const; -}; - -ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/src/ArduinoJson/Object/ObjectImpl.hpp b/src/ArduinoJson/Object/ObjectImpl.hpp index 3be3757e..eceea9bc 100644 --- a/src/ArduinoJson/Object/ObjectImpl.hpp +++ b/src/ArduinoJson/Object/ObjectImpl.hpp @@ -4,14 +4,13 @@ #pragma once -#include #include -#include +#include ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE template -inline VariantData* ObjectImpl::getMember(TAdaptedString key) const { +inline VariantData* VariantImpl::getMember(TAdaptedString key) const { auto it = findKey(key); if (it.done()) return nullptr; @@ -20,7 +19,7 @@ inline VariantData* ObjectImpl::getMember(TAdaptedString key) const { } template -VariantData* ObjectImpl::getOrAddMember(TAdaptedString key) { +VariantData* VariantImpl::getOrAddMember(TAdaptedString key) { auto data = getMember(key); if (data) return data; @@ -28,8 +27,8 @@ VariantData* ObjectImpl::getOrAddMember(TAdaptedString key) { } template -inline ObjectImpl::iterator ObjectImpl::findKey(TAdaptedString key) const { - if (isNull()) +inline VariantImpl::iterator VariantImpl::findKey(TAdaptedString key) const { + if (!isObject()) return iterator(); if (key.isNull()) return iterator(); @@ -44,13 +43,13 @@ inline ObjectImpl::iterator ObjectImpl::findKey(TAdaptedString key) const { } template -inline void ObjectImpl::removeMember(TAdaptedString key) { - remove(findKey(key)); +inline void VariantImpl::removeMember(TAdaptedString key) { + removeMember(findKey(key)); } template -inline VariantData* ObjectImpl::addMember(TAdaptedString key) { - if (isNull()) +inline VariantData* VariantImpl::addMember(TAdaptedString key) { + if (!isObject()) return nullptr; auto keySlot = allocVariant(); @@ -65,13 +64,13 @@ inline VariantData* ObjectImpl::addMember(TAdaptedString key) { if (!keyImpl.setString(key)) return nullptr; - CollectionImpl::appendPair(keySlot, valueSlot); + VariantImpl::appendPair(keySlot, valueSlot); return valueSlot.ptr(); } -inline VariantData* ObjectImpl::addPair(VariantData** value) { - ARDUINOJSON_ASSERT(!isNull()); +inline VariantData* VariantImpl::addPair(VariantData** value) { + ARDUINOJSON_ASSERT(isObject()); auto keySlot = allocVariant(); if (!keySlot) @@ -82,7 +81,7 @@ inline VariantData* ObjectImpl::addPair(VariantData** value) { return nullptr; *value = valueSlot.ptr(); - CollectionImpl::appendPair(keySlot, valueSlot); + VariantImpl::appendPair(keySlot, valueSlot); return keySlot.ptr(); } diff --git a/src/ArduinoJson/Variant/JsonVariantConst.hpp b/src/ArduinoJson/Variant/JsonVariantConst.hpp index 46683926..61803ab5 100644 --- a/src/ArduinoJson/Variant/JsonVariantConst.hpp +++ b/src/ArduinoJson/Variant/JsonVariantConst.hpp @@ -42,6 +42,9 @@ class JsonVariantConst : public detail::VariantTag, detail::ResourceManager* resources) : impl_(data, resources) {} + // INTERNAL USE ONLY + explicit JsonVariantConst(detail::VariantImpl impl) : impl_(impl) {} + // Returns true if the value is null or the reference is unbound. // https://arduinojson.org/v7/api/jsonvariantconst/isnull/ bool isNull() const { diff --git a/src/ArduinoJson/Variant/JsonVariantVisitor.hpp b/src/ArduinoJson/Variant/JsonVariantVisitor.hpp index c27b64f7..02b7e4d5 100644 --- a/src/ArduinoJson/Variant/JsonVariantVisitor.hpp +++ b/src/ArduinoJson/Variant/JsonVariantVisitor.hpp @@ -28,11 +28,11 @@ class VisitorAdapter { VisitorAdapter(TVisitor& visitor) : visitor_(&visitor) {} - result_type visit(const ArrayImpl& array) { + result_type visitArray(const VariantImpl& array) { return visitor_->visit(JsonArrayConst(array)); } - result_type visit(const ObjectImpl& object) { + result_type visitObject(const VariantImpl& object) { return visitor_->visit(JsonObjectConst(object)); } diff --git a/src/ArduinoJson/Variant/VariantAttorney.hpp b/src/ArduinoJson/Variant/VariantAttorney.hpp index ee4f4c4b..d006ad65 100644 --- a/src/ArduinoJson/Variant/VariantAttorney.hpp +++ b/src/ArduinoJson/Variant/VariantAttorney.hpp @@ -31,11 +31,6 @@ class VariantAttorney { return VariantImpl(client.getData(), client.getResourceManager()); } - template - static VariantImpl getOrCreateVariantImpl(TClient& client) { - return VariantImpl(client.getOrCreateData(), client.getResourceManager()); - } - template static VariantData* getOrCreateData(TClient& client) { return client.getOrCreateData(); diff --git a/src/ArduinoJson/Variant/VariantDataVisitor.hpp b/src/ArduinoJson/Variant/VariantDataVisitor.hpp index 7df61874..fc4a8f3b 100644 --- a/src/ArduinoJson/Variant/VariantDataVisitor.hpp +++ b/src/ArduinoJson/Variant/VariantDataVisitor.hpp @@ -4,10 +4,8 @@ #pragma once -#include #include #include -#include ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE @@ -15,6 +13,14 @@ template struct VariantDataVisitor { using result_type = TResult; + TResult visitArray(const VariantImpl&) { + return TResult(); + } + + TResult visitObject(const VariantImpl&) { + return TResult(); + } + template TResult visit(const T&) { return TResult(); diff --git a/src/ArduinoJson/Variant/VariantImpl.hpp b/src/ArduinoJson/Variant/VariantImpl.hpp index 424afd65..eea08e4a 100644 --- a/src/ArduinoJson/Variant/VariantImpl.hpp +++ b/src/ArduinoJson/Variant/VariantImpl.hpp @@ -4,11 +4,10 @@ #pragma once -#include +#include #include #include #include -#include #include #include #include @@ -16,7 +15,12 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE class VariantImpl { + VariantData* data_; + ResourceManager* resources_; + public: + using iterator = CollectionIterator; + VariantImpl() : data_(nullptr), resources_(nullptr) {} VariantImpl(VariantData* data, ResourceManager* resources) @@ -48,10 +52,10 @@ class VariantImpl { #endif case VariantType::Array: - return visit.visit(ArrayImpl(data_, resources_)); + return visit.visitArray(VariantImpl(data_, resources_)); case VariantType::Object: - return visit.visit(ObjectImpl(data_, resources_)); + return visit.visitObject(VariantImpl(data_, resources_)); case VariantType::TinyString: return visit.visit(JsonString(data_->content.asTinyString)); @@ -89,18 +93,10 @@ class VariantImpl { } } - VariantData* addElement() { - if (!data_) - return nullptr; - return ArrayImpl(data_->getOrCreateArray(), resources_).addElement(); - } + VariantData* addElement(); template - bool addValue(const T& value) { - if (!data_) - return false; - return ArrayImpl(data_->getOrCreateArray(), resources_).addValue(value); - } + bool addValue(const T& value); bool asBoolean() const { if (!data_) @@ -262,31 +258,26 @@ class VariantImpl { } #endif - VariantData* getElement(size_t index) { - return ArrayImpl(data_, resources_).getElement(index); + SlotId head() const { + return getCollectionData()->head; } + iterator createIterator() const; + + VariantData* getElement(size_t index) const; + + VariantData* getOrAddElement(size_t index); + + VariantData* addPair(VariantData** value); + template - VariantData* getMember(TAdaptedString key) { - return ObjectImpl(data_, resources_).getMember(key); - } - - VariantData* getOrAddElement(size_t index) { - if (!data_) - return nullptr; - return ArrayImpl(data_->getOrCreateArray(), resources_) - .getOrAddElement(index); - } + VariantData* addMember(TAdaptedString key); template - VariantData* getOrAddMember(TAdaptedString key) { - if (key.isNull()) - return nullptr; - if (!data_) - return nullptr; - return ObjectImpl(data_->getOrCreateObject(), resources_) - .getOrAddMember(key); - } + VariantData* getMember(TAdaptedString key) const; + + template + VariantData* getOrAddMember(TAdaptedString key); bool isArray() const { return type() == VariantType::Array; @@ -340,17 +331,21 @@ class VariantImpl { return data_ && data_->isString(); } - size_t nesting() { - return CollectionImpl(data_, resources_).nesting(); + size_t nesting() const; + + void removeElement(iterator it) { + if (!isArray()) + return; + removeOne(it); } - void removeElement(size_t index) { - ArrayImpl(data_, resources_).removeElement(index); - } + void removeElement(size_t index); template - void removeMember(TAdaptedString key) { - ObjectImpl(data_, resources_).removeMember(key); + void removeMember(TAdaptedString key); + + void removeMember(iterator it) { + removePair(it); } bool setBoolean(bool value) { @@ -454,13 +449,21 @@ class VariantImpl { bool setLinkedString(const char* s); - size_t size() { - auto size = CollectionImpl(data_, resources_).size(); + void empty(); - if (data_ && data_->type == VariantType::Object) - size /= 2; + size_t size() const { + if (!data_) + return 0; - return size; + size_t count = 0; + + for (auto it = createIterator(); !it.done(); it.next(resources_)) + count++; + + if (data_->type == VariantType::Object) + count /= 2; // TODO: do this in JsonObject? + + return count; } VariantType type() const { @@ -471,8 +474,39 @@ class VariantImpl { void clear(); private: - VariantData* data_; - ResourceManager* resources_; + template + iterator findKey(TAdaptedString key) const; + + iterator at(size_t index) const; + + void appendOne(Slot slot); + void appendPair(Slot key, Slot value); + + void removeOne(iterator it); + void removePair(iterator it); + + VariantData* getVariant(SlotId id) const { + ARDUINOJSON_ASSERT(resources_ != nullptr); + return resources_->getVariant(id); + } + + void freeVariant(Slot slot) { + ARDUINOJSON_ASSERT(resources_ != nullptr); + resources_->freeVariant(slot); + } + + Slot allocVariant() { + ARDUINOJSON_ASSERT(resources_ != nullptr); + return resources_->allocVariant(); + } + + Slot getPreviousSlot(VariantData*) const; + + CollectionData* getCollectionData() const { + ARDUINOJSON_ASSERT(data_ != nullptr); + ARDUINOJSON_ASSERT(data_->isCollection()); + return &data_->content.asCollection; + } }; template @@ -536,9 +570,25 @@ inline void VariantImpl::clear() { resources_->freeEightByte(data_->content.asSlotId); #endif - CollectionImpl(data_, resources_).clear(); + if (data_->type & VariantTypeBits::CollectionMask) + empty(); data_->type = VariantType::Null; } +inline void VariantImpl::empty() { + auto coll = getCollectionData(); + + auto next = coll->head; + while (next != NULL_SLOT) { + auto currId = next; + auto slot = getVariant(next); + next = slot->next; + freeVariant({slot, currId}); + } + + coll->head = NULL_SLOT; + coll->tail = NULL_SLOT; +} + ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/src/ArduinoJson/Variant/VariantRefBase.hpp b/src/ArduinoJson/Variant/VariantRefBase.hpp index 3ad24fb8..4f86ccd1 100644 --- a/src/ArduinoJson/Variant/VariantRefBase.hpp +++ b/src/ArduinoJson/Variant/VariantRefBase.hpp @@ -120,14 +120,14 @@ class VariantRefBase : public VariantTag { // https://arduinojson.org/v7/api/jsonvariant/add/ template bool add(const T& value) const { - return getOrCreateVariantImpl().addValue(value); + return getOrCreateOrCreateArray().addValue(value); } // Appends a value to the array. // https://arduinojson.org/v7/api/jsonvariant/add/ template ::value, int> = 0> bool add(T* value) const { - return getOrCreateVariantImpl().addValue(value); + return getOrCreateOrCreateArray().addValue(value); } // Removes an element of the array. @@ -279,6 +279,18 @@ class VariantRefBase : public VariantTag { return VariantImpl(getOrCreateData(), getResourceManager()); } + VariantImpl getOrCreateOrCreateArray() const { + auto data = getOrCreateData(); + return VariantImpl(data ? data->getOrCreateArray() : nullptr, + getResourceManager()); + } + + VariantImpl getOrCreateOrCreateObject() const { + auto data = getOrCreateData(); + return VariantImpl(data ? data->getOrCreateObject() : nullptr, + getResourceManager()); + } + FORCE_INLINE ArduinoJson::JsonVariant getVariant() const; FORCE_INLINE ArduinoJson::JsonVariantConst getVariantConst() const { diff --git a/src/ArduinoJson/Variant/VariantRefBaseImpl.hpp b/src/ArduinoJson/Variant/VariantRefBaseImpl.hpp index 8a2da2f6..46624e63 100644 --- a/src/ArduinoJson/Variant/VariantRefBaseImpl.hpp +++ b/src/ArduinoJson/Variant/VariantRefBaseImpl.hpp @@ -69,7 +69,7 @@ inline void convertToJson(const VariantRefBase& src, template template ::value, int>> inline T VariantRefBase::add() const { - return JsonVariant(getOrCreateVariantImpl().addElement(), + return JsonVariant(getOrCreateOrCreateArray().addElement(), getResourceManager()); }