forked from bblanchon/ArduinoJson
Store static string in a dedicated pool
This commit is contained in:
@@ -54,7 +54,7 @@ TEST_CASE("BasicJsonDocument") {
|
||||
doc["hello"] = "world";
|
||||
auto copy = doc;
|
||||
REQUIRE(copy.as<std::string>() == "{\"hello\":\"world\"}");
|
||||
REQUIRE(allocatorLog == "AA");
|
||||
REQUIRE(allocatorLog == "AAAA");
|
||||
}
|
||||
|
||||
SECTION("capacity") {
|
||||
|
||||
@@ -275,6 +275,12 @@ inline size_t sizeofPool(
|
||||
return MemoryPool<VariantData>::slotsToBytes(n);
|
||||
}
|
||||
|
||||
inline size_t sizeofStaticStringPool(
|
||||
ArduinoJson::detail::SlotCount n = ARDUINOJSON_POOL_CAPACITY) {
|
||||
using namespace ArduinoJson::detail;
|
||||
return MemoryPool<const char*>::slotsToBytes(n);
|
||||
}
|
||||
|
||||
inline size_t sizeofStringBuffer(size_t iteration = 1) {
|
||||
// returns 31, 63, 127, 255, etc.
|
||||
auto capacity = ArduinoJson::detail::StringBuilder::initialCapacity;
|
||||
|
||||
@@ -56,6 +56,7 @@ TEST_CASE("JsonArray::add(T)") {
|
||||
REQUIRE(array[0].is<int>() == false);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -104,6 +104,8 @@ TEST_CASE("deserializeJson(MemberProxy)") {
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":\"world\",\"value\":[42]}");
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -825,7 +825,9 @@ TEST_CASE("shrink filter") {
|
||||
|
||||
deserializeJson(doc, "{}", DeserializationOption::Filter(filter));
|
||||
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Reallocate(sizeofPool(), sizeofObject(1)),
|
||||
});
|
||||
REQUIRE(spy.log() ==
|
||||
AllocatorLog{
|
||||
Reallocate(sizeofPool(), sizeofObject(1)),
|
||||
Reallocate(sizeofStaticStringPool(), sizeofStaticStringPool(1)),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ TEST_CASE("ElementProxy::add()") {
|
||||
REQUIRE(doc.as<std::string>() == "[[\"world\"]]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ TEST_CASE("MemberProxy::add()") {
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":[42]}");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -34,6 +35,7 @@ TEST_CASE("MemberProxy::add()") {
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":[\"world\"]}");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -44,6 +46,7 @@ TEST_CASE("MemberProxy::add()") {
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":[\"world\"]}");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
@@ -55,8 +58,8 @@ TEST_CASE("MemberProxy::add()") {
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":[\"world\"]}");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@@ -71,6 +74,7 @@ TEST_CASE("MemberProxy::add()") {
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":[\"world\"]}");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
@@ -399,7 +403,7 @@ TEST_CASE("MemberProxy under memory constraints") {
|
||||
}
|
||||
|
||||
SECTION("value slot allocation fails") {
|
||||
timebomb.setCountdown(1);
|
||||
timebomb.setCountdown(2);
|
||||
|
||||
// fill the pool entirely, but leave one slot for the key
|
||||
doc["foo"][ARDUINOJSON_POOL_CAPACITY - 4] = 1;
|
||||
@@ -412,6 +416,7 @@ TEST_CASE("MemberProxy under memory constraints") {
|
||||
REQUIRE(doc.overflowed() == true);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
AllocateFail(sizeofPool()),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ TEST_CASE("JsonDocument::add(T)") {
|
||||
REQUIRE(doc.as<std::string>() == "[\"hello\"]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ TEST_CASE("JsonDocument constructor") {
|
||||
REQUIRE(doc2.as<std::string>() == "{\"hello\":\"world\"}");
|
||||
REQUIRE(spyingAllocator.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -85,6 +86,7 @@ TEST_CASE("JsonDocument constructor") {
|
||||
REQUIRE(doc2.as<std::string>() == "[\"hello\"]");
|
||||
REQUIRE(spyingAllocator.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,9 @@ TEST_CASE("JsonDocument::set()") {
|
||||
doc.set("example");
|
||||
|
||||
REQUIRE(doc.as<const char*>() == "example"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("const char*") {
|
||||
|
||||
@@ -75,7 +75,11 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
|
||||
doc.shrinkToFit();
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "hello");
|
||||
REQUIRE(spyingAllocator.log() == AllocatorLog{});
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog{
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
Reallocate(sizeofStaticStringPool(), sizeofStaticStringPool(1)),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("owned string") {
|
||||
@@ -110,7 +114,9 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
Reallocate(sizeofPool(), sizeofObject(1)),
|
||||
Reallocate(sizeofStaticStringPool(), sizeofStaticStringPool(1)),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -137,7 +143,9 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
Reallocate(sizeofPool(), sizeofArray(1)),
|
||||
Reallocate(sizeofStaticStringPool(), sizeofStaticStringPool(1)),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -164,20 +172,23 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
Reallocate(sizeofPool(), sizeofObject(1)),
|
||||
Reallocate(sizeofStaticStringPool(), sizeofStaticStringPool(2)),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("owned string in object") {
|
||||
doc["key"] = "abcdefg"_s;
|
||||
doc["key"_s] = "value"_s;
|
||||
|
||||
doc.shrinkToFit();
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"key\":\"abcdefg\"}");
|
||||
REQUIRE(doc.as<std::string>() == "{\"key\":\"value\"}");
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("abcdefg")),
|
||||
Allocate(sizeofString("key")),
|
||||
Allocate(sizeofString("value")),
|
||||
Reallocate(sizeofPool(), sizeofPool(2)),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -112,6 +112,7 @@ TEST_CASE("JsonDocument::operator[] key storage") {
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":0}");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -26,25 +26,12 @@ TEST_CASE("JsonObject::set()") {
|
||||
REQUIRE(obj2["hello"] == "world"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("copy local string value") {
|
||||
obj1["hello"] = "world"_s;
|
||||
spy.clearLog();
|
||||
|
||||
bool success = obj2.set(obj1);
|
||||
|
||||
REQUIRE(success == true);
|
||||
REQUIRE(obj2["hello"] == "world"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("copy local key") {
|
||||
obj1["hello"_s] = "world";
|
||||
SECTION("copy local string key and value") {
|
||||
obj1["hello"_s] = "world"_s;
|
||||
spy.clearLog();
|
||||
|
||||
bool success = obj2.set(obj1);
|
||||
@@ -54,6 +41,7 @@ TEST_CASE("JsonObject::set()") {
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -110,7 +98,7 @@ TEST_CASE("JsonObject::set()") {
|
||||
}
|
||||
|
||||
SECTION("copy fails in the middle of an array") {
|
||||
TimebombAllocator timebomb(1);
|
||||
TimebombAllocator timebomb(2);
|
||||
JsonDocument doc3(&timebomb);
|
||||
JsonObject obj3 = doc3.to<JsonObject>();
|
||||
|
||||
|
||||
@@ -102,21 +102,25 @@ TEST_CASE("JsonObject::operator[]") {
|
||||
REQUIRE(42 == obj[key]);
|
||||
}
|
||||
|
||||
SECTION("should not duplicate const char*") {
|
||||
SECTION("string literals") {
|
||||
obj["hello"] = "world";
|
||||
REQUIRE(spy.log() == AllocatorLog{Allocate(sizeofPool())});
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("should duplicate char* value") {
|
||||
obj["hello"] = const_cast<char*>("world");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("should duplicate char* key") {
|
||||
obj[const_cast<char*>("hello")] = "world";
|
||||
obj[const_cast<char*>("hello")] = 42;
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
@@ -136,12 +140,13 @@ TEST_CASE("JsonObject::operator[]") {
|
||||
obj["hello"] = "world"_s;
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("should duplicate std::string key") {
|
||||
obj["hello"_s] = "world";
|
||||
obj["hello"_s] = 42;
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
@@ -158,7 +163,7 @@ TEST_CASE("JsonObject::operator[]") {
|
||||
}
|
||||
|
||||
SECTION("should duplicate a non-static JsonString key") {
|
||||
obj[JsonString("hello", false)] = "world";
|
||||
obj[JsonString("hello", false)] = 42;
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
@@ -166,9 +171,10 @@ TEST_CASE("JsonObject::operator[]") {
|
||||
}
|
||||
|
||||
SECTION("should not duplicate a static JsonString key") {
|
||||
obj[JsonString("hello", true)] = "world";
|
||||
obj[JsonString("hello", true)] = 42;
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -38,13 +38,15 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
|
||||
REQUIRE(var1.as<std::string>() == "{\"value\":[42]}");
|
||||
}
|
||||
|
||||
SECTION("stores const char* by reference") {
|
||||
SECTION("stores string literals by pointer") {
|
||||
var1.set("hello!!");
|
||||
spyingAllocator.clearLog();
|
||||
|
||||
var2.set(var1);
|
||||
|
||||
REQUIRE(spyingAllocator.log() == AllocatorLog{});
|
||||
REQUIRE(spyingAllocator.log() == AllocatorLog{
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("stores char* by copy") {
|
||||
|
||||
@@ -23,7 +23,9 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
|
||||
REQUIRE(result == true);
|
||||
CHECK(variant ==
|
||||
"hello"_s); // linked string cannot contain '\0' at the moment
|
||||
CHECK(spy.log() == AllocatorLog{});
|
||||
CHECK(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("const char*") {
|
||||
@@ -137,7 +139,9 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(variant == "world"); // stores by pointer
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("non-static JsonString") {
|
||||
|
||||
@@ -104,6 +104,8 @@ TEST_CASE("deserializeMsgPack(MemberProxy)") {
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":\"world\",\"value\":[42]}");
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofStaticStringPool()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user