DynamicJsonDocument reallocates memory pool is it's too small

This commit is contained in:
Benoit Blanchon
2018-12-07 10:38:58 +01:00
parent b77b203935
commit e20c47c57b
3 changed files with 103 additions and 60 deletions

View File

@ -13,36 +13,48 @@ namespace ARDUINOJSON_NAMESPACE {
class DynamicJsonDocument : public JsonDocument {
public:
DynamicJsonDocument(size_t capa = ARDUINOJSON_DEFAULT_POOL_SIZE)
: JsonDocument(alloc(capa), addPadding(capa)) {}
: JsonDocument(allocPool(addPadding(capa))) {}
DynamicJsonDocument(const DynamicJsonDocument& src)
: JsonDocument(alloc(src.memoryUsage()), addPadding(src.memoryUsage())) {
: JsonDocument(allocPool(src.capacity())) {
copy(src);
}
DynamicJsonDocument(const JsonDocument& src)
: JsonDocument(alloc(src.memoryUsage()), addPadding(src.memoryUsage())) {
: JsonDocument(allocPool(src.capacity())) {
copy(src);
}
~DynamicJsonDocument() {
free(memoryPool().buffer());
freePool();
}
DynamicJsonDocument& operator=(const DynamicJsonDocument& src) {
reallocPoolIfTooSmall(src.memoryUsage());
copy(src);
return *this;
}
template <typename T>
DynamicJsonDocument& operator=(const JsonDocument& src) {
reallocPoolIfTooSmall(src.memoryUsage());
copy(src);
return *this;
}
private:
static char* alloc(size_t capa) {
return reinterpret_cast<char*>(malloc(addPadding(capa)));
MemoryPool allocPool(size_t capa) {
return MemoryPool(reinterpret_cast<char*>(malloc(capa)), capa);
}
void reallocPoolIfTooSmall(size_t requiredSize) {
if (requiredSize <= capacity()) return;
freePool();
replacePool(allocPool(addPadding(requiredSize)));
}
void freePool() {
free(memoryPool().buffer());
}
};

View File

@ -63,6 +63,9 @@ class JsonDocument : public Visitable {
}
protected:
JsonDocument(MemoryPool pool)
: nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT), _pool(pool) {}
JsonDocument(char* buf, size_t capa)
: nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT), _pool(buf, capa) {}
@ -71,6 +74,10 @@ class JsonDocument : public Visitable {
to<VariantRef>().set(src.as<VariantRef>());
}
void replacePool(MemoryPool pool) {
_pool = pool;
}
private:
VariantRef getVariant() {
return VariantRef(&_pool, &_data);

View File

@ -51,60 +51,6 @@ TEST_CASE("DynamicJsonDocument") {
}
}
SECTION("Copy constructor") {
deserializeJson(doc, "{\"hello\":\"world\"}");
doc.nestingLimit = 42;
DynamicJsonDocument doc2 = doc;
std::string json;
serializeJson(doc2, json);
REQUIRE(json == "{\"hello\":\"world\"}");
REQUIRE(doc2.nestingLimit == 42);
}
SECTION("Copy assignment") {
DynamicJsonDocument doc2;
deserializeJson(doc2, "{\"hello\":\"world\"}");
doc2.nestingLimit = 42;
doc = doc2;
std::string json;
serializeJson(doc, json);
REQUIRE(json == "{\"hello\":\"world\"}");
REQUIRE(doc.nestingLimit == 42);
}
SECTION("Construct from StaticJsonDocument") {
StaticJsonDocument<200> sdoc;
deserializeJson(sdoc, "{\"hello\":\"world\"}");
sdoc.nestingLimit = 42;
DynamicJsonDocument ddoc = sdoc;
std::string json;
serializeJson(ddoc, json);
REQUIRE(json == "{\"hello\":\"world\"}");
REQUIRE(ddoc.nestingLimit == 42);
}
SECTION("Assign from StaticJsonDocument") {
DynamicJsonDocument ddoc;
ddoc.to<JsonVariant>().set(666);
StaticJsonDocument<200> sdoc;
deserializeJson(sdoc, "{\"hello\":\"world\"}");
sdoc.nestingLimit = 42;
ddoc = sdoc;
std::string json;
serializeJson(ddoc, json);
REQUIRE(json == "{\"hello\":\"world\"}");
REQUIRE(ddoc.nestingLimit == 42);
}
SECTION("memoryUsage()") {
SECTION("Increases after adding value to array") {
JsonArray arr = doc.to<JsonArray>();
@ -127,3 +73,81 @@ TEST_CASE("DynamicJsonDocument") {
}
}
}
TEST_CASE("DynamicJsonDocument copies") {
SECTION("Copy constructor") {
DynamicJsonDocument doc1(1234);
deserializeJson(doc1, "{\"hello\":\"world\"}");
doc1.nestingLimit = 42;
DynamicJsonDocument doc2 = doc1;
std::string json;
serializeJson(doc2, json);
REQUIRE(json == "{\"hello\":\"world\"}");
REQUIRE(doc2.nestingLimit == 42);
REQUIRE(doc2.capacity() == doc1.capacity());
}
SECTION("Copy assignment preserves the buffer when capacity is sufficient") {
DynamicJsonDocument doc1(1234);
deserializeJson(doc1, "{\"hello\":\"world\"}");
doc1.nestingLimit = 42;
DynamicJsonDocument doc2(doc1.capacity());
doc2 = doc1;
std::string json;
serializeJson(doc2, json);
REQUIRE(json == "{\"hello\":\"world\"}");
REQUIRE(doc2.nestingLimit == 42);
REQUIRE(doc2.capacity() == doc1.capacity());
}
SECTION("Copy assignment realloc the buffer when capacity is insufficient") {
DynamicJsonDocument doc1(1234);
deserializeJson(doc1, "{\"hello\":\"world\"}");
doc1.nestingLimit = 42;
DynamicJsonDocument doc2(8);
REQUIRE(doc2.capacity() < doc1.memoryUsage());
doc2 = doc1;
REQUIRE(doc2.capacity() >= doc1.memoryUsage());
std::string json;
serializeJson(doc2, json);
REQUIRE(json == "{\"hello\":\"world\"}");
REQUIRE(doc2.nestingLimit == 42);
}
SECTION("Construct from StaticJsonDocument") {
StaticJsonDocument<200> sdoc;
deserializeJson(sdoc, "{\"hello\":\"world\"}");
sdoc.nestingLimit = 42;
DynamicJsonDocument ddoc = sdoc;
std::string json;
serializeJson(ddoc, json);
REQUIRE(json == "{\"hello\":\"world\"}");
REQUIRE(ddoc.nestingLimit == 42);
REQUIRE(ddoc.capacity() == sdoc.capacity());
}
SECTION("Assign from StaticJsonDocument") {
DynamicJsonDocument ddoc;
ddoc.to<JsonVariant>().set(666);
StaticJsonDocument<200> sdoc;
deserializeJson(sdoc, "{\"hello\":\"world\"}");
sdoc.nestingLimit = 42;
ddoc = sdoc;
std::string json;
serializeJson(ddoc, json);
REQUIRE(json == "{\"hello\":\"world\"}");
REQUIRE(ddoc.nestingLimit == 42);
}
}