Ver Fonte

Extract `ArrayImpl`, `CollectionImpl`, and `ObjectImpl`

Benoit Blanchon há 6 meses atrás
pai
commit
539b66fc7a

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

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

+ 25 - 23
src/ArduinoJson/Array/ArrayImpl.hpp

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

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

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

+ 23 - 28
src/ArduinoJson/Array/JsonArray.hpp

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

+ 15 - 18
src/ArduinoJson/Array/JsonArrayConst.hpp

@@ -24,10 +24,7 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
   // Returns an iterator to the first element of the array.
   // https://arduinojson.org/v7/api/jsonarrayconst/begin/
   iterator begin() const {
-    auto array = detail::VariantData::asArray(data_);
-    if (!array)
-      return iterator();
-    return iterator(array->createIterator(resources_), resources_);
+    return iterator(impl_.createIterator(), impl_.getResourceManager());
   }
 
   // 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.
-  JsonArrayConst() : data_(0), resources_(0) {}
+  JsonArrayConst() {}
 
   // INTERNAL USE ONLY
-  JsonArrayConst(const detail::VariantData* data,
-                 const detail::ResourceManager* resources)
-      : data_(data), resources_(resources) {}
+  JsonArrayConst(detail::VariantData* data, detail::ResourceManager* resources)
+      : impl_(detail::VariantData::asArray(data, resources)) {}
+
+  // INTERNAL USE ONLY
+  JsonArrayConst(const detail::ArrayImpl& impl) : impl_(impl) {}
 
   // Returns the element at the specified index.
   // https://arduinojson.org/v7/api/jsonarrayconst/subscript/
   template <typename T,
             detail::enable_if_t<detail::is_integral<T>::value, int> = 0>
   JsonVariantConst operator[](T index) const {
-    return JsonVariantConst(
-        detail::VariantData::getElement(data_, size_t(index), resources_),
-        resources_);
+    return JsonVariantConst(impl_.getElement(size_t(index)),
+                            impl_.getResourceManager());
   }
 
   // Returns the element at the specified index.
@@ -66,13 +64,13 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
   }
 
   operator JsonVariantConst() const {
-    return JsonVariantConst(getData(), resources_);
+    return JsonVariantConst(impl_.getData(), impl_.getResourceManager());
   }
 
   // Returns true if the reference is unbound.
   // https://arduinojson.org/v7/api/jsonarrayconst/isnull/
   bool isNull() const {
-    return !data_ || !data_->isArray();
+    return impl_.isNull();
   }
 
   // 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.
   // https://arduinojson.org/v7/api/jsonarrayconst/nesting/
   size_t nesting() const {
-    return detail::VariantData::nesting(getData(), resources_);
+    return impl_.nesting();
   }
 
   // Returns the number of elements in the array.
   // https://arduinojson.org/v7/api/jsonarrayconst/size/
   size_t size() const {
-    return data_ ? data_->size(resources_) : 0;
+    return impl_.size();
   }
 
   // DEPRECATED: always returns zero
@@ -101,11 +99,10 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
 
  private:
   const detail::VariantData* getData() const {
-    return data_;
+    return impl_.getData();
   }
 
-  const detail::VariantData* data_;
-  const detail::ResourceManager* resources_;
+  detail::ArrayImpl impl_;
 };
 
 // Compares the content of two arrays.

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

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

+ 43 - 33
src/ArduinoJson/Collection/CollectionData.hpp

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

+ 52 - 44
src/ArduinoJson/Collection/CollectionImpl.hpp

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

+ 2 - 2
src/ArduinoJson/Document/JsonDocument.hpp

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

+ 8 - 7
src/ArduinoJson/Json/JsonDeserializer.hpp

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

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

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

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

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

+ 6 - 13
src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp

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

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

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

+ 23 - 31
src/ArduinoJson/Object/JsonObject.hpp

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

+ 19 - 25
src/ArduinoJson/Object/JsonObjectConst.hpp

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

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

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

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

