mirror of
				https://github.com/bblanchon/ArduinoJson.git
				synced 2025-11-04 00:21:36 +01:00 
			
		
		
		
	Store index of slot in the pool instead of a pointer or a distance
This commit is contained in:
		@@ -22,12 +22,13 @@ class ArrayData : public CollectionData {
 | 
			
		||||
 | 
			
		||||
  VariantData* getOrAddElement(size_t index, ResourceManager* resources);
 | 
			
		||||
 | 
			
		||||
  VariantData* getElement(size_t index) const;
 | 
			
		||||
  VariantData* getElement(size_t index, const ResourceManager* resources) const;
 | 
			
		||||
 | 
			
		||||
  static VariantData* getElement(const ArrayData* array, size_t index) {
 | 
			
		||||
  static VariantData* getElement(const ArrayData* array, size_t index,
 | 
			
		||||
                                 const ResourceManager* resources) {
 | 
			
		||||
    if (!array)
 | 
			
		||||
      return nullptr;
 | 
			
		||||
    return array->getElement(index);
 | 
			
		||||
    return array->getElement(index, resources);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void removeElement(size_t index, ResourceManager* resources);
 | 
			
		||||
@@ -50,7 +51,7 @@ class ArrayData : public CollectionData {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  iterator at(size_t index) const;
 | 
			
		||||
  iterator at(size_t index, const ResourceManager* resources) const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
 | 
			
		||||
 
 | 
			
		||||
@@ -9,10 +9,11 @@
 | 
			
		||||
 | 
			
		||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
 | 
			
		||||
 | 
			
		||||
inline ArrayData::iterator ArrayData::at(size_t index) const {
 | 
			
		||||
  auto it = createIterator();
 | 
			
		||||
inline ArrayData::iterator ArrayData::at(
 | 
			
		||||
    size_t index, const ResourceManager* resources) const {
 | 
			
		||||
  auto it = createIterator(resources);
 | 
			
		||||
  while (!it.done() && index) {
 | 
			
		||||
    it.next();
 | 
			
		||||
    it.next(resources);
 | 
			
		||||
    --index;
 | 
			
		||||
  }
 | 
			
		||||
  return it;
 | 
			
		||||
@@ -20,9 +21,9 @@ inline ArrayData::iterator ArrayData::at(size_t index) const {
 | 
			
		||||
 | 
			
		||||
inline VariantData* ArrayData::getOrAddElement(size_t index,
 | 
			
		||||
                                               ResourceManager* resources) {
 | 
			
		||||
  auto it = createIterator();
 | 
			
		||||
  auto it = createIterator(resources);
 | 
			
		||||
  while (!it.done() && index > 0) {
 | 
			
		||||
    it.next();
 | 
			
		||||
    it.next(resources);
 | 
			
		||||
    index--;
 | 
			
		||||
  }
 | 
			
		||||
  if (it.done())
 | 
			
		||||
@@ -37,12 +38,13 @@ inline VariantData* ArrayData::getOrAddElement(size_t index,
 | 
			
		||||
  return element;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline VariantData* ArrayData::getElement(size_t index) const {
 | 
			
		||||
  return at(index).data();
 | 
			
		||||
inline VariantData* ArrayData::getElement(
 | 
			
		||||
    size_t index, const ResourceManager* resources) const {
 | 
			
		||||
  return at(index, resources).data();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void ArrayData::removeElement(size_t index, ResourceManager* resources) {
 | 
			
		||||
  remove(at(index), resources);
 | 
			
		||||
  remove(at(index, resources), resources);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,9 @@ class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>,
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  FORCE_INLINE VariantData* getData() const {
 | 
			
		||||
    return VariantData::getElement(VariantAttorney::getData(upstream_), index_);
 | 
			
		||||
    return VariantData::getElement(
 | 
			
		||||
        VariantAttorney::getData(upstream_), index_,
 | 
			
		||||
        VariantAttorney::getResourceManager(upstream_));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  FORCE_INLINE VariantData* getOrCreateData() const {
 | 
			
		||||
 
 | 
			
		||||
@@ -68,7 +68,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
 | 
			
		||||
  FORCE_INLINE iterator begin() const {
 | 
			
		||||
    if (!data_)
 | 
			
		||||
      return iterator();
 | 
			
		||||
    return iterator(data_->createIterator(), resources_);
 | 
			
		||||
    return iterator(data_->createIterator(resources_), resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns an iterator following the last element of the array.
 | 
			
		||||
@@ -148,19 +148,19 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
 | 
			
		||||
  // Returns the number of bytes occupied by the array.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonarray/memoryusage/
 | 
			
		||||
  FORCE_INLINE size_t memoryUsage() const {
 | 
			
		||||
    return data_ ? data_->memoryUsage() : 0;
 | 
			
		||||
    return data_ ? data_->memoryUsage(resources_) : 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns the depth (nesting level) of the array.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonarray/nesting/
 | 
			
		||||
  FORCE_INLINE size_t nesting() const {
 | 
			
		||||
    return detail::VariantData::nesting(collectionToVariant(data_));
 | 
			
		||||
    return detail::VariantData::nesting(collectionToVariant(data_), resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns the number of elements in the array.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonarray/size/
 | 
			
		||||
  FORCE_INLINE size_t size() const {
 | 
			
		||||
    return data_ ? data_->size() : 0;
 | 
			
		||||
    return data_ ? data_->size(resources_) : 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
 | 
			
		||||
  FORCE_INLINE iterator begin() const {
 | 
			
		||||
    if (!data_)
 | 
			
		||||
      return iterator();
 | 
			
		||||
    return iterator(data_->createIterator(), resources_);
 | 
			
		||||
    return iterator(data_->createIterator(resources_), resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns an iterator to the element following the last element of the array.
 | 
			
		||||
@@ -46,8 +46,8 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
 | 
			
		||||
  // Returns the element at the specified index.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonarrayconst/subscript/
 | 
			
		||||
  FORCE_INLINE JsonVariantConst operator[](size_t index) const {
 | 
			
		||||
    return JsonVariantConst(detail::ArrayData::getElement(data_, index),
 | 
			
		||||
                            resources_);
 | 
			
		||||
    return JsonVariantConst(
 | 
			
		||||
        detail::ArrayData::getElement(data_, index, resources_), resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  operator JsonVariantConst() const {
 | 
			
		||||
@@ -69,19 +69,19 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
 | 
			
		||||
  // Returns the number of bytes occupied by the array.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonarrayconst/memoryusage/
 | 
			
		||||
  FORCE_INLINE size_t memoryUsage() const {
 | 
			
		||||
    return data_ ? data_->memoryUsage() : 0;
 | 
			
		||||
    return data_ ? data_->memoryUsage(resources_) : 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns the depth (nesting level) of the array.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonarrayconst/nesting/
 | 
			
		||||
  FORCE_INLINE size_t nesting() const {
 | 
			
		||||
    return detail::VariantData::nesting(collectionToVariant(data_));
 | 
			
		||||
    return detail::VariantData::nesting(collectionToVariant(data_), resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns the number of elements in the array.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonarrayconst/size/
 | 
			
		||||
  FORCE_INLINE size_t size() const {
 | 
			
		||||
    return data_ ? data_->size() : 0;
 | 
			
		||||
    return data_ ? data_->size(resources_) : 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
 
 | 
			
		||||
@@ -50,7 +50,7 @@ class JsonArrayIterator {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  JsonArrayIterator& operator++() {
 | 
			
		||||
    iterator_.next();
 | 
			
		||||
    iterator_.next(resources_);
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -84,7 +84,7 @@ class JsonArrayConstIterator {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  JsonArrayConstIterator& operator++() {
 | 
			
		||||
    iterator_.next();
 | 
			
		||||
    iterator_.next(resources_);
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ class CollectionIterator {
 | 
			
		||||
 public:
 | 
			
		||||
  CollectionIterator() : slot_(nullptr) {}
 | 
			
		||||
 | 
			
		||||
  void next();
 | 
			
		||||
  void next(const ResourceManager* resources);
 | 
			
		||||
 | 
			
		||||
  bool done() const {
 | 
			
		||||
    return slot_ == nullptr;
 | 
			
		||||
@@ -70,8 +70,8 @@ class CollectionIterator {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class CollectionData {
 | 
			
		||||
  VariantSlot* head_ = 0;
 | 
			
		||||
  VariantSlot* tail_ = 0;
 | 
			
		||||
  SlotId head_ = NULL_SLOT;
 | 
			
		||||
  SlotId tail_ = NULL_SLOT;
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  // Placement new
 | 
			
		||||
@@ -83,13 +83,13 @@ class CollectionData {
 | 
			
		||||
 | 
			
		||||
  using iterator = CollectionIterator;
 | 
			
		||||
 | 
			
		||||
  iterator createIterator() const {
 | 
			
		||||
    return iterator(head_);
 | 
			
		||||
  iterator createIterator(const ResourceManager* resources) const {
 | 
			
		||||
    return iterator(resources->getSlot(head_));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t memoryUsage() const;
 | 
			
		||||
  size_t size() const;
 | 
			
		||||
  size_t nesting() const;
 | 
			
		||||
  size_t memoryUsage(const ResourceManager*) const;
 | 
			
		||||
  size_t size(const ResourceManager*) const;
 | 
			
		||||
  size_t nesting(const ResourceManager*) const;
 | 
			
		||||
 | 
			
		||||
  void clear(ResourceManager* resources);
 | 
			
		||||
 | 
			
		||||
@@ -99,8 +99,6 @@ class CollectionData {
 | 
			
		||||
    collection->clear(resources);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void movePointers(ptrdiff_t variantDistance);
 | 
			
		||||
 | 
			
		||||
  void remove(iterator it, ResourceManager* resources);
 | 
			
		||||
 | 
			
		||||
  static void remove(CollectionData* collection, iterator it,
 | 
			
		||||
@@ -113,7 +111,7 @@ class CollectionData {
 | 
			
		||||
  iterator addSlot(ResourceManager*);
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  VariantSlot* getPreviousSlot(VariantSlot*) const;
 | 
			
		||||
  SlotWithId getPreviousSlot(VariantSlot*, const ResourceManager*) const;
 | 
			
		||||
  static void releaseSlot(VariantSlot*, ResourceManager*);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -34,102 +34,95 @@ inline bool CollectionIterator::ownsKey() const {
 | 
			
		||||
  return slot_->ownsKey();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void CollectionIterator::next() {
 | 
			
		||||
inline void CollectionIterator::next(const ResourceManager* resources) {
 | 
			
		||||
  ARDUINOJSON_ASSERT(slot_ != nullptr);
 | 
			
		||||
  slot_ = slot_->next();
 | 
			
		||||
  auto nextId = slot_->next();
 | 
			
		||||
  if (nextId != NULL_SLOT)
 | 
			
		||||
    slot_ = resources->getSlot(nextId);
 | 
			
		||||
  else
 | 
			
		||||
    slot_ = nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline CollectionData::iterator CollectionData::addSlot(
 | 
			
		||||
    ResourceManager* resources) {
 | 
			
		||||
  auto slot = resources->allocVariant();
 | 
			
		||||
  auto slot = resources->allocSlot();
 | 
			
		||||
  if (!slot)
 | 
			
		||||
    return nullptr;
 | 
			
		||||
  if (tail_) {
 | 
			
		||||
    tail_->setNextNotNull(slot);
 | 
			
		||||
    tail_ = slot;
 | 
			
		||||
  if (tail_ != NULL_SLOT) {
 | 
			
		||||
    auto tail = resources->getSlot(tail_);
 | 
			
		||||
    tail->setNext(slot.id());
 | 
			
		||||
    tail_ = slot.id();
 | 
			
		||||
  } else {
 | 
			
		||||
    head_ = slot;
 | 
			
		||||
    tail_ = slot;
 | 
			
		||||
    head_ = slot.id();
 | 
			
		||||
    tail_ = slot.id();
 | 
			
		||||
  }
 | 
			
		||||
  return slot;
 | 
			
		||||
  return iterator(slot);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void CollectionData::clear(ResourceManager* resources) {
 | 
			
		||||
  for (auto slot = head_; slot; slot = slot->next())
 | 
			
		||||
    releaseSlot(slot, resources);
 | 
			
		||||
  head_ = 0;
 | 
			
		||||
  tail_ = 0;
 | 
			
		||||
  for (auto it = createIterator(resources); !it.done(); it.next(resources))
 | 
			
		||||
    releaseSlot(it.slot_, resources);
 | 
			
		||||
  head_ = NULL_SLOT;
 | 
			
		||||
  tail_ = NULL_SLOT;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline VariantSlot* CollectionData::getPreviousSlot(VariantSlot* target) const {
 | 
			
		||||
  VariantSlot* current = head_;
 | 
			
		||||
  while (current) {
 | 
			
		||||
    VariantSlot* next = current->next();
 | 
			
		||||
    if (next == target)
 | 
			
		||||
      return current;
 | 
			
		||||
    current = next;
 | 
			
		||||
inline SlotWithId CollectionData::getPreviousSlot(
 | 
			
		||||
    VariantSlot* target, const ResourceManager* resources) const {
 | 
			
		||||
  auto prev = SlotWithId();
 | 
			
		||||
  auto currentId = head_;
 | 
			
		||||
  while (currentId != NULL_SLOT) {
 | 
			
		||||
    auto currentSlot = resources->getSlot(currentId);
 | 
			
		||||
    if (currentSlot == target)
 | 
			
		||||
      return prev;
 | 
			
		||||
    prev = SlotWithId(currentSlot, currentId);
 | 
			
		||||
    currentId = currentSlot->next();
 | 
			
		||||
  }
 | 
			
		||||
  return 0;
 | 
			
		||||
  return SlotWithId();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void CollectionData::remove(iterator it, ResourceManager* resources) {
 | 
			
		||||
  if (it.done())
 | 
			
		||||
    return;
 | 
			
		||||
  auto curr = it.slot_;
 | 
			
		||||
  auto prev = getPreviousSlot(curr);
 | 
			
		||||
  auto prev = getPreviousSlot(curr, resources);
 | 
			
		||||
  auto next = curr->next();
 | 
			
		||||
  if (prev)
 | 
			
		||||
    prev->setNext(next);
 | 
			
		||||
  else
 | 
			
		||||
    head_ = next;
 | 
			
		||||
  if (!next)
 | 
			
		||||
    tail_ = prev;
 | 
			
		||||
  if (next == NULL_SLOT)
 | 
			
		||||
    tail_ = prev.id();
 | 
			
		||||
  releaseSlot(curr, resources);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline size_t CollectionData::memoryUsage() const {
 | 
			
		||||
inline size_t CollectionData::memoryUsage(
 | 
			
		||||
    const ResourceManager* resources) const {
 | 
			
		||||
  size_t total = 0;
 | 
			
		||||
  for (auto it = createIterator(); !it.done(); it.next()) {
 | 
			
		||||
    total += sizeof(VariantSlot) + it->memoryUsage();
 | 
			
		||||
  for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
 | 
			
		||||
    total += sizeof(VariantSlot) + it->memoryUsage(resources);
 | 
			
		||||
    if (it.ownsKey())
 | 
			
		||||
      total += sizeofString(strlen(it.key()));
 | 
			
		||||
  }
 | 
			
		||||
  return total;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline size_t CollectionData::nesting() const {
 | 
			
		||||
inline size_t CollectionData::nesting(const ResourceManager* resources) const {
 | 
			
		||||
  size_t maxChildNesting = 0;
 | 
			
		||||
  for (auto it = createIterator(); !it.done(); it.next()) {
 | 
			
		||||
    size_t childNesting = it->nesting();
 | 
			
		||||
  for (auto it = createIterator(resources); !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 {
 | 
			
		||||
inline size_t CollectionData::size(const ResourceManager* resources) const {
 | 
			
		||||
  size_t count = 0;
 | 
			
		||||
  for (auto it = createIterator(); !it.done(); it.next())
 | 
			
		||||
  for (auto it = createIterator(resources); !it.done(); it.next(resources))
 | 
			
		||||
    count++;
 | 
			
		||||
  return count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
inline void movePointer(T*& p, ptrdiff_t offset) {
 | 
			
		||||
  if (!p)
 | 
			
		||||
    return;
 | 
			
		||||
  p = reinterpret_cast<T*>(
 | 
			
		||||
      reinterpret_cast<void*>(reinterpret_cast<char*>(p) + offset));
 | 
			
		||||
  ARDUINOJSON_ASSERT(isAligned(p));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void CollectionData::movePointers(ptrdiff_t variantDistance) {
 | 
			
		||||
  movePointer(head_, variantDistance);
 | 
			
		||||
  movePointer(tail_, variantDistance);
 | 
			
		||||
  for (VariantSlot* slot = head_; slot; slot = slot->next())
 | 
			
		||||
    slot->data()->movePointers(variantDistance);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void CollectionData::releaseSlot(VariantSlot* slot,
 | 
			
		||||
                                        ResourceManager* resources) {
 | 
			
		||||
  ARDUINOJSON_ASSERT(slot != nullptr);
 | 
			
		||||
 
 | 
			
		||||
@@ -75,19 +75,18 @@
 | 
			
		||||
#  define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Number of bits to store the pointer to next node
 | 
			
		||||
// (saves RAM but limits the number of values in a document)
 | 
			
		||||
#ifndef ARDUINOJSON_SLOT_OFFSET_SIZE
 | 
			
		||||
// Number of bits to store the variant identifier
 | 
			
		||||
#ifndef ARDUINOJSON_SLOT_ID_SIZE
 | 
			
		||||
#  if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ <= 2
 | 
			
		||||
// Address space == 16-bit => max 127 values
 | 
			
		||||
#    define ARDUINOJSON_SLOT_OFFSET_SIZE 1
 | 
			
		||||
#    define ARDUINOJSON_SLOT_ID_SIZE 1
 | 
			
		||||
#  elif defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ >= 8 || \
 | 
			
		||||
      defined(_WIN64) && _WIN64
 | 
			
		||||
// Address space == 64-bit => max 2147483647 values
 | 
			
		||||
#    define ARDUINOJSON_SLOT_OFFSET_SIZE 4
 | 
			
		||||
#    define ARDUINOJSON_SLOT_ID_SIZE 4
 | 
			
		||||
#  else
 | 
			
		||||
// Address space == 32-bit => max 32767 values
 | 
			
		||||
#    define ARDUINOJSON_SLOT_OFFSET_SIZE 2
 | 
			
		||||
#    define ARDUINOJSON_SLOT_ID_SIZE 2
 | 
			
		||||
#  endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -86,8 +86,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
 | 
			
		||||
  // Reduces the capacity of the memory pool to match the current usage.
 | 
			
		||||
  // https://arduinojson.org/v6/api/JsonDocument/shrinktofit/
 | 
			
		||||
  void shrinkToFit() {
 | 
			
		||||
    auto offset = resources_.shrinkToFit();
 | 
			
		||||
    data_.movePointers(offset);
 | 
			
		||||
    resources_.shrinkToFit();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Reclaims the memory leaked when removing and replacing values.
 | 
			
		||||
@@ -105,14 +104,14 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsondocument/as/
 | 
			
		||||
  template <typename T>
 | 
			
		||||
  T as() {
 | 
			
		||||
    return getVariant().template as<T>();
 | 
			
		||||
    return getSlot().template as<T>();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Casts the root to the specified type.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsondocument/as/
 | 
			
		||||
  template <typename T>
 | 
			
		||||
  T as() const {
 | 
			
		||||
    return getVariant().template as<T>();
 | 
			
		||||
    return getSlot().template as<T>();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Empties the document and resets the memory pool
 | 
			
		||||
@@ -126,20 +125,20 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsondocument/is/
 | 
			
		||||
  template <typename T>
 | 
			
		||||
  bool is() {
 | 
			
		||||
    return getVariant().template is<T>();
 | 
			
		||||
    return getSlot().template is<T>();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns true if the root is of the specified type.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsondocument/is/
 | 
			
		||||
  template <typename T>
 | 
			
		||||
  bool is() const {
 | 
			
		||||
    return getVariant().template is<T>();
 | 
			
		||||
    return getSlot().template is<T>();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns true if the root is null.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsondocument/isnull/
 | 
			
		||||
  bool isNull() const {
 | 
			
		||||
    return getVariant().isNull();
 | 
			
		||||
    return getSlot().isNull();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns the number of used bytes in the memory pool.
 | 
			
		||||
@@ -157,13 +156,13 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
 | 
			
		||||
  // Returns the depth (nesting level) of the array.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsondocument/nesting/
 | 
			
		||||
  size_t nesting() const {
 | 
			
		||||
    return data_.nesting();
 | 
			
		||||
    return data_.nesting(&resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns the number of elements in the root array or object.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsondocument/size/
 | 
			
		||||
  size_t size() const {
 | 
			
		||||
    return data_.size();
 | 
			
		||||
    return data_.size(&resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Copies the specified document.
 | 
			
		||||
@@ -186,7 +185,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
 | 
			
		||||
  template <typename T>
 | 
			
		||||
  typename detail::VariantTo<T>::type to() {
 | 
			
		||||
    clear();
 | 
			
		||||
    return getVariant().template to<T>();
 | 
			
		||||
    return getSlot().template to<T>();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Creates an array and appends it to the root array.
 | 
			
		||||
@@ -233,14 +232,14 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsondocument/containskey/
 | 
			
		||||
  template <typename TChar>
 | 
			
		||||
  bool containsKey(TChar* key) const {
 | 
			
		||||
    return data_.getMember(detail::adaptString(key)) != 0;
 | 
			
		||||
    return data_.getMember(detail::adaptString(key), &resources_) != 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns true if the root object contains the specified key.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsondocument/containskey/
 | 
			
		||||
  template <typename TString>
 | 
			
		||||
  bool containsKey(const TString& key) const {
 | 
			
		||||
    return data_.getMember(detail::adaptString(key)) != 0;
 | 
			
		||||
    return data_.getMember(detail::adaptString(key), &resources_) != 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Gets or sets a root object's member.
 | 
			
		||||
@@ -269,8 +268,8 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
 | 
			
		||||
  FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value,
 | 
			
		||||
                                          JsonVariantConst>::type
 | 
			
		||||
  operator[](const TString& key) const {
 | 
			
		||||
    return JsonVariantConst(data_.getMember(detail::adaptString(key)),
 | 
			
		||||
                            &resources_);
 | 
			
		||||
    return JsonVariantConst(
 | 
			
		||||
        data_.getMember(detail::adaptString(key), &resources_), &resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Gets a root object's member.
 | 
			
		||||
@@ -279,8 +278,8 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
 | 
			
		||||
  FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value,
 | 
			
		||||
                                          JsonVariantConst>::type
 | 
			
		||||
  operator[](TChar* key) const {
 | 
			
		||||
    return JsonVariantConst(data_.getMember(detail::adaptString(key)),
 | 
			
		||||
                            &resources_);
 | 
			
		||||
    return JsonVariantConst(
 | 
			
		||||
        data_.getMember(detail::adaptString(key), &resources_), &resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Gets or sets a root array's element.
 | 
			
		||||
@@ -292,7 +291,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
 | 
			
		||||
  // Gets a root array's member.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsondocument/subscript/
 | 
			
		||||
  FORCE_INLINE JsonVariantConst operator[](size_t index) const {
 | 
			
		||||
    return JsonVariantConst(data_.getElement(index), &resources_);
 | 
			
		||||
    return JsonVariantConst(data_.getElement(index, &resources_), &resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Appends a new (null) element to the root array.
 | 
			
		||||
@@ -345,19 +344,19 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  FORCE_INLINE operator JsonVariant() {
 | 
			
		||||
    return getVariant();
 | 
			
		||||
    return getSlot();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  FORCE_INLINE operator JsonVariantConst() const {
 | 
			
		||||
    return getVariant();
 | 
			
		||||
    return getSlot();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  JsonVariant getVariant() {
 | 
			
		||||
  JsonVariant getSlot() {
 | 
			
		||||
    return JsonVariant(&data_, &resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  JsonVariantConst getVariant() const {
 | 
			
		||||
  JsonVariantConst getSlot() const {
 | 
			
		||||
    return JsonVariantConst(&data_, &resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -273,7 +273,7 @@ class JsonDeserializer {
 | 
			
		||||
      TFilter memberFilter = filter[key.c_str()];
 | 
			
		||||
 | 
			
		||||
      if (memberFilter.allow()) {
 | 
			
		||||
        auto member = object.getMember(adaptString(key.c_str()));
 | 
			
		||||
        auto member = object.getMember(adaptString(key.c_str()), resources_);
 | 
			
		||||
        if (!member) {
 | 
			
		||||
          // Save key in memory pool.
 | 
			
		||||
          auto savedKey = stringBuilder_.save();
 | 
			
		||||
 
 | 
			
		||||
@@ -16,17 +16,18 @@ class JsonSerializer : public VariantDataVisitor<size_t> {
 | 
			
		||||
 public:
 | 
			
		||||
  static const bool producesText = true;
 | 
			
		||||
 | 
			
		||||
  JsonSerializer(TWriter writer) : formatter_(writer) {}
 | 
			
		||||
  JsonSerializer(TWriter writer, const ResourceManager* resources)
 | 
			
		||||
      : formatter_(writer), resources_(resources) {}
 | 
			
		||||
 | 
			
		||||
  FORCE_INLINE size_t visit(const ArrayData& array) {
 | 
			
		||||
    write('[');
 | 
			
		||||
 | 
			
		||||
    auto it = array.createIterator();
 | 
			
		||||
    auto it = array.createIterator(resources_);
 | 
			
		||||
 | 
			
		||||
    while (!it.done()) {
 | 
			
		||||
      it->accept(*this);
 | 
			
		||||
 | 
			
		||||
      it.next();
 | 
			
		||||
      it.next(resources_);
 | 
			
		||||
      if (it.done())
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
@@ -40,14 +41,14 @@ class JsonSerializer : public VariantDataVisitor<size_t> {
 | 
			
		||||
  size_t visit(const ObjectData& object) {
 | 
			
		||||
    write('{');
 | 
			
		||||
 | 
			
		||||
    auto it = object.createIterator();
 | 
			
		||||
    auto it = object.createIterator(resources_);
 | 
			
		||||
 | 
			
		||||
    while (!it.done()) {
 | 
			
		||||
      formatter_.writeString(it.key());
 | 
			
		||||
      write(':');
 | 
			
		||||
      it->accept(*this);
 | 
			
		||||
 | 
			
		||||
      it.next();
 | 
			
		||||
      it.next(resources_);
 | 
			
		||||
      if (it.done())
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
@@ -113,6 +114,9 @@ class JsonSerializer : public VariantDataVisitor<size_t> {
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  TextFormatter<TWriter> formatter_;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  const ResourceManager* resources_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
 | 
			
		||||
 
 | 
			
		||||
@@ -16,10 +16,11 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
 | 
			
		||||
  typedef JsonSerializer<TWriter> base;
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  PrettyJsonSerializer(TWriter writer) : base(writer), nesting_(0) {}
 | 
			
		||||
  PrettyJsonSerializer(TWriter writer, const ResourceManager* resources)
 | 
			
		||||
      : base(writer, resources), nesting_(0) {}
 | 
			
		||||
 | 
			
		||||
  size_t visit(const ArrayData& array) {
 | 
			
		||||
    auto it = array.createIterator();
 | 
			
		||||
    auto it = array.createIterator(base::resources_);
 | 
			
		||||
    if (!it.done()) {
 | 
			
		||||
      base::write("[\r\n");
 | 
			
		||||
      nesting_++;
 | 
			
		||||
@@ -27,7 +28,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
 | 
			
		||||
        indent();
 | 
			
		||||
        it->accept(*this);
 | 
			
		||||
 | 
			
		||||
        it.next();
 | 
			
		||||
        it.next(base::resources_);
 | 
			
		||||
        base::write(it.done() ? "\r\n" : ",\r\n");
 | 
			
		||||
      }
 | 
			
		||||
      nesting_--;
 | 
			
		||||
@@ -40,7 +41,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t visit(const ObjectData& object) {
 | 
			
		||||
    auto it = object.createIterator();
 | 
			
		||||
    auto it = object.createIterator(base::resources_);
 | 
			
		||||
    if (!it.done()) {
 | 
			
		||||
      base::write("{\r\n");
 | 
			
		||||
      nesting_++;
 | 
			
		||||
@@ -50,7 +51,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
 | 
			
		||||
        base::write(": ");
 | 
			
		||||
        it->accept(*this);
 | 
			
		||||
 | 
			
		||||
        it.next();
 | 
			
		||||
        it.next(base::resources_);
 | 
			
		||||
        base::write(it.done() ? "\r\n" : ",\r\n");
 | 
			
		||||
      }
 | 
			
		||||
      nesting_--;
 | 
			
		||||
 
 | 
			
		||||
@@ -67,13 +67,17 @@ class ResourceManager {
 | 
			
		||||
    return overflowed_;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  VariantSlot* allocVariant() {
 | 
			
		||||
    auto p = variantPool_.allocVariant();
 | 
			
		||||
  SlotWithId allocSlot() {
 | 
			
		||||
    auto p = variantPool_.allocSlot();
 | 
			
		||||
    if (!p)
 | 
			
		||||
      overflowed_ = true;
 | 
			
		||||
    return p;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  VariantSlot* getSlot(SlotId id) const {
 | 
			
		||||
    return variantPool_.getSlot(id);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template <typename TAdaptedString>
 | 
			
		||||
  StringNode* saveString(TAdaptedString str) {
 | 
			
		||||
    if (str.isNull())
 | 
			
		||||
@@ -123,8 +127,8 @@ class ResourceManager {
 | 
			
		||||
    stringPool_.clear(allocator_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ptrdiff_t shrinkToFit() {
 | 
			
		||||
    return variantPool_.shrinkToFit(allocator_);
 | 
			
		||||
  void shrinkToFit() {
 | 
			
		||||
    variantPool_.shrinkToFit(allocator_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
 
 | 
			
		||||
@@ -6,10 +6,39 @@
 | 
			
		||||
 | 
			
		||||
#include <ArduinoJson/Memory/ResourceManager.hpp>
 | 
			
		||||
#include <ArduinoJson/Polyfills/assert.hpp>
 | 
			
		||||
#include <ArduinoJson/Polyfills/integer.hpp>
 | 
			
		||||
 | 
			
		||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
 | 
			
		||||
 | 
			
		||||
class VariantSlot;
 | 
			
		||||
using SlotId = uint_t<ARDUINOJSON_SLOT_ID_SIZE * 8>::type;
 | 
			
		||||
using SlotCount = SlotId;
 | 
			
		||||
const SlotId NULL_SLOT = SlotId(-1);
 | 
			
		||||
 | 
			
		||||
class SlotWithId {
 | 
			
		||||
 public:
 | 
			
		||||
  SlotWithId() : slot_(nullptr), id_(NULL_SLOT) {}
 | 
			
		||||
  SlotWithId(VariantSlot* slot, SlotId id) : slot_(slot), id_(id) {
 | 
			
		||||
    ARDUINOJSON_ASSERT((slot == nullptr) == (id == NULL_SLOT));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  SlotId id() const {
 | 
			
		||||
    return id_;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  operator VariantSlot*() {
 | 
			
		||||
    return slot_;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  VariantSlot* operator->() {
 | 
			
		||||
    ARDUINOJSON_ASSERT(slot_ != nullptr);
 | 
			
		||||
    return slot_;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  VariantSlot* slot_;
 | 
			
		||||
  SlotId id_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class VariantPool {
 | 
			
		||||
 public:
 | 
			
		||||
@@ -30,18 +59,19 @@ class VariantPool {
 | 
			
		||||
  void create(size_t cap, Allocator* allocator);
 | 
			
		||||
  void destroy(Allocator* allocator);
 | 
			
		||||
 | 
			
		||||
  VariantSlot* allocVariant();
 | 
			
		||||
  SlotWithId allocSlot();
 | 
			
		||||
  VariantSlot* getSlot(SlotId id) const;
 | 
			
		||||
  void clear();
 | 
			
		||||
  ptrdiff_t shrinkToFit(Allocator*);
 | 
			
		||||
  size_t capacity() const;
 | 
			
		||||
  size_t usage() const;
 | 
			
		||||
  void shrinkToFit(Allocator*);
 | 
			
		||||
  SlotCount capacity() const;
 | 
			
		||||
  SlotCount usage() const;
 | 
			
		||||
 | 
			
		||||
  static size_t bytesToSlots(size_t);
 | 
			
		||||
  static size_t slotsToBytes(size_t);
 | 
			
		||||
  static SlotCount bytesToSlots(size_t);
 | 
			
		||||
  static size_t slotsToBytes(SlotCount);
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  size_t capacity_ = 0;
 | 
			
		||||
  size_t usage_ = 0;
 | 
			
		||||
  SlotCount capacity_ = 0;
 | 
			
		||||
  SlotCount usage_ = 0;
 | 
			
		||||
  VariantSlot* slots_ = nullptr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -28,29 +28,31 @@ inline void VariantPool::destroy(Allocator* allocator) {
 | 
			
		||||
  usage_ = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline ptrdiff_t VariantPool::shrinkToFit(Allocator* allocator) {
 | 
			
		||||
  auto originalPool = slots_;
 | 
			
		||||
inline void VariantPool::shrinkToFit(Allocator* allocator) {
 | 
			
		||||
  slots_ = reinterpret_cast<VariantSlot*>(
 | 
			
		||||
      allocator->reallocate(slots_, slotsToBytes(usage_)));
 | 
			
		||||
  if (slots_)
 | 
			
		||||
    capacity_ = usage_;
 | 
			
		||||
  return reinterpret_cast<char*>(slots_) -
 | 
			
		||||
         reinterpret_cast<char*>(originalPool);
 | 
			
		||||
  capacity_ = usage_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline VariantSlot* VariantPool::allocVariant() {
 | 
			
		||||
inline SlotWithId VariantPool::allocSlot() {
 | 
			
		||||
  if (!slots_)
 | 
			
		||||
    return nullptr;
 | 
			
		||||
  if (usage_ + 1 > capacity_)
 | 
			
		||||
    return nullptr;
 | 
			
		||||
  return new (&slots_[usage_++]) VariantSlot;
 | 
			
		||||
    return {};
 | 
			
		||||
  if (usage_ >= capacity_)
 | 
			
		||||
    return {};
 | 
			
		||||
  auto index = usage_++;
 | 
			
		||||
  auto slot = &slots_[index];
 | 
			
		||||
  return {new (slot) VariantSlot, SlotId(index)};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline size_t VariantPool::usage() const {
 | 
			
		||||
inline VariantSlot* VariantPool::getSlot(SlotId id) const {
 | 
			
		||||
  return id == NULL_SLOT ? nullptr : &slots_[id];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline SlotCount VariantPool::usage() const {
 | 
			
		||||
  return usage_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline size_t VariantPool::capacity() const {
 | 
			
		||||
inline SlotCount VariantPool::capacity() const {
 | 
			
		||||
  return capacity_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -58,11 +60,11 @@ inline void VariantPool::clear() {
 | 
			
		||||
  usage_ = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline size_t VariantPool::bytesToSlots(size_t n) {
 | 
			
		||||
  return n / sizeof(VariantSlot);
 | 
			
		||||
inline SlotCount VariantPool::bytesToSlots(size_t n) {
 | 
			
		||||
  return static_cast<SlotCount>(n / sizeof(VariantSlot));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline size_t VariantPool::slotsToBytes(size_t n) {
 | 
			
		||||
inline size_t VariantPool::slotsToBytes(SlotCount n) {
 | 
			
		||||
  return n * sizeof(VariantSlot);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,8 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
 | 
			
		||||
 public:
 | 
			
		||||
  static const bool producesText = false;
 | 
			
		||||
 | 
			
		||||
  MsgPackSerializer(TWriter writer) : writer_(writer) {}
 | 
			
		||||
  MsgPackSerializer(TWriter writer, const ResourceManager* resources)
 | 
			
		||||
      : writer_(writer), resources_(resources) {}
 | 
			
		||||
 | 
			
		||||
  template <typename T>
 | 
			
		||||
  typename enable_if<is_floating_point<T>::value && sizeof(T) == 4,
 | 
			
		||||
@@ -48,7 +49,7 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t visit(const ArrayData& array) {
 | 
			
		||||
    size_t n = array.size();
 | 
			
		||||
    size_t n = array.size(resources_);
 | 
			
		||||
    if (n < 0x10) {
 | 
			
		||||
      writeByte(uint8_t(0x90 + n));
 | 
			
		||||
    } else if (n < 0x10000) {
 | 
			
		||||
@@ -58,14 +59,15 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
 | 
			
		||||
      writeByte(0xDD);
 | 
			
		||||
      writeInteger(uint32_t(n));
 | 
			
		||||
    }
 | 
			
		||||
    for (auto it = array.createIterator(); !it.done(); it.next()) {
 | 
			
		||||
    for (auto it = array.createIterator(resources_); !it.done();
 | 
			
		||||
         it.next(resources_)) {
 | 
			
		||||
      it->accept(*this);
 | 
			
		||||
    }
 | 
			
		||||
    return bytesWritten();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t visit(const ObjectData& object) {
 | 
			
		||||
    size_t n = object.size();
 | 
			
		||||
    size_t n = object.size(resources_);
 | 
			
		||||
    if (n < 0x10) {
 | 
			
		||||
      writeByte(uint8_t(0x80 + n));
 | 
			
		||||
    } else if (n < 0x10000) {
 | 
			
		||||
@@ -75,7 +77,8 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
 | 
			
		||||
      writeByte(0xDF);
 | 
			
		||||
      writeInteger(uint32_t(n));
 | 
			
		||||
    }
 | 
			
		||||
    for (auto it = object.createIterator(); !it.done(); it.next()) {
 | 
			
		||||
    for (auto it = object.createIterator(resources_); !it.done();
 | 
			
		||||
         it.next(resources_)) {
 | 
			
		||||
      visit(it.key());
 | 
			
		||||
      it->accept(*this);
 | 
			
		||||
    }
 | 
			
		||||
@@ -200,6 +203,7 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  CountingDecorator<TWriter> writer_;
 | 
			
		||||
  const ResourceManager* resources_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@
 | 
			
		||||
                                              ARDUINOJSON_ENABLE_INFINITY, \
 | 
			
		||||
                                              ARDUINOJSON_ENABLE_COMMENTS, \
 | 
			
		||||
                                              ARDUINOJSON_DECODE_UNICODE), \
 | 
			
		||||
                        ARDUINOJSON_SLOT_OFFSET_SIZE)
 | 
			
		||||
                        ARDUINOJSON_SLOT_ID_SIZE)
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -56,19 +56,19 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
 | 
			
		||||
  // Returns the number of bytes occupied by the object.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonobject/memoryusage/
 | 
			
		||||
  FORCE_INLINE size_t memoryUsage() const {
 | 
			
		||||
    return data_ ? data_->memoryUsage() : 0;
 | 
			
		||||
    return data_ ? data_->memoryUsage(resources_) : 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns the depth (nesting level) of the object.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonobject/nesting/
 | 
			
		||||
  FORCE_INLINE size_t nesting() const {
 | 
			
		||||
    return detail::VariantData::nesting(collectionToVariant(data_));
 | 
			
		||||
    return detail::VariantData::nesting(collectionToVariant(data_), resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns the number of members in the object.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonobject/size/
 | 
			
		||||
  FORCE_INLINE size_t size() const {
 | 
			
		||||
    return data_ ? data_->size() : 0;
 | 
			
		||||
    return data_ ? data_->size(resources_) : 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns an iterator to the first key-value pair of the object.
 | 
			
		||||
@@ -76,7 +76,7 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
 | 
			
		||||
  FORCE_INLINE iterator begin() const {
 | 
			
		||||
    if (!data_)
 | 
			
		||||
      return iterator();
 | 
			
		||||
    return iterator(data_->createIterator(), resources_);
 | 
			
		||||
    return iterator(data_->createIterator(resources_), resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns an iterator following the last key-value pair of the object.
 | 
			
		||||
@@ -158,7 +158,8 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
 | 
			
		||||
  FORCE_INLINE
 | 
			
		||||
      typename detail::enable_if<detail::IsString<TString>::value, bool>::type
 | 
			
		||||
      containsKey(const TString& key) const {
 | 
			
		||||
    return detail::ObjectData::getMember(data_, detail::adaptString(key)) != 0;
 | 
			
		||||
    return detail::ObjectData::getMember(data_, detail::adaptString(key),
 | 
			
		||||
                                         resources_) != 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns true if the object contains the specified key.
 | 
			
		||||
@@ -167,7 +168,8 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
 | 
			
		||||
  FORCE_INLINE
 | 
			
		||||
      typename detail::enable_if<detail::IsString<TChar*>::value, bool>::type
 | 
			
		||||
      containsKey(TChar* key) const {
 | 
			
		||||
    return detail::ObjectData::getMember(data_, detail::adaptString(key)) != 0;
 | 
			
		||||
    return detail::ObjectData::getMember(data_, detail::adaptString(key),
 | 
			
		||||
                                         resources_) != 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Creates an array and adds it to the object.
 | 
			
		||||
 
 | 
			
		||||
@@ -45,19 +45,19 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
 | 
			
		||||
  // Returns the number of bytes occupied by the object.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonobjectconst/memoryusage/
 | 
			
		||||
  FORCE_INLINE size_t memoryUsage() const {
 | 
			
		||||
    return data_ ? data_->memoryUsage() : 0;
 | 
			
		||||
    return data_ ? data_->memoryUsage(resources_) : 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns the depth (nesting level) of the object.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonobjectconst/nesting/
 | 
			
		||||
  FORCE_INLINE size_t nesting() const {
 | 
			
		||||
    return detail::VariantData::nesting(collectionToVariant(data_));
 | 
			
		||||
    return detail::VariantData::nesting(collectionToVariant(data_), resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns the number of members in the object.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonobjectconst/size/
 | 
			
		||||
  FORCE_INLINE size_t size() const {
 | 
			
		||||
    return data_ ? data_->size() : 0;
 | 
			
		||||
    return data_ ? data_->size(resources_) : 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns an iterator to the first key-value pair of the object.
 | 
			
		||||
@@ -65,7 +65,7 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
 | 
			
		||||
  FORCE_INLINE iterator begin() const {
 | 
			
		||||
    if (!data_)
 | 
			
		||||
      return iterator();
 | 
			
		||||
    return iterator(data_->createIterator(), resources_);
 | 
			
		||||
    return iterator(data_->createIterator(resources_), resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns an iterator following the last key-value pair of the object.
 | 
			
		||||
@@ -78,14 +78,16 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonobjectconst/containskey/
 | 
			
		||||
  template <typename TString>
 | 
			
		||||
  FORCE_INLINE bool containsKey(const TString& key) const {
 | 
			
		||||
    return detail::ObjectData::getMember(data_, detail::adaptString(key)) != 0;
 | 
			
		||||
    return detail::ObjectData::getMember(data_, detail::adaptString(key),
 | 
			
		||||
                                         resources_) != 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns true if the object contains the specified key.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonobjectconst/containskey/
 | 
			
		||||
  template <typename TChar>
 | 
			
		||||
  FORCE_INLINE bool containsKey(TChar* key) const {
 | 
			
		||||
    return detail::ObjectData::getMember(data_, detail::adaptString(key)) != 0;
 | 
			
		||||
    return detail::ObjectData::getMember(data_, detail::adaptString(key),
 | 
			
		||||
                                         resources_) != 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Gets the member with specified key.
 | 
			
		||||
@@ -94,9 +96,9 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
 | 
			
		||||
  FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value,
 | 
			
		||||
                                          JsonVariantConst>::type
 | 
			
		||||
  operator[](const TString& key) const {
 | 
			
		||||
    return JsonVariantConst(
 | 
			
		||||
        detail::ObjectData::getMember(data_, detail::adaptString(key)),
 | 
			
		||||
        resources_);
 | 
			
		||||
    return JsonVariantConst(detail::ObjectData::getMember(
 | 
			
		||||
                                data_, detail::adaptString(key), resources_),
 | 
			
		||||
                            resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Gets the member with specified key.
 | 
			
		||||
 
 | 
			
		||||
@@ -54,16 +54,16 @@ template <typename TDerived>
 | 
			
		||||
template <typename TString>
 | 
			
		||||
inline typename enable_if<IsString<TString>::value, bool>::type
 | 
			
		||||
VariantRefBase<TDerived>::containsKey(const TString& key) const {
 | 
			
		||||
  return VariantData::getMember(VariantAttorney::getData(derived()),
 | 
			
		||||
                                adaptString(key)) != 0;
 | 
			
		||||
  return VariantData::getMember(getData(), adaptString(key),
 | 
			
		||||
                                getResourceManager()) != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename TDerived>
 | 
			
		||||
template <typename TChar>
 | 
			
		||||
inline typename enable_if<IsString<TChar*>::value, bool>::type
 | 
			
		||||
VariantRefBase<TDerived>::containsKey(TChar* key) const {
 | 
			
		||||
  return VariantData::getMember(VariantAttorney::getData(derived()),
 | 
			
		||||
                                adaptString(key)) != 0;
 | 
			
		||||
  return VariantData::getMember(getData(), adaptString(key),
 | 
			
		||||
                                getResourceManager()) != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename TDerived>
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@ class JsonObjectIterator {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  JsonObjectIterator& operator++() {
 | 
			
		||||
    iterator_.next();
 | 
			
		||||
    iterator_.next(resources_);
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -69,7 +69,7 @@ class JsonObjectConstIterator {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  JsonObjectConstIterator& operator++() {
 | 
			
		||||
    iterator_.next();
 | 
			
		||||
    iterator_.next(resources_);
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -46,8 +46,9 @@ class MemberProxy
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  FORCE_INLINE VariantData* getData() const {
 | 
			
		||||
    return VariantData::getMember(VariantAttorney::getData(upstream_),
 | 
			
		||||
                                  adaptString(key_));
 | 
			
		||||
    return VariantData::getMember(
 | 
			
		||||
        VariantAttorney::getData(upstream_), adaptString(key_),
 | 
			
		||||
        VariantAttorney::getResourceManager(upstream_));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  FORCE_INLINE VariantData* getOrCreateData() const {
 | 
			
		||||
 
 | 
			
		||||
@@ -43,13 +43,15 @@ class ObjectData : public CollectionData {
 | 
			
		||||
  VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources);
 | 
			
		||||
 | 
			
		||||
  template <typename TAdaptedString>
 | 
			
		||||
  VariantData* getMember(TAdaptedString key) const;
 | 
			
		||||
  VariantData* getMember(TAdaptedString key,
 | 
			
		||||
                         const ResourceManager* resources) const;
 | 
			
		||||
 | 
			
		||||
  template <typename TAdaptedString>
 | 
			
		||||
  static VariantData* getMember(const ObjectData* object, TAdaptedString key) {
 | 
			
		||||
  static VariantData* getMember(const ObjectData* object, TAdaptedString key,
 | 
			
		||||
                                const ResourceManager* resources) {
 | 
			
		||||
    if (!object)
 | 
			
		||||
      return nullptr;
 | 
			
		||||
    return object->getMember(key);
 | 
			
		||||
    return object->getMember(key, resources);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template <typename TAdaptedString>
 | 
			
		||||
@@ -65,7 +67,7 @@ class ObjectData : public CollectionData {
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  template <typename TAdaptedString>
 | 
			
		||||
  iterator findKey(TAdaptedString key) const;
 | 
			
		||||
  iterator findKey(TAdaptedString key, const ResourceManager* resources) const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
 | 
			
		||||
 
 | 
			
		||||
@@ -10,24 +10,26 @@
 | 
			
		||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
 | 
			
		||||
 | 
			
		||||
template <typename TAdaptedString>
 | 
			
		||||
inline VariantData* ObjectData::getMember(TAdaptedString key) const {
 | 
			
		||||
  return findKey(key).data();
 | 
			
		||||
inline VariantData* ObjectData::getMember(
 | 
			
		||||
    TAdaptedString key, const ResourceManager* resources) const {
 | 
			
		||||
  return findKey(key, resources).data();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename TAdaptedString>
 | 
			
		||||
VariantData* ObjectData::getOrAddMember(TAdaptedString key,
 | 
			
		||||
                                        ResourceManager* resources) {
 | 
			
		||||
  auto it = findKey(key);
 | 
			
		||||
  auto it = findKey(key, resources);
 | 
			
		||||
  if (!it.done())
 | 
			
		||||
    return it.data();
 | 
			
		||||
  return addMember(key, resources);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename TAdaptedString>
 | 
			
		||||
inline ObjectData::iterator ObjectData::findKey(TAdaptedString key) const {
 | 
			
		||||
inline ObjectData::iterator ObjectData::findKey(
 | 
			
		||||
    TAdaptedString key, const ResourceManager* resources) const {
 | 
			
		||||
  if (key.isNull())
 | 
			
		||||
    return iterator();
 | 
			
		||||
  for (auto it = createIterator(); !it.done(); it.next()) {
 | 
			
		||||
  for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
 | 
			
		||||
    if (stringEquals(key, adaptString(it.key())))
 | 
			
		||||
      return it;
 | 
			
		||||
  }
 | 
			
		||||
@@ -37,7 +39,7 @@ inline ObjectData::iterator ObjectData::findKey(TAdaptedString key) const {
 | 
			
		||||
template <typename TAdaptedString>
 | 
			
		||||
inline void ObjectData::removeMember(TAdaptedString key,
 | 
			
		||||
                                     ResourceManager* resources) {
 | 
			
		||||
  remove(findKey(key), resources);
 | 
			
		||||
  remove(findKey(key, resources), resources);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
 | 
			
		||||
 
 | 
			
		||||
@@ -11,21 +11,21 @@
 | 
			
		||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
 | 
			
		||||
 | 
			
		||||
template <int Bits>
 | 
			
		||||
struct int_t;
 | 
			
		||||
struct uint_t;
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct int_t<8> {
 | 
			
		||||
  typedef int8_t type;
 | 
			
		||||
struct uint_t<8> {
 | 
			
		||||
  typedef uint8_t type;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct int_t<16> {
 | 
			
		||||
  typedef int16_t type;
 | 
			
		||||
struct uint_t<16> {
 | 
			
		||||
  typedef uint16_t type;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct int_t<32> {
 | 
			
		||||
  typedef int32_t type;
 | 
			
		||||
struct uint_t<32> {
 | 
			
		||||
  typedef uint32_t type;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,8 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
 | 
			
		||||
template <template <typename> class TSerializer>
 | 
			
		||||
size_t measure(ArduinoJson::JsonVariantConst source) {
 | 
			
		||||
  DummyWriter dp;
 | 
			
		||||
  TSerializer<DummyWriter> serializer(dp);
 | 
			
		||||
  TSerializer<DummyWriter> serializer(
 | 
			
		||||
      dp, VariantAttorney::getResourceManager(source));
 | 
			
		||||
  return VariantData::accept(VariantAttorney::getData(source), serializer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,8 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
 | 
			
		||||
 | 
			
		||||
template <template <typename> class TSerializer, typename TWriter>
 | 
			
		||||
size_t doSerialize(ArduinoJson::JsonVariantConst source, TWriter writer) {
 | 
			
		||||
  TSerializer<TWriter> serializer(writer);
 | 
			
		||||
  TSerializer<TWriter> serializer(writer,
 | 
			
		||||
                                  VariantAttorney::getResourceManager(source));
 | 
			
		||||
  return VariantData::accept(VariantAttorney::getData(source), serializer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -94,7 +94,7 @@ inline JsonVariant VariantRefBase<TDerived>::add() const {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename TDerived>
 | 
			
		||||
inline JsonVariant VariantRefBase<TDerived>::getVariant() const {
 | 
			
		||||
inline JsonVariant VariantRefBase<TDerived>::getSlot() const {
 | 
			
		||||
  return JsonVariant(getData(), getResourceManager());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -50,19 +50,19 @@ class JsonVariantConst : public detail::VariantTag,
 | 
			
		||||
  // Returns the number of bytes occupied by the value.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonvariantconst/memoryusage/
 | 
			
		||||
  FORCE_INLINE size_t memoryUsage() const {
 | 
			
		||||
    return data_ ? data_->memoryUsage() : 0;
 | 
			
		||||
    return data_ ? data_->memoryUsage(resources_) : 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns the depth (nesting level) of the value.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonvariantconst/nesting/
 | 
			
		||||
  FORCE_INLINE size_t nesting() const {
 | 
			
		||||
    return detail::VariantData::nesting(data_);
 | 
			
		||||
    return detail::VariantData::nesting(data_, resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns the size of the array or object.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonvariantconst/size/
 | 
			
		||||
  size_t size() const {
 | 
			
		||||
    return detail::VariantData::size(data_);
 | 
			
		||||
    return detail::VariantData::size(data_, resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Casts the value to the specified type.
 | 
			
		||||
@@ -93,8 +93,8 @@ class JsonVariantConst : public detail::VariantTag,
 | 
			
		||||
  // Gets array's element at specified index.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonvariantconst/subscript/
 | 
			
		||||
  FORCE_INLINE JsonVariantConst operator[](size_t index) const {
 | 
			
		||||
    return JsonVariantConst(detail::VariantData::getElement(data_, index),
 | 
			
		||||
                            resources_);
 | 
			
		||||
    return JsonVariantConst(
 | 
			
		||||
        detail::VariantData::getElement(data_, index, resources_), resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Gets object's member with specified key.
 | 
			
		||||
@@ -103,9 +103,9 @@ class JsonVariantConst : public detail::VariantTag,
 | 
			
		||||
  FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value,
 | 
			
		||||
                                          JsonVariantConst>::type
 | 
			
		||||
  operator[](const TString& key) const {
 | 
			
		||||
    return JsonVariantConst(
 | 
			
		||||
        detail::VariantData::getMember(data_, detail::adaptString(key)),
 | 
			
		||||
        resources_);
 | 
			
		||||
    return JsonVariantConst(detail::VariantData::getMember(
 | 
			
		||||
                                data_, detail::adaptString(key), resources_),
 | 
			
		||||
                            resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Gets object's member with specified key.
 | 
			
		||||
@@ -114,9 +114,9 @@ class JsonVariantConst : public detail::VariantTag,
 | 
			
		||||
  FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value,
 | 
			
		||||
                                          JsonVariantConst>::type
 | 
			
		||||
  operator[](TChar* key) const {
 | 
			
		||||
    return JsonVariantConst(
 | 
			
		||||
        detail::VariantData::getMember(data_, detail::adaptString(key)),
 | 
			
		||||
        resources_);
 | 
			
		||||
    return JsonVariantConst(detail::VariantData::getMember(
 | 
			
		||||
                                data_, detail::adaptString(key), resources_),
 | 
			
		||||
                            resources_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns true if tge object contains the specified key.
 | 
			
		||||
@@ -125,8 +125,8 @@ class JsonVariantConst : public detail::VariantTag,
 | 
			
		||||
  FORCE_INLINE
 | 
			
		||||
      typename detail::enable_if<detail::IsString<TString>::value, bool>::type
 | 
			
		||||
      containsKey(const TString& key) const {
 | 
			
		||||
    return detail::VariantData::getMember(getData(),
 | 
			
		||||
                                          detail::adaptString(key)) != 0;
 | 
			
		||||
    return detail::VariantData::getMember(getData(), detail::adaptString(key),
 | 
			
		||||
                                          resources_) != 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns true if tge object contains the specified key.
 | 
			
		||||
@@ -135,8 +135,8 @@ class JsonVariantConst : public detail::VariantTag,
 | 
			
		||||
  FORCE_INLINE
 | 
			
		||||
      typename detail::enable_if<detail::IsString<TChar*>::value, bool>::type
 | 
			
		||||
      containsKey(TChar* key) const {
 | 
			
		||||
    return detail::VariantData::getMember(getData(),
 | 
			
		||||
                                          detail::adaptString(key)) != 0;
 | 
			
		||||
    return detail::VariantData::getMember(getData(), detail::adaptString(key),
 | 
			
		||||
                                          resources_) != 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
 
 | 
			
		||||
@@ -185,30 +185,28 @@ class VariantData {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  VariantData* getElement(size_t index) const {
 | 
			
		||||
    auto array = asArray();
 | 
			
		||||
    if (!array)
 | 
			
		||||
      return nullptr;
 | 
			
		||||
    return array->getElement(index);
 | 
			
		||||
  VariantData* getElement(size_t index,
 | 
			
		||||
                          const ResourceManager* resources) const {
 | 
			
		||||
    return ArrayData::getElement(asArray(), index, resources);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static VariantData* getElement(const VariantData* var, size_t index) {
 | 
			
		||||
    return var != 0 ? var->getElement(index) : 0;
 | 
			
		||||
  static VariantData* getElement(const VariantData* var, size_t index,
 | 
			
		||||
                                 const ResourceManager* resources) {
 | 
			
		||||
    return var != 0 ? var->getElement(index, resources) : 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template <typename TAdaptedString>
 | 
			
		||||
  VariantData* getMember(TAdaptedString key) const {
 | 
			
		||||
    auto object = asObject();
 | 
			
		||||
    if (!object)
 | 
			
		||||
      return nullptr;
 | 
			
		||||
    return object->getMember(key);
 | 
			
		||||
  VariantData* getMember(TAdaptedString key,
 | 
			
		||||
                         const ResourceManager* resources) const {
 | 
			
		||||
    return ObjectData::getMember(asObject(), key, resources);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template <typename TAdaptedString>
 | 
			
		||||
  static VariantData* getMember(const VariantData* var, TAdaptedString key) {
 | 
			
		||||
  static VariantData* getMember(const VariantData* var, TAdaptedString key,
 | 
			
		||||
                                const ResourceManager* resources) {
 | 
			
		||||
    if (!var)
 | 
			
		||||
      return 0;
 | 
			
		||||
    return var->getMember(key);
 | 
			
		||||
    return var->getMember(key, resources);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  VariantData* getOrAddElement(size_t index, ResourceManager* resources) {
 | 
			
		||||
@@ -276,36 +274,32 @@ class VariantData {
 | 
			
		||||
    return type() == VALUE_IS_LINKED_STRING || type() == VALUE_IS_OWNED_STRING;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t memoryUsage() const {
 | 
			
		||||
  size_t memoryUsage(const ResourceManager* resources) const {
 | 
			
		||||
    switch (type()) {
 | 
			
		||||
      case VALUE_IS_OWNED_STRING:
 | 
			
		||||
      case VALUE_IS_RAW_STRING:
 | 
			
		||||
        return sizeofString(content_.asOwnedString->length);
 | 
			
		||||
      case VALUE_IS_OBJECT:
 | 
			
		||||
      case VALUE_IS_ARRAY:
 | 
			
		||||
        return content_.asCollection.memoryUsage();
 | 
			
		||||
        return content_.asCollection.memoryUsage(resources);
 | 
			
		||||
      default:
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void movePointers(ptrdiff_t variantDistance) {
 | 
			
		||||
    if (flags_ & COLLECTION_MASK)
 | 
			
		||||
      content_.asCollection.movePointers(variantDistance);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t nesting() const {
 | 
			
		||||
  size_t nesting(const ResourceManager* resources) const {
 | 
			
		||||
    auto collection = asCollection();
 | 
			
		||||
    if (collection)
 | 
			
		||||
      return collection->nesting();
 | 
			
		||||
      return collection->nesting(resources);
 | 
			
		||||
    else
 | 
			
		||||
      return 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static size_t nesting(const VariantData* var) {
 | 
			
		||||
  static size_t nesting(const VariantData* var,
 | 
			
		||||
                        const ResourceManager* resources) {
 | 
			
		||||
    if (!var)
 | 
			
		||||
      return 0;
 | 
			
		||||
    return var->nesting();
 | 
			
		||||
    return var->nesting(resources);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void operator=(const VariantData& src) {
 | 
			
		||||
@@ -455,12 +449,12 @@ class VariantData {
 | 
			
		||||
    content_.asOwnedString = s;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t size() const {
 | 
			
		||||
    return isCollection() ? content_.asCollection.size() : 0;
 | 
			
		||||
  size_t size(const ResourceManager* resources) const {
 | 
			
		||||
    return isCollection() ? content_.asCollection.size(resources) : 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static size_t size(const VariantData* var) {
 | 
			
		||||
    return var != 0 ? var->size() : 0;
 | 
			
		||||
  static size_t size(const VariantData* var, const ResourceManager* resources) {
 | 
			
		||||
    return var != 0 ? var->size(resources) : 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ArrayData& toArray() {
 | 
			
		||||
 
 | 
			
		||||
@@ -58,7 +58,7 @@ class VariantRefBase : public VariantTag {
 | 
			
		||||
  template <typename T>
 | 
			
		||||
  FORCE_INLINE typename enable_if<ConverterNeedsWriteableRef<T>::value, T>::type
 | 
			
		||||
  as() const {
 | 
			
		||||
    return Converter<T>::fromJson(getVariant());
 | 
			
		||||
    return Converter<T>::fromJson(getSlot());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template <typename T>
 | 
			
		||||
@@ -92,7 +92,7 @@ class VariantRefBase : public VariantTag {
 | 
			
		||||
  FORCE_INLINE
 | 
			
		||||
      typename enable_if<ConverterNeedsWriteableRef<T>::value, bool>::type
 | 
			
		||||
      is() const {
 | 
			
		||||
    return Converter<T>::checkJson(getVariant());
 | 
			
		||||
    return Converter<T>::checkJson(getSlot());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns true if the value is of the specified type.
 | 
			
		||||
@@ -127,20 +127,20 @@ class VariantRefBase : public VariantTag {
 | 
			
		||||
  // Returns the size of the array or object.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonvariant/size/
 | 
			
		||||
  FORCE_INLINE size_t size() const {
 | 
			
		||||
    return VariantData::size(getData());
 | 
			
		||||
    return VariantData::size(getData(), getResourceManager());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns the number of bytes occupied by the value.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonvariant/memoryusage/
 | 
			
		||||
  FORCE_INLINE size_t memoryUsage() const {
 | 
			
		||||
    VariantData* data = getData();
 | 
			
		||||
    return data ? data->memoryUsage() : 0;
 | 
			
		||||
    return data ? data->memoryUsage(getResourceManager()) : 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns the depth (nesting level) of the value.
 | 
			
		||||
  // https://arduinojson.org/v6/api/jsonvariant/nesting/
 | 
			
		||||
  FORCE_INLINE size_t nesting() const {
 | 
			
		||||
    return VariantData::nesting(getData());
 | 
			
		||||
    return VariantData::nesting(getData(), getResourceManager());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Appends a new (null) element to the array.
 | 
			
		||||
@@ -269,7 +269,7 @@ class VariantRefBase : public VariantTag {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  FORCE_INLINE ArduinoJson::JsonVariant getVariant() const;
 | 
			
		||||
  FORCE_INLINE ArduinoJson::JsonVariant getSlot() const;
 | 
			
		||||
 | 
			
		||||
  FORCE_INLINE ArduinoJson::JsonVariantConst getVariantConst() const {
 | 
			
		||||
    return ArduinoJson::JsonVariantConst(getData(), getResourceManager());
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,6 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <ArduinoJson/Memory/ResourceManager.hpp>
 | 
			
		||||
#include <ArduinoJson/Polyfills/integer.hpp>
 | 
			
		||||
#include <ArduinoJson/Polyfills/limits.hpp>
 | 
			
		||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
 | 
			
		||||
#include <ArduinoJson/Variant/VariantContent.hpp>
 | 
			
		||||
@@ -14,15 +13,13 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
 | 
			
		||||
 | 
			
		||||
struct StringNode;
 | 
			
		||||
 | 
			
		||||
typedef int_t<ARDUINOJSON_SLOT_OFFSET_SIZE * 8>::type VariantSlotDiff;
 | 
			
		||||
 | 
			
		||||
class VariantSlot {
 | 
			
		||||
  // CAUTION: same layout as VariantData
 | 
			
		||||
  // we cannot use composition because it adds padding
 | 
			
		||||
  // (+20% on ESP8266 for example)
 | 
			
		||||
  VariantContent content_;
 | 
			
		||||
  uint8_t flags_;
 | 
			
		||||
  VariantSlotDiff next_;
 | 
			
		||||
  SlotId next_;
 | 
			
		||||
  const char* key_;
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
@@ -33,7 +30,7 @@ class VariantSlot {
 | 
			
		||||
 | 
			
		||||
  static void operator delete(void*, void*) noexcept {}
 | 
			
		||||
 | 
			
		||||
  VariantSlot() : flags_(0), next_(0), key_(0) {}
 | 
			
		||||
  VariantSlot() : flags_(0), next_(NULL_SLOT), key_(0) {}
 | 
			
		||||
 | 
			
		||||
  VariantData* data() {
 | 
			
		||||
    return reinterpret_cast<VariantData*>(&content_);
 | 
			
		||||
@@ -43,29 +40,12 @@ class VariantSlot {
 | 
			
		||||
    return reinterpret_cast<const VariantData*>(&content_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  VariantSlot* next() {
 | 
			
		||||
    return next_ ? this + next_ : 0;
 | 
			
		||||
  SlotId next() const {
 | 
			
		||||
    return next_;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const VariantSlot* next() const {
 | 
			
		||||
    return const_cast<VariantSlot*>(this)->next();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setNext(VariantSlot* slot) {
 | 
			
		||||
    ARDUINOJSON_ASSERT(!slot || slot - this >=
 | 
			
		||||
                                    numeric_limits<VariantSlotDiff>::lowest());
 | 
			
		||||
    ARDUINOJSON_ASSERT(!slot || slot - this <=
 | 
			
		||||
                                    numeric_limits<VariantSlotDiff>::highest());
 | 
			
		||||
    next_ = VariantSlotDiff(slot ? slot - this : 0);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setNextNotNull(VariantSlot* slot) {
 | 
			
		||||
    ARDUINOJSON_ASSERT(slot != 0);
 | 
			
		||||
    ARDUINOJSON_ASSERT(slot - this >=
 | 
			
		||||
                       numeric_limits<VariantSlotDiff>::lowest());
 | 
			
		||||
    ARDUINOJSON_ASSERT(slot - this <=
 | 
			
		||||
                       numeric_limits<VariantSlotDiff>::highest());
 | 
			
		||||
    next_ = VariantSlotDiff(slot - this);
 | 
			
		||||
  void setNext(SlotId slot) {
 | 
			
		||||
    next_ = slot;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void setKey(const char* k) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user