Extract ArrayImpl, CollectionImpl, and ObjectImpl

This commit is contained in:
Benoit Blanchon
2025-06-25 16:29:07 +02:00
parent 8cc190b7bf
commit 48dec78781
26 changed files with 382 additions and 480 deletions

View File

@ -8,59 +8,30 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class ArrayData : public CollectionData { class ArrayImpl : public CollectionImpl {
public: public:
VariantData* addElement(ResourceManager* resources); ArrayImpl() {}
static VariantData* addElement(ArrayData* array, ResourceManager* resources) { ArrayImpl(CollectionData* data, ResourceManager* resources)
if (!array) : CollectionImpl(data, resources) {}
return nullptr;
return array->addElement(resources); VariantData* addElement();
}
template <typename T> template <typename T>
bool addValue(const T& value, ResourceManager* resources); bool addValue(const T& value);
template <typename T> VariantData* getOrAddElement(size_t index);
static bool addValue(ArrayData* array, const T& value,
ResourceManager* resources) {
if (!array)
return false;
return array->addValue(value, resources);
}
VariantData* getOrAddElement(size_t index, ResourceManager* resources); VariantData* getElement(size_t index) const;
VariantData* getElement(size_t index, const ResourceManager* resources) const; void removeElement(size_t index);
static VariantData* getElement(const ArrayData* array, size_t index, void remove(iterator it) {
const ResourceManager* resources) { CollectionImpl::removeOne(it);
if (!array)
return nullptr;
return array->getElement(index, resources);
}
void removeElement(size_t index, ResourceManager* resources);
static void removeElement(ArrayData* array, size_t index,
ResourceManager* resources) {
if (!array)
return;
array->removeElement(index, resources);
}
void remove(iterator it, ResourceManager* resources) {
CollectionData::removeOne(it, resources);
}
static void remove(ArrayData* array, iterator it,
ResourceManager* resources) {
if (array)
return array->remove(it, resources);
} }
private: private:
iterator at(size_t index, const ResourceManager* resources) const; iterator at(size_t index) const;
}; };
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -10,36 +10,37 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
inline ArrayData::iterator ArrayData::at( inline ArrayImpl::iterator ArrayImpl::at(size_t index) const {
size_t index, const ResourceManager* resources) const { auto it = createIterator();
auto it = createIterator(resources);
while (!it.done() && index) { while (!it.done() && index) {
it.next(resources); it.next(resources_);
--index; --index;
} }
return it; return it;
} }
inline VariantData* ArrayData::addElement(ResourceManager* resources) { inline VariantData* ArrayImpl::addElement() {
auto slot = resources->allocVariant(); if (!data_)
return nullptr;
ARDUINOJSON_ASSERT(resources_ != nullptr);
auto slot = resources_->allocVariant();
if (!slot) if (!slot)
return nullptr; return nullptr;
CollectionData::appendOne(slot, resources); CollectionImpl::appendOne(slot);
return slot.ptr(); return slot.ptr();
} }
inline VariantData* ArrayData::getOrAddElement(size_t index, inline VariantData* ArrayImpl::getOrAddElement(size_t index) {
ResourceManager* resources) { auto it = createIterator();
auto it = createIterator(resources);
while (!it.done() && index > 0) { while (!it.done() && index > 0) {
it.next(resources); it.next(resources_);
index--; index--;
} }
if (it.done()) if (it.done())
index++; index++;
VariantData* element = it.data(); VariantData* element = it.data();
while (index > 0) { while (index > 0) {
element = addElement(resources); element = addElement();
if (!element) if (!element)
return nullptr; return nullptr;
index--; index--;
@ -47,27 +48,28 @@ inline VariantData* ArrayData::getOrAddElement(size_t index,
return element; return element;
} }
inline VariantData* ArrayData::getElement( inline VariantData* ArrayImpl::getElement(size_t index) const {
size_t index, const ResourceManager* resources) const { return at(index).data();
return at(index, resources).data();
} }
inline void ArrayData::removeElement(size_t index, ResourceManager* resources) { inline void ArrayImpl::removeElement(size_t index) {
remove(at(index, resources), resources); remove(at(index));
} }
template <typename T> template <typename T>
inline bool ArrayData::addValue(const T& value, ResourceManager* resources) { inline bool ArrayImpl::addValue(const T& value) {
ARDUINOJSON_ASSERT(resources != nullptr); if (!data_)
auto slot = resources->allocVariant(); return false;
ARDUINOJSON_ASSERT(resources_ != nullptr);
auto slot = resources_->allocVariant();
if (!slot) if (!slot)
return false; return false;
JsonVariant variant(slot.ptr(), resources); JsonVariant variant(slot.ptr(), resources_);
if (!variant.set(value)) { if (!variant.set(value)) {
resources->freeVariant(slot); resources_->freeVariant(slot);
return false; return false;
} }
CollectionData::appendOne(slot, resources); CollectionImpl::appendOne(slot);
return true; return true;
} }

View File

@ -55,9 +55,9 @@ class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>,
} }
FORCE_INLINE VariantData* getData() const { FORCE_INLINE VariantData* getData() const {
return VariantData::getElement( auto data = VariantAttorney::getData(upstream_);
VariantAttorney::getData(upstream_), index_, auto resources = VariantAttorney::getResourceManager(upstream_);
VariantAttorney::getResourceManager(upstream_)); return VariantData::asArray(data, resources).getElement(index_);
} }
VariantData* getOrCreateData() const { VariantData* getOrCreateData() const {

View File

@ -20,24 +20,25 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
using iterator = JsonArrayIterator; using iterator = JsonArrayIterator;
// Constructs an unbound reference. // Constructs an unbound reference.
JsonArray() : data_(0), resources_(0) {} JsonArray() {}
// INTERNAL USE ONLY // INTERNAL USE ONLY
JsonArray(detail::VariantData* data, detail::ResourceManager* resources) JsonArray(detail::VariantData* data, detail::ResourceManager* resources)
: data_(data), resources_(resources) {} : impl_(detail::VariantData::asArray(data, resources)) {}
// INTERNAL USE ONLY
JsonArray(const detail::ArrayImpl& 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() {
void* data = data_; // prevent warning cast-align return JsonVariant(getData(), getResourceManager());
return JsonVariant(reinterpret_cast<detail::VariantData*>(data),
resources_);
} }
// 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(), resources_); return JsonArrayConst(getData(), getResourceManager());
} }
// Appends a new (empty) element to the array. // Appends a new (empty) element to the array.
@ -55,15 +56,14 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
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() const { JsonVariant add() const {
return JsonVariant(detail::VariantData::addElement(data_, resources_), return JsonVariant(impl_.addElement(), impl_.getResourceManager());
resources_);
} }
// Appends a value to the array. // Appends a value to the array.
// 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 detail::VariantData::addValue(data_, value, resources_); return impl_.addValue(value);
} }
// Appends a value to the array. // Appends a value to the array.
@ -71,16 +71,13 @@ 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 detail::VariantData::addValue(data_, value, resources_); return impl_.addValue(value);
} }
// Returns an iterator to the first element of the array. // Returns an iterator to the first element of the array.
// https://arduinojson.org/v7/api/jsonarray/begin/ // https://arduinojson.org/v7/api/jsonarray/begin/
iterator begin() const { iterator begin() const {
auto array = detail::VariantData::asArray(data_); return iterator(impl_.createIterator(), impl_.getResourceManager());
if (!array)
return iterator();
return iterator(array->createIterator(resources_), resources_);
} }
// Returns an iterator following the last element of the array. // Returns an iterator following the last element of the array.
@ -92,7 +89,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
// Copies an array. // Copies an array.
// https://arduinojson.org/v7/api/jsonarray/set/ // https://arduinojson.org/v7/api/jsonarray/set/
bool set(JsonArrayConst src) const { bool set(JsonArrayConst src) const {
if (!data_) if (isNull())
return false; return false;
clear(); clear();
@ -107,14 +104,13 @@ 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 {
detail::ArrayData::remove(detail::VariantData::asArray(data_), it.iterator_, impl_.remove(it.iterator_);
resources_);
} }
// Removes the element at the specified index. // Removes the element at the specified index.
// https://arduinojson.org/v7/api/jsonarray/remove/ // https://arduinojson.org/v7/api/jsonarray/remove/
void remove(size_t index) const { void remove(size_t index) const {
detail::VariantData::removeElement(data_, index, resources_); impl_.removeElement(index);
} }
// Removes the element at the specified index. // Removes the element at the specified index.
@ -129,7 +125,7 @@ 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 {
detail::ArrayData::clear(detail::VariantData::asArray(data_), resources_); impl_.clear();
} }
// Gets or sets the element at the specified index. // Gets or sets the element at the specified index.
@ -152,13 +148,13 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
} }
operator JsonVariantConst() const { operator JsonVariantConst() const {
return JsonVariantConst(data_, resources_); return JsonVariantConst(getData(), getResourceManager());
} }
// Returns true if the reference is unbound. // Returns true if the reference is unbound.
// https://arduinojson.org/v7/api/jsonarray/isnull/ // https://arduinojson.org/v7/api/jsonarray/isnull/
bool isNull() const { bool isNull() const {
return !data_ || !data_->isArray(); return impl_.isNull();
} }
// Returns true if the reference is bound. // Returns true if the reference is bound.
@ -170,13 +166,13 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
// Returns the depth (nesting level) of the array. // Returns the depth (nesting level) of the array.
// https://arduinojson.org/v7/api/jsonarray/nesting/ // https://arduinojson.org/v7/api/jsonarray/nesting/
size_t nesting() const { size_t nesting() const {
return detail::VariantData::nesting(data_, resources_); return impl_.nesting();
} }
// Returns the number of elements in the array. // Returns the number of elements in the array.
// https://arduinojson.org/v7/api/jsonarray/size/ // https://arduinojson.org/v7/api/jsonarray/size/
size_t size() const { size_t size() const {
return data_ ? data_->size(resources_) : 0; return impl_.size();
} }
// DEPRECATED: use add<JsonVariant>() instead // DEPRECATED: use add<JsonVariant>() instead
@ -203,19 +199,18 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
private: private:
detail::ResourceManager* getResourceManager() const { detail::ResourceManager* getResourceManager() const {
return resources_; return impl_.getResourceManager();
} }
detail::VariantData* getData() const { detail::VariantData* getData() const {
return data_; return impl_.getData();
} }
detail::VariantData* getOrCreateData() const { detail::VariantData* getOrCreateData() const {
return data_; return impl_.getData();
} }
detail::VariantData* data_; mutable detail::ArrayImpl impl_;
detail::ResourceManager* resources_;
}; };
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@ -24,10 +24,7 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
// Returns an iterator to the first element of the array. // Returns an iterator to the first element of the array.
// https://arduinojson.org/v7/api/jsonarrayconst/begin/ // https://arduinojson.org/v7/api/jsonarrayconst/begin/
iterator begin() const { iterator begin() const {
auto array = detail::VariantData::asArray(data_); return iterator(impl_.createIterator(), impl_.getResourceManager());
if (!array)
return iterator();
return iterator(array->createIterator(resources_), resources_);
} }
// Returns an iterator to the element following the last element of the array. // Returns an iterator to the element following the last element of the array.
@ -37,21 +34,22 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
} }
// Creates an unbound reference. // Creates an unbound reference.
JsonArrayConst() : data_(0), resources_(0) {} JsonArrayConst() {}
// INTERNAL USE ONLY // INTERNAL USE ONLY
JsonArrayConst(const detail::VariantData* data, JsonArrayConst(detail::VariantData* data, detail::ResourceManager* resources)
const detail::ResourceManager* resources) : impl_(detail::VariantData::asArray(data, resources)) {}
: data_(data), resources_(resources) {}
// INTERNAL USE ONLY
JsonArrayConst(const detail::ArrayImpl& 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/
template <typename T, template <typename T,
detail::enable_if_t<detail::is_integral<T>::value, int> = 0> detail::enable_if_t<detail::is_integral<T>::value, int> = 0>
JsonVariantConst operator[](T index) const { JsonVariantConst operator[](T index) const {
return JsonVariantConst( return JsonVariantConst(impl_.getElement(size_t(index)),
detail::VariantData::getElement(data_, size_t(index), resources_), impl_.getResourceManager());
resources_);
} }
// Returns the element at the specified index. // Returns the element at the specified index.
@ -66,13 +64,13 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
} }
operator JsonVariantConst() const { operator JsonVariantConst() const {
return JsonVariantConst(getData(), resources_); return JsonVariantConst(impl_.getData(), impl_.getResourceManager());
} }
// Returns true if the reference is unbound. // Returns true if the reference is unbound.
// https://arduinojson.org/v7/api/jsonarrayconst/isnull/ // https://arduinojson.org/v7/api/jsonarrayconst/isnull/
bool isNull() const { bool isNull() const {
return !data_ || !data_->isArray(); return impl_.isNull();
} }
// Returns true if the reference is bound. // Returns true if the reference is bound.
@ -84,13 +82,13 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
// Returns the depth (nesting level) of the array. // Returns the depth (nesting level) of the array.
// https://arduinojson.org/v7/api/jsonarrayconst/nesting/ // https://arduinojson.org/v7/api/jsonarrayconst/nesting/
size_t nesting() const { size_t nesting() const {
return detail::VariantData::nesting(getData(), resources_); return impl_.nesting();
} }
// Returns the number of elements in the array. // Returns the number of elements in the array.
// https://arduinojson.org/v7/api/jsonarrayconst/size/ // https://arduinojson.org/v7/api/jsonarrayconst/size/
size_t size() const { size_t size() const {
return data_ ? data_->size(resources_) : 0; return impl_.size();
} }
// DEPRECATED: always returns zero // DEPRECATED: always returns zero
@ -101,11 +99,10 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
private: private:
const detail::VariantData* getData() const { const detail::VariantData* getData() const {
return data_; return impl_.getData();
} }
const detail::VariantData* data_; detail::ArrayImpl impl_;
const detail::ResourceManager* resources_;
}; };
// 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::ArrayData::iterator iterator, explicit JsonArrayIterator(detail::ArrayImpl::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::ArrayData::iterator iterator_; detail::ArrayImpl::iterator iterator_;
detail::ResourceManager* resources_; detail::ResourceManager* resources_;
}; };
@ -64,8 +64,8 @@ class JsonArrayConstIterator {
public: public:
JsonArrayConstIterator() {} JsonArrayConstIterator() {}
explicit JsonArrayConstIterator(detail::ArrayData::iterator iterator, explicit JsonArrayConstIterator(detail::ArrayImpl::iterator iterator,
const detail::ResourceManager* resources) detail::ResourceManager* resources)
: iterator_(iterator), resources_(resources) {} : iterator_(iterator), resources_(resources) {}
JsonVariantConst operator*() const { JsonVariantConst operator*() const {
@ -89,8 +89,8 @@ class JsonArrayConstIterator {
} }
private: private:
detail::ArrayData::iterator iterator_; mutable detail::ArrayImpl::iterator iterator_;
const detail::ResourceManager* resources_; mutable detail::ResourceManager* resources_;
}; };
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@ -16,7 +16,7 @@ class VariantData;
class ResourceManager; class ResourceManager;
class CollectionIterator { class CollectionIterator {
friend class CollectionData; friend class CollectionImpl;
public: public:
CollectionIterator() : slot_(nullptr), currentId_(NULL_SLOT) {} CollectionIterator() : slot_(nullptr), currentId_(NULL_SLOT) {}
@ -51,11 +51,11 @@ class CollectionIterator {
} }
VariantData* data() { VariantData* data() {
return reinterpret_cast<VariantData*>(slot_); return slot_;
} }
const VariantData* data() const { const VariantData* data() const {
return reinterpret_cast<const VariantData*>(slot_); return slot_;
} }
private: private:
@ -65,58 +65,68 @@ class CollectionIterator {
SlotId currentId_, nextId_; SlotId currentId_, nextId_;
}; };
class CollectionData { struct CollectionData {
SlotId head_ = NULL_SLOT; SlotId head = NULL_SLOT;
SlotId tail_ = NULL_SLOT; SlotId tail = NULL_SLOT;
public:
// Placement new // Placement new
static void* operator new(size_t, void* p) noexcept { static void* operator new(size_t, void* p) noexcept {
return p; return p;
} }
static void operator delete(void*, void*) noexcept {} static void operator delete(void*, void*) noexcept {}
};
class CollectionImpl {
protected:
CollectionData* data_;
ResourceManager* resources_;
public:
using iterator = CollectionIterator; using iterator = CollectionIterator;
iterator createIterator(const ResourceManager* resources) const; CollectionImpl() : data_(nullptr), resources_(nullptr) {}
size_t size(const ResourceManager*) const; CollectionImpl(CollectionData* data, ResourceManager* resources)
size_t nesting(const ResourceManager*) const; : data_(data), resources_(resources) {}
void clear(ResourceManager* resources); explicit operator bool() const {
return data_ != nullptr;
static void clear(CollectionData* collection, ResourceManager* resources) {
if (!collection)
return;
collection->clear(resources);
} }
bool isNull() const {
return data_ == nullptr;
}
VariantData* getData() const {
void* data = data_; // prevent warning cast-align
return reinterpret_cast<VariantData*>(data);
}
ResourceManager* getResourceManager() const {
return resources_;
}
iterator createIterator() const;
size_t size() const;
size_t nesting() const;
void clear();
SlotId head() const { SlotId head() const {
return head_; return data_->head;
} }
protected: protected:
void appendOne(Slot<VariantData> slot, const ResourceManager* resources); void appendOne(Slot<VariantData> slot);
void appendPair(Slot<VariantData> key, Slot<VariantData> value, void appendPair(Slot<VariantData> key, Slot<VariantData> value);
const ResourceManager* resources);
void removeOne(iterator it, ResourceManager* resources); void removeOne(iterator it);
void removePair(iterator it, ResourceManager* resources); void removePair(iterator it);
private: private:
Slot<VariantData> getPreviousSlot(VariantData*, const ResourceManager*) const; Slot<VariantData> getPreviousSlot(VariantData*) const;
}; };
inline const VariantData* collectionToVariant(
const CollectionData* collection) {
const void* data = collection; // prevent warning cast-align
return reinterpret_cast<const VariantData*>(data);
}
inline VariantData* collectionToVariant(CollectionData* collection) {
void* data = collection; // prevent warning cast-align
return reinterpret_cast<VariantData*>(data);
}
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -25,57 +25,64 @@ inline void CollectionIterator::next(const ResourceManager* resources) {
nextId_ = slot_->next(); nextId_ = slot_->next();
} }
inline CollectionData::iterator CollectionData::createIterator( inline CollectionImpl::iterator CollectionImpl::createIterator() const {
const ResourceManager* resources) const { if (!data_)
return iterator(resources->getVariant(head_), head_); return iterator();
return iterator(resources_->getVariant(data_->head), data_->head);
} }
inline void CollectionData::appendOne(Slot<VariantData> slot, inline void CollectionImpl::appendOne(Slot<VariantData> slot) {
const ResourceManager* resources) { ARDUINOJSON_ASSERT(data_ != nullptr);
if (tail_ != NULL_SLOT) { ARDUINOJSON_ASSERT(resources_ != nullptr);
auto tail = resources->getVariant(tail_);
if (data_->tail != NULL_SLOT) {
auto tail = resources_->getVariant(data_->tail);
tail->setNext(slot.id()); tail->setNext(slot.id());
tail_ = slot.id(); data_->tail = slot.id();
} else { } else {
head_ = slot.id(); data_->head = slot.id();
tail_ = slot.id(); data_->tail = slot.id();
} }
} }
inline void CollectionData::appendPair(Slot<VariantData> key, inline void CollectionImpl::appendPair(Slot<VariantData> key,
Slot<VariantData> value, Slot<VariantData> value) {
const ResourceManager* resources) { ARDUINOJSON_ASSERT(data_ != nullptr);
ARDUINOJSON_ASSERT(resources_ != nullptr);
key->setNext(value.id()); key->setNext(value.id());
if (tail_ != NULL_SLOT) { if (data_->tail != NULL_SLOT) {
auto tail = resources->getVariant(tail_); auto tail = resources_->getVariant(data_->tail);
tail->setNext(key.id()); tail->setNext(key.id());
tail_ = value.id(); data_->tail = value.id();
} else { } else {
head_ = key.id(); data_->head = key.id();
tail_ = value.id(); data_->tail = value.id();
} }
} }
inline void CollectionData::clear(ResourceManager* resources) { inline void CollectionImpl::clear() {
auto next = head_; if (!data_)
return;
auto next = data_->head;
while (next != NULL_SLOT) { while (next != NULL_SLOT) {
auto currId = next; auto currId = next;
auto slot = resources->getVariant(next); auto slot = resources_->getVariant(next);
next = slot->next(); next = slot->next();
resources->freeVariant({slot, currId}); resources_->freeVariant({slot, currId});
} }
head_ = NULL_SLOT; data_->head = NULL_SLOT;
tail_ = NULL_SLOT; data_->tail = NULL_SLOT;
} }
inline Slot<VariantData> CollectionData::getPreviousSlot( inline Slot<VariantData> CollectionImpl::getPreviousSlot(
VariantData* target, const ResourceManager* resources) const { VariantData* target) const {
auto prev = Slot<VariantData>(); auto prev = Slot<VariantData>();
auto currentId = head_; auto currentId = data_->head;
while (currentId != NULL_SLOT) { while (currentId != NULL_SLOT) {
auto currentSlot = resources->getVariant(currentId); auto currentSlot = resources_->getVariant(currentId);
if (currentSlot == target) if (currentSlot == target)
break; break;
prev = Slot<VariantData>(currentSlot, currentId); prev = Slot<VariantData>(currentSlot, currentId);
@ -84,52 +91,53 @@ inline Slot<VariantData> CollectionData::getPreviousSlot(
return prev; return prev;
} }
inline void CollectionData::removeOne(iterator it, ResourceManager* resources) { inline void CollectionImpl::removeOne(iterator it) {
if (it.done()) if (it.done())
return; return;
auto curr = it.slot_; auto curr = it.slot_;
auto prev = getPreviousSlot(curr, resources); auto prev = getPreviousSlot(curr);
auto next = curr->next(); auto next = curr->next();
if (prev) if (prev)
prev->setNext(next); prev->setNext(next);
else else
head_ = next; data_->head = next;
if (next == NULL_SLOT) if (next == NULL_SLOT)
tail_ = prev.id(); data_->tail = prev.id();
resources->freeVariant({it.slot_, it.currentId_}); resources_->freeVariant({it.slot_, it.currentId_});
} }
inline void CollectionData::removePair(ObjectData::iterator it, inline void CollectionImpl::removePair(ObjectImpl::iterator it) {
ResourceManager* resources) {
if (it.done()) if (it.done())
return; return;
auto keySlot = it.slot_; auto keySlot = it.slot_;
auto valueId = it.nextId_; auto valueId = it.nextId_;
auto valueSlot = resources->getVariant(valueId); auto valueSlot = resources_->getVariant(valueId);
// remove value slot // remove value slot
keySlot->setNext(valueSlot->next()); keySlot->setNext(valueSlot->next());
resources->freeVariant({valueSlot, valueId}); resources_->freeVariant({valueSlot, valueId});
// remove key slot // remove key slot
removeOne(it, resources); removeOne(it);
} }
inline size_t CollectionData::nesting(const ResourceManager* resources) const { inline size_t CollectionImpl::nesting() const {
if (!data_)
return 0;
size_t maxChildNesting = 0; size_t maxChildNesting = 0;
for (auto it = createIterator(resources); !it.done(); it.next(resources)) { for (auto it = createIterator(); !it.done(); it.next(resources_)) {
size_t childNesting = it->nesting(resources); size_t childNesting = it->nesting(resources_);
if (childNesting > maxChildNesting) if (childNesting > maxChildNesting)
maxChildNesting = childNesting; maxChildNesting = childNesting;
} }
return maxChildNesting + 1; return maxChildNesting + 1;
} }
inline size_t CollectionData::size(const ResourceManager* resources) const { inline size_t CollectionImpl::size() const {
size_t count = 0; size_t count = 0;
for (auto it = createIterator(resources); !it.done(); it.next(resources)) for (auto it = createIterator(); !it.done(); it.next(resources_))
count++; count++;
return count; return count;
} }

View File

@ -415,8 +415,8 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
return &data_; return &data_;
} }
detail::ResourceManager resources_; mutable detail::ResourceManager resources_;
detail::VariantData data_; mutable detail::VariantData data_;
}; };
inline void convertToJson(const JsonDocument& src, JsonVariant dst) { inline void convertToJson(const JsonDocument& src, JsonVariant dst) {

View File

@ -71,13 +71,14 @@ class JsonDeserializer {
switch (current()) { switch (current()) {
case '[': case '[':
if (filter.allowArray()) if (filter.allowArray())
return parseArray(variant.toArray(), filter, nestingLimit); return parseArray(variant.toArray(resources_), filter, nestingLimit);
else else
return skipArray(nestingLimit); return skipArray(nestingLimit);
case '{': case '{':
if (filter.allowObject()) if (filter.allowObject())
return parseObject(variant.toObject(), filter, nestingLimit); return parseObject(variant.toObject(resources_), filter,
nestingLimit);
else else
return skipObject(nestingLimit); return skipObject(nestingLimit);
@ -146,7 +147,7 @@ class JsonDeserializer {
template <typename TFilter> template <typename TFilter>
DeserializationError::Code parseArray( DeserializationError::Code parseArray(
ArrayData& array, TFilter filter, ArrayImpl array, TFilter filter,
DeserializationOption::NestingLimit nestingLimit) { DeserializationOption::NestingLimit nestingLimit) {
DeserializationError::Code err; DeserializationError::Code err;
@ -172,7 +173,7 @@ class JsonDeserializer {
for (;;) { for (;;) {
if (elementFilter.allow()) { if (elementFilter.allow()) {
// Allocate slot in array // Allocate slot in array
VariantData* value = array.addElement(resources_); VariantData* value = array.addElement();
if (!value) if (!value)
return DeserializationError::NoMemory; return DeserializationError::NoMemory;
@ -232,7 +233,7 @@ class JsonDeserializer {
template <typename TFilter> template <typename TFilter>
DeserializationError::Code parseObject( DeserializationError::Code parseObject(
ObjectData& object, TFilter filter, ObjectImpl object, TFilter filter,
DeserializationOption::NestingLimit nestingLimit) { DeserializationOption::NestingLimit nestingLimit) {
DeserializationError::Code err; DeserializationError::Code err;
@ -273,9 +274,9 @@ class JsonDeserializer {
TFilter memberFilter = filter[key]; TFilter memberFilter = filter[key];
if (memberFilter.allow()) { if (memberFilter.allow()) {
auto member = object.getMember(adaptString(key), resources_); auto member = object.getMember(adaptString(key));
if (!member) { if (!member) {
auto keyVariant = object.addPair(&member, resources_); auto keyVariant = object.addPair(&member);
if (!keyVariant) if (!keyVariant)
return DeserializationError::NoMemory; return DeserializationError::NoMemory;

View File

@ -16,10 +16,10 @@ class JsonSerializer : public VariantDataVisitor<size_t> {
public: public:
static const bool producesText = true; static const bool producesText = true;
JsonSerializer(TWriter writer, const ResourceManager* resources) JsonSerializer(TWriter writer, ResourceManager* resources)
: formatter_(writer), resources_(resources) {} : formatter_(writer), resources_(resources) {}
size_t visit(const ArrayData& array) { size_t visit(const ArrayImpl& 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 ObjectData& object) { size_t visit(const ObjectImpl& object) {
write('{'); write('{');
auto slotId = object.head(); auto slotId = object.head();
@ -120,7 +120,7 @@ class JsonSerializer : public VariantDataVisitor<size_t> {
TextFormatter<TWriter> formatter_; TextFormatter<TWriter> formatter_;
protected: protected:
const ResourceManager* resources_; ResourceManager* resources_;
}; };
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

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

View File

@ -349,12 +349,10 @@ class MsgPackDeserializer {
bool allowArray = filter.allowArray(); bool allowArray = filter.allowArray();
ArrayData* array; ArrayImpl array;
if (allowArray) { if (allowArray) {
ARDUINOJSON_ASSERT(variant != 0); ARDUINOJSON_ASSERT(variant != 0);
array = &variant->toArray(); array = variant->toArray(resources_);
} else {
array = 0;
} }
TFilter elementFilter = filter[0U]; TFilter elementFilter = filter[0U];
@ -363,8 +361,7 @@ class MsgPackDeserializer {
VariantData* value; VariantData* value;
if (elementFilter.allow()) { if (elementFilter.allow()) {
ARDUINOJSON_ASSERT(array != 0); value = array.addElement();
value = array->addElement(resources_);
if (!value) if (!value)
return DeserializationError::NoMemory; return DeserializationError::NoMemory;
} else { } else {
@ -388,12 +385,10 @@ class MsgPackDeserializer {
if (nestingLimit.reached()) if (nestingLimit.reached())
return DeserializationError::TooDeep; return DeserializationError::TooDeep;
ObjectData* object; ObjectImpl object;
if (filter.allowObject()) { if (filter.allowObject()) {
ARDUINOJSON_ASSERT(variant != 0); ARDUINOJSON_ASSERT(variant != 0);
object = &variant->toObject(); object = variant->toObject(resources_);
} else {
object = 0;
} }
for (; n; --n) { for (; n; --n) {
@ -406,9 +401,7 @@ class MsgPackDeserializer {
VariantData* member = 0; VariantData* member = 0;
if (memberFilter.allow()) { if (memberFilter.allow()) {
ARDUINOJSON_ASSERT(object != 0); auto keyVariant = object.addPair(&member);
auto keyVariant = object->addPair(&member, resources_);
if (!keyVariant) if (!keyVariant)
return DeserializationError::NoMemory; return DeserializationError::NoMemory;

View File

@ -19,7 +19,7 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
public: public:
static const bool producesText = false; static const bool producesText = false;
MsgPackSerializer(TWriter writer, const ResourceManager* resources) MsgPackSerializer(TWriter writer, ResourceManager* resources)
: writer_(writer), resources_(resources) {} : writer_(writer), resources_(resources) {}
template <typename T> template <typename T>
@ -47,8 +47,8 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
return bytesWritten(); return bytesWritten();
} }
size_t visit(const ArrayData& array) { size_t visit(const ArrayImpl& array) {
size_t n = array.size(resources_); size_t n = array.size();
if (n < 0x10) { if (n < 0x10) {
writeByte(uint8_t(0x90 + n)); writeByte(uint8_t(0x90 + n));
} else if (n < 0x10000) { } else if (n < 0x10000) {
@ -69,8 +69,8 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
return bytesWritten(); return bytesWritten();
} }
size_t visit(const ObjectData& object) { size_t visit(const ObjectImpl& object) {
size_t n = object.size(resources_); size_t n = object.size();
if (n < 0x10) { if (n < 0x10) {
writeByte(uint8_t(0x80 + n)); writeByte(uint8_t(0x80 + n));
} else if (n < 0x10000) { } else if (n < 0x10000) {
@ -209,7 +209,7 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
} }
CountingDecorator<TWriter> writer_; CountingDecorator<TWriter> writer_;
const ResourceManager* resources_; ResourceManager* resources_;
}; };
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -20,30 +20,31 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
using iterator = JsonObjectIterator; using iterator = JsonObjectIterator;
// Creates an unbound reference. // Creates an unbound reference.
JsonObject() : data_(0), resources_(0) {} JsonObject() {}
// INTERNAL USE ONLY
JsonObject(const detail::ObjectImpl& impl) : impl_(impl) {}
// INTERNAL USE ONLY // INTERNAL USE ONLY
JsonObject(detail::VariantData* data, detail::ResourceManager* resource) JsonObject(detail::VariantData* data, detail::ResourceManager* resource)
: data_(data), resources_(resource) {} : impl_(detail::VariantData::asObject(data, resource)) {}
operator JsonVariant() const { operator JsonVariant() const {
void* data = data_; // prevent warning cast-align return JsonVariant(getData(), getResourceManager());
return JsonVariant(reinterpret_cast<detail::VariantData*>(data),
resources_);
} }
operator JsonObjectConst() const { operator JsonObjectConst() const {
return JsonObjectConst(data_, resources_); return JsonObjectConst(getData(), getResourceManager());
} }
operator JsonVariantConst() const { operator JsonVariantConst() const {
return JsonVariantConst(data_, resources_); return JsonVariantConst(getData(), getResourceManager());
} }
// 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 !data_ || !data_->isObject(); return impl_.isNull();
} }
// Returns true if the reference is bound. // Returns true if the reference is bound.
@ -55,22 +56,19 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
// Returns the depth (nesting level) of the object. // Returns the depth (nesting level) of the object.
// https://arduinojson.org/v7/api/jsonobject/nesting/ // https://arduinojson.org/v7/api/jsonobject/nesting/
size_t nesting() const { size_t nesting() const {
return detail::VariantData::nesting(data_, resources_); return impl_.nesting();
} }
// Returns the number of members in the object. // Returns the number of members in the object.
// https://arduinojson.org/v7/api/jsonobject/size/ // https://arduinojson.org/v7/api/jsonobject/size/
size_t size() const { size_t size() const {
return data_ ? data_->size(resources_) : 0; return impl_.size();
} }
// Returns an iterator to the first key-value pair of the object. // Returns an iterator to the first key-value pair of the object.
// https://arduinojson.org/v7/api/jsonobject/begin/ // https://arduinojson.org/v7/api/jsonobject/begin/
iterator begin() const { iterator begin() const {
auto obj = detail::VariantData::asObject(data_); return iterator(impl_.createIterator(), impl_.getResourceManager());
if (!obj)
return iterator();
return iterator(obj->createIterator(resources_), resources_);
} }
// Returns an iterator following the last key-value pair of the object. // Returns an iterator following the last key-value pair of the object.
@ -82,13 +80,13 @@ 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 {
detail::ObjectData::clear(detail::VariantData::asObject(data_), resources_); impl_.clear();
} }
// Copies an object. // Copies an object.
// https://arduinojson.org/v7/api/jsonobject/set/ // https://arduinojson.org/v7/api/jsonobject/set/
bool set(JsonObjectConst src) { bool set(JsonObjectConst src) {
if (!data_ || !src.data_) if (isNull() || src.isNull())
return false; return false;
clear(); clear();
@ -132,8 +130,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 {
detail::ObjectData::remove(detail::VariantData::asObject(data_), impl_.remove(it.iterator_);
it.iterator_, resources_);
} }
// Removes the member with the specified key. // Removes the member with the specified key.
@ -141,8 +138,7 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
template <typename TString, template <typename TString,
detail::enable_if_t<detail::IsString<TString>::value, int> = 0> detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
void remove(const TString& key) const { void remove(const TString& key) const {
detail::VariantData::removeMember(data_, detail::adaptString(key), impl_.removeMember(detail::adaptString(key));
resources_);
} }
// Removes the member with the specified key. // Removes the member with the specified key.
@ -158,8 +154,7 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
// https://arduinojson.org/v7/api/jsonobject/remove/ // https://arduinojson.org/v7/api/jsonobject/remove/
template <typename TChar> template <typename TChar>
FORCE_INLINE void remove(TChar* key) const { FORCE_INLINE void remove(TChar* key) const {
detail::VariantData::removeMember(data_, detail::adaptString(key), impl_.removeMember(detail::adaptString(key));
resources_);
} }
// DEPRECATED: use obj[key].is<T>() instead // DEPRECATED: use obj[key].is<T>() instead
@ -168,8 +163,7 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
detail::enable_if_t<detail::IsString<TString>::value, int> = 0> detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
ARDUINOJSON_DEPRECATED("use obj[key].is<T>() instead") ARDUINOJSON_DEPRECATED("use obj[key].is<T>() instead")
bool containsKey(const TString& key) const { bool containsKey(const TString& key) const {
return detail::VariantData::getMember(data_, detail::adaptString(key), return impl_.getMember(detail::adaptString(key)) != 0;
resources_) != 0;
} }
// DEPRECATED: use obj["key"].is<T>() instead // DEPRECATED: use obj["key"].is<T>() instead
@ -180,8 +174,7 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
int> = 0> int> = 0>
ARDUINOJSON_DEPRECATED("use obj[\"key\"].is<T>() instead") ARDUINOJSON_DEPRECATED("use obj[\"key\"].is<T>() instead")
bool containsKey(TChar* key) const { bool containsKey(TChar* key) const {
return detail::VariantData::getMember(data_, detail::adaptString(key), return impl_.getMember(detail::adaptString(key)) != 0;
resources_) != 0;
} }
// DEPRECATED: use obj[key].is<T>() instead // DEPRECATED: use obj[key].is<T>() instead
@ -229,19 +222,18 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
private: private:
detail::ResourceManager* getResourceManager() const { detail::ResourceManager* getResourceManager() const {
return resources_; return impl_.getResourceManager();
} }
detail::VariantData* getData() const { detail::VariantData* getData() const {
return data_; return impl_.getData();
} }
detail::VariantData* getOrCreateData() const { detail::VariantData* getOrCreateData() const {
return data_; return impl_.getData();
} }
detail::VariantData* data_; mutable detail::ObjectImpl impl_;
detail::ResourceManager* resources_;
}; };
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@ -19,21 +19,23 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
using iterator = JsonObjectConstIterator; using iterator = JsonObjectConstIterator;
// Creates an unbound reference. // Creates an unbound reference.
JsonObjectConst() : data_(0), resources_(0) {} JsonObjectConst() {}
// INTERNAL USE ONLY // INTERNAL USE ONLY
JsonObjectConst(const detail::VariantData* data, JsonObjectConst(detail::VariantData* data, detail::ResourceManager* resources)
const detail::ResourceManager* resources) : impl_(detail::VariantData::asObject(data, resources)) {}
: data_(data), resources_(resources) {}
// INTERNAL USE ONLY
JsonObjectConst(const detail::ObjectImpl& impl) : impl_(impl) {}
operator JsonVariantConst() const { operator JsonVariantConst() const {
return JsonVariantConst(getData(), resources_); return JsonVariantConst(impl_.getData(), impl_.getResourceManager());
} }
// Returns true if the reference is unbound. // Returns true if the reference is unbound.
// https://arduinojson.org/v7/api/jsonobjectconst/isnull/ // https://arduinojson.org/v7/api/jsonobjectconst/isnull/
bool isNull() const { bool isNull() const {
return !data_ || !data_->isObject(); return impl_.isNull();
} }
// Returns true if the reference is bound. // Returns true if the reference is bound.
@ -45,22 +47,19 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
// Returns the depth (nesting level) of the object. // Returns the depth (nesting level) of the object.
// https://arduinojson.org/v7/api/jsonobjectconst/nesting/ // https://arduinojson.org/v7/api/jsonobjectconst/nesting/
size_t nesting() const { size_t nesting() const {
return detail::VariantData::nesting(getData(), resources_); return impl_.nesting();
} }
// Returns the number of members in the object. // Returns the number of members in the object.
// https://arduinojson.org/v7/api/jsonobjectconst/size/ // https://arduinojson.org/v7/api/jsonobjectconst/size/
size_t size() const { size_t size() const {
return data_ ? data_->size(resources_) : 0; return impl_.size();
} }
// Returns an iterator to the first key-value pair of the object. // Returns an iterator to the first key-value pair of the object.
// https://arduinojson.org/v7/api/jsonobjectconst/begin/ // https://arduinojson.org/v7/api/jsonobjectconst/begin/
iterator begin() const { iterator begin() const {
auto obj = detail::VariantData::asObject(data_); return iterator(impl_.createIterator(), impl_.getResourceManager());
if (!obj)
return iterator();
return iterator(obj->createIterator(resources_), resources_);
} }
// Returns an iterator following the last key-value pair of the object. // Returns an iterator following the last key-value pair of the object.
@ -75,8 +74,7 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
detail::enable_if_t<detail::IsString<TString>::value, int> = 0> detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
ARDUINOJSON_DEPRECATED("use obj[key].is<T>() instead") ARDUINOJSON_DEPRECATED("use obj[key].is<T>() instead")
bool containsKey(const TString& key) const { bool containsKey(const TString& key) const {
return detail::VariantData::getMember(data_, detail::adaptString(key), return impl_.getMember(detail::adaptString(key)) != 0;
resources_) != 0;
} }
// DEPRECATED: use obj["key"].is<T>() instead // DEPRECATED: use obj["key"].is<T>() instead
@ -84,8 +82,7 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
template <typename TChar> template <typename TChar>
ARDUINOJSON_DEPRECATED("use obj[\"key\"].is<T>() instead") ARDUINOJSON_DEPRECATED("use obj[\"key\"].is<T>() instead")
bool containsKey(TChar* key) const { bool containsKey(TChar* key) const {
return detail::VariantData::getMember(data_, detail::adaptString(key), return impl_.getMember(detail::adaptString(key)) != 0;
resources_) != 0;
} }
// DEPRECATED: use obj[key].is<T>() instead // DEPRECATED: use obj[key].is<T>() instead
@ -102,9 +99,8 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
template <typename TString, template <typename TString,
detail::enable_if_t<detail::IsString<TString>::value, int> = 0> detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
JsonVariantConst operator[](const TString& key) const { JsonVariantConst operator[](const TString& key) const {
return JsonVariantConst(detail::VariantData::getMember( return JsonVariantConst(impl_.getMember(detail::adaptString(key)),
data_, detail::adaptString(key), resources_), impl_.getResourceManager());
resources_);
} }
// Gets the member with specified key. // Gets the member with specified key.
@ -114,9 +110,8 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
!detail::is_const<TChar>::value, !detail::is_const<TChar>::value,
int> = 0> int> = 0>
JsonVariantConst operator[](TChar* key) const { JsonVariantConst operator[](TChar* key) const {
return JsonVariantConst(detail::VariantData::getMember( return JsonVariantConst(impl_.getMember(detail::adaptString(key)),
data_, detail::adaptString(key), resources_), impl_.getResourceManager());
resources_);
} }
// Gets the member with specified key. // Gets the member with specified key.
@ -138,11 +133,10 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
private: private:
const detail::VariantData* getData() const { const detail::VariantData* getData() const {
return data_; return impl_.getData();
} }
const detail::VariantData* data_; detail::ObjectImpl impl_;
const detail::ResourceManager* resources_;
}; };
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::ObjectData::iterator iterator, explicit JsonObjectIterator(detail::ObjectImpl::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::ObjectData::iterator iterator_; detail::ObjectImpl::iterator iterator_;
detail::ResourceManager* resources_; detail::ResourceManager* resources_;
}; };
@ -50,8 +50,8 @@ class JsonObjectConstIterator {
public: public:
JsonObjectConstIterator() {} JsonObjectConstIterator() {}
explicit JsonObjectConstIterator(detail::ObjectData::iterator iterator, explicit JsonObjectConstIterator(detail::ObjectImpl::iterator iterator,
const detail::ResourceManager* resources) detail::ResourceManager* resources)
: iterator_(iterator), resources_(resources) {} : iterator_(iterator), resources_(resources) {}
JsonPairConst operator*() const { JsonPairConst operator*() const {
@ -76,8 +76,8 @@ class JsonObjectConstIterator {
} }
private: private:
detail::ObjectData::iterator iterator_; detail::ObjectImpl::iterator iterator_;
const detail::ResourceManager* resources_; detail::ResourceManager* resources_;
}; };
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@ -15,7 +15,7 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
class JsonPair { class JsonPair {
public: public:
// INTERNAL USE ONLY // INTERNAL USE ONLY
JsonPair(detail::ObjectData::iterator iterator, JsonPair(detail::ObjectImpl::iterator iterator,
detail::ResourceManager* resources) { detail::ResourceManager* resources) {
if (!iterator.done()) { if (!iterator.done()) {
key_ = iterator->asString(resources); key_ = iterator->asString(resources);
@ -43,8 +43,8 @@ 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::ObjectData::iterator iterator, JsonPairConst(detail::ObjectImpl::iterator iterator,
const detail::ResourceManager* resources) { detail::ResourceManager* resources) {
if (!iterator.done()) { if (!iterator.done()) {
key_ = iterator->asString(resources); key_ = iterator->asString(resources);
iterator.next(resources); iterator.next(resources);

View File

@ -8,63 +8,38 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class ObjectData : public CollectionData { class ObjectImpl : public CollectionImpl {
public: public:
template <typename TAdaptedString> ObjectImpl() {}
VariantData* addMember(TAdaptedString key, ResourceManager* resources);
VariantData* addPair(VariantData** value, ResourceManager* resources); ObjectImpl(CollectionData* data, ResourceManager* resources)
: CollectionImpl(data, resources) {}
template <typename TAdaptedString> template <typename TAdaptedString>
VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources); VariantData* addMember(TAdaptedString key);
VariantData* addPair(VariantData** value);
template <typename TAdaptedString> template <typename TAdaptedString>
VariantData* getMember(TAdaptedString key, VariantData* getOrAddMember(TAdaptedString key);
const ResourceManager* resources) const;
template <typename TAdaptedString> template <typename TAdaptedString>
static VariantData* getMember(const ObjectData* object, TAdaptedString key, VariantData* getMember(TAdaptedString key) const;
const ResourceManager* resources) {
if (!object) template <typename TAdaptedString>
return nullptr; void removeMember(TAdaptedString key);
return object->getMember(key, resources);
void remove(iterator it) {
CollectionImpl::removePair(it);
} }
template <typename TAdaptedString> size_t size() const {
void removeMember(TAdaptedString key, ResourceManager* resources); return CollectionImpl::size() / 2;
template <typename TAdaptedString>
static void removeMember(ObjectData* obj, TAdaptedString key,
ResourceManager* resources) {
if (!obj)
return;
obj->removeMember(key, resources);
}
void remove(iterator it, ResourceManager* resources) {
CollectionData::removePair(it, resources);
}
static void remove(ObjectData* obj, ObjectData::iterator it,
ResourceManager* resources) {
if (!obj)
return;
obj->remove(it, resources);
}
size_t size(const ResourceManager* resources) const {
return CollectionData::size(resources) / 2;
}
static size_t size(const ObjectData* obj, const ResourceManager* resources) {
if (!obj)
return 0;
return obj->size(resources);
} }
private: private:
template <typename TAdaptedString> template <typename TAdaptedString>
iterator findKey(TAdaptedString key, const ResourceManager* resources) const; iterator findKey(TAdaptedString key) const;
}; };
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -11,32 +11,29 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TAdaptedString> template <typename TAdaptedString>
inline VariantData* ObjectData::getMember( inline VariantData* ObjectImpl::getMember(TAdaptedString key) const {
TAdaptedString key, const ResourceManager* resources) const { auto it = findKey(key);
auto it = findKey(key, resources);
if (it.done()) if (it.done())
return nullptr; return nullptr;
it.next(resources); it.next(resources_);
return it.data(); return it.data();
} }
template <typename TAdaptedString> template <typename TAdaptedString>
VariantData* ObjectData::getOrAddMember(TAdaptedString key, VariantData* ObjectImpl::getOrAddMember(TAdaptedString key) {
ResourceManager* resources) { auto data = getMember(key);
auto data = getMember(key, resources);
if (data) if (data)
return data; return data;
return addMember(key, resources); return addMember(key);
} }
template <typename TAdaptedString> template <typename TAdaptedString>
inline ObjectData::iterator ObjectData::findKey( inline ObjectImpl::iterator ObjectImpl::findKey(TAdaptedString key) const {
TAdaptedString key, const ResourceManager* resources) const {
if (key.isNull()) if (key.isNull())
return iterator(); return iterator();
bool isKey = true; bool isKey = true;
for (auto it = createIterator(resources); !it.done(); it.next(resources)) { for (auto it = createIterator(); !it.done(); it.next(resources_)) {
if (isKey && stringEquals(key, adaptString(it->asString(resources)))) if (isKey && stringEquals(key, adaptString(it->asString(resources_))))
return it; return it;
isKey = !isKey; isKey = !isKey;
} }
@ -44,42 +41,47 @@ inline ObjectData::iterator ObjectData::findKey(
} }
template <typename TAdaptedString> template <typename TAdaptedString>
inline void ObjectData::removeMember(TAdaptedString key, inline void ObjectImpl::removeMember(TAdaptedString key) {
ResourceManager* resources) { remove(findKey(key));
remove(findKey(key, resources), resources);
} }
template <typename TAdaptedString> template <typename TAdaptedString>
inline VariantData* ObjectData::addMember(TAdaptedString key, inline VariantData* ObjectImpl::addMember(TAdaptedString key) {
ResourceManager* resources) { if (!data_)
auto keySlot = resources->allocVariant(); return nullptr;
ARDUINOJSON_ASSERT(resources_ != nullptr);
auto keySlot = resources_->allocVariant();
if (!keySlot) if (!keySlot)
return nullptr; return nullptr;
auto valueSlot = resources->allocVariant(); auto valueSlot = resources_->allocVariant();
if (!valueSlot) if (!valueSlot)
return nullptr; return nullptr;
if (!keySlot->setString(key, resources)) if (!keySlot->setString(key, resources_))
return nullptr; return nullptr;
CollectionData::appendPair(keySlot, valueSlot, resources); CollectionImpl::appendPair(keySlot, valueSlot);
return valueSlot.ptr(); return valueSlot.ptr();
} }
inline VariantData* ObjectData::addPair(VariantData** value, inline VariantData* ObjectImpl::addPair(VariantData** value) {
ResourceManager* resources) { if (!data_)
auto keySlot = resources->allocVariant(); return nullptr;
ARDUINOJSON_ASSERT(resources_ != nullptr);
auto keySlot = resources_->allocVariant();
if (!keySlot) if (!keySlot)
return nullptr; return nullptr;
auto valueSlot = resources->allocVariant(); auto valueSlot = resources_->allocVariant();
if (!valueSlot) if (!valueSlot)
return nullptr; return nullptr;
*value = valueSlot.ptr(); *value = valueSlot.ptr();
CollectionData::appendPair(keySlot, valueSlot, resources); CollectionImpl::appendPair(keySlot, valueSlot);
return keySlot.ptr(); return keySlot.ptr();
} }

View File

@ -38,8 +38,8 @@ class JsonVariantConst : public detail::VariantTag,
JsonVariantConst() : data_(nullptr), resources_(nullptr) {} JsonVariantConst() : data_(nullptr), resources_(nullptr) {}
// INTERNAL USE ONLY // INTERNAL USE ONLY
explicit JsonVariantConst(const detail::VariantData* data, explicit JsonVariantConst(detail::VariantData* data,
const detail::ResourceManager* resources) detail::ResourceManager* resources)
: data_(data), resources_(resources) {} : data_(data), resources_(resources) {}
// Returns true if the value is null or the reference is unbound. // Returns true if the value is null or the reference is unbound.
@ -181,17 +181,17 @@ class JsonVariantConst : public detail::VariantTag,
} }
protected: protected:
const detail::VariantData* getData() const { detail::VariantData* getData() const {
return data_; return data_;
} }
const detail::ResourceManager* getResourceManager() const { detail::ResourceManager* getResourceManager() const {
return resources_; return resources_;
} }
private: private:
const detail::VariantData* data_; mutable detail::VariantData* data_;
const detail::ResourceManager* resources_; mutable detail::ResourceManager* resources_;
}; };
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@ -26,17 +26,14 @@ class VisitorAdapter {
public: public:
using result_type = typename TVisitor::result_type; using result_type = typename TVisitor::result_type;
VisitorAdapter(TVisitor& visitor, const ResourceManager* resources) VisitorAdapter(TVisitor& visitor) : visitor_(&visitor) {}
: visitor_(&visitor), resources_(resources) {}
result_type visit(const ArrayData& value) { result_type visit(const ArrayImpl& array) {
return visitor_->visit( return visitor_->visit(JsonArrayConst(array));
JsonArrayConst(collectionToVariant(&value), resources_));
} }
result_type visit(const ObjectData& value) { result_type visit(const ObjectImpl& object) {
return visitor_->visit( return visitor_->visit(JsonObjectConst(object));
JsonObjectConst(collectionToVariant(&value), resources_));
} }
template <typename T> template <typename T>
@ -46,7 +43,6 @@ class VisitorAdapter {
private: private:
TVisitor* visitor_; TVisitor* visitor_;
const ResourceManager* resources_;
}; };
template <typename TVisitor> template <typename TVisitor>
@ -56,7 +52,7 @@ typename TVisitor::result_type accept(JsonVariantConst variant,
if (!data) if (!data)
return visit.visit(nullptr); return visit.visit(nullptr);
auto resources = VariantAttorney::getResourceManager(variant); auto resources = VariantAttorney::getResourceManager(variant);
VisitorAdapter<TVisitor> adapter(visit, resources); VisitorAdapter<TVisitor> adapter(visit);
return data->accept(adapter, resources); return data->accept(adapter, resources);
} }

View File

@ -57,8 +57,6 @@ union VariantContent {
uint32_t asUint32; uint32_t asUint32;
int32_t asInt32; int32_t asInt32;
SlotId asSlotId; SlotId asSlotId;
ArrayData asArray;
ObjectData asObject;
CollectionData asCollection; CollectionData asCollection;
struct StringNode* asOwnedString; struct StringNode* asOwnedString;
char asTinyString[tinyStringMaxLength + 1]; char asTinyString[tinyStringMaxLength + 1];

View File

@ -51,8 +51,8 @@ class VariantData {
} }
template <typename TVisitor> template <typename TVisitor>
typename TVisitor::result_type accept( typename TVisitor::result_type accept(TVisitor& visit,
TVisitor& visit, const ResourceManager* resources) const { ResourceManager* resources) {
#if ARDUINOJSON_USE_8_BYTE_POOL #if ARDUINOJSON_USE_8_BYTE_POOL
auto eightByteValue = getEightByte(resources); auto eightByteValue = getEightByte(resources);
#else #else
@ -68,10 +68,10 @@ class VariantData {
#endif #endif
case VariantType::Array: case VariantType::Array:
return visit.visit(content_.asArray); return visit.visit(asArray(resources));
case VariantType::Object: case VariantType::Object:
return visit.visit(content_.asObject); return visit.visit(asObject(resources));
case VariantType::TinyString: case VariantType::TinyString:
return visit.visit(JsonString(content_.asTinyString)); return visit.visit(JsonString(content_.asTinyString));
@ -110,8 +110,8 @@ class VariantData {
} }
template <typename TVisitor> template <typename TVisitor>
static typename TVisitor::result_type accept(const VariantData* var, static typename TVisitor::result_type accept(VariantData* var,
const ResourceManager* resources, ResourceManager* resources,
TVisitor& visit) { TVisitor& visit) {
if (var != 0) if (var != 0)
return var->accept(visit, resources); return var->accept(visit, resources);
@ -120,8 +120,8 @@ class VariantData {
} }
VariantData* addElement(ResourceManager* resources) { VariantData* addElement(ResourceManager* resources) {
auto array = isNull() ? &toArray() : asArray(); auto array = isNull() ? toArray(resources) : asArray(resources);
return detail::ArrayData::addElement(array, resources); return array.addElement();
} }
static VariantData* addElement(VariantData* var, ResourceManager* resources) { static VariantData* addElement(VariantData* var, ResourceManager* resources) {
@ -132,8 +132,8 @@ class VariantData {
template <typename T> template <typename T>
bool addValue(const T& value, ResourceManager* resources) { bool addValue(const T& value, ResourceManager* resources) {
auto array = isNull() ? &toArray() : asArray(); auto array = isNull() ? toArray(resources) : asArray(resources);
return detail::ArrayData::addValue(array, value, resources); return array.addValue(value);
} }
template <typename T> template <typename T>
@ -174,28 +174,19 @@ class VariantData {
} }
} }
ArrayData* asArray() { ArrayImpl asArray(ResourceManager* resources) {
return isArray() ? &content_.asArray : 0; return ArrayImpl(isArray() ? &content_.asCollection : nullptr, resources);
} }
const ArrayData* asArray() const { static ArrayImpl asArray(VariantData* var, ResourceManager* resources) {
return const_cast<VariantData*>(this)->asArray(); return ArrayImpl(
var && var->isArray() ? &var->content_.asCollection : nullptr,
resources);
} }
static ArrayData* asArray(VariantData* var) { CollectionImpl asCollection(ResourceManager* resources) {
return var ? var->asArray() : 0; return CollectionImpl(isCollection() ? &content_.asCollection : nullptr,
} resources);
static const ArrayData* asArray(const VariantData* var) {
return var ? var->asArray() : 0;
}
CollectionData* asCollection() {
return isCollection() ? &content_.asCollection : 0;
}
const CollectionData* asCollection() const {
return const_cast<VariantData*>(this)->asCollection();
} }
template <typename T> template <typename T>
@ -288,20 +279,14 @@ class VariantData {
return parseNumber<T>(str); return parseNumber<T>(str);
} }
ObjectData* asObject() { ObjectImpl asObject(ResourceManager* resources) {
return isObject() ? &content_.asObject : 0; return ObjectImpl(isObject() ? &content_.asCollection : nullptr, resources);
} }
const ObjectData* asObject() const { static ObjectImpl asObject(VariantData* var, ResourceManager* resources) {
return const_cast<VariantData*>(this)->asObject(); return ObjectImpl(
} var && var->isObject() ? &var->content_.asCollection : nullptr,
resources);
static ObjectData* asObject(VariantData* var) {
return var ? var->asObject() : 0;
}
static const ObjectData* asObject(const VariantData* var) {
return var ? var->asObject() : 0;
} }
JsonString asRawString() const { JsonString asRawString() const {
@ -334,45 +319,41 @@ class VariantData {
const EightByteValue* getEightByte(const ResourceManager* resources) const; const EightByteValue* getEightByte(const ResourceManager* resources) const;
#endif #endif
VariantData* getElement(size_t index, VariantData* getElement(size_t index, ResourceManager* resources) {
const ResourceManager* resources) const { return asArray(resources).getElement(index);
return ArrayData::getElement(asArray(), index, resources);
} }
static VariantData* getElement(const VariantData* var, size_t index, static VariantData* getElement(VariantData* var, size_t index,
const ResourceManager* resources) { ResourceManager* resources) {
return var != 0 ? var->getElement(index, resources) : 0; if (!var)
return nullptr;
return var->asArray(resources).getElement(index);
} }
template <typename TAdaptedString> template <typename TAdaptedString>
VariantData* getMember(TAdaptedString key, VariantData* getMember(TAdaptedString key, ResourceManager* resources) {
const ResourceManager* resources) const { return asObject(resources).getMember(key);
return ObjectData::getMember(asObject(), key, resources);
} }
template <typename TAdaptedString> template <typename TAdaptedString>
static VariantData* getMember(const VariantData* var, TAdaptedString key, static VariantData* getMember(VariantData* var, TAdaptedString key,
const ResourceManager* resources) { ResourceManager* resources) {
if (!var) if (!var)
return 0; return 0;
return var->getMember(key, resources); return var->getMember(key, resources);
} }
VariantData* getOrAddElement(size_t index, ResourceManager* resources) { VariantData* getOrAddElement(size_t index, ResourceManager* resources) {
auto array = isNull() ? &toArray() : asArray(); auto array = isNull() ? toArray(resources) : asArray(resources);
if (!array) return array.getOrAddElement(index);
return nullptr;
return array->getOrAddElement(index, resources);
} }
template <typename TAdaptedString> template <typename TAdaptedString>
VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources) { VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources) {
if (key.isNull()) if (key.isNull())
return nullptr; return nullptr;
auto obj = isNull() ? &toObject() : asObject(); auto obj = isNull() ? toObject(resources) : asObject(resources);
if (!obj) return obj.getOrAddMember(key);
return nullptr;
return obj->getOrAddMember(key, resources);
} }
bool isArray() const { bool isArray() const {
@ -438,23 +419,18 @@ class VariantData {
type_ == VariantType::TinyString; type_ == VariantType::TinyString;
} }
size_t nesting(const ResourceManager* resources) const { size_t nesting(ResourceManager* resources) {
auto collection = asCollection(); return asCollection(resources).nesting();
if (collection)
return collection->nesting(resources);
else
return 0;
} }
static size_t nesting(const VariantData* var, static size_t nesting(VariantData* var, ResourceManager* resources) {
const ResourceManager* resources) {
if (!var) if (!var)
return 0; return 0;
return var->nesting(resources); return var->nesting(resources);
} }
void removeElement(size_t index, ResourceManager* resources) { void removeElement(size_t index, ResourceManager* resources) {
ArrayData::removeElement(asArray(), index, resources); asArray(resources).removeElement(index);
} }
static void removeElement(VariantData* var, size_t index, static void removeElement(VariantData* var, size_t index,
@ -466,7 +442,7 @@ class VariantData {
template <typename TAdaptedString> template <typename TAdaptedString>
void removeMember(TAdaptedString key, ResourceManager* resources) { void removeMember(TAdaptedString key, ResourceManager* resources) {
ObjectData::removeMember(asObject(), key, resources); asObject(resources).removeMember(key);
} }
template <typename TAdaptedString> template <typename TAdaptedString>
@ -563,48 +539,44 @@ class VariantData {
content_.asOwnedString = s; content_.asOwnedString = s;
} }
size_t size(const ResourceManager* resources) const { size_t size(ResourceManager* resources) {
if (isObject()) if (isObject())
return content_.asObject.size(resources); return asObject(resources).size();
if (isArray()) if (isArray())
return content_.asArray.size(resources); return asArray(resources).size();
return 0; return 0;
} }
static size_t size(const VariantData* var, const ResourceManager* resources) { static size_t size(VariantData* var, ResourceManager* resources) {
return var != 0 ? var->size(resources) : 0; return var != 0 ? var->size(resources) : 0;
} }
ArrayData& toArray() { ArrayImpl toArray(ResourceManager* resources) {
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
type_ = VariantType::Array; type_ = VariantType::Array;
new (&content_.asArray) ArrayData(); return ArrayImpl(new (&content_.asCollection) CollectionData(), resources);
return content_.asArray;
} }
static VariantData* toArray(VariantData* var, ResourceManager* resources) { static ArrayImpl toArray(VariantData* var, ResourceManager* resources) {
if (!var) if (!var)
return 0; return ArrayImpl(nullptr, resources);
var->clear(resources); var->clear(resources);
var->toArray(); return var->toArray(resources);
return var;
} }
ObjectData& toObject() { ObjectImpl toObject(ResourceManager* resources) {
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
type_ = VariantType::Object; type_ = VariantType::Object;
new (&content_.asObject) ObjectData(); return ObjectImpl(new (&content_.asCollection) CollectionData(), resources);
return content_.asObject;
} }
static VariantData* toObject(VariantData* var, ResourceManager* resources) { static ObjectImpl toObject(VariantData* var, ResourceManager* resources) {
if (!var) if (!var)
return 0; return ObjectImpl();
var->clear(resources); var->clear(resources);
var->toObject(); return var->toObject(resources);
return var;
} }
VariantType type() const { VariantType type() const {

View File

@ -66,9 +66,7 @@ inline void VariantData::clear(ResourceManager* resources) {
resources->freeEightByte(content_.asSlotId); resources->freeEightByte(content_.asSlotId);
#endif #endif
auto collection = asCollection(); asCollection(resources).clear();
if (collection)
collection->clear(resources);
type_ = VariantType::Null; type_ = VariantType::Null;
} }

View File

@ -151,16 +151,14 @@ 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 {
return JsonArray( return JsonArray(
VariantData::toArray(getOrCreateData(), getResourceManager()), VariantData::toArray(getOrCreateData(), getResourceManager()));
getResourceManager());
} }
template <typename TDerived> template <typename TDerived>
template <typename T, enable_if_t<is_same<T, JsonObject>::value, int>> template <typename T, enable_if_t<is_same<T, JsonObject>::value, int>>
JsonObject VariantRefBase<TDerived>::to() const { JsonObject VariantRefBase<TDerived>::to() const {
return JsonObject( return JsonObject(
VariantData::toObject(getOrCreateData(), getResourceManager()), VariantData::toObject(getOrCreateData(), getResourceManager()));
getResourceManager());
} }
template <typename TDerived> template <typename TDerived>