diff --git a/extras/tests/MemoryPool/allocVariant.cpp b/extras/tests/MemoryPool/allocVariant.cpp index 32f9d1d6..da44965a 100644 --- a/extras/tests/MemoryPool/allocVariant.cpp +++ b/extras/tests/MemoryPool/allocVariant.cpp @@ -3,19 +3,20 @@ // MIT License #include +#include #include #include "Allocators.hpp" using namespace ArduinoJson::detail; -TEST_CASE("MemoryPool::allocVariant()") { +TEST_CASE("new (pool) VariantSlot()") { SECTION("Returns different pointer") { MemoryPool pool(4096); - VariantSlot* s1 = pool.allocVariant(); + VariantSlot* s1 = new (&pool) VariantSlot(); REQUIRE(s1 != 0); - VariantSlot* s2 = pool.allocVariant(); + VariantSlot* s2 = new (&pool) VariantSlot(); REQUIRE(s2 != 0); REQUIRE(s1 != s2); @@ -24,27 +25,27 @@ TEST_CASE("MemoryPool::allocVariant()") { SECTION("Returns aligned pointers") { MemoryPool pool(4096); - REQUIRE(isAligned(pool.allocVariant())); - REQUIRE(isAligned(pool.allocVariant())); + REQUIRE(isAligned(new (&pool) VariantSlot())); + REQUIRE(isAligned(new (&pool) VariantSlot())); } SECTION("Returns zero if capacity is 0") { MemoryPool pool(0); - REQUIRE(pool.allocVariant() == 0); + REQUIRE(new (&pool) VariantSlot() == 0); } SECTION("Returns zero if buffer is null") { MemoryPool pool(4096, FailingAllocator::instance()); - REQUIRE(pool.allocVariant() == 0); + REQUIRE(new (&pool) VariantSlot() == 0); } SECTION("Returns zero if capacity is insufficient") { MemoryPool pool(sizeof(VariantSlot)); - pool.allocVariant(); + new (&pool) VariantSlot(); - REQUIRE(pool.allocVariant() == 0); + REQUIRE(new (&pool) VariantSlot() == 0); } } diff --git a/extras/tests/MemoryPool/clear.cpp b/extras/tests/MemoryPool/clear.cpp index 45736393..ffe00777 100644 --- a/extras/tests/MemoryPool/clear.cpp +++ b/extras/tests/MemoryPool/clear.cpp @@ -4,6 +4,7 @@ #include #include +#include #include using namespace ArduinoJson::detail; @@ -14,7 +15,7 @@ TEST_CASE("MemoryPool::clear()") { MemoryPool pool(poolCapacity); SECTION("Discards allocated variants") { - pool.allocVariant(); + new (&pool) VariantSlot(); pool.clear(); REQUIRE(pool.size() == 0); diff --git a/extras/tests/MemoryPool/size.cpp b/extras/tests/MemoryPool/size.cpp index 1ac3ebb5..78fcda85 100644 --- a/extras/tests/MemoryPool/size.cpp +++ b/extras/tests/MemoryPool/size.cpp @@ -3,6 +3,7 @@ // MIT License #include +#include #include using namespace ArduinoJson::detail; @@ -24,10 +25,10 @@ TEST_CASE("MemoryPool::size()") { const size_t variantCount = pool.capacity() / sizeof(VariantSlot); for (size_t i = 0; i < variantCount; i++) - pool.allocVariant(); + new (&pool) VariantSlot(); size_t size = pool.size(); - pool.allocVariant(); + new (&pool) VariantSlot(); REQUIRE(size == pool.size()); } diff --git a/src/ArduinoJson/Collection/CollectionFunctions.hpp b/src/ArduinoJson/Collection/CollectionFunctions.hpp index afa81a5a..6af00dd7 100644 --- a/src/ArduinoJson/Collection/CollectionFunctions.hpp +++ b/src/ArduinoJson/Collection/CollectionFunctions.hpp @@ -12,7 +12,7 @@ inline VariantData* collectionAddElement(CollectionData* array, MemoryPool* pool) { if (!array) return nullptr; - auto slot = pool->allocVariant(); + auto slot = new (pool) VariantSlot(); if (!slot) return nullptr; array->add(slot); @@ -24,7 +24,7 @@ inline VariantData* collectionAddMember(CollectionData* obj, TAdaptedString key, MemoryPool* pool) { ARDUINOJSON_ASSERT(!key.isNull()); ARDUINOJSON_ASSERT(obj != nullptr); - auto slot = pool->allocVariant(); + auto slot = new (pool) VariantSlot(); if (!slot) return nullptr; if (key.isLinked()) diff --git a/src/ArduinoJson/Collection/CollectionImpl.hpp b/src/ArduinoJson/Collection/CollectionImpl.hpp index 4011c56a..12ee73d4 100644 --- a/src/ArduinoJson/Collection/CollectionImpl.hpp +++ b/src/ArduinoJson/Collection/CollectionImpl.hpp @@ -96,7 +96,7 @@ inline void CollectionData::movePointers(ptrdiff_t variantDistance) { movePointer(head_, variantDistance); movePointer(tail_, variantDistance); for (VariantSlot* slot = head_; slot; slot = slot->next()) - slot->movePointers(variantDistance); + slot->data()->movePointers(variantDistance); } ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/src/ArduinoJson/Document/JsonDocument.hpp b/src/ArduinoJson/Document/JsonDocument.hpp index e5d5b9af..4e3e3d98 100644 --- a/src/ArduinoJson/Document/JsonDocument.hpp +++ b/src/ArduinoJson/Document/JsonDocument.hpp @@ -86,7 +86,8 @@ class JsonDocument : public detail::VariantOperators { // Reduces the capacity of the memory pool to match the current usage. // https://arduinojson.org/v6/api/JsonDocument/shrinktofit/ void shrinkToFit() { - pool_.shrinkToFit(data_); + auto offset = pool_.shrinkToFit(); + data_.movePointers(offset); } // Reclaims the memory leaked when removing and replacing values. diff --git a/src/ArduinoJson/Json/JsonDeserializer.hpp b/src/ArduinoJson/Json/JsonDeserializer.hpp index b1d1a19f..5e406c1b 100644 --- a/src/ArduinoJson/Json/JsonDeserializer.hpp +++ b/src/ArduinoJson/Json/JsonDeserializer.hpp @@ -279,7 +279,7 @@ class JsonDeserializer { auto savedKey = stringBuilder_.save(); // Allocate slot in object - slot = pool_->allocVariant(); + slot = new (pool_) VariantSlot(); if (!slot) return DeserializationError::NoMemory; diff --git a/src/ArduinoJson/Memory/MemoryPool.hpp b/src/ArduinoJson/Memory/MemoryPool.hpp index 2324e1ba..e5c9df3d 100644 --- a/src/ArduinoJson/Memory/MemoryPool.hpp +++ b/src/ArduinoJson/Memory/MemoryPool.hpp @@ -10,22 +10,11 @@ #include #include #include -#include #include // memmove ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -// Returns the size (in bytes) of an array with n elements. -constexpr size_t sizeofArray(size_t n) { - return n * sizeof(VariantSlot); -} - -// Returns the size (in bytes) of an object with n members. -constexpr size_t sizeofObject(size_t n) { - return n * sizeof(VariantSlot); -} - class MemoryPool { public: MemoryPool(size_t capa, Allocator* allocator = DefaultAllocator::instance()) @@ -88,11 +77,13 @@ class MemoryPool { return overflowed_; } - VariantSlot* allocVariant() { - auto slot = allocRight(); - if (slot) - slot->clear(); - return slot; + void* allocFromPool(size_t bytes) { + if (!canAlloc(bytes)) { + overflowed_ = true; + return 0; + } + right_ -= bytes; + return right_; } template @@ -198,10 +189,10 @@ class MemoryPool { return p; } - void shrinkToFit(VariantData& variant) { + ptrdiff_t shrinkToFit() { ptrdiff_t bytes_reclaimed = squash(); if (bytes_reclaimed == 0) - return; + return 0; void* old_ptr = begin_; void* new_ptr = allocator_->reallocate(old_ptr, capacity()); @@ -210,8 +201,7 @@ class MemoryPool { static_cast(new_ptr) - static_cast(old_ptr); movePointers(ptr_offset); - reinterpret_cast(variant).movePointers(ptr_offset - - bytes_reclaimed); + return ptr_offset - bytes_reclaimed; } private: @@ -251,20 +241,6 @@ class MemoryPool { } } - template - T* allocRight() { - return reinterpret_cast(allocRight(sizeof(T))); - } - - void* allocRight(size_t bytes) { - if (!canAlloc(bytes)) { - overflowed_ = true; - return 0; - } - right_ -= bytes; - return right_; - } - void allocPool(size_t capa) { auto buf = capa ? reinterpret_cast(allocator_->allocate(capa)) : 0; begin_ = buf; diff --git a/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp b/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp index a9b19d37..7c4ece52 100644 --- a/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp +++ b/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp @@ -495,7 +495,7 @@ class MsgPackDeserializer { // Save key in memory pool. auto savedKey = stringBuilder_.save(); - VariantSlot* slot = pool_->allocVariant(); + VariantSlot* slot = new (pool_) VariantSlot(); if (!slot) return DeserializationError::NoMemory; diff --git a/src/ArduinoJson/Variant/VariantAttorney.hpp b/src/ArduinoJson/Variant/VariantAttorney.hpp index a2f6815f..cfaa868e 100644 --- a/src/ArduinoJson/Variant/VariantAttorney.hpp +++ b/src/ArduinoJson/Variant/VariantAttorney.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include "JsonVariantConst.hpp" diff --git a/src/ArduinoJson/Variant/VariantData.hpp b/src/ArduinoJson/Variant/VariantData.hpp index 830656c9..e2f37a4e 100644 --- a/src/ArduinoJson/Variant/VariantData.hpp +++ b/src/ArduinoJson/Variant/VariantData.hpp @@ -10,6 +10,7 @@ #include #include #include +#include ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE diff --git a/src/ArduinoJson/Variant/VariantFunctions.hpp b/src/ArduinoJson/Variant/VariantFunctions.hpp index 210a03fe..ef74096a 100644 --- a/src/ArduinoJson/Variant/VariantFunctions.hpp +++ b/src/ArduinoJson/Variant/VariantFunctions.hpp @@ -190,7 +190,7 @@ inline NO_INLINE VariantData* variantGetOrAddElement(VariantData* var, if (!slot) index++; while (index > 0) { - slot = pool->allocVariant(); + slot = new (pool) VariantSlot(); if (!slot) return nullptr; array->add(slot); diff --git a/src/ArduinoJson/Variant/VariantSlot.hpp b/src/ArduinoJson/Variant/VariantSlot.hpp index 90d5028e..291637ad 100644 --- a/src/ArduinoJson/Variant/VariantSlot.hpp +++ b/src/ArduinoJson/Variant/VariantSlot.hpp @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include @@ -25,11 +26,15 @@ class VariantSlot { const char* key_; public: - // Must be a POD! - // - no constructor - // - no destructor - // - no virtual - // - no inheritance + static void* operator new(size_t size, MemoryPool* pool) noexcept { + return pool->allocFromPool(size); + } + + static void operator delete(void*, MemoryPool*) noexcept { + // we cannot release memory from the pool + } + + VariantSlot() : flags_(0), next_(0), key_(0) {} VariantData* data() { return reinterpret_cast(&content_); @@ -93,21 +98,20 @@ class VariantSlot { bool ownsKey() const { return (flags_ & OWNED_KEY_BIT) != 0; } - - void clear() { - next_ = 0; - flags_ = 0; - key_ = 0; - } - - void movePointers(ptrdiff_t variantDistance) { - if (flags_ & COLLECTION_MASK) - content_.asCollection.movePointers(variantDistance); - } }; inline VariantData* slotData(VariantSlot* slot) { return reinterpret_cast(slot); } +// Returns the size (in bytes) of an array with n elements. +constexpr size_t sizeofArray(size_t n) { + return n * sizeof(VariantSlot); +} + +// Returns the size (in bytes) of an object with n members. +constexpr size_t sizeofObject(size_t n) { + return n * sizeof(VariantSlot); +} + ARDUINOJSON_END_PRIVATE_NAMESPACE