Просмотр исходного кода

Added copy-constructor and copy-assignment-operator for `JsonDocument` (issue #827)

Benoit Blanchon 7 лет назад
Родитель
Сommit
84f199f0dd

+ 1 - 0
CHANGELOG.md

@@ -11,6 +11,7 @@ HEAD
 * Increased the default capacity of `DynamicJsonDocument`
 * Fixed `JsonVariant::is<String>()` (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)
 -----------

+ 1 - 1
src/ArduinoJson/JsonArraySubscript.hpp

@@ -20,7 +20,7 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript>,
       : _array(array), _index(index) {}
 
   FORCE_INLINE JsonArraySubscript& operator=(const JsonArraySubscript& src) {
-    get_impl().set(src.as<JsonVariant>());
+    get_impl().set(src.as<JsonVariantConst>());
     return *this;
   }
 

+ 56 - 14
src/ArduinoJson/JsonDocument.hpp

@@ -18,9 +18,9 @@ class JsonDocument : public Visitable {
 
   JsonDocument() : nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {}
 
-  template <typename T>
-  bool is() const {
-    return getVariant().template is<T>();
+  template <typename Visitor>
+  void accept(Visitor& visitor) const {
+    return getVariant().accept(visitor);
   }
 
   template <typename T>
@@ -33,30 +33,37 @@ class JsonDocument : public Visitable {
     return getVariant().template as<T>();
   }
 
-  template <typename T>
-  typename JsonVariantTo<T>::type to() {
-    _memoryPool.clear();
-    return getVariant().template to<T>();
-  }
-
   void clear() {
     _memoryPool.clear();
     _rootData.type = JSON_NULL;
   }
 
-  size_t memoryUsage() const {
-    return _memoryPool.size();
+  template <typename T>
+  bool is() const {
+    return getVariant().template is<T>();
   }
 
-  template <typename Visitor>
-  void accept(Visitor& visitor) const {
-    return getVariant().accept(visitor);
+  size_t memoryUsage() const {
+    return _memoryPool.size();
   }
 
   TMemoryPool& memoryPool() {
     return _memoryPool;
   }
 
+  template <typename T>
+  typename JsonVariantTo<T>::type to() {
+    _memoryPool.clear();
+    return getVariant().template to<T>();
+  }
+
+ protected:
+  template <typename T>
+  void copy(const JsonDocument<T>& src) {
+    nestingLimit = src.nestingLimit;
+    to<JsonVariant>().set(src.template as<JsonVariant>());
+  }
+
  private:
   JsonVariant getVariant() {
     return JsonVariant(&_memoryPool, &_rootData);
@@ -76,14 +83,49 @@ class DynamicJsonDocument : public JsonDocument<DynamicMemoryPool> {
   DynamicJsonDocument(size_t capacity) {
     memoryPool().reserve(capacity);
   }
+
+  DynamicJsonDocument(const DynamicJsonDocument& src) {
+    memoryPool().reserve(src.memoryUsage());
+    copy(src);
+  }
+
+  template <typename T>
+  DynamicJsonDocument(const JsonDocument<T>& src) {
+    memoryPool().reserve(src.memoryUsage());
+    copy(src);
+  }
+
+  DynamicJsonDocument& operator=(const DynamicJsonDocument& src) {
+    copy(src);
+    return *this;
+  }
+
+  template <typename T>
+  DynamicJsonDocument& operator=(const JsonDocument<T>& src) {
+    copy(src);
+    return *this;
+  }
 };
 
 template <size_t CAPACITY>
 class StaticJsonDocument : public JsonDocument<StaticMemoryPool<CAPACITY> > {
  public:
+  StaticJsonDocument() {}
+
+  template <typename T>
+  StaticJsonDocument(const JsonDocument<T>& src) {
+    this->copy(src);
+  }
+
   StaticMemoryPoolBase& memoryPool() {
     return JsonDocument<StaticMemoryPool<CAPACITY> >::memoryPool();
   }
+
+  template <typename T>
+  StaticJsonDocument operator=(const JsonDocument<T>& src) {
+    this->copy(src);
+    return *this;
+  }
 };
 
 }  // namespace ARDUINOJSON_NAMESPACE

+ 3 - 1
src/ArduinoJson/JsonVariant.hpp

@@ -209,7 +209,8 @@ class JsonVariant : public JsonVariantProxy<JsonVariantData>,
     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<const JsonVariantData>,
                          public JsonVariantBase<JsonVariantConst>,
                          public Visitable {
   typedef JsonVariantProxy<const JsonVariantData> proxy_type;
+  friend class JsonVariant;
 
  public:
   JsonVariantConst() : proxy_type(0) {}

+ 5 - 1
src/ArduinoJson/JsonVariantImpl.hpp

@@ -30,7 +30,11 @@ inline bool JsonVariant::set(const JsonObjectSubscript<TString>& value) const {
   return set(value.template as<JsonVariant>());
 }
 
-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);
 }
 

+ 54 - 0
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<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);
+  }
 }

+ 84 - 2
test/JsonDocument/StaticJsonDocument.cpp

@@ -6,9 +6,8 @@
 #include <catch.hpp>
 
 TEST_CASE("StaticJsonDocument") {
-  StaticJsonDocument<200> doc;
-
   SECTION("serializeJson()") {
+    StaticJsonDocument<200> doc;
     JsonObject obj = doc.to<JsonObject>();
     obj["hello"] = "world";
 
@@ -17,4 +16,87 @@ TEST_CASE("StaticJsonDocument") {
 
     REQUIRE(json == "{\"hello\":\"world\"}");
   }
+
+  SECTION("Copy assignment") {
+    StaticJsonDocument<200> doc1, doc2;
+    doc1.to<JsonVariant>().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<JsonVariant>().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<JsonVariant>().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);
+  }
 }