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 { class DynamicJsonDocument : public JsonDocument {
public: public:
DynamicJsonDocument(size_t capa = ARDUINOJSON_DEFAULT_POOL_SIZE) DynamicJsonDocument(size_t capa = ARDUINOJSON_DEFAULT_POOL_SIZE)
: JsonDocument(alloc(capa), addPadding(capa)) {} : JsonDocument(allocPool(addPadding(capa))) {}
DynamicJsonDocument(const DynamicJsonDocument& src) DynamicJsonDocument(const DynamicJsonDocument& src)
: JsonDocument(alloc(src.memoryUsage()), addPadding(src.memoryUsage())) { : JsonDocument(allocPool(src.capacity())) {
copy(src); copy(src);
} }
DynamicJsonDocument(const JsonDocument& src) DynamicJsonDocument(const JsonDocument& src)
: JsonDocument(alloc(src.memoryUsage()), addPadding(src.memoryUsage())) { : JsonDocument(allocPool(src.capacity())) {
copy(src); copy(src);
} }
~DynamicJsonDocument() { ~DynamicJsonDocument() {
free(memoryPool().buffer()); freePool();
} }
DynamicJsonDocument& operator=(const DynamicJsonDocument& src) { DynamicJsonDocument& operator=(const DynamicJsonDocument& src) {
reallocPoolIfTooSmall(src.memoryUsage());
copy(src); copy(src);
return *this; return *this;
} }
template <typename T> template <typename T>
DynamicJsonDocument& operator=(const JsonDocument& src) { DynamicJsonDocument& operator=(const JsonDocument& src) {
reallocPoolIfTooSmall(src.memoryUsage());
copy(src); copy(src);
return *this; return *this;
} }
private: private:
static char* alloc(size_t capa) { MemoryPool allocPool(size_t capa) {
return reinterpret_cast<char*>(malloc(addPadding(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: protected:
JsonDocument(MemoryPool pool)
: nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT), _pool(pool) {}
JsonDocument(char* buf, size_t capa) JsonDocument(char* buf, size_t capa)
: nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT), _pool(buf, capa) {} : nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT), _pool(buf, capa) {}
@ -71,6 +74,10 @@ class JsonDocument : public Visitable {
to<VariantRef>().set(src.as<VariantRef>()); to<VariantRef>().set(src.as<VariantRef>());
} }
void replacePool(MemoryPool pool) {
_pool = pool;
}
private: private:
VariantRef getVariant() { VariantRef getVariant() {
return VariantRef(&_pool, &_data); 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("memoryUsage()") {
SECTION("Increases after adding value to array") { SECTION("Increases after adding value to array") {
JsonArray arr = doc.to<JsonArray>(); 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);
}
}