Răsfoiți Sursa

Merge `ArrayImpl`, `CollectionImpl`, and `ObjectImpl` into `VariantImpl`

Benoit Blanchon 6 luni în urmă
părinte
comite
f62d6f26e0

+ 0 - 41
src/ArduinoJson/Array/ArrayData.hpp

@@ -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

+ 13 - 14
src/ArduinoJson/Array/ArrayImpl.hpp

@@ -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;
 }
 

+ 6 - 2
src/ArduinoJson/Array/ElementProxy.hpp

@@ -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_;

+ 10 - 6
src/ArduinoJson/Array/JsonArray.hpp

@@ -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

+ 3 - 3
src/ArduinoJson/Array/JsonArrayConst.hpp

@@ -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.

+ 4 - 4
src/ArduinoJson/Array/JsonArrayIterator.hpp

@@ -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_;
 };
 

+ 1 - 73
src/ArduinoJson/Collection/CollectionData.hpp

@@ -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

+ 8 - 34
src/ArduinoJson/Collection/CollectionImpl.hpp

@@ -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

+ 11 - 3
src/ArduinoJson/Document/JsonDocument.hpp

@@ -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_);
   }

+ 2 - 2
src/ArduinoJson/Json/JsonDeserializer.hpp

@@ -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);

+ 2 - 2
src/ArduinoJson/Json/JsonSerializer.hpp

@@ -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();

+ 2 - 2
src/ArduinoJson/Json/PrettyJsonSerializer.hpp

@@ -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");

+ 4 - 4
src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp

@@ -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) {

+ 2 - 2
src/ArduinoJson/MsgPack/MsgPackSerializer.hpp

@@ -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));

+ 12 - 8
src/ArduinoJson/Object/JsonObject.hpp

@@ -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

+ 3 - 3
src/ArduinoJson/Object/JsonObjectConst.hpp

@@ -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) {

+ 4 - 4
src/ArduinoJson/Object/JsonObjectIterator.hpp

@@ -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_;
 };
 

+ 2 - 2
src/ArduinoJson/Object/JsonPair.hpp

@@ -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);

+ 6 - 2
src/ArduinoJson/Object/MemberProxy.hpp

@@ -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:

+ 0 - 51
src/ArduinoJson/Object/ObjectData.hpp

@@ -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

+ 13 - 14
src/ArduinoJson/Object/ObjectImpl.hpp

@@ -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();
 }

+ 3 - 0
src/ArduinoJson/Variant/JsonVariantConst.hpp

@@ -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 {

+ 2 - 2
src/ArduinoJson/Variant/JsonVariantVisitor.hpp

@@ -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));
   }
 

+ 0 - 5
src/ArduinoJson/Variant/VariantAttorney.hpp

@@ -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();

+ 8 - 2
src/ArduinoJson/Variant/VariantDataVisitor.hpp

@@ -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();

+ 98 - 48
src/ArduinoJson/Variant/VariantImpl.hpp

@@ -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* addMember(TAdaptedString key);
 
-  VariantData* getOrAddElement(size_t index) {
-    if (!data_)
-      return nullptr;
-    return ArrayImpl(data_->getOrCreateArray(), resources_)
-        .getOrAddElement(index);
-  }
+  template <typename TAdaptedString>
+  VariantData* getMember(TAdaptedString key) const;
 
   template <typename TAdaptedString>
-  VariantData* getOrAddMember(TAdaptedString key) {
-    if (key.isNull())
-      return nullptr;
-    if (!data_)
-      return nullptr;
-    return ObjectImpl(data_->getOrCreateObject(), resources_)
-        .getOrAddMember(key);
-  }
+  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(size_t index) {
-    ArrayImpl(data_, resources_).removeElement(index);
+  void removeElement(iterator it) {
+    if (!isArray())
+      return;
+    removeOne(it);
   }
 
+  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

+ 14 - 2
src/ArduinoJson/Variant/VariantRefBase.hpp

@@ -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 {

+ 1 - 1
src/ArduinoJson/Variant/VariantRefBaseImpl.hpp

@@ -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());
 }