mirror of
https://github.com/bblanchon/ArduinoJson.git
synced 2025-07-27 01:07:30 +02:00
Compare commits
5 Commits
v6.3.0-bet
...
v6.4.0-bet
Author | SHA1 | Date | |
---|---|---|---|
2d54019f83 | |||
98c8e8e35a | |||
b106b1ed14 | |||
2998a55f0b | |||
e5c4778ff7 |
@ -1,11 +1,17 @@
|
||||
ArduinoJson: change log
|
||||
=======================
|
||||
|
||||
v6.4.0-beta (2018-09-11)
|
||||
-----------
|
||||
|
||||
* Copy `JsonArray` and `JsonObject`, instead of storing pointers (issue #780)
|
||||
* Added `JsonVariant::to<JsonArray>()` and `JsonVariant::to<JsonObject>()`
|
||||
|
||||
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
|
||||
|
@ -7,7 +7,7 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/bblanchon/ArduinoJson.git"
|
||||
},
|
||||
"version": "6.3.0-beta",
|
||||
"version": "6.4.0-beta",
|
||||
"authors": {
|
||||
"name": "Benoit Blanchon",
|
||||
"url": "https://blog.benoitblanchon.fr"
|
||||
|
@ -1,5 +1,5 @@
|
||||
name=ArduinoJson
|
||||
version=6.3.0-beta
|
||||
version=6.4.0-beta
|
||||
author=Benoit Blanchon <blog.benoitblanchon.fr>
|
||||
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
|
||||
sentence=An efficient and elegant JSON library for Arduino.
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eux
|
||||
set -eu
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
@ -36,9 +36,14 @@ commit_new_version () {
|
||||
|
||||
add_tag () {
|
||||
CHANGES=$(awk '/\* /{ FOUND=1; print; next } { if (FOUND) exit}' CHANGELOG.md)
|
||||
git tag -m "ArduinoJson $VERSION\n$CHANGES" $TAG
|
||||
git tag -m "ArduinoJson $VERSION"$'\n'"$CHANGES" "$TAG"
|
||||
}
|
||||
|
||||
push () {
|
||||
git push --follow-tags
|
||||
}
|
||||
|
||||
update_version_in_source
|
||||
commit_new_version
|
||||
add_tag
|
||||
push
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
@ -26,13 +30,6 @@ struct JsonVariantData {
|
||||
content.asFloat = value;
|
||||
}
|
||||
|
||||
void setInteger(JsonInteger value) {
|
||||
if (value > 0)
|
||||
setPostiveInteger(static_cast<JsonUInt>(value));
|
||||
else
|
||||
setNegativeInteger(static_cast<JsonUInt>(-value));
|
||||
}
|
||||
|
||||
void setNegativeInteger(JsonUInt value) {
|
||||
type = JSON_NEGATIVE_INTEGER;
|
||||
content.asInteger = value;
|
||||
@ -43,13 +40,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 +66,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 +150,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
src/ArduinoJson/Data/JsonVariantTo.hpp
Normal file
33
src/ArduinoJson/Data/JsonVariantTo.hpp
Normal 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
|
@ -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
|
||||
|
@ -1,83 +0,0 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Memory/JsonBuffer.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(JsonBuffer *buffer) {
|
||||
node_type *newNode = new (buffer) 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
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h> // for NULL
|
||||
|
||||
#include "../Memory/JsonBufferAllocated.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::JsonBufferAllocated {
|
||||
ListNode() NOEXCEPT : next(NULL) {}
|
||||
|
||||
ListNode<T> *next;
|
||||
T content;
|
||||
};
|
||||
} // namespace Internals
|
||||
} // namespace ArduinoJson
|
21
src/ArduinoJson/Data/Slot.hpp
Normal file
21
src/ArduinoJson/Data/Slot.hpp
Normal 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
|
@ -16,11 +16,12 @@ namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
|
||||
template <template <typename, typename> class TDeserializer,
|
||||
typename TJsonBuffer, typename TReader, typename TWriter>
|
||||
TDeserializer<TReader, TWriter> makeDeserializer(TJsonBuffer *buffer,
|
||||
typename TMemoryPool, typename TReader, typename TWriter>
|
||||
TDeserializer<TReader, TWriter> makeDeserializer(TMemoryPool &memoryPool,
|
||||
TReader reader, TWriter writer,
|
||||
uint8_t nestingLimit) {
|
||||
return TDeserializer<TReader, TWriter>(buffer, reader, writer, nestingLimit);
|
||||
return TDeserializer<TReader, TWriter>(memoryPool, reader, writer,
|
||||
nestingLimit);
|
||||
}
|
||||
|
||||
// DeserializationError deserialize(TDocument& doc, TString input);
|
||||
@ -32,10 +33,10 @@ typename Internals::enable_if<!Internals::is_array<TString>::value,
|
||||
DeserializationError>::type
|
||||
deserialize(TDocument &doc, const TString &input) {
|
||||
using namespace Internals;
|
||||
return makeDeserializer<TDeserializer>(&doc.buffer(), makeReader(input),
|
||||
makeStringStorage(doc.buffer(), input),
|
||||
doc.nestingLimit)
|
||||
.parse(doc.template to<JsonVariantData>());
|
||||
return makeDeserializer<TDeserializer>(
|
||||
doc.memoryPool(), makeReader(input),
|
||||
makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
|
||||
.parse(doc.template to<JsonVariant>());
|
||||
}
|
||||
//
|
||||
// DeserializationError deserialize(TDocument& doc, TChar* input);
|
||||
@ -45,10 +46,10 @@ template <template <typename, typename> class TDeserializer, typename TDocument,
|
||||
typename TChar>
|
||||
DeserializationError deserialize(TDocument &doc, TChar *input) {
|
||||
using namespace Internals;
|
||||
return makeDeserializer<TDeserializer>(&doc.buffer(), makeReader(input),
|
||||
makeStringStorage(doc.buffer(), input),
|
||||
doc.nestingLimit)
|
||||
.parse(doc.template to<JsonVariantData>());
|
||||
return makeDeserializer<TDeserializer>(
|
||||
doc.memoryPool(), makeReader(input),
|
||||
makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
|
||||
.parse(doc.template to<JsonVariant>());
|
||||
}
|
||||
//
|
||||
// DeserializationError deserialize(TDocument& doc, TChar* input, size_t
|
||||
@ -61,9 +62,9 @@ DeserializationError deserialize(TDocument &doc, TChar *input,
|
||||
size_t inputSize) {
|
||||
using namespace Internals;
|
||||
return makeDeserializer<TDeserializer>(
|
||||
&doc.buffer(), makeReader(input, inputSize),
|
||||
makeStringStorage(doc.buffer(), input), doc.nestingLimit)
|
||||
.parse(doc.template to<JsonVariantData>());
|
||||
doc.memoryPool(), makeReader(input, inputSize),
|
||||
makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
|
||||
.parse(doc.template to<JsonVariant>());
|
||||
}
|
||||
//
|
||||
// DeserializationError deserialize(TDocument& doc, TStream input);
|
||||
@ -73,10 +74,10 @@ template <template <typename, typename> class TDeserializer, typename TDocument,
|
||||
typename TStream>
|
||||
DeserializationError deserialize(TDocument &doc, TStream &input) {
|
||||
using namespace Internals;
|
||||
return makeDeserializer<TDeserializer>(&doc.buffer(), makeReader(input),
|
||||
makeStringStorage(doc.buffer(), input),
|
||||
doc.nestingLimit)
|
||||
.parse(doc.template to<JsonVariantData>());
|
||||
return makeDeserializer<TDeserializer>(
|
||||
doc.memoryPool(), makeReader(input),
|
||||
makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
|
||||
.parse(doc.template to<JsonVariant>());
|
||||
}
|
||||
} // namespace Internals
|
||||
} // namespace ArduinoJson
|
||||
|
@ -4,10 +4,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "JsonArray.hpp"
|
||||
#include "JsonObject.hpp"
|
||||
#include "Data/JsonVariantTo.hpp"
|
||||
#include "JsonVariant.hpp"
|
||||
#include "Memory/DynamicJsonBuffer.hpp"
|
||||
#include "Memory/DynamicMemoryPool.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
|
||||
@ -17,7 +16,8 @@ class DynamicJsonDocument {
|
||||
|
||||
DynamicJsonDocument() : nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {}
|
||||
DynamicJsonDocument(size_t capacity)
|
||||
: nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT), _buffer(capacity) {}
|
||||
: nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT),
|
||||
_memoryPool(capacity) {}
|
||||
|
||||
template <typename T>
|
||||
bool is() const {
|
||||
@ -29,71 +29,36 @@ 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(&_buffer);
|
||||
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(&_buffer);
|
||||
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::DynamicJsonBuffer& buffer() {
|
||||
return _buffer;
|
||||
typename Internals::JsonVariantTo<T>::type to() {
|
||||
_memoryPool.clear();
|
||||
return getVariant().to<T>();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
_buffer.clear();
|
||||
_memoryPool.clear();
|
||||
_rootData.setNull();
|
||||
}
|
||||
|
||||
size_t memoryUsage() const {
|
||||
return _buffer.size();
|
||||
return _memoryPool.size();
|
||||
}
|
||||
|
||||
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:
|
||||
JsonVariant getVariant() const {
|
||||
return JsonVariant(&_buffer, &_rootData);
|
||||
return JsonVariant(&_memoryPool, &_rootData);
|
||||
}
|
||||
|
||||
mutable Internals::DynamicJsonBuffer _buffer;
|
||||
mutable Internals::DynamicMemoryPool _memoryPool;
|
||||
mutable Internals::JsonVariantData _rootData;
|
||||
};
|
||||
} // namespace ArduinoJson
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include "../Deserialization/deserialize.hpp"
|
||||
#include "../JsonVariant.hpp"
|
||||
#include "../Memory/JsonBuffer.hpp"
|
||||
#include "../Memory/MemoryPool.hpp"
|
||||
#include "../Numbers/isFloat.hpp"
|
||||
#include "../Numbers/isInteger.hpp"
|
||||
#include "../Polyfills/type_traits.hpp"
|
||||
@ -18,14 +18,14 @@ namespace Internals {
|
||||
template <typename TReader, typename TStringStorage>
|
||||
class JsonDeserializer {
|
||||
public:
|
||||
JsonDeserializer(JsonBuffer *buffer, TReader reader,
|
||||
JsonDeserializer(MemoryPool &memoryPool, TReader reader,
|
||||
TStringStorage stringStorage, uint8_t nestingLimit)
|
||||
: _buffer(buffer),
|
||||
: _memoryPool(&memoryPool),
|
||||
_reader(reader),
|
||||
_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 (_buffer) 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(_buffer);
|
||||
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 (_buffer) 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(_buffer, 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;
|
||||
}
|
||||
@ -335,7 +333,7 @@ class JsonDeserializer {
|
||||
}
|
||||
}
|
||||
|
||||
JsonBuffer *_buffer;
|
||||
MemoryPool *_memoryPool;
|
||||
TReader _reader;
|
||||
TStringStorage _stringStorage;
|
||||
uint8_t _nestingLimit;
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
@ -21,33 +25,56 @@ class JsonArray {
|
||||
public:
|
||||
typedef JsonArrayIterator iterator;
|
||||
|
||||
FORCE_INLINE JsonArray() : _buffer(0), _data(0) {}
|
||||
FORCE_INLINE JsonArray(Internals::JsonBuffer* buf,
|
||||
FORCE_INLINE JsonArray() : _memoryPool(0), _data(0) {}
|
||||
FORCE_INLINE JsonArray(Internals::MemoryPool* buf,
|
||||
Internals::JsonArrayData* arr)
|
||||
: _buffer(buf), _data(arr) {}
|
||||
FORCE_INLINE explicit JsonArray(Internals::JsonBuffer* buf)
|
||||
: _buffer(buf), _data(new (buf) Internals::JsonArrayData()) {}
|
||||
: _memoryPool(buf), _data(arr) {}
|
||||
|
||||
// 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(_buffer, _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,13 +261,10 @@ class JsonArray {
|
||||
|
||||
template <typename TValueRef>
|
||||
FORCE_INLINE bool add_impl(TValueRef value) {
|
||||
if (!_data) return false;
|
||||
iterator it = iterator(_buffer, _data->add(_buffer));
|
||||
if (it == end()) return false;
|
||||
return it->set(value);
|
||||
return add().set(value);
|
||||
}
|
||||
|
||||
Internals::JsonBuffer* _buffer;
|
||||
Internals::MemoryPool* _memoryPool;
|
||||
Internals::JsonArrayData* _data;
|
||||
};
|
||||
} // namespace ArduinoJson
|
||||
|
@ -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/JsonBufferAllocated.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 StaticJsonBuffer.
|
||||
#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>, JsonBufferAllocated {
|
||||
JsonVariantData* addSlot(JsonBuffer* buffer) {
|
||||
iterator it = add(buffer);
|
||||
return it != end() ? &*it : 0;
|
||||
}
|
||||
};
|
||||
} // namespace Internals
|
||||
} // namespace ArduinoJson
|
@ -10,16 +10,10 @@
|
||||
namespace ArduinoJson {
|
||||
|
||||
inline JsonArray JsonArray::createNestedArray() {
|
||||
if (!_data) return JsonArray();
|
||||
JsonArray array(_buffer);
|
||||
if (!array.isNull()) add(array);
|
||||
return array;
|
||||
return add().to<JsonArray>();
|
||||
}
|
||||
|
||||
inline JsonObject JsonArray::createNestedObject() {
|
||||
if (!_data) return JsonObject();
|
||||
JsonObject object(_buffer);
|
||||
if (!object.isNull()) add(object);
|
||||
return object;
|
||||
return add().to<JsonObject>();
|
||||
}
|
||||
} // namespace ArduinoJson
|
||||
|
@ -4,16 +4,16 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Data/ListIterator.hpp"
|
||||
#include "Data/Slot.hpp"
|
||||
#include "JsonVariant.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
|
||||
class JsonVariantPtr {
|
||||
public:
|
||||
JsonVariantPtr(Internals::JsonBuffer *buffer,
|
||||
JsonVariantPtr(Internals::MemoryPool *memoryPool,
|
||||
Internals::JsonVariantData *data)
|
||||
: _variant(buffer, data) {}
|
||||
: _variant(memoryPool, data) {}
|
||||
|
||||
JsonVariant *operator->() {
|
||||
return &_variant;
|
||||
@ -28,45 +28,46 @@ class JsonVariantPtr {
|
||||
};
|
||||
|
||||
class JsonArrayIterator {
|
||||
typedef Internals::ListIterator<Internals::JsonVariantData> internal_iterator;
|
||||
|
||||
public:
|
||||
JsonArrayIterator() {}
|
||||
explicit JsonArrayIterator(Internals::JsonBuffer *buffer,
|
||||
internal_iterator iterator)
|
||||
: _iterator(iterator), _buffer(buffer) {}
|
||||
JsonArrayIterator() : _slot(0) {}
|
||||
explicit JsonArrayIterator(Internals::MemoryPool *memoryPool,
|
||||
Internals::Slot *iterator)
|
||||
: _memoryPool(memoryPool), _slot(iterator) {}
|
||||
|
||||
JsonVariant operator*() const {
|
||||
return JsonVariant(_buffer, &*_iterator);
|
||||
return JsonVariant(_memoryPool, &_slot->value);
|
||||
}
|
||||
JsonVariantPtr operator->() {
|
||||
return JsonVariantPtr(_buffer, &*_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::JsonBuffer *_buffer;
|
||||
Internals::MemoryPool *_memoryPool;
|
||||
Internals::Slot *_slot;
|
||||
};
|
||||
} // namespace ArduinoJson
|
||||
|
@ -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:
|
||||
|
@ -4,28 +4,34 @@
|
||||
|
||||
#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;
|
||||
|
||||
FORCE_INLINE JsonObject() : _buffer(0), _data(0) {}
|
||||
FORCE_INLINE JsonObject(Internals::JsonBuffer* buf,
|
||||
FORCE_INLINE JsonObject() : _memoryPool(0), _data(0) {}
|
||||
FORCE_INLINE JsonObject(Internals::MemoryPool* buf,
|
||||
Internals::JsonObjectData* object)
|
||||
: _buffer(buf), _data(object) {}
|
||||
FORCE_INLINE explicit JsonObject(Internals::JsonBuffer* buf)
|
||||
: _buffer(buf), _data(new (buf) Internals::JsonObjectData()) {}
|
||||
: _memoryPool(buf), _data(object) {}
|
||||
|
||||
FORCE_INLINE iterator begin() const {
|
||||
if (!_data) return iterator();
|
||||
return iterator(_buffer, _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,75 +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(_buffer, &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(_buffer, &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(_buffer);
|
||||
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(_buffer, &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) {
|
||||
const char* dup = Internals::makeString(key).save(_buffer);
|
||||
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::JsonBuffer* _buffer;
|
||||
mutable Internals::MemoryPool* _memoryPool;
|
||||
mutable Internals::JsonObjectData* _data;
|
||||
};
|
||||
}; // namespace ArduinoJson
|
||||
} // namespace ArduinoJson
|
||||
|
@ -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/JsonBufferAllocated.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 StaticJsonBuffer.
|
||||
#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>, JsonBufferAllocated {
|
||||
JsonVariantData* addSlot(JsonBuffer* buffer, const char* key) {
|
||||
iterator it = add(buffer);
|
||||
if (it == end()) return 0;
|
||||
it->key = key;
|
||||
return &it->value;
|
||||
}
|
||||
};
|
||||
} // namespace Internals
|
||||
} // namespace ArduinoJson
|
@ -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(_buffer);
|
||||
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(_buffer);
|
||||
if (!object.isNull()) set(key, object);
|
||||
return object;
|
||||
return set(key).template to<JsonObject>();
|
||||
}
|
||||
} // namespace ArduinoJson
|
||||
|
@ -4,15 +4,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Data/ListIterator.hpp"
|
||||
#include "JsonPair.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
|
||||
class JsonPairPtr {
|
||||
public:
|
||||
JsonPairPtr(Internals::JsonBuffer *buffer, Internals::JsonPairData *data)
|
||||
: _pair(buffer, 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() {}
|
||||
explicit JsonObjectIterator(Internals::JsonBuffer *buffer,
|
||||
internal_iterator iterator)
|
||||
: _buffer(buffer), _iterator(iterator) {}
|
||||
JsonObjectIterator() : _slot(0) {}
|
||||
|
||||
explicit JsonObjectIterator(Internals::MemoryPool *memoryPool,
|
||||
Internals::Slot *slot)
|
||||
: _memoryPool(memoryPool), _slot(slot) {}
|
||||
|
||||
JsonPair operator*() const {
|
||||
return JsonPair(_buffer, &*_iterator);
|
||||
return JsonPair(_memoryPool, _slot);
|
||||
}
|
||||
JsonPairPtr operator->() {
|
||||
return JsonPairPtr(_buffer, &*_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::JsonBuffer *_buffer;
|
||||
internal_iterator _iterator;
|
||||
Internals::MemoryPool *_memoryPool;
|
||||
Internals::Slot *_slot;
|
||||
};
|
||||
} // namespace ArduinoJson
|
||||
|
@ -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,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::JsonBuffer* buffer, Internals::JsonPairData* data)
|
||||
: _key(data->key), _value(buffer, &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;
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "Data/JsonVariantData.hpp"
|
||||
#include "JsonVariant.hpp"
|
||||
#include "JsonVariantBase.hpp"
|
||||
#include "Memory/JsonBuffer.hpp"
|
||||
#include "Memory/MemoryPool.hpp"
|
||||
#include "Polyfills/type_traits.hpp"
|
||||
#include "Serialization/DynamicStringWriter.hpp"
|
||||
#include "SerializedValue.hpp"
|
||||
@ -31,12 +31,12 @@ class JsonObject;
|
||||
class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
|
||||
public:
|
||||
// Intenal use only
|
||||
FORCE_INLINE JsonVariant(Internals::JsonBuffer *buffer,
|
||||
FORCE_INLINE JsonVariant(Internals::MemoryPool *memoryPool,
|
||||
Internals::JsonVariantData *data)
|
||||
: _buffer(buffer), _data(data) {}
|
||||
: _memoryPool(memoryPool), _data(data) {}
|
||||
|
||||
// Creates an uninitialized JsonVariant
|
||||
FORCE_INLINE JsonVariant() : _buffer(0), _data(0) {}
|
||||
FORCE_INLINE JsonVariant() : _memoryPool(0), _data(0) {}
|
||||
|
||||
// set(bool value)
|
||||
FORCE_INLINE bool set(bool value) {
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -106,9 +106,9 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
|
||||
!Internals::is_same<const char *, T>::value>::type * = 0) {
|
||||
if (!_data) return false;
|
||||
const char *dup =
|
||||
Internals::makeString(value.data(), value.size()).save(_buffer);
|
||||
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;
|
||||
@ -122,9 +122,9 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
|
||||
typename Internals::enable_if<Internals::IsString<T>::value>::type * =
|
||||
0) {
|
||||
if (!_data) return false;
|
||||
const char *dup = Internals::makeString(value).save(_buffer);
|
||||
const char *dup = Internals::makeString(value).save(_memoryPool);
|
||||
if (dup) {
|
||||
_data->setString(dup);
|
||||
_data->setOwnedString(dup);
|
||||
return true;
|
||||
} else {
|
||||
_data->setNull();
|
||||
@ -139,9 +139,9 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
|
||||
typename Internals::enable_if<Internals::IsString<T *>::value>::type * =
|
||||
0) {
|
||||
if (!_data) return false;
|
||||
const char *dup = Internals::makeString(value).save(_buffer);
|
||||
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,21 +320,39 @@ 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::JsonBuffer *_buffer;
|
||||
Internals::MemoryPool *_memoryPool;
|
||||
Internals::JsonVariantData *_data;
|
||||
}; // namespace ArduinoJson
|
||||
} // namespace ArduinoJson
|
||||
|
@ -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,13 +31,35 @@ 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,
|
||||
JsonArray>::value,
|
||||
JsonArray>::type
|
||||
JsonVariant::as() const {
|
||||
return _data ? JsonArray(_buffer, _data->asArray()) : JsonArray();
|
||||
return _data ? JsonArray(_memoryPool, _data->asArray()) : JsonArray();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -58,6 +68,71 @@ inline typename Internals::enable_if<
|
||||
JsonObject>::value,
|
||||
T>::type
|
||||
JsonVariant::as() const {
|
||||
return _data ? JsonObject(_buffer, _data->asObject()) : JsonObject();
|
||||
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
|
||||
|
21
src/ArduinoJson/Memory/AllocableInMemoryPool.hpp
Normal file
21
src/ArduinoJson/Memory/AllocableInMemoryPool.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MemoryPool.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
|
||||
class AllocableInMemoryPool {
|
||||
public:
|
||||
void *operator new(size_t n, MemoryPool *memoryPool) NOEXCEPT {
|
||||
return memoryPool->alloc(n);
|
||||
}
|
||||
|
||||
void operator delete(void *, MemoryPool *)NOEXCEPT {}
|
||||
};
|
||||
} // namespace Internals
|
||||
} // namespace ArduinoJson
|
@ -4,7 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "JsonBuffer.hpp"
|
||||
#include "MemoryPool.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
@ -31,7 +31,7 @@ class DefaultAllocator {
|
||||
};
|
||||
|
||||
template <typename TAllocator>
|
||||
class DynamicJsonBufferBase : public JsonBuffer {
|
||||
class DynamicMemoryPoolBase : public MemoryPool {
|
||||
struct Block;
|
||||
struct EmptyBlock {
|
||||
Block* next;
|
||||
@ -45,27 +45,27 @@ class DynamicJsonBufferBase : public JsonBuffer {
|
||||
public:
|
||||
enum { EmptyBlockSize = sizeof(EmptyBlock) };
|
||||
|
||||
DynamicJsonBufferBase(size_t initialSize = 256)
|
||||
DynamicMemoryPoolBase(size_t initialSize = 256)
|
||||
: _head(NULL), _nextBlockCapacity(initialSize) {}
|
||||
|
||||
~DynamicJsonBufferBase() {
|
||||
~DynamicMemoryPoolBase() {
|
||||
clear();
|
||||
}
|
||||
|
||||
// Gets the number of bytes occupied in the buffer
|
||||
// Gets the number of bytes occupied in the memoryPool
|
||||
size_t size() const {
|
||||
size_t total = 0;
|
||||
for (const Block* b = _head; b; b = b->next) total += b->size;
|
||||
return total;
|
||||
}
|
||||
|
||||
// Allocates the specified amount of bytes in the buffer
|
||||
// Allocates the specified amount of bytes in the memoryPool
|
||||
virtual void* alloc(size_t bytes) {
|
||||
alignNextAlloc();
|
||||
return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes);
|
||||
}
|
||||
|
||||
// Resets the buffer.
|
||||
// Resets the memoryPool.
|
||||
// USE WITH CAUTION: this invalidates all previously allocated data
|
||||
void clear() {
|
||||
Block* currentBlock = _head;
|
||||
@ -80,7 +80,7 @@ class DynamicJsonBufferBase : public JsonBuffer {
|
||||
|
||||
class String {
|
||||
public:
|
||||
String(DynamicJsonBufferBase* parent)
|
||||
String(DynamicMemoryPoolBase* parent)
|
||||
: _parent(parent), _start(NULL), _length(0) {}
|
||||
|
||||
void append(char c) {
|
||||
@ -104,7 +104,7 @@ class DynamicJsonBufferBase : public JsonBuffer {
|
||||
}
|
||||
|
||||
private:
|
||||
DynamicJsonBufferBase* _parent;
|
||||
DynamicMemoryPoolBase* _parent;
|
||||
char* _start;
|
||||
size_t _length;
|
||||
};
|
||||
@ -152,12 +152,12 @@ class DynamicJsonBufferBase : public JsonBuffer {
|
||||
size_t _nextBlockCapacity;
|
||||
};
|
||||
|
||||
// Implements a JsonBuffer with dynamic memory allocation.
|
||||
// You are strongly encouraged to consider using StaticJsonBuffer which is much
|
||||
// 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::DynamicJsonBufferBase<Internals::DefaultAllocator>
|
||||
DynamicJsonBuffer;
|
||||
typedef DynamicMemoryPoolBase<DefaultAllocator> DynamicMemoryPool;
|
||||
} // namespace Internals
|
||||
} // namespace ArduinoJson
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
@ -166,4 +166,3 @@ typedef Internals::DynamicJsonBufferBase<Internals::DefaultAllocator>
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
} // namespace ArduinoJson
|
@ -1,22 +0,0 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "JsonBuffer.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
|
||||
class JsonBufferAllocated {
|
||||
public:
|
||||
void *operator new(size_t n, JsonBuffer *jsonBuffer) NOEXCEPT {
|
||||
if (!jsonBuffer) return NULL;
|
||||
return jsonBuffer->alloc(n);
|
||||
}
|
||||
|
||||
void operator delete(void *, JsonBuffer *)NOEXCEPT {}
|
||||
};
|
||||
} // namespace Internals
|
||||
} // namespace ArduinoJson
|
@ -14,11 +14,11 @@
|
||||
namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
// Handle the memory management (done in derived classes) and calls the parser.
|
||||
// This abstract class is implemented by StaticJsonBuffer which implements a
|
||||
// This abstract class is implemented by StaticMemoryPool which implements a
|
||||
// fixed memory allocation.
|
||||
class JsonBuffer {
|
||||
class MemoryPool {
|
||||
public:
|
||||
// Allocates n bytes in the JsonBuffer.
|
||||
// Allocates n bytes in the MemoryPool.
|
||||
// Return a pointer to the allocated memory or NULL if allocation fails.
|
||||
virtual void *alloc(size_t size) = 0;
|
||||
|
||||
@ -26,7 +26,7 @@ class JsonBuffer {
|
||||
// CAUTION: NO VIRTUAL DESTRUCTOR!
|
||||
// If we add a virtual constructor the Arduino compiler will add malloc()
|
||||
// and free() to the binary, adding 706 useless bytes.
|
||||
~JsonBuffer() {}
|
||||
~MemoryPool() {}
|
||||
|
||||
// Preserve aligment if necessary
|
||||
static FORCE_INLINE size_t round_size_up(size_t bytes) {
|
@ -5,16 +5,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Polyfills/mpl/max.hpp"
|
||||
#include "JsonBuffer.hpp"
|
||||
#include "MemoryPool.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
|
||||
class StaticJsonBufferBase : public JsonBuffer {
|
||||
class StaticMemoryPoolBase : public MemoryPool {
|
||||
public:
|
||||
class String {
|
||||
public:
|
||||
String(StaticJsonBufferBase* parent) : _parent(parent) {
|
||||
String(StaticMemoryPoolBase* parent) : _parent(parent) {
|
||||
_start = parent->_buffer + parent->_size;
|
||||
}
|
||||
|
||||
@ -36,31 +36,31 @@ class StaticJsonBufferBase : public JsonBuffer {
|
||||
}
|
||||
|
||||
private:
|
||||
StaticJsonBufferBase* _parent;
|
||||
StaticMemoryPoolBase* _parent;
|
||||
char* _start;
|
||||
};
|
||||
|
||||
StaticJsonBufferBase(char* buffer, size_t capa)
|
||||
: _buffer(buffer), _capacity(capa), _size(0) {}
|
||||
StaticMemoryPoolBase(char* memoryPool, size_t capa)
|
||||
: _buffer(memoryPool), _capacity(capa), _size(0) {}
|
||||
|
||||
// Gets the capacity of the buffer in bytes
|
||||
// Gets the capacity of the memoryPool in bytes
|
||||
size_t capacity() const {
|
||||
return _capacity;
|
||||
}
|
||||
|
||||
// Gets the current usage of the buffer in bytes
|
||||
// Gets the current usage of the memoryPool in bytes
|
||||
size_t size() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
// Allocates the specified amount of bytes in the buffer
|
||||
// Allocates the specified amount of bytes in the memoryPool
|
||||
virtual void* alloc(size_t bytes) {
|
||||
alignNextAlloc();
|
||||
if (!canAlloc(bytes)) return NULL;
|
||||
return doAlloc(bytes);
|
||||
}
|
||||
|
||||
// Resets the buffer.
|
||||
// Resets the memoryPool.
|
||||
// USE WITH CAUTION: this invalidates all previously allocated data
|
||||
void clear() {
|
||||
_size = 0;
|
||||
@ -71,7 +71,7 @@ class StaticJsonBufferBase : public JsonBuffer {
|
||||
}
|
||||
|
||||
protected:
|
||||
~StaticJsonBufferBase() {}
|
||||
~StaticMemoryPoolBase() {}
|
||||
|
||||
private:
|
||||
void alignNextAlloc() {
|
||||
@ -103,16 +103,16 @@ class StaticJsonBufferBase : public JsonBuffer {
|
||||
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
|
||||
#endif
|
||||
|
||||
// Implements a JsonBuffer with fixed memory allocation.
|
||||
// The template paramenter CAPACITY specifies the capacity of the buffer in
|
||||
// Implements a MemoryPool with fixed memory allocation.
|
||||
// The template paramenter CAPACITY specifies the capacity of the memoryPool in
|
||||
// bytes.
|
||||
template <size_t CAPACITY>
|
||||
class StaticJsonBuffer : public Internals::StaticJsonBufferBase {
|
||||
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 StaticJsonBuffer()
|
||||
: Internals::StaticJsonBufferBase(_buffer, ACTUAL_CAPACITY) {}
|
||||
explicit StaticMemoryPool()
|
||||
: StaticMemoryPoolBase(_buffer, ACTUAL_CAPACITY) {}
|
||||
|
||||
private:
|
||||
char _buffer[ACTUAL_CAPACITY];
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include "../Deserialization/deserialize.hpp"
|
||||
#include "../JsonVariant.hpp"
|
||||
#include "../Memory/JsonBuffer.hpp"
|
||||
#include "../Memory/MemoryPool.hpp"
|
||||
#include "../Polyfills/type_traits.hpp"
|
||||
#include "./endianess.hpp"
|
||||
#include "./ieee754.hpp"
|
||||
@ -17,24 +17,24 @@ namespace Internals {
|
||||
template <typename TReader, typename TStringStorage>
|
||||
class MsgPackDeserializer {
|
||||
public:
|
||||
MsgPackDeserializer(JsonBuffer *buffer, TReader reader,
|
||||
MsgPackDeserializer(MemoryPool &memoryPool, TReader reader,
|
||||
TStringStorage stringStorage, uint8_t nestingLimit)
|
||||
: _buffer(buffer),
|
||||
: _memoryPool(&memoryPool),
|
||||
_reader(reader),
|
||||
_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 (_buffer) 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(_buffer);
|
||||
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,40 +260,40 @@ 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 (_buffer) 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(_buffer, 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;
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
JsonBuffer *_buffer;
|
||||
MemoryPool *_memoryPool;
|
||||
TReader _reader;
|
||||
TStringStorage _stringStorage;
|
||||
uint8_t _nestingLimit;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -4,8 +4,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Data/JsonVariantTo.hpp"
|
||||
#include "JsonVariant.hpp"
|
||||
#include "Memory/StaticJsonBuffer.hpp"
|
||||
#include "Memory/StaticMemoryPool.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
|
||||
@ -16,8 +17,8 @@ class StaticJsonDocument {
|
||||
|
||||
StaticJsonDocument() : nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {}
|
||||
|
||||
Internals::StaticJsonBufferBase& buffer() {
|
||||
return _buffer;
|
||||
Internals::StaticMemoryPoolBase& memoryPool() {
|
||||
return _memoryPool;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -30,67 +31,32 @@ 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(&_buffer);
|
||||
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(&_buffer);
|
||||
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() {
|
||||
_buffer.clear();
|
||||
_memoryPool.clear();
|
||||
_rootData.setNull();
|
||||
}
|
||||
|
||||
size_t memoryUsage() const {
|
||||
return _buffer.size();
|
||||
return _memoryPool.size();
|
||||
}
|
||||
|
||||
template <typename Visitor>
|
||||
void visit(Visitor& visitor) const {
|
||||
return getVariant().visit(visitor);
|
||||
void accept(Visitor& visitor) const {
|
||||
return getVariant().accept(visitor);
|
||||
}
|
||||
|
||||
private:
|
||||
JsonVariant getVariant() const {
|
||||
return JsonVariant(&_buffer, &_rootData);
|
||||
return JsonVariant(&_memoryPool, &_rootData);
|
||||
}
|
||||
|
||||
mutable Internals::StaticJsonBuffer<CAPACITY> _buffer;
|
||||
mutable Internals::StaticMemoryPool<CAPACITY> _memoryPool;
|
||||
mutable Internals::JsonVariantData _rootData;
|
||||
};
|
||||
|
||||
|
@ -7,19 +7,19 @@
|
||||
namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
|
||||
template <typename TJsonBuffer>
|
||||
template <typename TMemoryPool>
|
||||
class StringCopier {
|
||||
public:
|
||||
StringCopier(TJsonBuffer& jb) : _jb(&jb) {}
|
||||
StringCopier(TMemoryPool& memoryPool) : _memoryPool(&memoryPool) {}
|
||||
|
||||
typedef typename TJsonBuffer::String String;
|
||||
typedef typename TMemoryPool::String String;
|
||||
|
||||
String startString() {
|
||||
return _jb->startString();
|
||||
return _memoryPool->startString();
|
||||
}
|
||||
|
||||
private:
|
||||
TJsonBuffer* _jb;
|
||||
TMemoryPool* _memoryPool;
|
||||
};
|
||||
} // namespace Internals
|
||||
} // namespace ArduinoJson
|
||||
|
@ -28,7 +28,7 @@ class StringMover {
|
||||
TChar* _startPtr;
|
||||
};
|
||||
|
||||
StringMover(TChar* buffer) : _ptr(buffer) {}
|
||||
StringMover(TChar* ptr) : _ptr(ptr) {}
|
||||
|
||||
String startString() {
|
||||
return String(&_ptr);
|
||||
|
@ -10,35 +10,35 @@
|
||||
namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
|
||||
template <typename TJsonBuffer, typename TInput, typename Enable = void>
|
||||
template <typename TMemoryPool, typename TInput, typename Enable = void>
|
||||
struct StringStorage {
|
||||
typedef StringCopier<TJsonBuffer> type;
|
||||
typedef StringCopier<TMemoryPool> type;
|
||||
|
||||
static type create(TJsonBuffer& jb, TInput&) {
|
||||
static type create(TMemoryPool& jb, TInput&) {
|
||||
return type(jb);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TJsonBuffer, typename TChar>
|
||||
struct StringStorage<TJsonBuffer, TChar*,
|
||||
template <typename TMemoryPool, typename TChar>
|
||||
struct StringStorage<TMemoryPool, TChar*,
|
||||
typename enable_if<!is_const<TChar>::value>::type> {
|
||||
typedef StringMover<TChar> type;
|
||||
|
||||
static type create(TJsonBuffer&, TChar* input) {
|
||||
static type create(TMemoryPool&, TChar* input) {
|
||||
return type(input);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TJsonBuffer, typename TInput>
|
||||
typename StringStorage<TJsonBuffer, TInput>::type makeStringStorage(
|
||||
TJsonBuffer& jb, TInput& input) {
|
||||
return StringStorage<TJsonBuffer, TInput>::create(jb, input);
|
||||
template <typename TMemoryPool, typename TInput>
|
||||
typename StringStorage<TMemoryPool, TInput>::type makeStringStorage(
|
||||
TMemoryPool& jb, TInput& input) {
|
||||
return StringStorage<TMemoryPool, TInput>::create(jb, input);
|
||||
}
|
||||
|
||||
template <typename TJsonBuffer, typename TChar>
|
||||
typename StringStorage<TJsonBuffer, TChar*>::type makeStringStorage(
|
||||
TJsonBuffer& jb, TChar* input) {
|
||||
return StringStorage<TJsonBuffer, TChar*>::create(jb, input);
|
||||
template <typename TMemoryPool, typename TChar>
|
||||
typename StringStorage<TMemoryPool, TChar*>::type makeStringStorage(
|
||||
TMemoryPool& jb, TChar* input) {
|
||||
return StringStorage<TMemoryPool, TChar*>::create(jb, input);
|
||||
}
|
||||
} // namespace Internals
|
||||
} // namespace ArduinoJson
|
||||
|
@ -14,10 +14,10 @@ class ArduinoString {
|
||||
ArduinoString(const ::String& str) : _str(&str) {}
|
||||
|
||||
template <typename Buffer>
|
||||
const char* save(Buffer* buffer) const {
|
||||
const char* save(Buffer* memoryPool) const {
|
||||
if (is_null()) return NULL;
|
||||
size_t n = _str->length() + 1;
|
||||
void* dup = buffer->alloc(n);
|
||||
void* dup = memoryPool->alloc(n);
|
||||
if (dup != NULL) memcpy(dup, _str->c_str(), n);
|
||||
return static_cast<const char*>(dup);
|
||||
}
|
||||
|
@ -23,9 +23,9 @@ class FixedSizeFlashString {
|
||||
}
|
||||
|
||||
template <typename Buffer>
|
||||
const char* save(Buffer* buffer) const {
|
||||
const char* save(Buffer* memoryPool) const {
|
||||
if (!_str) return NULL;
|
||||
void* dup = buffer->alloc(_size);
|
||||
void* dup = memoryPool->alloc(_size);
|
||||
if (dup != NULL) memcpy_P(dup, (const char*)_str, _size);
|
||||
return static_cast<const char*>(dup);
|
||||
}
|
||||
|
@ -24,9 +24,9 @@ class FixedSizeRamString {
|
||||
}
|
||||
|
||||
template <typename Buffer>
|
||||
const char* save(Buffer* buffer) const {
|
||||
const char* save(Buffer* memoryPool) const {
|
||||
if (!_str) return NULL;
|
||||
void* dup = buffer->alloc(_size);
|
||||
void* dup = memoryPool->alloc(_size);
|
||||
if (!dup) return NULL;
|
||||
memcpy(dup, _str, _size);
|
||||
return static_cast<const char*>(dup);
|
||||
|
@ -14,9 +14,9 @@ class StlString {
|
||||
StlString(const std::string& str) : _str(&str) {}
|
||||
|
||||
template <typename Buffer>
|
||||
const char* save(Buffer* buffer) const {
|
||||
const char* save(Buffer* memoryPool) const {
|
||||
size_t n = _str->length() + 1;
|
||||
void* dup = buffer->alloc(n);
|
||||
void* dup = memoryPool->alloc(n);
|
||||
if (dup != NULL) memcpy(dup, _str->c_str(), n);
|
||||
return static_cast<const char*>(dup);
|
||||
}
|
||||
|
@ -22,10 +22,10 @@ class ZeroTerminatedFlashString {
|
||||
}
|
||||
|
||||
template <typename Buffer>
|
||||
const char* save(Buffer* buffer) const {
|
||||
const char* save(Buffer* memoryPool) const {
|
||||
if (!_str) return NULL;
|
||||
size_t n = size() + 1; // copy the terminator
|
||||
void* dup = buffer->alloc(n);
|
||||
void* dup = memoryPool->alloc(n);
|
||||
if (dup != NULL) memcpy_P(dup, (const char*)_str, n);
|
||||
return static_cast<const char*>(dup);
|
||||
}
|
||||
|
@ -22,10 +22,10 @@ class ZeroTerminatedRamString {
|
||||
}
|
||||
|
||||
template <typename Buffer>
|
||||
const char* save(Buffer* buffer) const {
|
||||
const char* save(Buffer* memoryPool) const {
|
||||
if (!_str) return NULL;
|
||||
size_t n = size() + 1;
|
||||
void* dup = buffer->alloc(n);
|
||||
void* dup = memoryPool->alloc(n);
|
||||
if (!dup) return NULL;
|
||||
memcpy(dup, _str, n);
|
||||
return static_cast<const char*>(dup);
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define ARDUINOJSON_VERSION "6.3.0-beta"
|
||||
#define ARDUINOJSON_VERSION "6.4.0-beta"
|
||||
#define ARDUINOJSON_VERSION_MAJOR 6
|
||||
#define ARDUINOJSON_VERSION_MINOR 3
|
||||
#define ARDUINOJSON_VERSION_MINOR 4
|
||||
#define ARDUINOJSON_VERSION_REVISION 0
|
||||
|
@ -71,7 +71,7 @@ if(MSVC)
|
||||
)
|
||||
endif()
|
||||
|
||||
add_subdirectory(DynamicJsonBuffer)
|
||||
add_subdirectory(DynamicMemoryPool)
|
||||
add_subdirectory(IntegrationTests)
|
||||
add_subdirectory(JsonArray)
|
||||
add_subdirectory(JsonDeserializer)
|
||||
@ -84,4 +84,4 @@ add_subdirectory(Misc)
|
||||
add_subdirectory(MsgPackDeserializer)
|
||||
add_subdirectory(MsgPackSerializer)
|
||||
add_subdirectory(Numbers)
|
||||
add_subdirectory(StaticJsonBuffer)
|
||||
add_subdirectory(StaticMemoryPool)
|
||||
|
@ -1,13 +0,0 @@
|
||||
# ArduinoJson - arduinojson.org
|
||||
# Copyright Benoit Blanchon 2014-2018
|
||||
# MIT License
|
||||
|
||||
add_executable(DynamicJsonBufferTests
|
||||
alloc.cpp
|
||||
no_memory.cpp
|
||||
size.cpp
|
||||
startString.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(DynamicJsonBufferTests catch)
|
||||
add_test(DynamicJsonBuffer DynamicJsonBufferTests)
|
@ -1,29 +0,0 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson/Memory/DynamicJsonBuffer.hpp>
|
||||
#include <catch.hpp>
|
||||
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
TEST_CASE("DynamicJsonBuffer::size()") {
|
||||
DynamicJsonBuffer buffer;
|
||||
|
||||
SECTION("Initial size is 0") {
|
||||
REQUIRE(0 == buffer.size());
|
||||
}
|
||||
|
||||
SECTION("Increases after alloc()") {
|
||||
buffer.alloc(1);
|
||||
REQUIRE(1U <= buffer.size());
|
||||
buffer.alloc(1);
|
||||
REQUIRE(2U <= buffer.size());
|
||||
}
|
||||
|
||||
SECTION("Goes back to 0 after clear()") {
|
||||
buffer.alloc(1);
|
||||
buffer.clear();
|
||||
REQUIRE(0 == buffer.size());
|
||||
}
|
||||
}
|
13
test/DynamicMemoryPool/CMakeLists.txt
Normal file
13
test/DynamicMemoryPool/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# ArduinoJson - arduinojson.org
|
||||
# Copyright Benoit Blanchon 2014-2018
|
||||
# MIT License
|
||||
|
||||
add_executable(DynamicMemoryPoolTests
|
||||
alloc.cpp
|
||||
no_memory.cpp
|
||||
size.cpp
|
||||
startString.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(DynamicMemoryPoolTests catch)
|
||||
add_test(DynamicMemoryPool DynamicMemoryPoolTests)
|
@ -18,7 +18,7 @@ std::stringstream allocatorLog;
|
||||
|
||||
struct SpyingAllocator : DefaultAllocator {
|
||||
void* allocate(size_t n) {
|
||||
allocatorLog << "A" << (n - DynamicJsonBuffer::EmptyBlockSize);
|
||||
allocatorLog << "A" << (n - DynamicMemoryPool::EmptyBlockSize);
|
||||
return DefaultAllocator::allocate(n);
|
||||
}
|
||||
void deallocate(void* p) {
|
||||
@ -27,20 +27,20 @@ struct SpyingAllocator : DefaultAllocator {
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("DynamicJsonBuffer::alloc()") {
|
||||
TEST_CASE("DynamicMemoryPool::alloc()") {
|
||||
SECTION("Returns different pointers") {
|
||||
DynamicJsonBuffer buffer;
|
||||
void* p1 = buffer.alloc(1);
|
||||
void* p2 = buffer.alloc(2);
|
||||
DynamicMemoryPool memoryPool;
|
||||
void* p1 = memoryPool.alloc(1);
|
||||
void* p2 = memoryPool.alloc(2);
|
||||
REQUIRE(p1 != p2);
|
||||
}
|
||||
|
||||
SECTION("Doubles allocation size when full") {
|
||||
allocatorLog.str("");
|
||||
{
|
||||
DynamicJsonBufferBase<SpyingAllocator> buffer(1);
|
||||
buffer.alloc(1);
|
||||
buffer.alloc(1);
|
||||
DynamicMemoryPoolBase<SpyingAllocator> memoryPool(1);
|
||||
memoryPool.alloc(1);
|
||||
memoryPool.alloc(1);
|
||||
}
|
||||
REQUIRE(allocatorLog.str() == "A1A2FF");
|
||||
}
|
||||
@ -48,11 +48,11 @@ TEST_CASE("DynamicJsonBuffer::alloc()") {
|
||||
SECTION("Resets allocation size after clear()") {
|
||||
allocatorLog.str("");
|
||||
{
|
||||
DynamicJsonBufferBase<SpyingAllocator> buffer(1);
|
||||
buffer.alloc(1);
|
||||
buffer.alloc(1);
|
||||
buffer.clear();
|
||||
buffer.alloc(1);
|
||||
DynamicMemoryPoolBase<SpyingAllocator> memoryPool(1);
|
||||
memoryPool.alloc(1);
|
||||
memoryPool.alloc(1);
|
||||
memoryPool.clear();
|
||||
memoryPool.alloc(1);
|
||||
}
|
||||
REQUIRE(allocatorLog.str() == "A1A2FFA1F");
|
||||
}
|
||||
@ -60,15 +60,15 @@ TEST_CASE("DynamicJsonBuffer::alloc()") {
|
||||
SECTION("Makes a big allocation when needed") {
|
||||
allocatorLog.str("");
|
||||
{
|
||||
DynamicJsonBufferBase<SpyingAllocator> buffer(1);
|
||||
buffer.alloc(42);
|
||||
DynamicMemoryPoolBase<SpyingAllocator> memoryPool(1);
|
||||
memoryPool.alloc(42);
|
||||
}
|
||||
REQUIRE(allocatorLog.str() == "A42F");
|
||||
}
|
||||
|
||||
SECTION("Alignment") {
|
||||
// make room for two but not three
|
||||
DynamicJsonBuffer tinyBuf(2 * sizeof(void*) + 1);
|
||||
DynamicMemoryPool tinyBuf(2 * sizeof(void*) + 1);
|
||||
|
||||
REQUIRE(isAligned(tinyBuf.alloc(1))); // this on is aligned by design
|
||||
REQUIRE(isAligned(tinyBuf.alloc(1))); // this one fits in the first block
|
@ -14,8 +14,8 @@ struct NoMemoryAllocator {
|
||||
void deallocate(void*) {}
|
||||
};
|
||||
|
||||
TEST_CASE("DynamicJsonBuffer no memory") {
|
||||
DynamicJsonBufferBase<NoMemoryAllocator> _jsonBuffer;
|
||||
TEST_CASE("DynamicMemoryPool no memory") {
|
||||
DynamicMemoryPoolBase<NoMemoryAllocator> _memoryPool;
|
||||
|
||||
SECTION("FixCodeCoverage") {
|
||||
// call this function to fix code coverage
|
||||
@ -33,8 +33,8 @@ TEST_CASE("DynamicJsonBuffer no memory") {
|
||||
// }
|
||||
|
||||
SECTION("startString()") {
|
||||
DynamicJsonBufferBase<NoMemoryAllocator>::String str =
|
||||
_jsonBuffer.startString();
|
||||
DynamicMemoryPoolBase<NoMemoryAllocator>::String str =
|
||||
_memoryPool.startString();
|
||||
str.append('!');
|
||||
REQUIRE(0 == str.c_str());
|
||||
}
|
29
test/DynamicMemoryPool/size.cpp
Normal file
29
test/DynamicMemoryPool/size.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson/Memory/DynamicMemoryPool.hpp>
|
||||
#include <catch.hpp>
|
||||
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
TEST_CASE("DynamicMemoryPool::size()") {
|
||||
DynamicMemoryPool memoryPool;
|
||||
|
||||
SECTION("Initial size is 0") {
|
||||
REQUIRE(0 == memoryPool.size());
|
||||
}
|
||||
|
||||
SECTION("Increases after alloc()") {
|
||||
memoryPool.alloc(1);
|
||||
REQUIRE(1U <= memoryPool.size());
|
||||
memoryPool.alloc(1);
|
||||
REQUIRE(2U <= memoryPool.size());
|
||||
}
|
||||
|
||||
SECTION("Goes back to 0 after clear()") {
|
||||
memoryPool.alloc(1);
|
||||
memoryPool.clear();
|
||||
REQUIRE(0 == memoryPool.size());
|
||||
}
|
||||
}
|
@ -2,16 +2,16 @@
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson/Memory/DynamicJsonBuffer.hpp>
|
||||
#include <ArduinoJson/Memory/DynamicMemoryPool.hpp>
|
||||
#include <catch.hpp>
|
||||
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
TEST_CASE("DynamicJsonBuffer::startString()") {
|
||||
TEST_CASE("DynamicMemoryPool::startString()") {
|
||||
SECTION("WorksWhenBufferIsBigEnough") {
|
||||
DynamicJsonBuffer jsonBuffer(6);
|
||||
DynamicMemoryPool memoryPool(6);
|
||||
|
||||
DynamicJsonBuffer::String str = jsonBuffer.startString();
|
||||
DynamicMemoryPool::String str = memoryPool.startString();
|
||||
str.append('h');
|
||||
str.append('e');
|
||||
str.append('l');
|
||||
@ -22,9 +22,9 @@ TEST_CASE("DynamicJsonBuffer::startString()") {
|
||||
}
|
||||
|
||||
SECTION("GrowsWhenBufferIsTooSmall") {
|
||||
DynamicJsonBuffer jsonBuffer(5);
|
||||
DynamicMemoryPool memoryPool(5);
|
||||
|
||||
DynamicJsonBuffer::String str = jsonBuffer.startString();
|
||||
DynamicMemoryPool::String str = memoryPool.startString();
|
||||
str.append('h');
|
||||
str.append('e');
|
||||
str.append('l');
|
||||
@ -35,15 +35,15 @@ TEST_CASE("DynamicJsonBuffer::startString()") {
|
||||
}
|
||||
|
||||
SECTION("SizeIncreases") {
|
||||
DynamicJsonBuffer jsonBuffer(5);
|
||||
DynamicMemoryPool memoryPool(5);
|
||||
|
||||
DynamicJsonBuffer::String str = jsonBuffer.startString();
|
||||
REQUIRE(0 == jsonBuffer.size());
|
||||
DynamicMemoryPool::String str = memoryPool.startString();
|
||||
REQUIRE(0 == memoryPool.size());
|
||||
|
||||
str.append('h');
|
||||
REQUIRE(1 == jsonBuffer.size());
|
||||
REQUIRE(1 == memoryPool.size());
|
||||
|
||||
str.c_str();
|
||||
REQUIRE(2 == jsonBuffer.size());
|
||||
REQUIRE(2 == memoryPool.size());
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ TEST_CASE("JsonArray::copyFrom()") {
|
||||
REQUIRE(std::string("[1,2,3]") == json);
|
||||
}
|
||||
|
||||
SECTION("OneDimension_JsonBufferTooSmall") {
|
||||
SECTION("OneDimension_MemoryPoolTooSmall") {
|
||||
const size_t SIZE = JSON_ARRAY_SIZE(2);
|
||||
StaticJsonDocument<SIZE> doc;
|
||||
JsonArray array = doc.to<JsonArray>();
|
||||
@ -46,16 +46,19 @@ TEST_CASE("JsonArray::copyFrom()") {
|
||||
REQUIRE(std::string("[[1,2,3],[4,5,6]]") == json);
|
||||
}
|
||||
|
||||
SECTION("TwoDimensions_JsonBufferTooSmall") {
|
||||
SECTION("TwoDimensions_MemoryPoolTooSmall") {
|
||||
const size_t SIZE =
|
||||
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);
|
||||
|
@ -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);
|
||||
}*/
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -57,7 +57,7 @@ TEST_CASE("deserialize JSON array with a StaticJsonDocument") {
|
||||
deserializeJson(doc, " [ \"1234567\" ] ");
|
||||
|
||||
REQUIRE(JSON_ARRAY_SIZE(1) + sizeof("1234567") == doc.memoryUsage());
|
||||
// note: we use a string of 8 bytes to be sure that the StaticJsonBuffer
|
||||
// note: we use a string of 8 bytes to be sure that the StaticMemoryPool
|
||||
// will not insert bytes to enforce alignement
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,14 @@ TEST_CASE("deserializeJson(DynamicJsonDocument&)") {
|
||||
REQUIRE(doc.as<bool>() == false);
|
||||
}
|
||||
|
||||
SECTION("0") {
|
||||
DeserializationError err = deserializeJson(doc, "0");
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(doc.is<int>() == true);
|
||||
REQUIRE(doc.as<int>() == 0);
|
||||
REQUIRE(doc.as<std::string>() == "0"); // issue #808
|
||||
}
|
||||
|
||||
SECTION("NaN") {
|
||||
DeserializationError err = deserializeJson(doc, "NaN");
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
}*/
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
obj.remove("hello");
|
||||
|
||||
REQUIRE(0 == obj.size());
|
||||
}
|
||||
|
||||
SECTION("SizeUntouched_WhenRemoveIsCalledWithAWrongKey") {
|
||||
obj["hello"] = 1;
|
||||
|
||||
obj.remove("world");
|
||||
|
||||
REQUIRE(1 == obj.size());
|
||||
}
|
||||
|
||||
SECTION("RemoveByIterator") {
|
||||
obj["a"] = 0;
|
||||
obj["b"] = 1;
|
||||
obj["c"] = 2;
|
||||
|
||||
for (JsonObject::iterator it = obj.begin(); it != obj.end(); ++it) {
|
||||
if (it->value() == 1) obj.remove(it);
|
||||
SECTION("remove(key)") {
|
||||
SECTION("Remove first") {
|
||||
obj.remove("a");
|
||||
serializeJson(obj, result);
|
||||
REQUIRE("{\"b\":1,\"c\":2}" == result);
|
||||
}
|
||||
|
||||
std::string result;
|
||||
serializeJson(obj, result);
|
||||
REQUIRE("{\"a\":0,\"c\":2}" == result);
|
||||
SECTION("Remove middle") {
|
||||
obj.remove("b");
|
||||
serializeJson(obj, result);
|
||||
REQUIRE("{\"a\":0,\"c\":2}" == result);
|
||||
}
|
||||
|
||||
SECTION("Remove last") {
|
||||
obj.remove("c");
|
||||
serializeJson(obj, result);
|
||||
REQUIRE("{\"a\":0,\"b\":1}" == result);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("remove(iterator)") {
|
||||
JsonObject::iterator it = obj.begin();
|
||||
|
||||
SECTION("Remove first") {
|
||||
obj.remove(it);
|
||||
serializeJson(obj, result);
|
||||
REQUIRE("{\"b\":1,\"c\":2}" == result);
|
||||
}
|
||||
|
||||
SECTION("Remove middle") {
|
||||
++it;
|
||||
obj.remove(it);
|
||||
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
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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") {
|
||||
|
@ -45,6 +45,10 @@ TEST_CASE("serializeJson(JsonVariant)") {
|
||||
check(3.1415927, "3.1415927");
|
||||
}
|
||||
|
||||
SECTION("Zero") {
|
||||
check(0, "0");
|
||||
}
|
||||
|
||||
SECTION("Integer") {
|
||||
check(42, "42");
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
add_executable(JsonVariantTests
|
||||
as.cpp
|
||||
compare.cpp
|
||||
copy.cpp
|
||||
is.cpp
|
||||
isnull.cpp
|
||||
or.cpp
|
||||
|
@ -12,223 +12,150 @@ TEST_CASE("JsonVariant::as()") {
|
||||
DynamicJsonDocument doc;
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
|
||||
SECTION("DoubleAsBool") {
|
||||
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("set(4.2)") {
|
||||
variant.set(4.2);
|
||||
|
||||
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("DoubleAsCstr") {
|
||||
variant.set(4.2);
|
||||
REQUIRE_FALSE(variant.as<const char*>());
|
||||
}
|
||||
|
||||
SECTION("DoubleAsString") {
|
||||
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") {
|
||||
SECTION("set(0.0)") {
|
||||
variant.set(0.0);
|
||||
REQUIRE_FALSE(variant.as<bool>());
|
||||
|
||||
REQUIRE(variant.as<bool>() == false);
|
||||
REQUIRE(variant.as<long>() == 0L);
|
||||
}
|
||||
|
||||
SECTION("DoubleZeroAsLong") {
|
||||
variant.set(0.0);
|
||||
REQUIRE(0L == variant.as<long>());
|
||||
}
|
||||
|
||||
SECTION("FalseAsBool") {
|
||||
SECTION("set(false)") {
|
||||
variant.set(false);
|
||||
REQUIRE_FALSE(variant.as<bool>());
|
||||
|
||||
REQUIRE(false == variant.as<bool>());
|
||||
REQUIRE(variant.as<double>() == 0.0);
|
||||
REQUIRE(variant.as<long>() == 0L);
|
||||
REQUIRE(variant.as<std::string>() == "false");
|
||||
}
|
||||
|
||||
SECTION("FalseAsDouble") {
|
||||
variant.set(false);
|
||||
REQUIRE(0.0 == variant.as<double>());
|
||||
}
|
||||
|
||||
SECTION("FalseAsLong") {
|
||||
variant.set(false);
|
||||
REQUIRE(0L == variant.as<long>());
|
||||
}
|
||||
|
||||
SECTION("FalseAsString") {
|
||||
variant.set(false);
|
||||
REQUIRE(std::string("false") == variant.as<std::string>());
|
||||
}
|
||||
|
||||
SECTION("TrueAsBool") {
|
||||
SECTION("set(true)") {
|
||||
variant.set(true);
|
||||
|
||||
REQUIRE(variant.as<bool>());
|
||||
REQUIRE(variant.as<double>() == 1.0);
|
||||
REQUIRE(variant.as<long>() == 1L);
|
||||
REQUIRE(variant.as<std::string>() == "true");
|
||||
}
|
||||
|
||||
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") {
|
||||
SECTION("set(42L)") {
|
||||
variant.set(42L);
|
||||
REQUIRE(variant.as<bool>());
|
||||
|
||||
REQUIRE(variant.as<bool>() == true);
|
||||
REQUIRE(variant.as<double>() == 42.0);
|
||||
REQUIRE(variant.as<std::string>() == "42");
|
||||
}
|
||||
|
||||
SECTION("LongZeroAsBool") {
|
||||
variant.set(0L);
|
||||
REQUIRE_FALSE(variant.as<bool>());
|
||||
}
|
||||
|
||||
SECTION("PositiveLongAsDouble") {
|
||||
variant.set(42L);
|
||||
REQUIRE(42.0 == variant.as<double>());
|
||||
}
|
||||
|
||||
SECTION("NegativeLongAsDouble") {
|
||||
SECTION("set(-42L)") {
|
||||
variant.set(-42L);
|
||||
REQUIRE(-42.0 == variant.as<double>());
|
||||
|
||||
REQUIRE(variant.as<double>() == -42.0);
|
||||
REQUIRE(variant.as<std::string>() == "-42");
|
||||
}
|
||||
|
||||
SECTION("LongAsString") {
|
||||
variant.set(42L);
|
||||
REQUIRE(std::string("42") == variant.as<std::string>());
|
||||
}
|
||||
|
||||
SECTION("LongZeroAsDouble") {
|
||||
SECTION("set(0L)") {
|
||||
variant.set(0L);
|
||||
REQUIRE(0.0 == variant.as<double>());
|
||||
|
||||
SECTION("as<bool>()") {
|
||||
REQUIRE(false == variant.as<bool>());
|
||||
}
|
||||
|
||||
SECTION("as<double>()") {
|
||||
REQUIRE(variant.as<double>() == 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("NullAsBool") {
|
||||
SECTION("set(null)") {
|
||||
variant.set(null);
|
||||
REQUIRE_FALSE(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("NullAsDouble") {
|
||||
variant.set(null);
|
||||
REQUIRE(0.0 == variant.as<double>());
|
||||
}
|
||||
|
||||
SECTION("NullAsLong") {
|
||||
variant.set(null);
|
||||
REQUIRE(0L == variant.as<long>());
|
||||
}
|
||||
|
||||
SECTION("NullAsString") {
|
||||
variant.set(null);
|
||||
REQUIRE(std::string("null") == variant.as<std::string>());
|
||||
}
|
||||
|
||||
SECTION("NumberStringAsBool") {
|
||||
SECTION("set(\"42\")") {
|
||||
variant.set("42");
|
||||
|
||||
REQUIRE(variant.as<bool>());
|
||||
REQUIRE(variant.as<long>() == 42L);
|
||||
}
|
||||
|
||||
SECTION("NumberStringAsLong") {
|
||||
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") {
|
||||
SECTION("set(\"hello\")") {
|
||||
variant.set("hello");
|
||||
REQUIRE_FALSE(variant.as<bool>());
|
||||
|
||||
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("RandomStringAsLong") {
|
||||
variant.set("hello");
|
||||
REQUIRE(0L == variant.as<long>());
|
||||
}
|
||||
|
||||
SECTION("RandomStringAsConstCharPtr") {
|
||||
variant.set("hello");
|
||||
REQUIRE(std::string("hello") == variant.as<const char*>());
|
||||
}
|
||||
|
||||
SECTION("RandomStringAsCharPtr") {
|
||||
variant.set("hello");
|
||||
REQUIRE(std::string("hello") == variant.as<char*>());
|
||||
}
|
||||
|
||||
SECTION("RandomStringAsString") {
|
||||
variant.set("hello");
|
||||
REQUIRE(std::string("hello") == variant.as<std::string>());
|
||||
}
|
||||
|
||||
SECTION("TrueStringAsBool") {
|
||||
SECTION("set(\"true\")") {
|
||||
variant.set("true");
|
||||
|
||||
REQUIRE(variant.as<bool>());
|
||||
REQUIRE(variant.as<long>() == 1L);
|
||||
}
|
||||
|
||||
SECTION("TrueStringAsLong") {
|
||||
variant.set("true");
|
||||
REQUIRE(1L == variant.as<long>());
|
||||
}
|
||||
|
||||
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("as<std::string>()") {
|
||||
REQUIRE(variant.as<std::string>() == std::string("[4,2]"));
|
||||
}
|
||||
|
||||
SECTION("as<JsonArray>()") {
|
||||
JsonArray a = variant.as<JsonArray>();
|
||||
REQUIRE(a.size() == 2);
|
||||
REQUIRE(a[0] == 4);
|
||||
REQUIRE(a[1] == 2);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("ArrayAsJsonArray") {
|
||||
DynamicJsonDocument doc2;
|
||||
JsonArray arr = doc2.to<JsonArray>();
|
||||
|
||||
variant.set(arr);
|
||||
REQUIRE(arr == variant.as<JsonArray>());
|
||||
REQUIRE(arr == variant.as<JsonArray>()); // <- shorthand
|
||||
#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
|
||||
SECTION("Smallest int64 negative") {
|
||||
variant.set("-9223372036854775808");
|
||||
REQUIRE(variant.as<long long>() == -9223372036854775807 - 1);
|
||||
}
|
||||
|
||||
SECTION("ObjectAsJsonObject") {
|
||||
DynamicJsonDocument doc2;
|
||||
JsonObject obj = doc2.to<JsonObject>();
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -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
test/JsonVariant/copy.cpp
Normal file
84
test/JsonVariant/copy.cpp
Normal file
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}*/
|
||||
}
|
||||
|
@ -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) && \
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +0,0 @@
|
||||
# ArduinoJson - arduinojson.org
|
||||
# Copyright Benoit Blanchon 2014-2018
|
||||
# MIT License
|
||||
|
||||
add_executable(StaticJsonBufferTests
|
||||
alloc.cpp
|
||||
size.cpp
|
||||
startString.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(StaticJsonBufferTests catch)
|
||||
add_test(StaticJsonBuffer StaticJsonBufferTests)
|
@ -1,44 +0,0 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson/Memory/StaticJsonBuffer.hpp>
|
||||
#include <catch.hpp>
|
||||
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
TEST_CASE("StaticJsonBuffer::size()") {
|
||||
StaticJsonBuffer<64> buffer;
|
||||
|
||||
SECTION("Capacity equals template parameter") {
|
||||
REQUIRE(64 == buffer.capacity());
|
||||
}
|
||||
|
||||
SECTION("Initial size is 0") {
|
||||
REQUIRE(0 == buffer.size());
|
||||
}
|
||||
|
||||
SECTION("Increases after alloc()") {
|
||||
buffer.alloc(1);
|
||||
REQUIRE(1U <= buffer.size());
|
||||
buffer.alloc(1);
|
||||
REQUIRE(2U <= buffer.size());
|
||||
}
|
||||
|
||||
SECTION("Doesn't grow when buffer is full") {
|
||||
buffer.alloc(64);
|
||||
buffer.alloc(1);
|
||||
REQUIRE(64 == buffer.size());
|
||||
}
|
||||
|
||||
SECTION("Does't grow when buffer is too small for alloc") {
|
||||
buffer.alloc(65);
|
||||
REQUIRE(0 == buffer.size());
|
||||
}
|
||||
|
||||
SECTION("Goes back to zero after clear()") {
|
||||
buffer.alloc(1);
|
||||
buffer.clear();
|
||||
REQUIRE(0 == buffer.size());
|
||||
}
|
||||
}
|
12
test/StaticMemoryPool/CMakeLists.txt
Normal file
12
test/StaticMemoryPool/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
||||
# ArduinoJson - arduinojson.org
|
||||
# Copyright Benoit Blanchon 2014-2018
|
||||
# MIT License
|
||||
|
||||
add_executable(StaticMemoryPoolTests
|
||||
alloc.cpp
|
||||
size.cpp
|
||||
startString.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(StaticMemoryPoolTests catch)
|
||||
add_test(StaticMemoryPool StaticMemoryPoolTests)
|
@ -2,7 +2,7 @@
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson/Memory/StaticJsonBuffer.hpp>
|
||||
#include <ArduinoJson/Memory/StaticMemoryPool.hpp>
|
||||
#include <catch.hpp>
|
||||
|
||||
using namespace ArduinoJson::Internals;
|
||||
@ -13,42 +13,42 @@ static bool isAligned(void *ptr) {
|
||||
return (addr & mask) == 0;
|
||||
}
|
||||
|
||||
TEST_CASE("StaticJsonBuffer::alloc()") {
|
||||
StaticJsonBuffer<64> buffer;
|
||||
TEST_CASE("StaticMemoryPool::alloc()") {
|
||||
StaticMemoryPool<64> memoryPool;
|
||||
|
||||
SECTION("Returns different addresses") {
|
||||
void *p1 = buffer.alloc(1);
|
||||
void *p2 = buffer.alloc(1);
|
||||
void *p1 = memoryPool.alloc(1);
|
||||
void *p2 = memoryPool.alloc(1);
|
||||
REQUIRE(p1 != p2);
|
||||
}
|
||||
|
||||
SECTION("Returns non-NULL when using full capacity") {
|
||||
void *p = buffer.alloc(64);
|
||||
void *p = memoryPool.alloc(64);
|
||||
REQUIRE(0 != p);
|
||||
}
|
||||
|
||||
SECTION("Returns NULL when full") {
|
||||
buffer.alloc(64);
|
||||
void *p = buffer.alloc(1);
|
||||
memoryPool.alloc(64);
|
||||
void *p = memoryPool.alloc(1);
|
||||
REQUIRE(0 == p);
|
||||
}
|
||||
|
||||
SECTION("Returns NULL when buffer is too small") {
|
||||
void *p = buffer.alloc(65);
|
||||
SECTION("Returns NULL when memoryPool is too small") {
|
||||
void *p = memoryPool.alloc(65);
|
||||
REQUIRE(0 == p);
|
||||
}
|
||||
|
||||
SECTION("Returns aligned pointers") {
|
||||
for (size_t size = 1; size <= sizeof(void *); size++) {
|
||||
void *p = buffer.alloc(1);
|
||||
void *p = memoryPool.alloc(1);
|
||||
REQUIRE(isAligned(p));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Returns same address after clear()") {
|
||||
void *p1 = buffer.alloc(1);
|
||||
buffer.clear();
|
||||
void *p2 = buffer.alloc(1);
|
||||
void *p1 = memoryPool.alloc(1);
|
||||
memoryPool.clear();
|
||||
void *p2 = memoryPool.alloc(1);
|
||||
REQUIRE(p1 == p2);
|
||||
}
|
||||
}
|
44
test/StaticMemoryPool/size.cpp
Normal file
44
test/StaticMemoryPool/size.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2018
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson/Memory/StaticMemoryPool.hpp>
|
||||
#include <catch.hpp>
|
||||
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
TEST_CASE("StaticMemoryPool::size()") {
|
||||
StaticMemoryPool<64> memoryPool;
|
||||
|
||||
SECTION("Capacity equals template parameter") {
|
||||
REQUIRE(64 == memoryPool.capacity());
|
||||
}
|
||||
|
||||
SECTION("Initial size is 0") {
|
||||
REQUIRE(0 == memoryPool.size());
|
||||
}
|
||||
|
||||
SECTION("Increases after alloc()") {
|
||||
memoryPool.alloc(1);
|
||||
REQUIRE(1U <= memoryPool.size());
|
||||
memoryPool.alloc(1);
|
||||
REQUIRE(2U <= memoryPool.size());
|
||||
}
|
||||
|
||||
SECTION("Doesn't grow when memoryPool is full") {
|
||||
memoryPool.alloc(64);
|
||||
memoryPool.alloc(1);
|
||||
REQUIRE(64 == memoryPool.size());
|
||||
}
|
||||
|
||||
SECTION("Does't grow when memoryPool is too small for alloc") {
|
||||
memoryPool.alloc(65);
|
||||
REQUIRE(0 == memoryPool.size());
|
||||
}
|
||||
|
||||
SECTION("Goes back to zero after clear()") {
|
||||
memoryPool.alloc(1);
|
||||
memoryPool.clear();
|
||||
REQUIRE(0 == memoryPool.size());
|
||||
}
|
||||
}
|
@ -7,11 +7,11 @@
|
||||
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
TEST_CASE("StaticJsonBuffer::startString()") {
|
||||
TEST_CASE("StaticMemoryPool::startString()") {
|
||||
SECTION("WorksWhenBufferIsBigEnough") {
|
||||
StaticJsonBuffer<6> jsonBuffer;
|
||||
StaticMemoryPool<6> memoryPool;
|
||||
|
||||
StaticJsonBufferBase::String str = jsonBuffer.startString();
|
||||
StaticMemoryPoolBase::String str = memoryPool.startString();
|
||||
str.append('h');
|
||||
str.append('e');
|
||||
str.append('l');
|
||||
@ -22,9 +22,9 @@ TEST_CASE("StaticJsonBuffer::startString()") {
|
||||
}
|
||||
|
||||
SECTION("ReturnsNullWhenTooSmall") {
|
||||
StaticJsonBuffer<5> jsonBuffer;
|
||||
StaticMemoryPool<5> memoryPool;
|
||||
|
||||
StaticJsonBufferBase::String str = jsonBuffer.startString();
|
||||
StaticMemoryPoolBase::String str = memoryPool.startString();
|
||||
str.append('h');
|
||||
str.append('e');
|
||||
str.append('l');
|
||||
@ -35,15 +35,15 @@ TEST_CASE("StaticJsonBuffer::startString()") {
|
||||
}
|
||||
|
||||
SECTION("SizeIncreases") {
|
||||
StaticJsonBuffer<5> jsonBuffer;
|
||||
StaticMemoryPool<5> memoryPool;
|
||||
|
||||
StaticJsonBufferBase::String str = jsonBuffer.startString();
|
||||
REQUIRE(0 == jsonBuffer.size());
|
||||
StaticMemoryPoolBase::String str = memoryPool.startString();
|
||||
REQUIRE(0 == memoryPool.size());
|
||||
|
||||
str.append('h');
|
||||
REQUIRE(1 == jsonBuffer.size());
|
||||
REQUIRE(1 == memoryPool.size());
|
||||
|
||||
str.c_str();
|
||||
REQUIRE(2 == jsonBuffer.size());
|
||||
REQUIRE(2 == memoryPool.size());
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user