diff --git a/src/ArduinoJson/Document/DynamicJsonDocument.hpp b/src/ArduinoJson/Document/DynamicJsonDocument.hpp index a1514cde..802ec3ff 100644 --- a/src/ArduinoJson/Document/DynamicJsonDocument.hpp +++ b/src/ArduinoJson/Document/DynamicJsonDocument.hpp @@ -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 DynamicJsonDocument& operator=(const JsonDocument& src) { + reallocPoolIfTooSmall(src.memoryUsage()); copy(src); return *this; } private: - static char* alloc(size_t capa) { - return reinterpret_cast(malloc(addPadding(capa))); + MemoryPool allocPool(size_t capa) { + return MemoryPool(reinterpret_cast(malloc(capa)), capa); + } + + void reallocPoolIfTooSmall(size_t requiredSize) { + if (requiredSize <= capacity()) return; + freePool(); + replacePool(allocPool(addPadding(requiredSize))); + } + + void freePool() { + free(memoryPool().buffer()); } }; diff --git a/src/ArduinoJson/Document/JsonDocument.hpp b/src/ArduinoJson/Document/JsonDocument.hpp index efec5393..3eb37ac3 100644 --- a/src/ArduinoJson/Document/JsonDocument.hpp +++ b/src/ArduinoJson/Document/JsonDocument.hpp @@ -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().set(src.as()); } + void replacePool(MemoryPool pool) { + _pool = pool; + } + private: VariantRef getVariant() { return VariantRef(&_pool, &_data); diff --git a/test/JsonDocument/DynamicJsonDocument.cpp b/test/JsonDocument/DynamicJsonDocument.cpp index b6fe03ab..f4beb2d0 100644 --- a/test/JsonDocument/DynamicJsonDocument.cpp +++ b/test/JsonDocument/DynamicJsonDocument.cpp @@ -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().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(); @@ -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().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); + } +}