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

Copy JsonArray and JsonObject, instead of storing pointers (fixes #780)

Benoit Blanchon 7 лет назад
Родитель
Сommit
b106b1ed14
52 измененных файлов с 955 добавлено и 962 удалено
  1. 6 1
      CHANGELOG.md
  2. 21 9
      src/ArduinoJson/Data/JsonVariantContent.hpp
  3. 45 58
      src/ArduinoJson/Data/JsonVariantData.hpp
  4. 33 0
      src/ArduinoJson/Data/JsonVariantTo.hpp
  5. 11 9
      src/ArduinoJson/Data/JsonVariantType.hpp
  6. 0 83
      src/ArduinoJson/Data/List.hpp
  7. 0 50
      src/ArduinoJson/Data/ListConstIterator.hpp
  8. 0 60
      src/ArduinoJson/Data/ListIterator.hpp
  9. 0 24
      src/ArduinoJson/Data/ListNode.hpp
  10. 21 0
      src/ArduinoJson/Data/Slot.hpp
  11. 4 4
      src/ArduinoJson/Deserialization/deserialize.hpp
  12. 10 46
      src/ArduinoJson/DynamicJsonDocument.hpp
  13. 22 24
      src/ArduinoJson/Json/JsonDeserializer.hpp
  14. 14 14
      src/ArduinoJson/Json/JsonSerializer.hpp
  15. 86 19
      src/ArduinoJson/JsonArray.hpp
  16. 0 28
      src/ArduinoJson/JsonArrayData.hpp
  17. 2 8
      src/ArduinoJson/JsonArrayImpl.hpp
  18. 16 15
      src/ArduinoJson/JsonArrayIterator.hpp
  19. 7 2
      src/ArduinoJson/JsonArraySubscript.hpp
  20. 113 51
      src/ArduinoJson/JsonObject.hpp
  21. 0 30
      src/ArduinoJson/JsonObjectData.hpp
  22. 2 6
      src/ArduinoJson/JsonObjectImpl.hpp
  23. 18 18
      src/ArduinoJson/JsonObjectIterator.hpp
  24. 7 2
      src/ArduinoJson/JsonObjectSubscript.hpp
  25. 8 10
      src/ArduinoJson/JsonPair.hpp
  26. 33 22
      src/ArduinoJson/JsonVariant.hpp
  27. 91 16
      src/ArduinoJson/JsonVariantImpl.hpp
  28. 0 1
      src/ArduinoJson/Memory/AllocableInMemoryPool.hpp
  29. 2 3
      src/ArduinoJson/Memory/DynamicMemoryPool.hpp
  30. 3 3
      src/ArduinoJson/Memory/StaticMemoryPool.hpp
  31. 38 40
      src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp
  32. 15 17
      src/ArduinoJson/MsgPack/MsgPackSerializer.hpp
  33. 1 1
      src/ArduinoJson/Serialization/measure.hpp
  34. 1 1
      src/ArduinoJson/Serialization/serialize.hpp
  35. 6 40
      src/ArduinoJson/StaticJsonDocument.hpp
  36. 5 2
      test/JsonArray/copyFrom.cpp
  37. 5 5
      test/JsonArray/isNull.cpp
  38. 5 0
      test/JsonArray/subscript.cpp
  39. 21 0
      test/JsonDocument/DynamicJsonDocument.cpp
  40. 4 2
      test/JsonObject/createNestedArray.cpp
  41. 5 5
      test/JsonObject/isNull.cpp
  42. 5 0
      test/JsonObject/iterator.cpp
  43. 41 24
      test/JsonObject/remove.cpp
  44. 13 1
      test/JsonObject/size.cpp
  45. 6 0
      test/JsonObject/subscript.cpp
  46. 1 0
      test/JsonVariant/CMakeLists.txt
  47. 87 160
      test/JsonVariant/as.cpp
  48. 8 12
      test/JsonVariant/compare.cpp
  49. 84 0
      test/JsonVariant/copy.cpp
  50. 9 9
      test/JsonVariant/isnull.cpp
  51. 7 6
      test/JsonVariant/subscript.cpp
  52. 13 21
      test/JsonVariant/undefined.cpp

+ 6 - 1
CHANGELOG.md

@@ -1,11 +1,16 @@
 ArduinoJson: change log
 =======================
 
+HEAD
+----
+
+* Copy `JsonArray` and `JsonObject`, instead of storing pointers (issue #780)
+
 v6.3.0-beta (2018-08-31)
 -----------
 
 * Implemented reference semantics for `JsonVariant`
-* Replace `JsonPair`'s `key` and `value` with `key()` and `value()`
+* Replaced `JsonPair`'s `key` and `value` with `key()` and `value()`
 * Fixed `serializeJson(obj[key], dst)` (issue #794)
 
 > ### BREAKING CHANGES

+ 21 - 9
src/ArduinoJson/Data/JsonVariantContent.hpp

@@ -11,22 +11,34 @@
 
 namespace ArduinoJson {
 namespace Internals {
-// Forward declarations
-struct JsonArrayData;
-struct JsonObjectData;
+struct JsonObjectData {
+  struct Slot* head;
+  struct Slot* tail;
+};
+
+struct JsonArrayData {
+  struct Slot* head;
+  struct Slot* tail;
+};
 
-// A union that defines the actual content of a JsonVariant.
+struct RawData {
+  const char* data;
+  size_t size;
+};
+
+// A union that defines the actual content of a JsonVariantData.
 // The enum JsonVariantType determines which member is in use.
 union JsonVariantContent {
-  JsonFloat asFloat;         // used for double and float
-  JsonUInt asInteger;        // used for bool, char, short, int and longs
-  JsonArrayData* asArray;    // asArray cannot be null
-  JsonObjectData* asObject;  // asObject cannot be null
-  const char* asString;      // asString can be null
+  JsonFloat asFloat;
+  JsonUInt asInteger;
+  JsonArrayData asArray;
+  JsonObjectData asObject;
+  const char* asString;
   struct {
     const char* data;
     size_t size;
   } asRaw;
 };
+
 }  // namespace Internals
 }  // namespace ArduinoJson

+ 45 - 58
src/ArduinoJson/Data/JsonVariantData.hpp

@@ -16,6 +16,10 @@ struct JsonVariantData {
   JsonVariantType type;
   JsonVariantContent content;
 
+  JsonVariantData() {
+    type = JSON_NULL;
+  }
+
   void setBoolean(bool value) {
     type = JSON_BOOLEAN;
     content.asInteger = static_cast<JsonUInt>(value);
@@ -43,13 +47,24 @@ struct JsonVariantData {
     content.asInteger = value;
   }
 
-  void setString(const char *value) {
-    type = JSON_STRING;
+  void setOwnedString(const char *value) {
+    type = JSON_OWNED_STRING;
+    content.asString = value;
+  }
+
+  void setLinkedString(const char *value) {
+    type = JSON_LINKED_STRING;
     content.asString = value;
   }
 
-  void setRaw(const char *data, size_t size) {
-    type = JSON_RAW;
+  void setOwnedRaw(const char *data, size_t size) {
+    type = JSON_OWNED_RAW;
+    content.asRaw.data = data;
+    content.asRaw.size = size;
+  }
+
+  void setLinkedRaw(const char *data, size_t size) {
+    type = JSON_LINKED_RAW;
     content.asRaw.data = data;
     content.asRaw.size = size;
   }
@@ -58,66 +73,70 @@ struct JsonVariantData {
     type = JSON_NULL;
   }
 
-  void setArray(JsonArrayData &array) {
+  JsonArrayData *toArray() {
     type = JSON_ARRAY;
-    content.asArray = &array;
+    content.asArray.head = 0;
+    content.asArray.tail = 0;
+    return &content.asArray;
   }
 
-  void setObject(JsonObjectData &object) {
+  JsonObjectData *toObject() {
     type = JSON_OBJECT;
-    content.asObject = &object;
+    content.asObject.head = 0;
+    content.asObject.tail = 0;
+    return &content.asObject;
   }
 
-  JsonArrayData *asArray() const {
-    return type == JSON_ARRAY ? content.asArray : 0;
+  JsonArrayData *asArray() {
+    return type == JSON_ARRAY ? &content.asArray : 0;
   }
 
-  JsonObjectData *asObject() const {
-    return type == JSON_OBJECT ? content.asObject : 0;
+  JsonObjectData *asObject() {
+    return type == JSON_OBJECT ? &content.asObject : 0;
   }
 
   template <typename T>
   T asInteger() const {
     switch (type) {
-      case JSON_NULL:
-      case JSON_RAW:
-        return 0;
       case JSON_POSITIVE_INTEGER:
       case JSON_BOOLEAN:
         return T(content.asInteger);
       case JSON_NEGATIVE_INTEGER:
         return T(~content.asInteger + 1);
-      case JSON_STRING:
+      case JSON_LINKED_STRING:
+      case JSON_OWNED_STRING:
         return parseInteger<T>(content.asString);
-      default:
+      case JSON_FLOAT:
         return T(content.asFloat);
+      default:
+        return 0;
     }
   }
 
   template <typename T>
   T asFloat() const {
     switch (type) {
-      case JSON_NULL:
-      case JSON_RAW:
-        return 0;
       case JSON_POSITIVE_INTEGER:
       case JSON_BOOLEAN:
         return static_cast<T>(content.asInteger);
       case JSON_NEGATIVE_INTEGER:
         return -static_cast<T>(content.asInteger);
-      case JSON_STRING:
+      case JSON_LINKED_STRING:
+      case JSON_OWNED_STRING:
         return parseFloat<T>(content.asString);
-      default:
+      case JSON_FLOAT:
         return static_cast<T>(content.asFloat);
+      default:
+        return 0;
     }
   }
 
   const char *asString() const {
-    return type == JSON_STRING ? content.asString : NULL;
+    return isString() ? content.asString : NULL;
   }
 
   bool isArray() const {
-    return type == Internals::JSON_ARRAY;
+    return type == JSON_ARRAY;
   }
 
   bool isBoolean() const {
@@ -138,43 +157,11 @@ struct JsonVariantData {
   }
 
   bool isObject() const {
-    return type == Internals::JSON_OBJECT;
+    return type == JSON_OBJECT;
   }
 
   bool isString() const {
-    return type == Internals::JSON_STRING;
-  }
-
-  template <typename Visitor>
-  void visit(Visitor &visitor) const {
-    switch (type) {
-      case JSON_FLOAT:
-        return visitor.acceptFloat(content.asFloat);
-
-      case JSON_ARRAY:
-        return visitor.acceptArray(*content.asArray);
-
-      case JSON_OBJECT:
-        return visitor.acceptObject(*content.asObject);
-
-      case JSON_STRING:
-        return visitor.acceptString(content.asString);
-
-      case JSON_RAW:
-        return visitor.acceptRawJson(content.asRaw.data, content.asRaw.size);
-
-      case JSON_NEGATIVE_INTEGER:
-        return visitor.acceptNegativeInteger(content.asInteger);
-
-      case JSON_POSITIVE_INTEGER:
-        return visitor.acceptPositiveInteger(content.asInteger);
-
-      case JSON_BOOLEAN:
-        return visitor.acceptBoolean(content.asInteger != 0);
-
-      default:
-        return visitor.acceptNull();
-    }
+    return type == JSON_LINKED_STRING || type == JSON_OWNED_STRING;
   }
 };
 }  // namespace Internals

+ 33 - 0
src/ArduinoJson/Data/JsonVariantTo.hpp

@@ -0,0 +1,33 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+class JsonArray;
+class JsonObject;
+class JsonVariant;
+
+namespace Internals {
+
+// A metafunction that returns the type of the value returned by
+// JsonVariant::to<T>()
+template <typename T>
+struct JsonVariantTo {};
+
+template <>
+struct JsonVariantTo<JsonArray> {
+  typedef JsonArray type;
+};
+template <>
+struct JsonVariantTo<JsonObject> {
+  typedef JsonObject type;
+};
+template <>
+struct JsonVariantTo<JsonVariant> {
+  typedef JsonVariant type;
+};
+
+}  // namespace Internals
+}  // namespace ArduinoJson

+ 11 - 9
src/ArduinoJson/Data/JsonVariantType.hpp

@@ -11,15 +11,17 @@ namespace Internals {
 // Enumerated type to know the current type of a JsonVariant.
 // The value determines which member of JsonVariantContent is used.
 enum JsonVariantType {
-  JSON_NULL,     // JsonVariant has not been initialized
-  JSON_RAW,      // JsonVariant contains a raw string that should not be escaped
-  JSON_STRING,   // JsonVariant stores a const char*
-  JSON_BOOLEAN,  // JsonVariant stores a bool
-  JSON_POSITIVE_INTEGER,  // JsonVariant stores an JsonUInt
-  JSON_NEGATIVE_INTEGER,  // JsonVariant stores an JsonUInt that must be negated
-  JSON_ARRAY,             // JsonVariant stores a pointer to a JsonArrayData
-  JSON_OBJECT,            // JsonVariant stores a pointer to a JsonObjectData
-  JSON_FLOAT              // JsonVariant stores a JsonFloat
+  JSON_NULL,
+  JSON_LINKED_RAW,
+  JSON_OWNED_RAW,
+  JSON_LINKED_STRING,
+  JSON_OWNED_STRING,
+  JSON_BOOLEAN,
+  JSON_POSITIVE_INTEGER,
+  JSON_NEGATIVE_INTEGER,
+  JSON_ARRAY,
+  JSON_OBJECT,
+  JSON_FLOAT
 };
 }  // namespace Internals
 }  // namespace ArduinoJson

+ 0 - 83
src/ArduinoJson/Data/List.hpp

@@ -1,83 +0,0 @@
-// ArduinoJson - arduinojson.org
-// Copyright Benoit Blanchon 2014-2018
-// MIT License
-
-#pragma once
-
-#include "../Memory/MemoryPool.hpp"
-#include "ListConstIterator.hpp"
-#include "ListIterator.hpp"
-
-namespace ArduinoJson {
-namespace Internals {
-
-// A singly linked list of T.
-// The linked list is composed of ListNode<T>.
-// It is derived by JsonArrayData and JsonObjectData
-template <typename T>
-class List {
- public:
-  typedef T value_type;
-  typedef ListNode<T> node_type;
-  typedef ListIterator<T> iterator;
-  typedef ListConstIterator<T> const_iterator;
-
-  List() : _firstNode(NULL) {}
-
-  // Returns the numbers of elements in the list.
-  // For a JsonObjectData, it would return the number of key-value pairs
-  size_t size() const {
-    size_t nodeCount = 0;
-    for (node_type *node = _firstNode; node; node = node->next) nodeCount++;
-    return nodeCount;
-  }
-
-  iterator add(MemoryPool *memoryPool) {
-    node_type *newNode = new (memoryPool) node_type();
-
-    if (_firstNode) {
-      node_type *lastNode = _firstNode;
-      while (lastNode->next) lastNode = lastNode->next;
-      lastNode->next = newNode;
-    } else {
-      _firstNode = newNode;
-    }
-
-    return iterator(newNode);
-  }
-
-  iterator begin() {
-    return iterator(_firstNode);
-  }
-  iterator end() {
-    return iterator(NULL);
-  }
-
-  const_iterator begin() const {
-    return const_iterator(_firstNode);
-  }
-  const_iterator end() const {
-    return const_iterator(NULL);
-  }
-
-  void remove(iterator it) {
-    node_type *nodeToRemove = it._node;
-    if (!nodeToRemove) return;
-    if (nodeToRemove == _firstNode) {
-      _firstNode = nodeToRemove->next;
-    } else {
-      for (node_type *node = _firstNode; node; node = node->next)
-        if (node->next == nodeToRemove) node->next = nodeToRemove->next;
-    }
-  }
-
- protected:
-  void clear() {
-    _firstNode = 0;
-  }
-
- private:
-  node_type *_firstNode;
-};
-}  // namespace Internals
-}  // namespace ArduinoJson

+ 0 - 50
src/ArduinoJson/Data/ListConstIterator.hpp

@@ -1,50 +0,0 @@
-// ArduinoJson - arduinojson.org
-// Copyright Benoit Blanchon 2014-2018
-// MIT License
-
-#pragma once
-
-#include "ListNode.hpp"
-
-namespace ArduinoJson {
-namespace Internals {
-
-// A read-only forward itertor for List<T>
-template <typename T>
-class ListConstIterator {
- public:
-  explicit ListConstIterator(const ListNode<T> *node = NULL) : _node(node) {}
-
-  const T &operator*() const {
-    return _node->content;
-  }
-  const T *operator->() {
-    return &_node->content;
-  }
-
-  bool operator==(const ListConstIterator<T> &other) const {
-    return _node == other._node;
-  }
-
-  bool operator!=(const ListConstIterator<T> &other) const {
-    return _node != other._node;
-  }
-
-  ListConstIterator<T> &operator++() {
-    if (_node) _node = _node->next;
-    return *this;
-  }
-
-  ListConstIterator<T> &operator+=(size_t distance) {
-    while (_node && distance) {
-      _node = _node->next;
-      --distance;
-    }
-    return *this;
-  }
-
- private:
-  const ListNode<T> *_node;
-};
-}
-}

+ 0 - 60
src/ArduinoJson/Data/ListIterator.hpp

@@ -1,60 +0,0 @@
-// ArduinoJson - arduinojson.org
-// Copyright Benoit Blanchon 2014-2018
-// MIT License
-
-#pragma once
-
-#include "ListConstIterator.hpp"
-#include "ListNode.hpp"
-
-namespace ArduinoJson {
-namespace Internals {
-
-template <typename T>
-class List;
-
-// A read-write forward iterator for List<T>
-template <typename T>
-class ListIterator {
-  friend class List<T>;
-
- public:
-  explicit ListIterator(ListNode<T> *node = NULL) : _node(node) {}
-
-  T &operator*() const {
-    return _node->content;
-  }
-  T *operator->() {
-    return &_node->content;
-  }
-
-  bool operator==(const ListIterator<T> &other) const {
-    return _node == other._node;
-  }
-
-  bool operator!=(const ListIterator<T> &other) const {
-    return _node != other._node;
-  }
-
-  ListIterator<T> &operator++() {
-    if (_node) _node = _node->next;
-    return *this;
-  }
-
-  ListIterator<T> &operator+=(size_t distance) {
-    while (_node && distance) {
-      _node = _node->next;
-      --distance;
-    }
-    return *this;
-  }
-
-  operator ListConstIterator<T>() const {
-    return ListConstIterator<T>(_node);
-  }
-
- private:
-  ListNode<T> *_node;
-};
-}
-}

+ 0 - 24
src/ArduinoJson/Data/ListNode.hpp

@@ -1,24 +0,0 @@
-// ArduinoJson - arduinojson.org
-// Copyright Benoit Blanchon 2014-2018
-// MIT License
-
-#pragma once
-
-#include <stddef.h>  // for NULL
-
-#include "../Memory/AllocableInMemoryPool.hpp"
-
-namespace ArduinoJson {
-namespace Internals {
-
-// A node for a singly-linked list.
-// Used by List<T> and its iterators.
-template <typename T>
-struct ListNode : public Internals::AllocableInMemoryPool {
-  ListNode() NOEXCEPT : next(NULL) {}
-
-  ListNode<T> *next;
-  T content;
-};
-}  // namespace Internals
-}  // namespace ArduinoJson

+ 21 - 0
src/ArduinoJson/Data/Slot.hpp

@@ -0,0 +1,21 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../Memory/AllocableInMemoryPool.hpp"
+#include "JsonVariantData.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+struct Slot : AllocableInMemoryPool {
+  JsonVariantData value;
+  struct Slot* next;
+  struct Slot* prev;
+  const char* key;
+};
+
+}  // namespace Internals
+}  // namespace ArduinoJson

+ 4 - 4
src/ArduinoJson/Deserialization/deserialize.hpp

@@ -36,7 +36,7 @@ deserialize(TDocument &doc, const TString &input) {
   return makeDeserializer<TDeserializer>(
              doc.memoryPool(), makeReader(input),
              makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
-      .parse(doc.template to<JsonVariantData>());
+      .parse(doc.template to<JsonVariant>());
 }
 //
 // DeserializationError deserialize(TDocument& doc, TChar* input);
@@ -49,7 +49,7 @@ DeserializationError deserialize(TDocument &doc, TChar *input) {
   return makeDeserializer<TDeserializer>(
              doc.memoryPool(), makeReader(input),
              makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
-      .parse(doc.template to<JsonVariantData>());
+      .parse(doc.template to<JsonVariant>());
 }
 //
 // DeserializationError deserialize(TDocument& doc, TChar* input, size_t
@@ -64,7 +64,7 @@ DeserializationError deserialize(TDocument &doc, TChar *input,
   return makeDeserializer<TDeserializer>(
              doc.memoryPool(), makeReader(input, inputSize),
              makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
-      .parse(doc.template to<JsonVariantData>());
+      .parse(doc.template to<JsonVariant>());
 }
 //
 // DeserializationError deserialize(TDocument& doc, TStream input);
@@ -77,7 +77,7 @@ DeserializationError deserialize(TDocument &doc, TStream &input) {
   return makeDeserializer<TDeserializer>(
              doc.memoryPool(), makeReader(input),
              makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
-      .parse(doc.template to<JsonVariantData>());
+      .parse(doc.template to<JsonVariant>());
 }
 }  // namespace Internals
 }  // namespace ArduinoJson

+ 10 - 46
src/ArduinoJson/DynamicJsonDocument.hpp

@@ -4,8 +4,7 @@
 
 #pragma once
 
-#include "JsonArray.hpp"
-#include "JsonObject.hpp"
+#include "Data/JsonVariantTo.hpp"
 #include "JsonVariant.hpp"
 #include "Memory/DynamicMemoryPool.hpp"
 
@@ -30,49 +29,10 @@ class DynamicJsonDocument {
     return getVariant().as<T>();
   }
 
-  // JsonObject to<JsonObject>()
   template <typename T>
-  typename Internals::enable_if<Internals::is_same<T, JsonObject>::value,
-                                JsonObject>::type
-  to() {
-    clear();
-    JsonObject object(&_memoryPool);
-    getVariant().set(object);
-    return object;
-  }
-
-  // JsonArray to<JsonArray>()
-  template <typename T>
-  typename Internals::enable_if<Internals::is_same<T, JsonArray>::value,
-                                JsonArray>::type
-  to() {
-    clear();
-    JsonArray array(&_memoryPool);
-    getVariant().set(array);
-    return array;
-  }
-
-  // JsonVariant to<JsonVariant>()
-  template <typename T>
-  typename Internals::enable_if<Internals::is_same<T, JsonVariant>::value,
-                                JsonVariant>::type
-  to() {
-    clear();
-    return getVariant();
-  }
-
-  // JsonVariantData& to<JsonVariantData>()
-  template <typename T>
-  typename Internals::enable_if<
-      Internals::is_same<T, Internals::JsonVariantData>::value,
-      Internals::JsonVariantData&>::type
-  to() {
-    clear();
-    return _rootData;
-  }
-
-  Internals::DynamicMemoryPool& memoryPool() {
-    return _memoryPool;
+  typename Internals::JsonVariantTo<T>::type to() {
+    _memoryPool.clear();
+    return getVariant().to<T>();
   }
 
   void clear() {
@@ -85,8 +45,12 @@ class DynamicJsonDocument {
   }
 
   template <typename Visitor>
-  void visit(Visitor& visitor) const {
-    return _rootData.visit(visitor);
+  void accept(Visitor& visitor) const {
+    return getVariant().accept(visitor);
+  }
+
+  Internals::DynamicMemoryPool& memoryPool() {
+    return _memoryPool;
   }
 
  private:

+ 22 - 24
src/ArduinoJson/Json/JsonDeserializer.hpp

@@ -25,7 +25,7 @@ class JsonDeserializer {
         _stringStorage(stringStorage),
         _nestingLimit(nestingLimit),
         _loaded(false) {}
-  DeserializationError parse(JsonVariantData &variant) {
+  DeserializationError parse(JsonVariant variant) {
     DeserializationError err = skipSpacesAndComments();
     if (err) return err;
 
@@ -65,12 +65,11 @@ class JsonDeserializer {
     return true;
   }
 
-  DeserializationError parseArray(JsonVariantData &variant) {
+  DeserializationError parseArray(JsonVariant variant) {
     if (_nestingLimit == 0) return DeserializationError::TooDeep;
 
-    JsonArrayData *array = new (_memoryPool) JsonArrayData;
-    if (!array) return DeserializationError::NoMemory;
-    variant.setArray(*array);
+    JsonArray array = variant.to<JsonArray>();
+    if (array.isNull()) return DeserializationError::NoMemory;
 
     // Check opening braket
     if (!eat('[')) return DeserializationError::InvalidInput;
@@ -85,12 +84,12 @@ class JsonDeserializer {
     // Read each value
     for (;;) {
       // Allocate slot in array
-      JsonVariantData *value = array->addSlot(_memoryPool);
-      if (!value) return DeserializationError::NoMemory;
+      JsonVariant value = array.add();
+      if (value.isInvalid()) return DeserializationError::NoMemory;
 
       // 1 - Parse value
       _nestingLimit--;
-      err = parse(*value);
+      err = parse(value);
       _nestingLimit++;
       if (err) return err;
 
@@ -104,12 +103,11 @@ class JsonDeserializer {
     }
   }
 
-  DeserializationError parseObject(JsonVariantData &variant) {
+  DeserializationError parseObject(JsonVariant variant) {
     if (_nestingLimit == 0) return DeserializationError::TooDeep;
 
-    JsonObjectData *object = new (_memoryPool) JsonObjectData;
-    if (!object) return DeserializationError::NoMemory;
-    variant.setObject(*object);
+    JsonObject object = variant.to<JsonObject>();
+    if (object.isNull()) return DeserializationError::NoMemory;
 
     // Check opening brace
     if (!eat('{')) return DeserializationError::InvalidInput;
@@ -134,12 +132,12 @@ class JsonDeserializer {
       if (!eat(':')) return DeserializationError::InvalidInput;
 
       // Allocate slot in object
-      JsonVariantData *value = object->addSlot(_memoryPool, key);
-      if (!value) return DeserializationError::NoMemory;
+      JsonVariant value = object.set(key);
+      if (value.isInvalid()) return DeserializationError::NoMemory;
 
       // Parse value
       _nestingLimit--;
-      err = parse(*value);
+      err = parse(value);
       _nestingLimit++;
       if (err) return err;
 
@@ -157,7 +155,7 @@ class JsonDeserializer {
     }
   }
 
-  DeserializationError parseValue(JsonVariantData &variant) {
+  DeserializationError parseValue(JsonVariant variant) {
     if (isQuote(current())) {
       return parseStringValue(variant);
     } else {
@@ -173,11 +171,11 @@ class JsonDeserializer {
     }
   }
 
-  DeserializationError parseStringValue(JsonVariantData &variant) {
+  DeserializationError parseStringValue(JsonVariant variant) {
     const char *value;
     DeserializationError err = parseQuotedString(&value);
     if (err) return err;
-    variant.setString(value);
+    variant.set(value);
     return DeserializationError::Ok;
   }
 
@@ -235,7 +233,7 @@ class JsonDeserializer {
     return DeserializationError::Ok;
   }
 
-  DeserializationError parseNumericValue(JsonVariantData &result) {
+  DeserializationError parseNumericValue(JsonVariant result) {
     char buffer[64];
     uint8_t n = 0;
 
@@ -248,15 +246,15 @@ class JsonDeserializer {
     buffer[n] = 0;
 
     if (isInteger(buffer)) {
-      result.setInteger(parseInteger<JsonInteger>(buffer));
+      result.set(parseInteger<JsonInteger>(buffer));
     } else if (isFloat(buffer)) {
-      result.setFloat(parseFloat<JsonFloat>(buffer));
+      result.set(parseFloat<JsonFloat>(buffer));
     } else if (!strcmp(buffer, "true")) {
-      result.setBoolean(true);
+      result.set(true);
     } else if (!strcmp(buffer, "false")) {
-      result.setBoolean(false);
+      result.set(false);
     } else if (!strcmp(buffer, "null")) {
-      result.setNull();
+      // already null
     } else {
       return DeserializationError::InvalidInput;
     }

+ 14 - 14
src/ArduinoJson/Json/JsonSerializer.hpp

@@ -16,16 +16,16 @@ class JsonSerializer {
  public:
   JsonSerializer(TWriter &writer) : _writer(writer) {}
 
-  void acceptFloat(JsonFloat value) {
+  void visitFloat(JsonFloat value) {
     _writer.writeFloat(value);
   }
 
-  void acceptArray(const JsonArrayData &array) {
+  void visitArray(JsonArray array) {
     _writer.beginArray();
 
-    JsonArrayData::const_iterator it = array.begin();
+    JsonArray::iterator it = array.begin();
     while (it != array.end()) {
-      it->visit(*this);
+      it->accept(*this);
 
       ++it;
       if (it == array.end()) break;
@@ -36,14 +36,14 @@ class JsonSerializer {
     _writer.endArray();
   }
 
-  void acceptObject(const JsonObjectData &object) {
+  void visitObject(JsonObject object) {
     _writer.beginObject();
 
-    JsonObjectData::const_iterator it = object.begin();
+    JsonObject::iterator it = object.begin();
     while (it != object.end()) {
-      _writer.writeString(it->key);
+      _writer.writeString(it->key());
       _writer.writeColon();
-      it->value.visit(*this);
+      it->value().accept(*this);
 
       ++it;
       if (it == object.end()) break;
@@ -54,29 +54,29 @@ class JsonSerializer {
     _writer.endObject();
   }
 
-  void acceptString(const char *value) {
+  void visitString(const char *value) {
     _writer.writeString(value);
   }
 
-  void acceptRawJson(const char *data, size_t n) {
+  void visitRawJson(const char *data, size_t n) {
     // TODO
     for (size_t i = 0; i < n; i++) _writer.writeRaw(data[i]);
   }
 
-  void acceptNegativeInteger(JsonUInt value) {
+  void visitNegativeInteger(JsonUInt value) {
     _writer.writeRaw('-');
     _writer.writeInteger(value);
   }
 
-  void acceptPositiveInteger(JsonUInt value) {
+  void visitPositiveInteger(JsonUInt value) {
     _writer.writeInteger(value);
   }
 
-  void acceptBoolean(bool value) {
+  void visitBoolean(bool value) {
     _writer.writeBoolean(value);
   }
 
-  void acceptNull() {
+  void visitNull() {
     _writer.writeRaw("null");
   }
 

+ 86 - 19
src/ArduinoJson/JsonArray.hpp

@@ -4,13 +4,17 @@
 
 #pragma once
 
-#include "JsonArrayData.hpp"
+#include "Data/JsonVariantData.hpp"
 #include "JsonArrayIterator.hpp"
 
+// Returns the size (in bytes) of an array with n elements.
+// Can be very handy to determine the size of a StaticMemoryPool.
+#define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \
+  ((NUMBER_OF_ELEMENTS) * sizeof(ArduinoJson::Internals::Slot))
+
 namespace ArduinoJson {
 
 class JsonObject;
-
 namespace Internals {
 class JsonArraySubscript;
 }
@@ -25,29 +29,52 @@ class JsonArray {
   FORCE_INLINE JsonArray(Internals::MemoryPool* buf,
                          Internals::JsonArrayData* arr)
       : _memoryPool(buf), _data(arr) {}
-  FORCE_INLINE explicit JsonArray(Internals::MemoryPool* buf)
-      : _memoryPool(buf), _data(new (buf) Internals::JsonArrayData()) {}
 
   // Adds the specified value at the end of the array.
   //
   // bool add(TValue);
   // TValue = bool, long, int, short, float, double, serialized, JsonVariant,
-  //          std::string, String, JsonArrayData, JsonObject
+  //          std::string, String, JsonObject
   template <typename T>
   FORCE_INLINE bool add(const T& value) {
-    return add_impl<const T&>(value);
+    return add().set(value);
+  }
+  // Adds the specified value at the end of the array.
+  FORCE_INLINE bool add(JsonArray value) {
+    return add().set(value);
   }
   //
   // bool add(TValue);
   // TValue = char*, const char*, const FlashStringHelper*
   template <typename T>
   FORCE_INLINE bool add(T* value) {
-    return add_impl<T*>(value);
+    return add().set(value);
+  }
+
+  JsonVariant add() {
+    if (!_data) return JsonVariant();
+
+    Internals::Slot* slot = new (_memoryPool) Internals::Slot();
+    if (!slot) return JsonVariant();
+
+    slot->next = 0;
+
+    if (_data->tail) {
+      slot->prev = _data->tail;
+      _data->tail->next = slot;
+      _data->tail = slot;
+    } else {
+      slot->prev = 0;
+      _data->head = slot;
+      _data->tail = slot;
+    }
+
+    return JsonVariant(_memoryPool, &slot->value);
   }
 
   FORCE_INLINE iterator begin() const {
     if (!_data) return iterator();
-    return iterator(_memoryPool, _data->begin());
+    return iterator(_memoryPool, _data->head);
   }
 
   FORCE_INLINE iterator end() const {
@@ -83,6 +110,15 @@ class JsonArray {
     return ok;
   }
 
+  // Copy a JsonArray
+  bool copyFrom(JsonArray src) {
+    bool ok = _data != 0;
+    for (iterator it = src.begin(); it != src.end(); ++it) {
+      ok &= add(*it);
+    }
+    return ok;
+  }
+
   // Exports a 1D array
   template <typename T, size_t N>
   FORCE_INLINE size_t copyTo(T (&array)[N]) const {
@@ -115,8 +151,17 @@ class JsonArray {
   FORCE_INLINE const Internals::JsonArraySubscript operator[](
       size_t index) const;
 
-  FORCE_INLINE bool operator==(const JsonArray& rhs) const {
-    return _data == rhs._data;
+  FORCE_INLINE bool operator==(JsonArray rhs) const {
+    iterator it1 = begin();
+    iterator it2 = rhs.begin();
+    for (;;) {
+      if (it1 == end() && it2 == rhs.end()) return true;
+      if (it1 == end()) return false;
+      if (it2 == end()) return false;
+      if (*it1 != *it2) return false;
+      ++it1;
+      ++it2;
+    }
   }
 
   // Gets the value at the specified index.
@@ -137,7 +182,18 @@ class JsonArray {
   // Removes element at specified position.
   FORCE_INLINE void remove(iterator it) {
     if (!_data) return;
-    _data->remove(it.internal());
+
+    Internals::Slot* slot = it.internal();
+    if (!slot) return;
+
+    if (slot->prev)
+      slot->prev->next = slot->next;
+    else
+      _data->head = slot->next;
+    if (slot->next)
+      slot->next->prev = slot->prev;
+    else
+      _data->tail = slot->prev;
   }
 
   // Removes element at specified index.
@@ -163,10 +219,24 @@ class JsonArray {
     if (!_data) return false;
     return set_impl<T*>(index, value);
   }
+  // Sets the value at specified index.
+  //
+  // bool add(size_t index, JsonArray);
+  template <typename T>
+  FORCE_INLINE bool set(size_t index, JsonArray value) {
+    if (!_data) return false;
+    return get<JsonVariant>(index).set(value);
+  }
 
   FORCE_INLINE size_t size() const {
     if (!_data) return 0;
-    return _data->size();
+    Internals::Slot* slot = _data->head;
+    size_t n = 0;
+    while (slot) {
+      slot = slot->next;
+      n++;
+    }
+    return n;
   }
 
   FORCE_INLINE bool isNull() const {
@@ -174,11 +244,11 @@ class JsonArray {
   }
 
   template <typename Visitor>
-  FORCE_INLINE void visit(Visitor& visitor) const {
+  FORCE_INLINE void accept(Visitor& visitor) const {
     if (_data)
-      visitor.acceptArray(*_data);
+      visitor.visitArray(*this);
     else
-      visitor.acceptNull();
+      visitor.visitNull();
   }
 
  private:
@@ -191,10 +261,7 @@ class JsonArray {
 
   template <typename TValueRef>
   FORCE_INLINE bool add_impl(TValueRef value) {
-    if (!_data) return false;
-    iterator it = iterator(_memoryPool, _data->add(_memoryPool));
-    if (it == end()) return false;
-    return it->set(value);
+    return add().set(value);
   }
 
   Internals::MemoryPool* _memoryPool;

+ 0 - 28
src/ArduinoJson/JsonArrayData.hpp

@@ -1,28 +0,0 @@
-// ArduinoJson - arduinojson.org
-// Copyright Benoit Blanchon 2014-2018
-// MIT License
-
-#pragma once
-
-#include "Data/JsonVariantData.hpp"
-#include "Data/List.hpp"
-#include "Memory/AllocableInMemoryPool.hpp"
-#include "Polyfills/type_traits.hpp"
-
-// Returns the size (in bytes) of an array with n elements.
-// Can be very handy to determine the size of a StaticMemoryPool.
-#define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS)        \
-  (sizeof(ArduinoJson::Internals::JsonArrayData) + \
-   (NUMBER_OF_ELEMENTS) *                          \
-       sizeof(ArduinoJson::Internals::JsonArrayData::node_type))
-
-namespace ArduinoJson {
-namespace Internals {
-struct JsonArrayData : List<JsonVariantData>, AllocableInMemoryPool {
-  JsonVariantData* addSlot(MemoryPool* memoryPool) {
-    iterator it = add(memoryPool);
-    return it != end() ? &*it : 0;
-  }
-};
-}  // namespace Internals
-}  // namespace ArduinoJson

+ 2 - 8
src/ArduinoJson/JsonArrayImpl.hpp

@@ -10,16 +10,10 @@
 namespace ArduinoJson {
 
 inline JsonArray JsonArray::createNestedArray() {
-  if (!_data) return JsonArray();
-  JsonArray array(_memoryPool);
-  if (!array.isNull()) add(array);
-  return array;
+  return add().to<JsonArray>();
 }
 
 inline JsonObject JsonArray::createNestedObject() {
-  if (!_data) return JsonObject();
-  JsonObject object(_memoryPool);
-  if (!object.isNull()) add(object);
-  return object;
+  return add().to<JsonObject>();
 }
 }  // namespace ArduinoJson

+ 16 - 15
src/ArduinoJson/JsonArrayIterator.hpp

@@ -4,7 +4,7 @@
 
 #pragma once
 
-#include "Data/ListIterator.hpp"
+#include "Data/Slot.hpp"
 #include "JsonVariant.hpp"
 
 namespace ArduinoJson {
@@ -28,45 +28,46 @@ class JsonVariantPtr {
 };
 
 class JsonArrayIterator {
-  typedef Internals::ListIterator<Internals::JsonVariantData> internal_iterator;
-
  public:
-  JsonArrayIterator() {}
+  JsonArrayIterator() : _slot(0) {}
   explicit JsonArrayIterator(Internals::MemoryPool *memoryPool,
-                             internal_iterator iterator)
-      : _iterator(iterator), _memoryPool(memoryPool) {}
+                             Internals::Slot *iterator)
+      : _memoryPool(memoryPool), _slot(iterator) {}
 
   JsonVariant operator*() const {
-    return JsonVariant(_memoryPool, &*_iterator);
+    return JsonVariant(_memoryPool, &_slot->value);
   }
   JsonVariantPtr operator->() {
-    return JsonVariantPtr(_memoryPool, &*_iterator);
+    return JsonVariantPtr(_memoryPool, &_slot->value);
   }
 
   bool operator==(const JsonArrayIterator &other) const {
-    return _iterator == other._iterator;
+    return _slot == other._slot;
   }
 
   bool operator!=(const JsonArrayIterator &other) const {
-    return _iterator != other._iterator;
+    return _slot != other._slot;
   }
 
   JsonArrayIterator &operator++() {
-    ++_iterator;
+    _slot = _slot->next;
     return *this;
   }
 
   JsonArrayIterator &operator+=(size_t distance) {
-    _iterator += distance;
+    while (distance && _slot) {
+      _slot = _slot->next;
+      distance--;
+    }
     return *this;
   }
 
-  internal_iterator internal() {
-    return _iterator;
+  Internals::Slot *internal() {
+    return _slot;
   }
 
  private:
-  internal_iterator _iterator;
   Internals::MemoryPool *_memoryPool;
+  Internals::Slot *_slot;
 };
 }  // namespace ArduinoJson

+ 7 - 2
src/ArduinoJson/JsonArraySubscript.hpp

@@ -57,6 +57,11 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
     return _array.is<T>(_index);
   }
 
+  template <typename T>
+  FORCE_INLINE typename JsonVariantTo<T>::type to() {
+    return _array.get<JsonVariant>(_index).to<T>();
+  }
+
   // Replaces the value
   //
   // bool set(const TValue&)
@@ -75,8 +80,8 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
   }
 
   template <typename Visitor>
-  void visit(Visitor& visitor) const {
-    return _array.get<JsonVariant>(_index).visit(visitor);
+  void accept(Visitor& visitor) const {
+    return _array.get<JsonVariant>(_index).accept(visitor);
   }
 
  private:

+ 113 - 51
src/ArduinoJson/JsonObject.hpp

@@ -4,14 +4,17 @@
 
 #pragma once
 
-#include "./JsonObjectData.hpp"
 #include "./JsonObjectIterator.hpp"
 
+// Returns the size (in bytes) of an object with n elements.
+// Can be very handy to determine the size of a StaticMemoryPool.
+#define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \
+  ((NUMBER_OF_ELEMENTS) * sizeof(ArduinoJson::Internals::Slot))
+
 namespace ArduinoJson {
 
 class JsonObject {
   friend class JsonVariant;
-  typedef Internals::JsonObjectData::iterator internal_iterator;
 
  public:
   typedef JsonObjectIterator iterator;
@@ -20,12 +23,15 @@ class JsonObject {
   FORCE_INLINE JsonObject(Internals::MemoryPool* buf,
                           Internals::JsonObjectData* object)
       : _memoryPool(buf), _data(object) {}
-  FORCE_INLINE explicit JsonObject(Internals::MemoryPool* buf)
-      : _memoryPool(buf), _data(new (buf) Internals::JsonObjectData()) {}
 
   FORCE_INLINE iterator begin() const {
     if (!_data) return iterator();
-    return iterator(_memoryPool, _data->begin());
+    return iterator(_memoryPool, _data->head);
+  }
+
+  void clear() {
+    _data->head = 0;
+    _data->tail = 0;
   }
 
   // Tells weither the specified key is present and associated with a value.
@@ -44,6 +50,15 @@ class JsonObject {
     return containsKey_impl<TString*>(key);
   }
 
+  bool copyFrom(JsonObject src) {
+    bool ok = _data != 0;
+    clear();
+    for (iterator it = src.begin(); it != src.end(); ++it) {
+      ok &= set(it->key(), it->value());
+    }
+    return ok;
+  }
+
   FORCE_INLINE iterator end() const {
     return iterator();
   }
@@ -155,13 +170,26 @@ class JsonObject {
     return Internals::JsonObjectSubscript<TString*>(*this, key);
   }
 
-  FORCE_INLINE bool operator==(const JsonObject& rhs) const {
-    return _data == rhs._data;
+  FORCE_INLINE bool operator==(JsonObject rhs) const {
+    if (size() != rhs.size()) return false;
+    for (iterator it = begin(); it != end(); ++it) {
+      if (rhs.get<JsonVariant>(it->key()) != it->value()) return false;
+    }
+    return true;
   }
 
   FORCE_INLINE void remove(iterator it) {
     if (!_data) return;
-    _data->remove(it.internal());
+    Internals::Slot* slot = it.internal();
+    if (!slot) return;
+    if (slot->prev)
+      slot->prev->next = slot->next;
+    else
+      _data->head = slot->next;
+    if (slot->next)
+      slot->next->prev = slot->prev;
+    else
+      _data->tail = slot->prev;
   }
 
   // Removes the specified key and the associated value.
@@ -188,7 +216,7 @@ class JsonObject {
   //          std::string, String, JsonArray, JsonObject
   template <typename TValue, typename TString>
   FORCE_INLINE bool set(const TString& key, const TValue& value) {
-    return set_impl<const TString&, const TValue&>(key, value);
+    return set(key).set(value);
   }
   //
   // bool set(TKey, TValue);
@@ -196,7 +224,7 @@ class JsonObject {
   // TValue = char*, const char*, const FlashStringHelper*
   template <typename TValue, typename TString>
   FORCE_INLINE bool set(const TString& key, TValue* value) {
-    return set_impl<const TString&, TValue*>(key, value);
+    return set(key).set(value);
   }
   //
   // bool set(TKey, const TValue&);
@@ -205,7 +233,7 @@ class JsonObject {
   //          std::string, String, JsonArray, JsonObject
   template <typename TValue, typename TString>
   FORCE_INLINE bool set(TString* key, const TValue& value) {
-    return set_impl<TString*, const TValue&>(key, value);
+    return set(key).set(value);
   }
   //
   // bool set(TKey, TValue);
@@ -213,12 +241,28 @@ class JsonObject {
   // TValue = char*, const char*, const FlashStringHelper*
   template <typename TValue, typename TString>
   FORCE_INLINE bool set(TString* key, TValue* value) {
-    return set_impl<TString*, TValue*>(key, value);
+    return set(key).set(value);
+  }
+
+  template <typename TString>
+  FORCE_INLINE JsonVariant set(TString* key) {
+    return set_impl<TString*>(key);
+  }
+
+  template <typename TString>
+  FORCE_INLINE JsonVariant set(const TString& key) {
+    return set_impl<const TString&>(key);
   }
 
   FORCE_INLINE size_t size() const {
     if (!_data) return 0;
-    return _data->size();
+    size_t n = 0;
+    Internals::Slot* slot = _data->head;
+    while (slot) {
+      n++;
+      slot = slot->next;
+    }
+    return n;
   }
 
   FORCE_INLINE bool isNull() const {
@@ -226,17 +270,17 @@ class JsonObject {
   }
 
   template <typename Visitor>
-  FORCE_INLINE void visit(Visitor& visitor) const {
+  FORCE_INLINE void accept(Visitor& visitor) const {
     if (_data)
-      visitor.acceptObject(*_data);
+      visitor.visitObject(*this);
     else
-      visitor.acceptNull();
+      visitor.visitNull();
   }
 
  private:
   template <typename TStringRef>
   FORCE_INLINE bool containsKey_impl(TStringRef key) const {
-    return findKey<TStringRef>(key) != _data->end();
+    return findSlot<TStringRef>(key) != 0;
   }
 
   template <typename TStringRef>
@@ -247,77 +291,95 @@ class JsonObject {
 
   // Returns the list node that matches the specified key.
   template <typename TStringRef>
-  internal_iterator findKey(TStringRef key) {
-    if (!_data) return internal_iterator();
-    internal_iterator it;
-    for (it = _data->begin(); it != _data->end(); ++it) {
-      if (Internals::makeString(key).equals(it->key)) break;
+  Internals::Slot* findSlot(TStringRef key) {
+    if (!_data) return 0;
+    Internals::Slot* slot = _data->head;
+    while (slot) {
+      if (Internals::makeString(key).equals(slot->key)) break;
+      slot = slot->next;
     }
-    return it;
+    return slot;
   }
   template <typename TStringRef>
-  FORCE_INLINE internal_iterator findKey(TStringRef key) const {
-    return const_cast<JsonObject*>(this)->findKey<TStringRef>(key);
+  FORCE_INLINE Internals::Slot* findSlot(TStringRef key) const {
+    return const_cast<JsonObject*>(this)->findSlot<TStringRef>(key);
   }
 
   template <typename TStringRef, typename TValue>
   FORCE_INLINE typename Internals::JsonVariantAs<TValue>::type get_impl(
       TStringRef key) const {
-    internal_iterator it = findKey<TStringRef>(key);
-    return it != _data->end()
-               ? JsonVariant(_memoryPool, &it->value).as<TValue>()
-               : TValue();
+    Internals::Slot* slot = findSlot<TStringRef>(key);
+    return slot ? JsonVariant(_memoryPool, &slot->value).as<TValue>()
+                : TValue();
   }
 
   template <typename TStringRef, typename TValue>
   FORCE_INLINE bool is_impl(TStringRef key) const {
-    internal_iterator it = findKey<TStringRef>(key);
-    return it != _data->end()
-               ? JsonVariant(_memoryPool, &it->value).is<TValue>()
-               : false;
+    Internals::Slot* slot = findSlot<TStringRef>(key);
+    return slot ? JsonVariant(_memoryPool, &slot->value).is<TValue>() : false;
   }
 
   template <typename TStringRef>
   FORCE_INLINE void remove_impl(TStringRef key) {
     if (!_data) return;
-    _data->remove(findKey<TStringRef>(key));
+    Internals::Slot* slot = findSlot<TStringRef>(key);
+    if (!slot) return;
+    if (slot->prev)
+      slot->prev->next = slot->next;
+    else
+      _data->head = slot->next;
+    if (slot->next)
+      slot->next->prev = slot->prev;
+    else
+      _data->tail = slot->prev;
   }
 
-  template <typename TStringRef, typename TValueRef>
-  FORCE_INLINE bool set_impl(TStringRef key, TValueRef value) {
-    if (!_data) return false;
+  template <typename TStringRef>
+  FORCE_INLINE JsonVariant set_impl(TStringRef key) {
+    if (!_data) return JsonVariant();
 
     // ignore null key
-    if (Internals::makeString(key).is_null()) return false;
+    if (Internals::makeString(key).is_null()) return JsonVariant();
 
     // search a matching key
-    internal_iterator it = findKey<TStringRef>(key);
-    if (it == _data->end()) {
+    Internals::Slot* slot = findSlot<TStringRef>(key);
+    if (!slot) {
       // add the key
-      // TODO: use JsonPairData directly, we don't need an iterator
-      it = _data->add(_memoryPool);
-      if (it == _data->end()) return false;
-      if (!set_key(it, key)) return false;
+      slot = new (_memoryPool) Internals::Slot();
+      if (!slot) return JsonVariant();
+
+      slot->next = 0;
+
+      if (_data->tail) {
+        slot->prev = _data->tail;
+        _data->tail->next = slot;
+        _data->tail = slot;
+      } else {
+        slot->prev = 0;
+        _data->head = slot;
+        _data->tail = slot;
+      }
+
+      if (!set_key(slot, key)) return JsonVariant();
     }
 
-    // save the value
-    return JsonVariant(_memoryPool, &it->value).set(value);
+    return JsonVariant(_memoryPool, &slot->value);
   }
 
-  FORCE_INLINE bool set_key(internal_iterator& it, const char* key) {
-    it->key = key;
+  FORCE_INLINE bool set_key(Internals::Slot* slot, const char* key) {
+    slot->key = key;
     return true;
   }
 
   template <typename T>
-  FORCE_INLINE bool set_key(internal_iterator& it, const T& key) {
+  FORCE_INLINE bool set_key(Internals::Slot* slot, const T& key) {
     const char* dup = Internals::makeString(key).save(_memoryPool);
     if (!dup) return false;
-    it->key = dup;
+    slot->key = dup;
     return true;
   }
 
   mutable Internals::MemoryPool* _memoryPool;
   mutable Internals::JsonObjectData* _data;
-};
+};  // namespace ArduinoJson
 }  // namespace ArduinoJson

+ 0 - 30
src/ArduinoJson/JsonObjectData.hpp

@@ -1,30 +0,0 @@
-// ArduinoJson - arduinojson.org
-// Copyright Benoit Blanchon 2014-2018
-// MIT License
-
-#pragma once
-
-#include "Data/List.hpp"
-#include "JsonPair.hpp"
-#include "Memory/AllocableInMemoryPool.hpp"
-#include "Polyfills/type_traits.hpp"
-
-// Returns the size (in bytes) of an object with n elements.
-// Can be very handy to determine the size of a StaticMemoryPool.
-#define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS)        \
-  (sizeof(ArduinoJson::Internals::JsonObjectData) + \
-   (NUMBER_OF_ELEMENTS) *                           \
-       sizeof(ArduinoJson::Internals::JsonObjectData::node_type))
-
-namespace ArduinoJson {
-namespace Internals {
-struct JsonObjectData : List<JsonPairData>, AllocableInMemoryPool {
-  JsonVariantData* addSlot(MemoryPool* memoryPool, const char* key) {
-    iterator it = add(memoryPool);
-    if (it == end()) return 0;
-    it->key = key;
-    return &it->value;
-  }
-};
-}  // namespace Internals
-}  // namespace ArduinoJson

+ 2 - 6
src/ArduinoJson/JsonObjectImpl.hpp

@@ -22,16 +22,12 @@ inline JsonArray JsonObject::createNestedArray(TString* key) {
 template <typename TStringRef>
 inline JsonArray JsonObject::createNestedArray_impl(TStringRef key) {
   if (!_data) return JsonArray();
-  JsonArray array(_memoryPool);
-  if (!array.isNull()) set(key, array);
-  return array;
+  return set(key).template to<JsonArray>();
 }
 
 template <typename TStringRef>
 inline JsonObject JsonObject::createNestedObject_impl(TStringRef key) {
   if (!_data) return JsonObject();
-  JsonObject object(_memoryPool);
-  if (!object.isNull()) set(key, object);
-  return object;
+  return set(key).template to<JsonObject>();
 }
 }  // namespace ArduinoJson

+ 18 - 18
src/ArduinoJson/JsonObjectIterator.hpp

@@ -4,15 +4,14 @@
 
 #pragma once
 
-#include "Data/ListIterator.hpp"
 #include "JsonPair.hpp"
 
 namespace ArduinoJson {
 
 class JsonPairPtr {
  public:
-  JsonPairPtr(Internals::MemoryPool *memoryPool, Internals::JsonPairData *data)
-      : _pair(memoryPool, data) {}
+  JsonPairPtr(Internals::MemoryPool *memoryPool, Internals::Slot *slot)
+      : _pair(memoryPool, slot) {}
 
   const JsonPair *operator->() const {
     return &_pair;
@@ -26,47 +25,48 @@ class JsonPairPtr {
   JsonPair _pair;
 };
 
-// A read-write forward iterator for JsonArray
 class JsonObjectIterator {
-  typedef Internals::ListIterator<Internals::JsonPairData> internal_iterator;
-
  public:
-  JsonObjectIterator() {}
+  JsonObjectIterator() : _slot(0) {}
+
   explicit JsonObjectIterator(Internals::MemoryPool *memoryPool,
-                              internal_iterator iterator)
-      : _memoryPool(memoryPool), _iterator(iterator) {}
+                              Internals::Slot *slot)
+      : _memoryPool(memoryPool), _slot(slot) {}
 
   JsonPair operator*() const {
-    return JsonPair(_memoryPool, &*_iterator);
+    return JsonPair(_memoryPool, _slot);
   }
   JsonPairPtr operator->() {
-    return JsonPairPtr(_memoryPool, &*_iterator);
+    return JsonPairPtr(_memoryPool, _slot);
   }
 
   bool operator==(const JsonObjectIterator &other) const {
-    return _iterator == other._iterator;
+    return _slot == other._slot;
   }
 
   bool operator!=(const JsonObjectIterator &other) const {
-    return _iterator != other._iterator;
+    return _slot != other._slot;
   }
 
   JsonObjectIterator &operator++() {
-    ++_iterator;
+    if (_slot) _slot = _slot->next;
     return *this;
   }
 
   JsonObjectIterator &operator+=(size_t distance) {
-    _iterator += distance;
+    while (_slot && distance > 0) {
+      _slot = _slot->next;
+      distance--;
+    }
     return *this;
   }
 
-  internal_iterator internal() {
-    return _iterator;
+  Internals::Slot *internal() {
+    return _slot;
   }
 
  private:
   Internals::MemoryPool *_memoryPool;
-  internal_iterator _iterator;
+  Internals::Slot *_slot;
 };
 }  // namespace ArduinoJson

+ 7 - 2
src/ArduinoJson/JsonObjectSubscript.hpp

@@ -64,6 +64,11 @@ class JsonObjectSubscript
     return _object.is<TValue>(_key);
   }
 
+  template <typename TValue>
+  FORCE_INLINE typename JsonVariantTo<TValue>::type to() {
+    return _object.set(_key).template to<TValue>();
+  }
+
   // Sets the specified value.
   //
   // bool set(const TValue&);
@@ -84,8 +89,8 @@ class JsonObjectSubscript
   }
 
   template <typename Visitor>
-  void visit(Visitor &visitor) const {
-    return _object.get<JsonVariant>(_key).visit(visitor);
+  void accept(Visitor &visitor) const {
+    return _object.get<JsonVariant>(_key).accept(visitor);
   }
 
  private:

+ 8 - 10
src/ArduinoJson/JsonPair.hpp

@@ -8,19 +8,17 @@
 
 namespace ArduinoJson {
 
-namespace Internals {
-
-struct JsonPairData {
-  const char* key;
-  JsonVariantData value;
-};
-}  // namespace Internals
-
 // A key value pair for JsonObjectData.
 class JsonPair {
  public:
-  JsonPair(Internals::MemoryPool* memoryPool, Internals::JsonPairData* data)
-      : _key(data->key), _value(memoryPool, &data->value) {}
+  JsonPair(Internals::MemoryPool* memoryPool, Internals::Slot* slot) {
+    if (slot) {
+      _key = slot->key;
+      _value = JsonVariant(memoryPool, &slot->value);
+    } else {
+      _key = 0;
+    }
+  }
 
   const char* key() const {
     return _key;

+ 33 - 22
src/ArduinoJson/JsonVariant.hpp

@@ -92,7 +92,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
   // set(SerializedValue<const char *>)
   FORCE_INLINE bool set(Internals::SerializedValue<const char *> value) {
     if (!_data) return false;
-    _data->setRaw(value.data(), value.size());
+    _data->setLinkedRaw(value.data(), value.size());
     return true;
   }
 
@@ -108,7 +108,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
     const char *dup =
         Internals::makeString(value.data(), value.size()).save(_memoryPool);
     if (dup)
-      _data->setRaw(dup, value.size());
+      _data->setOwnedRaw(dup, value.size());
     else
       _data->setNull();
     return true;
@@ -124,7 +124,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
     if (!_data) return false;
     const char *dup = Internals::makeString(value).save(_memoryPool);
     if (dup) {
-      _data->setString(dup);
+      _data->setOwnedString(dup);
       return true;
     } else {
       _data->setNull();
@@ -141,7 +141,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
     if (!_data) return false;
     const char *dup = Internals::makeString(value).save(_memoryPool);
     if (dup) {
-      _data->setString(dup);
+      _data->setOwnedString(dup);
       return true;
     } else {
       _data->setNull();
@@ -152,22 +152,15 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
   // set(const char*);
   FORCE_INLINE bool set(const char *value) {
     if (!_data) return false;
-    _data->setString(value);
+    _data->setLinkedString(value);
     return true;
   }
 
-  FORCE_INLINE bool set(const JsonVariant &value) {
-    if (!_data) return false;
-    if (value._data)
-      *_data = *value._data;
-    else
-      _data->setNull();
-    return true;
-  }
+  bool set(const JsonVariant &value);
 
-  FORCE_INLINE bool set(const JsonArray &array);
+  FORCE_INLINE bool set(JsonArray array);
   FORCE_INLINE bool set(const Internals::JsonArraySubscript &);
-  FORCE_INLINE bool set(const JsonObject &object);
+  FORCE_INLINE bool set(JsonObject object);
   template <typename TString>
   FORCE_INLINE bool set(const Internals::JsonObjectSubscript<TString> &);
 
@@ -327,19 +320,37 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
     return _data && _data->isObject();
   }
 
-  // Returns true if the variant has a value
   FORCE_INLINE bool isNull() const {
     return _data == 0 || _data->isNull();
   }
 
-  template <typename Visitor>
-  FORCE_INLINE void visit(Visitor &visitor) const {
-    if (_data)
-      _data->visit(visitor);
-    else
-      visitor.acceptNull();
+  FORCE_INLINE bool isInvalid() const {
+    return _data == 0;
   }
 
+  template <typename Visitor>
+  void accept(Visitor &visitor) const;
+
+  // Change the type of the variant
+  //
+  // JsonArray to<JsonArray>()
+  template <typename T>
+  typename Internals::enable_if<Internals::is_same<T, JsonArray>::value,
+                                JsonArray>::type
+  to();
+  //
+  // JsonObject to<JsonObject>()
+  template <typename T>
+  typename Internals::enable_if<Internals::is_same<T, JsonObject>::value,
+                                JsonObject>::type
+  to();
+  //
+  // JsonObject to<JsonVariant>()
+  template <typename T>
+  typename Internals::enable_if<Internals::is_same<T, JsonVariant>::value,
+                                JsonVariant>::type
+  to();
+
  private:
   Internals::MemoryPool *_memoryPool;
   Internals::JsonVariantData *_data;

+ 91 - 16
src/ArduinoJson/JsonVariantImpl.hpp

@@ -5,8 +5,6 @@
 #pragma once
 
 #include "Configuration.hpp"
-#include "JsonArrayData.hpp"
-#include "JsonObjectData.hpp"
 #include "JsonVariant.hpp"
 #include "Numbers/parseFloat.hpp"
 #include "Numbers/parseInteger.hpp"
@@ -15,26 +13,16 @@
 
 namespace ArduinoJson {
 
-inline bool JsonVariant::set(const JsonArray& array) {
-  if (!_data) return false;
-  if (array._data)
-    _data->setArray(*array._data);
-  else
-    _data->setNull();
-  return true;
+inline bool JsonVariant::set(JsonArray array) {
+  return to<JsonArray>().copyFrom(array);
 }
 
 inline bool JsonVariant::set(const Internals::JsonArraySubscript& value) {
   return set(value.as<JsonVariant>());
 }
 
-inline bool JsonVariant::set(const JsonObject& object) {
-  if (!_data) return false;
-  if (object._data)
-    _data->setObject(*object._data);
-  else
-    _data->setNull();
-  return true;
+inline bool JsonVariant::set(JsonObject object) {
+  return to<JsonObject>().copyFrom(object);
 }
 
 template <typename TString>
@@ -43,6 +31,28 @@ inline bool JsonVariant::set(
   return set(value.template as<JsonVariant>());
 }
 
+inline bool JsonVariant::set(const JsonVariant& value) {
+  if (!_data) return false;
+  if (!value._data) {
+    _data->setNull();
+    return true;
+  }
+  switch (value._data->type) {
+    case Internals::JSON_ARRAY:
+      return set(value.as<JsonArray>());
+    case Internals::JSON_OBJECT:
+      return set(value.as<JsonObject>());
+    case Internals::JSON_OWNED_STRING:
+      return set(const_cast<char*>(value._data->content.asString));
+    case Internals::JSON_OWNED_RAW:
+      return set(serialized(const_cast<char*>(value._data->content.asRaw.data),
+                            value._data->content.asRaw.size));
+    default:
+      *_data = *value._data;
+      return true;
+  }
+}
+
 template <typename T>
 inline typename Internals::enable_if<
     Internals::is_same<typename Internals::remove_const<T>::type,
@@ -60,4 +70,69 @@ inline typename Internals::enable_if<
 JsonVariant::as() const {
   return _data ? JsonObject(_memoryPool, _data->asObject()) : JsonObject();
 }
+
+template <typename T>
+inline typename Internals::enable_if<Internals::is_same<T, JsonArray>::value,
+                                     JsonArray>::type
+JsonVariant::to() {
+  if (!_data) return JsonArray();
+  return JsonArray(_memoryPool, _data->toArray());
+}
+
+template <typename T>
+typename Internals::enable_if<Internals::is_same<T, JsonObject>::value,
+                              JsonObject>::type
+JsonVariant::to() {
+  if (!_data) return JsonObject();
+  return JsonObject(_memoryPool, _data->toObject());
+}
+
+template <typename T>
+typename Internals::enable_if<Internals::is_same<T, JsonVariant>::value,
+                              JsonVariant>::type
+JsonVariant::to() {
+  if (!_data) return JsonVariant();
+  _data->setNull();
+  return *this;
+}
+
+template <typename Visitor>
+inline void JsonVariant::accept(Visitor& visitor) const {
+  using namespace Internals;
+  if (!_data) return visitor.visitNull();
+
+  switch (_data->type) {
+    case JSON_FLOAT:
+      return visitor.visitFloat(_data->content.asFloat);
+
+    case JSON_ARRAY:
+      return visitor.visitArray(
+          JsonArray(_memoryPool, &_data->content.asArray));
+
+    case JSON_OBJECT:
+      return visitor.visitObject(
+          JsonObject(_memoryPool, &_data->content.asObject));
+
+    case JSON_LINKED_STRING:
+    case JSON_OWNED_STRING:
+      return visitor.visitString(_data->content.asString);
+
+    case JSON_LINKED_RAW:
+    case JSON_OWNED_RAW:
+      return visitor.visitRawJson(_data->content.asRaw.data,
+                                  _data->content.asRaw.size);
+
+    case JSON_NEGATIVE_INTEGER:
+      return visitor.visitNegativeInteger(_data->content.asInteger);
+
+    case JSON_POSITIVE_INTEGER:
+      return visitor.visitPositiveInteger(_data->content.asInteger);
+
+    case JSON_BOOLEAN:
+      return visitor.visitBoolean(_data->content.asInteger != 0);
+
+    default:
+      return visitor.visitNull();
+  }
+}
 }  // namespace ArduinoJson

+ 0 - 1
src/ArduinoJson/Memory/AllocableInMemoryPool.hpp

@@ -12,7 +12,6 @@ namespace Internals {
 class AllocableInMemoryPool {
  public:
   void *operator new(size_t n, MemoryPool *memoryPool) NOEXCEPT {
-    if (!memoryPool) return NULL;
     return memoryPool->alloc(n);
   }
 

+ 2 - 3
src/ArduinoJson/Memory/DynamicMemoryPool.hpp

@@ -155,9 +155,9 @@ class DynamicMemoryPoolBase : public MemoryPool {
 // Implements a MemoryPool with dynamic memory allocation.
 // You are strongly encouraged to consider using StaticMemoryPool which is much
 // more suitable for embedded systems.
-typedef Internals::DynamicMemoryPoolBase<Internals::DefaultAllocator>
-    DynamicMemoryPool;
+typedef DynamicMemoryPoolBase<DefaultAllocator> DynamicMemoryPool;
 }  // namespace Internals
+}  // namespace ArduinoJson
 
 #if defined(__clang__)
 #pragma clang diagnostic pop
@@ -166,4 +166,3 @@ typedef Internals::DynamicMemoryPoolBase<Internals::DefaultAllocator>
 #pragma GCC diagnostic pop
 #endif
 #endif
-}  // namespace ArduinoJson

+ 3 - 3
src/ArduinoJson/Memory/StaticMemoryPool.hpp

@@ -107,12 +107,12 @@ class StaticMemoryPoolBase : public MemoryPool {
 // The template paramenter CAPACITY specifies the capacity of the memoryPool in
 // bytes.
 template <size_t CAPACITY>
-class StaticMemoryPool : public Internals::StaticMemoryPoolBase {
-  static const size_t ACTUAL_CAPACITY = Internals::Max<1, CAPACITY>::value;
+class StaticMemoryPool : public StaticMemoryPoolBase {
+  static const size_t ACTUAL_CAPACITY = Max<1, CAPACITY>::value;
 
  public:
   explicit StaticMemoryPool()
-      : Internals::StaticMemoryPoolBase(_buffer, ACTUAL_CAPACITY) {}
+      : StaticMemoryPoolBase(_buffer, ACTUAL_CAPACITY) {}
 
  private:
   char _buffer[ACTUAL_CAPACITY];

+ 38 - 40
src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp

@@ -24,17 +24,17 @@ class MsgPackDeserializer {
         _stringStorage(stringStorage),
         _nestingLimit(nestingLimit) {}
 
-  DeserializationError parse(JsonVariantData &variant) {
+  DeserializationError parse(JsonVariant variant) {
     uint8_t code;
     if (!readByte(code)) return DeserializationError::IncompleteInput;
 
     if ((code & 0x80) == 0) {
-      variant.setInteger(code);
+      variant.set(code);
       return DeserializationError::Ok;
     }
 
     if ((code & 0xe0) == 0xe0) {
-      variant.setInteger(static_cast<int8_t>(code));
+      variant.set(static_cast<int8_t>(code));
       return DeserializationError::Ok;
     }
 
@@ -48,15 +48,15 @@ class MsgPackDeserializer {
 
     switch (code) {
       case 0xc0:
-        variant.setNull();
+        // already null
         return DeserializationError::Ok;
 
       case 0xc2:
-        variant.setBoolean(false);
+        variant.set(false);
         return DeserializationError::Ok;
 
       case 0xc3:
-        variant.setBoolean(true);
+        variant.set(true);
         return DeserializationError::Ok;
 
       case 0xcc:
@@ -171,54 +171,54 @@ class MsgPackDeserializer {
   }
 
   template <typename T>
-  DeserializationError readInteger(JsonVariantData &variant) {
+  DeserializationError readInteger(JsonVariant variant) {
     T value;
     if (!readInteger(value)) return DeserializationError::IncompleteInput;
-    variant.setInteger(value);
+    variant.set(value);
     return DeserializationError::Ok;
   }
 
   template <typename T>
   typename enable_if<sizeof(T) == 4, DeserializationError>::type readFloat(
-      JsonVariantData &variant) {
+      JsonVariant variant) {
     T value;
     if (!readBytes(value)) return DeserializationError::IncompleteInput;
     fixEndianess(value);
-    variant.setFloat(value);
+    variant.set(value);
     return DeserializationError::Ok;
   }
 
   template <typename T>
   typename enable_if<sizeof(T) == 8, DeserializationError>::type readDouble(
-      JsonVariantData &variant) {
+      JsonVariant variant) {
     T value;
     if (!readBytes(value)) return DeserializationError::IncompleteInput;
     fixEndianess(value);
-    variant.setFloat(value);
+    variant.set(value);
     return DeserializationError::Ok;
   }
 
   template <typename T>
   typename enable_if<sizeof(T) == 4, DeserializationError>::type readDouble(
-      JsonVariantData &variant) {
+      JsonVariant variant) {
     uint8_t i[8];  // input is 8 bytes
     T value;       // output is 4 bytes
     uint8_t *o = reinterpret_cast<uint8_t *>(&value);
     if (!readBytes(i, 8)) return DeserializationError::IncompleteInput;
     doubleToFloat(i, o);
     fixEndianess(value);
-    variant.setFloat(value);
+    variant.set(value);
     return DeserializationError::Ok;
   }
 
   template <typename T>
-  DeserializationError readString(JsonVariantData &variant) {
+  DeserializationError readString(JsonVariant variant) {
     T size;
     if (!readInteger(size)) return DeserializationError::IncompleteInput;
     return readString(variant, size);
   }
 
-  DeserializationError readString(JsonVariantData &variant, size_t n) {
+  DeserializationError readString(JsonVariant variant, size_t n) {
     typename remove_reference<TStringStorage>::type::String str =
         _stringStorage.startString();
     for (; n; --n) {
@@ -228,33 +228,31 @@ class MsgPackDeserializer {
     }
     const char *s = str.c_str();
     if (s == NULL) return DeserializationError::NoMemory;
-    variant.setString(s);
+    variant.set(s);
     return DeserializationError::Ok;
   }
 
   template <typename TSize>
-  DeserializationError readArray(JsonVariantData &variant) {
+  DeserializationError readArray(JsonVariant variant) {
     TSize size;
     if (!readInteger(size)) return DeserializationError::IncompleteInput;
     return readArray(variant, size);
   }
 
-  DeserializationError readArray(JsonVariantData &variant, size_t n) {
-    JsonArrayData *array = new (_memoryPool) JsonArrayData;
-    if (!array) return DeserializationError::NoMemory;
-
-    variant.setArray(*array);
-    return readArray(*array, n);
+  DeserializationError readArray(JsonVariant variant, size_t n) {
+    JsonArray array = variant.to<JsonArray>();
+    if (array.isNull()) return DeserializationError::NoMemory;
+    return readArray(array, n);
   }
 
-  DeserializationError readArray(JsonArrayData &array, size_t n) {
+  DeserializationError readArray(JsonArray array, size_t n) {
     if (_nestingLimit == 0) return DeserializationError::TooDeep;
     --_nestingLimit;
     for (; n; --n) {
-      JsonVariantData *value = array.addSlot(_memoryPool);
-      if (!value) return DeserializationError::NoMemory;
+      JsonVariant value = array.add();
+      if (value.isInvalid()) return DeserializationError::NoMemory;
 
-      DeserializationError err = parse(*value);
+      DeserializationError err = parse(value);
       if (err) return err;
     }
     ++_nestingLimit;
@@ -262,33 +260,33 @@ class MsgPackDeserializer {
   }
 
   template <typename TSize>
-  DeserializationError readObject(JsonVariantData &variant) {
+  DeserializationError readObject(JsonVariant variant) {
     TSize size;
     if (!readInteger(size)) return DeserializationError::IncompleteInput;
     return readObject(variant, size);
   }
 
-  DeserializationError readObject(JsonVariantData &variant, size_t n) {
-    JsonObjectData *object = new (_memoryPool) JsonObjectData;
-    if (!object) return DeserializationError::NoMemory;
-    variant.setObject(*object);
+  DeserializationError readObject(JsonVariant variant, size_t n) {
+    JsonObject object = variant.to<JsonObject>();
+    if (object.isNull()) return DeserializationError::NoMemory;
 
-    return readObject(*object, n);
+    return readObject(object, n);
   }
 
-  DeserializationError readObject(JsonObjectData &object, size_t n) {
+  DeserializationError readObject(JsonObject object, size_t n) {
     if (_nestingLimit == 0) return DeserializationError::TooDeep;
     --_nestingLimit;
     for (; n; --n) {
-      JsonVariantData key;
+      JsonVariantData keyData;
+      JsonVariant key(_memoryPool, &keyData);
       DeserializationError err = parse(key);
       if (err) return err;
-      if (!key.isString()) return DeserializationError::NotSupported;
+      if (!keyData.isString()) return DeserializationError::NotSupported;
 
-      JsonVariantData *value = object.addSlot(_memoryPool, key.asString());
-      if (!value) return DeserializationError::NoMemory;
+      JsonVariant value = object.set(keyData.asString());
+      if (value.isInvalid()) return DeserializationError::NoMemory;
 
-      err = parse(*value);
+      err = parse(value);
       if (err) return err;
     }
     ++_nestingLimit;

+ 15 - 17
src/ArduinoJson/MsgPack/MsgPackSerializer.hpp

@@ -19,13 +19,13 @@ class MsgPackSerializer {
   MsgPackSerializer(TWriter& writer) : _writer(&writer), _bytesWritten(0) {}
 
   template <typename T>
-  typename enable_if<sizeof(T) == 4>::type acceptFloat(T value32) {
+  typename enable_if<sizeof(T) == 4>::type visitFloat(T value32) {
     writeByte(0xCA);
     writeInteger(value32);
   }
 
   template <typename T>
-  typename enable_if<sizeof(T) == 8>::type acceptFloat(T value64) {
+  typename enable_if<sizeof(T) == 8>::type visitFloat(T value64) {
     float value32 = float(value64);
     if (value32 == value64) {
       writeByte(0xCA);
@@ -36,7 +36,7 @@ class MsgPackSerializer {
     }
   }
 
-  void acceptArray(const JsonArrayData& array) {
+  void visitArray(JsonArray array) {
     size_t n = array.size();
     if (n < 0x10) {
       writeByte(uint8_t(0x90 + array.size()));
@@ -47,13 +47,12 @@ class MsgPackSerializer {
       writeByte(0xDD);
       writeInteger(uint32_t(n));
     }
-    for (JsonArrayData::const_iterator it = array.begin(); it != array.end();
-         ++it) {
-      it->visit(*this);
+    for (JsonArray::iterator it = array.begin(); it != array.end(); ++it) {
+      it->accept(*this);
     }
   }
 
-  void acceptObject(const JsonObjectData& object) {
+  void visitObject(JsonObject object) {
     size_t n = object.size();
     if (n < 0x10) {
       writeByte(uint8_t(0x80 + n));
@@ -64,14 +63,13 @@ class MsgPackSerializer {
       writeByte(0xDF);
       writeInteger(uint32_t(n));
     }
-    for (JsonObjectData::const_iterator it = object.begin(); it != object.end();
-         ++it) {
-      acceptString(it->key);
-      it->value.visit(*this);
+    for (JsonObject::iterator it = object.begin(); it != object.end(); ++it) {
+      visitString(it->key());
+      it->value().accept(*this);
     }
   }
 
-  void acceptString(const char* value) {
+  void visitString(const char* value) {
     if (!value) return writeByte(0xC0);  // nil
 
     size_t n = strlen(value);
@@ -91,11 +89,11 @@ class MsgPackSerializer {
     writeBytes(reinterpret_cast<const uint8_t*>(value), n);
   }
 
-  void acceptRawJson(const char* data, size_t size) {
+  void visitRawJson(const char* data, size_t size) {
     writeBytes(reinterpret_cast<const uint8_t*>(data), size);
   }
 
-  void acceptNegativeInteger(JsonUInt value) {
+  void visitNegativeInteger(JsonUInt value) {
     JsonUInt negated = JsonUInt(~value + 1);
     if (value <= 0x20) {
       writeInteger(int8_t(negated));
@@ -117,7 +115,7 @@ class MsgPackSerializer {
 #endif
   }
 
-  void acceptPositiveInteger(JsonUInt value) {
+  void visitPositiveInteger(JsonUInt value) {
     if (value <= 0x7F) {
       writeInteger(uint8_t(value));
     } else if (value <= 0xFF) {
@@ -138,11 +136,11 @@ class MsgPackSerializer {
 #endif
   }
 
-  void acceptBoolean(bool value) {
+  void visitBoolean(bool value) {
     writeByte(value ? 0xC3 : 0xC2);
   }
 
-  void acceptNull() {
+  void visitNull() {
     writeByte(0xC0);
   }
 

+ 1 - 1
src/ArduinoJson/Serialization/measure.hpp

@@ -13,7 +13,7 @@ template <template <typename> class TSerializer, typename TSource>
 size_t measure(const TSource &source) {
   DummyWriter dp;
   TSerializer<DummyWriter> serializer(dp);
-  source.visit(serializer);
+  source.accept(serializer);
   return serializer.bytesWritten();
 }
 

+ 1 - 1
src/ArduinoJson/Serialization/serialize.hpp

@@ -19,7 +19,7 @@ template <template <typename> class TSerializer, typename TSource,
 typename enable_if<!IsWriteableString<TPrint>::value, size_t>::type serialize(
     const TSource &source, TPrint &destination) {
   TSerializer<TPrint> serializer(destination);
-  source.visit(serializer);
+  source.accept(serializer);
   return serializer.bytesWritten();
 }
 

+ 6 - 40
src/ArduinoJson/StaticJsonDocument.hpp

@@ -4,6 +4,7 @@
 
 #pragma once
 
+#include "Data/JsonVariantTo.hpp"
 #include "JsonVariant.hpp"
 #include "Memory/StaticMemoryPool.hpp"
 
@@ -30,45 +31,10 @@ class StaticJsonDocument {
     return getVariant().template as<T>();
   }
 
-  // JsonObject to<JsonObject>()
   template <typename T>
-  typename Internals::enable_if<Internals::is_same<T, JsonObject>::value,
-                                JsonObject>::type
-  to() {
-    clear();
-    JsonObject object(&_memoryPool);
-    getVariant().set(object);
-    return object;
-  }
-
-  // JsonArray to<JsonArray>()
-  template <typename T>
-  typename Internals::enable_if<Internals::is_same<T, JsonArray>::value,
-                                JsonArray>::type
-  to() {
-    clear();
-    JsonArray array(&_memoryPool);
-    getVariant().set(array);
-    return array;
-  }
-
-  // JsonVariant to<JsonVariant>()
-  template <typename T>
-  typename Internals::enable_if<Internals::is_same<T, JsonVariant>::value,
-                                JsonVariant>::type
-  to() {
-    clear();
-    return getVariant();
-  }
-
-  // JsonVariantData& to<JsonVariantData>()
-  template <typename T>
-  typename Internals::enable_if<
-      Internals::is_same<T, Internals::JsonVariantData>::value,
-      Internals::JsonVariantData&>::type
-  to() {
-    clear();
-    return _rootData;
+  typename Internals::JsonVariantTo<T>::type to() {
+    _memoryPool.clear();
+    return getVariant().template to<T>();
   }
 
   void clear() {
@@ -81,8 +47,8 @@ class StaticJsonDocument {
   }
 
   template <typename Visitor>
-  void visit(Visitor& visitor) const {
-    return getVariant().visit(visitor);
+  void accept(Visitor& visitor) const {
+    return getVariant().accept(visitor);
   }
 
  private:

+ 5 - 2
test/JsonArray/copyFrom.cpp

@@ -51,11 +51,14 @@ TEST_CASE("JsonArray::copyFrom()") {
         JSON_ARRAY_SIZE(2) + JSON_ARRAY_SIZE(3) + JSON_ARRAY_SIZE(2);
     StaticJsonDocument<SIZE> doc;
     JsonArray array = doc.to<JsonArray>();
-    char json[32];
+    char json[32] = "";
     int source[][3] = {{1, 2, 3}, {4, 5, 6}};
 
+    CAPTURE(SIZE)
+
     bool ok = array.copyFrom(source);
-    REQUIRE_FALSE(ok);
+    CAPTURE(doc.memoryUsage());
+    CHECK_FALSE(ok);
 
     serializeJson(array, json, sizeof(json));
     REQUIRE(std::string("[[1,2,3],[4,5]]") == json);

+ 5 - 5
test/JsonArray/isNull.cpp

@@ -17,9 +17,9 @@ TEST_CASE("JsonArray::isNull()") {
     REQUIRE(array.isNull() == false);
   }
 
-  SECTION("returns true when allocation fails") {
-    StaticJsonDocument<1> doc;
-    JsonArray array = doc.to<JsonArray>();
-    REQUIRE(array.isNull() == true);
-  }
+  /*  SECTION("returns true when allocation fails") {
+      StaticJsonDocument<1> doc;
+      JsonArray array = doc.to<JsonArray>();
+      REQUIRE(array.isNull() == true);
+    }*/
 }

+ 5 - 0
test/JsonArray/subscript.cpp

@@ -119,6 +119,11 @@ TEST_CASE("JsonArray::operator[]") {
     REQUIRE(expectedSize == doc.memoryUsage());
   }
 
+  SECTION("array[0].to<JsonObject>()") {
+    JsonObject obj = array[0].to<JsonObject>();
+    REQUIRE(obj.isNull() == false);
+  }
+
 #ifdef HAS_VARIABLE_LENGTH_ARRAY
   SECTION("set(VLA)") {
     int i = 16;

+ 21 - 0
test/JsonDocument/DynamicJsonDocument.cpp

@@ -17,4 +17,25 @@ TEST_CASE("DynamicJsonDocument") {
 
     REQUIRE(json == "{\"hello\":\"world\"}");
   }
+
+  SECTION("memoryUsage()") {
+    SECTION("starts at zero") {
+      REQUIRE(doc.memoryUsage() == 0);
+    }
+
+    SECTION("JSON_ARRAY_SIZE(0)") {
+      doc.to<JsonArray>();
+      REQUIRE(doc.memoryUsage() == JSON_ARRAY_SIZE(0));
+    }
+
+    SECTION("JSON_ARRAY_SIZE(1)") {
+      doc.to<JsonArray>().add(42);
+      REQUIRE(doc.memoryUsage() == JSON_ARRAY_SIZE(1));
+    }
+
+    SECTION("JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(0)") {
+      doc.to<JsonArray>().createNestedArray();
+      REQUIRE(doc.memoryUsage() == JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(0));
+    }
+  }
 }

+ 4 - 2
test/JsonObject/createNestedArray.cpp

@@ -10,7 +10,8 @@ TEST_CASE("JsonObject::createNestedArray()") {
   JsonObject obj = doc.to<JsonObject>();
 
   SECTION("key is a const char*") {
-    obj.createNestedArray("hello");
+    JsonArray arr = obj.createNestedArray("hello");
+    REQUIRE(arr.isNull() == false);
   }
 
 #ifdef HAS_VARIABLE_LENGTH_ARRAY
@@ -19,7 +20,8 @@ TEST_CASE("JsonObject::createNestedArray()") {
     char vla[i];
     strcpy(vla, "hello");
 
-    obj.createNestedArray(vla);
+    JsonArray arr = obj.createNestedArray(vla);
+    REQUIRE(arr.isNull() == false);
   }
 #endif
 }

+ 5 - 5
test/JsonObject/isNull.cpp

@@ -17,9 +17,9 @@ TEST_CASE("JsonObject::isNull()") {
     REQUIRE(array.isNull() == false);
   }
 
-  SECTION("returns true when allocation fails") {
-    StaticJsonDocument<1> doc;
-    JsonObject array = doc.to<JsonObject>();
-    REQUIRE(array.isNull() == true);
-  }
+  /*  SECTION("returns true when allocation fails") {
+      StaticJsonDocument<1> doc;
+      JsonObject array = doc.to<JsonObject>();
+      REQUIRE(array.isNull() == true);
+    }*/
 }

+ 5 - 0
test/JsonObject/iterator.cpp

@@ -40,4 +40,9 @@ TEST_CASE("JsonObject::begin()/end()") {
   //   ++it;
   //   REQUIRE(const_object.end() == it);
   // }
+
+  SECTION("Dereferencing end() is safe") {
+    REQUIRE(obj.end()->key() == 0);
+    REQUIRE(obj.end()->value().isNull());
+  }
 }

+ 41 - 24
test/JsonObject/remove.cpp

@@ -9,47 +9,64 @@
 TEST_CASE("JsonObject::remove()") {
   DynamicJsonDocument doc;
   JsonObject obj = doc.to<JsonObject>();
+  obj["a"] = 0;
+  obj["b"] = 1;
+  obj["c"] = 2;
+  std::string result;
 
-  SECTION("SizeDecreased_WhenValuesAreRemoved") {
-    obj["hello"] = 1;
+  SECTION("remove(key)") {
+    SECTION("Remove first") {
+      obj.remove("a");
+      serializeJson(obj, result);
+      REQUIRE("{\"b\":1,\"c\":2}" == result);
+    }
 
-    obj.remove("hello");
+    SECTION("Remove middle") {
+      obj.remove("b");
+      serializeJson(obj, result);
+      REQUIRE("{\"a\":0,\"c\":2}" == result);
+    }
 
-    REQUIRE(0 == obj.size());
+    SECTION("Remove last") {
+      obj.remove("c");
+      serializeJson(obj, result);
+      REQUIRE("{\"a\":0,\"b\":1}" == result);
+    }
   }
 
-  SECTION("SizeUntouched_WhenRemoveIsCalledWithAWrongKey") {
-    obj["hello"] = 1;
-
-    obj.remove("world");
+  SECTION("remove(iterator)") {
+    JsonObject::iterator it = obj.begin();
 
-    REQUIRE(1 == obj.size());
-  }
-
-  SECTION("RemoveByIterator") {
-    obj["a"] = 0;
-    obj["b"] = 1;
-    obj["c"] = 2;
+    SECTION("Remove first") {
+      obj.remove(it);
+      serializeJson(obj, result);
+      REQUIRE("{\"b\":1,\"c\":2}" == result);
+    }
 
-    for (JsonObject::iterator it = obj.begin(); it != obj.end(); ++it) {
-      if (it->value() == 1) obj.remove(it);
+    SECTION("Remove middle") {
+      ++it;
+      obj.remove(it);
+      serializeJson(obj, result);
+      REQUIRE("{\"a\":0,\"c\":2}" == result);
     }
 
-    std::string result;
-    serializeJson(obj, result);
-    REQUIRE("{\"a\":0,\"c\":2}" == result);
+    SECTION("Remove last") {
+      it += 2;
+      obj.remove(it);
+      serializeJson(obj, result);
+      REQUIRE("{\"a\":0,\"b\":1}" == result);
+    }
   }
 
 #ifdef HAS_VARIABLE_LENGTH_ARRAY
   SECTION("key is a vla") {
-    obj["hello"] = 1;
-
     int i = 16;
     char vla[i];
-    strcpy(vla, "hello");
+    strcpy(vla, "b");
     obj.remove(vla);
 
-    REQUIRE(0 == obj.size());
+    serializeJson(obj, result);
+    REQUIRE("{\"a\":0,\"c\":2}" == result);
   }
 #endif
 }

+ 13 - 1
test/JsonObject/size.cpp

@@ -19,9 +19,21 @@ TEST_CASE("JsonObject::size()") {
     REQUIRE(1 == obj.size());
   }
 
-  SECTION("doesn't increase when the smae key is added twice") {
+  SECTION("decreases when values are removed") {
+    obj.set("hello", 42);
+    obj.remove("hello");
+    REQUIRE(0 == obj.size());
+  }
+
+  SECTION("doesn't increase when the same key is added twice") {
     obj["hello"] = 1;
     obj["hello"] = 2;
     REQUIRE(1 == obj.size());
   }
+
+  SECTION("doesn't decrease when another key is removed") {
+    obj["hello"] = 1;
+    obj.remove("world");
+    REQUIRE(1 == obj.size());
+  }
 }

+ 6 - 0
test/JsonObject/subscript.cpp

@@ -160,6 +160,12 @@ TEST_CASE("JsonObject::operator[]") {
     REQUIRE(obj[null] == 0);
   }
 
+  SECTION("obj[key].to<JsonArray>()") {
+    JsonArray arr = obj["hello"].to<JsonArray>();
+
+    REQUIRE(arr.isNull() == false);
+  }
+
 #if defined(HAS_VARIABLE_LENGTH_ARRAY) && \
     !defined(SUBSCRIPT_CONFLICTS_WITH_BUILTIN_OPERATOR)
   SECTION("obj[VLA] = str") {

+ 1 - 0
test/JsonVariant/CMakeLists.txt

@@ -5,6 +5,7 @@
 add_executable(JsonVariantTests
 	as.cpp
 	compare.cpp
+	copy.cpp
 	is.cpp
 	isnull.cpp
 	or.cpp

+ 87 - 160
test/JsonVariant/as.cpp

@@ -12,223 +12,150 @@ TEST_CASE("JsonVariant::as()") {
   DynamicJsonDocument doc;
   JsonVariant variant = doc.to<JsonVariant>();
 
-  SECTION("DoubleAsBool") {
-    variant.set(4.2);
-    REQUIRE(variant.as<bool>());
-  }
-
-  SECTION("DoubleAsCstr") {
-    variant.set(4.2);
-    REQUIRE_FALSE(variant.as<const char*>());
+  SECTION("not set") {
+    REQUIRE(false == variant.as<bool>());
+    REQUIRE(0 == variant.as<int>());
+    REQUIRE(0.0f == variant.as<float>());
+    REQUIRE(0 == variant.as<char*>());
+    REQUIRE("null" == variant.as<std::string>());
   }
 
-  SECTION("DoubleAsString") {
+  SECTION("set(4.2)") {
     variant.set(4.2);
-    REQUIRE(std::string("4.2") == variant.as<std::string>());
-  }
 
-  SECTION("DoubleAsLong") {
-    variant.set(4.2);
-    REQUIRE(4L == variant.as<long>());
-  }
-
-  SECTION("DoubleAsUnsigned") {
-    variant.set(4.2);
-    REQUIRE(4U == variant.as<unsigned>());
-  }
-
-  SECTION("DoubleZeroAsBool") {
-    variant.set(0.0);
-    REQUIRE_FALSE(variant.as<bool>());
+    REQUIRE(variant.as<bool>());
+    REQUIRE(0 == variant.as<const char*>());
+    REQUIRE(variant.as<std::string>() == "4.2");
+    REQUIRE(variant.as<long>() == 4L);
+    REQUIRE(variant.as<unsigned>() == 4U);
   }
 
-  SECTION("DoubleZeroAsLong") {
+  SECTION("set(0.0)") {
     variant.set(0.0);
-    REQUIRE(0L == variant.as<long>());
-  }
-
-  SECTION("FalseAsBool") {
-    variant.set(false);
-    REQUIRE_FALSE(variant.as<bool>());
-  }
 
-  SECTION("FalseAsDouble") {
-    variant.set(false);
-    REQUIRE(0.0 == variant.as<double>());
+    REQUIRE(variant.as<bool>() == false);
+    REQUIRE(variant.as<long>() == 0L);
   }
 
-  SECTION("FalseAsLong") {
+  SECTION("set(false)") {
     variant.set(false);
-    REQUIRE(0L == variant.as<long>());
-  }
 
-  SECTION("FalseAsString") {
-    variant.set(false);
-    REQUIRE(std::string("false") == variant.as<std::string>());
+    REQUIRE(false == variant.as<bool>());
+    REQUIRE(variant.as<double>() == 0.0);
+    REQUIRE(variant.as<long>() == 0L);
+    REQUIRE(variant.as<std::string>() == "false");
   }
 
-  SECTION("TrueAsBool") {
+  SECTION("set(true)") {
     variant.set(true);
-    REQUIRE(variant.as<bool>());
-  }
-
-  SECTION("TrueAsDouble") {
-    variant.set(true);
-    REQUIRE(1.0 == variant.as<double>());
-  }
-
-  SECTION("TrueAsLong") {
-    variant.set(true);
-    REQUIRE(1L == variant.as<long>());
-  }
-
-  SECTION("TrueAsString") {
-    variant.set(true);
-    REQUIRE(std::string("true") == variant.as<std::string>());
-  }
 
-  SECTION("LongAsBool") {
-    variant.set(42L);
     REQUIRE(variant.as<bool>());
+    REQUIRE(variant.as<double>() == 1.0);
+    REQUIRE(variant.as<long>() == 1L);
+    REQUIRE(variant.as<std::string>() == "true");
   }
 
-  SECTION("LongZeroAsBool") {
-    variant.set(0L);
-    REQUIRE_FALSE(variant.as<bool>());
-  }
-
-  SECTION("PositiveLongAsDouble") {
+  SECTION("set(42L)") {
     variant.set(42L);
-    REQUIRE(42.0 == variant.as<double>());
+
+    REQUIRE(variant.as<bool>() == true);
+    REQUIRE(variant.as<double>() == 42.0);
+    REQUIRE(variant.as<std::string>() == "42");
   }
 
-  SECTION("NegativeLongAsDouble") {
+  SECTION("set(-42L)") {
     variant.set(-42L);
-    REQUIRE(-42.0 == variant.as<double>());
-  }
 
-  SECTION("LongAsString") {
-    variant.set(42L);
-    REQUIRE(std::string("42") == variant.as<std::string>());
+    REQUIRE(variant.as<double>() == -42.0);
+    REQUIRE(variant.as<std::string>() == "-42");
   }
 
-  SECTION("LongZeroAsDouble") {
+  SECTION("set(0L)") {
     variant.set(0L);
-    REQUIRE(0.0 == variant.as<double>());
-  }
 
-  SECTION("NullAsBool") {
-    variant.set(null);
-    REQUIRE_FALSE(variant.as<bool>());
-  }
+    SECTION("as<bool>()") {
+      REQUIRE(false == variant.as<bool>());
+    }
 
-  SECTION("NullAsDouble") {
-    variant.set(null);
-    REQUIRE(0.0 == variant.as<double>());
-  }
-
-  SECTION("NullAsLong") {
-    variant.set(null);
-    REQUIRE(0L == variant.as<long>());
+    SECTION("as<double>()") {
+      REQUIRE(variant.as<double>() == 0.0);
+    }
   }
 
-  SECTION("NullAsString") {
+  SECTION("set(null)") {
     variant.set(null);
-    REQUIRE(std::string("null") == variant.as<std::string>());
-  }
 
-  SECTION("NumberStringAsBool") {
-    variant.set("42");
-    REQUIRE(variant.as<bool>());
+    REQUIRE(variant.as<bool>() == false);
+    REQUIRE(variant.as<double>() == 0.0);
+    REQUIRE(variant.as<long>() == 0L);
+    REQUIRE(variant.as<std::string>() == "null");
   }
 
-  SECTION("NumberStringAsLong") {
+  SECTION("set(\"42\")") {
     variant.set("42");
-    REQUIRE(42L == variant.as<long>());
-  }
-
-#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
-  SECTION("NumberStringAsInt64Negative") {
-    variant.set("-9223372036854775808");
-    REQUIRE(-9223372036854775807 - 1 == variant.as<long long>());
-  }
-
-  SECTION("NumberStringAsInt64Positive") {
-    variant.set("9223372036854775807");
-    REQUIRE(9223372036854775807 == variant.as<long long>());
-  }
-#endif
-
-  SECTION("RandomStringAsBool") {
-    variant.set("hello");
-    REQUIRE_FALSE(variant.as<bool>());
-  }
 
-  SECTION("RandomStringAsLong") {
-    variant.set("hello");
-    REQUIRE(0L == variant.as<long>());
-  }
-
-  SECTION("RandomStringAsConstCharPtr") {
-    variant.set("hello");
-    REQUIRE(std::string("hello") == variant.as<const char*>());
+    REQUIRE(variant.as<bool>());
+    REQUIRE(variant.as<long>() == 42L);
   }
 
-  SECTION("RandomStringAsCharPtr") {
+  SECTION("set(\"hello\")") {
     variant.set("hello");
-    REQUIRE(std::string("hello") == variant.as<char*>());
-  }
 
-  SECTION("RandomStringAsString") {
-    variant.set("hello");
-    REQUIRE(std::string("hello") == variant.as<std::string>());
+    REQUIRE(variant.as<bool>() == false);
+    REQUIRE(variant.as<long>() == 0L);
+    REQUIRE(variant.as<const char*>() == std::string("hello"));
+    REQUIRE(variant.as<char*>() == std::string("hello"));
+    REQUIRE(variant.as<std::string>() == std::string("hello"));
   }
 
-  SECTION("TrueStringAsBool") {
+  SECTION("set(\"true\")") {
     variant.set("true");
-    REQUIRE(variant.as<bool>());
-  }
 
-  SECTION("TrueStringAsLong") {
-    variant.set("true");
-    REQUIRE(1L == variant.as<long>());
+    REQUIRE(variant.as<bool>());
+    REQUIRE(variant.as<long>() == 1L);
   }
 
-  SECTION("ObjectAsString") {
-    DynamicJsonDocument doc2;
-    JsonObject obj = doc2.to<JsonObject>();
-
+  SECTION("to<JsonObject>()") {
+    JsonObject obj = variant.to<JsonObject>();
     obj["key"] = "value";
 
-    variant.set(obj);
-    REQUIRE(std::string("{\"key\":\"value\"}") == variant.as<std::string>());
+    SECTION("as<std::string>()") {
+      REQUIRE(variant.as<std::string>() == std::string("{\"key\":\"value\"}"));
+    }
+
+    SECTION("ObjectAsJsonObject") {
+      JsonObject o = variant.as<JsonObject>();
+      REQUIRE(o.size() == 1);
+      REQUIRE(o["key"] == std::string("value"));
+    }
   }
 
-  SECTION("ArrayAsString") {
-    DynamicJsonDocument doc2;
-    JsonArray arr = doc2.to<JsonArray>();
+  SECTION("to<JsonArray>()") {
+    JsonArray arr = variant.to<JsonArray>();
     arr.add(4);
     arr.add(2);
 
-    variant.set(arr);
-    REQUIRE(std::string("[4,2]") == variant.as<std::string>());
-  }
-
-  SECTION("ArrayAsJsonArray") {
-    DynamicJsonDocument doc2;
-    JsonArray arr = doc2.to<JsonArray>();
+    SECTION("as<std::string>()") {
+      REQUIRE(variant.as<std::string>() == std::string("[4,2]"));
+    }
 
-    variant.set(arr);
-    REQUIRE(arr == variant.as<JsonArray>());
-    REQUIRE(arr == variant.as<JsonArray>());  // <- shorthand
+    SECTION("as<JsonArray>()") {
+      JsonArray a = variant.as<JsonArray>();
+      REQUIRE(a.size() == 2);
+      REQUIRE(a[0] == 4);
+      REQUIRE(a[1] == 2);
+    }
   }
 
-  SECTION("ObjectAsJsonObject") {
-    DynamicJsonDocument doc2;
-    JsonObject obj = doc2.to<JsonObject>();
+#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
+  SECTION("Smallest int64 negative") {
+    variant.set("-9223372036854775808");
+    REQUIRE(variant.as<long long>() == -9223372036854775807 - 1);
+  }
 
-    variant.set(obj);
-    REQUIRE(obj == variant.as<JsonObject>());
-    REQUIRE(obj == variant.as<JsonObject>());  // <- shorthand
+  SECTION("Biggerst int64 positive") {
+    variant.set("9223372036854775807");
+    REQUIRE(variant.as<long long>() == 9223372036854775807);
   }
+#endif
 }

+ 8 - 12
test/JsonVariant/compare.cpp

@@ -265,13 +265,11 @@ TEST_CASE("JsonVariant comparisons") {
   }
 
   SECTION("ArrayInVariant") {
-    DynamicJsonDocument docArr1, docArr2;
-    JsonArray array1 = docArr1.to<JsonArray>();
-    JsonArray array2 = docArr2.to<JsonArray>();
+    JsonArray array1 = variant1.to<JsonArray>();
+    JsonArray array2 = variant2.to<JsonArray>();
 
-    variant1.set(array1);
-    variant2.set(array1);
-    variant3.set(array2);
+    array1.add(42);
+    array2.add(42);
 
     REQUIRE(variant1 == variant2);
     REQUIRE_FALSE(variant1 != variant2);
@@ -281,13 +279,11 @@ TEST_CASE("JsonVariant comparisons") {
   }
 
   SECTION("ObjectInVariant") {
-    DynamicJsonDocument docObj1, docObj2;
-    JsonObject obj1 = docObj1.to<JsonObject>();
-    JsonObject obj2 = docObj2.to<JsonObject>();
+    JsonObject obj1 = variant1.to<JsonObject>();
+    JsonObject obj2 = variant2.to<JsonObject>();
 
-    variant1.set(obj1);
-    variant2.set(obj1);
-    variant3.set(obj2);
+    obj1["hello"] = "world";
+    obj2["hello"] = "world";
 
     REQUIRE(variant1 == variant2);
     REQUIRE_FALSE(variant1 != variant2);

+ 84 - 0
test/JsonVariant/copy.cpp

@@ -0,0 +1,84 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#include <ArduinoJson.h>
+#include <catch.hpp>
+
+TEST_CASE("JsonVariant::set(JsonVariant)") {
+  DynamicJsonDocument doc1;
+  DynamicJsonDocument doc2;
+  JsonVariant var1 = doc1.to<JsonVariant>();
+  JsonVariant var2 = doc2.to<JsonVariant>();
+
+  SECTION("stores JsonArray by copy") {
+    JsonArray arr = doc2.to<JsonArray>();
+
+    arr.add(42);
+    var1.set(doc2.as<JsonVariant>());
+    arr[0] = 666;
+
+    REQUIRE(var1.as<std::string>() == "[42]");
+  }
+
+  SECTION("stores JsonObject by copy") {
+    JsonObject obj = doc2.to<JsonObject>();
+
+    obj["value"] = 42;
+    var1.set(doc2.as<JsonVariant>());
+    obj["value"] = 666;
+
+    REQUIRE(var1.as<std::string>() == "{\"value\":42}");
+  }
+
+  SECTION("stores const char* by reference") {
+    var1.set("hello!!");
+    var2.set(var1);
+
+    REQUIRE(doc1.memoryUsage() == 0);
+    REQUIRE(doc2.memoryUsage() == 0);
+  }
+
+  SECTION("stores char* by copy") {
+    char str[] = "hello!!";
+
+    var1.set(str);
+    var2.set(var1);
+
+    REQUIRE(doc1.memoryUsage() == 8);
+    REQUIRE(doc2.memoryUsage() == 8);
+  }
+
+  SECTION("stores std::string by copy") {
+    var1.set(std::string("hello!!"));
+    var2.set(var1);
+
+    REQUIRE(doc1.memoryUsage() == 8);
+    REQUIRE(doc2.memoryUsage() == 8);
+  }
+
+  SECTION("stores Serialized<const char*> by reference") {
+    var1.set(serialized("hello!!", 8));
+    var2.set(var1);
+
+    REQUIRE(doc1.memoryUsage() == 0);
+    REQUIRE(doc2.memoryUsage() == 0);
+  }
+
+  SECTION("stores Serialized<char*> by copy") {
+    char str[] = "hello!!";
+    var1.set(serialized(str, 8));
+    var2.set(var1);
+
+    REQUIRE(doc1.memoryUsage() == 8);
+    REQUIRE(doc2.memoryUsage() == 8);
+  }
+
+  SECTION("stores Serialized<std::string> by copy") {
+    var1.set(serialized(std::string("hello!!!")));
+    var2.set(var1);
+
+    REQUIRE(doc1.memoryUsage() == 8);
+    REQUIRE(doc2.memoryUsage() == 8);
+  }
+}

+ 9 - 9
test/JsonVariant/isnull.cpp

@@ -35,13 +35,13 @@ TEST_CASE("JsonVariant::isNull()") {
     REQUIRE(variant.isNull() == false);
   }
 
-  SECTION("return true when InvalidArray") {
-    variant.set(JsonArray());
-    REQUIRE(variant.isNull() == true);
-  }
-
-  SECTION("return true when InvalidObject") {
-    variant.set(JsonObject());
-    REQUIRE(variant.isNull() == true);
-  }
+  /*  SECTION("return true when InvalidArray") {
+      variant.set(JsonArray());
+      REQUIRE(variant.isNull() == true);
+    }
+  */
+  /*  SECTION("return true when InvalidObject") {
+      variant.set(JsonObject());
+      REQUIRE(variant.isNull() == true);
+    }*/
 }

+ 7 - 6
test/JsonVariant/subscript.cpp

@@ -23,9 +23,7 @@ TEST_CASE("JsonVariant::operator[]") {
   }
 
   SECTION("The JsonVariant is a JsonArray") {
-    DynamicJsonDocument doc2;
-    JsonArray array = doc2.to<JsonArray>();
-    var.set(array);
+    JsonArray array = var.to<JsonArray>();
 
     SECTION("get value") {
       array.add("element at index 0");
@@ -62,9 +60,7 @@ TEST_CASE("JsonVariant::operator[]") {
   }
 
   SECTION("The JsonVariant is a JsonObject") {
-    DynamicJsonDocument doc2;
-    JsonObject object = doc2.to<JsonObject>();
-    var.set(object);
+    JsonObject object = var.to<JsonObject>();
 
     SECTION("get value") {
       object["a"] = "element at key \"a\"";
@@ -92,6 +88,11 @@ TEST_CASE("JsonVariant::operator[]") {
       REQUIRE(1 == var.size());
       REQUIRE(std::string("world") == var["hello"]);
     }
+
+    SECTION("var[key].to<JsonArray>()") {
+      JsonArray arr = var["hello"].to<JsonArray>();
+      REQUIRE(arr.isNull() == false);
+    }
   }
 
 #if defined(HAS_VARIABLE_LENGTH_ARRAY) && \

+ 13 - 21
test/JsonVariant/undefined.cpp

@@ -8,47 +8,39 @@
 TEST_CASE("JsonVariant undefined") {
   JsonVariant variant;
 
-  SECTION("AsLongReturns0") {
+  SECTION("as<long>()") {
     REQUIRE(0 == variant.as<long>());
   }
 
-  SECTION("AsUnsignedReturns0") {
+  SECTION("as<unsigned>()") {
     REQUIRE(0 == variant.as<unsigned>());
   }
 
-  SECTION("AsStringReturnsNull") {
+  SECTION("as<char*>()") {
     REQUIRE(0 == variant.as<char*>());
   }
 
-  SECTION("AsDoubleReturns0") {
+  SECTION("as<double>()") {
     REQUIRE(0 == variant.as<double>());
   }
 
-  SECTION("AsBoolReturnsFalse") {
+  SECTION("as<bool>()") {
     REQUIRE(false == variant.as<bool>());
   }
 
-  SECTION("AsArrayReturnInvalid") {
-    REQUIRE(JsonArray() == variant.as<JsonArray>());
+  SECTION("as<JsonArray>()") {
+    REQUIRE(variant.as<JsonArray>().isNull());
   }
 
-  SECTION("AsConstArrayReturnInvalid") {
-    REQUIRE(JsonArray() == variant.as<const JsonArray>());
+  SECTION("as<const JsonArray>()") {
+    REQUIRE(variant.as<const JsonArray>().isNull());
   }
 
-  SECTION("AsObjectReturnInvalid") {
-    REQUIRE(JsonObject() == variant.as<JsonObject>());
+  SECTION("as<JsonObject>()") {
+    REQUIRE(variant.as<JsonObject>().isNull());
   }
 
-  SECTION("AsConstObjectReturnInvalid") {
-    REQUIRE(JsonObject() == variant.as<const JsonObject>());
-  }
-
-  SECTION("AsArrayWrapperReturnInvalid") {
-    REQUIRE(JsonArray() == variant.as<JsonArray>());
-  }
-
-  SECTION("AsObjectWrapperReturnInvalid") {
-    REQUIRE(JsonObject() == variant.as<JsonObject>());
+  SECTION("as<const JsonObject>()") {
+    REQUIRE(variant.as<const JsonObject>().isNull());
   }
 }