Kaynağa Gözat

VariantPool: store `VariantSlot`s instead of `char`s

Benoit Blanchon 2 yıl önce
ebeveyn
işleme
0f511b873d

+ 7 - 7
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<std::string>() == "{\"hello\":\"world\"}");
+    REQUIRE(doc2.as<std::string>() == "[{\"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));
   }

+ 7 - 6
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<std::string>() == "{\"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<JsonVariant>(), &spyingAllocator);
 
     REQUIRE(doc2.as<std::string>() == "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)));
   }
 }

+ 1 - 0
extras/tests/ResourceManager/allocVariant.cpp

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

+ 1 - 0
src/ArduinoJson/Collection/CollectionImpl.hpp

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

+ 5 - 6
src/ArduinoJson/Memory/ResourceManager.hpp

@@ -4,7 +4,6 @@
 
 #pragma once
 
-#include <ArduinoJson/Memory/Alignment.hpp>
 #include <ArduinoJson/Memory/Allocator.hpp>
 #include <ArduinoJson/Memory/StringPool.hpp>
 #include <ArduinoJson/Memory/VariantPool.hpp>
@@ -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 {

+ 6 - 5
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

+ 24 - 16
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<char*>(allocator->allocate(cap));
-  if (data_) {
-    capacity_ = cap;
+  slots_ = reinterpret_cast<VariantSlot*>(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<char*>(allocator->reallocate(data_, usage_));
-  if (data_)
+  auto originalPool = slots_;
+  slots_ = reinterpret_cast<VariantSlot*>(
+      allocator->reallocate(slots_, slotsToBytes(usage_)));
+  if (slots_)
     capacity_ = usage_;
-  return data_ - originalPool;
+  return reinterpret_cast<char*>(slots_) -
+         reinterpret_cast<char*>(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