Merge ArrayImpl, CollectionImpl, and ObjectImpl into VariantImpl

This commit is contained in:
Benoit Blanchon
2025-07-04 09:57:02 +02:00
parent 1f1227d595
commit f62d6f26e0
28 changed files with 235 additions and 337 deletions

View File

@ -1,41 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Collection/CollectionData.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class ArrayImpl : public CollectionImpl {
public:
ArrayImpl() {}
ArrayImpl(VariantData* data, ResourceManager* resources)
: CollectionImpl(data, resources) {}
bool isNull() const {
return !data_ || data_->type != VariantType::Array;
}
VariantData* addElement();
template <typename T>
bool addValue(const T& value);
VariantData* getOrAddElement(size_t index);
VariantData* getElement(size_t index) const;
void removeElement(size_t index);
void remove(iterator it) {
CollectionImpl::removeOne(it);
}
private:
iterator at(size_t index) const;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -4,14 +4,13 @@
#pragma once #pragma once
#include <ArduinoJson/Array/ArrayData.hpp>
#include <ArduinoJson/Variant/VariantCompare.hpp> #include <ArduinoJson/Variant/VariantCompare.hpp>
#include <ArduinoJson/Variant/VariantData.hpp> #include <ArduinoJson/Variant/VariantImpl.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
inline ArrayImpl::iterator ArrayImpl::at(size_t index) const { inline VariantImpl::iterator VariantImpl::at(size_t index) const {
if (isNull()) if (!isArray())
return iterator(); return iterator();
auto it = createIterator(); auto it = createIterator();
@ -22,17 +21,17 @@ inline ArrayImpl::iterator ArrayImpl::at(size_t index) const {
return it; return it;
} }
inline VariantData* ArrayImpl::addElement() { inline VariantData* VariantImpl::addElement() {
if (isNull()) if (!isArray())
return nullptr; return nullptr;
auto slot = allocVariant(); auto slot = allocVariant();
if (!slot) if (!slot)
return nullptr; return nullptr;
CollectionImpl::appendOne(slot); VariantImpl::appendOne(slot);
return slot.ptr(); return slot.ptr();
} }
inline VariantData* ArrayImpl::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) {
it.next(resources_); it.next(resources_);
@ -50,17 +49,17 @@ inline VariantData* ArrayImpl::getOrAddElement(size_t index) {
return element; return element;
} }
inline VariantData* ArrayImpl::getElement(size_t index) const { inline VariantData* VariantImpl::getElement(size_t index) const {
return at(index).data(); return at(index).data();
} }
inline void ArrayImpl::removeElement(size_t index) { inline void VariantImpl::removeElement(size_t index) {
remove(at(index)); removeElement(at(index));
} }
template <typename T> template <typename T>
inline bool ArrayImpl::addValue(const T& value) { inline bool VariantImpl::addValue(const T& value) {
if (isNull()) if (!isArray())
return false; return false;
auto slot = allocVariant(); auto slot = allocVariant();
if (!slot) if (!slot)
@ -70,7 +69,7 @@ inline bool ArrayImpl::addValue(const T& value) {
freeVariant(slot); freeVariant(slot);
return false; return false;
} }
CollectionImpl::appendOne(slot); appendOne(slot);
return true; return true;
} }

View File

@ -59,8 +59,12 @@ class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>,
} }
VariantData* getOrCreateData() const { VariantData* getOrCreateData() const {
return VariantAttorney::getOrCreateVariantImpl(upstream_).getOrAddElement( auto data = VariantAttorney::getOrCreateData(upstream_);
index_); auto resources = VariantAttorney::getResourceManager(upstream_);
if (!data)
return nullptr;
data->getOrCreateArray();
return VariantImpl(data, resources).getOrAddElement(index_);
} }
TUpstream upstream_; TUpstream upstream_;

View File

