瀏覽代碼

Remove `memoryUsage()`

Benoit Blanchon 2 年之前
父節點
當前提交
00c9d8680a
共有 43 個文件被更改,包括 823 次插入536 次删除
  1. 1 0
      CHANGELOG.md
  2. 9 10
      extras/tests/Cpp17/string_view.cpp
  3. 8 0
      extras/tests/Helpers/Allocators.hpp
  4. 0 1
      extras/tests/JsonArray/CMakeLists.txt
  5. 24 15
      extras/tests/JsonArray/add.cpp
  6. 0 46
      extras/tests/JsonArray/memoryUsage.cpp
  7. 12 7
      extras/tests/JsonArray/subscript.cpp
  8. 16 8
      extras/tests/JsonDeserializer/array.cpp
  9. 7 2
      extras/tests/JsonDeserializer/filter.cpp
  10. 12 2
      extras/tests/JsonDeserializer/input_types.cpp
  11. 7 2
      extras/tests/JsonDeserializer/misc.cpp
  12. 39 4
      extras/tests/JsonDeserializer/object.cpp
  13. 27 6
      extras/tests/JsonDeserializer/string.cpp
  14. 0 1
      extras/tests/JsonDocument/CMakeLists.txt
  15. 0 15
      extras/tests/JsonDocument/ElementProxy.cpp
  16. 22 29
      extras/tests/JsonDocument/MemberProxy.cpp
  17. 20 5
      extras/tests/JsonDocument/add.cpp
  18. 0 4
      extras/tests/JsonDocument/garbageCollect.cpp
  19. 0 52
      extras/tests/JsonDocument/memoryUsage.cpp
  20. 0 1
      extras/tests/JsonObject/CMakeLists.txt
  21. 30 12
      extras/tests/JsonObject/copy.cpp
  22. 0 47
      extras/tests/JsonObject/memoryUsage.cpp
  23. 0 24
      extras/tests/JsonObject/std_string.cpp
  24. 31 19
      extras/tests/JsonObject/subscript.cpp
  25. 0 1
      extras/tests/JsonSerializer/std_string.cpp
  26. 0 1
      extras/tests/JsonVariant/CMakeLists.txt
  27. 8 4
      extras/tests/JsonVariant/clear.cpp
  28. 0 16
      extras/tests/JsonVariant/copy.cpp
  29. 0 45
      extras/tests/JsonVariant/memoryUsage.cpp
  30. 16 7
      extras/tests/JsonVariant/remove.cpp
  31. 14 7
      extras/tests/JsonVariant/set.cpp
  32. 19 11
      extras/tests/Misc/printable.cpp
  33. 501 64
      extras/tests/MsgPackDeserializer/filter.cpp
  34. 0 6
      src/ArduinoJson/Array/JsonArray.hpp
  35. 0 6
      src/ArduinoJson/Array/JsonArrayConst.hpp
  36. 0 1
      src/ArduinoJson/Collection/CollectionData.hpp
  37. 0 11
      src/ArduinoJson/Collection/CollectionImpl.hpp
  38. 0 6
      src/ArduinoJson/Document/JsonDocument.hpp
  39. 0 6
      src/ArduinoJson/Object/JsonObject.hpp
  40. 0 6
      src/ArduinoJson/Object/JsonObjectConst.hpp
  41. 0 6
      src/ArduinoJson/Variant/JsonVariantConst.hpp
  42. 0 13
      src/ArduinoJson/Variant/VariantData.hpp
  43. 0 7
      src/ArduinoJson/Variant/VariantRefBase.hpp

+ 1 - 0
CHANGELOG.md

@@ -22,3 +22,4 @@ HEAD
 * `JsonDocument`'s capacity grows as needed, no need to pass it to the constructor anymore
 * `JsonDocument`'s allocator is not monotonic anymore, removed values get recycled
 * Show a link to the documentation when user passes an unsupported input type
+* Remove `JsonDocument::memoryUsage()`

+ 9 - 10
extras/tests/Cpp17/string_view.cpp

@@ -3,6 +3,8 @@
 
 #include <string_view>
 
+#include "Allocators.hpp"
+
 #if !ARDUINOJSON_ENABLE_STRING_VIEW
 #  error ARDUINOJSON_ENABLE_STRING_VIEW must be set to 1
 #endif
@@ -11,7 +13,8 @@ using ArduinoJson::detail::sizeofArray;
 using ArduinoJson::detail::sizeofString;
 
 TEST_CASE("string_view") {
-  JsonDocument doc;
+  SpyingAllocator allocator;
+  JsonDocument doc(&allocator);
   JsonVariant variant = doc.to<JsonVariant>();
 
   SECTION("deserializeJson()") {
@@ -56,18 +59,14 @@ TEST_CASE("string_view") {
 
   SECTION("String deduplication") {
     doc.add(std::string_view("example one", 7));
-    REQUIRE(doc.memoryUsage() == sizeofArray(1) + sizeofString(7));
-
     doc.add(std::string_view("example two", 7));
-    REQUIRE(doc.memoryUsage() == sizeofArray(2) + sizeofString(7));
-
     doc.add(std::string_view("example\0tree", 12));
-    REQUIRE(doc.memoryUsage() ==
-            sizeofArray(3) + sizeofString(7) + sizeofString(12));
-
     doc.add(std::string_view("example\0tree and a half", 12));
-    REQUIRE(doc.memoryUsage() ==
-            sizeofArray(4) + sizeofString(7) + sizeofString(12));
+
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(7))
+                                   << AllocatorLog::Allocate(sizeofString(12)));
   }
 
   SECTION("as<std::string_view>()") {

+ 8 - 0
extras/tests/Helpers/Allocators.hpp

@@ -117,11 +117,16 @@ class SpyingAllocator : public ArduinoJson::Allocator {
       : upstream_(upstream) {}
   virtual ~SpyingAllocator() {}
 
+  size_t allocatedBytes() const {
+    return allocatedBytes_;
+  }
+
   void* allocate(size_t n) override {
     auto block = reinterpret_cast<AllocatedBlock*>(
         upstream_->allocate(sizeof(AllocatedBlock) + n - 1));
     if (block) {
       log_ << AllocatorLog::Allocate(n);
+      allocatedBytes_ += n;
       block->size = n;
       return block->payload;
     } else {
@@ -132,6 +137,7 @@ class SpyingAllocator : public ArduinoJson::Allocator {
 
   void deallocate(void* p) override {
     auto block = AllocatedBlock::fromPayload(p);
+    allocatedBytes_ -= block->size;
     log_ << AllocatorLog::Deallocate(block ? block->size : 0);
     upstream_->deallocate(block);
   }
@@ -144,6 +150,7 @@ class SpyingAllocator : public ArduinoJson::Allocator {
     if (block) {
       log_ << AllocatorLog::Reallocate(oldSize, n);
       block->size = n;
+      allocatedBytes_ += n - oldSize;
       return block->payload;
     } else {
       log_ << AllocatorLog::ReallocateFail(oldSize, n);
@@ -177,6 +184,7 @@ class SpyingAllocator : public ArduinoJson::Allocator {
 
   AllocatorLog log_;
   Allocator* upstream_;
+  size_t allocatedBytes_ = 0;
 };
 
 class ControllableAllocator : public ArduinoJson::Allocator {

+ 0 - 1
extras/tests/JsonArray/CMakeLists.txt

@@ -11,7 +11,6 @@ add_executable(JsonArrayTests
 	equals.cpp
 	isNull.cpp
 	iterator.cpp
-	memoryUsage.cpp
 	nesting.cpp
 	remove.cpp
 	size.cpp

+ 24 - 15
extras/tests/JsonArray/add.cpp

@@ -5,11 +5,14 @@
 #include <ArduinoJson.h>
 #include <catch.hpp>
 
+#include "Allocators.hpp"
+
 using ArduinoJson::detail::sizeofArray;
 using ArduinoJson::detail::sizeofString;
 
 TEST_CASE("JsonArray::add()") {
-  JsonDocument doc;
+  SpyingAllocator allocator;
+  JsonDocument doc(&allocator);
   JsonArray array = doc.to<JsonArray>();
 
   SECTION("int") {
@@ -99,43 +102,49 @@ TEST_CASE("JsonArray::add()") {
 
   SECTION("should not duplicate const char*") {
     array.add("world");
-    const size_t expectedSize = sizeofArray(1);
-    REQUIRE(expectedSize == doc.memoryUsage());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool()));
   }
 
   SECTION("should duplicate char*") {
     array.add(const_cast<char*>("world"));
-    const size_t expectedSize = sizeofArray(1) + sizeofString(5);
-    REQUIRE(expectedSize == doc.memoryUsage());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(5)));
   }
 
   SECTION("should duplicate std::string") {
     array.add(std::string("world"));
-    const size_t expectedSize = sizeofArray(1) + sizeofString(5);
-    REQUIRE(expectedSize == doc.memoryUsage());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(5)));
   }
 
   SECTION("should duplicate serialized(const char*)") {
     array.add(serialized("{}"));
-    const size_t expectedSize = sizeofArray(1) + sizeofString(2);
-    REQUIRE(expectedSize == doc.memoryUsage());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(2)));
   }
 
   SECTION("should duplicate serialized(char*)") {
     array.add(serialized(const_cast<char*>("{}")));
-    const size_t expectedSize = sizeofArray(1) + sizeofString(2);
-    REQUIRE(expectedSize == doc.memoryUsage());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(2)));
   }
 
   SECTION("should duplicate serialized(std::string)") {
     array.add(serialized(std::string("{}")));
-    const size_t expectedSize = sizeofArray(1) + sizeofString(2);
-    REQUIRE(expectedSize == doc.memoryUsage());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(2)));
   }
 
   SECTION("should duplicate serialized(std::string)") {
     array.add(serialized(std::string("\0XX", 3)));
-    const size_t expectedSize = sizeofArray(1) + sizeofString(3);
-    REQUIRE(expectedSize == doc.memoryUsage());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(3)));
   }
 }

