VariantPool: store VariantSlots instead of chars

This commit is contained in:
Benoit Blanchon
2023-07-03 09:23:18 +02:00
parent 1d96826371
commit 0f511b873d
7 changed files with 51 additions and 40 deletions

View File

@ -32,15 +32,15 @@ TEST_CASE("JsonDocument assignment") {
SECTION("Copy assignment reallocates when capacity is smaller") { SECTION("Copy assignment reallocates when capacity is smaller") {
JsonDocument doc1(4096, &spyingAllocator); JsonDocument doc1(4096, &spyingAllocator);
deserializeJson(doc1, "{\"hello\":\"world\"}"); deserializeJson(doc1, "[{\"hello\":\"world\"}]");
JsonDocument doc2(8, &spyingAllocator); JsonDocument doc2(sizeofArray(1), &spyingAllocator);
spyingAllocator.clearLog(); spyingAllocator.clearLog();
doc2 = doc1; doc2 = doc1;
REQUIRE(doc2.as<std::string>() == "{\"hello\":\"world\"}"); REQUIRE(doc2.as<std::string>() == "[{\"hello\":\"world\"}]");
REQUIRE(spyingAllocator.log() == REQUIRE(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::Deallocate(8) AllocatorLog() << AllocatorLog::Deallocate(sizeofArray(1))
<< AllocatorLog::Allocate(4096) << AllocatorLog::Allocate(4096)
<< AllocatorLog::Allocate(sizeofString(5)) // hello << AllocatorLog::Allocate(sizeofString(5)) // hello
<< AllocatorLog::Allocate(sizeofString(5)) // world << AllocatorLog::Allocate(sizeofString(5)) // world
@ -68,7 +68,7 @@ TEST_CASE("JsonDocument assignment") {
{ {
JsonDocument doc1(4096, &spyingAllocator); JsonDocument doc1(4096, &spyingAllocator);
doc1.set(std::string("The size of this string is 32!!")); doc1.set(std::string("The size of this string is 32!!"));
JsonDocument doc2(8, &spyingAllocator); JsonDocument doc2(128, &spyingAllocator);
doc2 = std::move(doc1); doc2 = std::move(doc1);
@ -78,8 +78,8 @@ TEST_CASE("JsonDocument assignment") {
REQUIRE(spyingAllocator.log() == REQUIRE(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::Allocate(4096) AllocatorLog() << AllocatorLog::Allocate(4096)
<< AllocatorLog::Allocate(sizeofString(31)) << AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::Allocate(8) << AllocatorLog::Allocate(128)
<< AllocatorLog::Deallocate(8) << AllocatorLog::Deallocate(128)
<< AllocatorLog::Deallocate(sizeofString(31)) << AllocatorLog::Deallocate(sizeofString(31))
<< AllocatorLog::Deallocate(4096)); << AllocatorLog::Deallocate(4096));
} }

View File

@ -8,6 +8,7 @@
#include "Allocators.hpp" #include "Allocators.hpp"
using ArduinoJson::detail::addPadding; using ArduinoJson::detail::addPadding;
using ArduinoJson::detail::sizeofObject;
using ArduinoJson::detail::sizeofString; using ArduinoJson::detail::sizeofString;
TEST_CASE("JsonDocument constructor") { TEST_CASE("JsonDocument constructor") {
@ -66,8 +67,8 @@ TEST_CASE("JsonDocument constructor") {
JsonDocument doc2(obj, &spyingAllocator); JsonDocument doc2(obj, &spyingAllocator);
REQUIRE(doc2.as<std::string>() == "{\"hello\":\"world\"}"); REQUIRE(doc2.as<std::string>() == "{\"hello\":\"world\"}");
REQUIRE(spyingAllocator.log() == AllocatorLog() << AllocatorLog::Allocate( REQUIRE(spyingAllocator.log() ==
addPadding(doc1.memoryUsage()))); AllocatorLog() << AllocatorLog::Allocate(sizeofObject(1)));
} }
SECTION("Construct from JsonArray") { SECTION("Construct from JsonArray") {
@ -89,9 +90,9 @@ TEST_CASE("JsonDocument constructor") {
JsonDocument doc2(doc1.as<JsonVariant>(), &spyingAllocator); JsonDocument doc2(doc1.as<JsonVariant>(), &spyingAllocator);
REQUIRE(doc2.as<std::string>() == "hello"); REQUIRE(doc2.as<std::string>() == "hello");
REQUIRE( REQUIRE(spyingAllocator.log() ==
spyingAllocator.log() == AllocatorLog() << AllocatorLog::Allocate(
AllocatorLog() << AllocatorLog::Allocate(addPadding(doc1.memoryUsage())) sizeofString(5)) // TODO: remove
<< AllocatorLog::Allocate(sizeofString(5))); << AllocatorLog::Allocate(sizeofString(5)));
} }
} }

View File

@ -2,6 +2,7 @@
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2023, Benoit BLANCHON
// MIT License // MIT License
#include <ArduinoJson/Memory/Alignment.hpp>
#include <ArduinoJson/Memory/ResourceManager.hpp> #include <ArduinoJson/Memory/ResourceManager.hpp>
#include <ArduinoJson/Memory/VariantPoolImpl.hpp> #include <ArduinoJson/Memory/VariantPoolImpl.hpp>
#include <catch.hpp> #include <catch.hpp>

View File

@ -5,6 +5,7 @@
#pragma once #pragma once
#include <ArduinoJson/Collection/CollectionData.hpp> #include <ArduinoJson/Collection/CollectionData.hpp>
#include <ArduinoJson/Memory/Alignment.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp> #include <ArduinoJson/Strings/StringAdapters.hpp>
#include <ArduinoJson/Variant/VariantCompare.hpp> #include <ArduinoJson/Variant/VariantCompare.hpp>
#include <ArduinoJson/Variant/VariantData.hpp> #include <ArduinoJson/Variant/VariantData.hpp>

View File

@ -4,7 +4,6 @@
#pragma once #pragma once
#include <ArduinoJson/Memory/Alignment.hpp>
#include <ArduinoJson/Memory/Allocator.hpp> #include <ArduinoJson/Memory/Allocator.hpp>
#include <ArduinoJson/Memory/StringPool.hpp> #include <ArduinoJson/Memory/StringPool.hpp>
#include <ArduinoJson/Memory/VariantPool.hpp> #include <ArduinoJson/Memory/VariantPool.hpp>
@ -22,7 +21,7 @@ class ResourceManager {
ResourceManager(size_t capa, ResourceManager(size_t capa,
Allocator* allocator = DefaultAllocator::instance()) Allocator* allocator = DefaultAllocator::instance())
: allocator_(allocator), overflowed_(false) { : allocator_(allocator), overflowed_(false) {
variantPool_.create(addPadding(capa), allocator); variantPool_.create(capa, allocator);
} }
~ResourceManager() { ~ResourceManager() {
@ -48,8 +47,8 @@ class ResourceManager {
} }
void reallocPool(size_t requiredSize) { void reallocPool(size_t requiredSize) {
size_t capa = addPadding(requiredSize); size_t capa = VariantPool::bytesToSlots(requiredSize);
if (capa == capacity()) if (capa == variantPool_.capacity())
return; return;
variantPool_.destroy(allocator_); variantPool_.destroy(allocator_);
variantPool_.create(requiredSize, allocator_); variantPool_.create(requiredSize, allocator_);
@ -57,11 +56,11 @@ class ResourceManager {
// Gets the capacity of the memoryPool in bytes // Gets the capacity of the memoryPool in bytes
size_t capacity() const { size_t capacity() const {
return variantPool_.capacity(); return VariantPool::slotsToBytes(variantPool_.capacity());
} }
size_t size() const { size_t size() const {
return variantPool_.usage() + stringPool_.size(); return VariantPool::slotsToBytes(variantPool_.usage()) + stringPool_.size();
} }
bool overflowed() const { bool overflowed() const {

View File

@ -14,7 +14,7 @@ class VariantSlot;
class VariantPool { class VariantPool {
public: public:
~VariantPool() { ~VariantPool() {
ARDUINOJSON_ASSERT(data_ == nullptr); ARDUINOJSON_ASSERT(slots_ == nullptr);
} }
VariantPool& operator=(VariantPool&& src) { VariantPool& operator=(VariantPool&& src) {
@ -22,8 +22,8 @@ class VariantPool {
src.capacity_ = 0; src.capacity_ = 0;
usage_ = src.usage_; usage_ = src.usage_;
src.usage_ = 0; src.usage_ = 0;
data_ = src.data_; slots_ = src.slots_;
src.data_ = nullptr; src.slots_ = nullptr;
return *this; return *this;
} }
@ -36,12 +36,13 @@ class VariantPool {
size_t capacity() const; size_t capacity() const;
size_t usage() const; size_t usage() const;
static size_t sizeForCapacity(size_t); static size_t bytesToSlots(size_t);
static size_t slotsToBytes(size_t);
private: private:
size_t capacity_ = 0; size_t capacity_ = 0;
size_t usage_ = 0; size_t usage_ = 0;
char* data_ = nullptr; VariantSlot* slots_ = nullptr;
}; };
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -10,40 +10,40 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
inline void VariantPool::create(size_t cap, Allocator* allocator) { inline void VariantPool::create(size_t cap, Allocator* allocator) {
ARDUINOJSON_ASSERT(data_ == nullptr); ARDUINOJSON_ASSERT(slots_ == nullptr);
if (!cap) if (!cap)
return; return;
data_ = reinterpret_cast<char*>(allocator->allocate(cap)); slots_ = reinterpret_cast<VariantSlot*>(allocator->allocate(cap));
if (data_) { if (slots_) {
capacity_ = cap; capacity_ = bytesToSlots(cap);
usage_ = 0; usage_ = 0;
} }
} }
inline void VariantPool::destroy(Allocator* allocator) { inline void VariantPool::destroy(Allocator* allocator) {
if (data_) if (slots_)
allocator->deallocate(data_); allocator->deallocate(slots_);
data_ = nullptr; slots_ = nullptr;
capacity_ = 0; capacity_ = 0;
usage_ = 0; usage_ = 0;
} }
inline ptrdiff_t VariantPool::shrinkToFit(Allocator* allocator) { inline ptrdiff_t VariantPool::shrinkToFit(Allocator* allocator) {
auto originalPool = data_; auto originalPool = slots_;
data_ = reinterpret_cast<char*>(allocator->reallocate(data_, usage_)); slots_ = reinterpret_cast<VariantSlot*>(
if (data_) allocator->reallocate(slots_, slotsToBytes(usage_)));
if (slots_)
capacity_ = usage_; capacity_ = usage_;
return data_ - originalPool; return reinterpret_cast<char*>(slots_) -
reinterpret_cast<char*>(originalPool);
} }
inline VariantSlot* VariantPool::allocVariant() { inline VariantSlot* VariantPool::allocVariant() {
if (!data_) if (!slots_)
return nullptr; return nullptr;
if (usage_ + sizeof(VariantSlot) > capacity_) if (usage_ + 1 > capacity_)
return nullptr; return nullptr;
auto p = data_ + usage_; return new (&slots_[usage_++]) VariantSlot;
usage_ += sizeof(VariantSlot);
return new (p) VariantSlot;
} }
inline size_t VariantPool::usage() const { inline size_t VariantPool::usage() const {
@ -58,4 +58,12 @@ inline void VariantPool::clear() {
usage_ = 0; 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 ARDUINOJSON_END_PRIVATE_NAMESPACE