@ -26,16 +26,19 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
JsonArray(detail::VariantData* data, detail::ResourceManager* resources) JsonArray(detail::VariantData* data, detail::ResourceManager* resources)
: impl_(data, resources) {} : impl_(data, resources) {}
// INTERNAL USE ONLY
JsonArray(detail::VariantImpl impl) : impl_(impl) {}
// 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() {
return JsonVariant(getData(), getResourceManager()); return JsonVariant(impl_);
} }
// Returns a read-only reference to the array. // Returns a read-only reference to the array.
// https://arduinojson.org/v7/api/jsonarrayconst/ // https://arduinojson.org/v7/api/jsonarrayconst/
operator JsonArrayConst() const { operator JsonArrayConst() const {
return JsonArrayConst(getData(), getResourceManager()); return JsonArrayConst(impl_);
} }
// Appends a new (empty) element to the array. // Appends a new (empty) element to the array.
@ -101,7 +104,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
// Removes the element at the specified iterator. // Removes the element at the specified iterator.
// https://arduinojson.org/v7/api/jsonarray/remove/ // https://arduinojson.org/v7/api/jsonarray/remove/
void remove(iterator it) const { void remove(iterator it) const {
impl_.remove(it.iterator_); impl_.removeElement(it.iterator_);
} }
// Removes the element at the specified index. // Removes the element at the specified index.
@ -122,7 +125,8 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
// Removes all the elements of the array. // Removes all the elements of the array.
// https://arduinojson.org/v7/api/jsonarray/clear/ // https://arduinojson.org/v7/api/jsonarray/clear/
void clear() const { void clear() const {
impl_.clear(); if (impl_.isArray())
impl_.empty();
} }
// Gets or sets the element at the specified index. // Gets or sets the element at the specified index.
@ -145,7 +149,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
} }
operator JsonVariantConst() const { operator JsonVariantConst() const {
return JsonVariantConst(getData(), getResourceManager()); return JsonVariantConst(impl_);
} }
// Returns true if the reference is unbound. // Returns true if the reference is unbound.
@ -207,7 +211,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
return impl_.getData(); return impl_.getData();
} }
mutable detail::ArrayImpl impl_; mutable detail::VariantImpl impl_;
}; };
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@ -41,7 +41,7 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
: impl_(data, resources) {} : impl_(data, resources) {}
// INTERNAL USE ONLY // INTERNAL USE ONLY
JsonArrayConst(const detail::ArrayImpl& impl) : impl_(impl) {} JsonArrayConst(const detail::VariantImpl& impl) : impl_(impl) {}
// Returns the element at the specified index. // Returns the element at the specified index.
// https://arduinojson.org/v7/api/jsonarrayconst/subscript/ // https://arduinojson.org/v7/api/jsonarrayconst/subscript/
@ -64,7 +64,7 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
} }
operator JsonVariantConst() const { operator JsonVariantConst() const {
return JsonVariantConst(impl_.getData(), impl_.getResourceManager()); return JsonVariantConst(impl_);
} }
// Returns true if the reference is unbound. // Returns true if the reference is unbound.
@ -102,7 +102,7 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
return impl_.getData(); return impl_.getData();
} }
detail::ArrayImpl impl_; detail::VariantImpl impl_;
}; };
// Compares the content of two arrays. // Compares the content of two arrays.

View File

@ -30,7 +30,7 @@ class JsonArrayIterator {
public: public:
JsonArrayIterator() {} JsonArrayIterator() {}
explicit JsonArrayIterator(detail::ArrayImpl::iterator iterator, explicit JsonArrayIterator(detail::VariantImpl::iterator iterator,
detail::ResourceManager* resources) detail::ResourceManager* resources)
: iterator_(iterator), resources_(resources) {} : iterator_(iterator), resources_(resources) {}
@ -55,7 +55,7 @@ class JsonArrayIterator {
} }
private: private:
detail::ArrayImpl::iterator iterator_; detail::VariantImpl::iterator iterator_;
detail::ResourceManager* resources_; detail::ResourceManager* resources_;
}; };
@ -64,7 +64,7 @@ class JsonArrayConstIterator {
public: public:
JsonArrayConstIterator() {} JsonArrayConstIterator() {}
explicit JsonArrayConstIterator(detail::ArrayImpl::iterator iterator, explicit JsonArrayConstIterator(detail::VariantImpl::iterator iterator,
detail::ResourceManager* resources) detail::ResourceManager* resources)
: iterator_(iterator), resources_(resources) {} : iterator_(iterator), resources_(resources) {}
@ -89,7 +89,7 @@ class JsonArrayConstIterator {
} }
private: private:
mutable detail::ArrayImpl::iterator iterator_; mutable detail::VariantImpl::iterator iterator_;
mutable detail::ResourceManager* resources_; mutable detail::ResourceManager* resources_;
}; };

View File

