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

View File

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

View File

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

View File

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

View File

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

View File

@ -15,7 +15,7 @@ struct VariantData;
class ResourceManager;
class CollectionIterator {
friend class CollectionImpl;
friend class VariantImpl;
public:
CollectionIterator() : slot_(nullptr), currentId_(NULL_SLOT) {}
@ -65,76 +65,4 @@ class CollectionIterator {
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -60,8 +60,12 @@ class MemberProxy
}
VariantData* getOrCreateData() const {
return VariantAttorney::getOrCreateVariantImpl(upstream_).getOrAddMember(
key_);
auto data = VariantAttorney::getOrCreateData(upstream_);
auto resources = VariantAttorney::getResourceManager(upstream_);
if (!data)
return nullptr;
data->getOrCreateObject();
return VariantImpl(data, resources).getOrAddMember(key_);
}
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
#include <ArduinoJson/Object/ObjectData.hpp>
#include <ArduinoJson/Variant/VariantCompare.hpp>
#include <ArduinoJson/Variant/VariantData.hpp>
#include <ArduinoJson/Variant/VariantImpl.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TAdaptedString>
inline VariantData* ObjectImpl::getMember(TAdaptedString key) const {
inline VariantData* VariantImpl::getMember(TAdaptedString key) const {
auto it = findKey(key);
if (it.done())
return nullptr;
@ -20,7 +19,7 @@ inline VariantData* ObjectImpl::getMember(TAdaptedString key) const {
}
template <typename TAdaptedString>
VariantData* ObjectImpl::getOrAddMember(TAdaptedString key) {
VariantData* VariantImpl::getOrAddMember(TAdaptedString key) {
auto data = getMember(key);
if (data)
return data;
@ -28,8 +27,8 @@ VariantData* ObjectImpl::getOrAddMember(TAdaptedString key) {
}
template <typename TAdaptedString>
inline ObjectImpl::iterator ObjectImpl::findKey(TAdaptedString key) const {
if (isNull())
inline VariantImpl::iterator VariantImpl::findKey(TAdaptedString key) const {
if (!isObject())
return iterator();
if (key.isNull())
return iterator();
@ -44,13 +43,13 @@ inline ObjectImpl::iterator ObjectImpl::findKey(TAdaptedString key) const {
}
template <typename TAdaptedString>
inline void ObjectImpl::removeMember(TAdaptedString key) {
remove(findKey(key));
inline void VariantImpl::removeMember(TAdaptedString key) {
removeMember(findKey(key));
}
template <typename TAdaptedString>
inline VariantData* ObjectImpl::addMember(TAdaptedString key) {
if (isNull())
inline VariantData* VariantImpl::addMember(TAdaptedString key) {
if (!isObject())
return nullptr;
auto keySlot = allocVariant();
@ -65,13 +64,13 @@ inline VariantData* ObjectImpl::addMember(TAdaptedString key) {
if (!keyImpl.setString(key))
return nullptr;
CollectionImpl::appendPair(keySlot, valueSlot);
VariantImpl::appendPair(keySlot, valueSlot);
return valueSlot.ptr();
}
inline VariantData* ObjectImpl::addPair(VariantData** value) {
ARDUINOJSON_ASSERT(!isNull());
inline VariantData* VariantImpl::addPair(VariantData** value) {
ARDUINOJSON_ASSERT(isObject());
auto keySlot = allocVariant();
if (!keySlot)
@ -82,7 +81,7 @@ inline VariantData* ObjectImpl::addPair(VariantData** value) {
return nullptr;
*value = valueSlot.ptr();
CollectionImpl::appendPair(keySlot, valueSlot);
VariantImpl::appendPair(keySlot, valueSlot);
return keySlot.ptr();
}

View File

@ -42,6 +42,9 @@ class JsonVariantConst : public detail::VariantTag,
detail::ResourceManager* 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.
// https://arduinojson.org/v7/api/jsonvariantconst/isnull/
bool isNull() const {

View File

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

View File

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

View File

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

View File

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

View File

@ -120,14 +120,14 @@ class VariantRefBase : public VariantTag {
// https://arduinojson.org/v7/api/jsonvariant/add/
template <typename T>
bool add(const T& value) const {
return getOrCreateVariantImpl().addValue(value);
return getOrCreateOrCreateArray().addValue(value);
}
// Appends a value to the array.
// https://arduinojson.org/v7/api/jsonvariant/add/
template <typename T, enable_if_t<!is_const<T>::value, int> = 0>
bool add(T* value) const {
return getOrCreateVariantImpl().addValue(value);
return getOrCreateOrCreateArray().addValue(value);
}
// Removes an element of the array.
@ -279,6 +279,18 @@ class VariantRefBase : public VariantTag {
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::JsonVariantConst getVariantConst() const {

View File

@ -69,7 +69,7 @@ inline void convertToJson(const VariantRefBase<TDerived>& src,
template <typename TDerived>
template <typename T, enable_if_t<is_same<T, JsonVariant>::value, int>>
inline T VariantRefBase<TDerived>::add() const {
return JsonVariant(getOrCreateVariantImpl().addElement(),
return JsonVariant(getOrCreateOrCreateArray().addElement(),
getResourceManager());
}