@@ -15,7 +15,7 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
 class JsonPair {
  public:
   // INTERNAL USE ONLY
-  JsonPair(detail::ObjectData::iterator iterator,
+  JsonPair(detail::ObjectImpl::iterator iterator,
            detail::ResourceManager* resources) {
     if (!iterator.done()) {
       key_ = iterator->asString();
@@ -43,8 +43,8 @@ class JsonPair {
 // https://arduinojson.org/v7/api/jsonobjectconst/begin_end/
 class JsonPairConst {
  public:
-  JsonPairConst(detail::ObjectData::iterator iterator,
-                const detail::ResourceManager* resources) {
+  JsonPairConst(detail::ObjectImpl::iterator iterator,
+                detail::ResourceManager* resources) {
     if (!iterator.done()) {
       key_ = iterator->asString();
       iterator.next(resources);

+ 14 - 39
src/ArduinoJson/Object/ObjectData.hpp

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

+ 27 - 25
src/ArduinoJson/Object/ObjectImpl.hpp

@@ -11,31 +11,28 @@
 ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
 
 template <typename TAdaptedString>
-inline VariantData* ObjectData::getMember(
-    TAdaptedString key, const ResourceManager* resources) const {
-  auto it = findKey(key, resources);
+inline VariantData* ObjectImpl::getMember(TAdaptedString key) const {
+  auto it = findKey(key);
   if (it.done())
     return nullptr;
-  it.next(resources);
+  it.next(resources_);
   return it.data();
 }
 
 template <typename TAdaptedString>
-VariantData* ObjectData::getOrAddMember(TAdaptedString key,
-                                        ResourceManager* resources) {
-  auto data = getMember(key, resources);
+VariantData* ObjectImpl::getOrAddMember(TAdaptedString key) {
+  auto data = getMember(key);
   if (data)
     return data;
-  return addMember(key, resources);
+  return addMember(key);
 }
 
 template <typename TAdaptedString>
-inline ObjectData::iterator ObjectData::findKey(
-    TAdaptedString key, const ResourceManager* resources) const {
+inline ObjectImpl::iterator ObjectImpl::findKey(TAdaptedString key) const {
   if (key.isNull())
     return iterator();
   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())))
       return it;
     isKey = !isKey;
@@ -44,42 +41,47 @@ inline ObjectData::iterator ObjectData::findKey(
 }
 
 template <typename TAdaptedString>
-inline void ObjectData::removeMember(TAdaptedString key,
-                                     ResourceManager* resources) {
-  remove(findKey(key, resources), resources);
+inline void ObjectImpl::removeMember(TAdaptedString key) {
+  remove(findKey(key));
 }
 
 template <typename TAdaptedString>
-inline VariantData* ObjectData::addMember(TAdaptedString key,
-                                          ResourceManager* resources) {
-  auto keySlot = resources->allocVariant();
+inline VariantData* ObjectImpl::addMember(TAdaptedString key) {
+  if (!data_)
+    return nullptr;
+  ARDUINOJSON_ASSERT(resources_ != nullptr);
+
+  auto keySlot = resources_->allocVariant();
   if (!keySlot)
     return nullptr;
 
-  auto valueSlot = resources->allocVariant();
+  auto valueSlot = resources_->allocVariant();
   if (!valueSlot)
     return nullptr;
 
-  if (!keySlot->setString(key, resources))
+  if (!keySlot->setString(key, resources_))
     return nullptr;
 
-  CollectionData::appendPair(keySlot, valueSlot, resources);
+  CollectionImpl::appendPair(keySlot, valueSlot);
 
   return valueSlot.ptr();
 }
 
-inline VariantData* ObjectData::addPair(VariantData** value,
-                                        ResourceManager* resources) {
-  auto keySlot = resources->allocVariant();
+inline VariantData* ObjectImpl::addPair(VariantData** value) {
+  if (!data_)
+    return nullptr;
+  ARDUINOJSON_ASSERT(resources_ != nullptr);
+
+  auto keySlot = resources_->allocVariant();
   if (!keySlot)
     return nullptr;
 
-  auto valueSlot = resources->allocVariant();
+  auto valueSlot = resources_->allocVariant();
   if (!valueSlot)
     return nullptr;
   *value = valueSlot.ptr();
 
-  CollectionData::appendPair(keySlot, valueSlot, resources);
+  CollectionImpl::appendPair(keySlot, valueSlot);
 
   return keySlot.ptr();
 }

+ 6 - 6
src/ArduinoJson/Variant/JsonVariantConst.hpp

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

+ 6 - 10
src/ArduinoJson/Variant/JsonVariantVisitor.hpp

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

+ 0 - 2
src/ArduinoJson/Variant/VariantContent.hpp

@@ -58,8 +58,6 @@ union VariantContent {
 #if ARDUINOJSON_USE_8_BYTE_POOL
   SlotId asSlotId;
 #endif
-  ArrayData asArray;
-  ObjectData asObject;
   CollectionData asCollection;
   struct StringNode* asStringNode;
   char asTinyString[tinyStringMaxLength + 1];

+ 59 - 87
src/ArduinoJson/Variant/VariantData.hpp

@@ -51,8 +51,8 @@ class VariantData {
   }
 
   template <typename TVisitor>
-  typename TVisitor::result_type accept(
-      TVisitor& visit, const ResourceManager* resources) const {
+  typename TVisitor::result_type accept(TVisitor& visit,
+                                        ResourceManager* resources) {
 #if ARDUINOJSON_USE_8_BYTE_POOL
     auto eightByteValue = getEightByte(resources);
 #else
@@ -68,10 +68,10 @@ class VariantData {
 #endif
 
       case VariantType::Array:
-        return visit.visit(content_.asArray);
+        return visit.visit(asArray(resources));
 
       case VariantType::Object:
-        return visit.visit(content_.asObject);
+        return visit.visit(asObject(resources));
 
       case VariantType::TinyString:
         return visit.visit(JsonString(content_.asTinyString));
@@ -107,8 +107,8 @@ class VariantData {
   }
 
   template <typename TVisitor>
-  static typename TVisitor::result_type accept(const VariantData* var,
-                                               const ResourceManager* resources,
+  static typename TVisitor::result_type accept(VariantData* var,
+                                               ResourceManager* resources,
                                                TVisitor& visit) {
     if (var != 0)
       return var->accept(visit, resources);
@@ -117,8 +117,8 @@ class VariantData {
   }
 
   VariantData* addElement(ResourceManager* resources) {
-    auto array = isNull() ? &toArray() : asArray();
-    return detail::ArrayData::addElement(array, resources);
+    auto array = isNull() ? toArray(resources) : asArray(resources);
+    return array.addElement();
   }
 
   static VariantData* addElement(VariantData* var, ResourceManager* resources) {
@@ -129,8 +129,8 @@ class VariantData {
 
   template <typename T>
   bool addValue(const T& value, ResourceManager* resources) {
-    auto array = isNull() ? &toArray() : asArray();
-    return detail::ArrayData::addValue(array, value, resources);
+    auto array = isNull() ? toArray(resources) : asArray(resources);
+    return array.addValue(value);
   }
 
   template <typename T>
@@ -171,28 +171,19 @@ class VariantData {
     }
   }
 
-  ArrayData* asArray() {
-    return isArray() ? &content_.asArray : 0;
+  ArrayImpl asArray(ResourceManager* resources) {
+    return ArrayImpl(isArray() ? &content_.asCollection : nullptr, resources);
   }
 
-  const ArrayData* asArray() const {
-    return const_cast<VariantData*>(this)->asArray();
+  static ArrayImpl asArray(VariantData* var, ResourceManager* resources) {
+    return ArrayImpl(
+        var && var->isArray() ? &var->content_.asCollection : nullptr,
+        resources);
   }
 
-  static ArrayData* asArray(VariantData* var) {
-    return var ? var->asArray() : 0;
-  }
-
-  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();
+  CollectionImpl asCollection(ResourceManager* resources) {
+    return CollectionImpl(isCollection() ? &content_.asCollection : nullptr,
+                          resources);
   }
 
   template <typename T>
@@ -279,20 +270,14 @@ class VariantData {
     return parseNumber<T>(str);
   }
 
-  ObjectData* asObject() {
-    return isObject() ? &content_.asObject : 0;
-  }
-
-  const ObjectData* asObject() const {
-    return const_cast<VariantData*>(this)->asObject();
-  }
-
-  static ObjectData* asObject(VariantData* var) {
-    return var ? var->asObject() : 0;
+  ObjectImpl asObject(ResourceManager* resources) {
+    return ObjectImpl(isObject() ? &content_.asCollection : nullptr, resources);
   }
 
-  static const ObjectData* asObject(const VariantData* var) {
-    return var ? var->asObject() : 0;
+  static ObjectImpl asObject(VariantData* var, ResourceManager* resources) {
+    return ObjectImpl(
+        var && var->isObject() ? &var->content_.asCollection : nullptr,
+        resources);
   }
 
   JsonString asRawString() const {
@@ -321,45 +306,41 @@ class VariantData {
   const EightByteValue* getEightByte(const ResourceManager* resources) const;
 #endif
 
-  VariantData* getElement(size_t index,
-                          const ResourceManager* resources) const {
-    return ArrayData::getElement(asArray(), index, resources);
+  VariantData* getElement(size_t index, ResourceManager* resources) {
+    return asArray(resources).getElement(index);
   }
 
-  static VariantData* getElement(const VariantData* var, size_t index,
-                                 const ResourceManager* resources) {
-    return var != 0 ? var->getElement(index, resources) : 0;
+  static VariantData* getElement(VariantData* var, size_t index,
+                                 ResourceManager* resources) {
+    if (!var)
+      return nullptr;
+    return var->asArray(resources).getElement(index);
   }
 
   template <typename TAdaptedString>
-  VariantData* getMember(TAdaptedString key,
-                         const ResourceManager* resources) const {
-    return ObjectData::getMember(asObject(), key, resources);
+  VariantData* getMember(TAdaptedString key, ResourceManager* resources) {
+    return asObject(resources).getMember(key);
   }
 
   template <typename TAdaptedString>
-  static VariantData* getMember(const VariantData* var, TAdaptedString key,
-                                const ResourceManager* resources) {
+  static VariantData* getMember(VariantData* var, TAdaptedString key,
+                                ResourceManager* resources) {
     if (!var)
       return 0;
     return var->getMember(key, resources);
   }
 
   VariantData* getOrAddElement(size_t index, ResourceManager* resources) {
-    auto array = isNull() ? &toArray() : asArray();
-    if (!array)
-      return nullptr;
-    return array->getOrAddElement(index, resources);
+    auto array = isNull() ? toArray(resources) : asArray(resources);
+    return array.getOrAddElement(index);
   }
 
   template <typename TAdaptedString>
   VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources) {
     if (key.isNull())
       return nullptr;
-    auto obj = isNull() ? &toObject() : asObject();
-    if (!obj)
-      return nullptr;
-    return obj->getOrAddMember(key, resources);
+    auto obj = isNull() ? toObject(resources) : asObject(resources);
+    return obj.getOrAddMember(key);
   }
 
   bool isArray() const {
@@ -423,23 +404,18 @@ class VariantData {
     return type_ == VariantType::LongString || type_ == VariantType::TinyString;
   }
 
-  size_t nesting(const ResourceManager* resources) const {
-    auto collection = asCollection();
-    if (collection)
-      return collection->nesting(resources);
-    else
-      return 0;
+  size_t nesting(ResourceManager* resources) {
+    return asCollection(resources).nesting();
   }
 
-  static size_t nesting(const VariantData* var,
-                        const ResourceManager* resources) {
+  static size_t nesting(VariantData* var, ResourceManager* resources) {
     if (!var)
       return 0;
     return var->nesting(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,
@@ -451,7 +427,7 @@ class VariantData {
 
   template <typename TAdaptedString>
   void removeMember(TAdaptedString key, ResourceManager* resources) {
-    ObjectData::removeMember(asObject(), key, resources);
+    asObject(resources).removeMember(key);
   }
 
   template <typename TAdaptedString>
@@ -546,48 +522,44 @@ class VariantData {
     content_.asStringNode = s;
   }
 
-  size_t size(const ResourceManager* resources) const {
+  size_t size(ResourceManager* resources) {
     if (isObject())
-      return content_.asObject.size(resources);
+      return asObject(resources).size();
 
     if (isArray())
-      return content_.asArray.size(resources);
+      return asArray(resources).size();
 
     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;
   }
 
-  ArrayData& toArray() {
+  ArrayImpl toArray(ResourceManager* resources) {
     ARDUINOJSON_ASSERT(type_ == VariantType::Null);  // must call clear() first
     type_ = VariantType::Array;
-    new (&content_.asArray) ArrayData();
-    return content_.asArray;
+    return ArrayImpl(new (&content_.asCollection) CollectionData(), resources);
   }
 
-  static VariantData* toArray(VariantData* var, ResourceManager* resources) {
+  static ArrayImpl toArray(VariantData* var, ResourceManager* resources) {
     if (!var)
-      return 0;
+      return ArrayImpl(nullptr, resources);
     var->clear(resources);
-    var->toArray();
-    return var;
+    return var->toArray(resources);
   }
 
-  ObjectData& toObject() {
+  ObjectImpl toObject(ResourceManager* resources) {
     ARDUINOJSON_ASSERT(type_ == VariantType::Null);  // must call clear() first
     type_ = VariantType::Object;
-    new (&content_.asObject) ObjectData();
-    return content_.asObject;
+    return ObjectImpl(new (&content_.asCollection) CollectionData(), resources);
   }
 
-  static VariantData* toObject(VariantData* var, ResourceManager* resources) {
+  static ObjectImpl toObject(VariantData* var, ResourceManager* resources) {
     if (!var)
-      return 0;
+      return ObjectImpl();
     var->clear(resources);
-    var->toObject();
-    return var;
+    return var->toObject(resources);
   }
 
   VariantType type() const {

+ 1 - 3
src/ArduinoJson/Variant/VariantImpl.hpp

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

+ 2 - 4
src/ArduinoJson/Variant/VariantRefBaseImpl.hpp

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