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

This commit is contained in:
Benoit Blanchon
2018-09-11 16:05:56 +02:00
parent 2998a55f0b
commit b106b1ed14
52 changed files with 971 additions and 978 deletions

View File

@@ -11,22 +11,34 @@
namespace ArduinoJson {
namespace Internals {
// Forward declarations
struct JsonArrayData;
struct JsonObjectData;
struct JsonObjectData {
struct Slot* head;
struct Slot* tail;
};
// A union that defines the actual content of a JsonVariant.
struct JsonArrayData {
struct Slot* head;
struct Slot* tail;
};
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

View File

@@ -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 setRaw(const char *data, size_t size) {
type = JSON_RAW;
void setLinkedString(const char *value) {
type = JSON_LINKED_STRING;
content.asString = value;
}
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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;
};
}
}

View File

@@ -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;
};
}
}

View File

@@ -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

View File

@@ -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