diff --git a/extras/tests/Helpers/Allocators.hpp b/extras/tests/Helpers/Allocators.hpp index fd6e7b21..a551c311 100644 --- a/extras/tests/Helpers/Allocators.hpp +++ b/extras/tests/Helpers/Allocators.hpp @@ -265,12 +265,14 @@ class TimebombAllocator : public ArduinoJson::Allocator { } // namespace inline size_t sizeofPoolList(size_t n = ARDUINOJSON_INITIAL_POOL_COUNT) { - return sizeof(ArduinoJson::detail::MemoryPool) * n; + using namespace ArduinoJson::detail; + return sizeof(MemoryPool) * n; } inline size_t sizeofPool( ArduinoJson::detail::SlotCount n = ARDUINOJSON_POOL_CAPACITY) { - return ArduinoJson::detail::MemoryPool::slotsToBytes(n); + using namespace ArduinoJson::detail; + return MemoryPool::slotsToBytes(n); } inline size_t sizeofStringBuffer(size_t iteration = 1) { diff --git a/extras/tests/ResourceManager/StringBuilder.cpp b/extras/tests/ResourceManager/StringBuilder.cpp index 00905e3d..b649afeb 100644 --- a/extras/tests/ResourceManager/StringBuilder.cpp +++ b/extras/tests/ResourceManager/StringBuilder.cpp @@ -2,7 +2,6 @@ // Copyright © 2014-2024, Benoit BLANCHON // MIT License -#include #include #include diff --git a/extras/tests/ResourceManager/clear.cpp b/extras/tests/ResourceManager/clear.cpp index a444e69c..a7736039 100644 --- a/extras/tests/ResourceManager/clear.cpp +++ b/extras/tests/ResourceManager/clear.cpp @@ -2,7 +2,6 @@ // Copyright © 2014-2024, Benoit BLANCHON // MIT License -#include #include #include #include diff --git a/extras/tests/ResourceManager/saveString.cpp b/extras/tests/ResourceManager/saveString.cpp index a054bdef..88c242f6 100644 --- a/extras/tests/ResourceManager/saveString.cpp +++ b/extras/tests/ResourceManager/saveString.cpp @@ -2,7 +2,6 @@ // Copyright © 2014-2024, Benoit BLANCHON // MIT License -#include #include #include #include diff --git a/extras/tests/ResourceManager/shrinkToFit.cpp b/extras/tests/ResourceManager/shrinkToFit.cpp index ea2d6527..a09fd8a3 100644 --- a/extras/tests/ResourceManager/shrinkToFit.cpp +++ b/extras/tests/ResourceManager/shrinkToFit.cpp @@ -2,7 +2,6 @@ // Copyright © 2014-2024, Benoit BLANCHON // MIT License -#include #include #include #include diff --git a/extras/tests/ResourceManager/size.cpp b/extras/tests/ResourceManager/size.cpp index e24ecdca..8d4b799d 100644 --- a/extras/tests/ResourceManager/size.cpp +++ b/extras/tests/ResourceManager/size.cpp @@ -2,7 +2,6 @@ // Copyright © 2014-2024, Benoit BLANCHON // MIT License -#include #include #include #include diff --git a/extras/tests/ResourceManager/swap.cpp b/extras/tests/ResourceManager/swap.cpp index 50517d48..a2b1fe99 100644 --- a/extras/tests/ResourceManager/swap.cpp +++ b/extras/tests/ResourceManager/swap.cpp @@ -3,7 +3,6 @@ // MIT License #include -#include #include #include #include diff --git a/src/ArduinoJson.hpp b/src/ArduinoJson.hpp index e61a20d3..a14f2b1a 100644 --- a/src/ArduinoJson.hpp +++ b/src/ArduinoJson.hpp @@ -36,13 +36,13 @@ #include "ArduinoJson/Array/ElementProxy.hpp" #include "ArduinoJson/Array/Utilities.hpp" #include "ArduinoJson/Collection/CollectionImpl.hpp" -#include "ArduinoJson/Memory/MemoryPoolImpl.hpp" #include "ArduinoJson/Memory/ResourceManagerImpl.hpp" #include "ArduinoJson/Object/MemberProxy.hpp" #include "ArduinoJson/Object/ObjectImpl.hpp" #include "ArduinoJson/Variant/ConverterImpl.hpp" #include "ArduinoJson/Variant/JsonVariantCopier.hpp" #include "ArduinoJson/Variant/VariantCompare.hpp" +#include "ArduinoJson/Variant/VariantImpl.hpp" #include "ArduinoJson/Variant/VariantRefBaseImpl.hpp" #include "ArduinoJson/Json/JsonDeserializer.hpp" diff --git a/src/ArduinoJson/Collection/CollectionData.hpp b/src/ArduinoJson/Collection/CollectionData.hpp index 616ed18b..a1c575c7 100644 --- a/src/ArduinoJson/Collection/CollectionData.hpp +++ b/src/ArduinoJson/Collection/CollectionData.hpp @@ -4,7 +4,7 @@ #pragma once -#include +#include #include #include @@ -13,6 +13,7 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE class VariantData; +class ResourceManager; class CollectionIterator { friend class CollectionData; @@ -78,9 +79,7 @@ class CollectionData { using iterator = CollectionIterator; - iterator createIterator(const ResourceManager* resources) const { - return iterator(resources->getVariant(head_), head_); - } + iterator createIterator(const ResourceManager* resources) const; size_t size(const ResourceManager*) const; size_t nesting(const ResourceManager*) const; @@ -98,15 +97,17 @@ class CollectionData { } protected: - void appendOne(VariantWithId slot, const ResourceManager* resources); - void appendPair(VariantWithId key, VariantWithId value, + void appendOne(SlotWithId slot, + const ResourceManager* resources); + void appendPair(SlotWithId key, SlotWithId value, const ResourceManager* resources); void removeOne(iterator it, ResourceManager* resources); void removePair(iterator it, ResourceManager* resources); private: - VariantWithId getPreviousSlot(VariantData*, const ResourceManager*) const; + SlotWithId getPreviousSlot(VariantData*, + const ResourceManager*) const; }; inline const VariantData* collectionToVariant( diff --git a/src/ArduinoJson/Collection/CollectionImpl.hpp b/src/ArduinoJson/Collection/CollectionImpl.hpp index d68f48ac..4c022b9c 100644 --- a/src/ArduinoJson/Collection/CollectionImpl.hpp +++ b/src/ArduinoJson/Collection/CollectionImpl.hpp @@ -25,7 +25,12 @@ inline void CollectionIterator::next(const ResourceManager* resources) { nextId_ = slot_->next(); } -inline void CollectionData::appendOne(VariantWithId slot, +inline CollectionData::iterator CollectionData::createIterator( + const ResourceManager* resources) const { + return iterator(resources->getVariant(head_), head_); +} + +inline void CollectionData::appendOne(SlotWithId slot, const ResourceManager* resources) { if (tail_ != NULL_SLOT) { auto tail = resources->getVariant(tail_); @@ -37,7 +42,8 @@ inline void CollectionData::appendOne(VariantWithId slot, } } -inline void CollectionData::appendPair(VariantWithId key, VariantWithId value, +inline void CollectionData::appendPair(SlotWithId key, + SlotWithId value, const ResourceManager* resources) { key->setNext(value.id()); @@ -57,22 +63,22 @@ inline void CollectionData::clear(ResourceManager* resources) { auto currId = next; auto slot = resources->getVariant(next); next = slot->next(); - resources->freeVariant(VariantWithId(slot, currId)); + resources->freeVariant(SlotWithId(slot, currId)); } head_ = NULL_SLOT; tail_ = NULL_SLOT; } -inline VariantWithId CollectionData::getPreviousSlot( +inline SlotWithId CollectionData::getPreviousSlot( VariantData* target, const ResourceManager* resources) const { - auto prev = VariantWithId(); + auto prev = SlotWithId(); auto currentId = head_; while (currentId != NULL_SLOT) { auto currentSlot = resources->getVariant(currentId); if (currentSlot == target) break; - prev = VariantWithId(currentSlot, currentId); + prev = SlotWithId(currentSlot, currentId); currentId = currentSlot->next(); } return prev; diff --git a/src/ArduinoJson/Memory/MemoryPool.hpp b/src/ArduinoJson/Memory/MemoryPool.hpp index d7062b3a..742e9d7b 100644 --- a/src/ArduinoJson/Memory/MemoryPool.hpp +++ b/src/ArduinoJson/Memory/MemoryPool.hpp @@ -10,15 +10,15 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -class VariantData; using SlotId = uint_t; using SlotCount = SlotId; const SlotId NULL_SLOT = SlotId(-1); +template class SlotWithId { public: SlotWithId() : slot_(nullptr), id_(NULL_SLOT) {} - SlotWithId(VariantData* slot, SlotId id) : slot_(slot), id_(id) { + SlotWithId(T* slot, SlotId id) : slot_(slot), id_(id) { ARDUINOJSON_ASSERT((slot == nullptr) == (id == NULL_SLOT)); } @@ -30,38 +30,81 @@ class SlotWithId { return id_; } - VariantData* ptr() const { + T* ptr() const { return slot_; } - VariantData* operator->() { + T* operator->() const { ARDUINOJSON_ASSERT(slot_ != nullptr); return slot_; } private: - VariantData* slot_; + T* slot_; SlotId id_; }; +template class MemoryPool { public: - void create(SlotCount cap, Allocator* allocator); - void destroy(Allocator* allocator); + void create(SlotCount cap, Allocator* allocator) { + ARDUINOJSON_ASSERT(cap > 0); + slots_ = reinterpret_cast(allocator->allocate(slotsToBytes(cap))); + capacity_ = slots_ ? cap : 0; + usage_ = 0; + } - SlotWithId allocSlot(); - VariantData* getSlot(SlotId id) const; - void clear(); - void shrinkToFit(Allocator*); - SlotCount usage() const; + void destroy(Allocator* allocator) { + if (slots_) + allocator->deallocate(slots_); + slots_ = nullptr; + capacity_ = 0; + usage_ = 0; + } - static SlotCount bytesToSlots(size_t); - static size_t slotsToBytes(SlotCount); + SlotWithId allocSlot() { + if (!slots_) + return {}; + if (usage_ >= capacity_) + return {}; + auto index = usage_++; + return {slots_ + index, SlotId(index)}; + } + + T* getSlot(SlotId id) const { + ARDUINOJSON_ASSERT(id < usage_); + return slots_ + id; + } + + void clear() { + usage_ = 0; + } + + void shrinkToFit(Allocator* allocator) { + auto newSlots = reinterpret_cast( + allocator->reallocate(slots_, slotsToBytes(usage_))); + if (newSlots) { + slots_ = newSlots; + capacity_ = usage_; + } + } + + SlotCount usage() const { + return usage_; + } + + static SlotCount bytesToSlots(size_t n) { + return static_cast(n / sizeof(T)); + } + + static size_t slotsToBytes(SlotCount n) { + return n * sizeof(T); + } private: SlotCount capacity_; SlotCount usage_; - VariantData* slots_; + T* slots_; }; ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/src/ArduinoJson/Memory/MemoryPoolImpl.hpp b/src/ArduinoJson/Memory/MemoryPoolImpl.hpp deleted file mode 100644 index 059ef788..00000000 --- a/src/ArduinoJson/Memory/MemoryPoolImpl.hpp +++ /dev/null @@ -1,81 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright © 2014-2024, Benoit BLANCHON -// MIT License - -#pragma once - -#include -#include - -ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE - -inline void MemoryPool::create(SlotCount cap, Allocator* allocator) { - ARDUINOJSON_ASSERT(cap > 0); - slots_ = - reinterpret_cast(allocator->allocate(slotsToBytes(cap))); - capacity_ = slots_ ? cap : 0; - usage_ = 0; -} - -inline void MemoryPool::destroy(Allocator* allocator) { - if (slots_) - allocator->deallocate(slots_); - slots_ = nullptr; - capacity_ = 0; - usage_ = 0; -} - -inline void MemoryPool::shrinkToFit(Allocator* allocator) { - auto newSlots = reinterpret_cast( - allocator->reallocate(slots_, slotsToBytes(usage_))); - if (newSlots) { - slots_ = newSlots; - capacity_ = usage_; - } -} - -inline SlotWithId MemoryPool::allocSlot() { - if (!slots_) - return {}; - if (usage_ >= capacity_) - return {}; - auto index = usage_++; - auto slot = &slots_[index]; - return {slot, SlotId(index)}; -} - -inline VariantData* MemoryPool::getSlot(SlotId id) const { - ARDUINOJSON_ASSERT(id < usage_); - return &slots_[id]; -} - -inline SlotCount MemoryPool::usage() const { - return usage_; -} - -inline void MemoryPool::clear() { - usage_ = 0; -} - -inline SlotCount MemoryPool::bytesToSlots(size_t n) { - return static_cast(n / sizeof(VariantData)); -} - -inline size_t MemoryPool::slotsToBytes(SlotCount n) { - return n * sizeof(VariantData); -} - -inline SlotWithId MemoryPoolList::allocFromFreeList() { - ARDUINOJSON_ASSERT(freeList_ != NULL_SLOT); - auto id = freeList_; - auto slot = getSlot(freeList_); - freeList_ = reinterpret_cast(slot)->next; - return {slot, id}; -} - -inline void MemoryPoolList::freeSlot(SlotWithId slot) { - reinterpret_cast(slot.ptr())->next = freeList_; - freeList_ = slot.id(); -} - -ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/src/ArduinoJson/Memory/MemoryPoolList.hpp b/src/ArduinoJson/Memory/MemoryPoolList.hpp index 27fe57c4..0aea4992 100644 --- a/src/ArduinoJson/Memory/MemoryPoolList.hpp +++ b/src/ArduinoJson/Memory/MemoryPoolList.hpp @@ -14,12 +14,17 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE using PoolCount = SlotId; +template class MemoryPoolList { struct FreeSlot { SlotId next; }; + static_assert(sizeof(FreeSlot) <= sizeof(T), "T is too small"); + public: + using Pool = MemoryPool; + MemoryPoolList() = default; ~MemoryPoolList() { @@ -74,7 +79,7 @@ class MemoryPoolList { return *this; } - SlotWithId allocSlot(Allocator* allocator) { + SlotWithId allocSlot(Allocator* allocator) { // try to allocate from free list if (freeList_ != NULL_SLOT) { return allocFromFreeList(); @@ -95,9 +100,12 @@ class MemoryPoolList { return allocFromLastPool(); } - void freeSlot(SlotWithId slot); + void freeSlot(SlotWithId slot) { + reinterpret_cast(slot.ptr())->next = freeList_; + freeList_ = slot.id(); + } - VariantData* getSlot(SlotId id) const { + T* getSlot(SlotId id) const { if (id == NULL_SLOT) return nullptr; auto poolIndex = SlotId(id / ARDUINOJSON_POOL_CAPACITY); @@ -125,21 +133,31 @@ class MemoryPoolList { return total; } + size_t size() const { + return Pool::slotsToBytes(usage()); + } + void shrinkToFit(Allocator* allocator) { if (count_ > 0) pools_[count_ - 1].shrinkToFit(allocator); if (pools_ != preallocatedPools_ && count_ != capacity_) { - pools_ = static_cast( - allocator->reallocate(pools_, count_ * sizeof(MemoryPool))); + pools_ = static_cast( + allocator->reallocate(pools_, count_ * sizeof(Pool))); ARDUINOJSON_ASSERT(pools_ != nullptr); // realloc to smaller can't fail capacity_ = count_; } } private: - SlotWithId allocFromFreeList(); + SlotWithId allocFromFreeList() { + ARDUINOJSON_ASSERT(freeList_ != NULL_SLOT); + auto id = freeList_; + auto slot = getSlot(freeList_); + freeList_ = reinterpret_cast(slot)->next; + return {slot, id}; + } - SlotWithId allocFromLastPool() { + SlotWithId allocFromLastPool() { ARDUINOJSON_ASSERT(count_ > 0); auto poolIndex = SlotId(count_ - 1); auto slot = pools_[poolIndex].allocSlot(); @@ -149,7 +167,7 @@ class MemoryPoolList { SlotId(poolIndex * ARDUINOJSON_POOL_CAPACITY + slot.id())}; } - MemoryPool* addPool(Allocator* allocator) { + Pool* addPool(Allocator* allocator) { if (count_ == capacity_ && !increaseCapacity(allocator)) return nullptr; auto pool = &pools_[count_++]; @@ -167,24 +185,23 @@ class MemoryPoolList { auto newCapacity = PoolCount(capacity_ * 2); if (pools_ == preallocatedPools_) { - newPools = allocator->allocate(newCapacity * sizeof(MemoryPool)); + newPools = allocator->allocate(newCapacity * sizeof(Pool)); if (!newPools) return false; memcpy(newPools, preallocatedPools_, sizeof(preallocatedPools_)); } else { - newPools = - allocator->reallocate(pools_, newCapacity * sizeof(MemoryPool)); + newPools = allocator->reallocate(pools_, newCapacity * sizeof(Pool)); if (!newPools) return false; } - pools_ = static_cast(newPools); + pools_ = static_cast(newPools); capacity_ = newCapacity; return true; } - MemoryPool preallocatedPools_[ARDUINOJSON_INITIAL_POOL_COUNT]; - MemoryPool* pools_ = preallocatedPools_; + Pool preallocatedPools_[ARDUINOJSON_INITIAL_POOL_COUNT]; + Pool* pools_ = preallocatedPools_; PoolCount count_ = 0; PoolCount capacity_ = ARDUINOJSON_INITIAL_POOL_COUNT; SlotId freeList_ = NULL_SLOT; diff --git a/src/ArduinoJson/Memory/ResourceManager.hpp b/src/ArduinoJson/Memory/ResourceManager.hpp index 45e329cd..7b23923e 100644 --- a/src/ArduinoJson/Memory/ResourceManager.hpp +++ b/src/ArduinoJson/Memory/ResourceManager.hpp @@ -10,10 +10,10 @@ #include #include #include +#include ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -class MemoryPool; class VariantData; class VariantWithId; @@ -42,16 +42,16 @@ class ResourceManager { } size_t size() const { - return MemoryPool::slotsToBytes(variantPools_.usage()) + stringPool_.size(); + return variantPools_.size() + stringPool_.size(); } bool overflowed() const { return overflowed_; } - VariantWithId allocVariant(); + SlotWithId allocVariant(); - void freeVariant(VariantWithId slot); + void freeVariant(SlotWithId slot); VariantData* getVariant(SlotId id) const; @@ -112,7 +112,7 @@ class ResourceManager { Allocator* allocator_; bool overflowed_; StringPool stringPool_; - MemoryPoolList variantPools_; + MemoryPoolList variantPools_; }; ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/src/ArduinoJson/Memory/ResourceManagerImpl.hpp b/src/ArduinoJson/Memory/ResourceManagerImpl.hpp index 0deb5729..73200f45 100644 --- a/src/ArduinoJson/Memory/ResourceManagerImpl.hpp +++ b/src/ArduinoJson/Memory/ResourceManagerImpl.hpp @@ -10,7 +10,7 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -inline VariantWithId ResourceManager::allocVariant() { +inline SlotWithId ResourceManager::allocVariant() { auto p = variantPools_.allocSlot(allocator_); if (!p) { overflowed_ = true; @@ -19,7 +19,7 @@ inline VariantWithId ResourceManager::allocVariant() { return {new (p.ptr()) VariantData, p.id()}; } -inline void ResourceManager::freeVariant(VariantWithId variant) { +inline void ResourceManager::freeVariant(SlotWithId variant) { variant->setNull(this); variantPools_.freeSlot(variant); } diff --git a/src/ArduinoJson/Memory/StringPool.hpp b/src/ArduinoJson/Memory/StringPool.hpp index 91851e80..6121b290 100644 --- a/src/ArduinoJson/Memory/StringPool.hpp +++ b/src/ArduinoJson/Memory/StringPool.hpp @@ -12,8 +12,6 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -class MemoryPool; - class StringPool { public: StringPool() = default; diff --git a/src/ArduinoJson/Variant/VariantData.hpp b/src/ArduinoJson/Variant/VariantData.hpp index f36fcaf0..86b2adce 100644 --- a/src/ArduinoJson/Variant/VariantData.hpp +++ b/src/ArduinoJson/Variant/VariantData.hpp @@ -408,14 +408,7 @@ class VariantData { } template - void setRawString(SerializedValue value, ResourceManager* resources) { - release(resources); - auto dup = resources->saveString(adaptString(value.data(), value.size())); - if (dup) - setRawString(dup); - else - setNull(); - } + void setRawString(SerializedValue value, ResourceManager* resources); template static void setRawString(VariantData* var, SerializedValue value, @@ -426,25 +419,7 @@ class VariantData { } template - bool setString(TAdaptedString value, ResourceManager* resources) { - setNull(resources); - - if (value.isNull()) - return false; - - if (value.isLinked()) { - setLinkedString(value.data()); - return true; - } - - auto dup = resources->saveString(value); - if (dup) { - setOwnedString(dup); - return true; - } - - return false; - } + bool setString(TAdaptedString value, ResourceManager* resources); bool setString(StringNode* s, ResourceManager*) { setOwnedString(s); @@ -524,30 +499,7 @@ class VariantData { } private: - void release(ResourceManager* resources) { - if (type_ & OWNED_VALUE_BIT) - resources->dereferenceString(content_.asOwnedString->data); - - auto collection = asCollection(); - if (collection) - collection->clear(resources); - } -}; - -class VariantWithId : public SlotWithId { - public: - VariantWithId() {} - VariantWithId(VariantData* data, SlotId id) - : SlotWithId(reinterpret_cast(data), id) {} - - VariantData* ptr() { - return reinterpret_cast(SlotWithId::ptr()); - } - - VariantData* operator->() { - ARDUINOJSON_ASSERT(ptr() != nullptr); - return ptr(); - } + void release(ResourceManager* resources); }; ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/src/ArduinoJson/Variant/VariantImpl.hpp b/src/ArduinoJson/Variant/VariantImpl.hpp new file mode 100644 index 00000000..ae131509 --- /dev/null +++ b/src/ArduinoJson/Variant/VariantImpl.hpp @@ -0,0 +1,54 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2024, Benoit BLANCHON +// MIT License + +#pragma once + +#include +#include + +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE + +template +inline void VariantData::setRawString(SerializedValue value, + ResourceManager* resources) { + release(resources); + auto dup = resources->saveString(adaptString(value.data(), value.size())); + if (dup) + setRawString(dup); + else + setNull(); +} + +template +inline bool VariantData::setString(TAdaptedString value, + ResourceManager* resources) { + setNull(resources); + + if (value.isNull()) + return false; + + if (value.isLinked()) { + setLinkedString(value.data()); + return true; + } + + auto dup = resources->saveString(value); + if (dup) { + setOwnedString(dup); + return true; + } + + return false; +} + +inline void VariantData::release(ResourceManager* resources) { + if (type_ & OWNED_VALUE_BIT) + resources->dereferenceString(content_.asOwnedString->data); + + auto collection = asCollection(); + if (collection) + collection->clear(resources); +} + +ARDUINOJSON_END_PRIVATE_NAMESPACE