+ 0 - 46
extras/tests/JsonArray/memoryUsage.cpp

@@ -1,46 +0,0 @@
-// ArduinoJson - https://arduinojson.org
-// Copyright © 2014-2023, Benoit BLANCHON
-// MIT License
-
-#include <ArduinoJson.h>
-#include <catch.hpp>
-
-using ArduinoJson::detail::sizeofArray;
-using ArduinoJson::detail::sizeofObject;
-using ArduinoJson::detail::sizeofString;
-
-TEST_CASE("JsonArray::memoryUsage()") {
-  JsonDocument doc;
-  JsonArray arr = doc.to<JsonArray>();
-
-  SECTION("return 0 if uninitialized") {
-    JsonArray unitialized;
-    REQUIRE(unitialized.memoryUsage() == 0);
-  }
-
-  SECTION("sizeofArray(0) if empty") {
-    REQUIRE(arr.memoryUsage() == sizeofArray(0));
-  }
-
-  SECTION("sizeofArray(1) after add") {
-    arr.add("hello");
-    REQUIRE(arr.memoryUsage() == sizeofArray(1));
-  }
-
-  SECTION("includes the size of the string") {
-    arr.add(std::string("hello"));
-    REQUIRE(arr.memoryUsage() == sizeofArray(1) + sizeofString(5));
-  }
-
-  SECTION("includes the size of the nested array") {
-    JsonArray nested = arr.createNestedArray();
-    nested.add(42);
-    REQUIRE(arr.memoryUsage() == 2 * sizeofArray(1));
-  }
-
-  SECTION("includes the size of the nested arrect") {
-    JsonObject nested = arr.createNestedObject();
-    nested["hello"] = "world";
-    REQUIRE(arr.memoryUsage() == sizeofObject(1) + sizeofArray(1));
-  }
-}

+ 12 - 7
extras/tests/JsonArray/subscript.cpp

@@ -6,11 +6,14 @@
 #include <stdint.h>
 #include <catch.hpp>
 
