Kaynağa Gözat

Release `VariantData` resources explicitly before setting value

Benoit Blanchon 1 yıl önce
ebeveyn
işleme
e682337655

+ 1 - 1
src/ArduinoJson/Json/JsonDeserializer.hpp

@@ -283,7 +283,7 @@ class JsonDeserializer {
           if (!member)
             return DeserializationError::NoMemory;
         } else {
-          member->setNull(resources_);
+          member->clear(resources_);
         }
 
         // Parse value

+ 1 - 1
src/ArduinoJson/Memory/ResourceManagerImpl.hpp

@@ -20,7 +20,7 @@ inline Slot<VariantData> ResourceManager::allocVariant() {
 }
 
 inline void ResourceManager::freeVariant(Slot<VariantData> variant) {
-  variant->setNull(this);
+  variant->clear(this);
   variantPools_.freeSlot(variant);
 }
 

+ 1 - 1
src/ArduinoJson/MsgPack/MsgPackBinary.hpp

@@ -29,6 +29,7 @@ struct Converter<MsgPackBinary> : private detail::VariantAttorney {
     if (!data)
       return;
     auto resources = getResourceManager(dst);
+    data->clear(resources);
     if (src.data()) {
       size_t headerSize = src.size() >= 0x10000 ? 5
                           : src.size() >= 0x100 ? 3
@@ -62,7 +63,6 @@ struct Converter<MsgPackBinary> : private detail::VariantAttorney {
         return;
       }
     }
-    data->setNull();
   }
 
   static MsgPackBinary fromJson(JsonVariantConst src) {

+ 1 - 1
src/ArduinoJson/MsgPack/MsgPackExtension.hpp

@@ -35,6 +35,7 @@ struct Converter<MsgPackExtension> : private detail::VariantAttorney {
     if (!data)
       return;
     auto resources = getResourceManager(dst);
+    data->clear(resources);
     if (src.data()) {
       uint8_t format, sizeBytes;
       if (src.size() >= 0x10000) {
@@ -76,7 +77,6 @@ struct Converter<MsgPackExtension> : private detail::VariantAttorney {
         return;
       }
     }
-    data->setNull();
   }
 
   static MsgPackExtension fromJson(JsonVariantConst src) {

+ 12 - 7
src/ArduinoJson/Variant/ConverterImpl.hpp

@@ -63,7 +63,9 @@ struct Converter<T, detail::enable_if_t<detail::is_integral<T>::value &&
     auto data = getData(dst);
     if (!data)
       return false;
-    data->setInteger(src, getResourceManager(dst));
+    auto resources = getResourceManager(dst);
+    data->clear(resources);
+    data->setInteger(src);
     return true;
   }
 
@@ -103,7 +105,9 @@ struct Converter<bool> : private detail::VariantAttorney {
     auto data = getData(dst);
     if (!data)
       return false;
-    data->setBoolean(src, getResourceManager(dst));
+    auto resources = getResourceManager(dst);
+    data->clear(resources);
+    data->setBoolean(src);
     return true;
   }
 
@@ -125,7 +129,9 @@ struct Converter<T, detail::enable_if_t<detail::is_floating_point<T>::value>>
     auto data = getData(dst);
     if (!data)
       return false;
-    data->setFloat(static_cast<JsonFloat>(src), getResourceManager(dst));
+    auto resources = getResourceManager(dst);
+    data->clear(resources);
+    data->setFloat(static_cast<JsonFloat>(src));
     return true;
   }
 
@@ -199,7 +205,7 @@ struct Converter<SerializedValue<T>> : private detail::VariantAttorney {
 template <>
 struct Converter<detail::nullptr_t> : private detail::VariantAttorney {
   static void toJson(detail::nullptr_t, JsonVariant dst) {
-    detail::VariantData::setNull(getData(dst), getResourceManager(dst));
+    detail::VariantData::clear(getData(dst), getResourceManager(dst));
   }
   static detail::nullptr_t fromJson(JsonVariantConst) {
     return nullptr;
@@ -252,12 +258,11 @@ inline void convertToJson(const ::Printable& src, JsonVariant dst) {
   auto data = detail::VariantAttorney::getData(dst);
   if (!resources || !data)
     return;
+  data->clear(resources);
   detail::StringBuilderPrint print(resources);
   src.printTo(print);
-  if (print.overflowed()) {
-    data->setNull();
+  if (print.overflowed())
     return;
-  }
   data->setOwnedString(print.save());
 }
 

+ 24 - 46
src/ArduinoJson/Variant/VariantData.hpp

@@ -344,64 +344,38 @@ class VariantData {
     var->removeMember(key, resources);
   }
 
-  void reset() {
+  void reset() {  // TODO: remove
     type_ = VALUE_IS_NULL;
   }
 
   void setBoolean(bool value) {
+    ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL);  // must call clear() first
     type_ = VALUE_IS_BOOLEAN;
     content_.asBoolean = value;
   }
 
-  void setBoolean(bool value, ResourceManager* resources) {
-    release(resources);
-    setBoolean(value);
-  }
-
   void setFloat(JsonFloat value) {
+    ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL);  // must call clear() first
     type_ = VALUE_IS_FLOAT;
     content_.asFloat = value;
   }
 
-  void setFloat(JsonFloat value, ResourceManager* resources) {
-    release(resources);
-    setFloat(value);
-  }
-
   template <typename T>
   enable_if_t<is_signed<T>::value> setInteger(T value) {
+    ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL);  // must call clear() first
     type_ = VALUE_IS_SIGNED_INTEGER;
     content_.asSignedInteger = value;
   }
 
   template <typename T>
   enable_if_t<is_unsigned<T>::value> setInteger(T value) {
+    ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL);  // must call clear() first
     type_ = VALUE_IS_UNSIGNED_INTEGER;
     content_.asUnsignedInteger = static_cast<JsonUInt>(value);
   }
 
-  template <typename T>
-  void setInteger(T value, ResourceManager* resources) {
-    release(resources);
-    setInteger(value);
-  }
-
-  void setNull() {
-    type_ = VALUE_IS_NULL;
-  }
-
-  void setNull(ResourceManager* resources) {
-    release(resources);
-    setNull();
-  }
-
-  static void setNull(VariantData* var, ResourceManager* resources) {
-    if (!var)
-      return;
-    var->setNull(resources);
-  }
-
   void setRawString(StringNode* s) {
+    ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL);  // must call clear() first
     ARDUINOJSON_ASSERT(s);
     type_ = VALUE_IS_RAW_STRING;
     content_.asOwnedString = s;
@@ -415,6 +389,7 @@ class VariantData {
                            ResourceManager* resources) {
     if (!var)
       return;
+    var->clear(resources);
     var->setRawString(value, resources);
   }
 
@@ -431,16 +406,19 @@ class VariantData {
                         ResourceManager* resources) {
     if (!var)
       return;
+    var->clear(resources);
     var->setString(value, resources);
   }
 
   void setLinkedString(const char* s) {
+    ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL);  // must call clear() first
     ARDUINOJSON_ASSERT(s);
     type_ = VALUE_IS_LINKED_STRING;
     content_.asLinkedString = s;
   }
 
   void setOwnedString(StringNode* s) {
+    ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL);  // must call clear() first
     ARDUINOJSON_ASSERT(s);
     type_ = VALUE_IS_OWNED_STRING;
     content_.asOwnedString = s;
