From 0f511b873de50f6ca39cf8bb33150132933fdf94 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Mon, 3 Jul 2023 09:23:18 +0200 Subject: [PATCH] VariantPool: store `VariantSlot`s instead of `char`s --- extras/tests/JsonDocument/assignment.cpp | 14 +++---- extras/tests/JsonDocument/constructor.cpp | 13 +++--- extras/tests/ResourceManager/allocVariant.cpp | 1 + src/ArduinoJson/Collection/CollectionImpl.hpp | 1 + src/ArduinoJson/Memory/ResourceManager.hpp | 11 +++-- src/ArduinoJson/Memory/VariantPool.hpp | 11 ++--- src/ArduinoJson/Memory/VariantPoolImpl.hpp | 40 +++++++++++-------- 7 files changed, 51 insertions(+), 40 deletions(-) diff --git a/extras/tests/JsonDocument/assignment.cpp b/extras/tests/JsonDocument/assignment.cpp index f3b440ed..e374a6c9 100644 --- a/extras/tests/JsonDocument/assignment.cpp +++ b/extras/tests/JsonDocument/assignment.cpp @@ -32,15 +32,15 @@ TEST_CASE("JsonDocument assignment") { SECTION("Copy assignment reallocates when capacity is smaller") { JsonDocument doc1(4096, &spyingAllocator); - deserializeJson(doc1, "{\"hello\":\"world\"}"); - JsonDocument doc2(8, &spyingAllocator); + deserializeJson(doc1, "[{\"hello\":\"world\"}]"); + JsonDocument doc2(sizeofArray(1), &spyingAllocator); spyingAllocator.clearLog(); doc2 = doc1; - REQUIRE(doc2.as() == "{\"hello\":\"world\"}"); + REQUIRE(doc2.as() == "[{\"hello\":\"world\"}]"); REQUIRE(spyingAllocator.log() == - AllocatorLog() << AllocatorLog::Deallocate(8) + AllocatorLog() << AllocatorLog::Deallocate(sizeofArray(1)) << AllocatorLog::Allocate(4096) << AllocatorLog::Allocate(sizeofString(5)) // hello << AllocatorLog::Allocate(sizeofString(5)) // world @@ -68,7 +68,7 @@ TEST_CASE("JsonDocument assignment") { { JsonDocument doc1(4096, &spyingAllocator); doc1.set(std::string("The size of this string is 32!!")); - JsonDocument doc2(8, &spyingAllocator); + JsonDocument doc2(128, &spyingAllocator); doc2 = std::move(doc1); @@ -78,8 +78,8 @@ TEST_CASE("JsonDocument assignment") { REQUIRE(spyingAllocator.log() == AllocatorLog() << AllocatorLog::Allocate(4096) << AllocatorLog::Allocate(sizeofString(31)) - << AllocatorLog::Allocate(8) - << AllocatorLog::Deallocate(8) + << AllocatorLog::Allocate(128) + << AllocatorLog::Deallocate(128) << AllocatorLog::Deallocate(sizeofString(31)) << AllocatorLog::Deallocate(4096)); } diff --git a/extras/tests/JsonDocument/constructor.cpp b/extras/tests/JsonDocument/constructor.cpp index 841ed952..5e733bd7 100644 --- a/extras/tests/JsonDocument/constructor.cpp +++ b/extras/tests/JsonDocument/constructor.cpp @@ -8,6 +8,7 @@ #include "Allocators.hpp" using ArduinoJson::detail::addPadding; +using ArduinoJson::detail::sizeofObject; using ArduinoJson::detail::sizeofString; TEST_CASE("JsonDocument constructor") { @@ -66,8 +67,8 @@ TEST_CASE("JsonDocument constructor") { JsonDocument doc2(obj, &spyingAllocator); REQUIRE(doc2.as() == "{\"hello\":\"world\"}"); - REQUIRE(spyingAllocator.log() == AllocatorLog() << AllocatorLog::Allocate( - addPadding(doc1.memoryUsage()))); + REQUIRE(spyingAllocator.log() == + AllocatorLog() << AllocatorLog::Allocate(sizeofObject(1))); } SECTION("Construct from JsonArray") { @@ -89,9 +90,9 @@ TEST_CASE("JsonDocument constructor") { JsonDocument doc2(doc1.as(), &spyingAllocator); REQUIRE(doc2.as() == "hello"); - REQUIRE( - spyingAllocator.log() == - AllocatorLog() << AllocatorLog::Allocate(addPadding(doc1.memoryUsage())) - << AllocatorLog::Allocate(sizeofString(5))); + REQUIRE(spyingAllocator.log() == + AllocatorLog() << AllocatorLog::Allocate( + sizeofString(5)) // TODO: remove + << AllocatorLog::Allocate(sizeofString(5))); } } diff --git a/extras/tests/ResourceManager/allocVariant.cpp b/extras/tests/ResourceManager/allocVariant.cpp index 9d2d6feb..3a87badc 100644 --- a/extras/tests/ResourceManager/allocVariant.cpp +++ b/extras/tests/ResourceManager/allocVariant.cpp @@ -2,6 +2,7 @@ // Copyright © 2014-2023, Benoit BLANCHON // MIT License +#include #include #include #include diff --git a/src/ArduinoJson/Collection/CollectionImpl.hpp b/src/ArduinoJson/Collection/CollectionImpl.hpp index 19d923d3..5c462ac7 100644 --- a/src/ArduinoJson/Collection/CollectionImpl.hpp +++ b/src/ArduinoJson/Collection/CollectionImpl.hpp @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include #include diff --git a/src/ArduinoJson/Memory/ResourceManager.hpp b/src/ArduinoJson/Memory/ResourceManager.hpp index f3a4942d..66b2297e 100644 --- a/src/ArduinoJson/Memory/ResourceManager.hpp +++ b/src/ArduinoJson/Memory/ResourceManager.hpp @@ -4,7 +4,6 @@ #pragma once -#include #include #include #include @@ -22,7 +21,7 @@ class ResourceManager { ResourceManager(size_t capa, Allocator* allocator = DefaultAllocator::instance()) : allocator_(allocator), overflowed_(false) { - variantPool_.create(addPadding(capa), allocator); + variantPool_.create(capa, allocator); } ~ResourceManager() { @@ -48,8 +47,8 @@ class ResourceManager { } void reallocPool(size_t requiredSize) { - size_t capa = addPadding(requiredSize); - if (capa == capacity()) + size_t capa = VariantPool::bytesToSlots(requiredSize); + if (capa == variantPool_.capacity()) return; variantPool_.destroy(allocator_); variantPool_.create(requiredSize, allocator_); @@ -57,11 +56,11 @@ class ResourceManager { // Gets the capacity of the memoryPool in bytes size_t capacity() const { - return variantPool_.capacity(); + return VariantPool::slotsToBytes(variantPool_.capacity()); } size_t size() const { - return variantPool_.usage() + stringPool_.size(); + return VariantPool::slotsToBytes(variantPool_.usage()) + stringPool_.size(); } bool overflowed() const { diff --git a/src/ArduinoJson/Memory/VariantPool.hpp b/src/ArduinoJson/Memory/VariantPool.hpp index a17ec329..3588d1cf 100644 --- a/src/ArduinoJson/Memory/VariantPool.hpp +++ b/src/ArduinoJson/Memory/VariantPool.hpp @@ -14,7 +14,7 @@ class VariantSlot; class VariantPool { public: ~VariantPool() { - ARDUINOJSON_ASSERT(data_ == nullptr); + ARDUINOJSON_ASSERT(slots_ == nullptr); } VariantPool& operator=(VariantPool&& src) { @@ -22,8 +22,8 @@ class VariantPool { src.capacity_ = 0; usage_ = src.usage_; src.usage_ = 0; - data_ = src.data_; - src.data_ = nullptr; + slots_ = src.slots_; + src.slots_ = nullptr; return *this; } @@ -36,12 +36,13 @@ class VariantPool { size_t capacity() const; size_t usage() const; - static size_t sizeForCapacity(size_t); + static size_t bytesToSlots(size_t); + static size_t slotsToBytes(size_t); private: size_t capacity_ = 0; size_t usage_ = 0; - char* data_ = nullptr; + VariantSlot* slots_ = nullptr; }; ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/src/ArduinoJson/Memory/VariantPoolImpl.hpp b/src/ArduinoJson/Memory/VariantPoolImpl.hpp index dc575e6a..357646a9 100644 --- a/src/ArduinoJson/Memory/VariantPoolImpl.hpp +++ b/src/ArduinoJson/Memory/VariantPoolImpl.hpp @@ -10,40 +10,40 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE inline void VariantPool::create(size_t cap, Allocator* allocator) { - ARDUINOJSON_ASSERT(data_ == nullptr); + ARDUINOJSON_ASSERT(slots_ == nullptr); if (!cap) return; - data_ = reinterpret_cast(allocator->allocate(cap)); - if (data_) { - capacity_ = cap; + slots_ = reinterpret_cast(allocator->allocate(cap)); + if (slots_) { + capacity_ = bytesToSlots(cap); usage_ = 0; } } inline void VariantPool::destroy(Allocator* allocator) { - if (data_) - allocator->deallocate(data_); - data_ = nullptr; + if (slots_) + allocator->deallocate(slots_); + slots_ = nullptr; capacity_ = 0; usage_ = 0; } inline ptrdiff_t VariantPool::shrinkToFit(Allocator* allocator) { - auto originalPool = data_; - data_ = reinterpret_cast(allocator->reallocate(data_, usage_)); - if (data_) + auto originalPool = slots_; + slots_ = reinterpret_cast( + allocator->reallocate(slots_, slotsToBytes(usage_))); + if (slots_) capacity_ = usage_; - return data_ - originalPool; + return reinterpret_cast(slots_) - + reinterpret_cast(originalPool); } inline VariantSlot* VariantPool::allocVariant() { - if (!data_) + if (!slots_) return nullptr; - if (usage_ + sizeof(VariantSlot) > capacity_) + if (usage_ + 1 > capacity_) return nullptr; - auto p = data_ + usage_; - usage_ += sizeof(VariantSlot); - return new (p) VariantSlot; + return new (&slots_[usage_++]) VariantSlot; } inline size_t VariantPool::usage() const { @@ -58,4 +58,12 @@ inline void VariantPool::clear() { usage_ = 0; } +inline size_t VariantPool::bytesToSlots(size_t n) { + return n / sizeof(VariantSlot); +} + +inline size_t VariantPool::slotsToBytes(size_t n) { + return n * sizeof(VariantSlot); +} + ARDUINOJSON_END_PRIVATE_NAMESPACE