+#include "Allocators.hpp"
+
 using ArduinoJson::detail::sizeofArray;
 using ArduinoJson::detail::sizeofString;
 
 TEST_CASE("JsonArray::operator[]") {
-  JsonDocument doc;
+  SpyingAllocator allocator;
+  JsonDocument doc(&allocator);
   JsonArray array = doc.to<JsonArray>();
 
   SECTION("Pad with null") {
@@ -115,20 +118,22 @@ TEST_CASE("JsonArray::operator[]") {
 
   SECTION("should not duplicate const char*") {
     array[0] = "world";
-    const size_t expectedSize = sizeofArray(1);
-    REQUIRE(expectedSize == doc.memoryUsage());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool()));
   }
 
   SECTION("should duplicate char*") {
     array[0] = const_cast<char*>("world");
-    const size_t expectedSize = sizeofArray(1) + sizeofString(5);
-    REQUIRE(expectedSize == doc.memoryUsage());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(5)));
   }
 
   SECTION("should duplicate std::string") {
     array[0] = std::string("world");
-    const size_t expectedSize = sizeofArray(1) + sizeofString(5);
-    REQUIRE(expectedSize == doc.memoryUsage());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(5)));
   }
 
   SECTION("array[0].to<JsonObject>()") {

+ 16 - 8
extras/tests/JsonDeserializer/array.cpp

@@ -11,7 +11,8 @@ using ArduinoJson::detail::sizeofArray;
 using ArduinoJson::detail::sizeofString;
 
 TEST_CASE("deserialize JSON array") {
-  JsonDocument doc;
+  SpyingAllocator allocator;
+  JsonDocument doc(&allocator);
 
   SECTION("An empty array") {
     DeserializationError err = deserializeJson(doc, "[]");
@@ -253,16 +254,19 @@ TEST_CASE("deserialize JSON array") {
     JsonArray arr = doc.as<JsonArray>();
 
     REQUIRE(arr.size() == 0);
-    REQUIRE(doc.memoryUsage() == sizeofArray(0));
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Deallocate(sizeofPool()));
   }
 }
 
 TEST_CASE("deserialize JSON array under memory constraints") {
-  TimebombAllocator allocator(100);
+  TimebombAllocator timebomb(100);
+  SpyingAllocator allocator(&timebomb);
   JsonDocument doc(&allocator);
 
   SECTION("empty array requires no allocation") {
-    allocator.setCountdown(0);
+    timebomb.setCountdown(0);
     char input[] = "[]";
 
     DeserializationError err = deserializeJson(doc, input);
@@ -271,7 +275,7 @@ TEST_CASE("deserialize JSON array under memory constraints") {
   }
 
   SECTION("allocation of pool list fails") {
-    allocator.setCountdown(0);
+    timebomb.setCountdown(0);
     char input[] = "[1]";
 
     DeserializationError err = deserializeJson(doc, input);
@@ -281,7 +285,7 @@ TEST_CASE("deserialize JSON array under memory constraints") {
   }
 
   SECTION("allocation of pool fails") {
-    allocator.setCountdown(0);
+    timebomb.setCountdown(0);
     char input[] = "[1]";
 
     DeserializationError err = deserializeJson(doc, input);
@@ -291,7 +295,7 @@ TEST_CASE("deserialize JSON array under memory constraints") {
   }
 
   SECTION("allocation of string fails in array") {
-    allocator.setCountdown(1);
+    timebomb.setCountdown(1);
     char input[] = "[0,\"hi!\"]";
 
     DeserializationError err = deserializeJson(doc, input);
@@ -303,6 +307,10 @@ TEST_CASE("deserialize JSON array under memory constraints") {
   SECTION("don't store space characters") {
     deserializeJson(doc, "  [ \"1234567\" ] ");
 
-    REQUIRE(sizeofArray(1) + sizeofString(7) == doc.memoryUsage());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(31))
+                                   << AllocatorLog::Reallocate(
+                                          sizeofString(31), sizeofString(7)));
   }
 }

+ 7 - 2
extras/tests/JsonDeserializer/filter.cpp

@@ -9,6 +9,8 @@
 #include <sstream>
 #include <string>
 
+#include "Allocators.hpp"
+
 using ArduinoJson::detail::sizeofArray;
 using ArduinoJson::detail::sizeofObject;
 using ArduinoJson::detail::sizeofString;
@@ -689,8 +691,9 @@ TEST_CASE("Filtering") {
   for (size_t i = 0; i < sizeof(testCases) / sizeof(testCases[0]); i++) {
     CAPTURE(i);
 
+    SpyingAllocator allocator;
     JsonDocument filter;
-    JsonDocument doc;
+    JsonDocument doc(&allocator);
     TestCase& tc = testCases[i];
 
     CAPTURE(tc.filter);
@@ -703,7 +706,9 @@ TEST_CASE("Filtering") {
                               tc.nestingLimit)) == tc.error);
 
     CHECK(doc.as<std::string>() == tc.output);
-    CHECK(doc.memoryUsage() == tc.memoryUsage);
+
+    doc.shrinkToFit();
+    CHECK(allocator.allocatedBytes() == tc.memoryUsage);
   }
 }
 

+ 12 - 2
extras/tests/JsonDeserializer/input_types.cpp

@@ -7,20 +7,30 @@
 #include <catch.hpp>
 #include <sstream>
 
+#include "Allocators.hpp"
 #include "CustomReader.hpp"
 
 using ArduinoJson::detail::sizeofObject;
 using ArduinoJson::detail::sizeofString;
 
 TEST_CASE("deserializeJson(char*)") {
-  JsonDocument doc;
+  SpyingAllocator allocator;
+  JsonDocument doc(&allocator);
 
   char input[] = "{\"hello\":\"world\"}";
 
   DeserializationError err = deserializeJson(doc, input);
 
   REQUIRE(err == DeserializationError::Ok);
-  CHECK(doc.memoryUsage() == sizeofObject(1) + 2 * sizeofString(5));
+
+  REQUIRE(allocator.log() == AllocatorLog()
+                                 << AllocatorLog::Allocate(sizeofString(31))
+                                 << AllocatorLog::Reallocate(sizeofString(31),
+                                                             sizeofString(5))
+                                 << AllocatorLog::Allocate(sizeofPool())
+                                 << AllocatorLog::Allocate(sizeofString(31))
+                                 << AllocatorLog::Reallocate(sizeofString(31),
+                                                             sizeofString(5)));
 }
 
 TEST_CASE("deserializeJson(unsigned char*, unsigned int)") {  // issue #1897

+ 7 - 2
extras/tests/JsonDeserializer/misc.cpp

@@ -5,12 +5,15 @@
 #include <ArduinoJson.h>
 #include <catch.hpp>
 
+#include "Allocators.hpp"
+
 using namespace Catch::Matchers;
 
 using ArduinoJson::detail::sizeofObject;
 
 TEST_CASE("deserializeJson(JsonDocument&)") {
-  JsonDocument doc;
+  SpyingAllocator allocator;
+  JsonDocument doc(&allocator);
 
   SECTION("Edge cases") {
     SECTION("null char*") {
@@ -114,6 +117,8 @@ TEST_CASE("deserializeJson(JsonDocument&)") {
     deserializeJson(doc, "{}");
 
     REQUIRE(doc.is<JsonObject>());
-    REQUIRE(doc.memoryUsage() == sizeofObject(0));
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Deallocate(sizeofPool()));
   }
 }

+ 39 - 4
extras/tests/JsonDeserializer/object.cpp

@@ -11,7 +11,8 @@ using ArduinoJson::detail::sizeofObject;
 using ArduinoJson::detail::sizeofString;
 
 TEST_CASE("deserialize JSON object") {
-  JsonDocument doc;
+  SpyingAllocator allocator;
+  JsonDocument doc(&allocator);
 
   SECTION("An empty object") {
     DeserializationError err = deserializeJson(doc, "{}");
@@ -282,8 +283,28 @@ TEST_CASE("deserialize JSON object") {
       DeserializationError err = deserializeJson(doc, "{a:{b:{c:1}},a:2}");
 
       REQUIRE(err == DeserializationError::Ok);
-      REQUIRE(doc["a"] == 2);
-      REQUIRE(doc.memoryUsage() == 3 * sizeofObject(1) + sizeofString(1));
+      REQUIRE(doc.as<std::string>() == "{\"a\":2}");
+      REQUIRE(allocator.log() ==
+              AllocatorLog()
+                  // a
+                  << AllocatorLog::Allocate(sizeofString(31))
+                  << AllocatorLog::Reallocate(sizeofString(31), sizeofString(1))
+                  // pool
+                  << AllocatorLog::Allocate(sizeofPool())
+                  // b
+                  << AllocatorLog::Allocate(sizeofString(31))
+                  << AllocatorLog::Reallocate(sizeofString(31), sizeofString(1))
+                  // c
+                  << AllocatorLog::Allocate(sizeofString(31))
+                  << AllocatorLog::Reallocate(sizeofString(31), sizeofString(1))
+                  // string builder
+                  << AllocatorLog::Allocate(sizeofString(31))
+                  // remove b & c
+                  << AllocatorLog::Deallocate(sizeofString(1)) * 2
+                  // string builder
+                  << AllocatorLog::Deallocate(sizeofString(31))
+
+      );
     }
 
     SECTION("Repeated key with zero copy mode") {  // issue #1697
@@ -310,7 +331,21 @@ TEST_CASE("deserialize JSON object") {
 
     REQUIRE(doc.is<JsonObject>());
     REQUIRE(obj.size() == 0);
-    REQUIRE(doc.memoryUsage() == sizeofObject(0));
+    REQUIRE(allocator.log() ==
+            AllocatorLog()
+                // string "hello"
+                << AllocatorLog::Allocate(sizeofString(31))
+                << AllocatorLog::Reallocate(sizeofString(31), sizeofString(5))
+                // pool
+                << AllocatorLog::Allocate(sizeofPool())
+                // string "world"
+                << AllocatorLog::Allocate(sizeofString(31))
+                << AllocatorLog::Reallocate(sizeofString(31), sizeofString(5))
+                // free pool
+                << AllocatorLog::Deallocate(sizeofPool())
+                // free "hello" and "world"
+                << AllocatorLog::Deallocate(sizeofString(5))
+                << AllocatorLog::Deallocate(sizeofString(5)));
   }
 
   SECTION("Issue #1335") {

+ 27 - 6
extras/tests/JsonDeserializer/string.cpp

@@ -155,21 +155,42 @@ TEST_CASE("String allocation fails") {
 }
 
 TEST_CASE("Deduplicate values") {
-  JsonDocument doc;
+  SpyingAllocator allocator;
+  JsonDocument doc(&allocator);
   deserializeJson(doc, "[\"example\",\"example\"]");
 
-  CHECK(doc.memoryUsage() == sizeofArray(2) + sizeofString(7));
   CHECK(doc[0].as<const char*>() == doc[1].as<const char*>());
+  REQUIRE(allocator.log() == AllocatorLog()
+                                 // pool
+                                 << AllocatorLog::Allocate(sizeofPool())
+                                 // string builder
+                                 << AllocatorLog::Allocate(sizeofString(31))
+                                 // string "example"
+                                 << AllocatorLog::Reallocate(sizeofString(31),
+                                                             sizeofString(7))
+                                 // string builder
+                                 << AllocatorLog::Allocate(sizeofString(31))
+                                 << AllocatorLog::Deallocate(sizeofString(31)));
 }
 
 TEST_CASE("Deduplicate keys") {
-  JsonDocument doc;
+  SpyingAllocator allocator;
+  JsonDocument doc(&allocator);
   deserializeJson(doc, "[{\"example\":1},{\"example\":2}]");
 
-  CHECK(doc.memoryUsage() ==
-        2 * sizeofObject(1) + sizeofArray(2) + sizeofString(7));
-
   const char* key1 = doc[0].as<JsonObject>().begin()->key().c_str();
   const char* key2 = doc[1].as<JsonObject>().begin()->key().c_str();
   CHECK(key1 == key2);
+
+  REQUIRE(allocator.log() == AllocatorLog()
+                                 // pool
+                                 << AllocatorLog::Allocate(sizeofPool())
+                                 // string builder
+                                 << AllocatorLog::Allocate(sizeofString(31))
+                                 // string "example"
+                                 << AllocatorLog::Reallocate(sizeofString(31),
+                                                             sizeofString(7))
+                                 // string builder
+                                 << AllocatorLog::Allocate(sizeofString(31))
+                                 << AllocatorLog::Deallocate(sizeofString(31)));
 }

+ 0 - 1
extras/tests/JsonDocument/CMakeLists.txt

@@ -15,7 +15,6 @@ add_executable(JsonDocumentTests
 	isNull.cpp
 	issue1120.cpp
 	MemberProxy.cpp
-	memoryUsage.cpp
 	nesting.cpp
 	overflowed.cpp
 	remove.cpp

+ 0 - 15
extras/tests/JsonDocument/ElementProxy.cpp

@@ -189,21 +189,6 @@ TEST_CASE("ElementProxy::size()") {
   }
 }
 
-TEST_CASE("ElementProxy::memoryUsage()") {
-  JsonDocument doc;
-  doc.add();
-  ElementProxy ep = doc[0];
-
-  SECTION("returns 0 for null") {
-    REQUIRE(ep.memoryUsage() == 0);
-  }
-
-  SECTION("returns size for string") {
-    ep.set(std::string("hello"));
-    REQUIRE(ep.memoryUsage() == sizeofString(5));
-  }
-}
-
 TEST_CASE("ElementProxy::operator[]") {
   JsonDocument doc;
   ElementProxy ep = doc[1];

+ 22 - 29
extras/tests/JsonDocument/MemberProxy.cpp

@@ -239,20 +239,6 @@ TEST_CASE("MemberProxy::size()") {
   }
 }
 
-TEST_CASE("MemberProxy::memoryUsage()") {
-  JsonDocument doc;
-  MemberProxy mp = doc["hello"];
-
-  SECTION("returns 0 when null") {
-    REQUIRE(mp.memoryUsage() == 0);
-  }
-
-  SECTION("return the size for a string") {
-    mp.set(std::string("hello"));
-    REQUIRE(mp.memoryUsage() == sizeofString(5));
-  }
-}
-
 TEST_CASE("MemberProxy::operator[]") {
   JsonDocument doc;
   MemberProxy mp = doc["hello"];
@@ -329,18 +315,20 @@ TEST_CASE("MemberProxy::createNestedObject(key)") {
 }
 
 TEST_CASE("Deduplicate keys") {
-  JsonDocument doc;
+  SpyingAllocator allocator;
+  JsonDocument doc(&allocator);
 
   SECTION("std::string") {
     doc[0][std::string("example")] = 1;
     doc[1][std::string("example")] = 2;
 
-    CHECK(doc.memoryUsage() ==
-          sizeofArray(2) + 2 * sizeofObject(1) + sizeofString(7));
-
     const char* key1 = doc[0].as<JsonObject>().begin()->key().c_str();
     const char* key2 = doc[1].as<JsonObject>().begin()->key().c_str();
     CHECK(key1 == key2);
+
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(7)));
   }
 
   SECTION("char*") {
@@ -348,42 +336,46 @@ TEST_CASE("Deduplicate keys") {
     doc[0][key] = 1;
     doc[1][key] = 2;
 
-    CHECK(doc.memoryUsage() ==
-          sizeofArray(2) + 2 * sizeofObject(1) + sizeofString(7));
-
     const char* key1 = doc[0].as<JsonObject>().begin()->key().c_str();
     const char* key2 = doc[1].as<JsonObject>().begin()->key().c_str();
     CHECK(key1 == key2);
+
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(7)));
   }
 
   SECTION("Arduino String") {
     doc[0][String("example")] = 1;
     doc[1][String("example")] = 2;
 
-    CHECK(doc.memoryUsage() ==
-          sizeofArray(2) + 2 * sizeofObject(1) + sizeofString(7));
-
     const char* key1 = doc[0].as<JsonObject>().begin()->key().c_str();
     const char* key2 = doc[1].as<JsonObject>().begin()->key().c_str();
     CHECK(key1 == key2);
+
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(7)));
   }
 
   SECTION("Flash string") {
     doc[0][F("example")] = 1;
     doc[1][F("example")] = 2;
 
-    CHECK(doc.memoryUsage() ==
-          sizeofArray(2) + 2 * sizeofObject(1) + sizeofString(7));
-
     const char* key1 = doc[0].as<JsonObject>().begin()->key().c_str();
     const char* key2 = doc[1].as<JsonObject>().begin()->key().c_str();
     CHECK(key1 == key2);
+
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(7)));
   }
 }
 
 TEST_CASE("MemberProxy under memory constraints") {
   ControllableAllocator allocator;
-  JsonDocument doc(&allocator);
+  SpyingAllocator spy(&allocator);
+  JsonDocument doc(&spy);
 
   SECTION("key allocation fails") {
     allocator.disable();
@@ -392,7 +384,8 @@ TEST_CASE("MemberProxy under memory constraints") {
 
     REQUIRE(doc.is<JsonObject>());
     REQUIRE(doc.size() == 0);
-    REQUIRE(doc.memoryUsage() == 0);
     REQUIRE(doc.overflowed() == true);
+    REQUIRE(spy.log() == AllocatorLog()
+                             << AllocatorLog::AllocateFail(sizeofString(5)));
   }
 }

+ 20 - 5
extras/tests/JsonDocument/add.cpp

@@ -8,30 +8,39 @@
 
 #include <catch.hpp>
 
+#include "Allocators.hpp"
+
 using ArduinoJson::detail::sizeofArray;
 using ArduinoJson::detail::sizeofString;
 
 TEST_CASE("JsonDocument::add()") {
-  JsonDocument doc;
+  SpyingAllocator allocator;
+  JsonDocument doc(&allocator);
 
   SECTION("integer") {
     doc.add(42);
 
     REQUIRE(doc.as<std::string>() == "[42]");
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool()));
   }
 
   SECTION("const char*") {
     doc.add("hello");
 
     REQUIRE(doc.as<std::string>() == "[\"hello\"]");
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool()));
   }
 
   SECTION("std::string") {
     doc.add(std::string("example"));
     doc.add(std::string("example"));
 
-    CHECK(doc.memoryUsage() == sizeofArray(2) + sizeofString(7));
     CHECK(doc[0].as<const char*>() == doc[1].as<const char*>());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(7)));
   }
 
   SECTION("char*") {
@@ -39,23 +48,29 @@ TEST_CASE("JsonDocument::add()") {
     doc.add(value);
     doc.add(value);
 
-    CHECK(doc.memoryUsage() == sizeofArray(2) + sizeofString(7));
     CHECK(doc[0].as<const char*>() == doc[1].as<const char*>());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(7)));
   }
 
   SECTION("Arduino String") {
     doc.add(String("example"));
     doc.add(String("example"));
 
-    CHECK(doc.memoryUsage() == sizeofArray(2) + sizeofString(7));
     CHECK(doc[0].as<const char*>() == doc[1].as<const char*>());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(7)));
   }
 
   SECTION("Flash string") {
     doc.add(F("example"));
     doc.add(F("example"));
 
-    CHECK(doc.memoryUsage() == sizeofArray(2) + sizeofString(7));
     CHECK(doc[0].as<const char*>() == doc[1].as<const char*>());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(7)));
   }
 }

