diff --git a/src/ArduinoJson.hpp b/src/ArduinoJson.hpp index 278828fa..77aae315 100644 --- a/src/ArduinoJson.hpp +++ b/src/ArduinoJson.hpp @@ -48,7 +48,6 @@ #include "ArduinoJson/Object/MemberProxy.hpp" #include "ArduinoJson/Object/ObjectImpl.hpp" #include "ArduinoJson/Variant/ConverterImpl.hpp" -#include "ArduinoJson/Variant/JsonVariantCopier.hpp" #include "ArduinoJson/Variant/VariantCompare.hpp" #include "ArduinoJson/Variant/VariantRefBaseImpl.hpp" diff --git a/src/ArduinoJson/Array/ArrayImpl.hpp b/src/ArduinoJson/Array/ArrayImpl.hpp index 8ff01deb..0c60b661 100644 --- a/src/ArduinoJson/Array/ArrayImpl.hpp +++ b/src/ArduinoJson/Array/ArrayImpl.hpp @@ -76,6 +76,31 @@ inline void VariantImpl::removeElement(size_t index) { removeElement(at(index)); } +inline bool VariantImpl::copyArray(const VariantImpl& src) { + ARDUINOJSON_ASSERT(isNull()); + + if (!data_) + return false; + + data_->toArray(); + + for (auto it = src.createIterator(); !it.done(); it.move()) { + auto slot = allocVariant(); + if (!slot) + return false; + + VariantImpl element(slot.ptr(), resources_); + if (!element.copyVariant(*it)) { + freeVariant(slot); + return false; + } + + addElement(slot); + } + + return true; +} + // Returns the size (in bytes) of an array with n elements. constexpr size_t sizeofArray(size_t n) { return n * sizeof(VariantData); diff --git a/src/ArduinoJson/Array/JsonArray.hpp b/src/ArduinoJson/Array/JsonArray.hpp index 7c2e8eb4..e66b9306 100644 --- a/src/ArduinoJson/Array/JsonArray.hpp +++ b/src/ArduinoJson/Array/JsonArray.hpp @@ -89,16 +89,8 @@ class JsonArray : public detail::VariantOperators { // Copies an array. // https://arduinojson.org/v7/api/jsonarray/set/ bool set(JsonArrayConst src) const { - if (isNull()) - return false; - - clear(); - for (auto element : src) { - if (!add(element)) - return false; - } - - return true; + impl_.clear(); + return impl_.copyArray(detail::VariantAttorney::getImpl(src)); } // Removes the element at the specified iterator. diff --git a/src/ArduinoJson/Collection/CollectionImpl.hpp b/src/ArduinoJson/Collection/CollectionImpl.hpp index 29cba09a..e1f8e8e5 100644 --- a/src/ArduinoJson/Collection/CollectionImpl.hpp +++ b/src/ArduinoJson/Collection/CollectionImpl.hpp @@ -18,8 +18,12 @@ inline VariantImpl::iterator VariantImpl::createIterator() const { return iterator(coll->head, resources_); } -inline void VariantImpl::appendPair(Slot key, - Slot value) { +inline void VariantImpl::addMember(Slot key, + Slot value) { + ARDUINOJSON_ASSERT(isObject()); + ARDUINOJSON_ASSERT(key); + ARDUINOJSON_ASSERT(value); + auto coll = getCollectionData(); key->next = value.id(); diff --git a/src/ArduinoJson/Json/JsonDeserializer.hpp b/src/ArduinoJson/Json/JsonDeserializer.hpp index 27df53c8..aab1a4b6 100644 --- a/src/ArduinoJson/Json/JsonDeserializer.hpp +++ b/src/ArduinoJson/Json/JsonDeserializer.hpp @@ -280,11 +280,18 @@ class JsonDeserializer { VariantImpl object(objectData, resources_); auto member = object.getMember(adaptString(key)); if (!member) { - auto keyVariant = object.addPair(&member); - if (!keyVariant) + auto keySlot = resources_->allocVariant(); + if (!keySlot) return DeserializationError::NoMemory; - stringBuilder_.save(keyVariant); + auto valueSlot = resources_->allocVariant(); + if (!valueSlot) + return DeserializationError::NoMemory; + + object.addMember(keySlot, valueSlot); + + stringBuilder_.save(keySlot.ptr()); + member = valueSlot.ptr(); } else { VariantImpl(member, resources_).clear(); } diff --git a/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp b/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp index f89e691d..fd153e2c 100644 --- a/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp +++ b/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp @@ -401,11 +401,18 @@ class MsgPackDeserializer { VariantData* member = 0; if (memberFilter.allow()) { - auto keyVariant = object.addPair(&member); - if (!keyVariant) + auto keySlot = resources_->allocVariant(); + if (!keySlot) return DeserializationError::NoMemory; - stringBuffer_.save(keyVariant); + auto valueSlot = resources_->allocVariant(); + if (!valueSlot) + return DeserializationError::NoMemory; + + object.addMember(keySlot, valueSlot); + + member = valueSlot.ptr(); + stringBuffer_.save(keySlot.ptr()); } err = parseVariant(member, memberFilter, nestingLimit.decrement()); diff --git a/src/ArduinoJson/Object/JsonObject.hpp b/src/ArduinoJson/Object/JsonObject.hpp index dc29d395..5ece4d69 100644 --- a/src/ArduinoJson/Object/JsonObject.hpp +++ b/src/ArduinoJson/Object/JsonObject.hpp @@ -83,16 +83,11 @@ class JsonObject : public detail::VariantOperators { // Copies an object. // https://arduinojson.org/v7/api/jsonobject/set/ bool set(JsonObjectConst src) { - if (isNull() || src.isNull()) + if (isNull() || + src.isNull()) // TODO: this check is not consistent with JsonArray return false; - - clear(); - for (auto kvp : src) { - if (!operator[](kvp.key()).set(kvp.value())) - return false; - } - - return true; + impl_.clear(); + return impl_.copyObject(detail::VariantAttorney::getImpl(src)); } // Gets or sets the member with specified key. diff --git a/src/ArduinoJson/Object/ObjectImpl.hpp b/src/ArduinoJson/Object/ObjectImpl.hpp index 1200bf4e..3ab70576 100644 --- a/src/ArduinoJson/Object/ObjectImpl.hpp +++ b/src/ArduinoJson/Object/ObjectImpl.hpp @@ -9,6 +9,46 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE +inline bool VariantImpl::copyObject(const VariantImpl& src) { + ARDUINOJSON_ASSERT(isNull()); + + if (!data_) + return false; + + data_->toObject(); + + for (auto it = src.createIterator(); !it.done(); it.move()) { + auto keySlot = allocVariant(); + if (!keySlot) + return false; + + auto key = VariantImpl(keySlot.ptr(), resources_); + if (!key.copyVariant(*it)) { + freeVariant(keySlot); + return false; + } + + it.move(); // move to value + ARDUINOJSON_ASSERT(!it.done()); + + auto valueSlot = allocVariant(); + if (!valueSlot) { + freeVariant(keySlot); + return false; + } + + // TODO: we add the pair before copying the value to be keep the old + // behavior but this is not consistent with issue #2081 + addMember(keySlot, valueSlot); + + auto value = VariantImpl(valueSlot.ptr(), resources_); + if (!value.copyVariant(*it)) + return false; + } + + return true; +} + template inline VariantData* VariantImpl::getMember(TAdaptedString key) const { auto it = findKey(key); @@ -70,28 +110,11 @@ inline VariantData* VariantImpl::addMember(TAdaptedString key) { if (!keyImpl.setString(key)) return nullptr; - VariantImpl::appendPair(keySlot, valueSlot); + addMember(keySlot, valueSlot); return valueSlot.ptr(); } -inline VariantData* VariantImpl::addPair(VariantData** value) { - ARDUINOJSON_ASSERT(isObject()); - - auto keySlot = allocVariant(); - if (!keySlot) - return nullptr; - - auto valueSlot = allocVariant(); - if (!valueSlot) - return nullptr; - *value = valueSlot.ptr(); - - VariantImpl::appendPair(keySlot, valueSlot); - - return keySlot.ptr(); -} - // Returns the size (in bytes) of an object with n members. constexpr size_t sizeofObject(size_t n) { return 2 * n * sizeof(VariantData); diff --git a/src/ArduinoJson/Variant/JsonVariant.hpp b/src/ArduinoJson/Variant/JsonVariant.hpp index 8cb3c402..a38daacc 100644 --- a/src/ArduinoJson/Variant/JsonVariant.hpp +++ b/src/ArduinoJson/Variant/JsonVariant.hpp @@ -37,14 +37,12 @@ class JsonVariant : public detail::VariantRefBase, mutable detail::VariantImpl impl_; }; -namespace detail { -bool copyVariant(JsonVariant dst, JsonVariantConst src); -} - template <> struct Converter : private detail::VariantAttorney { static bool toJson(JsonVariantConst src, JsonVariant dst) { - return copyVariant(dst, src); + auto impl = getImpl(dst); + impl.clear(); + return impl.copyVariant(getImpl(src)); } static JsonVariant fromJson(JsonVariant src) { @@ -59,7 +57,9 @@ struct Converter : private detail::VariantAttorney { template <> struct Converter : private detail::VariantAttorney { static bool toJson(JsonVariantConst src, JsonVariant dst) { - return copyVariant(dst, src); + auto impl = getImpl(dst); + impl.clear(); + return impl.copyVariant(getImpl(src)); } static JsonVariantConst fromJson(JsonVariantConst src) { diff --git a/src/ArduinoJson/Variant/JsonVariantCopier.hpp b/src/ArduinoJson/Variant/JsonVariantCopier.hpp deleted file mode 100644 index 6875c9ac..00000000 --- a/src/ArduinoJson/Variant/JsonVariantCopier.hpp +++ /dev/null @@ -1,34 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright © 2014-2025, Benoit BLANCHON -// MIT License - -#pragma once - -#include -#include - -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE - -class JsonVariantCopier { - public: - using result_type = bool; - - JsonVariantCopier(JsonVariant dst) : dst_(dst) {} - - template - bool visit(T src) { - return dst_.set(src); - } - - private: - JsonVariant dst_; -}; - -inline bool copyVariant(JsonVariant dst, JsonVariantConst src) { - if (dst.isUnbound()) - return false; - JsonVariantCopier copier(dst); - return accept(src, copier); -} - -ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/src/ArduinoJson/Variant/VariantData.hpp b/src/ArduinoJson/Variant/VariantData.hpp index 82b60b63..fb4046d2 100644 --- a/src/ArduinoJson/Variant/VariantData.hpp +++ b/src/ArduinoJson/Variant/VariantData.hpp @@ -85,17 +85,19 @@ struct VariantData { } VariantData* toArray() { + return toCollection(VariantType::Array); + } + + VariantData* toCollection(VariantType collectionType) { ARDUINOJSON_ASSERT(type == VariantType::Null); - type = VariantType::Array; + ARDUINOJSON_ASSERT(collectionType & VariantTypeBits::CollectionMask); + type = collectionType; new (&content.asCollection) CollectionData(); return this; } VariantData* toObject() { - ARDUINOJSON_ASSERT(type == VariantType::Null); - type = VariantType::Object; - new (&content.asCollection) CollectionData(); - return this; + return toCollection(VariantType::Object); } VariantData* getOrCreateArray() { diff --git a/src/ArduinoJson/Variant/VariantImpl.hpp b/src/ArduinoJson/Variant/VariantImpl.hpp index aa2e9fbe..746c8e27 100644 --- a/src/ArduinoJson/Variant/VariantImpl.hpp +++ b/src/ArduinoJson/Variant/VariantImpl.hpp @@ -276,7 +276,7 @@ class VariantImpl { VariantData* getOrAddElement(size_t index); - VariantData* addPair(VariantData** value); + void addMember(Slot key, Slot value); template VariantData* addMember(TAdaptedString key); @@ -354,6 +354,36 @@ class VariantImpl { void removeMember(iterator it); + bool copyVariant(const VariantImpl& src) { + switch (src.type()) { + case VariantType::Null: + return true; + + case VariantType::Array: + return copyArray(src); + + case VariantType::Object: + return copyObject(src); + + case VariantType::RawString: + return setRawString(adaptString(src.asRawString())); + + case VariantType::LinkedString: + return setLinkedString(src.asLinkedString()); + + case VariantType::OwnedString: + return setOwnedString(adaptString(src.asString())); + + default: + data_->content = src.data_->content; + data_->type = src.data_->type; + return true; + } + } + + bool copyArray(const VariantImpl& src); + bool copyObject(const VariantImpl& src); + bool setBoolean(bool value) { if (!data_) return false; @@ -548,8 +578,6 @@ class VariantImpl { iterator at(size_t index) const; - void appendPair(Slot key, Slot value); - void removeOne(iterator it); void removePair(iterator it);