Kaynağa Gözat

VariantImpl: add copy functions

Benoit Blanchon 6 ay önce
ebeveyn
işleme
274fe06b33

+ 0 - 1
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"
 

+ 25 - 0
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);

+ 2 - 10
src/ArduinoJson/Array/JsonArray.hpp

@@ -89,16 +89,8 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
   // 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.

+ 6 - 2
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<VariantData> key,
-                                    Slot<VariantData> value) {
+inline void VariantImpl::addMember(Slot<VariantData> key,
+                                   Slot<VariantData> value) {
+  ARDUINOJSON_ASSERT(isObject());
+  ARDUINOJSON_ASSERT(key);
+  ARDUINOJSON_ASSERT(value);
+
   auto coll = getCollectionData();
 
   key->next = value.id();

+ 10 - 3
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();
         }

+ 10 - 3
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());

+ 4 - 9
src/ArduinoJson/Object/JsonObject.hpp

@@ -83,16 +83,11 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
   // 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.

+ 41 - 18
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 <typename TAdaptedString>
 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);

+ 6 - 6
src/ArduinoJson/Variant/JsonVariant.hpp

@@ -37,14 +37,12 @@ class JsonVariant : public detail::VariantRefBase<JsonVariant>,
   mutable detail::VariantImpl impl_;
 };
 
-namespace detail {
-bool copyVariant(JsonVariant dst, JsonVariantConst src);
-}
-
 template <>
 struct Converter<JsonVariant> : 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<JsonVariant> : private detail::VariantAttorney {
 template <>
 struct Converter<JsonVariantConst> : 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) {

+ 0 - 34
src/ArduinoJson/Variant/JsonVariantCopier.hpp

@@ -1,34 +0,0 @@
-// ArduinoJson - https://arduinojson.org
-// Copyright © 2014-2025, Benoit BLANCHON
-// MIT License
-
-#pragma once
-
-#include <ArduinoJson/Variant/JsonVariant.hpp>
-#include <ArduinoJson/Variant/JsonVariantVisitor.hpp>
-
-ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
-
-class JsonVariantCopier {
- public:
-  using result_type = bool;
-
-  JsonVariantCopier(JsonVariant dst) : dst_(dst) {}
-
-  template <typename T>
-  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

+ 7 - 5
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() {

+ 31 - 3
src/ArduinoJson/Variant/VariantImpl.hpp

@@ -276,7 +276,7 @@ class VariantImpl {
 
   VariantData* getOrAddElement(size_t index);
 
-  VariantData* addPair(VariantData** value);
+  void addMember(Slot<VariantData> key, Slot<VariantData> value);
 
   template <typename TAdaptedString>
   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<VariantData> key, Slot<VariantData> value);
-
   void removeOne(iterator it);
   void removePair(iterator it);