Compare commits

...

19 Commits

Author SHA1 Message Date
2ec9569b36 Set version to 6.3.0-beta 2018-08-31 16:57:14 +02:00
58303d0837 Added date in change log 2018-08-31 16:38:42 +02:00
e3639918eb Reduced executable size 2018-08-31 16:29:08 +02:00
6d290bd001 Fixed duplication of char* 2018-08-22 14:37:17 +02:00
7683667b3c Fixed serializeJson(obj[key], dst) (closes #794) 2018-08-21 18:07:41 +02:00
9cbc891816 Implemented reference semantics for JsonVariant 2018-08-21 17:56:16 +02:00
0454bd1ef6 Set version to 6.2.3-beta 2018-07-19 18:28:03 +02:00
f139100b23 Added a script to update the version number 2018-07-19 18:27:44 +02:00
3f666bd5f0 Fixed exception when using Flash strings as object keys (fixes #784) 2018-07-19 17:22:28 +02:00
d53a93e0ae Set version to 6.2.2-beta 2018-07-18 20:21:00 +02:00
2059d610a8 Fixed invalid application of 'sizeof' to incomplete type (closes #783) 2018-07-18 20:19:22 +02:00
9bbfbd0a6a Set version to 6.2.1-beta 2018-07-17 10:27:04 +02:00
6e4f1dc756 Fixed JsonObject not inserting keys of type String (fixes #782) 2018-07-17 10:24:21 +02:00
dc13882624 Update badges to show status of branch 6.x 2018-07-12 11:01:26 +02:00
6bb17d5896 Checked that issue issue #628 is fixed 2018-07-12 10:33:56 +02:00
1a513cbd16 Set version to 6.2.0-beta 2018-07-12 09:10:13 +02:00
87fa87d87b Renamed function RawJson() to serialized() 2018-07-12 09:08:20 +02:00
765752261c Improved float serialization when -fsingle-precision-constant is used 2018-07-04 12:07:03 +02:00
037f90aada Disabled lazy number deserialization (fixes #772) 2018-07-04 12:02:58 +02:00
135 changed files with 3228 additions and 2173 deletions

View File

@ -1,7 +1,103 @@
ArduinoJson: change log
=======================
v6.1.0-beta
v6.3.0-beta (2018-08-31)
-----------
* Implemented reference semantics for `JsonVariant`
* Replace `JsonPair`'s `key` and `value` with `key()` and `value()`
* Fixed `serializeJson(obj[key], dst)` (issue #794)
> ### BREAKING CHANGES
>
> #### JsonVariant
>
> `JsonVariant` now has a semantic similar to `JsonObject` and `JsonArray`.
> It's a reference to a value stored in the `JsonDocument`.
> As a consequence, a `JsonVariant` cannot be used as a standalone variable anymore.
>
> Old code:
>
> ```c++
> JsonVariant myValue = 42;
> ```
>
> New code:
>
> ```c++
> DynamicJsonDocument doc;
> JsonVariant myValue = doc.to<JsonVariant>();
> myValue.set(42);
> ```
>
> #### JsonPair
>
> Old code:
>
> ```c++
> for(JsonPair p : myObject) {
> Serial.println(p.key);
> Serial.println(p.value.as<int>());
> }
> ```
>
> New code:
>
> ```c++
> for(JsonPair p : myObject) {
> Serial.println(p.key());
> Serial.println(p.value().as<int>());
> }
> ```
>
> CAUTION: the key is now read only!
v6.2.3-beta (2018-07-19)
-----------
* Fixed exception when using Flash strings as object keys (issue #784)
v6.2.2-beta (2018-07-18)
-----------
* Fixed `invalid application of 'sizeof' to incomplete type '__FlashStringHelper'` (issue #783)
* Fixed `char[]` not duplicated when passed to `JsonVariant::operator[]`
v6.2.1-beta (2018-07-17)
-----------
* Fixed `JsonObject` not inserting keys of type `String` (issue #782)
v6.2.0-beta (2018-07-12)
-----------
* Disabled lazy number deserialization (issue #772)
* Improved float serialization when `-fsingle-precision-constant` is used
* Renamed function `RawJson()` to `serialized()`
* `serializeMsgPack()` now supports values marked with `serialized()`
> ### BREAKING CHANGES
>
> #### Non quoted strings
>
> Non quoted strings are now forbidden in values, but they are still allowed in keys.
> For example, `{key:"value"}` is accepted, but `{key:value}` is not.
>
> #### Preformatted values
>
> Old code:
>
> ```c++
> object["values"] = RawJson("[1,2,3,4]");
> ```
>
> New code:
>
> ```c++
> object["values"] = serialized("[1,2,3,4]");
> ```
v6.1.0-beta (2018-07-02)
-----------
* Return `JsonArray` and `JsonObject` by value instead of reference (issue #309)
@ -15,7 +111,7 @@ v6.1.0-beta
> JsonObject& obj = doc.to<JsonObject>();
> JsonArray& arr = obj.createNestedArray("key");
> if (!arr.success()) {
> Serial.println("No enough memory");
> Serial.println("Not enough memory");
> return;
> }
> ```
@ -26,17 +122,17 @@ v6.1.0-beta
> JsonObject obj = doc.to<JsonObject>();
> JsonArray arr = obj.createNestedArray("key");
> if (arr.isNull()) {
> Serial.println("No enough memory");
> Serial.println("Not enough memory");
> return;
> }
> ```
v6.0.1-beta
v6.0.1-beta (2018-06-11)
-----------
* Fixed conflicts with `isnan()` and `isinf()` macros (issue #752)
v6.0.0-beta
v6.0.0-beta (2018-06-07)
-----------
* Added `DynamicJsonDocument` and `StaticJsonDocument`

View File

@ -2,7 +2,7 @@
---
[![Build status](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/master?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/master) [![Build Status](https://travis-ci.org/bblanchon/ArduinoJson.svg?branch=master)](https://travis-ci.org/bblanchon/ArduinoJson) [![Coverage Status](https://img.shields.io/coveralls/bblanchon/ArduinoJson.svg)](https://coveralls.io/r/bblanchon/ArduinoJson?branch=master) [![Star this project](http://githubbadges.com/star.svg?user=bblanchon&repo=ArduinoJson&style=flat&color=fff&background=007ec6)](https://github.com/bblanchon/ArduinoJson)
[![Build status](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/6.x?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x) [![Build Status](https://travis-ci.org/bblanchon/ArduinoJson.svg?branch=6.x)](https://travis-ci.org/bblanchon/ArduinoJson) [![Coverage Status](https://img.shields.io/coveralls/bblanchon/ArduinoJson.svg)](https://coveralls.io/r/bblanchon/ArduinoJson?branch=6.x) [![Star this project](http://githubbadges.com/star.svg?user=bblanchon&repo=ArduinoJson&style=flat&color=fff&background=007ec6)](https://github.com/bblanchon/ArduinoJson)
ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).

View File

@ -37,8 +37,9 @@ void setup() {
// JsonBuffer.
obj["sensor"] = F("gps");
// It works with RawJson too:
obj["sensor"] = RawJson(F("\"gps\""));
// It works with serialized() too:
obj["sensor"] = serialized(F("\"gps\""));
obj["sensor"] = serialized(F("\xA3gps"), 3);
// You can compare the content of a JsonVariant to a Flash String
if (obj["sensor"] == F("gps")) {

View File

@ -41,8 +41,8 @@ void setup() {
// WARNING: the content of the String will be duplicated in the JsonBuffer.
obj["sensor"] = sensor;
// It works with RawJson too:
obj["sensor"] = RawJson(sensor);
// It works with serialized() too:
obj["sensor"] = serialized(sensor);
// You can also concatenate strings
// WARNING: the content of the String will be duplicated in the JsonBuffer.

View File

@ -7,7 +7,7 @@
"type": "git",
"url": "https://github.com/bblanchon/ArduinoJson.git"
},
"version": "6.1.0-beta",
"version": "6.3.0-beta",
"authors": {
"name": "Benoit Blanchon",
"url": "https://blog.benoitblanchon.fr"

View File

@ -1,5 +1,5 @@
name=ArduinoJson
version=6.1.0-beta
version=6.3.0-beta
author=Benoit Blanchon <blog.benoitblanchon.fr>
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
sentence=An efficient and elegant JSON library for Arduino.

44
scripts/publish.sh Normal file
View File

@ -0,0 +1,44 @@
#!/usr/bin/env bash
set -eux
cd "$(dirname "$0")/.."
VERSION="$1"
DATE=$(date +%F)
TAG="v$VERSION"
update_version_in_source () {
IFS=".-" read MAJOR MINOR REVISION EXTRA < <(echo "$VERSION")
UNDERLINE=$(printf -- '-%.0s' $(seq 1 ${#TAG}))
sed -i~ -bE "4s/HEAD/$TAG ($DATE)/; 5s/-+/$UNDERLINE/" CHANGELOG.md
rm CHANGELOG.md*~
sed -i~ -bE "s/\"version\":.*$/\"version\": \"$VERSION\",/" library.json
rm library.json*~
sed -i~ -bE "s/version=.*$/version=$VERSION/" library.properties
rm library.properties*~
sed -i~ -bE \
-e "s/ARDUINOJSON_VERSION .*$/ARDUINOJSON_VERSION \"$VERSION\"/" \
-e "s/ARDUINOJSON_VERSION_MAJOR .*$/ARDUINOJSON_VERSION_MAJOR $MAJOR/" \
-e "s/ARDUINOJSON_VERSION_MINOR .*$/ARDUINOJSON_VERSION_MINOR $MINOR/" \
-e "s/ARDUINOJSON_VERSION_REVISION .*$/ARDUINOJSON_VERSION_REVISION $REVISION/" \
src/ArduinoJson/version.hpp
rm src/ArduinoJson/version.hpp*~
}
commit_new_version () {
git add src/ArduinoJson/version.hpp CHANGELOG.md library.json library.properties
git commit -m "Set version to $VERSION"
}
add_tag () {
CHANGES=$(awk '/\* /{ FOUND=1; print; next } { if (FOUND) exit}' CHANGELOG.md)
git tag -m "ArduinoJson $VERSION\n$CHANGES" $TAG
}
update_version_in_source
commit_new_version
add_tag

View File

@ -4,6 +4,8 @@
#pragma once
#include <stdlib.h> // size_t
#include "JsonFloat.hpp"
#include "JsonInteger.hpp"
@ -18,9 +20,13 @@ struct JsonObjectData;
union JsonVariantContent {
JsonFloat asFloat; // used for double and float
JsonUInt asInteger; // used for bool, char, short, int and longs
const char* asString; // asString can be null
JsonArrayData* asArray; // asArray cannot be null
JsonObjectData* asObject; // asObject cannot be null
const char* asString; // asString can be null
struct {
const char* data;
size_t size;
} asRaw;
};
} // namespace Internals
} // namespace ArduinoJson

View File

@ -0,0 +1,181 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "../Numbers/parseFloat.hpp"
#include "../Numbers/parseInteger.hpp"
#include "JsonVariantContent.hpp"
#include "JsonVariantType.hpp"
namespace ArduinoJson {
namespace Internals {
struct JsonVariantData {
JsonVariantType type;
JsonVariantContent content;
void setBoolean(bool value) {
type = JSON_BOOLEAN;
content.asInteger = static_cast<JsonUInt>(value);
}
void setFloat(JsonFloat value) {
type = JSON_FLOAT;
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;
}
void setPostiveInteger(JsonUInt value) {
type = JSON_POSITIVE_INTEGER;
content.asInteger = value;
}
void setString(const char *value) {
type = JSON_STRING;
content.asString = value;
}
void setRaw(const char *data, size_t size) {
type = JSON_RAW;
content.asRaw.data = data;
content.asRaw.size = size;
}
void setNull() {
type = JSON_NULL;
}
void setArray(JsonArrayData &array) {
type = JSON_ARRAY;
content.asArray = &array;
}
void setObject(JsonObjectData &object) {
type = JSON_OBJECT;
content.asObject = &object;
}
JsonArrayData *asArray() const {
return type == JSON_ARRAY ? content.asArray : 0;
}
JsonObjectData *asObject() const {
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:
return parseInteger<T>(content.asString);
default:
return T(content.asFloat);
}
}
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:
return parseFloat<T>(content.asString);
default:
return static_cast<T>(content.asFloat);
}
}
const char *asString() const {
return type == JSON_STRING ? content.asString : NULL;
}
bool isArray() const {
return type == Internals::JSON_ARRAY;
}
bool isBoolean() const {
return type == JSON_BOOLEAN;
}
bool isFloat() const {
return type == JSON_FLOAT || type == JSON_POSITIVE_INTEGER ||
type == JSON_NEGATIVE_INTEGER;
}
bool isInteger() const {
return type == JSON_POSITIVE_INTEGER || type == JSON_NEGATIVE_INTEGER;
}
bool isNull() const {
return type == JSON_NULL;
}
bool isObject() const {
return type == Internals::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();
}
}
};
} // namespace Internals
} // namespace ArduinoJson

View File

@ -1,23 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
template <typename T>
struct JsonVariantDefault {
static T get() {
return T();
}
};
template <typename T>
struct JsonVariantDefault<const T> : JsonVariantDefault<T> {};
template <typename T>
struct JsonVariantDefault<T&> : JsonVariantDefault<T> {};
}
}

View File

@ -11,10 +11,10 @@ namespace Internals {
// Enumerated type to know the current type of a JsonVariant.
// The value determines which member of JsonVariantContent is used.
enum JsonVariantType {
JSON_UNDEFINED, // JsonVariant has not been initialized
JSON_UNPARSED, // JsonVariant contains an unparsed string
JSON_STRING, // JsonVariant stores a const char*
JSON_BOOLEAN, // JsonVariant stores a bool
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

View File

@ -22,7 +22,7 @@ class List {
typedef ListIterator<T> iterator;
typedef ListConstIterator<T> const_iterator;
explicit List(JsonBuffer *buf) : _buffer(buf), _firstNode(NULL) {}
List() : _firstNode(NULL) {}
// Returns the numbers of elements in the list.
// For a JsonObjectData, it would return the number of key-value pairs
@ -32,8 +32,8 @@ class List {
return nodeCount;
}
iterator add() {
node_type *newNode = new (_buffer) node_type();
iterator add(JsonBuffer *buffer) {
node_type *newNode = new (buffer) node_type();
if (_firstNode) {
node_type *lastNode = _firstNode;
@ -71,11 +71,6 @@ class List {
}
}
JsonBuffer &buffer() const {
return *_buffer;
}
JsonBuffer *_buffer; // TODO!!
protected:
void clear() {
_firstNode = 0;

View File

@ -15,7 +15,7 @@ namespace Internals {
// Used by List<T> and its iterators.
template <typename T>
struct ListNode : public Internals::JsonBufferAllocated {
ListNode() throw() : next(NULL) {}
ListNode() NOEXCEPT : next(NULL) {}
ListNode<T> *next;
T content;

View File

@ -1,52 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "../JsonVariant.hpp"
#include "../Memory/JsonBuffer.hpp"
#include "../Polyfills/type_traits.hpp"
#include "../Strings/StringTraits.hpp"
namespace ArduinoJson {
namespace Internals {
template <typename Source, typename Enable = void>
struct ValueSaver {
template <typename Destination>
static bool save(JsonBuffer*, Destination& destination, Source source) {
destination = source;
return true;
}
};
template <typename Source>
struct ValueSaver<
Source, typename enable_if<StringTraits<Source>::should_duplicate>::type> {
template <typename Destination>
static bool save(JsonBuffer* buffer, Destination& dest, Source source) {
if (!StringTraits<Source>::is_null(source)) {
typename StringTraits<Source>::duplicate_t dup =
StringTraits<Source>::duplicate(source, buffer);
if (!dup) return false;
dest = dup;
} else {
dest = reinterpret_cast<const char*>(0);
}
return true;
}
};
// const char*, const signed char*, const unsigned char*
template <typename Char>
struct ValueSaver<
Char*, typename enable_if<!StringTraits<Char*>::should_duplicate>::type> {
template <typename Destination>
static bool save(JsonBuffer*, Destination& dest, Char* source) {
dest = reinterpret_cast<const char*>(source);
return true;
}
};
} // namespace Internals
} // namespace ArduinoJson

View File

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

View File

@ -12,24 +12,21 @@
namespace ArduinoJson {
class DynamicJsonDocument {
Internals::DynamicJsonBuffer _buffer;
JsonVariant _root;
public:
uint8_t nestingLimit;
DynamicJsonDocument() : nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {}
DynamicJsonDocument(size_t capacity)
: _buffer(capacity), nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {}
: nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT), _buffer(capacity) {}
template <typename T>
bool is() const {
return _root.is<T>();
return getVariant().is<T>();
}
template <typename T>
typename Internals::JsonVariantAs<T>::type as() const {
return _root.as<T>();
return getVariant().as<T>();
}
// JsonObject to<JsonObject>()
@ -39,7 +36,7 @@ class DynamicJsonDocument {
to() {
clear();
JsonObject object(&_buffer);
_root = object;
getVariant().set(object);
return object;
}
@ -50,17 +47,27 @@ class DynamicJsonDocument {
to() {
clear();
JsonArray array(&_buffer);
_root = array;
getVariant().set(array);
return array;
}
// JsonVariant& to<JsonVariant>()
// JsonVariant to<JsonVariant>()
template <typename T>
typename Internals::enable_if<Internals::is_same<T, JsonVariant>::value,
T&>::type
JsonVariant>::type
to() {
clear();
return _root;
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() {
@ -69,7 +76,7 @@ class DynamicJsonDocument {
void clear() {
_buffer.clear();
_root = JsonVariant();
_rootData.setNull();
}
size_t memoryUsage() const {
@ -78,7 +85,15 @@ class DynamicJsonDocument {
template <typename Visitor>
void visit(Visitor& visitor) const {
return _root.visit(visitor);
return _rootData.visit(visitor);
}
private:
JsonVariant getVariant() const {
return JsonVariant(&_buffer, &_rootData);
}
mutable Internals::DynamicJsonBuffer _buffer;
mutable Internals::JsonVariantData _rootData;
};
} // namespace ArduinoJson

View File

@ -19,19 +19,22 @@ class IndentedPrint {
isNewLine = true;
}
size_t print(char c) {
size_t write(uint8_t c) {
size_t n = 0;
if (isNewLine) n += writeTabs();
n += sink->print(c);
n += sink->write(c);
isNewLine = c == '\n';
return n;
}
size_t print(const char *s) {
size_t write(const uint8_t *s, size_t n) {
// TODO: optimize
size_t n = 0;
while (*s) n += print(*s++);
return n;
size_t bytesWritten = 0;
while (n > 0) {
bytesWritten += write(*s++);
n--;
}
return bytesWritten;
}
// Adds one level of indentation
@ -57,7 +60,7 @@ class IndentedPrint {
size_t writeTabs() {
size_t n = 0;
for (int i = 0; i < level * tabSize; i++) n += sink->print(' ');
for (int i = 0; i < level * tabSize; i++) n += sink->write(' ');
return n;
}

View File

@ -7,6 +7,8 @@
#include "../Deserialization/deserialize.hpp"
#include "../JsonVariant.hpp"
#include "../Memory/JsonBuffer.hpp"
#include "../Numbers/isFloat.hpp"
#include "../Numbers/isInteger.hpp"
#include "../Polyfills/type_traits.hpp"
#include "./EscapeSequence.hpp"
@ -23,7 +25,7 @@ class JsonDeserializer {
_stringStorage(stringStorage),
_nestingLimit(nestingLimit),
_loaded(false) {}
DeserializationError parse(JsonVariant &variant) {
DeserializationError parse(JsonVariantData &variant) {
DeserializationError err = skipSpacesAndComments();
if (err) return err;
@ -63,12 +65,12 @@ class JsonDeserializer {
return true;
}
DeserializationError parseArray(JsonVariant &variant) {
DeserializationError parseArray(JsonVariantData &variant) {
if (_nestingLimit == 0) return DeserializationError::TooDeep;
JsonArray array(_buffer);
if (array.isNull()) return DeserializationError::NoMemory;
variant = array;
JsonArrayData *array = new (_buffer) JsonArrayData;
if (!array) return DeserializationError::NoMemory;
variant.setArray(*array);
// Check opening braket
if (!eat('[')) return DeserializationError::InvalidInput;
@ -82,13 +84,15 @@ class JsonDeserializer {
// Read each value
for (;;) {
// Allocate slot in array
JsonVariantData *value = array->addSlot(_buffer);
if (!value) return DeserializationError::NoMemory;
// 1 - Parse value
JsonVariant value;
_nestingLimit--;
err = parse(value);
err = parse(*value);
_nestingLimit++;
if (err) return err;
if (!array.add(value)) return DeserializationError::NoMemory;
// 2 - Skip spaces
err = skipSpacesAndComments();
@ -100,12 +104,12 @@ class JsonDeserializer {
}
}
DeserializationError parseObject(JsonVariant &variant) {
DeserializationError parseObject(JsonVariantData &variant) {
if (_nestingLimit == 0) return DeserializationError::TooDeep;
JsonObject object(_buffer);
if (object.isNull()) return DeserializationError::NoMemory;
variant = object;
JsonObjectData *object = new (_buffer) JsonObjectData;
if (!object) return DeserializationError::NoMemory;
variant.setObject(*object);
// Check opening brace
if (!eat('{')) return DeserializationError::InvalidInput;
@ -121,7 +125,7 @@ class JsonDeserializer {
for (;;) {
// Parse key
const char *key;
err = parseString(&key);
err = parseKey(&key);
if (err) return err;
// Skip spaces
@ -129,13 +133,15 @@ class JsonDeserializer {
if (err) return err; // Colon
if (!eat(':')) return DeserializationError::InvalidInput;
// Allocate slot in object
JsonVariantData *value = object->addSlot(_buffer, key);
if (!value) return DeserializationError::NoMemory;
// Parse value
JsonVariant value;
_nestingLimit--;
err = parse(value);
err = parse(*value);
_nestingLimit++;
if (err) return err;
if (!object.set(key, value)) return DeserializationError::NoMemory;
// Skip spaces
err = skipSpacesAndComments();
@ -151,49 +157,70 @@ class JsonDeserializer {
}
}
DeserializationError parseValue(JsonVariant &variant) {
bool hasQuotes = isQuote(current());
const char *value;
DeserializationError error = parseString(&value);
if (error) return error;
if (hasQuotes) {
variant = value;
DeserializationError parseValue(JsonVariantData &variant) {
if (isQuote(current())) {
return parseStringValue(variant);
} else {
variant = RawJson(value);
return parseNumericValue(variant);
}
}
DeserializationError parseKey(const char **key) {
if (isQuote(current())) {
return parseQuotedString(key);
} else {
return parseNonQuotedString(key);
}
}
DeserializationError parseStringValue(JsonVariantData &variant) {
const char *value;
DeserializationError err = parseQuotedString(&value);
if (err) return err;
variant.setString(value);
return DeserializationError::Ok;
}
DeserializationError parseString(const char **result) {
DeserializationError parseQuotedString(const char **result) {
typename remove_reference<TStringStorage>::type::String str =
_stringStorage.startString();
char stopChar = current();
move();
for (;;) {
char c = current();
move();
if (c == stopChar) break;
if (c == '\0') return DeserializationError::IncompleteInput;
if (c == '\\') {
c = current();
if (c == '\0') return DeserializationError::IncompleteInput;
if (c == 'u') return DeserializationError::NotSupported;
// replace char
c = EscapeSequence::unescapeChar(c);
if (c == '\0') return DeserializationError::InvalidInput;
move();
}
str.append(c);
}
*result = str.c_str();
if (*result == NULL) return DeserializationError::NoMemory;
return DeserializationError::Ok;
}
DeserializationError parseNonQuotedString(const char **result) {
typename remove_reference<TStringStorage>::type::String str =
_stringStorage.startString();
char c = current();
if (c == '\0') return DeserializationError::IncompleteInput;
if (isQuote(c)) { // quotes
move();
char stopChar = c;
for (;;) {
c = current();
move();
if (c == stopChar) break;
if (c == '\0') return DeserializationError::IncompleteInput;
if (c == '\\') {
c = current();
if (c == '\0') return DeserializationError::IncompleteInput;
if (c == 'u') return DeserializationError::NotSupported;
// replace char
c = EscapeSequence::unescapeChar(c);
if (c == '\0') return DeserializationError::InvalidInput;
move();
}
str.append(c);
}
} else if (canBeInNonQuotedString(c)) { // no quotes
if (canBeInNonQuotedString(c)) { // no quotes
do {
move();
str.append(c);
@ -208,6 +235,34 @@ class JsonDeserializer {
return DeserializationError::Ok;
}
DeserializationError parseNumericValue(JsonVariantData &result) {
char buffer[64];
uint8_t n = 0;
char c = current();
while (canBeInNonQuotedString(c) && n < 63) {
move();
buffer[n++] = c;
c = current();
}
buffer[n] = 0;
if (isInteger(buffer)) {
result.setInteger(parseInteger<JsonInteger>(buffer));
} else if (isFloat(buffer)) {
result.setFloat(parseFloat<JsonFloat>(buffer));
} else if (!strcmp(buffer, "true")) {
result.setBoolean(true);
} else if (!strcmp(buffer, "false")) {
result.setBoolean(false);
} else if (!strcmp(buffer, "null")) {
result.setNull();
} else {
return DeserializationError::InvalidInput;
}
return DeserializationError::Ok;
}
static inline bool isBetween(char c, char min, char max) {
return min <= c && c <= max;
}
@ -286,7 +341,7 @@ class JsonDeserializer {
uint8_t _nestingLimit;
char _current;
bool _loaded;
};
}; // namespace Internals
} // namespace Internals
template <typename TDocument, typename TInput>

View File

@ -11,19 +11,19 @@
namespace ArduinoJson {
namespace Internals {
template <typename TPrint>
template <typename TWriter>
class JsonSerializer {
public:
JsonSerializer(TPrint &destination) : _writer(destination) {}
JsonSerializer(TWriter &writer) : _writer(writer) {}
void acceptFloat(JsonFloat value) {
_writer.writeFloat(value);
}
void acceptArray(const JsonArray &array) {
void acceptArray(const JsonArrayData &array) {
_writer.beginArray();
JsonArray::const_iterator it = array.begin();
JsonArrayData::const_iterator it = array.begin();
while (it != array.end()) {
it->visit(*this);
@ -36,10 +36,10 @@ class JsonSerializer {
_writer.endArray();
}
void acceptObject(const JsonObject &object) {
void acceptObject(const JsonObjectData &object) {
_writer.beginObject();
JsonObject::const_iterator it = object.begin();
JsonObjectData::const_iterator it = object.begin();
while (it != object.end()) {
_writer.writeString(it->key);
_writer.writeColon();
@ -58,8 +58,9 @@ class JsonSerializer {
_writer.writeString(value);
}
void acceptRawJson(const char *value) {
_writer.writeRaw(value);
void acceptRawJson(const char *data, size_t n) {
// TODO
for (size_t i = 0; i < n; i++) _writer.writeRaw(data[i]);
}
void acceptNegativeInteger(JsonUInt value) {
@ -84,13 +85,13 @@ class JsonSerializer {
}
private:
JsonWriter<TPrint> _writer;
JsonWriter<TWriter> _writer;
};
} // namespace Internals
template <typename TSource, typename TDestination>
size_t serializeJson(TSource &source, TDestination &destination) {
size_t serializeJson(const TSource &source, TDestination &destination) {
using namespace Internals;
return serialize<JsonSerializer>(source, destination);
}

View File

@ -5,6 +5,7 @@
#pragma once
#include <stdint.h>
#include <string.h> // for strlen
#include "../Data/JsonInteger.hpp"
#include "../Numbers/FloatParts.hpp"
#include "../Polyfills/attributes.hpp"
@ -13,12 +14,12 @@
namespace ArduinoJson {
namespace Internals {
template <typename Print>
template <typename TWriter>
class JsonWriter {
public:
explicit JsonWriter(Print &sink) : _sink(sink), _length(0) {}
explicit JsonWriter(TWriter &writer) : _writer(writer), _length(0) {}
// Returns the number of bytes sent to the Print implementation.
// Returns the number of bytes sent to the TWriter implementation.
size_t bytesWritten() const {
return _length;
}
@ -45,7 +46,10 @@ class JsonWriter {
}
void writeBoolean(bool value) {
writeRaw(value ? "true" : "false");
if (value)
writeRaw("true");
else
writeRaw("false");
}
void writeString(const char *value) {
@ -98,45 +102,53 @@ class JsonWriter {
template <typename UInt>
void writeInteger(UInt value) {
char buffer[22];
char *end = buffer + sizeof(buffer) - 1;
char *ptr = end;
char *end = buffer + sizeof(buffer);
char *begin = end;
*ptr = 0;
// write the string in reverse order
do {
*--ptr = char(value % 10 + '0');
*--begin = char(value % 10 + '0');
value = UInt(value / 10);
} while (value);
writeRaw(ptr);
// and dump it in the right order
writeRaw(begin, end);
}
void writeDecimals(uint32_t value, int8_t width) {
// buffer should be big enough for all digits, the dot and the null
// terminator
// buffer should be big enough for all digits and the dot
char buffer[16];
char *ptr = buffer + sizeof(buffer) - 1;
char *end = buffer + sizeof(buffer);
char *begin = end;
// write the string in reverse order
*ptr = 0;
while (width--) {
*--ptr = char(value % 10 + '0');
*--begin = char(value % 10 + '0');
value /= 10;
}
*--ptr = '.';
*--begin = '.';
// and dump it in the right order
writeRaw(ptr);
writeRaw(begin, end);
}
void writeRaw(const char *s) {
_length += _sink.print(s);
_length += _writer.write(reinterpret_cast<const uint8_t *>(s), strlen(s));
}
void writeRaw(const char *begin, const char *end) {
_length += _writer.write(reinterpret_cast<const uint8_t *>(begin),
static_cast<size_t>(end - begin));
}
template <size_t N>
void writeRaw(const char (&s)[N]) {
_length += _writer.write(reinterpret_cast<const uint8_t *>(s), N - 1);
}
void writeRaw(char c) {
_length += _sink.print(c);
_length += _writer.write(static_cast<uint8_t>(c));
}
protected:
Print &_sink;
TWriter &_writer;
size_t _length;
private:

View File

@ -10,25 +10,28 @@ namespace ArduinoJson {
namespace Internals {
// Converts a compact JSON string into an indented one.
template <typename Print>
template <typename TWriter>
class Prettyfier {
public:
explicit Prettyfier(IndentedPrint<Print>& p) : _sink(p) {
explicit Prettyfier(IndentedPrint<TWriter>& p) : _sink(p) {
_previousChar = 0;
_inString = false;
}
size_t print(char c) {
size_t n = _inString ? handleStringChar(c) : handleMarkupChar(c);
_previousChar = c;
size_t write(uint8_t c) {
size_t n = _inString ? handleStringChar(c) : handleMarkupChar(char(c));
_previousChar = char(c);
return n;
}
size_t print(const char* s) {
size_t write(const uint8_t* s, size_t n) {
// TODO: optimize
size_t n = 0;
while (*s) n += print(*s++);
return n;
size_t bytesWritten = 0;
while (n > 0) {
bytesWritten += write(*s++);
n--;
}
return bytesWritten;
}
private:
@ -38,12 +41,12 @@ class Prettyfier {
return _previousChar == '{' || _previousChar == '[';
}
size_t handleStringChar(char c) {
size_t handleStringChar(uint8_t c) {
bool isQuote = c == '"' && _previousChar != '\\';
if (isQuote) _inString = false;
return _sink.print(c);
return _sink.write(c);
}
size_t handleMarkupChar(char c) {
@ -73,26 +76,26 @@ class Prettyfier {
size_t writeBlockClose(char c) {
size_t n = 0;
n += unindentIfNeeded();
n += _sink.print(c);
n += write(c);
return n;
}
size_t writeBlockOpen(char c) {
size_t n = 0;
n += indentIfNeeded();
n += _sink.print(c);
n += write(c);
return n;
}
size_t writeColon() {
size_t n = 0;
n += _sink.print(": ");
n += write(": ");
return n;
}
size_t writeComma() {
size_t n = 0;
n += _sink.print(",\r\n");
n += write(",\r\n");
return n;
}
@ -100,14 +103,14 @@ class Prettyfier {
_inString = true;
size_t n = 0;
n += indentIfNeeded();
n += _sink.print('"');
n += write('"');
return n;
}
size_t writeNormalChar(char c) {
size_t n = 0;
n += indentIfNeeded();
n += _sink.print(c);
n += write(c);
return n;
}
@ -115,19 +118,28 @@ class Prettyfier {
if (!inEmptyBlock()) return 0;
_sink.indent();
return _sink.print("\r\n");
return write("\r\n");
}
size_t unindentIfNeeded() {
if (inEmptyBlock()) return 0;
_sink.unindent();
return _sink.print("\r\n");
return write("\r\n");
}
size_t write(char c) {
return _sink.write(static_cast<uint8_t>(c));
}
template <size_t N>
size_t write(const char (&s)[N]) {
return _sink.write(reinterpret_cast<const uint8_t*>(s), N - 1);
}
char _previousChar;
IndentedPrint<Print>& _sink;
IndentedPrint<TWriter>& _sink;
bool _inString;
};
}
}
} // namespace Internals
} // namespace ArduinoJson

View File

@ -4,7 +4,8 @@
#pragma once
#include "./JsonArrayData.hpp"
#include "JsonArrayData.hpp"
#include "JsonArrayIterator.hpp"
namespace ArduinoJson {
@ -18,52 +19,44 @@ class JsonArray {
friend class JsonVariant;
public:
typedef Internals::JsonArrayData::iterator iterator;
typedef Internals::JsonArrayData::const_iterator const_iterator;
typedef JsonArrayIterator iterator;
JsonArray() : _data(0) {}
JsonArray(Internals::JsonArrayData* arr) : _data(arr) {}
JsonArray(Internals::JsonBuffer* buf)
: _data(new (buf) Internals::JsonArrayData(buf)) {}
FORCE_INLINE JsonArray() : _buffer(0), _data(0) {}
FORCE_INLINE JsonArray(Internals::JsonBuffer* buf,
Internals::JsonArrayData* arr)
: _buffer(buf), _data(arr) {}
FORCE_INLINE explicit JsonArray(Internals::JsonBuffer* buf)
: _buffer(buf), _data(new (buf) Internals::JsonArrayData()) {}
// Adds the specified value at the end of the array.
//
// bool add(TValue);
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
// std::string, String, JsonArrayData, JsonObject
template <typename T>
bool add(const T& value) {
FORCE_INLINE bool add(const T& value) {
return add_impl<const T&>(value);
}
//
// bool add(TValue);
// TValue = char*, const char*, const FlashStringHelper*
template <typename T>
bool add(T* value) {
FORCE_INLINE bool add(T* value) {
return add_impl<T*>(value);
}
iterator begin() {
FORCE_INLINE iterator begin() const {
if (!_data) return iterator();
return _data->begin();
return iterator(_buffer, _data->begin());
}
const_iterator begin() const {
if (!_data) return const_iterator();
return _data->begin();
}
iterator end() {
FORCE_INLINE iterator end() const {
return iterator();
}
const_iterator end() const {
return const_iterator();
}
// Imports a 1D array
template <typename T, size_t N>
bool copyFrom(T (&array)[N]) {
FORCE_INLINE bool copyFrom(T (&array)[N]) {
return copyFrom(array, N);
}
@ -92,7 +85,7 @@ class JsonArray {
// Exports a 1D array
template <typename T, size_t N>
size_t copyTo(T (&array)[N]) const {
FORCE_INLINE size_t copyTo(T (&array)[N]) const {
return copyTo(array, N);
}
@ -100,8 +93,7 @@ class JsonArray {
template <typename T>
size_t copyTo(T* array, size_t len) const {
size_t i = 0;
for (const_iterator it = begin(); it != end() && i < len; ++it)
array[i++] = *it;
for (iterator it = begin(); it != end() && i < len; ++it) array[i++] = *it;
return i;
}
@ -110,54 +102,56 @@ class JsonArray {
void copyTo(T (&array)[N1][N2]) const {
if (!_data) return;
size_t i = 0;
for (const_iterator it = begin(); it != end() && i < N1; ++it) {
for (iterator it = begin(); it != end() && i < N1; ++it) {
it->as<JsonArray>().copyTo(array[i++]);
}
}
JsonArray createNestedArray();
JsonObject createNestedObject();
FORCE_INLINE JsonArray createNestedArray();
FORCE_INLINE JsonObject createNestedObject();
Internals::JsonArraySubscript operator[](size_t index);
FORCE_INLINE Internals::JsonArraySubscript operator[](size_t index);
const Internals::JsonArraySubscript operator[](size_t index) const;
FORCE_INLINE const Internals::JsonArraySubscript operator[](
size_t index) const;
bool operator==(const JsonArray& rhs) const {
FORCE_INLINE bool operator==(const JsonArray& rhs) const {
return _data == rhs._data;
}
// Gets the value at the specified index.
template <typename T>
typename Internals::JsonVariantAs<T>::type get(size_t index) const {
const_iterator it = begin() += index;
return it != end() ? it->as<T>() : Internals::JsonVariantDefault<T>::get();
FORCE_INLINE typename Internals::JsonVariantAs<T>::type get(
size_t index) const {
iterator it = begin() += index;
return it != end() ? it->as<T>() : T();
}
// Check the type of the value at specified index.
template <typename T>
bool is(size_t index) const {
const_iterator it = begin() += index;
FORCE_INLINE bool is(size_t index) const {
iterator it = begin() += index;
return it != end() ? it->is<T>() : false;
}
// Removes element at specified position.
void remove(iterator it) {
FORCE_INLINE void remove(iterator it) {
if (!_data) return;
_data->remove(it);
_data->remove(it.internal());
}
// Removes element at specified index.
void remove(size_t index) {
FORCE_INLINE void remove(size_t index) {
remove(begin() += index);
}
// Sets the value at specified index.
//
// bool add(size_t index, const TValue&);
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
// std::string, String, JsonArrayData, JsonObject
template <typename T>
bool set(size_t index, const T& value) {
FORCE_INLINE bool set(size_t index, const T& value) {
if (!_data) return false;
return set_impl<const T&>(index, value);
}
@ -165,44 +159,45 @@ class JsonArray {
// bool add(size_t index, TValue);
// TValue = char*, const char*, const FlashStringHelper*
template <typename T>
bool set(size_t index, T* value) {
FORCE_INLINE bool set(size_t index, T* value) {
if (!_data) return false;
return set_impl<T*>(index, value);
}
size_t size() const {
FORCE_INLINE size_t size() const {
if (!_data) return 0;
return _data->size();
}
bool isNull() const {
FORCE_INLINE bool isNull() const {
return _data == 0;
}
template <typename Visitor>
void visit(Visitor& visitor) const {
FORCE_INLINE void visit(Visitor& visitor) const {
if (_data)
return visitor.acceptArray(*this);
visitor.acceptArray(*_data);
else
visitor.acceptNull();
}
private:
template <typename TValueRef>
bool set_impl(size_t index, TValueRef value) {
FORCE_INLINE bool set_impl(size_t index, TValueRef value) {
iterator it = begin() += index;
if (it == end()) return false;
return Internals::ValueSaver<TValueRef>::save(_data->_buffer, *it, value);
return it->set(value);
}
template <typename TValueRef>
bool add_impl(TValueRef value) {
FORCE_INLINE bool add_impl(TValueRef value) {
if (!_data) return false;
iterator it = _data->add();
iterator it = iterator(_buffer, _data->add(_buffer));
if (it == end()) return false;
return Internals::ValueSaver<TValueRef>::save(_data->_buffer, *it, value);
return it->set(value);
}
Internals::JsonBuffer* _buffer;
Internals::JsonArrayData* _data;
};
} // namespace ArduinoJson

View File

@ -4,12 +4,10 @@
#pragma once
#include "Data/JsonVariantData.hpp"
#include "Data/List.hpp"
#include "Data/ValueSaver.hpp"
#include "JsonVariant.hpp"
#include "Memory/JsonBufferAllocated.hpp"
#include "Polyfills/type_traits.hpp"
#include "Strings/StringTraits.hpp"
// Returns the size (in bytes) of an array with n elements.
// Can be very handy to determine the size of a StaticJsonBuffer.
@ -20,8 +18,11 @@
namespace ArduinoJson {
namespace Internals {
struct JsonArrayData : List<JsonVariant>, JsonBufferAllocated {
explicit JsonArrayData(JsonBuffer *buf) throw() : List<JsonVariant>(buf) {}
struct JsonArrayData : List<JsonVariantData>, JsonBufferAllocated {
JsonVariantData* addSlot(JsonBuffer* buffer) {
iterator it = add(buffer);
return it != end() ? &*it : 0;
}
};
} // namespace Internals
} // namespace ArduinoJson

View File

@ -11,14 +11,14 @@ namespace ArduinoJson {
inline JsonArray JsonArray::createNestedArray() {
if (!_data) return JsonArray();
JsonArray array(_data->_buffer);
JsonArray array(_buffer);
if (!array.isNull()) add(array);
return array;
}
inline JsonObject JsonArray::createNestedObject() {
if (!_data) return JsonObject();
JsonObject object(_data->_buffer);
JsonObject object(_buffer);
if (!object.isNull()) add(object);
return object;
}

View File

@ -0,0 +1,72 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "Data/ListIterator.hpp"
#include "JsonVariant.hpp"
namespace ArduinoJson {
class JsonVariantPtr {
public:
JsonVariantPtr(Internals::JsonBuffer *buffer,
Internals::JsonVariantData *data)
: _variant(buffer, data) {}
JsonVariant *operator->() {
return &_variant;
}
JsonVariant &operator*() {
return _variant;
}
private:
JsonVariant _variant;
};
class JsonArrayIterator {
typedef Internals::ListIterator<Internals::JsonVariantData> internal_iterator;
public:
JsonArrayIterator() {}
explicit JsonArrayIterator(Internals::JsonBuffer *buffer,
internal_iterator iterator)
: _iterator(iterator), _buffer(buffer) {}
JsonVariant operator*() const {
return JsonVariant(_buffer, &*_iterator);
}
JsonVariantPtr operator->() {
return JsonVariantPtr(_buffer, &*_iterator);
}
bool operator==(const JsonArrayIterator &other) const {
return _iterator == other._iterator;
}
bool operator!=(const JsonArrayIterator &other) const {
return _iterator != other._iterator;
}
JsonArrayIterator &operator++() {
++_iterator;
return *this;
}
JsonArrayIterator &operator+=(size_t distance) {
_iterator += distance;
return *this;
}
internal_iterator internal() {
return _iterator;
}
private:
internal_iterator _iterator;
Internals::JsonBuffer *_buffer;
};
} // namespace ArduinoJson

View File

@ -20,14 +20,14 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
: _array(array), _index(index) {}
FORCE_INLINE JsonArraySubscript& operator=(const JsonArraySubscript& src) {
_array.set(_index, src);
_array.set(_index, src.as<JsonVariant>());
return *this;
}
// Replaces the value
//
// operator=(const TValue&)
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
// std::string, String, JsonArray, JsonObject
template <typename T>
FORCE_INLINE JsonArraySubscript& operator=(const T& src) {
@ -60,7 +60,7 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
// Replaces the value
//
// bool set(const TValue&)
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
// std::string, String, JsonArray, JsonObject
template <typename TValue>
FORCE_INLINE bool set(const TValue& value) {

View File

@ -5,29 +5,27 @@
#pragma once
#include "./JsonObjectData.hpp"
#include "./JsonObjectIterator.hpp"
namespace ArduinoJson {
class JsonObject {
friend class JsonVariant;
typedef Internals::JsonObjectData::iterator internal_iterator;
public:
typedef Internals::JsonObjectData::iterator iterator;
typedef Internals::JsonObjectData::const_iterator const_iterator;
typedef JsonObjectIterator iterator;
JsonObject() : _data(0) {}
JsonObject(Internals::JsonObjectData* object) : _data(object) {}
JsonObject(Internals::JsonBuffer* buf)
: _data(new (buf) Internals::JsonObjectData(buf)) {}
FORCE_INLINE JsonObject() : _buffer(0), _data(0) {}
FORCE_INLINE JsonObject(Internals::JsonBuffer* buf,
Internals::JsonObjectData* object)
: _buffer(buf), _data(object) {}
FORCE_INLINE explicit JsonObject(Internals::JsonBuffer* buf)
: _buffer(buf), _data(new (buf) Internals::JsonObjectData()) {}
iterator begin() {
FORCE_INLINE iterator begin() const {
if (!_data) return iterator();
return _data->begin();
}
const_iterator begin() const {
if (!_data) return const_iterator();
return _data->begin();
return iterator(_buffer, _data->begin());
}
// Tells weither the specified key is present and associated with a value.
@ -35,42 +33,38 @@ class JsonObject {
// bool containsKey(TKey);
// TKey = const std::string&, const String&
template <typename TString>
bool containsKey(const TString& key) const {
FORCE_INLINE bool containsKey(const TString& key) const {
return containsKey_impl<const TString&>(key);
}
//
// bool containsKey(TKey);
// TKey = char*, const char*, char[], const char[], const FlashStringHelper*
template <typename TString>
bool containsKey(TString* key) const {
FORCE_INLINE bool containsKey(TString* key) const {
return containsKey_impl<TString*>(key);
}
iterator end() {
FORCE_INLINE iterator end() const {
return iterator();
}
const_iterator end() const {
return const_iterator();
}
// Creates and adds a JsonArray.
//
// JsonArray createNestedArray(TKey);
// TKey = const std::string&, const String&
template <typename TString>
JsonArray createNestedArray(const TString& key);
FORCE_INLINE JsonArray createNestedArray(const TString& key);
// JsonArray createNestedArray(TKey);
// TKey = char*, const char*, char[], const char[], const FlashStringHelper*
template <typename TString>
JsonArray createNestedArray(TString* key);
FORCE_INLINE JsonArray createNestedArray(TString* key);
// Creates and adds a JsonObject.
//
// JsonObject createNestedObject(TKey);
// TKey = const std::string&, const String&
template <typename TString>
JsonObject createNestedObject(const TString& key) {
FORCE_INLINE JsonObject createNestedObject(const TString& key) {
if (!_data) return JsonObject();
return createNestedObject_impl<const TString&>(key);
}
@ -78,7 +72,7 @@ class JsonObject {
// JsonObject createNestedObject(TKey);
// TKey = char*, const char*, char[], const char[], const FlashStringHelper*
template <typename TString>
JsonObject createNestedObject(TString* key) {
FORCE_INLINE JsonObject createNestedObject(TString* key) {
return createNestedObject_impl<TString*>(key);
}
@ -89,7 +83,7 @@ class JsonObject {
// TValue = bool, char, long, int, short, float, double,
// std::string, String, JsonArray, JsonObject
template <typename TValue, typename TString>
typename Internals::JsonVariantAs<TValue>::type get(
FORCE_INLINE typename Internals::JsonVariantAs<TValue>::type get(
const TString& key) const {
return get_impl<const TString&, TValue>(key);
}
@ -99,7 +93,8 @@ class JsonObject {
// TValue = bool, char, long, int, short, float, double,
// std::string, String, JsonArray, JsonObject
template <typename TValue, typename TString>
typename Internals::JsonVariantAs<TValue>::type get(TString* key) const {
FORCE_INLINE typename Internals::JsonVariantAs<TValue>::type get(
TString* key) const {
return get_impl<TString*, TValue>(key);
}
@ -111,7 +106,7 @@ class JsonObject {
// TValue = bool, char, long, int, short, float, double,
// std::string, String, JsonArray, JsonObject
template <typename TValue, typename TString>
bool is(const TString& key) const {
FORCE_INLINE bool is(const TString& key) const {
return is_impl<const TString&, TValue>(key);
}
//
@ -120,7 +115,7 @@ class JsonObject {
// TValue = bool, char, long, int, short, float, double,
// std::string, String, JsonArray, JsonObject
template <typename TValue, typename TString>
bool is(TString* key) const {
FORCE_INLINE bool is(TString* key) const {
return is_impl<TString*, TValue>(key);
}
@ -129,7 +124,7 @@ class JsonObject {
// JsonObjectSubscript operator[](TKey)
// TKey = const std::string&, const String&
template <typename TString>
Internals::JsonObjectSubscript<const TString&> operator[](
FORCE_INLINE Internals::JsonObjectSubscript<const TString&> operator[](
const TString& key) {
return Internals::JsonObjectSubscript<const TString&>(*this, key);
}
@ -137,7 +132,8 @@ class JsonObject {
// JsonObjectSubscript operator[](TKey)
// TKey = char*, const char*, char[], const char[N], const FlashStringHelper*
template <typename TString>
Internals::JsonObjectSubscript<TString*> operator[](TString* key) {
FORCE_INLINE Internals::JsonObjectSubscript<TString*> operator[](
TString* key) {
return Internals::JsonObjectSubscript<TString*>(*this, key);
}
@ -146,7 +142,7 @@ class JsonObject {
// const JsonObjectSubscript operator[](TKey) const;
// TKey = const std::string&, const String&
template <typename TString>
const Internals::JsonObjectSubscript<const TString&> operator[](
FORCE_INLINE const Internals::JsonObjectSubscript<const TString&> operator[](
const TString& key) const {
return Internals::JsonObjectSubscript<const TString&>(*this, key);
}
@ -154,18 +150,18 @@ class JsonObject {
// const JsonObjectSubscript operator[](TKey) const;
// TKey = const char*, const char[N], const FlashStringHelper*
template <typename TString>
const Internals::JsonObjectSubscript<TString*> operator[](
FORCE_INLINE const Internals::JsonObjectSubscript<TString*> operator[](
TString* key) const {
return Internals::JsonObjectSubscript<TString*>(*this, key);
}
bool operator==(const JsonObject& rhs) const {
FORCE_INLINE bool operator==(const JsonObject& rhs) const {
return _data == rhs._data;
}
void remove(iterator it) {
FORCE_INLINE void remove(iterator it) {
if (!_data) return;
_data->remove(it);
_data->remove(it.internal());
}
// Removes the specified key and the associated value.
@ -173,14 +169,14 @@ class JsonObject {
// void remove(TKey);
// TKey = const std::string&, const String&
template <typename TString>
void remove(const TString& key) {
FORCE_INLINE void remove(const TString& key) {
remove_impl<const TString&>(key);
}
//
// void remove(TKey);
// TKey = char*, const char*, char[], const char[], const FlashStringHelper*
template <typename TString>
void remove(TString* key) {
FORCE_INLINE void remove(TString* key) {
remove_impl<TString*>(key);
}
@ -188,10 +184,10 @@ class JsonObject {
//
// bool set(TKey, TValue);
// TKey = const std::string&, const String&
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
// std::string, String, JsonArray, JsonObject
template <typename TValue, typename TString>
bool set(const TString& key, const TValue& value) {
FORCE_INLINE bool set(const TString& key, const TValue& value) {
return set_impl<const TString&, const TValue&>(key, value);
}
//
@ -199,16 +195,16 @@ class JsonObject {
// TKey = const std::string&, const String&
// TValue = char*, const char*, const FlashStringHelper*
template <typename TValue, typename TString>
bool set(const TString& key, TValue* value) {
FORCE_INLINE bool set(const TString& key, TValue* value) {
return set_impl<const TString&, TValue*>(key, value);
}
//
// bool set(TKey, const TValue&);
// TKey = char*, const char*, const FlashStringHelper*
// TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
// TValue = bool, long, int, short, float, double, serialized, JsonVariant,
// std::string, String, JsonArray, JsonObject
template <typename TValue, typename TString>
bool set(TString* key, const TValue& value) {
FORCE_INLINE bool set(TString* key, const TValue& value) {
return set_impl<TString*, const TValue&>(key, value);
}
//
@ -216,96 +212,110 @@ class JsonObject {
// TKey = char*, const char*, const FlashStringHelper*
// TValue = char*, const char*, const FlashStringHelper*
template <typename TValue, typename TString>
bool set(TString* key, TValue* value) {
FORCE_INLINE bool set(TString* key, TValue* value) {
return set_impl<TString*, TValue*>(key, value);
}
size_t size() const {
FORCE_INLINE size_t size() const {
if (!_data) return 0;
return _data->size();
}
bool isNull() const {
FORCE_INLINE bool isNull() const {
return _data == 0;
}
template <typename Visitor>
void visit(Visitor& visitor) const {
FORCE_INLINE void visit(Visitor& visitor) const {
if (_data)
visitor.acceptObject(*this);
visitor.acceptObject(*_data);
else
return visitor.acceptNull();
visitor.acceptNull();
}
private:
template <typename TStringRef>
bool containsKey_impl(TStringRef key) const {
return findKey<TStringRef>(key) != end();
FORCE_INLINE bool containsKey_impl(TStringRef key) const {
return findKey<TStringRef>(key) != _data->end();
}
template <typename TStringRef>
JsonArray createNestedArray_impl(TStringRef key);
FORCE_INLINE JsonArray createNestedArray_impl(TStringRef key);
template <typename TStringRef>
JsonObject createNestedObject_impl(TStringRef key);
FORCE_INLINE JsonObject createNestedObject_impl(TStringRef key);
// Returns the list node that matches the specified key.
template <typename TStringRef>
iterator findKey(TStringRef key) {
iterator it;
for (it = begin(); it != end(); ++it) {
if (Internals::StringTraits<TStringRef>::equals(key, it->key)) break;
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;
}
return it;
}
template <typename TStringRef>
const_iterator findKey(TStringRef key) const {
FORCE_INLINE internal_iterator findKey(TStringRef key) const {
return const_cast<JsonObject*>(this)->findKey<TStringRef>(key);
}
template <typename TStringRef, typename TValue>
typename Internals::JsonVariantAs<TValue>::type get_impl(
FORCE_INLINE typename Internals::JsonVariantAs<TValue>::type get_impl(
TStringRef key) const {
const_iterator it = findKey<TStringRef>(key);
return it != end() ? it->value.as<TValue>()
: Internals::JsonVariantDefault<TValue>::get();
internal_iterator it = findKey<TStringRef>(key);
return it != _data->end() ? JsonVariant(_buffer, &it->value).as<TValue>()
: TValue();
}
template <typename TStringRef, typename TValue>
bool is_impl(TStringRef key) const {
const_iterator it = findKey<TStringRef>(key);
return it != end() ? it->value.is<TValue>() : false;
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;
}
template <typename TStringRef>
void remove_impl(TStringRef key) {
FORCE_INLINE void remove_impl(TStringRef key) {
if (!_data) return;
_data->remove(findKey<TStringRef>(key));
}
template <typename TStringRef, typename TValueRef>
bool set_impl(TStringRef key, TValueRef value) {
FORCE_INLINE bool set_impl(TStringRef key, TValueRef value) {
if (!_data) return false;
// ignore null key
if (Internals::StringTraits<TStringRef>::is_null(key)) return false;
if (Internals::makeString(key).is_null()) return false;
// search a matching key
iterator it = findKey<TStringRef>(key);
if (it == end()) {
internal_iterator it = findKey<TStringRef>(key);
if (it == _data->end()) {
// add the key
it = _data->add();
if (it == end()) return false;
bool key_ok =
Internals::ValueSaver<TStringRef>::save(_data->_buffer, it->key, key);
if (!key_ok) return false;
// 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;
}
// save the value
return Internals::ValueSaver<TValueRef>::save(_data->_buffer, it->value,
value);
return JsonVariant(_buffer, &it->value).set(value);
}
Internals::JsonObjectData* _data;
FORCE_INLINE bool set_key(internal_iterator& it, const char* key) {
it->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);
if (!dup) return false;
it->key = dup;
return true;
}
mutable Internals::JsonBuffer* _buffer;
mutable Internals::JsonObjectData* _data;
};
} // namespace ArduinoJson

View File

@ -5,11 +5,9 @@
#pragma once
#include "Data/List.hpp"
#include "Data/ValueSaver.hpp"
#include "JsonPair.hpp"
#include "Memory/JsonBufferAllocated.hpp"
#include "Polyfills/type_traits.hpp"
#include "Strings/StringTraits.hpp"
// Returns the size (in bytes) of an object with n elements.
// Can be very handy to determine the size of a StaticJsonBuffer.
@ -20,8 +18,13 @@
namespace ArduinoJson {
namespace Internals {
struct JsonObjectData : List<JsonPair>, JsonBufferAllocated {
explicit JsonObjectData(JsonBuffer* buf) throw() : List<JsonPair>(buf) {}
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

View File

@ -22,7 +22,7 @@ inline JsonArray JsonObject::createNestedArray(TString* key) {
template <typename TStringRef>
inline JsonArray JsonObject::createNestedArray_impl(TStringRef key) {
if (!_data) return JsonArray();
JsonArray array(_data->_buffer);
JsonArray array(_buffer);
if (!array.isNull()) set(key, array);
return array;
}
@ -30,7 +30,7 @@ inline JsonArray JsonObject::createNestedArray_impl(TStringRef key) {
template <typename TStringRef>
inline JsonObject JsonObject::createNestedObject_impl(TStringRef key) {
if (!_data) return JsonObject();
JsonObject object(_data->_buffer);
JsonObject object(_buffer);
if (!object.isNull()) set(key, object);
return object;
}

View File

@ -0,0 +1,72 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "Data/ListIterator.hpp"
#include "JsonPair.hpp"
namespace ArduinoJson {
class JsonPairPtr {
public:
JsonPairPtr(Internals::JsonBuffer *buffer, Internals::JsonPairData *data)
: _pair(buffer, data) {}
const JsonPair *operator->() const {
return &_pair;
}
const JsonPair &operator*() const {
return _pair;
}
private:
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) {}
JsonPair operator*() const {
return JsonPair(_buffer, &*_iterator);
}
JsonPairPtr operator->() {
return JsonPairPtr(_buffer, &*_iterator);
}
bool operator==(const JsonObjectIterator &other) const {
return _iterator == other._iterator;
}
bool operator!=(const JsonObjectIterator &other) const {
return _iterator != other._iterator;
}
JsonObjectIterator &operator++() {
++_iterator;
return *this;
}
JsonObjectIterator &operator+=(size_t distance) {
_iterator += distance;
return *this;
}
internal_iterator internal() {
return _iterator;
}
private:
Internals::JsonBuffer *_buffer;
internal_iterator _iterator;
};
} // namespace ArduinoJson

View File

@ -67,7 +67,8 @@ class JsonObjectSubscript
// Sets the specified value.
//
// bool set(const TValue&);
// TValue = bool, char, long, int, short, float, double, RawJson, JsonVariant,
// TValue = bool, char, long, int, short, float, double, serialized,
// JsonVariant,
// std::string, String, JsonArray, JsonObject
template <typename TValue>
FORCE_INLINE typename enable_if<!is_array<TValue>::value, bool>::type set(
@ -94,7 +95,7 @@ class JsonObjectSubscript
template <typename TImpl>
template <typename TString>
inline typename enable_if<StringTraits<TString>::has_equals,
inline typename enable_if<IsString<TString>::value,
const JsonObjectSubscript<const TString &> >::type
JsonVariantSubscripts<TImpl>::operator[](const TString &key) const {
return impl()->template as<JsonObject>()[key];
@ -102,7 +103,7 @@ inline typename enable_if<StringTraits<TString>::has_equals,
template <typename TImpl>
template <typename TString>
inline typename enable_if<StringTraits<TString>::has_equals,
inline typename enable_if<IsString<TString>::value,
JsonObjectSubscript<const TString &> >::type
JsonVariantSubscripts<TImpl>::operator[](const TString &key) {
return impl()->template as<JsonObject>()[key];
@ -110,17 +111,17 @@ inline typename enable_if<StringTraits<TString>::has_equals,
template <typename TImpl>
template <typename TString>
inline typename enable_if<StringTraits<const TString *>::has_equals,
JsonObjectSubscript<const TString *> >::type
JsonVariantSubscripts<TImpl>::operator[](const TString *key) {
inline typename enable_if<IsString<TString *>::value,
JsonObjectSubscript<TString *> >::type
JsonVariantSubscripts<TImpl>::operator[](TString *key) {
return impl()->template as<JsonObject>()[key];
}
template <typename TImpl>
template <typename TString>
inline typename enable_if<StringTraits<TString *>::has_equals,
const JsonObjectSubscript<const TString *> >::type
JsonVariantSubscripts<TImpl>::operator[](const TString *key) const {
inline typename enable_if<IsString<TString *>::value,
const JsonObjectSubscript<TString *> >::type
JsonVariantSubscripts<TImpl>::operator[](TString *key) const {
return impl()->template as<JsonObject>()[key];
}

View File

@ -8,9 +8,30 @@
namespace ArduinoJson {
// A key value pair for JsonObjectData.
struct JsonPair {
namespace Internals {
struct JsonPairData {
const char* key;
JsonVariant value;
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) {}
const char* key() const {
return _key;
}
JsonVariant value() const {
return _value;
}
private:
const char* _key;
JsonVariant _value;
};
} // namespace ArduinoJson

View File

@ -7,12 +7,13 @@
#include <stddef.h>
#include <stdint.h> // for uint8_t
#include "Data/JsonVariantContent.hpp"
#include "Data/JsonVariantDefault.hpp"
#include "Data/JsonVariantType.hpp"
#include "Data/JsonVariantData.hpp"
#include "JsonVariant.hpp"
#include "JsonVariantBase.hpp"
#include "Memory/JsonBuffer.hpp"
#include "Polyfills/type_traits.hpp"
#include "RawJson.hpp"
#include "Serialization/DynamicStringWriter.hpp"
#include "SerializedValue.hpp"
namespace ArduinoJson {
@ -29,83 +30,146 @@ class JsonObject;
// - a reference to a JsonArray or JsonObject
class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
public:
// Intenal use only
FORCE_INLINE JsonVariant(Internals::JsonBuffer *buffer,
Internals::JsonVariantData *data)
: _buffer(buffer), _data(data) {}
// Creates an uninitialized JsonVariant
JsonVariant() : _type(Internals::JSON_UNDEFINED) {}
FORCE_INLINE JsonVariant() : _buffer(0), _data(0) {}
// Create a JsonVariant containing a boolean value.
// It will be serialized as "true" or "false" in JSON.
JsonVariant(bool value) {
using namespace Internals;
_type = JSON_BOOLEAN;
_content.asInteger = static_cast<JsonUInt>(value);
// set(bool value)
FORCE_INLINE bool set(bool value) {
if (!_data) return false;
_data->setBoolean(value);
return true;
}
// Create a JsonVariant containing a floating point value.
// JsonVariant(double value);
// JsonVariant(float value);
// set(double value);
// set(float value);
template <typename T>
JsonVariant(T value,
typename Internals::enable_if<
Internals::is_floating_point<T>::value>::type * = 0) {
using namespace Internals;
_type = JSON_FLOAT;
_content.asFloat = static_cast<JsonFloat>(value);
FORCE_INLINE bool set(
T value, typename Internals::enable_if<
Internals::is_floating_point<T>::value>::type * = 0) {
if (!_data) return false;
_data->setFloat(static_cast<Internals::JsonFloat>(value));
return true;
}
// Create a JsonVariant containing an integer value.
// JsonVariant(char)
// JsonVariant(signed short)
// JsonVariant(signed int)
// JsonVariant(signed long)
// JsonVariant(signed char)
// set(char)
// set(signed short)
// set(signed int)
// set(signed long)
// set(signed char)
template <typename T>
JsonVariant(
FORCE_INLINE bool set(
T value,
typename Internals::enable_if<Internals::is_integral<T>::value &&
Internals::is_signed<T>::value>::type * =
0) {
using namespace Internals;
if (value >= 0) {
_type = JSON_POSITIVE_INTEGER;
_content.asInteger = static_cast<JsonUInt>(value);
} else {
_type = JSON_NEGATIVE_INTEGER;
_content.asInteger = ~static_cast<JsonUInt>(value) + 1;
}
if (!_data) return false;
if (value >= 0)
_data->setPostiveInteger(static_cast<Internals::JsonUInt>(value));
else
_data->setNegativeInteger(~static_cast<Internals::JsonUInt>(value) + 1);
return true;
}
// JsonVariant(unsigned short)
// JsonVariant(unsigned int)
// JsonVariant(unsigned long)
// set(unsigned short)
// set(unsigned int)
// set(unsigned long)
template <typename T>
JsonVariant(
FORCE_INLINE bool set(
T value,
typename Internals::enable_if<Internals::is_integral<T>::value &&
Internals::is_unsigned<T>::value>::type * =
0) {
using namespace Internals;
_type = JSON_POSITIVE_INTEGER;
_content.asInteger = static_cast<JsonUInt>(value);
if (!_data) return false;
_data->setPostiveInteger(static_cast<Internals::JsonUInt>(value));
return true;
}
// Create a JsonVariant containing a string.
// JsonVariant(const char*);
// JsonVariant(const signed char*);
// JsonVariant(const unsigned char*);
template <typename TChar>
JsonVariant(const TChar *value,
typename Internals::enable_if<sizeof(TChar) == 1>::type * = 0) {
_type = Internals::JSON_STRING;
_content.asString = reinterpret_cast<const char *>(value);
// set(SerializedValue<const char *>)
FORCE_INLINE bool set(Internals::SerializedValue<const char *> value) {
if (!_data) return false;
_data->setRaw(value.data(), value.size());
return true;
}
// Create a JsonVariant containing an unparsed string
JsonVariant(Internals::RawJsonString<const char *> value) {
_type = Internals::JSON_UNPARSED;
_content.asString = value;
// set(SerializedValue<std::string>)
// set(SerializedValue<String>)
// set(SerializedValue<const __FlashStringHelper*>)
template <typename T>
FORCE_INLINE bool set(
Internals::SerializedValue<T> value,
typename Internals::enable_if<
!Internals::is_same<const char *, T>::value>::type * = 0) {
if (!_data) return false;
const char *dup =
Internals::makeString(value.data(), value.size()).save(_buffer);
if (dup)
_data->setRaw(dup, value.size());
else
_data->setNull();
return true;
}
JsonVariant(JsonArray array);
JsonVariant(JsonObject object);
// set(const std::string&)
// set(const String&)
template <typename T>
FORCE_INLINE bool set(
const T &value,
typename Internals::enable_if<Internals::IsString<T>::value>::type * =
0) {
if (!_data) return false;
const char *dup = Internals::makeString(value).save(_buffer);
if (dup) {
_data->setString(dup);
return true;
} else {
_data->setNull();
return false;
}
}
// set(char*)
template <typename T>
FORCE_INLINE bool set(
T *value,
typename Internals::enable_if<Internals::IsString<T *>::value>::type * =
0) {
if (!_data) return false;
const char *dup = Internals::makeString(value).save(_buffer);
if (dup) {
_data->setString(dup);
return true;
} else {
_data->setNull();
return false;
}
}
// set(const char*);
FORCE_INLINE bool set(const char *value) {
if (!_data) return false;
_data->setString(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;
}
FORCE_INLINE bool set(const JsonArray &array);
FORCE_INLINE bool set(const Internals::JsonArraySubscript &);
FORCE_INLINE bool set(const JsonObject &object);
template <typename TString>
FORCE_INLINE bool set(const Internals::JsonObjectSubscript<TString> &);
// Get the variant as the specified type.
//
@ -119,43 +183,47 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
// unsigned int as<unsigned int>() const;
// unsigned long as<unsigned long>() const;
template <typename T>
const typename Internals::enable_if<Internals::is_integral<T>::value, T>::type
FORCE_INLINE const typename Internals::enable_if<
Internals::is_integral<T>::value, T>::type
as() const {
return variantAsInteger<T>();
return _data ? _data->asInteger<T>() : T();
}
// bool as<bool>() const
template <typename T>
const typename Internals::enable_if<Internals::is_same<T, bool>::value,
T>::type
FORCE_INLINE const typename Internals::enable_if<
Internals::is_same<T, bool>::value, T>::type
as() const {
return variantAsInteger<int>() != 0;
return _data && _data->asInteger<int>() != 0;
}
//
// double as<double>() const;
// float as<float>() const;
template <typename T>
const typename Internals::enable_if<Internals::is_floating_point<T>::value,
T>::type
FORCE_INLINE const typename Internals::enable_if<
Internals::is_floating_point<T>::value, T>::type
as() const {
return variantAsFloat<T>();
return _data ? _data->asFloat<T>() : 0;
}
//
// const char* as<const char*>() const;
// const char* as<char*>() const;
template <typename T>
typename Internals::enable_if<Internals::is_same<T, const char *>::value ||
Internals::is_same<T, char *>::value,
const char *>::type
FORCE_INLINE typename Internals::enable_if<
Internals::is_same<T, const char *>::value ||
Internals::is_same<T, char *>::value,
const char *>::type
as() const {
return variantAsString();
return _data ? _data->asString() : 0;
}
//
// std::string as<std::string>() const;
// String as<String>() const;
template <typename T>
typename Internals::enable_if<Internals::StringTraits<T>::has_append, T>::type
as() const {
const char *cstr = variantAsString();
FORCE_INLINE
typename Internals::enable_if<Internals::IsWriteableString<T>::value,
T>::type
as() const {
const char *cstr = _data ? _data->asString() : 0;
if (cstr) return T(cstr);
T s;
serializeJson(*this, s);
@ -165,7 +233,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
// JsonArray as<JsonArray>() const;
// const JsonArray as<const JsonArray>() const;
template <typename T>
typename Internals::enable_if<
FORCE_INLINE typename Internals::enable_if<
Internals::is_same<typename Internals::remove_const<T>::type,
JsonArray>::value,
JsonArray>::type
@ -174,7 +242,7 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
// JsonObject as<JsonObject>() const;
// const JsonObject as<const JsonObject>() const;
template <typename T>
typename Internals::enable_if<
FORCE_INLINE typename Internals::enable_if<
Internals::is_same<typename Internals::remove_const<T>::type,
JsonObject>::value,
T>::type
@ -182,9 +250,10 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
//
// JsonVariant as<JsonVariant> const;
template <typename T>
typename Internals::enable_if<Internals::is_same<T, JsonVariant>::value,
T>::type
as() const {
FORCE_INLINE
typename Internals::enable_if<Internals::is_same<T, JsonVariant>::value,
T>::type
as() const {
return *this;
}
@ -201,124 +270,78 @@ class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
// bool is<unsigned int>() const;
// bool is<unsigned long>() const;
template <typename T>
typename Internals::enable_if<Internals::is_integral<T>::value, bool>::type
FORCE_INLINE typename Internals::enable_if<Internals::is_integral<T>::value,
bool>::type
is() const {
return variantIsInteger();
return _data && _data->isInteger();
}
//
// bool is<double>() const;
// bool is<float>() const;
template <typename T>
typename Internals::enable_if<Internals::is_floating_point<T>::value,
bool>::type
is() const {
return variantIsFloat();
FORCE_INLINE
typename Internals::enable_if<Internals::is_floating_point<T>::value,
bool>::type
is() const {
return _data && _data->isFloat();
}
//
// bool is<bool>() const
template <typename T>
typename Internals::enable_if<Internals::is_same<T, bool>::value, bool>::type
FORCE_INLINE typename Internals::enable_if<Internals::is_same<T, bool>::value,
bool>::type
is() const {
return variantIsBoolean();
return _data && _data->isBoolean();
}
//
// bool is<const char*>() const;
// bool is<char*>() const;
template <typename T>
typename Internals::enable_if<Internals::is_same<T, const char *>::value ||
Internals::is_same<T, char *>::value,
bool>::type
FORCE_INLINE typename Internals::enable_if<
Internals::is_same<T, const char *>::value ||
Internals::is_same<T, char *>::value,
bool>::type
is() const {
return variantIsString();
return _data && _data->isString();
}
//
// bool is<JsonArray> const;
// bool is<const JsonArray> const;
template <typename T>
typename Internals::enable_if<
FORCE_INLINE typename Internals::enable_if<
Internals::is_same<typename Internals::remove_const<T>::type,
JsonArray>::value,
bool>::type
is() const {
return variantIsArray();
return _data && _data->isArray();
}
//
// bool is<JsonObject> const;
// bool is<const JsonObject> const;
template <typename T>
typename Internals::enable_if<
FORCE_INLINE typename Internals::enable_if<
Internals::is_same<typename Internals::remove_const<T>::type,
JsonObject>::value,
bool>::type
is() const {
return variantIsObject();
return _data && _data->isObject();
}
// Returns true if the variant has a value
bool isNull() const {
return _type == Internals::JSON_UNDEFINED;
FORCE_INLINE bool isNull() const {
return _data == 0 || _data->isNull();
}
template <typename Visitor>
void visit(Visitor &visitor) const {
using namespace Internals;
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_UNPARSED:
return visitor.acceptRawJson(_content.asString);
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: // JSON_UNDEFINED
return visitor.acceptNull();
}
FORCE_INLINE void visit(Visitor &visitor) const {
if (_data)
_data->visit(visitor);
else
visitor.acceptNull();
}
private:
JsonArray variantAsArray() const;
JsonObject variantAsObject() const;
const char *variantAsString() const;
template <typename T>
T variantAsFloat() const;
template <typename T>
T variantAsInteger() const;
bool variantIsBoolean() const;
bool variantIsFloat() const;
bool variantIsInteger() const;
bool variantIsArray() const {
return _type == Internals::JSON_ARRAY;
}
bool variantIsObject() const {
return _type == Internals::JSON_OBJECT;
}
bool variantIsString() const {
return _type == Internals::JSON_STRING ||
(_type == Internals::JSON_UNPARSED && _content.asString &&
!strcmp("null", _content.asString));
}
// The current type of the variant
Internals::JsonVariantType _type;
// The various alternatives for the value of the variant.
Internals::JsonVariantContent _content;
};
Internals::JsonBuffer *_buffer;
Internals::JsonVariantData *_data;
}; // namespace ArduinoJson
} // namespace ArduinoJson

View File

@ -5,8 +5,10 @@
#pragma once
#include "Data/IsVariant.hpp"
#include "Data/JsonFloat.hpp"
#include "Data/JsonInteger.hpp"
#include "Polyfills/type_traits.hpp"
#include "Strings/StringTraits.hpp"
#include "Strings/StringTypes.hpp"
namespace ArduinoJson {
class JsonArray;
@ -104,16 +106,14 @@ class JsonVariantComparisons {
}
template <typename TString>
typename enable_if<StringTraits<TString>::has_equals, bool>::type equals(
typename enable_if<IsString<TString>::value, bool>::type equals(
const TString &comparand) const {
const char *value = as<const char *>();
return StringTraits<TString>::equals(comparand, value);
return makeString(comparand).equals(as<const char *>());
}
template <typename TComparand>
typename enable_if<!IsVariant<TComparand>::value &&
!StringTraits<TComparand>::has_equals,
bool>::type
typename enable_if<
!IsVariant<TComparand>::value && !IsString<TComparand>::value, bool>::type
equals(const TComparand &comparand) const {
return as<TComparand>() == comparand;
}
@ -132,8 +132,7 @@ class JsonVariantComparisons {
if (is<JsonObject>() && right.template is<JsonObject>())
return as<JsonObject>() == right.template as<JsonObject>();
if (is<char *>() && right.template is<char *>())
return StringTraits<const char *>::equals(as<char *>(),
right.template as<char *>());
return makeString(as<char *>()).equals(right.template as<char *>());
return false;
}

View File

@ -8,8 +8,6 @@
#include "JsonArrayData.hpp"
#include "JsonObjectData.hpp"
#include "JsonVariant.hpp"
#include "Numbers/isFloat.hpp"
#include "Numbers/isInteger.hpp"
#include "Numbers/parseFloat.hpp"
#include "Numbers/parseInteger.hpp"
@ -17,22 +15,32 @@
namespace ArduinoJson {
inline JsonVariant::JsonVariant(JsonArray array) {
if (!array.isNull()) {
_type = Internals::JSON_ARRAY;
_content.asArray = array._data;
} else {
_type = Internals::JSON_UNDEFINED;
}
inline bool JsonVariant::set(const JsonArray& array) {
if (!_data) return false;
if (array._data)
_data->setArray(*array._data);
else
_data->setNull();
return true;
}
inline JsonVariant::JsonVariant(JsonObject object) {
if (!object.isNull()) {
_type = Internals::JSON_OBJECT;
_content.asObject = object._data;
} else {
_type = Internals::JSON_UNDEFINED;
}
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;
}
template <typename TString>
inline bool JsonVariant::set(
const Internals::JsonObjectSubscript<TString>& value) {
return set(value.template as<JsonVariant>());
}
template <typename T>
@ -41,7 +49,7 @@ inline typename Internals::enable_if<
JsonArray>::value,
JsonArray>::type
JsonVariant::as() const {
return variantAsArray();
return _data ? JsonArray(_buffer, _data->asArray()) : JsonArray();
}
template <typename T>
@ -50,89 +58,6 @@ inline typename Internals::enable_if<
JsonObject>::value,
T>::type
JsonVariant::as() const {
return variantAsObject();
return _data ? JsonObject(_buffer, _data->asObject()) : JsonObject();
}
inline JsonArray JsonVariant::variantAsArray() const {
if (_type == Internals::JSON_ARRAY) return _content.asArray;
return JsonArray();
}
inline JsonObject JsonVariant::variantAsObject() const {
if (_type == Internals::JSON_OBJECT) return _content.asObject;
return JsonObject();
}
template <typename T>
inline T JsonVariant::variantAsInteger() const {
using namespace Internals;
switch (_type) {
case JSON_UNDEFINED:
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_UNPARSED:
return parseInteger<T>(_content.asString);
default:
return T(_content.asFloat);
}
}
inline const char *JsonVariant::variantAsString() const {
using namespace Internals;
if (_type == JSON_UNPARSED && _content.asString &&
!strcmp("null", _content.asString))
return NULL;
if (_type == JSON_STRING || _type == JSON_UNPARSED) return _content.asString;
return NULL;
}
template <typename T>
inline T JsonVariant::variantAsFloat() const {
using namespace Internals;
switch (_type) {
case JSON_UNDEFINED:
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_UNPARSED:
return parseFloat<T>(_content.asString);
default:
return static_cast<T>(_content.asFloat);
}
}
inline bool JsonVariant::variantIsBoolean() const {
using namespace Internals;
if (_type == JSON_BOOLEAN) return true;
if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
return !strcmp(_content.asString, "true") ||
!strcmp(_content.asString, "false");
}
inline bool JsonVariant::variantIsInteger() const {
using namespace Internals;
return _type == JSON_POSITIVE_INTEGER || _type == JSON_NEGATIVE_INTEGER ||
(_type == JSON_UNPARSED && isInteger(_content.asString));
}
inline bool JsonVariant::variantIsFloat() const {
using namespace Internals;
return _type == JSON_FLOAT || _type == JSON_POSITIVE_INTEGER ||
_type == JSON_NEGATIVE_INTEGER ||
(_type == JSON_UNPARSED && isFloat(_content.asString));
}
} // namespace ArduinoJson

View File

@ -7,7 +7,7 @@
#include "Data/JsonVariantAs.hpp"
#include "Polyfills/attributes.hpp"
#include "Polyfills/type_traits.hpp"
#include "Strings/StringTraits.hpp"
#include "Strings/StringTypes.hpp"
namespace ArduinoJson {
class JsonArray;
@ -43,31 +43,30 @@ class JsonVariantSubscripts {
// TKey = const std::string&, const String&
template <typename TString>
FORCE_INLINE
typename enable_if<StringTraits<TString>::has_equals,
typename enable_if<IsString<TString>::value,
const JsonObjectSubscript<const TString &> >::type
operator[](const TString &key) const;
//
// const JsonObjectSubscript operator[](TKey) const;
// TKey = const std::string&, const String&
template <typename TString>
FORCE_INLINE typename enable_if<StringTraits<TString>::has_equals,
FORCE_INLINE typename enable_if<IsString<TString>::value,
JsonObjectSubscript<const TString &> >::type
operator[](const TString &key);
//
// JsonObjectSubscript operator[](TKey);
// TKey = const char*, const char[N], const FlashStringHelper*
template <typename TString>
FORCE_INLINE typename enable_if<StringTraits<const TString *>::has_equals,
JsonObjectSubscript<const TString *> >::type
operator[](const TString *key);
FORCE_INLINE typename enable_if<IsString<TString *>::value,
JsonObjectSubscript<TString *> >::type
operator[](TString *key);
//
// JsonObjectSubscript operator[](TKey);
// TKey = const char*, const char[N], const FlashStringHelper*
template <typename TString>
FORCE_INLINE
typename enable_if<StringTraits<TString *>::has_equals,
const JsonObjectSubscript<const TString *> >::type
operator[](const TString *key) const;
FORCE_INLINE typename enable_if<IsString<TString *>::value,
const JsonObjectSubscript<TString *> >::type
operator[](TString *key) const;
private:
const TImpl *impl() const {

View File

@ -11,12 +11,12 @@ namespace Internals {
class JsonBufferAllocated {
public:
void *operator new(size_t n, JsonBuffer *jsonBuffer) throw() {
void *operator new(size_t n, JsonBuffer *jsonBuffer) NOEXCEPT {
if (!jsonBuffer) return NULL;
return jsonBuffer->alloc(n);
}
void operator delete(void *, JsonBuffer *)throw();
void operator delete(void *, JsonBuffer *)NOEXCEPT {}
};
} // namespace Internals
} // namespace ArduinoJson

View File

@ -24,17 +24,17 @@ class MsgPackDeserializer {
_stringStorage(stringStorage),
_nestingLimit(nestingLimit) {}
DeserializationError parse(JsonVariant &variant) {
DeserializationError parse(JsonVariantData &variant) {
uint8_t code;
if (!readByte(code)) return DeserializationError::IncompleteInput;
if ((code & 0x80) == 0) {
variant = code;
variant.setInteger(code);
return DeserializationError::Ok;
}
if ((code & 0xe0) == 0xe0) {
variant = static_cast<int8_t>(code);
variant.setInteger(static_cast<int8_t>(code));
return DeserializationError::Ok;
}
@ -48,15 +48,15 @@ class MsgPackDeserializer {
switch (code) {
case 0xc0:
variant = static_cast<char *>(0);
variant.setNull();
return DeserializationError::Ok;
case 0xc2:
variant = false;
variant.setBoolean(false);
return DeserializationError::Ok;
case 0xc3:
variant = true;
variant.setBoolean(true);
return DeserializationError::Ok;
case 0xcc:
@ -171,54 +171,54 @@ class MsgPackDeserializer {
}
template <typename T>
DeserializationError readInteger(JsonVariant &variant) {
DeserializationError readInteger(JsonVariantData &variant) {
T value;
if (!readInteger(value)) return DeserializationError::IncompleteInput;
variant = value;
variant.setInteger(value);
return DeserializationError::Ok;
}
template <typename T>
typename enable_if<sizeof(T) == 4, DeserializationError>::type readFloat(
JsonVariant &variant) {
JsonVariantData &variant) {
T value;
if (!readBytes(value)) return DeserializationError::IncompleteInput;
fixEndianess(value);
variant = value;
variant.setFloat(value);
return DeserializationError::Ok;
}
template <typename T>
typename enable_if<sizeof(T) == 8, DeserializationError>::type readDouble(
JsonVariant &variant) {
JsonVariantData &variant) {
T value;
if (!readBytes(value)) return DeserializationError::IncompleteInput;
fixEndianess(value);
variant = value;
variant.setFloat(value);
return DeserializationError::Ok;
}
template <typename T>
typename enable_if<sizeof(T) == 4, DeserializationError>::type readDouble(
JsonVariant &variant) {
JsonVariantData &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 = value;
variant.setFloat(value);
return DeserializationError::Ok;
}
template <typename T>
DeserializationError readString(JsonVariant &variant) {
DeserializationError readString(JsonVariantData &variant) {
T size;
if (!readInteger(size)) return DeserializationError::IncompleteInput;
return readString(variant, size);
}
DeserializationError readString(JsonVariant &variant, size_t n) {
DeserializationError readString(JsonVariantData &variant, size_t n) {
typename remove_reference<TStringStorage>::type::String str =
_stringStorage.startString();
for (; n; --n) {
@ -228,64 +228,68 @@ class MsgPackDeserializer {
}
const char *s = str.c_str();
if (s == NULL) return DeserializationError::NoMemory;
variant = s;
variant.setString(s);
return DeserializationError::Ok;
}
template <typename TSize>
DeserializationError readArray(JsonVariant &variant) {
DeserializationError readArray(JsonVariantData &variant) {
TSize size;
if (!readInteger(size)) return DeserializationError::IncompleteInput;
return readArray(variant, size);
}
DeserializationError readArray(JsonVariant &variant, size_t n) {
JsonArray array(_buffer);
if (array.isNull()) return DeserializationError::NoMemory;
variant = array;
return readArray(array, n);
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(JsonArray array, size_t n) {
DeserializationError readArray(JsonArrayData &array, size_t n) {
if (_nestingLimit == 0) return DeserializationError::TooDeep;
--_nestingLimit;
for (; n; --n) {
JsonVariant variant;
DeserializationError err = parse(variant);
JsonVariantData *value = array.addSlot(_buffer);
if (!value) return DeserializationError::NoMemory;
DeserializationError err = parse(*value);
if (err) return err;
if (!array.add(variant)) return DeserializationError::NoMemory;
}
++_nestingLimit;
return DeserializationError::Ok;
}
template <typename TSize>
DeserializationError readObject(JsonVariant &variant) {
DeserializationError readObject(JsonVariantData &variant) {
TSize size;
if (!readInteger(size)) return DeserializationError::IncompleteInput;
return readObject(variant, size);
}
DeserializationError readObject(JsonVariant &variant, size_t n) {
JsonObject object(_buffer);
if (object.isNull()) return DeserializationError::NoMemory;
variant = object;
return readObject(object, n);
DeserializationError readObject(JsonVariantData &variant, size_t n) {
JsonObjectData *object = new (_buffer) JsonObjectData;
if (!object) return DeserializationError::NoMemory;
variant.setObject(*object);
return readObject(*object, n);
}
DeserializationError readObject(JsonObject object, size_t n) {
DeserializationError readObject(JsonObjectData &object, size_t n) {
if (_nestingLimit == 0) return DeserializationError::TooDeep;
--_nestingLimit;
for (; n; --n) {
DeserializationError err;
JsonVariant variant;
err = parse(variant);
JsonVariantData key;
DeserializationError err = parse(key);
if (err) return err;
const char *key = variant.as<char *>();
if (!key) return DeserializationError::NotSupported;
err = parse(variant);
if (!key.isString()) return DeserializationError::NotSupported;
JsonVariantData *value = object.addSlot(_buffer, key.asString());
if (!value) return DeserializationError::NoMemory;
err = parse(*value);
if (err) return err;
if (!object.set(key, variant)) return DeserializationError::NoMemory;
}
++_nestingLimit;
return DeserializationError::Ok;

View File

@ -13,10 +13,10 @@
namespace ArduinoJson {
namespace Internals {
template <typename TPrint>
template <typename TWriter>
class MsgPackSerializer {
public:
MsgPackSerializer(TPrint& output) : _output(&output), _bytesWritten(0) {}
MsgPackSerializer(TWriter& writer) : _writer(&writer), _bytesWritten(0) {}
template <typename T>
typename enable_if<sizeof(T) == 4>::type acceptFloat(T value32) {
@ -36,7 +36,7 @@ class MsgPackSerializer {
}
}
void acceptArray(const JsonArray& array) {
void acceptArray(const JsonArrayData& array) {
size_t n = array.size();
if (n < 0x10) {
writeByte(uint8_t(0x90 + array.size()));
@ -47,13 +47,13 @@ class MsgPackSerializer {
writeByte(0xDD);
writeInteger(uint32_t(n));
}
for (JsonArray::const_iterator it = array.begin(); it != array.end();
for (JsonArrayData::const_iterator it = array.begin(); it != array.end();
++it) {
it->visit(*this);
}
}
void acceptObject(const JsonObject& object) {
void acceptObject(const JsonObjectData& object) {
size_t n = object.size();
if (n < 0x10) {
writeByte(uint8_t(0x80 + n));
@ -64,7 +64,7 @@ class MsgPackSerializer {
writeByte(0xDF);
writeInteger(uint32_t(n));
}
for (JsonObject::const_iterator it = object.begin(); it != object.end();
for (JsonObjectData::const_iterator it = object.begin(); it != object.end();
++it) {
acceptString(it->key);
it->value.visit(*this);
@ -91,7 +91,9 @@ class MsgPackSerializer {
writeBytes(reinterpret_cast<const uint8_t*>(value), n);
}
void acceptRawJson(const char* /*value*/) {}
void acceptRawJson(const char* data, size_t size) {
writeBytes(reinterpret_cast<const uint8_t*>(data), size);
}
void acceptNegativeInteger(JsonUInt value) {
JsonUInt negated = JsonUInt(~value + 1);
@ -150,12 +152,11 @@ class MsgPackSerializer {
private:
void writeByte(uint8_t c) {
_output->print(char(c));
_bytesWritten++;
_bytesWritten += _writer->write(c);
}
void writeBytes(const uint8_t* c, size_t n) {
for (; n > 0; --n, ++c) writeByte(*c);
void writeBytes(const uint8_t* p, size_t n) {
_bytesWritten += _writer->write(p, n);
}
template <typename T>
@ -164,7 +165,7 @@ class MsgPackSerializer {
writeBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
}
TPrint* _output;
TWriter* _writer;
size_t _bytesWritten;
};
} // namespace Internals

View File

@ -44,28 +44,46 @@ struct FloatTraits<T, 8 /*64bits*/> {
static T positiveBinaryPowerOfTen(int index) {
static T factors[] = {
1e1, 1e2, 1e4, 1e8, 1e16, 1e32,
// workaround to support platforms with single precision literals
forge(0x4D384F03, 0xE93FF9F5), forge(0x5A827748, 0xF9301D32),
forge(0x75154FDD, 0x7F73BF3C)};
1e1,
1e2,
1e4,
1e8,
1e16,
forge(0x4693B8B5, 0xB5056E17), // 1e32
forge(0x4D384F03, 0xE93FF9F5), // 1e64
forge(0x5A827748, 0xF9301D32), // 1e128
forge(0x75154FDD, 0x7F73BF3C) // 1e256
};
return factors[index];
}
static T negativeBinaryPowerOfTen(int index) {
static T factors[] = {
1e-1, 1e-2, 1e-4, 1e-8, 1e-16, 1e-32,
// workaround to support platforms with single precision literals
forge(0x32A50FFD, 0x44F4A73D), forge(0x255BBA08, 0xCF8C979D),
forge(0x0AC80628, 0x64AC6F43)};
forge(0x3FB99999, 0x9999999A), // 1e-1
forge(0x3F847AE1, 0x47AE147B), // 1e-2
forge(0x3F1A36E2, 0xEB1C432D), // 1e-4
forge(0x3E45798E, 0xE2308C3A), // 1e-8
forge(0x3C9CD2B2, 0x97D889BC), // 1e-16
forge(0x3949F623, 0xD5A8A733), // 1e-32
forge(0x32A50FFD, 0x44F4A73D), // 1e-64
forge(0x255BBA08, 0xCF8C979D), // 1e-128
forge(0x0AC80628, 0x64AC6F43) // 1e-256
};
return factors[index];
}
static T negativeBinaryPowerOfTenPlusOne(int index) {
static T factors[] = {
1e0, 1e-1, 1e-3, 1e-7, 1e-15, 1e-31,
// workaround to support platforms with single precision literals
forge(0x32DA53FC, 0x9631D10D), forge(0x25915445, 0x81B7DEC2),
forge(0x0AFE07B2, 0x7DD78B14)};
1e0,
forge(0x3FB99999, 0x9999999A), // 1e-1
forge(0x3F50624D, 0xD2F1A9FC), // 1e-3
forge(0x3E7AD7F2, 0x9ABCAF48), // 1e-7
forge(0x3CD203AF, 0x9EE75616), // 1e-15
forge(0x398039D6, 0x65896880), // 1e-31
forge(0x32DA53FC, 0x9631D10D), // 1e-63
forge(0x25915445, 0x81B7DEC2), // 1e-127
forge(0x0AFE07B2, 0x7DD78B14) // 1e-255
};
return factors[index];
}
@ -77,6 +95,9 @@ struct FloatTraits<T, 8 /*64bits*/> {
return forge(0x7ff00000, 0x00000000);
}
// constructs a double floating point values from its binary representation
// we use this function to workaround platforms with single precision literals
// (for example, when -fsingle-precision-constant is passed to GCC)
static T forge(uint32_t msb, uint32_t lsb) {
union {
uint64_t integerBits;

View File

@ -10,7 +10,7 @@ namespace ArduinoJson {
namespace Internals {
inline bool isInteger(const char* s) {
if (!s) return false;
if (!s || !*s) return false;
if (issign(*s)) s++;
while (isdigit(*s)) s++;
return *s == '\0';

View File

@ -27,3 +27,9 @@
#define DEPRECATED(msg)
#endif
#if __cplusplus >= 201103L
#define NOEXCEPT noexcept
#else
#define NOEXCEPT throw()
#endif

View File

@ -4,6 +4,7 @@
#pragma once
#include "../../Configuration.hpp"
#include "is_same.hpp"
namespace ArduinoJson {

View File

@ -1,46 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
// A special type of data that can be used to insert pregenerated JSON portions.
template <typename T>
class RawJsonString {
public:
explicit RawJsonString(T str) : _str(str) {}
operator T() const {
return _str;
}
private:
T _str;
};
template <typename String>
struct StringTraits<RawJsonString<String>, void> {
static bool is_null(RawJsonString<String> source) {
return StringTraits<String>::is_null(static_cast<String>(source));
}
typedef RawJsonString<const char*> duplicate_t;
template <typename Buffer>
static duplicate_t duplicate(RawJsonString<String> source, Buffer* buffer) {
return duplicate_t(StringTraits<String>::duplicate(source, buffer));
}
static const bool has_append = false;
static const bool has_equals = false;
static const bool should_duplicate = StringTraits<String>::should_duplicate;
};
}
template <typename T>
inline Internals::RawJsonString<T> RawJson(T str) {
return Internals::RawJsonString<T>(str);
}
}

View File

@ -7,14 +7,14 @@
namespace ArduinoJson {
namespace Internals {
class DummyPrint {
class DummyWriter {
public:
size_t print(char) {
size_t write(uint8_t) {
return 1;
}
size_t print(const char* s) {
return strlen(s);
size_t write(const uint8_t*, size_t n) {
return n;
}
};
} // namespace Internals

View File

@ -1,35 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "../Strings/StringTraits.hpp"
namespace ArduinoJson {
namespace Internals {
// A Print implementation that allows to write in a String
template <typename TString>
class DynamicStringBuilder {
public:
DynamicStringBuilder(TString &str) : _str(str) {}
size_t print(char c) {
StringTraits<TString>::append(_str, c);
return 1;
}
size_t print(const char *s) {
size_t initialLen = _str.length();
StringTraits<TString>::append(_str, s);
return _str.length() - initialLen;
}
private:
DynamicStringBuilder &operator=(const DynamicStringBuilder &);
TString &_str;
};
} // namespace Internals
} // namespace ArduinoJson

View File

@ -0,0 +1,81 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "../Polyfills/type_traits.hpp"
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
#include <WString.h>
#endif
#if ARDUINOJSON_ENABLE_STD_STRING
#include <string>
#endif
namespace ArduinoJson {
namespace Internals {
template <typename>
struct IsWriteableString : false_type {};
// A Print implementation that allows to write in a String
template <typename TString>
class DynamicStringWriter {};
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
template <>
struct IsWriteableString<String> : true_type {};
template <>
class DynamicStringWriter<String> {
public:
DynamicStringWriter(String &str) : _str(&str) {}
size_t write(uint8_t c) {
_str->operator+=(static_cast<char>(c));
return 1;
}
size_t write(const uint8_t *s, size_t n) {
// CAUTION: Arduino String doesn't have append()
// and old version doesn't have size() either
_str->reserve(_str->length() + n);
while (n > 0) {
_str->operator+=(static_cast<char>(*s++));
n--;
}
return n;
}
private:
String *_str;
};
#endif
#if ARDUINOJSON_ENABLE_STD_STRING
template <>
struct IsWriteableString<std::string> : true_type {};
template <>
class DynamicStringWriter<std::string> {
public:
DynamicStringWriter(std::string &str) : _str(&str) {}
size_t write(uint8_t c) {
_str->operator+=(static_cast<char>(c));
return 1;
}
size_t write(const uint8_t *s, size_t n) {
_str->append(reinterpret_cast<const char *>(s), n);
return n;
}
private:
std::string *_str;
};
#endif
} // namespace Internals
} // namespace ArduinoJson

View File

@ -8,22 +8,25 @@ namespace ArduinoJson {
namespace Internals {
// A Print implementation that allows to write in a char[]
class StaticStringBuilder {
class StaticStringWriter {
public:
StaticStringBuilder(char *buf, size_t size) : end(buf + size - 1), p(buf) {
StaticStringWriter(char *buf, size_t size) : end(buf + size - 1), p(buf) {
*p = '\0';
}
size_t print(char c) {
size_t write(uint8_t c) {
if (p >= end) return 0;
*p++ = c;
*p++ = static_cast<char>(c);
*p = '\0';
return 1;
}
size_t print(const char *s) {
size_t write(const uint8_t *s, size_t n) {
char *begin = p;
while (p < end && *s) *p++ = *s++;
while (p < end && n > 0) {
*p++ = static_cast<char>(*s++);
n--;
}
*p = '\0';
return size_t(p - begin);
}

View File

@ -13,27 +13,28 @@
namespace ArduinoJson {
namespace Internals {
class StreamPrintAdapter {
class StreamWriter {
public:
explicit StreamPrintAdapter(std::ostream& os) : _os(os) {}
explicit StreamWriter(std::ostream& os) : _os(os) {}
size_t print(char c) {
size_t write(uint8_t c) {
_os << c;
return 1;
}
size_t print(const char* s) {
_os << s;
return strlen(s);
size_t write(const uint8_t* s, size_t n) {
_os.write(reinterpret_cast<const char*>(s),
static_cast<std::streamsize>(n));
return n;
}
private:
// cannot be assigned
StreamPrintAdapter& operator=(const StreamPrintAdapter&);
StreamWriter& operator=(const StreamWriter&);
std::ostream& _os;
};
}
}
} // namespace Internals
} // namespace ArduinoJson
#endif // ARDUINOJSON_ENABLE_STD_STREAM

View File

@ -4,15 +4,15 @@
#pragma once
#include "./DummyPrint.hpp"
#include "./DummyWriter.hpp"
namespace ArduinoJson {
namespace Internals {
template <template <typename> class TSerializer, typename TSource>
size_t measure(const TSource &source) {
DummyPrint dp;
TSerializer<DummyPrint> serializer(dp);
DummyWriter dp;
TSerializer<DummyWriter> serializer(dp);
source.visit(serializer);
return serializer.bytesWritten();
}

View File

@ -4,11 +4,11 @@
#pragma once
#include "./DynamicStringBuilder.hpp"
#include "./StaticStringBuilder.hpp"
#include "./DynamicStringWriter.hpp"
#include "./StaticStringWriter.hpp"
#if ARDUINOJSON_ENABLE_STD_STREAM
#include "./StreamPrintAdapter.hpp"
#include "./StreamWriter.hpp"
#endif
namespace ArduinoJson {
@ -16,7 +16,7 @@ namespace Internals {
template <template <typename> class TSerializer, typename TSource,
typename TPrint>
typename enable_if<!StringTraits<TPrint>::has_append, size_t>::type serialize(
typename enable_if<!IsWriteableString<TPrint>::value, size_t>::type serialize(
const TSource &source, TPrint &destination) {
TSerializer<TPrint> serializer(destination);
source.visit(serializer);
@ -26,29 +26,29 @@ typename enable_if<!StringTraits<TPrint>::has_append, size_t>::type serialize(
#if ARDUINOJSON_ENABLE_STD_STREAM
template <template <typename> class TSerializer, typename TSource>
size_t serialize(const TSource &source, std::ostream &os) {
StreamPrintAdapter adapter(os);
return serialize<TSerializer>(source, adapter);
StreamWriter writer(os);
return serialize<TSerializer>(source, writer);
}
#endif
template <template <typename> class TSerializer, typename TSource>
size_t serialize(const TSource &source, char *buffer, size_t bufferSize) {
StaticStringBuilder sb(buffer, bufferSize);
return serialize<TSerializer>(source, sb);
StaticStringWriter writer(buffer, bufferSize);
return serialize<TSerializer>(source, writer);
}
template <template <typename> class TSerializer, typename TSource, size_t N>
size_t serialize(const TSource &source, char (&buffer)[N]) {
StaticStringBuilder sb(buffer, N);
return serialize<TSerializer>(source, sb);
StaticStringWriter writer(buffer, N);
return serialize<TSerializer>(source, writer);
}
template <template <typename> class TSerializer, typename TSource,
typename TString>
typename enable_if<StringTraits<TString>::has_append, size_t>::type serialize(
typename enable_if<IsWriteableString<TString>::value, size_t>::type serialize(
const TSource &source, TString &str) {
DynamicStringBuilder<TString> sb(str);
return serialize<TSerializer>(source, sb);
DynamicStringWriter<TString> writer(str);
return serialize<TSerializer>(source, writer);
}
} // namespace Internals

View File

@ -0,0 +1,70 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "Strings/StringTypes.hpp"
namespace ArduinoJson {
namespace Internals {
// A special type of data that can be used to insert pregenerated JSON portions.
template <typename T>
class SerializedValue {
public:
explicit SerializedValue(T str) : _str(str) {}
operator T() const {
return _str;
}
const char* data() const {
return _str.c_str();
}
size_t size() const {
// CAUTION: the old Arduino String doesn't have size()
return _str.length();
}
private:
T _str;
};
template <typename TChar>
class SerializedValue<TChar*> {
public:
explicit SerializedValue(TChar* p, size_t n) : _data(p), _size(n) {}
operator TChar*() const {
return _data;
}
TChar* data() const {
return _data;
}
size_t size() const {
return _size;
}
private:
TChar* _data;
size_t _size;
};
} // namespace Internals
template <typename T>
inline Internals::SerializedValue<T> serialized(T str) {
return Internals::SerializedValue<T>(str);
}
template <typename TChar>
inline Internals::SerializedValue<TChar*> serialized(TChar* p) {
return Internals::SerializedValue<TChar*>(p, Internals::makeString(p).size());
}
template <typename TChar>
inline Internals::SerializedValue<TChar*> serialized(TChar* p, size_t n) {
return Internals::SerializedValue<TChar*>(p, n);
}
} // namespace ArduinoJson

View File

@ -9,11 +9,8 @@
namespace ArduinoJson {
template <size_t CAPACITY = sizeof(JsonVariant)>
template <size_t CAPACITY>
class StaticJsonDocument {
Internals::StaticJsonBuffer<CAPACITY> _buffer;
JsonVariant _root;
public:
uint8_t nestingLimit;
@ -25,12 +22,12 @@ class StaticJsonDocument {
template <typename T>
bool is() const {
return _root.is<T>();
return getVariant().template is<T>();
}
template <typename T>
typename Internals::JsonVariantAs<T>::type as() const {
return _root.as<T>();
return getVariant().template as<T>();
}
// JsonObject to<JsonObject>()
@ -40,7 +37,7 @@ class StaticJsonDocument {
to() {
clear();
JsonObject object(&_buffer);
_root = object;
getVariant().set(object);
return object;
}
@ -51,22 +48,32 @@ class StaticJsonDocument {
to() {
clear();
JsonArray array(&_buffer);
_root = array;
getVariant().set(array);
return array;
}
// JsonVariant to<JsonVariant>()
template <typename T>
typename Internals::enable_if<Internals::is_same<T, JsonVariant>::value,
T&>::type
JsonVariant>::type
to() {
clear();
return _root;
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;
}
void clear() {
_buffer.clear();
_root = JsonVariant();
_rootData.setNull();
}
size_t memoryUsage() const {
@ -75,8 +82,16 @@ class StaticJsonDocument {
template <typename Visitor>
void visit(Visitor& visitor) const {
return _root.visit(visitor);
return getVariant().visit(visitor);
}
private:
JsonVariant getVariant() const {
return JsonVariant(&_buffer, &_rootData);
}
mutable Internals::StaticJsonBuffer<CAPACITY> _buffer;
mutable Internals::JsonVariantData _rootData;
};
} // namespace ArduinoJson

View File

@ -0,0 +1,60 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include <WString.h>
namespace ArduinoJson {
namespace Internals {
class ArduinoString {
public:
ArduinoString(const ::String& str) : _str(&str) {}
template <typename Buffer>
const char* save(Buffer* buffer) const {
if (is_null()) return NULL;
size_t n = _str->length() + 1;
void* dup = buffer->alloc(n);
if (dup != NULL) memcpy(dup, _str->c_str(), n);
return static_cast<const char*>(dup);
}
bool is_null() const {
// Arduino's String::c_str() can return NULL
return !_str->c_str();
}
bool equals(const char* expected) const {
// Arduino's String::c_str() can return NULL
const char* actual = _str->c_str();
if (!actual || !expected) return actual == expected;
return 0 == strcmp(actual, expected);
}
const char* data() const {
return _str->c_str();
}
size_t size() const {
return _str->length();
}
private:
const ::String* _str;
};
template <>
struct IsString< ::String> : true_type {};
template <>
struct IsString< ::StringSumHelper> : true_type {};
inline ArduinoString makeString(const ::String& str) {
return ArduinoString(str);
}
} // namespace Internals
} // namespace ArduinoJson

View File

@ -1,44 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
template <typename TChar>
struct CharPointerTraits {
static bool equals(const TChar* str, const char* expected) {
const char* actual = reinterpret_cast<const char*>(str);
if (!actual || !expected) return actual == expected;
return strcmp(actual, expected) == 0;
}
static bool is_null(const TChar* str) {
return !str;
}
typedef const char* duplicate_t;
template <typename Buffer>
static duplicate_t duplicate(const TChar* str, Buffer* buffer) {
if (!str) return NULL;
size_t size = strlen(reinterpret_cast<const char*>(str)) + 1;
void* dup = buffer->alloc(size);
if (dup != NULL) memcpy(dup, str, size);
return static_cast<duplicate_t>(dup);
}
static const bool has_append = false;
static const bool has_equals = true;
static const bool should_duplicate = !is_const<TChar>::value;
};
// char*, unsigned char*, signed char*
// const char*, const unsigned char*, const signed char*
template <typename TChar>
struct StringTraits<TChar*, typename enable_if<sizeof(TChar) == 1>::type>
: CharPointerTraits<TChar> {};
} // namespace Internals
} // namespace ArduinoJson

View File

@ -0,0 +1,47 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
class FixedSizeFlashString {
public:
FixedSizeFlashString(const __FlashStringHelper* str, size_t sz)
: _str(str), _size(sz) {}
bool equals(const char* expected) const {
const char* actual = reinterpret_cast<const char*>(_str);
if (!actual || !expected) return actual == expected;
return strncmp_P(expected, actual, _size) == 0;
}
bool is_null() const {
return !_str;
}
template <typename Buffer>
const char* save(Buffer* buffer) const {
if (!_str) return NULL;
void* dup = buffer->alloc(_size);
if (dup != NULL) memcpy_P(dup, (const char*)_str, _size);
return static_cast<const char*>(dup);
}
size_t size() const {
return strlen_P(reinterpret_cast<const char*>(_str));
}
private:
const __FlashStringHelper* _str;
size_t _size;
};
inline FixedSizeFlashString makeString(const __FlashStringHelper* str,
size_t sz) {
return FixedSizeFlashString(str, sz);
}
} // namespace Internals
} // namespace ArduinoJson

View File

@ -0,0 +1,50 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include <string.h> // strcmp
namespace ArduinoJson {
namespace Internals {
class FixedSizeRamString {
public:
FixedSizeRamString(const char* str, size_t n) : _str(str), _size(n) {}
bool equals(const char* expected) const {
const char* actual = reinterpret_cast<const char*>(_str);
if (!actual || !expected) return actual == expected;
return strcmp(actual, expected) == 0;
}
bool is_null() const {
return !_str;
}
template <typename Buffer>
const char* save(Buffer* buffer) const {
if (!_str) return NULL;
void* dup = buffer->alloc(_size);
if (!dup) return NULL;
memcpy(dup, _str, _size);
return static_cast<const char*>(dup);
}
size_t size() const {
return strlen(reinterpret_cast<const char*>(_str));
}
private:
const char* _str;
size_t _size;
};
template <typename TChar>
inline FixedSizeRamString makeString(const TChar* str, size_t size) {
return FixedSizeRamString(reinterpret_cast<const char*>(str), size);
}
} // namespace Internals
} // namespace ArduinoJson

View File

@ -1,41 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#if ARDUINOJSON_ENABLE_PROGMEM
namespace ArduinoJson {
namespace Internals {
template <>
struct StringTraits<const __FlashStringHelper*, void> {
static bool equals(const __FlashStringHelper* str, const char* expected) {
const char* actual = reinterpret_cast<const char*>(str);
if (!actual || !expected) return actual == expected;
return strcmp_P(expected, actual) == 0;
}
static bool is_null(const __FlashStringHelper* str) {
return !str;
}
typedef const char* duplicate_t;
template <typename Buffer>
static duplicate_t duplicate(const __FlashStringHelper* str, Buffer* buffer) {
if (!str) return NULL;
size_t size = strlen_P((const char*)str) + 1;
void* dup = buffer->alloc(size);
if (dup != NULL) memcpy_P(dup, (const char*)str, size);
return static_cast<duplicate_t>(dup);
}
static const bool has_append = false;
static const bool has_equals = true;
static const bool should_duplicate = true;
};
} // namespace Internals
} // namespace ArduinoJson
#endif

View File

@ -1,73 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#if ARDUINOJSON_ENABLE_STD_STRING || ARDUINOJSON_ENABLE_ARDUINO_STRING
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
#include <WString.h>
#endif
#if ARDUINOJSON_ENABLE_STD_STRING
#include <string>
#endif
namespace ArduinoJson {
namespace Internals {
template <typename TString>
struct StdStringTraits {
typedef const char* duplicate_t;
template <typename Buffer>
static duplicate_t duplicate(const TString& str, Buffer* buffer) {
if (!str.c_str()) return NULL; // <- Arduino string can return NULL
size_t size = str.length() + 1;
void* dup = buffer->alloc(size);
if (dup != NULL) memcpy(dup, str.c_str(), size);
return static_cast<duplicate_t>(dup);
}
static bool is_null(const TString& str) {
// Arduino's String::c_str() can return NULL
return !str.c_str();
}
static bool equals(const TString& str, const char* expected) {
// Arduino's String::c_str() can return NULL
const char* actual = str.c_str();
if (!actual || !expected) return actual == expected;
return 0 == strcmp(actual, expected);
}
static void append(TString& str, char c) {
str += c;
}
static void append(TString& str, const char* s) {
str += s;
}
static const bool has_append = true;
static const bool has_equals = true;
static const bool should_duplicate = true;
};
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
template <>
struct StringTraits<String, void> : StdStringTraits<String> {};
template <>
struct StringTraits<StringSumHelper, void> : StdStringTraits<StringSumHelper> {
};
#endif
#if ARDUINOJSON_ENABLE_STD_STRING
template <>
struct StringTraits<std::string, void> : StdStringTraits<std::string> {};
#endif
} // namespace Internals
} // namespace ArduinoJson
#endif

View File

@ -0,0 +1,53 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include <string>
namespace ArduinoJson {
namespace Internals {
class StlString {
public:
StlString(const std::string& str) : _str(&str) {}
template <typename Buffer>
const char* save(Buffer* buffer) const {
size_t n = _str->length() + 1;
void* dup = buffer->alloc(n);
if (dup != NULL) memcpy(dup, _str->c_str(), n);
return static_cast<const char*>(dup);
}
bool is_null() const {
return false;
}
bool equals(const char* expected) const {
if (!expected) return false;
return *_str == expected;
}
const char* data() const {
return _str->data();
}
size_t size() const {
return _str->size();
}
private:
const std::string* _str;
};
template <>
struct IsString<std::string> : true_type {};
inline StlString makeString(const std::string& str) {
return StlString(str);
}
} // namespace Internals
} // namespace ArduinoJson

View File

@ -1,30 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include <string.h>
#include "../Configuration.hpp"
#include "../Polyfills/type_traits.hpp"
namespace ArduinoJson {
namespace Internals {
template <typename TString, typename Enable = void>
struct StringTraits {
static const bool has_append = false;
static const bool has_equals = false;
};
template <typename TString>
struct StringTraits<const TString, void> : StringTraits<TString> {};
template <typename TString>
struct StringTraits<TString&, void> : StringTraits<TString> {};
} // namespace Internals
} // namespace ArduinoJson
#include "CharPointer.hpp"
#include "FlashString.hpp"
#include "StdString.hpp"

View File

@ -0,0 +1,36 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "../Polyfills/type_traits.hpp"
namespace ArduinoJson {
namespace Internals {
template <typename>
struct IsString : false_type {};
template <typename T>
struct IsString<const T> : IsString<T> {};
template <typename T>
struct IsString<T&> : IsString<T> {};
} // namespace Internals
} // namespace ArduinoJson
#include "FixedSizeRamString.hpp"
#include "ZeroTerminatedRamString.hpp"
#if ARDUINOJSON_ENABLE_STD_STRING
#include "StlString.hpp"
#endif
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
#include "ArduinoString.hpp"
#endif
#if ARDUINOJSON_ENABLE_PROGMEM
#include "FixedSizeFlashString.hpp"
#include "ZeroTerminatedFlashString.hpp"
#endif

View File

@ -0,0 +1,48 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
class ZeroTerminatedFlashString {
public:
ZeroTerminatedFlashString(const __FlashStringHelper* str) : _str(str) {}
bool equals(const char* expected) const {
const char* actual = reinterpret_cast<const char*>(_str);
if (!actual || !expected) return actual == expected;
return strcmp_P(expected, actual) == 0;
}
bool is_null() const {
return !_str;
}
template <typename Buffer>
const char* save(Buffer* buffer) const {
if (!_str) return NULL;
size_t n = size() + 1; // copy the terminator
void* dup = buffer->alloc(n);
if (dup != NULL) memcpy_P(dup, (const char*)_str, n);
return static_cast<const char*>(dup);
}
size_t size() const {
return strlen_P(reinterpret_cast<const char*>(_str));
}
private:
const __FlashStringHelper* _str;
};
inline ZeroTerminatedFlashString makeString(const __FlashStringHelper* str) {
return ZeroTerminatedFlashString(str);
}
template <>
struct IsString<const __FlashStringHelper*> : true_type {};
} // namespace Internals
} // namespace ArduinoJson

View File

@ -0,0 +1,53 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
class ZeroTerminatedRamString {
public:
ZeroTerminatedRamString(const char* str) : _str(str) {}
bool equals(const char* expected) const {
const char* actual = reinterpret_cast<const char*>(_str);
if (!actual || !expected) return actual == expected;
return strcmp(actual, expected) == 0;
}
bool is_null() const {
return !_str;
}
template <typename Buffer>
const char* save(Buffer* buffer) const {
if (!_str) return NULL;
size_t n = size() + 1;
void* dup = buffer->alloc(n);
if (!dup) return NULL;
memcpy(dup, _str, n);
return static_cast<const char*>(dup);
}
size_t size() const {
return strlen(reinterpret_cast<const char*>(_str));
}
private:
const char* _str;
};
template <typename TChar>
inline ZeroTerminatedRamString makeString(const TChar* str) {
return ZeroTerminatedRamString(reinterpret_cast<const char*>(str));
}
template <typename TChar>
struct IsString<TChar*> {
static const bool value = sizeof(TChar) == 1;
};
} // namespace Internals
} // namespace ArduinoJson

View File

@ -4,7 +4,7 @@
#pragma once
#define ARDUINOJSON_VERSION "6.1.0-beta"
#define ARDUINOJSON_VERSION "6.3.0-beta"
#define ARDUINOJSON_VERSION_MAJOR 6
#define ARDUINOJSON_VERSION_MINOR 1
#define ARDUINOJSON_VERSION_MINOR 3
#define ARDUINOJSON_VERSION_REVISION 0

View File

@ -38,7 +38,9 @@ endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
add_compile_options(
-Wstrict-null-sentinel
-Wno-vla # Allow VLA in tests
)
add_definitions(-DHAS_VARIABLE_LENGTH_ARRAY)
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.5)
add_compile_options(-Wlogical-op) # the flag exists in 4.4 but is buggy
@ -53,6 +55,11 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(
-Wc++11-compat
-Wdeprecated-register
-Wno-vla-extension # Allow VLA in tests
)
add_definitions(
-DHAS_VARIABLE_LENGTH_ARRAY
-DSUBSCRIPT_CONFLICTS_WITH_BUILTIN_OPERATOR
)
endif()
@ -67,13 +74,14 @@ endif()
add_subdirectory(DynamicJsonBuffer)
add_subdirectory(IntegrationTests)
add_subdirectory(JsonArray)
add_subdirectory(JsonObject)
add_subdirectory(JsonDeserializer)
add_subdirectory(JsonDocument)
add_subdirectory(JsonObject)
add_subdirectory(JsonSerializer)
add_subdirectory(JsonVariant)
add_subdirectory(JsonWriter)
add_subdirectory(Misc)
add_subdirectory(MsgPackDeserializer)
add_subdirectory(MsgPackSerializer)
add_subdirectory(Polyfills)
add_subdirectory(Numbers)
add_subdirectory(StaticJsonBuffer)

View File

@ -4,6 +4,7 @@
add_executable(IntegrationTests
gbathree.cpp
issue772.cpp
round_trip.cpp
)

View File

@ -0,0 +1,27 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
// https://github.com/bblanchon/ArduinoJson/issues/772
TEST_CASE("Issue772") {
DynamicJsonDocument doc1, doc2;
DeserializationError err;
std::string data =
"{\"state\":{\"reported\":{\"timestamp\":\"2018-07-02T09:40:12Z\","
"\"mac\":\"2C3AE84FC076\",\"firmwareVersion\":\"v0.2.7-5-gf4d4d78\","
"\"visibleLight\":261,\"infraRed\":255,\"ultraViolet\":0.02,"
"\"Temperature\":26.63,\"Pressure\":101145.7,\"Humidity\":54.79883,"
"\"Vbat\":4.171261,\"soilMoisture\":0,\"ActB\":0}}}";
err = deserializeJson(doc1, data);
REQUIRE(err == DeserializationError::Ok);
data = "";
serializeMsgPack(doc1, data);
err = deserializeMsgPack(doc2, data);
REQUIRE(err == DeserializationError::Ok);
}

View File

@ -4,16 +4,17 @@
add_executable(JsonArrayTests
add.cpp
basics.cpp
copyFrom.cpp
copyTo.cpp
invalid.cpp
createNested.cpp
isNull.cpp
iterator.cpp
remove.cpp
set.cpp
size.cpp
std_string.cpp
subscript.cpp
undefined.cpp
)
target_link_libraries(JsonArrayTests catch)

View File

@ -7,57 +7,69 @@
TEST_CASE("JsonArray::add()") {
DynamicJsonDocument doc;
JsonArray _array = doc.to<JsonArray>();
JsonArray array = doc.to<JsonArray>();
SECTION("int") {
_array.add(123);
REQUIRE(123 == _array[0].as<int>());
REQUIRE(_array[0].is<int>());
REQUIRE(_array[0].is<double>());
array.add(123);
REQUIRE(123 == array[0].as<int>());
REQUIRE(array[0].is<int>());
REQUIRE(array[0].is<double>());
}
SECTION("double") {
_array.add(123.45);
REQUIRE(123.45 == _array[0].as<double>());
REQUIRE(_array[0].is<double>());
REQUIRE_FALSE(_array[0].is<bool>());
array.add(123.45);
REQUIRE(123.45 == array[0].as<double>());
REQUIRE(array[0].is<double>());
REQUIRE_FALSE(array[0].is<bool>());
}
SECTION("bool") {
_array.add(true);
REQUIRE(true == _array[0].as<bool>());
REQUIRE(_array[0].is<bool>());
REQUIRE_FALSE(_array[0].is<int>());
array.add(true);
REQUIRE(true == array[0].as<bool>());
REQUIRE(array[0].is<bool>());
REQUIRE_FALSE(array[0].is<int>());
}
SECTION("const char*") {
const char* str = "hello";
_array.add(str);
REQUIRE(str == _array[0].as<std::string>());
REQUIRE(_array[0].is<const char*>());
REQUIRE_FALSE(_array[0].is<int>());
array.add(str);
REQUIRE(str == array[0].as<std::string>());
REQUIRE(array[0].is<const char*>());
REQUIRE_FALSE(array[0].is<int>());
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("vla") {
int i = 16;
char vla[i];
strcpy(vla, "world");
array.add(vla);
REQUIRE(std::string("world") == array[0]);
}
#endif
SECTION("nested array") {
DynamicJsonDocument doc2;
JsonArray arr = doc2.to<JsonArray>();
_array.add(arr);
array.add(arr);
REQUIRE(arr == _array[0].as<JsonArray>());
REQUIRE(_array[0].is<JsonArray>());
REQUIRE_FALSE(_array[0].is<int>());
REQUIRE(arr == array[0].as<JsonArray>());
REQUIRE(array[0].is<JsonArray>());
REQUIRE_FALSE(array[0].is<int>());
}
SECTION("nested object") {
DynamicJsonDocument doc2;
JsonObject obj = doc2.to<JsonObject>();
_array.add(obj);
array.add(obj);
REQUIRE(obj == _array[0].as<JsonObject>());
REQUIRE(_array[0].is<JsonObject>());
REQUIRE_FALSE(_array[0].is<int>());
REQUIRE(obj == array[0].as<JsonObject>());
REQUIRE(array[0].is<JsonObject>());
REQUIRE_FALSE(array[0].is<int>());
}
SECTION("array subscript") {
@ -66,9 +78,9 @@ TEST_CASE("JsonArray::add()") {
JsonArray arr = doc2.to<JsonArray>();
arr.add(str);
_array.add(arr[0]);
array.add(arr[0]);
REQUIRE(str == _array[0]);
REQUIRE(str == array[0]);
}
SECTION("object subscript") {
@ -77,37 +89,49 @@ TEST_CASE("JsonArray::add()") {
JsonObject obj = doc2.to<JsonObject>();
obj["x"] = str;
_array.add(obj["x"]);
array.add(obj["x"]);
REQUIRE(str == _array[0]);
REQUIRE(str == array[0]);
}
SECTION("should not duplicate const char*") {
_array.add("world");
array.add("world");
const size_t expectedSize = JSON_ARRAY_SIZE(1);
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate char*") {
_array.add(const_cast<char*>("world"));
array.add(const_cast<char*>("world"));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate std::string") {
_array.add(std::string("world"));
array.add(std::string("world"));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should not duplicate RawJson(const char*)") {
_array.add(RawJson("{}"));
SECTION("should not duplicate serialized(const char*)") {
array.add(serialized("{}"));
const size_t expectedSize = JSON_ARRAY_SIZE(1);
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate RawJson(char*)") {
_array.add(RawJson(const_cast<char*>("{}")));
SECTION("should duplicate serialized(char*)") {
array.add(serialized(const_cast<char*>("{}")));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 2;
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate serialized(std::string)") {
array.add(serialized(std::string("{}")));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 2;
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate serialized(std::string)") {
array.add(serialized(std::string("\0XX", 3)));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 3;
REQUIRE(expectedSize == doc.memoryUsage());
}

View File

@ -9,14 +9,6 @@ TEST_CASE("JsonArray basics") {
DynamicJsonDocument doc;
JsonArray array = doc.to<JsonArray>();
SECTION("isNull()") {
REQUIRE(array.isNull() == false);
}
SECTION("InitialSizeIsZero") {
REQUIRE(0U == array.size());
}
SECTION("CreateNestedArray") {
JsonArray arr = array.createNestedArray();
REQUIRE(arr == array[0].as<JsonArray>());

25
test/JsonArray/isNull.cpp Normal file
View File

@ -0,0 +1,25 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonArray::isNull()") {
SECTION("returns true for undefined JsonArray") {
JsonArray array;
REQUIRE(array.isNull() == true);
}
SECTION("returns false when allocation succeeds") {
StaticJsonDocument<JSON_ARRAY_SIZE(0)> doc;
JsonArray array = doc.to<JsonArray>();
REQUIRE(array.isNull() == false);
}
SECTION("returns true when allocation fails") {
StaticJsonDocument<1> doc;
JsonArray array = doc.to<JsonArray>();
REQUIRE(array.isNull() == true);
}
}

View File

@ -30,8 +30,4 @@ TEST_CASE("JsonArray::begin()/end()") {
SECTION("Mutable") {
run_iterator_test<JsonArray::iterator>();
}
SECTION("Const") {
run_iterator_test<JsonArray::const_iterator>();
}
}

View File

@ -9,57 +9,70 @@ using namespace Catch::Matchers;
TEST_CASE("JsonArray::set()") {
DynamicJsonDocument doc;
JsonArray _array = doc.to<JsonArray>();
_array.add(0);
JsonArray array = doc.to<JsonArray>();
array.add(0);
SECTION("int") {
_array.set(0, 123);
REQUIRE(123 == _array[0].as<int>());
REQUIRE(_array[0].is<int>());
REQUIRE_FALSE(_array[0].is<bool>());
array.set(0, 123);
REQUIRE(123 == array[0].as<int>());
REQUIRE(array[0].is<int>());
REQUIRE_FALSE(array[0].is<bool>());
}
SECTION("double") {
_array.set(0, 123.45);
REQUIRE(123.45 == _array[0].as<double>());
REQUIRE(_array[0].is<double>());
REQUIRE_FALSE(_array[0].is<int>());
array.set(0, 123.45);
REQUIRE(123.45 == array[0].as<double>());
REQUIRE(array[0].is<double>());
REQUIRE_FALSE(array[0].is<int>());
}
SECTION("bool") {
_array.set(0, true);
REQUIRE(true == _array[0].as<bool>());
REQUIRE(_array[0].is<bool>());
REQUIRE_FALSE(_array[0].is<int>());
array.set(0, true);
REQUIRE(true == array[0].as<bool>());
REQUIRE(array[0].is<bool>());
REQUIRE_FALSE(array[0].is<int>());
}
SECTION("const char*") {
_array.set(0, "hello");
REQUIRE_THAT(_array[0].as<const char*>(), Equals("hello"));
REQUIRE(_array[0].is<const char*>());
REQUIRE_FALSE(_array[0].is<int>());
array.set(0, "hello");
REQUIRE_THAT(array[0].as<const char*>(), Equals("hello"));
REQUIRE(array[0].is<const char*>());
REQUIRE_FALSE(array[0].is<int>());
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("set()") {
int i = 16;
char vla[i];
strcpy(vla, "world");
array.add("hello");
array.set(0, vla);
REQUIRE(std::string("world") == array[0]);
}
#endif
SECTION("nested array") {
DynamicJsonDocument doc2;
JsonArray arr = doc2.to<JsonArray>();
_array.set(0, arr);
array.set(0, arr);
REQUIRE(arr == _array[0].as<JsonArray>());
REQUIRE(_array[0].is<JsonArray>());
REQUIRE_FALSE(_array[0].is<int>());
REQUIRE(arr == array[0].as<JsonArray>());
REQUIRE(array[0].is<JsonArray>());
REQUIRE_FALSE(array[0].is<int>());
}
SECTION("nested object") {
DynamicJsonDocument doc2;
JsonObject obj = doc2.to<JsonObject>();
_array.set(0, obj);
array.set(0, obj);
REQUIRE(obj == _array[0].as<JsonObject>());
REQUIRE(_array[0].is<JsonObject>());
REQUIRE_FALSE(_array[0].is<int>());
REQUIRE(obj == array[0].as<JsonObject>());
REQUIRE(array[0].is<JsonObject>());
REQUIRE_FALSE(array[0].is<int>());
}
SECTION("array subscript") {
@ -67,9 +80,9 @@ TEST_CASE("JsonArray::set()") {
JsonArray arr = doc2.to<JsonArray>();
arr.add("hello");
_array.set(0, arr[0]);
array.set(0, arr[0]);
REQUIRE_THAT(_array[0].as<char*>(), Equals("hello"));
REQUIRE_THAT(array[0].as<char*>(), Equals("hello"));
}
SECTION("object subscript") {
@ -77,25 +90,25 @@ TEST_CASE("JsonArray::set()") {
JsonObject obj = doc2.to<JsonObject>();
obj["x"] = "hello";
_array.set(0, obj["x"]);
array.set(0, obj["x"]);
REQUIRE_THAT(_array[0].as<char*>(), Equals("hello"));
REQUIRE_THAT(array[0].as<char*>(), Equals("hello"));
}
SECTION("should not duplicate const char*") {
_array.set(0, "world");
array.set(0, "world");
const size_t expectedSize = JSON_ARRAY_SIZE(1);
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate char*") {
_array.set(0, const_cast<char*>("world"));
array.set(0, const_cast<char*>("world"));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate std::string") {
_array.set(0, std::string("world"));
array.set(0, std::string("world"));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
REQUIRE(expectedSize == doc.memoryUsage());
}

View File

@ -7,29 +7,33 @@
TEST_CASE("JsonArray::size()") {
DynamicJsonDocument doc;
JsonArray _array = doc.to<JsonArray>();
JsonArray array = doc.to<JsonArray>();
SECTION("InitialSizeIsZero") {
REQUIRE(0U == array.size());
}
SECTION("increases after add()") {
_array.add("hello");
REQUIRE(1U == _array.size());
array.add("hello");
REQUIRE(1U == array.size());
_array.add("world");
REQUIRE(2U == _array.size());
array.add("world");
REQUIRE(2U == array.size());
}
SECTION("remains the same after set()") {
_array.add("hello");
REQUIRE(1U == _array.size());
array.add("hello");
REQUIRE(1U == array.size());
_array.set(0, "hello");
REQUIRE(1U == _array.size());
array.set(0, "hello");
REQUIRE(1U == array.size());
}
SECTION("remains the same after assigment") {
_array.add("hello");
REQUIRE(1U == _array.size());
array.add("hello");
REQUIRE(1U == array.size());
_array[0] = "hello";
REQUIRE(1U == _array.size());
array[0] = "hello";
REQUIRE(1U == array.size());
}
}

View File

@ -8,85 +8,85 @@
TEST_CASE("JsonArray::operator[]") {
DynamicJsonDocument doc;
JsonArray _array = doc.to<JsonArray>();
_array.add(0);
JsonArray array = doc.to<JsonArray>();
array.add(0);
SECTION("int") {
_array[0] = 123;
REQUIRE(123 == _array[0].as<int>());
REQUIRE(true == _array[0].is<int>());
REQUIRE(false == _array[0].is<bool>());
array[0] = 123;
REQUIRE(123 == array[0].as<int>());
REQUIRE(true == array[0].is<int>());
REQUIRE(false == array[0].is<bool>());
}
#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
SECTION("long long") {
_array[0] = 9223372036854775807;
REQUIRE(9223372036854775807 == _array[0].as<long long>());
REQUIRE(true == _array[0].is<int>());
REQUIRE(false == _array[0].is<bool>());
array[0] = 9223372036854775807;
REQUIRE(9223372036854775807 == array[0].as<long long>());
REQUIRE(true == array[0].is<int>());
REQUIRE(false == array[0].is<bool>());
}
#endif
SECTION("double") {
_array[0] = 123.45;
REQUIRE(123.45 == _array[0].as<double>());
REQUIRE(true == _array[0].is<double>());
REQUIRE(false == _array[0].is<int>());
array[0] = 123.45;
REQUIRE(123.45 == array[0].as<double>());
REQUIRE(true == array[0].is<double>());
REQUIRE(false == array[0].is<int>());
}
SECTION("bool") {
_array[0] = true;
REQUIRE(true == _array[0].as<bool>());
REQUIRE(true == _array[0].is<bool>());
REQUIRE(false == _array[0].is<int>());
array[0] = true;
REQUIRE(true == array[0].as<bool>());
REQUIRE(true == array[0].is<bool>());
REQUIRE(false == array[0].is<int>());
}
SECTION("const char*") {
const char* str = "hello";
_array[0] = str;
REQUIRE(str == _array[0].as<const char*>());
REQUIRE(str == _array[0].as<char*>()); // <- short hand
REQUIRE(true == _array[0].is<const char*>());
REQUIRE(false == _array[0].is<int>());
array[0] = str;
REQUIRE(str == array[0].as<const char*>());
REQUIRE(str == array[0].as<char*>()); // <- short hand
REQUIRE(true == array[0].is<const char*>());
REQUIRE(false == array[0].is<int>());
}
SECTION("nested array") {
DynamicJsonDocument doc2;
JsonArray arr = doc2.to<JsonArray>();
JsonArray arr2 = doc2.to<JsonArray>();
_array[0] = arr;
array[0] = arr2;
REQUIRE(arr == _array[0].as<JsonArray>());
REQUIRE(arr == _array[0].as<JsonArray>()); // <- short hand
// REQUIRE(arr == _array[0].as<const JsonArray>());
// REQUIRE(arr == _array[0].as<const JsonArray>()); // <- short hand
REQUIRE(true == _array[0].is<JsonArray>());
REQUIRE(false == _array[0].is<int>());
REQUIRE(arr2 == array[0].as<JsonArray>());
REQUIRE(arr2 == array[0].as<JsonArray>()); // <- short hand
// REQUIRE(arr2 == array[0].as<const JsonArray>());
// REQUIRE(arr2 == array[0].as<const JsonArray>()); // <- short hand
REQUIRE(true == array[0].is<JsonArray>());
REQUIRE(false == array[0].is<int>());
}
SECTION("nested object") {
DynamicJsonDocument doc2;
JsonObject obj = doc2.to<JsonObject>();
_array[0] = obj;
array[0] = obj;
REQUIRE(obj == _array[0].as<JsonObject>());
REQUIRE(obj == _array[0].as<const JsonObject>()); // <- short hand
REQUIRE(true == _array[0].is<JsonObject>());
REQUIRE(false == _array[0].is<int>());
REQUIRE(obj == array[0].as<JsonObject>());
REQUIRE(obj == array[0].as<const JsonObject>()); // <- short hand
REQUIRE(true == array[0].is<JsonObject>());
REQUIRE(false == array[0].is<int>());
}
SECTION("array subscript") {
DynamicJsonDocument doc2;
JsonArray arr = doc2.to<JsonArray>();
JsonArray arr2 = doc2.to<JsonArray>();
const char* str = "hello";
arr.add(str);
arr2.add(str);
_array[0] = arr[0];
array[0] = arr2[0];
REQUIRE(str == _array[0]);
REQUIRE(str == array[0]);
}
SECTION("object subscript") {
@ -96,26 +96,50 @@ TEST_CASE("JsonArray::operator[]") {
obj["x"] = str;
_array[0] = obj["x"];
array[0] = obj["x"];
REQUIRE(str == _array[0]);
REQUIRE(str == array[0]);
}
SECTION("should not duplicate const char*") {
_array[0] = "world";
array[0] = "world";
const size_t expectedSize = JSON_ARRAY_SIZE(1);
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate char*") {
_array[0] = const_cast<char*>("world");
array[0] = const_cast<char*>("world");
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate std::string") {
_array[0] = std::string("world");
array[0] = std::string("world");
const size_t expectedSize = JSON_ARRAY_SIZE(1) + 6;
REQUIRE(expectedSize == doc.memoryUsage());
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("set(VLA)") {
int i = 16;
char vla[i];
strcpy(vla, "world");
array.add("hello");
array[0].set(vla);
REQUIRE(std::string("world") == array[0]);
}
SECTION("operator=(VLA)") {
int i = 16;
char vla[i];
strcpy(vla, "world");
array.add("hello");
array[0] = vla;
REQUIRE(std::string("world") == array[0]);
}
#endif
}

View File

@ -3,15 +3,14 @@
# MIT License
add_executable(JsonDeserializerTests
DeserializationError.cpp
deserializeJsonArray.cpp
deserializeJsonArrayStatic.cpp
deserializeJsonObject.cpp
deserializeJsonObjectStatic.cpp
deserializeJsonValue.cpp
DeserializationError.cpp
input_types.cpp
nestingLimit.cpp
std_istream.cpp
std_string.cpp
)
target_link_libraries(JsonDeserializerTests catch)

View File

@ -128,12 +128,7 @@ TEST_CASE("deserialize JSON array") {
SECTION("No quotes") {
DeserializationError err = deserializeJson(doc, "[ hello , world ]");
JsonArray arr = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(2 == arr.size());
REQUIRE(arr[0] == "hello");
REQUIRE(arr[1] == "world");
REQUIRE(err == DeserializationError::InvalidInput);
}
SECTION("Double quotes (empty strings)") {

View File

@ -39,7 +39,7 @@ TEST_CASE("deserialize JSON object") {
}
SECTION("No quotes") {
DeserializationError err = deserializeJson(doc, "{key:value}");
DeserializationError err = deserializeJson(doc, "{key:'value'}");
JsonObject obj = doc.as<JsonObject>();
REQUIRE(err == DeserializationError::Ok);

View File

@ -87,6 +87,40 @@ TEST_CASE("deserializeJson(DynamicJsonDocument&)") {
REQUIRE(doc.as<bool>() == false);
}
SECTION("NaN") {
DeserializationError err = deserializeJson(doc, "NaN");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<float>() == true);
REQUIRE(Internals::isnan(doc.as<float>()));
}
SECTION("Infinity") {
DeserializationError err = deserializeJson(doc, "Infinity");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<float>() == true);
REQUIRE(Internals::isinf(doc.as<float>()));
}
SECTION("+Infinity") {
DeserializationError err = deserializeJson(doc, "+Infinity");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<float>() == true);
REQUIRE(Internals::isinf(doc.as<float>()));
}
SECTION("-Infinity") {
DeserializationError err = deserializeJson(doc, "-Infinity");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<float>() == true);
REQUIRE(Internals::isinf(doc.as<float>()));
}
SECTION("issue #628") {
DeserializationError err = deserializeJson(doc, "null");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<float>() == false);
}
SECTION("Should clear the JsonVariant") {
deserializeJson(doc, "[1,2,3]");
deserializeJson(doc, "{}");

View File

@ -6,6 +6,35 @@
#include <catch.hpp>
#include <sstream>
TEST_CASE("deserializeJson(const std::string&)") {
DynamicJsonDocument doc;
SECTION("should accept const string") {
const std::string input("[42]");
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("should accept temporary string") {
DeserializationError err = deserializeJson(doc, std::string("[42]"));
REQUIRE(err == DeserializationError::Ok);
}
SECTION("should duplicate content") {
std::string input("[\"hello\"]");
DeserializationError err = deserializeJson(doc, input);
input[2] = 'X'; // alter the string tomake sure we made a copy
JsonArray array = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(std::string("hello") == array[0]);
}
}
TEST_CASE("deserializeJson(std::istream&)") {
DynamicJsonDocument doc;
@ -21,7 +50,7 @@ TEST_CASE("deserializeJson(std::istream&)") {
}
SECTION("object") {
std::istringstream json(" { hello : world // comment\n }");
std::istringstream json(" { hello : 'world' // comment\n }");
DeserializationError err = deserializeJson(doc, json);
JsonObject obj = doc.as<JsonObject>();
@ -71,3 +100,16 @@ TEST_CASE("deserializeJson(std::istream&)") {
REQUIRE('1' == char(json.get()));
}
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
TEST_CASE("deserializeJson(VLA)") {
int i = 9;
char vla[i];
strcpy(vla, "{\"a\":42}");
StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc;
DeserializationError err = deserializeJson(doc, vla);
REQUIRE(err == DeserializationError::Ok);
}
#endif

View File

@ -1,35 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("deserializeJson(const std::string&)") {
DynamicJsonDocument doc;
SECTION("should accept const string") {
const std::string input("[42]");
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("should accept temporary string") {
DeserializationError err = deserializeJson(doc, std::string("[42]"));
REQUIRE(err == DeserializationError::Ok);
}
SECTION("should duplicate content") {
std::string input("[\"hello\"]");
DeserializationError err = deserializeJson(doc, input);
input[2] = 'X'; // alter the string tomake sure we made a copy
JsonArray array = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(std::string("hello") == array[0]);
}
}

View File

@ -0,0 +1,11 @@
# ArduinoJson - arduinojson.org
# Copyright Benoit Blanchon 2014-2018
# MIT License
add_executable(JsonDocumentTests
DynamicJsonDocument.cpp
StaticJsonDocument.cpp
)
target_link_libraries(JsonDocumentTests catch)
add_test(JsonDocument JsonDocumentTests)

View File

@ -0,0 +1,20 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("DynamicJsonDocument") {
DynamicJsonDocument doc;
SECTION("serializeJson()") {
JsonObject obj = doc.to<JsonObject>();
obj["hello"] = "world";
std::string json;
serializeJson(doc, json);
REQUIRE(json == "{\"hello\":\"world\"}");
}
}

View File

@ -0,0 +1,20 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("StaticJsonDocument") {
StaticJsonDocument<200> doc;
SECTION("serializeJson()") {
JsonObject obj = doc.to<JsonObject>();
obj["hello"] = "world";
std::string json;
serializeJson(doc, json);
REQUIRE(json == "{\"hello\":\"world\"}");
}
}

View File

@ -3,10 +3,13 @@
# MIT License
add_executable(JsonObjectTests
basics.cpp
containsKey.cpp
createNestedArray.cpp
createNestedObject.cpp
get.cpp
invalid.cpp
is.cpp
isNull.cpp
iterator.cpp
remove.cpp
set.cpp

View File

@ -1,15 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonObject basics") {
DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
SECTION("isNull()") {
REQUIRE(obj.isNull() == false);
}
}

View File

@ -8,23 +8,29 @@
TEST_CASE("JsonObject::containsKey()") {
DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
obj.set("hello", 42);
SECTION("ContainsKeyReturnsFalseForNonExistingKey") {
obj.set("hello", 42);
SECTION("returns false if key not present") {
REQUIRE(false == obj.containsKey("world"));
}
SECTION("ContainsKeyReturnsTrueForDefinedValue") {
obj.set("hello", 42);
SECTION("returns true if key present") {
REQUIRE(true == obj.containsKey("hello"));
}
SECTION("ContainsKeyReturnsFalseAfterRemove") {
obj.set("hello", 42);
SECTION("returns false after remove()") {
obj.remove("hello");
REQUIRE(false == obj.containsKey("hello"));
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("key is a VLA") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
REQUIRE(true == obj.containsKey(vla));
}
#endif
}

View File

@ -0,0 +1,25 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonObject::createNestedArray()") {
DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
SECTION("key is a const char*") {
obj.createNestedArray("hello");
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("key is a VLA") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
obj.createNestedArray(vla);
}
#endif
}

View File

@ -0,0 +1,25 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonObject::createNestedObject()") {
DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
SECTION("key is a const char*") {
obj.createNestedObject("hello");
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("key is a VLA") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
obj.createNestedObject(vla);
}
#endif
}

View File

@ -11,9 +11,20 @@ TEST_CASE("JsonObject::get()") {
DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
SECTION("GetConstCharPointer_GivenStringLiteral") {
SECTION("get<const char*>(const char*)") {
obj.set("hello", "world");
const char* value = obj.get<const char*>("hello");
REQUIRE_THAT(value, Equals("world"));
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("get<const char*>(VLA)") {
obj.set("hello", "world");
int i = 16;
char vla[i];
strcpy(vla, "hello");
REQUIRE(std::string("world") == obj.get<char*>(vla));
}
#endif
}

28
test/JsonObject/is.cpp Normal file
View File

@ -0,0 +1,28 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonObject::is<T>()") {
DynamicJsonDocument doc;
JsonObject obj = doc.to<JsonObject>();
obj["int"] = 42;
obj["str"] = "hello";
SECTION("is<int>(const char*)") {
REQUIRE(true == obj.is<int>("int"));
REQUIRE(false == obj.is<int>("str"));
}
#if HAS_VARIABLE_LENGTH_ARRAY
SECTION("is<T>(VLA)") {
int i = 16;
char vla[i];
strcpy(vla, "int");
REQUIRE(true == obj.is<int>(vla));
}
#endif
}

View File

@ -0,0 +1,25 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonObject::isNull()") {
SECTION("returns true for undefined JsonObject") {
JsonObject array;
REQUIRE(array.isNull() == true);
}
SECTION("returns false when allocation succeeds") {
StaticJsonDocument<JSON_OBJECT_SIZE(0)> doc;
JsonObject array = doc.to<JsonObject>();
REQUIRE(array.isNull() == false);
}
SECTION("returns true when allocation fails") {
StaticJsonDocument<1> doc;
JsonObject array = doc.to<JsonObject>();
REQUIRE(array.isNull() == true);
}
}

View File

@ -16,36 +16,28 @@ TEST_CASE("JsonObject::begin()/end()") {
SECTION("NonConstIterator") {
JsonObject::iterator it = obj.begin();
REQUIRE(obj.end() != it);
REQUIRE_THAT(it->key, Equals("ab"));
REQUIRE(12 == it->value);
it->key = "a.b";
it->value = 1.2;
REQUIRE_THAT(it->key(), Equals("ab"));
REQUIRE(12 == it->value());
++it;
REQUIRE(obj.end() != it);
REQUIRE_THAT(it->key, Equals("cd"));
REQUIRE(34 == it->value);
it->key = "c.d";
it->value = 3.4;
REQUIRE_THAT(it->key(), Equals("cd"));
REQUIRE(34 == it->value());
++it;
REQUIRE(obj.end() == it);
REQUIRE(2 == obj.size());
REQUIRE(1.2 == obj["a.b"]);
REQUIRE(3.4 == obj["c.d"]);
}
SECTION("ConstIterator") {
const JsonObject const_object = obj;
JsonObject::const_iterator it = const_object.begin();
// SECTION("ConstIterator") {
// const JsonObject const_object = obj;
// JsonObject::iterator it = const_object.begin();
REQUIRE(const_object.end() != it);
REQUIRE_THAT(it->key, Equals("ab"));
REQUIRE(12 == it->value);
++it;
REQUIRE(const_object.end() != it);
REQUIRE_THAT(it->key, Equals("cd"));
REQUIRE(34 == it->value);
++it;
REQUIRE(const_object.end() == it);
}
// REQUIRE(const_object.end() != it);
// REQUIRE_THAT(it->key(), Equals("ab"));
// REQUIRE(12 == it->value());
// ++it;
// REQUIRE(const_object.end() != it);
// REQUIRE_THAT(it->key(), Equals("cd"));
// REQUIRE(34 == it->value());
// ++it;
// REQUIRE(const_object.end() == it);
// }
}

View File

@ -32,11 +32,24 @@ TEST_CASE("JsonObject::remove()") {
obj["c"] = 2;
for (JsonObject::iterator it = obj.begin(); it != obj.end(); ++it) {
if (it->value == 1) obj.remove(it);
if (it->value() == 1) obj.remove(it);
}
std::string result;
serializeJson(obj, result);
REQUIRE("{\"a\":0,\"c\":2}" == result);
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("key is a vla") {
obj["hello"] = 1;
int i = 16;
char vla[i];
strcpy(vla, "hello");
obj.remove(vla);
REQUIRE(0 == obj.size());
}
#endif
}

View File

@ -42,6 +42,38 @@ TEST_CASE("JsonObject::set()") {
REQUIRE_FALSE(obj["hello"].is<long>());
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("key is a VLA") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
obj.set(vla, "world");
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("value is a VLA") {
int i = 16;
char vla[i];
strcpy(vla, "world");
obj.set("hello", vla);
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("key and value are VLAs") {
int i = 16;
char vla[i];
strcpy(vla, "world");
obj.set(vla, vla);
REQUIRE(std::string("world") == obj["world"]);
}
#endif
SECTION("nested array") {
DynamicJsonDocument doc2;
JsonArray arr = doc2.to<JsonArray>();

View File

@ -159,4 +159,58 @@ TEST_CASE("JsonObject::operator[]") {
REQUIRE(obj.size() == 1);
REQUIRE(obj[null] == 0);
}
#if defined(HAS_VARIABLE_LENGTH_ARRAY) && \
!defined(SUBSCRIPT_CONFLICTS_WITH_BUILTIN_OPERATOR)
SECTION("obj[VLA] = str") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
obj[vla] = "world";
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("obj[str] = VLA") { // issue #416
int i = 32;
char vla[i];
strcpy(vla, "world");
obj["hello"] = vla;
REQUIRE(std::string("world") == obj["hello"].as<char*>());
}
SECTION("obj.set(VLA, str)") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
obj[vla] = "world";
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("obj.set(str, VLA)") {
int i = 32;
char vla[i];
strcpy(vla, "world");
obj["hello"].set(vla);
REQUIRE(std::string("world") == obj["hello"].as<char*>());
}
SECTION("obj[VLA]") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
deserializeJson(doc, "{\"hello\":\"world\"}");
obj = doc.as<JsonObject>();
REQUIRE(std::string("world") == obj[vla]);
}
#endif
}

View File

@ -8,6 +8,7 @@ add_executable(JsonSerializerTests
JsonObject.cpp
JsonObjectPretty.cpp
JsonVariant.cpp
misc.cpp
std_stream.cpp
std_string.cpp
)

View File

@ -67,15 +67,15 @@ TEST_CASE("serializeJson(JsonArray)") {
check(array, "[1,2]");
}
SECTION("RawJson(const char*)") {
array.add(RawJson("{\"key\":\"value\"}"));
SECTION("serialized(const char*)") {
array.add(serialized("{\"key\":\"value\"}"));
check(array, "[{\"key\":\"value\"}]");
}
SECTION("RawJson(char*)") {
SECTION("serialized(char*)") {
char tmp[] = "{\"key\":\"value\"}";
array.add(RawJson(tmp));
array.add(serialized(tmp));
check(array, "[{\"key\":\"value\"}]");
}

Some files were not shown because too many files have changed in this diff Show More