VariantImpl: remove addValue()

This removes the two-way dependency between `JsonVariant` and `VariantImpl`
This commit is contained in:
Benoit Blanchon
2025-07-20 14:56:06 +02:00
parent e86c6acf2e
commit f680598a2f
7 changed files with 60 additions and 53 deletions

View File

@ -5,7 +5,6 @@
#pragma once #pragma once
#include <ArduinoJson/Collection/CollectionIterator.hpp> #include <ArduinoJson/Collection/CollectionIterator.hpp>
#include <ArduinoJson/Variant/VariantCompare.hpp>
#include <ArduinoJson/Variant/VariantImpl.hpp> #include <ArduinoJson/Variant/VariantImpl.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
@ -28,10 +27,23 @@ inline VariantData* VariantImpl::addElement() {
auto slot = allocVariant(); auto slot = allocVariant();
if (!slot) if (!slot)
return nullptr; return nullptr;
VariantImpl::appendOne(slot); addElement(slot);
return slot.ptr(); return slot.ptr();
} }
inline void VariantImpl::addElement(Slot<VariantData> slot) {
auto coll = getCollectionData();
if (coll->tail != NULL_SLOT) {
auto tail = getVariant(coll->tail);
tail->next = slot.id();
coll->tail = slot.id();
} else {
coll->head = slot.id();
coll->tail = slot.id();
}
}
inline VariantData* VariantImpl::getOrAddElement(size_t index) { inline VariantData* VariantImpl::getOrAddElement(size_t index) {
auto it = createIterator(); auto it = createIterator();
while (!it.done() && index > 0) { while (!it.done() && index > 0) {
@ -64,22 +76,6 @@ inline void VariantImpl::removeElement(size_t index) {
removeElement(at(index)); removeElement(at(index));
} }
template <typename T>
inline bool VariantImpl::addValue(const T& value) {
if (!isArray())
return false;
auto slot = allocVariant();
if (!slot)
return false;
JsonVariant variant(slot.ptr(), resources_);
if (!variant.set(value)) {
freeVariant(slot);
return false;
}
appendOne(slot);
return true;
}
// Returns the size (in bytes) of an array with n elements. // Returns the size (in bytes) of an array with n elements.
constexpr size_t sizeofArray(size_t n) { constexpr size_t sizeofArray(size_t n) {
return n * sizeof(VariantData); return n * sizeof(VariantData);

View File

@ -25,6 +25,10 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
// INTERNAL USE ONLY // INTERNAL USE ONLY
JsonArray(detail::VariantImpl impl) : impl_(impl) {} JsonArray(detail::VariantImpl impl) : impl_(impl) {}
// INTERNAL USE ONLY
JsonArray(detail::VariantData* data, detail::ResourceManager* resources)
: impl_(data, resources) {}
// Returns a JsonVariant pointing to the array. // Returns a JsonVariant pointing to the array.
// https://arduinojson.org/v7/api/jsonvariant/ // https://arduinojson.org/v7/api/jsonvariant/
operator JsonVariant() { operator JsonVariant() {
@ -59,7 +63,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
// https://arduinojson.org/v7/api/jsonarray/add/ // https://arduinojson.org/v7/api/jsonarray/add/
template <typename T> template <typename T>
bool add(const T& value) const { bool add(const T& value) const {
return impl_.addValue(value); return doAdd(value);
} }
// Appends a value to the array. // Appends a value to the array.
@ -67,7 +71,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
template <typename T, template <typename T,
detail::enable_if_t<!detail::is_const<T>::value, int> = 0> detail::enable_if_t<!detail::is_const<T>::value, int> = 0>
bool add(T* value) const { bool add(T* value) const {
return impl_.addValue(value); return doAdd(value);
} }
// Returns an iterator to the first element of the array. // Returns an iterator to the first element of the array.
@ -203,6 +207,27 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
return impl_; return impl_;
} }
template <typename T>
bool doAdd(const T& value) const {
if (!impl_.isArray())
return false;
auto resources = impl_.resources();
ARDUINOJSON_ASSERT(resources != nullptr);
auto slot = resources->allocVariant();
if (!slot)
return false;
if (!JsonVariant(slot.ptr(), resources).set(value)) {
detail::VariantImpl(slot.ptr(), resources).clear();
resources->freeVariant(slot);
return false;
}
impl_.addElement(slot);
return true;
}
mutable detail::VariantImpl impl_; mutable detail::VariantImpl impl_;
}; };

View File

@ -18,19 +18,6 @@ inline VariantImpl::iterator VariantImpl::createIterator() const {
return iterator(coll->head, resources_); return iterator(coll->head, resources_);
} }
inline void VariantImpl::appendOne(Slot<VariantData> slot) {
auto coll = getCollectionData();
if (coll->tail != NULL_SLOT) {
auto tail = getVariant(coll->tail);
tail->next = slot.id();
coll->tail = slot.id();
} else {
coll->head = slot.id();
coll->tail = slot.id();
}
}
inline void VariantImpl::appendPair(Slot<VariantData> key, inline void VariantImpl::appendPair(Slot<VariantData> key,
Slot<VariantData> value) { Slot<VariantData> value) {
auto coll = getCollectionData(); auto coll = getCollectionData();

View File

@ -267,14 +267,14 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
template <typename T, detail::enable_if_t< template <typename T, detail::enable_if_t<
detail::is_same<T, JsonVariant>::value, int> = 0> detail::is_same<T, JsonVariant>::value, int> = 0>
JsonVariant add() { JsonVariant add() {
return JsonVariant(getOrCreateArray().addElement(), &resources_); return getOrCreateArray().add<T>();
} }
// Appends a value to the root array. // Appends a value to the root array.
// https://arduinojson.org/v7/api/jsondocument/add/ // https://arduinojson.org/v7/api/jsondocument/add/
template <typename TValue> template <typename TValue>
bool add(const TValue& value) { bool add(const TValue& value) {
return getOrCreateArray().addValue(value); return getOrCreateArray().add(value);
} }
// Appends a value to the root array. // Appends a value to the root array.
@ -282,7 +282,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
template <typename TChar, template <typename TChar,
detail::enable_if_t<!detail::is_const<TChar>::value, int> = 0> detail::enable_if_t<!detail::is_const<TChar>::value, int> = 0>
bool add(TChar* value) { bool add(TChar* value) {
return getOrCreateArray().addValue(value); return getOrCreateArray().add(value);
} }
// Removes an element of the root array. // Removes an element of the root array.
@ -396,8 +396,8 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
return {&data_, &resources_}; return {&data_, &resources_};
} }
detail::VariantImpl getOrCreateArray() { JsonArray getOrCreateArray() {
return detail::VariantImpl(data_.getOrCreateArray(), &resources_); return JsonArray(data_.getOrCreateArray(), &resources_);
} }
JsonVariant getVariant() { JsonVariant getVariant() {

View File

@ -97,9 +97,7 @@ class VariantImpl {
} }
VariantData* addElement(); VariantData* addElement();
void addElement(Slot<VariantData> slot);
template <typename T>
bool addValue(const T& value);
bool asBoolean() const { bool asBoolean() const {
if (!data_) if (!data_)
@ -550,7 +548,6 @@ class VariantImpl {
iterator at(size_t index) const; iterator at(size_t index) const;
void appendOne(Slot<VariantData> slot);
void appendPair(Slot<VariantData> key, Slot<VariantData> value); void appendPair(Slot<VariantData> key, Slot<VariantData> value);
void removeOne(iterator it); void removeOne(iterator it);

View File

@ -120,14 +120,14 @@ class VariantRefBase : public VariantTag {
// https://arduinojson.org/v7/api/jsonvariant/add/ // https://arduinojson.org/v7/api/jsonvariant/add/
template <typename T> template <typename T>
bool add(const T& value) const { bool add(const T& value) const {
return getOrCreateArray().addValue(value); return getOrCreateArray().add(value);
} }
// Appends a value to the array. // Appends a value to the array.
// https://arduinojson.org/v7/api/jsonvariant/add/ // https://arduinojson.org/v7/api/jsonvariant/add/
template <typename T, enable_if_t<!is_const<T>::value, int> = 0> template <typename T, enable_if_t<!is_const<T>::value, int> = 0>
bool add(T* value) const { bool add(T* value) const {
return getOrCreateArray().addValue(value); return getOrCreateArray().add(value);
} }
// Removes an element of the array. // Removes an element of the array.
@ -267,13 +267,7 @@ class VariantRefBase : public VariantTag {
return VariantAttorney::getOrCreateImpl(derived()); return VariantAttorney::getOrCreateImpl(derived());
} }
VariantImpl getOrCreateArray() const { JsonArray getOrCreateArray() const;
auto impl = getOrCreateImpl();
auto data = impl.data();
if (data)
data->getOrCreateArray();
return impl;
}
FORCE_INLINE ArduinoJson::JsonVariant getVariant() const; FORCE_INLINE ArduinoJson::JsonVariant getVariant() const;

View File

@ -69,8 +69,7 @@ inline bool convertToJson(const VariantRefBase<TDerived>& src,
template <typename TDerived> template <typename TDerived>
template <typename T, enable_if_t<is_same<T, JsonVariant>::value, int>> template <typename T, enable_if_t<is_same<T, JsonVariant>::value, int>>
inline T VariantRefBase<TDerived>::add() const { inline T VariantRefBase<TDerived>::add() const {
auto impl = getOrCreateArray(); return getOrCreateArray().template add<T>();
return JsonVariant(impl.addElement(), impl.resources());
} }
template <typename TDerived> template <typename TDerived>
@ -141,6 +140,15 @@ inline bool VariantRefBase<TDerived>::doSet(const T& value, true_type) const {
return TConverter::toJson(value, JsonVariant(impl)); return TConverter::toJson(value, JsonVariant(impl));
} }
template <typename TDerived>
inline JsonArray VariantRefBase<TDerived>::getOrCreateArray() const {
auto impl = getOrCreateImpl();
auto data = impl.data();
if (data)
data->getOrCreateArray();
return JsonArray(impl);
}
template <typename TDerived> template <typename TDerived>
template <typename T, enable_if_t<is_same<T, JsonArray>::value, int>> template <typename T, enable_if_t<is_same<T, JsonArray>::value, int>>
inline JsonArray VariantRefBase<TDerived>::to() const { inline JsonArray VariantRefBase<TDerived>::to() const {