+ 0 - 4
extras/tests/JsonDocument/garbageCollect.cpp

@@ -19,14 +19,12 @@ TEST_CASE("JsonDocument::garbageCollect()") {
 
   SECTION("when allocation succeeds") {
     deserializeJson(doc, "{\"blanket\":1,\"dancing\":2}");
-    REQUIRE(doc.memoryUsage() == sizeofObject(2) + 2 * sizeofString(7));
     doc.remove("blanket");
     spyingAllocator.clearLog();
 
     bool result = doc.garbageCollect();
 
     REQUIRE(result == true);
-    REQUIRE(doc.memoryUsage() == sizeofObject(1) + sizeofString(7));
     REQUIRE(doc.as<std::string>() == "{\"dancing\":2}");
     REQUIRE(spyingAllocator.log() ==
             AllocatorLog() << AllocatorLog::Allocate(sizeofString(7))
@@ -37,7 +35,6 @@ TEST_CASE("JsonDocument::garbageCollect()") {
 
   SECTION("when allocation fails") {
     deserializeJson(doc, "{\"blanket\":1,\"dancing\":2}");
-    REQUIRE(doc.memoryUsage() == sizeofObject(2) + 2 * sizeofString(7));
     doc.remove("blanket");
     controllableAllocator.disable();
     spyingAllocator.clearLog();
@@ -45,7 +42,6 @@ TEST_CASE("JsonDocument::garbageCollect()") {
     bool result = doc.garbageCollect();
 
     REQUIRE(result == false);
-    REQUIRE(doc.memoryUsage() == sizeofObject(2) + sizeofString(7));
     REQUIRE(doc.as<std::string>() == "{\"dancing\":2}");
 
     REQUIRE(spyingAllocator.log() ==

+ 0 - 52
extras/tests/JsonDocument/memoryUsage.cpp

@@ -1,52 +0,0 @@
-// ArduinoJson - https://arduinojson.org
-// Copyright © 2014-2023, Benoit BLANCHON
-// MIT License
-
-#include <ArduinoJson.h>
-#include <catch.hpp>
-
-using ArduinoJson::detail::sizeofArray;
-using ArduinoJson::detail::sizeofObject;
-
-TEST_CASE("JsonDocument::memoryUsage()") {
-  JsonDocument doc;
-
-  SECTION("starts at zero") {
-    REQUIRE(doc.memoryUsage() == 0);
-  }
-
-  SECTION("sizeofArray(0)") {
-    doc.to<JsonArray>();
-    REQUIRE(doc.memoryUsage() == sizeofArray(0));
-  }
-
-  SECTION("sizeofArray(1)") {
-    doc.to<JsonArray>().add(42);
-    REQUIRE(doc.memoryUsage() == sizeofArray(1));
-  }
-
-  SECTION("sizeofArray(1) + sizeofArray(0)") {
-    doc.to<JsonArray>().createNestedArray();
-    REQUIRE(doc.memoryUsage() == sizeofArray(1) + sizeofArray(0));
-  }
-
-  SECTION("Increases after adding value to array") {
-    JsonArray arr = doc.to<JsonArray>();
-
-    REQUIRE(doc.memoryUsage() == sizeofArray(0));
-    arr.add(42);
-    REQUIRE(doc.memoryUsage() == sizeofArray(1));
-    arr.add(43);
-    REQUIRE(doc.memoryUsage() == sizeofArray(2));
-  }
-
-  SECTION("Increases after adding value to object") {
-    JsonObject obj = doc.to<JsonObject>();
-
-    REQUIRE(doc.memoryUsage() == sizeofObject(0));
-    obj["a"] = 1;
-    REQUIRE(doc.memoryUsage() == sizeofObject(1));
-    obj["b"] = 2;
-    REQUIRE(doc.memoryUsage() == sizeofObject(2));
-  }
-}

+ 0 - 1
extras/tests/JsonObject/CMakeLists.txt

@@ -13,7 +13,6 @@ add_executable(JsonObjectTests
 	invalid.cpp
 	isNull.cpp
 	iterator.cpp
-	memoryUsage.cpp
 	nesting.cpp
 	remove.cpp
 	size.cpp

+ 30 - 12
extras/tests/JsonObject/copy.cpp

@@ -7,61 +7,80 @@
 
 #include "Allocators.hpp"
 
+using ArduinoJson::detail::sizeofString;
+
 TEST_CASE("JsonObject::set()") {
-  JsonDocument doc1;
-  JsonDocument doc2;
+  SpyingAllocator allocator;
+  JsonDocument doc1(&allocator);
+  JsonDocument doc2(&allocator);
 
   JsonObject obj1 = doc1.to<JsonObject>();
   JsonObject obj2 = doc2.to<JsonObject>();
 
   SECTION("doesn't copy static string in key or value") {
     obj1["hello"] = "world";
+    allocator.clearLog();
 
     bool success = obj2.set(obj1);
 
     REQUIRE(success == true);
-    REQUIRE(doc1.memoryUsage() == doc2.memoryUsage());
     REQUIRE(obj2["hello"] == std::string("world"));
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool()));
   }
 
   SECTION("copy local string value") {
     obj1["hello"] = std::string("world");
+    allocator.clearLog();
 
     bool success = obj2.set(obj1);
 
     REQUIRE(success == true);
-    REQUIRE(doc1.memoryUsage() == doc2.memoryUsage());
     REQUIRE(obj2["hello"] == std::string("world"));
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(5)));
   }
 
   SECTION("copy local key") {
     obj1[std::string("hello")] = "world";
+    allocator.clearLog();
 
     bool success = obj2.set(obj1);
 
     REQUIRE(success == true);
-    REQUIRE(doc1.memoryUsage() == doc2.memoryUsage());
     REQUIRE(obj2["hello"] == std::string("world"));
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofString(5))
+                                   << AllocatorLog::Allocate(sizeofPool()));
   }
 
   SECTION("copy string from deserializeJson()") {
     deserializeJson(doc1, "{'hello':'world'}");
+    allocator.clearLog();
 
     bool success = obj2.set(obj1);
 
     REQUIRE(success == true);
-    REQUIRE(doc1.memoryUsage() == doc2.memoryUsage());
     REQUIRE(obj2["hello"] == std::string("world"));
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofString(5))
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(5)));
   }
 
   SECTION("copy string from deserializeMsgPack()") {
     deserializeMsgPack(doc1, "\x81\xA5hello\xA5world");
+    allocator.clearLog();
 
     bool success = obj2.set(obj1);
 
     REQUIRE(success == true);
-    REQUIRE(doc1.memoryUsage() == doc2.memoryUsage());
     REQUIRE(obj2["hello"] == std::string("world"));
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofString(5))
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(5)));
   }
 
   SECTION("should work with JsonObjectConst") {
@@ -69,13 +88,12 @@ TEST_CASE("JsonObject::set()") {
 
     obj2.set(static_cast<JsonObjectConst>(obj1));
 
-    REQUIRE(doc1.memoryUsage() == doc2.memoryUsage());
     REQUIRE(obj2["hello"] == std::string("world"));
   }
 
   SECTION("copy fails in the middle of an object") {
-    TimebombAllocator allocator(2);
-    JsonDocument doc3(&allocator);
+    TimebombAllocator timebomb(2);
+    JsonDocument doc3(&timebomb);
     JsonObject obj3 = doc3.to<JsonObject>();
 
     obj1[std::string("a")] = 1;
@@ -88,8 +106,8 @@ TEST_CASE("JsonObject::set()") {
   }
 
   SECTION("copy fails in the middle of an array") {
-    TimebombAllocator allocator(1);
-    JsonDocument doc3(&allocator);
+    TimebombAllocator timebomb(1);
+    JsonDocument doc3(&timebomb);
     JsonObject obj3 = doc3.to<JsonObject>();
 
     obj1["hello"][0] = std::string("world");

+ 0 - 47
extras/tests/JsonObject/memoryUsage.cpp

@@ -1,47 +0,0 @@
-// ArduinoJson - https://arduinojson.org
-// Copyright © 2014-2023, Benoit BLANCHON
-// MIT License
-
-#include <ArduinoJson.h>
-#include <catch.hpp>
-#include <string>
-
-using ArduinoJson::detail::sizeofArray;
-using ArduinoJson::detail::sizeofObject;
-using ArduinoJson::detail::sizeofString;
-
-TEST_CASE("JsonObject::memoryUsage()") {
-  JsonDocument doc;
-  JsonObject obj = doc.to<JsonObject>();
-
-  SECTION("return 0 if uninitialized") {
-    JsonObject unitialized;
-    REQUIRE(unitialized.memoryUsage() == 0);
-  }
-
-  SECTION("sizeofObject(0) for empty object") {
-    REQUIRE(obj.memoryUsage() == sizeofObject(0));
-  }
-
-  SECTION("sizeofObject(1) after add") {
-    obj["hello"] = 42;
-    REQUIRE(obj.memoryUsage() == sizeofObject(1));
-  }
-
-  SECTION("includes the size of the key") {
-    obj[std::string("hello")] = 42;
-    REQUIRE(obj.memoryUsage() == sizeofObject(1) + sizeofString(5));
-  }
-
-  SECTION("includes the size of the nested array") {
-    JsonArray nested = obj.createNestedArray("nested");
-    nested.add(42);
-    REQUIRE(obj.memoryUsage() == sizeofObject(1) + sizeofArray(1));
-  }
-
-  SECTION("includes the size of the nested object") {
-    JsonObject nested = obj.createNestedObject("nested");
-    nested["hello"] = "world";
-    REQUIRE(obj.memoryUsage() == 2 * sizeofObject(1));
-  }
-}

+ 0 - 24
extras/tests/JsonObject/std_string.cpp

@@ -83,28 +83,4 @@ TEST_CASE("std::string") {
     eraseString(value);
     REQUIRE(std::string("world") == obj["hello"]);
   }
-
-  SECTION("memoryUsage() increases when adding a new key") {
-    std::string key1("hello"), key2("world");
-    JsonObject obj = doc.to<JsonObject>();
-
-    obj[key1] = 1;
-    size_t sizeBefore = doc.memoryUsage();
-    obj[key2] = 2;
-    size_t sizeAfter = doc.memoryUsage();
-
-    REQUIRE(sizeAfter - sizeBefore >= key2.size());
-  }
-
-  SECTION("memoryUsage() remains when adding the same key") {
-    std::string key("hello");
-    JsonObject obj = doc.to<JsonObject>();
-
-    obj[key] = 1;
-    size_t sizeBefore = doc.memoryUsage();
-    obj[key] = 2;
-    size_t sizeAfter = doc.memoryUsage();
-
-    REQUIRE(sizeBefore == sizeAfter);
-  }
 }

+ 31 - 19
extras/tests/JsonObject/subscript.cpp

@@ -5,11 +5,14 @@
 #include <ArduinoJson.h>
 #include <catch.hpp>
 
+#include "Allocators.hpp"
+
 using ArduinoJson::detail::sizeofObject;
 using ArduinoJson::detail::sizeofString;
 
 TEST_CASE("JsonObject::operator[]") {
-  JsonDocument doc;
+  SpyingAllocator allocator;
+  JsonDocument doc(&allocator);
   JsonObject obj = doc.to<JsonObject>();
 
   SECTION("int") {
@@ -103,56 +106,65 @@ TEST_CASE("JsonObject::operator[]") {
 
   SECTION("should not duplicate const char*") {
     obj["hello"] = "world";
-    const size_t expectedSize = sizeofObject(1);
-    REQUIRE(expectedSize == doc.memoryUsage());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool()));
   }
 
   SECTION("should duplicate char* value") {
     obj["hello"] = const_cast<char*>("world");
-    const size_t expectedSize = sizeofObject(1) + sizeofString(5);
-    REQUIRE(expectedSize == doc.memoryUsage());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(5)));
   }
 
   SECTION("should duplicate char* key") {
     obj[const_cast<char*>("hello")] = "world";
-    const size_t expectedSize = sizeofObject(1) + sizeofString(5);
-    REQUIRE(expectedSize == doc.memoryUsage());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofString(5))
+                                   << AllocatorLog::Allocate(sizeofPool()));
   }
 
   SECTION("should duplicate char* key&value") {
     obj[const_cast<char*>("hello")] = const_cast<char*>("world");
-    const size_t expectedSize = sizeofObject(1) + 2 * sizeofString(5);
-    REQUIRE(expectedSize <= doc.memoryUsage());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofString(5))
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(5)));
   }
 
   SECTION("should duplicate std::string value") {
     obj["hello"] = std::string("world");
-    const size_t expectedSize = sizeofObject(1) + sizeofString(5);
-    REQUIRE(expectedSize == doc.memoryUsage());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(5)));
   }
 
   SECTION("should duplicate std::string key") {
     obj[std::string("hello")] = "world";
-    const size_t expectedSize = sizeofObject(1) + sizeofString(5);
-    REQUIRE(expectedSize == doc.memoryUsage());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofString(5))
+                                   << AllocatorLog::Allocate(sizeofPool()));
   }
 
   SECTION("should duplicate std::string key&value") {
     obj[std::string("hello")] = std::string("world");
-    const size_t expectedSize = sizeofObject(1) + 2 * sizeofString(5);
-    REQUIRE(expectedSize <= doc.memoryUsage());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofString(5))
+                                   << AllocatorLog::Allocate(sizeofPool())
+                                   << AllocatorLog::Allocate(sizeofString(5)));
   }
 
   SECTION("should duplicate a non-static JsonString key") {
     obj[JsonString("hello", JsonString::Copied)] = "world";
-    const size_t expectedSize = sizeofObject(1) + sizeofString(5);
-    REQUIRE(expectedSize == doc.memoryUsage());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofString(5))
+                                   << AllocatorLog::Allocate(sizeofPool()));
   }
 
   SECTION("should not duplicate a static JsonString key") {
     obj[JsonString("hello", JsonString::Linked)] = "world";
-    const size_t expectedSize = sizeofObject(1);
-    REQUIRE(expectedSize == doc.memoryUsage());
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofPool()));
   }
 
   SECTION("should ignore null key") {

+ 0 - 1
extras/tests/JsonSerializer/std_string.cpp

@@ -51,7 +51,6 @@ TEST_CASE("serialize JsonObject to std::string") {
 TEST_CASE("serialize an std::string containing a NUL") {
   JsonDocument doc;
   doc.set(std::string("hello\0world", 11));
-  CHECK(doc.memoryUsage() == sizeofString(11));
 
   std::string json;
   serializeJson(doc, json);

+ 0 - 1
extras/tests/JsonVariant/CMakeLists.txt

@@ -13,7 +13,6 @@ add_executable(JsonVariantTests
 	createNested.cpp
 	is.cpp
 	isnull.cpp
-	memoryUsage.cpp
 	misc.cpp
 	nesting.cpp
 	nullptr.cpp

+ 8 - 4
extras/tests/JsonVariant/clear.cpp

@@ -6,10 +6,13 @@
 #include <stdint.h>
 #include <catch.hpp>
 
+#include "Allocators.hpp"
+
 using ArduinoJson::detail::sizeofString;
 
 TEST_CASE("JsonVariant::clear()") {
-  JsonDocument doc;
+  SpyingAllocator allocator;
+  JsonDocument doc(&allocator);
   JsonVariant var = doc.to<JsonVariant>();
 
   SECTION("size goes back to zero") {
@@ -28,9 +31,10 @@ TEST_CASE("JsonVariant::clear()") {
 
   SECTION("releases owned string") {
     var.set(std::string("hello"));
-    REQUIRE(doc.memoryUsage() == sizeofString(5));
-
     var.clear();
-    REQUIRE(doc.memoryUsage() == 0);
+
+    REQUIRE(allocator.log() ==
+            AllocatorLog() << AllocatorLog::Allocate(sizeofString(5))
+                           << AllocatorLog::Deallocate(sizeofString(5)));
   }
 }

+ 0 - 16
extras/tests/JsonVariant/copy.cpp

@@ -44,8 +44,6 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
 
     var2.set(var1);
 
-    REQUIRE(doc1.memoryUsage() == 0);
-    REQUIRE(doc2.memoryUsage() == 0);
     REQUIRE(spyingAllocator.log() == AllocatorLog());
   }
 
@@ -56,8 +54,6 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
 
     var2.set(var1);
 
-    REQUIRE(doc1.memoryUsage() == sizeofString(7));
-    REQUIRE(doc2.memoryUsage() == sizeofString(7));
     REQUIRE(spyingAllocator.log() ==
             AllocatorLog() << AllocatorLog::Allocate(sizeofString((7))));
   }
@@ -70,8 +66,6 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
 
     var2.set(var1);
 
-    REQUIRE(doc1.memoryUsage() == sizeofString(7));
-    REQUIRE(doc2.memoryUsage() == 0);
     REQUIRE(doc2.overflowed() == true);
     REQUIRE(spyingAllocator.log() ==
             AllocatorLog() << AllocatorLog::AllocateFail(sizeofString((7))));
@@ -83,8 +77,6 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
 
     var2.set(var1);
 
-    REQUIRE(doc1.memoryUsage() == sizeofString(7));
-    REQUIRE(doc2.memoryUsage() == sizeofString(7));
     REQUIRE(spyingAllocator.log() ==
             AllocatorLog() << AllocatorLog::Allocate(sizeofString((7))));
   }
@@ -95,8 +87,6 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
 
     var2.set(var1);
 
-    REQUIRE(doc1.memoryUsage() == sizeofString(7));
-    REQUIRE(doc2.memoryUsage() == sizeofString(7));
     REQUIRE(spyingAllocator.log() ==
             AllocatorLog() << AllocatorLog::Allocate(sizeofString((7))));
   }
@@ -108,8 +98,6 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
 
     var2.set(var1);
 
-    REQUIRE(doc1.memoryUsage() == sizeofString(7));
-    REQUIRE(doc2.memoryUsage() == sizeofString(7));
     REQUIRE(spyingAllocator.log() ==
             AllocatorLog() << AllocatorLog::Allocate(sizeofString((7))));
   }
@@ -120,8 +108,6 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
 
     var2.set(var1);
 
-    REQUIRE(doc1.memoryUsage() == sizeofString(7));
-    REQUIRE(doc2.memoryUsage() == sizeofString(7));
     REQUIRE(spyingAllocator.log() ==
             AllocatorLog() << AllocatorLog::Allocate(sizeofString((7))));
   }
