Release VariantData resources explicitly before setting value

This commit is contained in:
Benoit Blanchon
2024-08-26 15:09:56 +02:00
parent 4ada3f849c
commit e682337655
9 changed files with 47 additions and 64 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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