@ -15,7 +15,7 @@ struct VariantData;
class ResourceManager; class ResourceManager;
class CollectionIterator { class CollectionIterator {
friend class CollectionImpl; friend class VariantImpl;
public: public:
CollectionIterator() : slot_(nullptr), currentId_(NULL_SLOT) {} CollectionIterator() : slot_(nullptr), currentId_(NULL_SLOT) {}
@ -65,76 +65,4 @@ class CollectionIterator {
SlotId currentId_; SlotId currentId_;
}; };
class CollectionImpl {
protected:
VariantData* data_;
ResourceManager* resources_;
public:
using iterator = CollectionIterator;
CollectionImpl() : data_(nullptr), resources_(nullptr) {}
CollectionImpl(VariantData* data, ResourceManager* resources)
: data_(data), resources_(resources) {}
explicit operator bool() const {
return data_ && data_->isCollection();
}
bool isNull() const {
return !operator bool();
}
VariantData* getData() const {
return data_;
}
ResourceManager* getResourceManager() const {
return resources_;
}
iterator createIterator() const;
size_t size() const;
size_t nesting() const;
void clear();
SlotId head() const {
return getCollectionData()->head;
}
protected:
void appendOne(Slot<VariantData> slot);
void appendPair(Slot<VariantData> key, Slot<VariantData> value);
void removeOne(iterator it);
void removePair(iterator it);
VariantData* getVariant(SlotId id) const {
ARDUINOJSON_ASSERT(resources_ != nullptr);
return resources_->getVariant(id);
}
void freeVariant(Slot<VariantData> slot) {
ARDUINOJSON_ASSERT(resources_ != nullptr);
resources_->freeVariant(slot);
}
Slot<VariantData> allocVariant() {
ARDUINOJSON_ASSERT(resources_ != nullptr);
return resources_->allocVariant();
}
private:
Slot<VariantData> getPreviousSlot(VariantData*) const;
CollectionData* getCollectionData() const {
ARDUINOJSON_ASSERT(data_ != nullptr);
ARDUINOJSON_ASSERT(data_->isCollection());
return &data_->content.asCollection;
}
};
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -19,14 +19,14 @@ inline void CollectionIterator::next(const ResourceManager* resources) {
currentId_ = nextId; currentId_ = nextId;
} }
inline CollectionImpl::iterator CollectionImpl::createIterator() const { inline VariantImpl::iterator VariantImpl::createIterator() const {
if (!data_ || !data_->isCollection()) if (!data_ || !data_->isCollection())
return iterator(); return iterator();
auto coll = getCollectionData(); auto coll = getCollectionData();
return iterator(getVariant(coll->head), coll->head); return iterator(getVariant(coll->head), coll->head);
} }
inline void CollectionImpl::appendOne(Slot<VariantData> slot) { inline void VariantImpl::appendOne(Slot<VariantData> slot) {
auto coll = getCollectionData(); auto coll = getCollectionData();
if (coll->tail != NULL_SLOT) { if (coll->tail != NULL_SLOT) {
@ -39,8 +39,8 @@ inline void CollectionImpl::appendOne(Slot<VariantData> slot) {
} }
} }
inline void CollectionImpl::appendPair(Slot<VariantData> key, inline void VariantImpl::appendPair(Slot<VariantData> key,
Slot<VariantData> value) { Slot<VariantData> value) {
auto coll = getCollectionData(); auto coll = getCollectionData();
key->next = value.id(); key->next = value.id();
@ -54,26 +54,7 @@ inline void CollectionImpl::appendPair(Slot<VariantData> key,
coll->tail = value.id(); coll->tail = value.id();
} }
} }
inline Slot<VariantData> VariantImpl::getPreviousSlot(
inline void CollectionImpl::clear() {
if (!data_ || !data_->isCollection())
return;
auto coll = getCollectionData();
auto next = coll->head;
while (next != NULL_SLOT) {
auto currId = next;
auto slot = getVariant(next);
next = slot->next;
freeVariant({slot, currId});
}
coll->head = NULL_SLOT;
coll->tail = NULL_SLOT;
}
inline Slot<VariantData> CollectionImpl::getPreviousSlot(
VariantData* target) const { VariantData* target) const {
auto coll = getCollectionData(); auto coll = getCollectionData();
auto prev = Slot<VariantData>(); auto prev = Slot<VariantData>();
@ -88,7 +69,7 @@ inline Slot<VariantData> CollectionImpl::getPreviousSlot(
return prev; return prev;
} }
inline void CollectionImpl::removeOne(iterator it) { inline void VariantImpl::removeOne(iterator it) {
if (it.done()) if (it.done())
return; return;
auto coll = getCollectionData(); auto coll = getCollectionData();
@ -104,7 +85,7 @@ inline void CollectionImpl::removeOne(iterator it) {
freeVariant({it.slot_, it.currentId_}); freeVariant({it.slot_, it.currentId_});
} }
inline void CollectionImpl::removePair(ObjectImpl::iterator it) { inline void VariantImpl::removePair(VariantImpl::iterator it) {
if (it.done()) if (it.done())
return; return;
@ -121,7 +102,7 @@ inline void CollectionImpl::removePair(ObjectImpl::iterator it) {
removeOne(it); removeOne(it);
} }
inline size_t CollectionImpl::nesting() const { inline size_t VariantImpl::nesting() const {
if (!data_ || !data_->isCollection()) if (!data_ || !data_->isCollection())
return 0; return 0;
size_t maxChildNesting = 0; size_t maxChildNesting = 0;
@ -134,11 +115,4 @@ inline size_t CollectionImpl::nesting() const {
return maxChildNesting + 1; return maxChildNesting + 1;
} }
inline size_t CollectionImpl::size() const {
size_t count = 0;
for (auto it = createIterator(); !it.done(); it.next(resources_))
count++;
return count;
}
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

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(getVariantImpl().addElement(), &resources_); return JsonVariant(getOrCreateArray().addElement(), &resources_);
} }
// 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 getVariantImpl().addValue(value); return getOrCreateArray().addValue(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 getVariantImpl().addValue(value); return getOrCreateArray().addValue(value);
} }
// Removes an element of the root array. // Removes an element of the root array.
@ -392,6 +392,14 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
return detail::VariantImpl(&data_, &resources_); return detail::VariantImpl(&data_, &resources_);
} }
detail::VariantImpl getOrCreateArray() {
return detail::VariantImpl(data_.getOrCreateArray(), &resources_);
}
detail::VariantImpl getOrCreateObject() {
return detail::VariantImpl(data_.getOrCreateObject(), &resources_);
}
JsonVariant getVariant() { JsonVariant getVariant() {
return JsonVariant(&data_, &resources_); return JsonVariant(&data_, &resources_);
} }

View File