@@ -133,8 +119,6 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
 
     var2.set(var1);
 
-    REQUIRE(doc1.memoryUsage() == sizeofString(7));
-    REQUIRE(doc2.memoryUsage() == 0);
     REQUIRE(doc2.overflowed() == true);
     REQUIRE(spyingAllocator.log() ==
             AllocatorLog() << AllocatorLog::AllocateFail(sizeofString((7))));

+ 0 - 45
extras/tests/JsonVariant/memoryUsage.cpp

@@ -1,45 +0,0 @@
-// ArduinoJson - https://arduinojson.org
-// Copyright © 2014-2023, Benoit BLANCHON
-// MIT License
-
-#include <ArduinoJson.h>
-#include <catch.hpp>
-#include <string>
-
-using ArduinoJson::detail::sizeofArray;
-using ArduinoJson::detail::sizeofObject;
-using ArduinoJson::detail::sizeofString;
-
-TEST_CASE("JsonVariant::memoryUsage()") {
-  JsonDocument doc;
-  JsonVariant var = doc.to<JsonVariant>();
-
-  SECTION("returns 0 if uninitialized") {
-    JsonVariant unitialized;
-    REQUIRE(unitialized.memoryUsage() == 0);
-  }
-
-  SECTION("returns size of object") {
-    JsonObject obj = var.to<JsonObject>();
-    obj["hello"] = 42;
-    REQUIRE(var.memoryUsage() == sizeofObject(1));
-  }
-
-  SECTION("returns size of array") {
-    JsonArray arr = var.to<JsonArray>();
-    arr.add(42);
-    REQUIRE(var.memoryUsage() == sizeofArray(1));
-  }
-
-  SECTION("returns size of owned string") {
-    var.set(std::string("hello"));
-    REQUIRE(var.memoryUsage() == sizeofString(5));
-    REQUIRE(var.memoryUsage() == doc.memoryUsage());
-  }
-
-  SECTION("returns size of raw string") {
-    var.set(serialized("hello"));
-    REQUIRE(var.memoryUsage() == sizeofString(5));
-    REQUIRE(var.memoryUsage() == doc.memoryUsage());
-  }
-}

