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";
|
doc["hello"] = "world";
|
||||||
auto copy = doc;
|
auto copy = doc;
|
||||||
REQUIRE(copy.as<std::string>() == "{\"hello\":\"world\"}");
|
REQUIRE(copy.as<std::string>() == "{\"hello\":\"world\"}");
|
||||||
REQUIRE(allocatorLog == "AA");
|
REQUIRE(allocatorLog == "AAAA");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("capacity") {
|
SECTION("capacity") {
|
||||||
|
@ -275,6 +275,12 @@ inline size_t sizeofPool(
|
|||||||
return MemoryPool<VariantData>::slotsToBytes(n);
|
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) {
|
inline size_t sizeofStringBuffer(size_t iteration = 1) {
|
||||||
// returns 31, 63, 127, 255, etc.
|
// returns 31, 63, 127, 255, etc.
|
||||||
auto capacity = ArduinoJson::detail::StringBuilder::initialCapacity;
|
auto capacity = ArduinoJson::detail::StringBuilder::initialCapacity;
|
||||||
|
@ -56,6 +56,7 @@ TEST_CASE("JsonArray::add(T)") {
|
|||||||
REQUIRE(array[0].is<int>() == false);
|
REQUIRE(array[0].is<int>() == false);
|
||||||
REQUIRE(spy.log() == AllocatorLog{
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,6 +104,8 @@ TEST_CASE("deserializeJson(MemberProxy)") {
|
|||||||
|
|
||||||
REQUIRE(err == DeserializationError::Ok);
|
REQUIRE(err == DeserializationError::Ok);
|
||||||
REQUIRE(doc.as<std::string>() == "{\"hello\":\"world\",\"value\":[42]}");
|
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));
|
deserializeJson(doc, "{}", DeserializationOption::Filter(filter));
|
||||||
|
|
||||||
REQUIRE(spy.log() == AllocatorLog{
|
REQUIRE(spy.log() ==
|
||||||
Reallocate(sizeofPool(), sizeofObject(1)),
|
AllocatorLog{
|
||||||
});
|
Reallocate(sizeofPool(), sizeofObject(1)),
|
||||||
|
Reallocate(sizeofStaticStringPool(), sizeofStaticStringPool(1)),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ TEST_CASE("ElementProxy::add()") {
|
|||||||
REQUIRE(doc.as<std::string>() == "[[\"world\"]]");
|
REQUIRE(doc.as<std::string>() == "[[\"world\"]]");
|
||||||
REQUIRE(spy.log() == AllocatorLog{
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ TEST_CASE("MemberProxy::add()") {
|
|||||||
REQUIRE(doc.as<std::string>() == "{\"hello\":[42]}");
|
REQUIRE(doc.as<std::string>() == "{\"hello\":[42]}");
|
||||||
REQUIRE(spy.log() == AllocatorLog{
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,6 +35,7 @@ TEST_CASE("MemberProxy::add()") {
|
|||||||
REQUIRE(doc.as<std::string>() == "{\"hello\":[\"world\"]}");
|
REQUIRE(doc.as<std::string>() == "{\"hello\":[\"world\"]}");
|
||||||
REQUIRE(spy.log() == AllocatorLog{
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,6 +46,7 @@ TEST_CASE("MemberProxy::add()") {
|
|||||||
REQUIRE(doc.as<std::string>() == "{\"hello\":[\"world\"]}");
|
REQUIRE(doc.as<std::string>() == "{\"hello\":[\"world\"]}");
|
||||||
REQUIRE(spy.log() == AllocatorLog{
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
Allocate(sizeofString("world")),
|
Allocate(sizeofString("world")),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -55,8 +58,8 @@ TEST_CASE("MemberProxy::add()") {
|
|||||||
REQUIRE(doc.as<std::string>() == "{\"hello\":[\"world\"]}");
|
REQUIRE(doc.as<std::string>() == "{\"hello\":[\"world\"]}");
|
||||||
REQUIRE(spy.log() == AllocatorLog{
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
Allocate(sizeofString("world")),
|
Allocate(sizeofString("world")),
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,6 +74,7 @@ TEST_CASE("MemberProxy::add()") {
|
|||||||
REQUIRE(doc.as<std::string>() == "{\"hello\":[\"world\"]}");
|
REQUIRE(doc.as<std::string>() == "{\"hello\":[\"world\"]}");
|
||||||
REQUIRE(spy.log() == AllocatorLog{
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
Allocate(sizeofString("world")),
|
Allocate(sizeofString("world")),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -399,7 +403,7 @@ TEST_CASE("MemberProxy under memory constraints") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SECTION("value slot allocation fails") {
|
SECTION("value slot allocation fails") {
|
||||||
timebomb.setCountdown(1);
|
timebomb.setCountdown(2);
|
||||||
|
|
||||||
// fill the pool entirely, but leave one slot for the key
|
// fill the pool entirely, but leave one slot for the key
|
||||||
doc["foo"][ARDUINOJSON_POOL_CAPACITY - 4] = 1;
|
doc["foo"][ARDUINOJSON_POOL_CAPACITY - 4] = 1;
|
||||||
@ -412,6 +416,7 @@ TEST_CASE("MemberProxy under memory constraints") {
|
|||||||
REQUIRE(doc.overflowed() == true);
|
REQUIRE(doc.overflowed() == true);
|
||||||
REQUIRE(spy.log() == AllocatorLog{
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
AllocateFail(sizeofPool()),
|
AllocateFail(sizeofPool()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ TEST_CASE("JsonDocument::add(T)") {
|
|||||||
REQUIRE(doc.as<std::string>() == "[\"hello\"]");
|
REQUIRE(doc.as<std::string>() == "[\"hello\"]");
|
||||||
REQUIRE(spy.log() == AllocatorLog{
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ TEST_CASE("JsonDocument constructor") {
|
|||||||
REQUIRE(doc2.as<std::string>() == "{\"hello\":\"world\"}");
|
REQUIRE(doc2.as<std::string>() == "{\"hello\":\"world\"}");
|
||||||
REQUIRE(spyingAllocator.log() == AllocatorLog{
|
REQUIRE(spyingAllocator.log() == AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,6 +86,7 @@ TEST_CASE("JsonDocument constructor") {
|
|||||||
REQUIRE(doc2.as<std::string>() == "[\"hello\"]");
|
REQUIRE(doc2.as<std::string>() == "[\"hello\"]");
|
||||||
REQUIRE(spyingAllocator.log() == AllocatorLog{
|
REQUIRE(spyingAllocator.log() == AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,9 @@ TEST_CASE("JsonDocument::set()") {
|
|||||||
doc.set("example");
|
doc.set("example");
|
||||||
|
|
||||||
REQUIRE(doc.as<const char*>() == "example"_s);
|
REQUIRE(doc.as<const char*>() == "example"_s);
|
||||||
REQUIRE(spy.log() == AllocatorLog{});
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("const char*") {
|
SECTION("const char*") {
|
||||||
|
@ -75,7 +75,11 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
|
|||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
|
|
||||||
REQUIRE(doc.as<std::string>() == "hello");
|
REQUIRE(doc.as<std::string>() == "hello");
|
||||||
REQUIRE(spyingAllocator.log() == AllocatorLog{});
|
REQUIRE(spyingAllocator.log() ==
|
||||||
|
AllocatorLog{
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
|
Reallocate(sizeofStaticStringPool(), sizeofStaticStringPool(1)),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("owned string") {
|
SECTION("owned string") {
|
||||||
@ -110,7 +114,9 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
|
|||||||
REQUIRE(spyingAllocator.log() ==
|
REQUIRE(spyingAllocator.log() ==
|
||||||
AllocatorLog{
|
AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
Reallocate(sizeofPool(), sizeofObject(1)),
|
Reallocate(sizeofPool(), sizeofObject(1)),
|
||||||
|
Reallocate(sizeofStaticStringPool(), sizeofStaticStringPool(1)),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +143,9 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
|
|||||||
REQUIRE(spyingAllocator.log() ==
|
REQUIRE(spyingAllocator.log() ==
|
||||||
AllocatorLog{
|
AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
Reallocate(sizeofPool(), sizeofArray(1)),
|
Reallocate(sizeofPool(), sizeofArray(1)),
|
||||||
|
Reallocate(sizeofStaticStringPool(), sizeofStaticStringPool(1)),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,20 +172,23 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
|
|||||||
REQUIRE(spyingAllocator.log() ==
|
REQUIRE(spyingAllocator.log() ==
|
||||||
AllocatorLog{
|
AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
Reallocate(sizeofPool(), sizeofObject(1)),
|
Reallocate(sizeofPool(), sizeofObject(1)),
|
||||||
|
Reallocate(sizeofStaticStringPool(), sizeofStaticStringPool(2)),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("owned string in object") {
|
SECTION("owned string in object") {
|
||||||
doc["key"] = "abcdefg"_s;
|
doc["key"_s] = "value"_s;
|
||||||
|
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
|
|
||||||
REQUIRE(doc.as<std::string>() == "{\"key\":\"abcdefg\"}");
|
REQUIRE(doc.as<std::string>() == "{\"key\":\"value\"}");
|
||||||
REQUIRE(spyingAllocator.log() ==
|
REQUIRE(spyingAllocator.log() ==
|
||||||
AllocatorLog{
|
AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
Allocate(sizeofString("abcdefg")),
|
Allocate(sizeofString("key")),
|
||||||
|
Allocate(sizeofString("value")),
|
||||||
Reallocate(sizeofPool(), sizeofPool(2)),
|
Reallocate(sizeofPool(), sizeofPool(2)),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -112,6 +112,7 @@ TEST_CASE("JsonDocument::operator[] key storage") {
|
|||||||
REQUIRE(doc.as<std::string>() == "{\"hello\":0}");
|
REQUIRE(doc.as<std::string>() == "{\"hello\":0}");
|
||||||
REQUIRE(spy.log() == AllocatorLog{
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,25 +26,12 @@ TEST_CASE("JsonObject::set()") {
|
|||||||
REQUIRE(obj2["hello"] == "world"_s);
|
REQUIRE(obj2["hello"] == "world"_s);
|
||||||
REQUIRE(spy.log() == AllocatorLog{
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("copy local string value") {
|
SECTION("copy local string key and value") {
|
||||||
obj1["hello"] = "world"_s;
|
obj1["hello"_s] = "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";
|
|
||||||
spy.clearLog();
|
spy.clearLog();
|
||||||
|
|
||||||
bool success = obj2.set(obj1);
|
bool success = obj2.set(obj1);
|
||||||
@ -54,6 +41,7 @@ TEST_CASE("JsonObject::set()") {
|
|||||||
REQUIRE(spy.log() == AllocatorLog{
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
Allocate(sizeofString("hello")),
|
Allocate(sizeofString("hello")),
|
||||||
|
Allocate(sizeofString("world")),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +98,7 @@ TEST_CASE("JsonObject::set()") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SECTION("copy fails in the middle of an array") {
|
SECTION("copy fails in the middle of an array") {
|
||||||
TimebombAllocator timebomb(1);
|
TimebombAllocator timebomb(2);
|
||||||
JsonDocument doc3(&timebomb);
|
JsonDocument doc3(&timebomb);
|
||||||
JsonObject obj3 = doc3.to<JsonObject>();
|
JsonObject obj3 = doc3.to<JsonObject>();
|
||||||
|
|
||||||
|
@ -102,21 +102,25 @@ TEST_CASE("JsonObject::operator[]") {
|
|||||||
REQUIRE(42 == obj[key]);
|
REQUIRE(42 == obj[key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("should not duplicate const char*") {
|
SECTION("string literals") {
|
||||||
obj["hello"] = "world";
|
obj["hello"] = "world";
|
||||||
REQUIRE(spy.log() == AllocatorLog{Allocate(sizeofPool())});
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
|
Allocate(sizeofPool()),
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("should duplicate char* value") {
|
SECTION("should duplicate char* value") {
|
||||||
obj["hello"] = const_cast<char*>("world");
|
obj["hello"] = const_cast<char*>("world");
|
||||||
REQUIRE(spy.log() == AllocatorLog{
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
Allocate(sizeofString("world")),
|
Allocate(sizeofString("world")),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("should duplicate char* key") {
|
SECTION("should duplicate char* key") {
|
||||||
obj[const_cast<char*>("hello")] = "world";
|
obj[const_cast<char*>("hello")] = 42;
|
||||||
REQUIRE(spy.log() == AllocatorLog{
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
Allocate(sizeofString("hello")),
|
Allocate(sizeofString("hello")),
|
||||||
@ -136,12 +140,13 @@ TEST_CASE("JsonObject::operator[]") {
|
|||||||
obj["hello"] = "world"_s;
|
obj["hello"] = "world"_s;
|
||||||
REQUIRE(spy.log() == AllocatorLog{
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
Allocate(sizeofString("world")),
|
Allocate(sizeofString("world")),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("should duplicate std::string key") {
|
SECTION("should duplicate std::string key") {
|
||||||
obj["hello"_s] = "world";
|
obj["hello"_s] = 42;
|
||||||
REQUIRE(spy.log() == AllocatorLog{
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
Allocate(sizeofString("hello")),
|
Allocate(sizeofString("hello")),
|
||||||
@ -158,7 +163,7 @@ TEST_CASE("JsonObject::operator[]") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SECTION("should duplicate a non-static JsonString key") {
|
SECTION("should duplicate a non-static JsonString key") {
|
||||||
obj[JsonString("hello", false)] = "world";
|
obj[JsonString("hello", false)] = 42;
|
||||||
REQUIRE(spy.log() == AllocatorLog{
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
Allocate(sizeofString("hello")),
|
Allocate(sizeofString("hello")),
|
||||||
@ -166,9 +171,10 @@ TEST_CASE("JsonObject::operator[]") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SECTION("should not duplicate a static JsonString key") {
|
SECTION("should not duplicate a static JsonString key") {
|
||||||
obj[JsonString("hello", true)] = "world";
|
obj[JsonString("hello", true)] = 42;
|
||||||
REQUIRE(spy.log() == AllocatorLog{
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
Allocate(sizeofPool()),
|
Allocate(sizeofPool()),
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,13 +38,15 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
|
|||||||
REQUIRE(var1.as<std::string>() == "{\"value\":[42]}");
|
REQUIRE(var1.as<std::string>() == "{\"value\":[42]}");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("stores const char* by reference") {
|
SECTION("stores string literals by pointer") {
|
||||||
var1.set("hello!!");
|
var1.set("hello!!");
|
||||||
spyingAllocator.clearLog();
|
spyingAllocator.clearLog();
|
||||||
|
|
||||||
var2.set(var1);
|
var2.set(var1);
|
||||||
|
|
||||||
REQUIRE(spyingAllocator.log() == AllocatorLog{});
|
REQUIRE(spyingAllocator.log() == AllocatorLog{
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("stores char* by copy") {
|
SECTION("stores char* by copy") {
|
||||||
|
@ -23,7 +23,9 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
|
|||||||
REQUIRE(result == true);
|
REQUIRE(result == true);
|
||||||
CHECK(variant ==
|
CHECK(variant ==
|
||||||
"hello"_s); // linked string cannot contain '\0' at the moment
|
"hello"_s); // linked string cannot contain '\0' at the moment
|
||||||
CHECK(spy.log() == AllocatorLog{});
|
CHECK(spy.log() == AllocatorLog{
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("const char*") {
|
SECTION("const char*") {
|
||||||
@ -137,7 +139,9 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
|
|||||||
|
|
||||||
REQUIRE(result == true);
|
REQUIRE(result == true);
|
||||||
REQUIRE(variant == "world"); // stores by pointer
|
REQUIRE(variant == "world"); // stores by pointer
|
||||||
REQUIRE(spy.log() == AllocatorLog{});
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("non-static JsonString") {
|
SECTION("non-static JsonString") {
|
||||||
|
@ -104,6 +104,8 @@ TEST_CASE("deserializeMsgPack(MemberProxy)") {
|
|||||||
|
|
||||||
REQUIRE(err == DeserializationError::Ok);
|
REQUIRE(err == DeserializationError::Ok);
|
||||||
REQUIRE(doc.as<std::string>() == "{\"hello\":\"world\",\"value\":[42]}");
|
REQUIRE(doc.as<std::string>() == "{\"hello\":\"world\",\"value\":[42]}");
|
||||||
REQUIRE(spy.log() == AllocatorLog{});
|
REQUIRE(spy.log() == AllocatorLog{
|
||||||
|
Allocate(sizeofStaticStringPool()),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,11 @@ class Slot {
|
|||||||
return ptr_;
|
return ptr_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
T& operator*() const {
|
||||||
|
ARDUINOJSON_ASSERT(ptr_ != nullptr);
|
||||||
|
return *ptr_;
|
||||||
|
}
|
||||||
|
|
||||||
T* operator->() const {
|
T* operator->() const {
|
||||||
ARDUINOJSON_ASSERT(ptr_ != nullptr);
|
ARDUINOJSON_ASSERT(ptr_ != nullptr);
|
||||||
return ptr_;
|
return ptr_;
|
||||||
|
@ -34,6 +34,7 @@ class ResourceManager {
|
|||||||
~ResourceManager() {
|
~ResourceManager() {
|
||||||
stringPool_.clear(allocator_);
|
stringPool_.clear(allocator_);
|
||||||
variantPools_.clear(allocator_);
|
variantPools_.clear(allocator_);
|
||||||
|
staticStringsPools_.clear(allocator_);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceManager(const ResourceManager&) = delete;
|
ResourceManager(const ResourceManager&) = delete;
|
||||||
@ -42,6 +43,7 @@ class ResourceManager {
|
|||||||
friend void swap(ResourceManager& a, ResourceManager& b) {
|
friend void swap(ResourceManager& a, ResourceManager& b) {
|
||||||
swap(a.stringPool_, b.stringPool_);
|
swap(a.stringPool_, b.stringPool_);
|
||||||
swap(a.variantPools_, b.variantPools_);
|
swap(a.variantPools_, b.variantPools_);
|
||||||
|
swap(a.staticStringsPools_, b.staticStringsPools_);
|
||||||
swap_(a.allocator_, b.allocator_);
|
swap_(a.allocator_, b.allocator_);
|
||||||
swap_(a.overflowed_, b.overflowed_);
|
swap_(a.overflowed_, b.overflowed_);
|
||||||
}
|
}
|
||||||
@ -111,14 +113,28 @@ class ResourceManager {
|
|||||||
stringPool_.dereference(s, allocator_);
|
stringPool_.dereference(s, allocator_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SlotId saveStaticString(const char* s) {
|
||||||
|
auto slot = staticStringsPools_.allocSlot(allocator_);
|
||||||
|
if (!slot)
|
||||||
|
return NULL_SLOT;
|
||||||
|
*slot = s;
|
||||||
|
return slot.id();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* getStaticString(SlotId id) const {
|
||||||
|
return *staticStringsPools_.getSlot(id);
|
||||||
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
variantPools_.clear(allocator_);
|
variantPools_.clear(allocator_);
|
||||||
overflowed_ = false;
|
overflowed_ = false;
|
||||||
stringPool_.clear(allocator_);
|
stringPool_.clear(allocator_);
|
||||||
|
staticStringsPools_.clear(allocator_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void shrinkToFit() {
|
void shrinkToFit() {
|
||||||
variantPools_.shrinkToFit(allocator_);
|
variantPools_.shrinkToFit(allocator_);
|
||||||
|
staticStringsPools_.shrinkToFit(allocator_);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -126,6 +142,7 @@ class ResourceManager {
|
|||||||
bool overflowed_;
|
bool overflowed_;
|
||||||
StringPool stringPool_;
|
StringPool stringPool_;
|
||||||
MemoryPoolList<SlotData> variantPools_;
|
MemoryPoolList<SlotData> variantPools_;
|
||||||
|
MemoryPoolList<const char*> staticStringsPools_;
|
||||||
};
|
};
|
||||||
|
|
||||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
|
@ -18,7 +18,7 @@ class JsonPair {
|
|||||||
JsonPair(detail::ObjectData::iterator iterator,
|
JsonPair(detail::ObjectData::iterator iterator,
|
||||||
detail::ResourceManager* resources) {
|
detail::ResourceManager* resources) {
|
||||||
if (!iterator.done()) {
|
if (!iterator.done()) {
|
||||||
key_ = iterator->asString();
|
key_ = iterator->asString(resources);
|
||||||
iterator.next(resources);
|
iterator.next(resources);
|
||||||
value_ = JsonVariant(iterator.data(), resources);
|
value_ = JsonVariant(iterator.data(), resources);
|
||||||
}
|
}
|
||||||
@ -46,7 +46,7 @@ class JsonPairConst {
|
|||||||
JsonPairConst(detail::ObjectData::iterator iterator,
|
JsonPairConst(detail::ObjectData::iterator iterator,
|
||||||
const detail::ResourceManager* resources) {
|
const detail::ResourceManager* resources) {
|
||||||
if (!iterator.done()) {
|
if (!iterator.done()) {
|
||||||
key_ = iterator->asString();
|
key_ = iterator->asString(resources);
|
||||||
iterator.next(resources);
|
iterator.next(resources);
|
||||||
value_ = JsonVariantConst(iterator.data(), resources);
|
value_ = JsonVariantConst(iterator.data(), resources);
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ inline ObjectData::iterator ObjectData::findKey(
|
|||||||
return iterator();
|
return iterator();
|
||||||
bool isKey = true;
|
bool isKey = true;
|
||||||
for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
|
for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
|
||||||
if (isKey && stringEquals(key, adaptString(it->asString())))
|
if (isKey && stringEquals(key, adaptString(it->asString(resources))))
|
||||||
return it;
|
return it;
|
||||||
isKey = !isKey;
|
isKey = !isKey;
|
||||||
}
|
}
|
||||||
|
@ -160,7 +160,7 @@ struct Converter<const char*> : private detail::VariantAttorney {
|
|||||||
|
|
||||||
static const char* fromJson(JsonVariantConst src) {
|
static const char* fromJson(JsonVariantConst src) {
|
||||||
auto data = getData(src);
|
auto data = getData(src);
|
||||||
return data ? data->asString().c_str() : 0;
|
return data ? data->asString(getResourceManager(src)).c_str() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool checkJson(JsonVariantConst src) {
|
static bool checkJson(JsonVariantConst src) {
|
||||||
@ -178,7 +178,7 @@ struct Converter<JsonString> : private detail::VariantAttorney {
|
|||||||
|
|
||||||
static JsonString fromJson(JsonVariantConst src) {
|
static JsonString fromJson(JsonVariantConst src) {
|
||||||
auto data = getData(src);
|
auto data = getData(src);
|
||||||
return data ? data->asString() : JsonString();
|
return data ? data->asString(getResourceManager(src)) : JsonString();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool checkJson(JsonVariantConst src) {
|
static bool checkJson(JsonVariantConst src) {
|
||||||
|
@ -53,13 +53,10 @@ union VariantContent {
|
|||||||
bool asBoolean;
|
bool asBoolean;
|
||||||
uint32_t asUint32;
|
uint32_t asUint32;
|
||||||
int32_t asInt32;
|
int32_t asInt32;
|
||||||
#if ARDUINOJSON_USE_EXTENSIONS
|
|
||||||
SlotId asSlotId;
|
SlotId asSlotId;
|
||||||
#endif
|
|
||||||
ArrayData asArray;
|
ArrayData asArray;
|
||||||
ObjectData asObject;
|
ObjectData asObject;
|
||||||
CollectionData asCollection;
|
CollectionData asCollection;
|
||||||
const char* asLinkedString;
|
|
||||||
struct StringNode* asOwnedString;
|
struct StringNode* asOwnedString;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ class VariantData {
|
|||||||
return visit.visit(content_.asObject);
|
return visit.visit(content_.asObject);
|
||||||
|
|
||||||
case VariantType::LinkedString:
|
case VariantType::LinkedString:
|
||||||
return visit.visit(JsonString(content_.asLinkedString, true));
|
return visit.visit(JsonString(asLinkedString(resources), true));
|
||||||
|
|
||||||
case VariantType::OwnedString:
|
case VariantType::OwnedString:
|
||||||
return visit.visit(JsonString(content_.asOwnedString->data,
|
return visit.visit(JsonString(content_.asOwnedString->data,
|
||||||
@ -200,7 +200,7 @@ class VariantData {
|
|||||||
return static_cast<T>(extension->asInt64);
|
return static_cast<T>(extension->asInt64);
|
||||||
#endif
|
#endif
|
||||||
case VariantType::LinkedString:
|
case VariantType::LinkedString:
|
||||||
str = content_.asLinkedString;
|
str = asLinkedString(resources);
|
||||||
break;
|
break;
|
||||||
case VariantType::OwnedString:
|
case VariantType::OwnedString:
|
||||||
str = content_.asOwnedString->data;
|
str = content_.asOwnedString->data;
|
||||||
@ -242,7 +242,7 @@ class VariantData {
|
|||||||
return convertNumber<T>(extension->asInt64);
|
return convertNumber<T>(extension->asInt64);
|
||||||
#endif
|
#endif
|
||||||
case VariantType::LinkedString:
|
case VariantType::LinkedString:
|
||||||
str = content_.asLinkedString;
|
str = asLinkedString(resources);
|
||||||
break;
|
break;
|
||||||
case VariantType::OwnedString:
|
case VariantType::OwnedString:
|
||||||
str = content_.asOwnedString->data;
|
str = content_.asOwnedString->data;
|
||||||
@ -279,10 +279,12 @@ class VariantData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonString asString() const {
|
const char* asLinkedString(const ResourceManager* resources) const;
|
||||||
|
|
||||||
|
JsonString asString(const ResourceManager* resources) const {
|
||||||
switch (type_) {
|
switch (type_) {
|
||||||
case VariantType::LinkedString:
|
case VariantType::LinkedString:
|
||||||
return JsonString(content_.asLinkedString, true);
|
return JsonString(asLinkedString(resources), true);
|
||||||
case VariantType::OwnedString:
|
case VariantType::OwnedString:
|
||||||
return JsonString(content_.asOwnedString->data,
|
return JsonString(content_.asOwnedString->data,
|
||||||
content_.asOwnedString->length);
|
content_.asOwnedString->length);
|
||||||
@ -502,12 +504,7 @@ class VariantData {
|
|||||||
var->setString(value, resources);
|
var->setString(value, resources);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLinkedString(const char* s) {
|
bool setLinkedString(const char* s, ResourceManager* resources);
|
||||||
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
|
|
||||||
ARDUINOJSON_ASSERT(s);
|
|
||||||
type_ = VariantType::LinkedString;
|
|
||||||
content_.asLinkedString = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setOwnedString(StringNode* s) {
|
void setOwnedString(StringNode* s) {
|
||||||
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
|
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
|
||||||
|
@ -18,6 +18,20 @@ inline void VariantData::setRawString(SerializedValue<T> value,
|
|||||||
setRawString(dup);
|
setRawString(dup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool VariantData::setLinkedString(const char* s,
|
||||||
|
ResourceManager* resources) {
|
||||||
|
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
|
||||||
|
ARDUINOJSON_ASSERT(s);
|
||||||
|
|
||||||
|
auto slotId = resources->saveStaticString(s);
|
||||||
|
if (slotId == NULL_SLOT)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
type_ = VariantType::LinkedString;
|
||||||
|
content_.asSlotId = slotId;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename TAdaptedString>
|
template <typename TAdaptedString>
|
||||||
inline bool VariantData::setString(TAdaptedString value,
|
inline bool VariantData::setString(TAdaptedString value,
|
||||||
ResourceManager* resources) {
|
ResourceManager* resources) {
|
||||||
@ -26,10 +40,8 @@ inline bool VariantData::setString(TAdaptedString value,
|
|||||||
if (value.isNull())
|
if (value.isNull())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (value.isStatic()) {
|
if (value.isStatic())
|
||||||
setLinkedString(value.data());
|
return setLinkedString(value.data(), resources);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto dup = resources->saveString(value);
|
auto dup = resources->saveString(value);
|
||||||
if (dup) {
|
if (dup) {
|
||||||
@ -65,6 +77,12 @@ inline const VariantExtension* VariantData::getExtension(
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
inline const char* VariantData::asLinkedString(
|
||||||
|
const ResourceManager* resources) const {
|
||||||
|
ARDUINOJSON_ASSERT(type_ == VariantType::LinkedString);
|
||||||
|
return resources->getStaticString(content_.asSlotId);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
enable_if_t<sizeof(T) == 8, bool> VariantData::setFloat(
|
enable_if_t<sizeof(T) == 8, bool> VariantData::setFloat(
|
||||||
T value, ResourceManager* resources) {
|
T value, ResourceManager* resources) {
|
||||||
|
Reference in New Issue
Block a user