@ -173,7 +173,7 @@ class JsonDeserializer {
// Read each value // Read each value
for (;;) { for (;;) {
if (elementFilter.allow()) { if (elementFilter.allow()) {
ArrayImpl array(arrayData, resources_); VariantImpl array(arrayData, resources_);
// Allocate slot in array // Allocate slot in array
VariantData* value = array.addElement(); VariantData* value = array.addElement();
@ -277,7 +277,7 @@ class JsonDeserializer {
TFilter memberFilter = filter[key]; TFilter memberFilter = filter[key];
if (memberFilter.allow()) { if (memberFilter.allow()) {
ObjectImpl object(objectData, resources_); VariantImpl object(objectData, resources_);
auto member = object.getMember(adaptString(key)); auto member = object.getMember(adaptString(key));
if (!member) { if (!member) {
auto keyVariant = object.addPair(&member); auto keyVariant = object.addPair(&member);

View File

@ -19,7 +19,7 @@ class JsonSerializer : public VariantDataVisitor<size_t> {
JsonSerializer(TWriter writer, ResourceManager* resources) JsonSerializer(TWriter writer, ResourceManager* resources)
: formatter_(writer), resources_(resources) {} : formatter_(writer), resources_(resources) {}
size_t visit(const ArrayImpl& array) { size_t visitArray(const VariantImpl& array) {
write('['); write('[');
auto slotId = array.head(); auto slotId = array.head();
@ -39,7 +39,7 @@ class JsonSerializer : public VariantDataVisitor<size_t> {
return bytesWritten(); return bytesWritten();
} }
size_t visit(const ObjectImpl& object) { size_t visitObject(const VariantImpl& object) {
write('{'); write('{');
auto slotId = object.head(); auto slotId = object.head();

View File

@ -19,7 +19,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
PrettyJsonSerializer(TWriter writer, ResourceManager* resources) PrettyJsonSerializer(TWriter writer, ResourceManager* resources)
: base(writer, resources), nesting_(0) {} : base(writer, resources), nesting_(0) {}
size_t visit(const ArrayImpl& array) { size_t visitArray(const VariantImpl& array) {
auto it = array.createIterator(); auto it = array.createIterator();
if (!it.done()) { if (!it.done()) {
base::write("[\r\n"); base::write("[\r\n");
@ -40,7 +40,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
return this->bytesWritten(); return this->bytesWritten();
} }
size_t visit(const ObjectImpl& object) { size_t visitObject(const VariantImpl& object) {
auto it = object.createIterator(); auto it = object.createIterator();
if (!it.done()) { if (!it.done()) {
base::write("{\r\n"); base::write("{\r\n");

View File

@ -349,10 +349,10 @@ class MsgPackDeserializer {
bool allowArray = filter.allowArray(); bool allowArray = filter.allowArray();
ArrayImpl array; VariantImpl array;
if (allowArray) { if (allowArray) {
ARDUINOJSON_ASSERT(variant != 0); ARDUINOJSON_ASSERT(variant != 0);
array = ArrayImpl(variant->toArray(), resources_); array = VariantImpl(variant->toArray(), resources_);
} }
TFilter elementFilter = filter[0U]; TFilter elementFilter = filter[0U];
@ -385,10 +385,10 @@ class MsgPackDeserializer {
if (nestingLimit.reached()) if (nestingLimit.reached())
return DeserializationError::TooDeep; return DeserializationError::TooDeep;
ObjectImpl object; VariantImpl object;
if (filter.allowObject()) { if (filter.allowObject()) {
ARDUINOJSON_ASSERT(variant != 0); ARDUINOJSON_ASSERT(variant != 0);
object = ObjectImpl(variant->toObject(), resources_); object = VariantImpl(variant->toObject(), resources_);
} }
for (; n; --n) { for (; n; --n) {

View File

@ -47,7 +47,7 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
return bytesWritten(); return bytesWritten();
} }
size_t visit(const ArrayImpl& array) { size_t visitArray(const VariantImpl& array) {
size_t n = array.size(); size_t n = array.size();
if (n < 0x10) { if (n < 0x10) {
writeByte(uint8_t(0x90 + n)); writeByte(uint8_t(0x90 + n));
@ -69,7 +69,7 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
return bytesWritten(); return bytesWritten();
} }
size_t visit(const ObjectImpl& object) { size_t visitObject(const VariantImpl& object) {
size_t n = object.size(); size_t n = object.size();
if (n < 0x10) { if (n < 0x10) {
writeByte(uint8_t(0x80 + n)); writeByte(uint8_t(0x80 + n));

View File

@ -26,28 +26,31 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
JsonObject(detail::VariantData* data, detail::ResourceManager* resource) JsonObject(detail::VariantData* data, detail::ResourceManager* resource)
: impl_(data, resource) {} : impl_(data, resource) {}
// INTERNAL USE ONLY
JsonObject(detail::VariantImpl impl) : impl_(impl) {}
operator JsonVariant() const { operator JsonVariant() const {
return JsonVariant(getData(), getResourceManager()); return JsonVariant(impl_);
} }
operator JsonObjectConst() const { operator JsonObjectConst() const {
return JsonObjectConst(getData(), getResourceManager()); return JsonObjectConst(impl_);
} }
operator JsonVariantConst() const { operator JsonVariantConst() const {
return JsonVariantConst(getData(), getResourceManager()); return JsonVariantConst(impl_);
} }
// Returns true if the reference is unbound. // Returns true if the reference is unbound.
// https://arduinojson.org/v7/api/jsonobject/isnull/ // https://arduinojson.org/v7/api/jsonobject/isnull/
bool isNull() const { bool isNull() const {
return impl_.isNull(); return !operator bool();
} }
// Returns true if the reference is bound. // Returns true if the reference is bound.
// https://arduinojson.org/v7/api/jsonobject/isnull/ // https://arduinojson.org/v7/api/jsonobject/isnull/
operator bool() const { operator bool() const {
return !isNull(); return impl_.isObject();
} }
// Returns the depth (nesting level) of the object. // Returns the depth (nesting level) of the object.
@ -77,7 +80,8 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
// Removes all the members of the object. // Removes all the members of the object.
// https://arduinojson.org/v7/api/jsonobject/clear/ // https://arduinojson.org/v7/api/jsonobject/clear/
void clear() const { void clear() const {
impl_.clear(); if (impl_.isObject())
impl_.empty();
} }
// Copies an object. // Copies an object.
@ -127,7 +131,7 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
// Removes the member at the specified iterator. // Removes the member at the specified iterator.
// https://arduinojson.org/v7/api/jsonobject/remove/ // https://arduinojson.org/v7/api/jsonobject/remove/
FORCE_INLINE void remove(iterator it) const { FORCE_INLINE void remove(iterator it) const {
impl_.remove(it.iterator_); impl_.removeMember(it.iterator_);
} }
// Removes the member with the specified key. // Removes the member with the specified key.
@ -230,7 +234,7 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
return impl_.getData(); return impl_.getData();
} }
mutable detail::ObjectImpl impl_; mutable detail::VariantImpl impl_;
}; };
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@ -26,10 +26,10 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
: impl_(data, resources) {} : impl_(data, resources) {}
// INTERNAL USE ONLY // INTERNAL USE ONLY
JsonObjectConst(const detail::ObjectImpl& impl) : impl_(impl) {} JsonObjectConst(const detail::VariantImpl& impl) : impl_(impl) {}
operator JsonVariantConst() const { operator JsonVariantConst() const {
return JsonVariantConst(impl_.getData(), impl_.getResourceManager()); return JsonVariantConst(impl_);
} }
// Returns true if the reference is unbound. // Returns true if the reference is unbound.
@ -136,7 +136,7 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
return impl_.getData(); return impl_.getData();
} }
detail::ObjectImpl impl_; detail::VariantImpl impl_;
}; };
inline bool operator==(JsonObjectConst lhs, JsonObjectConst rhs) { inline bool operator==(JsonObjectConst lhs, JsonObjectConst rhs) {

View File

@ -14,7 +14,7 @@ class JsonObjectIterator {
public: public:
JsonObjectIterator() {} JsonObjectIterator() {}
explicit JsonObjectIterator(detail::ObjectImpl::iterator iterator, explicit JsonObjectIterator(detail::VariantImpl::iterator iterator,
detail::ResourceManager* resources) detail::ResourceManager* resources)
: iterator_(iterator), resources_(resources) {} : iterator_(iterator), resources_(resources) {}
@ -40,7 +40,7 @@ class JsonObjectIterator {
} }
private: private:
detail::ObjectImpl::iterator iterator_; detail::VariantImpl::iterator iterator_;
detail::ResourceManager* resources_; detail::ResourceManager* resources_;
}; };
@ -50,7 +50,7 @@ class JsonObjectConstIterator {
public: public:
JsonObjectConstIterator() {} JsonObjectConstIterator() {}
explicit JsonObjectConstIterator(detail::ObjectImpl::iterator iterator, explicit JsonObjectConstIterator(detail::VariantImpl::iterator iterator,
detail::ResourceManager* resources) detail::ResourceManager* resources)
: iterator_(iterator), resources_(resources) {} : iterator_(iterator), resources_(resources) {}
@ -76,7 +76,7 @@ class JsonObjectConstIterator {
} }
private: private:
detail::ObjectImpl::iterator iterator_; detail::VariantImpl::iterator iterator_;
detail::ResourceManager* resources_; detail::ResourceManager* resources_;
}; };

View File

@ -15,7 +15,7 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
class JsonPair { class JsonPair {
public: public:
// INTERNAL USE ONLY // INTERNAL USE ONLY
JsonPair(detail::ObjectImpl::iterator iterator, JsonPair(detail::VariantImpl::iterator iterator,
detail::ResourceManager* resources) { detail::ResourceManager* resources) {
if (!iterator.done()) { if (!iterator.done()) {
detail::VariantImpl variant(iterator.data(), resources); detail::VariantImpl variant(iterator.data(), resources);
@ -44,7 +44,7 @@ class JsonPair {
// https://arduinojson.org/v7/api/jsonobjectconst/begin_end/ // https://arduinojson.org/v7/api/jsonobjectconst/begin_end/
class JsonPairConst { class JsonPairConst {
public: public:
JsonPairConst(detail::ObjectImpl::iterator iterator, JsonPairConst(detail::VariantImpl::iterator iterator,
detail::ResourceManager* resources) { detail::ResourceManager* resources) {
if (!iterator.done()) { if (!iterator.done()) {
detail::VariantImpl variant(iterator.data(), resources); detail::VariantImpl variant(iterator.data(), resources);

View File

@ -60,8 +60,12 @@ class MemberProxy
} }
VariantData* getOrCreateData() const { VariantData* getOrCreateData() const {
return VariantAttorney::getOrCreateVariantImpl(upstream_).getOrAddMember( auto data = VariantAttorney::getOrCreateData(upstream_);
key_); auto resources = VariantAttorney::getResourceManager(upstream_);
if (!data)
return nullptr;
data->getOrCreateObject();
return VariantImpl(data, resources).getOrAddMember(key_);
} }
private: private:

View File

@ -1,51 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2025, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Collection/CollectionData.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class VariantImpl;
class ObjectImpl : public CollectionImpl {
public:
ObjectImpl() {}
ObjectImpl(VariantData* data, ResourceManager* resources)
: CollectionImpl(data, resources) {}
bool isNull() const {
return !data_ || data_->type != VariantType::Object;
}
template <typename TAdaptedString>
VariantData* addMember(TAdaptedString key);
VariantData* addPair(VariantData** value);
template <typename TAdaptedString>
VariantData* getOrAddMember(TAdaptedString key);
template <typename TAdaptedString>
VariantData* getMember(TAdaptedString key) const;
template <typename TAdaptedString>
void removeMember(TAdaptedString key);
void remove(iterator it) {
CollectionImpl::removePair(it);
}
size_t size() const {
return CollectionImpl::size() / 2;
}
private:
template <typename TAdaptedString>
iterator findKey(TAdaptedString key) const;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -4,14 +4,13 @@
#pragma once #pragma once
#include <ArduinoJson/Object/ObjectData.hpp>
#include <ArduinoJson/Variant/VariantCompare.hpp> #include <ArduinoJson/Variant/VariantCompare.hpp>
#include <ArduinoJson/Variant/VariantData.hpp> #include <ArduinoJson/Variant/VariantImpl.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TAdaptedString> template <typename TAdaptedString>
inline VariantData* ObjectImpl::getMember(TAdaptedString key) const { inline VariantData* VariantImpl::getMember(TAdaptedString key) const {
auto it = findKey(key); auto it = findKey(key);
if (it.done()) if (it.done())
return nullptr; return nullptr;
@ -20,7 +19,7 @@ inline VariantData* ObjectImpl::getMember(TAdaptedString key) const {
} }
template <typename TAdaptedString> template <typename TAdaptedString>
VariantData* ObjectImpl::getOrAddMember(TAdaptedString key) { VariantData* VariantImpl::getOrAddMember(TAdaptedString key) {
auto data = getMember(key); auto data = getMember(key);
if (data) if (data)
return data; return data;
@ -28,8 +27,8 @@ VariantData* ObjectImpl::getOrAddMember(TAdaptedString key) {
} }
template <typename TAdaptedString> template <typename TAdaptedString>
inline ObjectImpl::iterator ObjectImpl::findKey(TAdaptedString key) const { inline VariantImpl::iterator VariantImpl::findKey(TAdaptedString key) const {
if (isNull()) if (!isObject())
return iterator(); return iterator();
if (key.isNull()) if (key.isNull())
return iterator(); return iterator();
@ -44,13 +43,13 @@ inline ObjectImpl::iterator ObjectImpl::findKey(TAdaptedString key) const {
} }
template <typename TAdaptedString> template <typename TAdaptedString>
inline void ObjectImpl::removeMember(TAdaptedString key) { inline void VariantImpl::removeMember(TAdaptedString key) {
remove(findKey(key)); removeMember(findKey(key));
} }
template <typename TAdaptedString> template <typename TAdaptedString>
inline VariantData* ObjectImpl::addMember(TAdaptedString key) { inline VariantData* VariantImpl::addMember(TAdaptedString key) {
if (isNull()) if (!isObject())
return nullptr; return nullptr;
auto keySlot = allocVariant(); auto keySlot = allocVariant();
@ -65,13 +64,13 @@ inline VariantData* ObjectImpl::addMember(TAdaptedString key) {
if (!keyImpl.setString(key)) if (!keyImpl.setString(key))
return nullptr; return nullptr;
CollectionImpl::appendPair(keySlot, valueSlot); VariantImpl::appendPair(keySlot, valueSlot);
return valueSlot.ptr(); return valueSlot.ptr();
} }
inline VariantData* ObjectImpl::addPair(VariantData** value) { inline VariantData* VariantImpl::addPair(VariantData** value) {
ARDUINOJSON_ASSERT(!isNull()); ARDUINOJSON_ASSERT(isObject());
auto keySlot = allocVariant(); auto keySlot = allocVariant();
if (!keySlot) if (!keySlot)
@ -82,7 +81,7 @@ inline VariantData* ObjectImpl::addPair(VariantData** value) {
return nullptr; return nullptr;
*value = valueSlot.ptr(); *value = valueSlot.ptr();
CollectionImpl::appendPair(keySlot, valueSlot); VariantImpl::appendPair(keySlot, valueSlot);
return keySlot.ptr(); return keySlot.ptr();
} }

View File

@ -42,6 +42,9 @@ class JsonVariantConst : public detail::VariantTag,
detail::ResourceManager* resources) detail::ResourceManager* resources)
: impl_(data, resources) {} : impl_(data, resources) {}
// INTERNAL USE ONLY
explicit JsonVariantConst(detail::VariantImpl impl) : impl_(impl) {}
// Returns true if the value is null or the reference is unbound. // Returns true if the value is null or the reference is unbound.
// https://arduinojson.org/v7/api/jsonvariantconst/isnull/ // https://arduinojson.org/v7/api/jsonvariantconst/isnull/
bool isNull() const { bool isNull() const {

View File

@ -28,11 +28,11 @@ class VisitorAdapter {
VisitorAdapter(TVisitor& visitor) : visitor_(&visitor) {} VisitorAdapter(TVisitor& visitor) : visitor_(&visitor) {}
result_type visit(const ArrayImpl& array) { result_type visitArray(const VariantImpl& array) {
return visitor_->visit(JsonArrayConst(array)); return visitor_->visit(JsonArrayConst(array));
} }
result_type visit(const ObjectImpl& object) { result_type visitObject(const VariantImpl& object) {
return visitor_->visit(JsonObjectConst(object)); return visitor_->visit(JsonObjectConst(object));
} }

View File

@ -31,11 +31,6 @@ class VariantAttorney {
return VariantImpl(client.getData(), client.getResourceManager()); return VariantImpl(client.getData(), client.getResourceManager());
} }
template <typename TClient>
static VariantImpl getOrCreateVariantImpl(TClient& client) {
return VariantImpl(client.getOrCreateData(), client.getResourceManager());
}
template <typename TClient> template <typename TClient>
static VariantData* getOrCreateData(TClient& client) { static VariantData* getOrCreateData(TClient& client) {
return client.getOrCreateData(); return client.getOrCreateData();

View File

@ -4,10 +4,8 @@
#pragma once #pragma once
#include <ArduinoJson/Array/ArrayData.hpp>
#include <ArduinoJson/Numbers/JsonFloat.hpp> #include <ArduinoJson/Numbers/JsonFloat.hpp>
#include <ArduinoJson/Numbers/JsonInteger.hpp> #include <ArduinoJson/Numbers/JsonInteger.hpp>
#include <ArduinoJson/Object/ObjectData.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
@ -15,6 +13,14 @@ template <typename TResult>
struct VariantDataVisitor { struct VariantDataVisitor {
using result_type = TResult; using result_type = TResult;
TResult visitArray(const VariantImpl&) {
return TResult();
}
TResult visitObject(const VariantImpl&) {
return TResult();
}
template <typename T> template <typename T>
TResult visit(const T&) { TResult visit(const T&) {
return TResult(); return TResult();

View File

@ -4,11 +4,10 @@
#pragma once #pragma once
#include <ArduinoJson/Array/ArrayData.hpp> #include <ArduinoJson/Collection/CollectionData.hpp>
#include <ArduinoJson/Memory/ResourceManager.hpp> #include <ArduinoJson/Memory/ResourceManager.hpp>
#include <ArduinoJson/Misc/SerializedValue.hpp> #include <ArduinoJson/Misc/SerializedValue.hpp>
#include <ArduinoJson/Numbers/convertNumber.hpp> #include <ArduinoJson/Numbers/convertNumber.hpp>
#include <ArduinoJson/Object/ObjectData.hpp>
#include <ArduinoJson/Strings/JsonString.hpp> #include <ArduinoJson/Strings/JsonString.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp> #include <ArduinoJson/Strings/StringAdapters.hpp>
#include <ArduinoJson/Variant/VariantData.hpp> #include <ArduinoJson/Variant/VariantData.hpp>
@ -16,7 +15,12 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class VariantImpl { class VariantImpl {
VariantData* data_;
ResourceManager* resources_;
public: public:
using iterator = CollectionIterator;
VariantImpl() : data_(nullptr), resources_(nullptr) {} VariantImpl() : data_(nullptr), resources_(nullptr) {}
VariantImpl(VariantData* data, ResourceManager* resources) VariantImpl(VariantData* data, ResourceManager* resources)
@ -48,10 +52,10 @@ class VariantImpl {
#endif #endif
case VariantType::Array: case VariantType::Array:
return visit.visit(ArrayImpl(data_, resources_)); return visit.visitArray(VariantImpl(data_, resources_));
case VariantType::Object: case VariantType::Object:
return visit.visit(ObjectImpl(data_, resources_)); return visit.visitObject(VariantImpl(data_, resources_));
case VariantType::TinyString: case VariantType::TinyString:
return visit.visit(JsonString(data_->content.asTinyString)); return visit.visit(JsonString(data_->content.asTinyString));
@ -89,18 +93,10 @@ class VariantImpl {
} }
} }
VariantData* addElement() { VariantData* addElement();
if (!data_)
return nullptr;
return ArrayImpl(data_->getOrCreateArray(), resources_).addElement();
}
template <typename T> template <typename T>
bool addValue(const T& value) { bool addValue(const T& value);
if (!data_)
return false;
return ArrayImpl(data_->getOrCreateArray(), resources_).addValue(value);
}
bool asBoolean() const { bool asBoolean() const {
if (!data_) if (!data_)
@ -262,31 +258,26 @@ class VariantImpl {
} }
#endif #endif
VariantData* getElement(size_t index) { SlotId head() const {
return ArrayImpl(data_, resources_).getElement(index); return getCollectionData()->head;
} }
iterator createIterator() const;
VariantData* getElement(size_t index) const;
VariantData* getOrAddElement(size_t index);
VariantData* addPair(VariantData** value);
template <typename TAdaptedString> template <typename TAdaptedString>
VariantData* getMember(TAdaptedString key) { VariantData* addMember(TAdaptedString key);
return ObjectImpl(data_, resources_).getMember(key);
}
VariantData* getOrAddElement(size_t index) {
if (!data_)
return nullptr;
return ArrayImpl(data_->getOrCreateArray(), resources_)
.getOrAddElement(index);
}
template <typename TAdaptedString> template <typename TAdaptedString>
VariantData* getOrAddMember(TAdaptedString key) { VariantData* getMember(TAdaptedString key) const;
if (key.isNull())
return nullptr; template <typename TAdaptedString>
if (!data_) VariantData* getOrAddMember(TAdaptedString key);
return nullptr;
return ObjectImpl(data_->getOrCreateObject(), resources_)
.getOrAddMember(key);
}
bool isArray() const { bool isArray() const {
return type() == VariantType::Array; return type() == VariantType::Array;
@ -340,17 +331,21 @@ class VariantImpl {
return data_ && data_->isString(); return data_ && data_->isString();
} }
size_t nesting() { size_t nesting() const;
return CollectionImpl(data_, resources_).nesting();
void removeElement(iterator it) {
if (!isArray())
return;
removeOne(it);
} }
void removeElement(size_t index) { void removeElement(size_t index);
ArrayImpl(data_, resources_).removeElement(index);
}
template <typename TAdaptedString> template <typename TAdaptedString>
void removeMember(TAdaptedString key) { void removeMember(TAdaptedString key);
ObjectImpl(data_, resources_).removeMember(key);
void removeMember(iterator it) {
removePair(it);
} }
bool setBoolean(bool value) { bool setBoolean(bool value) {
@ -454,13 +449,21 @@ class VariantImpl {
bool setLinkedString(const char* s); bool setLinkedString(const char* s);
size_t size() { void empty();
auto size = CollectionImpl(data_, resources_).size();
if (data_ && data_->type == VariantType::Object) size_t size() const {
size /= 2; if (!data_)
return 0;
return size; size_t count = 0;
for (auto it = createIterator(); !it.done(); it.next(resources_))
count++;
if (data_->type == VariantType::Object)
count /= 2; // TODO: do this in JsonObject?
return count;
} }
VariantType type() const { VariantType type() const {
@ -471,8 +474,39 @@ class VariantImpl {
void clear(); void clear();
private: private:
VariantData* data_; template <typename TAdaptedString>
ResourceManager* resources_; iterator findKey(TAdaptedString key) const;
iterator at(size_t index) const;
void appendOne(Slot<VariantData> slot);
void appendPair(Slot<VariantData> key, Slot<VariantData> value);
void removeOne(iterator it);
void removePair(iterator it);
VariantData* getVariant(SlotId id) const {
ARDUINOJSON_ASSERT(resources_ != nullptr);
return resources_->getVariant(id);
}
void freeVariant(Slot<VariantData> slot) {
ARDUINOJSON_ASSERT(resources_ != nullptr);
resources_->freeVariant(slot);
}
Slot<VariantData> allocVariant() {
ARDUINOJSON_ASSERT(resources_ != nullptr);
return resources_->allocVariant();
}
Slot<VariantData> getPreviousSlot(VariantData*) const;
CollectionData* getCollectionData() const {
ARDUINOJSON_ASSERT(data_ != nullptr);
ARDUINOJSON_ASSERT(data_->isCollection());
return &data_->content.asCollection;
}
}; };
template <typename T> template <typename T>
@ -536,9 +570,25 @@ inline void VariantImpl::clear() {
resources_->freeEightByte(data_->content.asSlotId); resources_->freeEightByte(data_->content.asSlotId);
#endif #endif
CollectionImpl(data_, resources_).clear(); if (data_->type & VariantTypeBits::CollectionMask)
empty();
data_->type = VariantType::Null; data_->type = VariantType::Null;
} }
inline void VariantImpl::empty() {
auto coll = getCollectionData();
auto next = coll->head;
while (next != NULL_SLOT) {
auto currId = next;
auto slot = getVariant(next);
next = slot->next;
freeVariant({slot, currId});
}
coll->head = NULL_SLOT;
coll->tail = NULL_SLOT;
}
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

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 getOrCreateVariantImpl().addValue(value); return getOrCreateOrCreateArray().addValue(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 getOrCreateVariantImpl().addValue(value); return getOrCreateOrCreateArray().addValue(value);
} }
// Removes an element of the array. // Removes an element of the array.
@ -279,6 +279,18 @@ class VariantRefBase : public VariantTag {
return VariantImpl(getOrCreateData(), getResourceManager()); return VariantImpl(getOrCreateData(), getResourceManager());
} }
VariantImpl getOrCreateOrCreateArray() const {
auto data = getOrCreateData();
return VariantImpl(data ? data->getOrCreateArray() : nullptr,
getResourceManager());
}
VariantImpl getOrCreateOrCreateObject() const {
auto data = getOrCreateData();
return VariantImpl(data ? data->getOrCreateObject() : nullptr,
getResourceManager());
}
FORCE_INLINE ArduinoJson::JsonVariant getVariant() const; FORCE_INLINE ArduinoJson::JsonVariant getVariant() const;
FORCE_INLINE ArduinoJson::JsonVariantConst getVariantConst() const { FORCE_INLINE ArduinoJson::JsonVariantConst getVariantConst() const {

View File

@ -69,7 +69,7 @@ inline void 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 {
return JsonVariant(getOrCreateVariantImpl().addElement(), return JsonVariant(getOrCreateOrCreateArray().addElement(),
getResourceManager()); getResourceManager());
} }