+ 16 - 7
extras/tests/JsonVariant/remove.cpp

@@ -6,11 +6,14 @@
 #include <stdint.h>
 #include <catch.hpp>
 
+#include "Allocators.hpp"
+
 using ArduinoJson::detail::sizeofArray;
 using ArduinoJson::detail::sizeofString;
 
 TEST_CASE("JsonVariant::remove(int)") {
-  JsonDocument doc;
+  SpyingAllocator allocator;
+  JsonDocument doc(&allocator);
 
   SECTION("release top level strings") {
     doc.add(std::string("hello"));
@@ -19,19 +22,23 @@ TEST_CASE("JsonVariant::remove(int)") {
 
     JsonVariant var = doc.as<JsonVariant>();
     REQUIRE(var.as<std::string>() == "[\"hello\",\"hello\",\"world\"]");
-    REQUIRE(doc.memoryUsage() == sizeofArray(3) + 2 * sizeofString(5));
 
+    allocator.clearLog();
     var.remove(1);
     REQUIRE(var.as<std::string>() == "[\"hello\",\"world\"]");
-    REQUIRE(doc.memoryUsage() == sizeofArray(3) + 2 * sizeofString(5));
+    REQUIRE(allocator.log() == AllocatorLog());
 
+    allocator.clearLog();
     var.remove(1);
     REQUIRE(var.as<std::string>() == "[\"hello\"]");
-    REQUIRE(doc.memoryUsage() == sizeofArray(3) + 1 * sizeofString(5));
+    REQUIRE(allocator.log() ==
+            AllocatorLog() << AllocatorLog::Deallocate(sizeofString(5)));
 
+    allocator.clearLog();
     var.remove(0);
     REQUIRE(var.as<std::string>() == "[]");
-    REQUIRE(doc.memoryUsage() == sizeofArray(3));
+    REQUIRE(allocator.log() ==
+            AllocatorLog() << AllocatorLog::Deallocate(sizeofString(5)));
   }
 
   SECTION("release strings in nested array") {
@@ -39,11 +46,13 @@ TEST_CASE("JsonVariant::remove(int)") {
 
     JsonVariant var = doc.as<JsonVariant>();
     REQUIRE(var.as<std::string>() == "[[\"hello\"]]");
-    REQUIRE(doc.memoryUsage() == 2 * sizeofArray(1) + sizeofString(5));
 
+    allocator.clearLog();
     var.remove(0);
+
     REQUIRE(var.as<std::string>() == "[]");
-    REQUIRE(doc.memoryUsage() == 2 * sizeofArray(1));
+    REQUIRE(allocator.log() ==
+            AllocatorLog() << AllocatorLog::Deallocate(sizeofString(5)));
   }
 }
 

+ 14 - 7
extras/tests/JsonVariant/set.cpp

@@ -177,34 +177,41 @@ TEST_CASE("JsonVariant::set(JsonDocument)") {
 }
 
 TEST_CASE("JsonVariant::set() releases the previous value") {
-  JsonDocument doc;
+  SpyingAllocator allocator;
+  JsonDocument doc(&allocator);
   doc["hello"] = std::string("world");
-  REQUIRE(doc.memoryUsage() == sizeofObject(1) + sizeofString(5));
+  allocator.clearLog();
 
   JsonVariant v = doc["hello"];
 
   SECTION("int") {
     v.set(42);
-    REQUIRE(doc.memoryUsage() == sizeofObject(1));
+    REQUIRE(allocator.log() ==
+            AllocatorLog() << AllocatorLog::Deallocate(sizeofString(5)));
   }
 
   SECTION("bool") {
     v.set(false);
-    REQUIRE(doc.memoryUsage() == sizeofObject(1));
+    REQUIRE(allocator.log() ==
+            AllocatorLog() << AllocatorLog::Deallocate(sizeofString(5)));
   }
 
   SECTION("const char*") {
     v.set("hello");
-    REQUIRE(doc.memoryUsage() == sizeofObject(1));
+    REQUIRE(allocator.log() ==
+            AllocatorLog() << AllocatorLog::Deallocate(sizeofString(5)));
   }
 
   SECTION("float") {
     v.set(1.2);
-    REQUIRE(doc.memoryUsage() == sizeofObject(1));
+    REQUIRE(allocator.log() ==
+            AllocatorLog() << AllocatorLog::Deallocate(sizeofString(5)));
   }
 
   SECTION("Serialized<const char*>") {
     v.set(serialized("[]"));
-    REQUIRE(doc.memoryUsage() == sizeofObject(1) + sizeofString(2));
+    REQUIRE(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Deallocate(sizeofString(5))
+                                   << AllocatorLog::Allocate(sizeofString(2)));
   }
 }

+ 19 - 11
extras/tests/Misc/printable.cpp

@@ -53,7 +53,8 @@ struct PrintableString : public Printable {
 
 TEST_CASE("Printable") {
   SECTION("Doesn't overflow") {
-    JsonDocument doc;
+    SpyingAllocator allocator;
+    JsonDocument doc(&allocator);
     const char* value = "example";
 
     doc.set(666);  // to make sure we override the value
@@ -64,8 +65,10 @@ TEST_CASE("Printable") {
       CHECK(doc.as<std::string>() == value);
       CHECK(printable.totalBytesWritten() == 7);
       CHECK(doc.overflowed() == false);
-      CHECK(doc.memoryUsage() == sizeofString(7));
-      CHECK(doc.as<JsonVariant>().memoryUsage() == sizeofString(7));
+      CHECK(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofString(31))
+                                   << AllocatorLog::Reallocate(
+                                          sizeofString(31), sizeofString(7)));
     }
 
     SECTION("Via Print::write(const char* size_t)") {
@@ -74,8 +77,10 @@ TEST_CASE("Printable") {
       CHECK(doc.as<std::string>() == value);
       CHECK(printable.totalBytesWritten() == 7);
       CHECK(doc.overflowed() == false);
-      CHECK(doc.memoryUsage() == sizeofString(7));
-      CHECK(doc.as<JsonVariant>().memoryUsage() == sizeofString(7));
+      CHECK(allocator.log() == AllocatorLog()
+                                   << AllocatorLog::Allocate(sizeofString(31))
+                                   << AllocatorLog::Reallocate(
+                                          sizeofString(31), sizeofString(7)));
     }
   }
 
@@ -95,7 +100,6 @@ TEST_CASE("Printable") {
       CHECK(doc.isNull());
       CHECK(printable.totalBytesWritten() == 0);
       CHECK(doc.overflowed() == true);
-      CHECK(doc.memoryUsage() == 0);
       CHECK(spyingAllocator.log() ==
             AllocatorLog() << AllocatorLog::AllocateFail(sizeofString(31)));
     }
@@ -109,7 +113,6 @@ TEST_CASE("Printable") {
       CHECK(doc.isNull());
       CHECK(printable.totalBytesWritten() == 0);
       CHECK(doc.overflowed() == true);
-      CHECK(doc.memoryUsage() == 0);
       CHECK(spyingAllocator.log() ==
             AllocatorLog() << AllocatorLog::AllocateFail(sizeofString(31)));
     }
@@ -132,7 +135,6 @@ TEST_CASE("Printable") {
       CHECK(doc.isNull());
       CHECK(printable.totalBytesWritten() == 31);
       CHECK(doc.overflowed() == true);
-      CHECK(doc.memoryUsage() == 0);
       CHECK(spyingAllocator.log() ==
             AllocatorLog() << AllocatorLog::Allocate(sizeofString(31))
                            << AllocatorLog::ReallocateFail(sizeofString(31),
@@ -149,7 +151,6 @@ TEST_CASE("Printable") {
       CHECK(doc.isNull());
       CHECK(printable.totalBytesWritten() == 31);
       CHECK(doc.overflowed() == true);
-      CHECK(doc.memoryUsage() == 0);
       CHECK(spyingAllocator.log() ==
             AllocatorLog() << AllocatorLog::Allocate(sizeofString(31))
                            << AllocatorLog::ReallocateFail(sizeofString(31),
@@ -167,12 +168,19 @@ TEST_CASE("Printable") {
   }
 
   SECTION("String deduplication") {
-    JsonDocument doc;
+    SpyingAllocator allocator;
+    JsonDocument doc(&allocator);
     doc.add(PrintableString<PrintOneCharacterAtATime>("Hello World!"));
     doc.add(PrintableString<PrintAllAtOnce>("Hello World!"));
     REQUIRE(doc.size() == 2);
     CHECK(doc[0] == "Hello World!");
     CHECK(doc[1] == "Hello World!");
-    CHECK(doc.memoryUsage() == sizeofArray(2) + sizeofString(12));
+    CHECK(allocator.log() == AllocatorLog()
+                                 << AllocatorLog::Allocate(sizeofPool())
+                                 << AllocatorLog::Allocate(sizeofString(31))
+                                 << AllocatorLog::Reallocate(sizeofString(31),
+                                                             sizeofString(12))
+                                 << AllocatorLog::Allocate(sizeofString(31))
+                                 << AllocatorLog::Deallocate(sizeofString(31)));
   }
 }

文件差異過大導致無法顯示
+ 501 - 64
extras/tests/MsgPackDeserializer/filter.cpp


+ 0 - 6
src/ArduinoJson/Array/JsonArray.hpp

@@ -145,12 +145,6 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
     return data_ != 0;
   }
 
-  // Returns the number of bytes occupied by the array.
-  // https://arduinojson.org/v6/api/jsonarray/memoryusage/
-  FORCE_INLINE size_t memoryUsage() const {
-    return data_ ? data_->memoryUsage(resources_) : 0;
-  }
-
   // Returns the depth (nesting level) of the array.
   // https://arduinojson.org/v6/api/jsonarray/nesting/
   FORCE_INLINE size_t nesting() const {

+ 0 - 6
src/ArduinoJson/Array/JsonArrayConst.hpp

@@ -66,12 +66,6 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
     return data_ != 0;
   }
 
-  // Returns the number of bytes occupied by the array.
-  // https://arduinojson.org/v6/api/jsonarrayconst/memoryusage/
-  FORCE_INLINE size_t memoryUsage() const {
-    return data_ ? data_->memoryUsage(resources_) : 0;
-  }
-
   // Returns the depth (nesting level) of the array.
   // https://arduinojson.org/v6/api/jsonarrayconst/nesting/
   FORCE_INLINE size_t nesting() const {

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

@@ -88,7 +88,6 @@ class CollectionData {
     return iterator(resources->getSlot(head_), head_);
   }
 
-  size_t memoryUsage(const ResourceManager*) const;
   size_t size(const ResourceManager*) const;
   size_t nesting(const ResourceManager*) const;
 

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

@@ -105,17 +105,6 @@ inline void CollectionData::remove(iterator it, ResourceManager* resources) {
   releaseSlot({it.slot_, it.currentId_}, resources);
 }
 
-inline size_t CollectionData::memoryUsage(
-    const ResourceManager* resources) const {
-  size_t total = 0;
-  for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
-    total += sizeof(VariantSlot) + it->memoryUsage(resources);
-    if (it.ownsKey())
-      total += sizeofString(strlen(it.key()));
-  }
-  return total;
-}
-
 inline size_t CollectionData::nesting(const ResourceManager* resources) const {
   size_t maxChildNesting = 0;
   for (auto it = createIterator(resources); !it.done(); it.next(resources)) {

+ 0 - 6
src/ArduinoJson/Document/JsonDocument.hpp

@@ -128,12 +128,6 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
     return getSlot().isNull();
   }
 
-  // Returns the number of used bytes in the memory pool.
-  // https://arduinojson.org/v6/api/jsondocument/memoryusage/
-  size_t memoryUsage() const {
-    return resources_.size();
-  }
-
   // Returns trues if the memory pool was too small.
   // https://arduinojson.org/v6/api/jsondocument/overflowed/
   bool overflowed() const {

+ 0 - 6
src/ArduinoJson/Object/JsonObject.hpp

@@ -53,12 +53,6 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
     return data_ != 0;
   }
 
-  // Returns the number of bytes occupied by the object.
-  // https://arduinojson.org/v6/api/jsonobject/memoryusage/
-  FORCE_INLINE size_t memoryUsage() const {
-    return data_ ? data_->memoryUsage(resources_) : 0;
-  }
-
   // Returns the depth (nesting level) of the object.
   // https://arduinojson.org/v6/api/jsonobject/nesting/
   FORCE_INLINE size_t nesting() const {

+ 0 - 6
src/ArduinoJson/Object/JsonObjectConst.hpp

@@ -42,12 +42,6 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
     return data_ != 0;
   }
 
-  // Returns the number of bytes occupied by the object.
-  // https://arduinojson.org/v6/api/jsonobjectconst/memoryusage/
-  FORCE_INLINE size_t memoryUsage() const {
-    return data_ ? data_->memoryUsage(resources_) : 0;
-  }
-
   // Returns the depth (nesting level) of the object.
   // https://arduinojson.org/v6/api/jsonobjectconst/nesting/
   FORCE_INLINE size_t nesting() const {

+ 0 - 6
src/ArduinoJson/Variant/JsonVariantConst.hpp

@@ -47,12 +47,6 @@ class JsonVariantConst : public detail::VariantTag,
     return !data_;
   }
 
-  // Returns the number of bytes occupied by the value.
-  // https://arduinojson.org/v6/api/jsonvariantconst/memoryusage/
-  FORCE_INLINE size_t memoryUsage() const {
-    return data_ ? data_->memoryUsage(resources_) : 0;
-  }
-
   // Returns the depth (nesting level) of the value.
   // https://arduinojson.org/v6/api/jsonvariantconst/nesting/
   FORCE_INLINE size_t nesting() const {

+ 0 - 13
src/ArduinoJson/Variant/VariantData.hpp

@@ -274,19 +274,6 @@ class VariantData {
     return type() == VALUE_IS_LINKED_STRING || type() == VALUE_IS_OWNED_STRING;
   }
 
-  size_t memoryUsage(const ResourceManager* resources) const {
-    switch (type()) {
-      case VALUE_IS_OWNED_STRING:
-      case VALUE_IS_RAW_STRING:
-        return sizeofString(content_.asOwnedString->length);
-      case VALUE_IS_OBJECT:
-      case VALUE_IS_ARRAY:
-        return content_.asCollection.memoryUsage(resources);
-      default:
-        return 0;
-    }
-  }
-
   size_t nesting(const ResourceManager* resources) const {
     auto collection = asCollection();
     if (collection)

+ 0 - 7
src/ArduinoJson/Variant/VariantRefBase.hpp

@@ -130,13 +130,6 @@ class VariantRefBase : public VariantTag {
     return VariantData::size(getData(), getResourceManager());
   }
 
-  // Returns the number of bytes occupied by the value.
-  // https://arduinojson.org/v6/api/jsonvariant/memoryusage/
-  FORCE_INLINE size_t memoryUsage() const {
-    VariantData* data = getData();
-    return data ? data->memoryUsage(getResourceManager()) : 0;
-  }
-
   // Returns the depth (nesting level) of the value.
   // https://arduinojson.org/v6/api/jsonvariant/nesting/
   FORCE_INLINE size_t nesting() const {

部分文件因文件數量過多而無法顯示