@@ -461,45 +439,45 @@ class VariantData {
   }
 
   ArrayData& toArray() {
+    ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL);  // must call clear() first
     type_ = VALUE_IS_ARRAY;
     new (&content_.asArray) ArrayData();
     return content_.asArray;
   }
 
-  ArrayData& toArray(ResourceManager* resources) {
-    release(resources);
-    return toArray();
-  }
-
   static ArrayData* toArray(VariantData* var, ResourceManager* resources) {
     if (!var)
       return 0;
-    return &var->toArray(resources);
+    var->clear(resources);
+    return &var->toArray();
   }
 
   ObjectData& toObject() {
+    ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL);  // must call clear() first
     type_ = VALUE_IS_OBJECT;
     new (&content_.asObject) ObjectData();
     return content_.asObject;
   }
 
-  ObjectData& toObject(ResourceManager* resources) {
-    release(resources);
-    return toObject();
-  }
-
   static ObjectData* toObject(VariantData* var, ResourceManager* resources) {
     if (!var)
       return 0;
-    return &var->toObject(resources);
+    var->clear(resources);
+    return &var->toObject();
   }
 
   uint8_t type() const {
     return type_;
   }
 
- private:
-  void release(ResourceManager* resources);
+  // Release the resources used by this variant and set it to null.
+  void clear(ResourceManager* resources);
+
+  static void clear(VariantData* var, ResourceManager* resources) {
+    if (!var)
+      return;
+    var->clear(resources);
+  }
 };
 
 ARDUINOJSON_END_PRIVATE_NAMESPACE

+ 5 - 5
src/ArduinoJson/Variant/VariantImpl.hpp

@@ -12,18 +12,16 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
 template <typename T>
 inline void VariantData::setRawString(SerializedValue<T> value,
                                       ResourceManager* resources) {
-  release(resources);
+  ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL);  // must call clear() first
   auto dup = resources->saveString(adaptString(value.data(), value.size()));
   if (dup)
     setRawString(dup);
-  else
-    setNull();
 }
 
 template <typename TAdaptedString>
 inline bool VariantData::setString(TAdaptedString value,
                                    ResourceManager* resources) {
-  setNull(resources);
+  ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL);  // must call clear() first
 
   if (value.isNull())
     return false;
@@ -42,13 +40,15 @@ inline bool VariantData::setString(TAdaptedString value,
   return false;
 }
 
-inline void VariantData::release(ResourceManager* resources) {
+inline void VariantData::clear(ResourceManager* resources) {
   if (type_ & OWNED_VALUE_BIT)
     resources->dereferenceString(content_.asOwnedString->data);
 
   auto collection = asCollection();
   if (collection)
     collection->clear(resources);
+
+  type_ = VALUE_IS_NULL;
 }
 
 ARDUINOJSON_END_PRIVATE_NAMESPACE

+ 1 - 1
src/ArduinoJson/Variant/VariantRefBase.hpp

@@ -29,7 +29,7 @@ class VariantRefBase : public VariantTag {
   // Sets the value to null.
   // https://arduinojson.org/v7/api/jsonvariant/clear/
   void clear() const {
-    VariantData::setNull(getOrCreateData(), getResourceManager());
+    VariantData::clear(getOrCreateData(), getResourceManager());
   }
 
   // Returns true if the value is null or the reference is unbound.

+ 1 - 1
src/ArduinoJson/Variant/VariantRefBaseImpl.hpp

@@ -174,7 +174,7 @@ enable_if_t<is_same<T, JsonVariant>::value, JsonVariant>
 VariantRefBase<TDerived>::to() const {
   auto data = getOrCreateData();
   auto resources = getResourceManager();
-  detail::VariantData::setNull(data, resources);
+  detail::VariantData::clear(data, resources);
   return JsonVariant(data, resources);
 }