diff --git a/CHANGELOG.md b/CHANGELOG.md index e9a1240e..750c09f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ HEAD * Increased the default capacity of `DynamicJsonDocument` * Fixed `JsonVariant::is()` (closes #763) * Added `JsonArrayConst`, `JsonObjectConst`, and `JsonVariantConst` +* Added copy-constructor and copy-assignment-operator for `JsonDocument` (issue #827) v6.4.0-beta (2018-09-11) ----------- diff --git a/src/ArduinoJson/JsonArraySubscript.hpp b/src/ArduinoJson/JsonArraySubscript.hpp index 1ea37e76..8c24bfb6 100644 --- a/src/ArduinoJson/JsonArraySubscript.hpp +++ b/src/ArduinoJson/JsonArraySubscript.hpp @@ -20,7 +20,7 @@ class JsonArraySubscript : public JsonVariantBase, : _array(array), _index(index) {} FORCE_INLINE JsonArraySubscript& operator=(const JsonArraySubscript& src) { - get_impl().set(src.as()); + get_impl().set(src.as()); return *this; } diff --git a/src/ArduinoJson/JsonDocument.hpp b/src/ArduinoJson/JsonDocument.hpp index 57ce63a5..3ab0cb85 100644 --- a/src/ArduinoJson/JsonDocument.hpp +++ b/src/ArduinoJson/JsonDocument.hpp @@ -18,9 +18,9 @@ class JsonDocument : public Visitable { JsonDocument() : nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {} - template - bool is() const { - return getVariant().template is(); + template + void accept(Visitor& visitor) const { + return getVariant().accept(visitor); } template @@ -33,30 +33,37 @@ class JsonDocument : public Visitable { return getVariant().template as(); } - template - typename JsonVariantTo::type to() { - _memoryPool.clear(); - return getVariant().template to(); - } - void clear() { _memoryPool.clear(); _rootData.type = JSON_NULL; } + template + bool is() const { + return getVariant().template is(); + } + size_t memoryUsage() const { return _memoryPool.size(); } - template - void accept(Visitor& visitor) const { - return getVariant().accept(visitor); - } - TMemoryPool& memoryPool() { return _memoryPool; } + template + typename JsonVariantTo::type to() { + _memoryPool.clear(); + return getVariant().template to(); + } + + protected: + template + void copy(const JsonDocument& src) { + nestingLimit = src.nestingLimit; + to().set(src.template as()); + } + private: JsonVariant getVariant() { return JsonVariant(&_memoryPool, &_rootData); @@ -76,14 +83,49 @@ class DynamicJsonDocument : public JsonDocument { DynamicJsonDocument(size_t capacity) { memoryPool().reserve(capacity); } + + DynamicJsonDocument(const DynamicJsonDocument& src) { + memoryPool().reserve(src.memoryUsage()); + copy(src); + } + + template + DynamicJsonDocument(const JsonDocument& src) { + memoryPool().reserve(src.memoryUsage()); + copy(src); + } + + DynamicJsonDocument& operator=(const DynamicJsonDocument& src) { + copy(src); + return *this; + } + + template + DynamicJsonDocument& operator=(const JsonDocument& src) { + copy(src); + return *this; + } }; template class StaticJsonDocument : public JsonDocument > { public: + StaticJsonDocument() {} + + template + StaticJsonDocument(const JsonDocument& src) { + this->copy(src); + } + StaticMemoryPoolBase& memoryPool() { return JsonDocument >::memoryPool(); } + + template + StaticJsonDocument operator=(const JsonDocument& src) { + this->copy(src); + return *this; + } }; } // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/JsonVariant.hpp b/src/ArduinoJson/JsonVariant.hpp index 96c63e7f..f96255bd 100644 --- a/src/ArduinoJson/JsonVariant.hpp +++ b/src/ArduinoJson/JsonVariant.hpp @@ -209,7 +209,8 @@ class JsonVariant : public JsonVariantProxy, return variantSetString(_data, value, _memoryPool); } - bool set(const JsonVariant &value) const; + bool set(JsonVariantConst value) const; + bool set(JsonVariant value) const; FORCE_INLINE bool set(JsonArray array) const; FORCE_INLINE bool set(const JsonArraySubscript &) const; @@ -284,6 +285,7 @@ class JsonVariantConst : public JsonVariantProxy, public JsonVariantBase, public Visitable { typedef JsonVariantProxy proxy_type; + friend class JsonVariant; public: JsonVariantConst() : proxy_type(0) {} diff --git a/src/ArduinoJson/JsonVariantImpl.hpp b/src/ArduinoJson/JsonVariantImpl.hpp index 67b1eac4..94aa9fb2 100644 --- a/src/ArduinoJson/JsonVariantImpl.hpp +++ b/src/ArduinoJson/JsonVariantImpl.hpp @@ -30,7 +30,11 @@ inline bool JsonVariant::set(const JsonObjectSubscript& value) const { return set(value.template as()); } -inline bool JsonVariant::set(const JsonVariant& value) const { +inline bool JsonVariant::set(JsonVariantConst value) const { + return variantCopy(_data, value._data, _memoryPool); +} + +inline bool JsonVariant::set(JsonVariant value) const { return variantCopy(_data, value._data, _memoryPool); } diff --git a/test/JsonDocument/DynamicJsonDocument.cpp b/test/JsonDocument/DynamicJsonDocument.cpp index dfc08205..9aa16c3b 100644 --- a/test/JsonDocument/DynamicJsonDocument.cpp +++ b/test/JsonDocument/DynamicJsonDocument.cpp @@ -38,4 +38,58 @@ TEST_CASE("DynamicJsonDocument") { REQUIRE(doc.memoryUsage() == JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(0)); } } + + 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); + } } diff --git a/test/JsonDocument/StaticJsonDocument.cpp b/test/JsonDocument/StaticJsonDocument.cpp index ee416d9a..fe8c7e68 100644 --- a/test/JsonDocument/StaticJsonDocument.cpp +++ b/test/JsonDocument/StaticJsonDocument.cpp @@ -6,9 +6,8 @@ #include TEST_CASE("StaticJsonDocument") { - StaticJsonDocument<200> doc; - SECTION("serializeJson()") { + StaticJsonDocument<200> doc; JsonObject obj = doc.to(); obj["hello"] = "world"; @@ -17,4 +16,87 @@ TEST_CASE("StaticJsonDocument") { REQUIRE(json == "{\"hello\":\"world\"}"); } + + SECTION("Copy assignment") { + StaticJsonDocument<200> doc1, doc2; + doc1.to().set(666); + deserializeJson(doc2, "{\"hello\":\"world\"}"); + doc2.nestingLimit = 42; + + doc1 = doc2; + + std::string json; + serializeJson(doc1, json); + REQUIRE(json == "{\"hello\":\"world\"}"); + REQUIRE(doc1.nestingLimit == 42); + } + + SECTION("Copy constructor") { + StaticJsonDocument<200> doc1; + deserializeJson(doc1, "{\"hello\":\"world\"}"); + doc1.nestingLimit = 42; + + StaticJsonDocument<200> doc2 = doc1; + + std::string json; + serializeJson(doc2, json); + REQUIRE(json == "{\"hello\":\"world\"}"); + REQUIRE(doc2.nestingLimit == 42); + } + + SECTION("Assign from StaticJsonDocument of different capacity") { + StaticJsonDocument<200> doc1; + StaticJsonDocument<300> doc2; + doc1.to().set(666); + deserializeJson(doc2, "{\"hello\":\"world\"}"); + doc2.nestingLimit = 42; + + doc1 = doc2; + + std::string json; + serializeJson(doc1, json); + REQUIRE(json == "{\"hello\":\"world\"}"); + REQUIRE(doc1.nestingLimit == 42); + } + + SECTION("Assign from DynamicJsonDocument") { + StaticJsonDocument<200> doc1; + DynamicJsonDocument doc2; + doc1.to().set(666); + deserializeJson(doc2, "{\"hello\":\"world\"}"); + doc2.nestingLimit = 42; + + doc1 = doc2; + + std::string json; + serializeJson(doc1, json); + REQUIRE(json == "{\"hello\":\"world\"}"); + REQUIRE(doc1.nestingLimit == 42); + } + + SECTION("Construct from StaticJsonDocument of different size") { + StaticJsonDocument<300> doc2; + deserializeJson(doc2, "{\"hello\":\"world\"}"); + doc2.nestingLimit = 42; + + StaticJsonDocument<200> doc1 = doc2; + + std::string json; + serializeJson(doc1, json); + REQUIRE(json == "{\"hello\":\"world\"}"); + REQUIRE(doc1.nestingLimit == 42); + } + + SECTION("Construct from DynamicJsonDocument") { + DynamicJsonDocument doc2; + deserializeJson(doc2, "{\"hello\":\"world\"}"); + doc2.nestingLimit = 42; + + StaticJsonDocument<200> doc1 = doc2; + + std::string json; + serializeJson(doc1, json); + REQUIRE(json == "{\"hello\":\"world\"}"); + REQUIRE(doc1.nestingLimit == 42); + } }