update ArduinoJson to latest v6.20.0 (saves 1600 bytes in flash. whoot!)

This commit is contained in:
Proddy
2022-12-27 21:48:03 +01:00
parent 6390f4aa48
commit 5d45064c2d
96 changed files with 3504 additions and 3314 deletions

View File

@@ -1,6 +1,41 @@
ArduinoJson: change log ArduinoJson: change log
======================= =======================
v6.20.0 (2022-12-26)
-------
* Add `JsonVariant::shallowCopy()` (issue #1343)
* Fix `9.22337e+18 is outside the range of representable values of type 'long'`
* Fix comparison operators for `JsonArray`, `JsonArrayConst`, `JsonObject`, and `JsonObjectConst`
* Fix lax parsing of `true`, `false`, and `null` (issue #1781)
* Remove undocumented `accept()` functions
* Rename `addElement()` to `add()`
* Remove `getElement()`, `getOrAddElement()`, `getMember()`, and `getOrAddMember()`
* Remove undocumented `JsonDocument::data()` and `JsonDocument::memoryPool()`
* Remove undocumented `JsonArrayIterator::internal()` and `JsonObjectIterator::internal()`
* Rename things in `ARDUINOJSON_NAMESPACE` to match the public names
* Add documentation to most public symbols
* Remove support for naked `char` (was deprecated since 6.18.0)
> ### BREAKING CHANGES
>
> This release hides `JsonVariant`'s functions that were only intended for internal use.
> If you were using them in your programs, you must replace with `operator[]` and `to<JsonVariant>()`, like so:
>
> ```c++
> // before
> JsonVariant a = variant.getElement(idx);
> JsonVariant b = variant.getOrAddElement(idx);
> JsonVariant c = variant.getMember(key);
> JsonVariant d = variant.getOrAddMember(key);
>
> // after
> JsonVariant a = variant[idx];
> JsonVariant b = idx < variant.size() ? variant[idx] : variant[idx].to<JsonVariant>();
> JsonVariant c = variant[key];
> JsonVariant d = variant.containsKey(key) ? variant[key] : variant[key].to<JsonVariant>();
> ```
v6.19.4 (2022-04-05) v6.19.4 (2022-04-05)
------- -------

View File

@@ -1,14 +1,15 @@
![ArduinoJson](banner.svg) <p align="center">
<a href="https://arduinojson.org/"><img alt="ArduinoJson" src="logo.svg" /></a>
</p>
--- ---
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/bblanchon/ArduinoJson/Continuous%20Integration?logo=github)](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A6.x) [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/bblanchon/ArduinoJson/ci.yml?branch=6.x)](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A6.x)
[![Continuous Integration](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/6.x?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x) [![Continuous Integration](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/6.x?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/arduinojson.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/arduinojson.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
[![LGTM Grade](https://img.shields.io/lgtm/grade/cpp/github/bblanchon/ArduinoJson?label=quality&logo=lgtm)](https://lgtm.com/projects/g/bblanchon/ArduinoJson/)
[![Coveralls branch](https://img.shields.io/coveralls/github/bblanchon/ArduinoJson/6.x?logo=coveralls)](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x) [![Coveralls branch](https://img.shields.io/coveralls/github/bblanchon/ArduinoJson/6.x?logo=coveralls)](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x)
[![Arduino Library Manager](https://img.shields.io/static/v1?label=Arduino&message=v6.19.4&logo=arduino&logoColor=white&color=blue)](https://www.ardu-badge.com/ArduinoJson/6.19.4) [![Arduino Library Manager](https://img.shields.io/static/v1?label=Arduino&message=v6.20.0&logo=arduino&logoColor=white&color=blue)](https://www.ardu-badge.com/ArduinoJson/6.20.0)
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/bblanchon/library/ArduinoJson.svg?version=6.19.4)](https://registry.platformio.org/packages/libraries/bblanchon/ArduinoJson?version=6.19.4) [![PlatformIO Registry](https://badges.registry.platformio.org/packages/bblanchon/library/ArduinoJson.svg?version=6.20.0)](https://registry.platformio.org/packages/libraries/bblanchon/ArduinoJson?version=6.20.0)
[![GitHub stars](https://img.shields.io/github/stars/bblanchon/ArduinoJson?style=flat&logo=github)](https://github.com/bblanchon/ArduinoJson/stargazers) [![GitHub stars](https://img.shields.io/github/stars/bblanchon/ArduinoJson?style=flat&logo=github)](https://github.com/bblanchon/ArduinoJson/stargazers)
[![GitHub Sponsors](https://img.shields.io/github/sponsors/bblanchon?logo=github)](https://github.com/sponsors/bblanchon) [![GitHub Sponsors](https://img.shields.io/github/sponsors/bblanchon?logo=github)](https://github.com/sponsors/bblanchon)
@@ -16,32 +17,32 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
## Features ## Features
* [JSON deserialization](https://arduinojson.org/v6/api/json/deserializejson/?utm_source=github&utm_medium=readme) * [JSON deserialization](https://arduinojson.org/v6/api/json/deserializejson/)
* [Optionally decodes UTF-16 escape sequences to UTF-8](https://arduinojson.org/v6/api/config/decode_unicode/?utm_source=github&utm_medium=readme) * [Optionally decodes UTF-16 escape sequences to UTF-8](https://arduinojson.org/v6/api/config/decode_unicode/)
* [Optionally stores links to the input buffer (zero-copy)](https://arduinojson.org/v6/api/json/deserializejson/?utm_source=github&utm_medium=readme) * [Optionally stores links to the input buffer (zero-copy)](https://arduinojson.org/v6/api/json/deserializejson/)
* [Optionally supports comments in the input](https://arduinojson.org/v6/api/config/enable_comments/?utm_source=github&utm_medium=readme) * [Optionally supports comments in the input](https://arduinojson.org/v6/api/config/enable_comments/)
* [Optionally filters the input to keep only desired values](https://arduinojson.org/v6/api/json/deserializejson/?utm_source=github&utm_medium=readme#filtering) * [Optionally filters the input to keep only desired values](https://arduinojson.org/v6/api/json/deserializejson/#filtering)
* Supports single quotes as a string delimiter * Supports single quotes as a string delimiter
* Compatible with [NDJSON](http://ndjson.org/) and [JSON Lines](https://jsonlines.org/) * Compatible with [NDJSON](http://ndjson.org/) and [JSON Lines](https://jsonlines.org/)
* [JSON serialization](https://arduinojson.org/v6/api/json/serializejson/?utm_source=github&utm_medium=readme) * [JSON serialization](https://arduinojson.org/v6/api/json/serializejson/)
* [Can write to a buffer or a stream](https://arduinojson.org/v6/api/json/serializejson/?utm_source=github&utm_medium=readme) * [Can write to a buffer or a stream](https://arduinojson.org/v6/api/json/serializejson/)
* [Optionally indents the document (prettified JSON)](https://arduinojson.org/v6/api/json/serializejsonpretty/?utm_source=github&utm_medium=readme) * [Optionally indents the document (prettified JSON)](https://arduinojson.org/v6/api/json/serializejsonpretty/)
* [MessagePack serialization](https://arduinojson.org/v6/api/msgpack/serializemsgpack/?utm_source=github&utm_medium=readme) * [MessagePack serialization](https://arduinojson.org/v6/api/msgpack/serializemsgpack/)
* [MessagePack deserialization](https://arduinojson.org/v6/api/msgpack/deserializemsgpack/?utm_source=github&utm_medium=readme) * [MessagePack deserialization](https://arduinojson.org/v6/api/msgpack/deserializemsgpack/)
* Efficient * Efficient
* [Twice smaller than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/?utm_source=github&utm_medium=readme) * [Twice smaller than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
* [Almost 10% faster than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/?utm_source=github&utm_medium=readme) * [Almost 10% faster than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
* [Consumes roughly 10% less RAM than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/?utm_source=github&utm_medium=readme) * [Consumes roughly 10% less RAM than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
* [Fixed memory allocation, no heap fragmentation](https://arduinojson.org/v6/api/jsondocument/?utm_source=github&utm_medium=readme) * [Fixed memory allocation, no heap fragmentation](https://arduinojson.org/v6/api/jsondocument/)
* [Optionally works without heap memory (zero malloc)](https://arduinojson.org/v6/api/staticjsondocument/?utm_source=github&utm_medium=readme) * [Optionally works without heap memory (zero malloc)](https://arduinojson.org/v6/api/staticjsondocument/)
* [Deduplicates strings](https://arduinojson.org/news/2020/08/01/version-6-16-0/?utm_source=github&utm_medium=readme) * [Deduplicates strings](https://arduinojson.org/news/2020/08/01/version-6-16-0/)
* Versatile * Versatile
* Supports [custom allocators (to use external RAM chip, for example)](https://arduinojson.org/v6/how-to/use-external-ram-on-esp32/?utm_source=github&utm_medium=readme) * Supports [custom allocators (to use external RAM chip, for example)](https://arduinojson.org/v6/how-to/use-external-ram-on-esp32/)
* Supports [`String`](https://arduinojson.org/v6/api/config/enable_arduino_string/?utm_source=github&utm_medium=readme), [`std::string`](https://arduinojson.org/v6/api/config/enable_std_string/?utm_source=github&utm_medium=readme), and [`std::string_view`](https://arduinojson.org/v6/api/config/enable_string_view/?utm_source=github&utm_medium=readme) * Supports [`String`](https://arduinojson.org/v6/api/config/enable_arduino_string/), [`std::string`](https://arduinojson.org/v6/api/config/enable_std_string/), and [`std::string_view`](https://arduinojson.org/v6/api/config/enable_string_view/)
* Supports [`Stream`](https://arduinojson.org/v6/api/config/enable_arduino_stream/?utm_source=github&utm_medium=readme) and [`std::istream`/`std::ostream`](https://arduinojson.org/v6/api/config/enable_std_stream/?utm_source=github&utm_medium=readme) * Supports [`Stream`](https://arduinojson.org/v6/api/config/enable_arduino_stream/) and [`std::istream`/`std::ostream`](https://arduinojson.org/v6/api/config/enable_std_stream/)
* Supports [Flash strings](https://arduinojson.org/v6/api/config/enable_progmem/?utm_source=github&utm_medium=readme) * Supports [Flash strings](https://arduinojson.org/v6/api/config/enable_progmem/)
* Supports [custom readers](https://arduinojson.org/v6/api/json/deserializejson/?utm_source=github&utm_medium=readme#custom-reader) and [custom writers](https://arduinojson.org/v6/api/json/serializejson/?utm_source=github&utm_medium=readme#custom-writer) * Supports [custom readers](https://arduinojson.org/v6/api/json/deserializejson/#custom-reader) and [custom writers](https://arduinojson.org/v6/api/json/serializejson/#custom-writer)
* Supports [custom converters](https://arduinojson.org/news/2021/05/04/version-6-18-0/?utm_source=github&utm_medium=readme) * Supports [custom converters](https://arduinojson.org/news/2021/05/04/version-6-18-0/)
* Portable * Portable
* Usable on any C++ project (not limited to Arduino) * Usable on any C++ project (not limited to Arduino)
* Compatible with C++98, C++11, C++14 and C++17 * Compatible with C++98, C++11, C++14 and C++17
@@ -69,15 +70,15 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
* [Visual Micro](http://www.visualmicro.com/) * [Visual Micro](http://www.visualmicro.com/)
* [Visual Studio](https://www.visualstudio.com/) * [Visual Studio](https://www.visualstudio.com/)
* [Even works with online compilers like wandbox.org](https://wandbox.org/permlink/RlZSKy17DjJ6HcdN) * [Even works with online compilers like wandbox.org](https://wandbox.org/permlink/RlZSKy17DjJ6HcdN)
* [CMake friendly](https://arduinojson.org/v6/how-to/use-arduinojson-with-cmake/?utm_source=github&utm_medium=readme) * [CMake friendly](https://arduinojson.org/v6/how-to/use-arduinojson-with-cmake/)
* Well designed * Well designed
* [Elegant API](http://arduinojson.org/v6/example/?utm_source=github&utm_medium=readme) * [Elegant API](http://arduinojson.org/v6/example/)
* [Thread-safe](https://en.wikipedia.org/wiki/Thread_safety) * [Thread-safe](https://en.wikipedia.org/wiki/Thread_safety)
* Self-contained (no external dependency) * Self-contained (no external dependency)
* `const` friendly * `const` friendly
* [`for` friendly](https://arduinojson.org/v6/api/jsonobject/begin_end/?utm_source=github&utm_medium=readme) * [`for` friendly](https://arduinojson.org/v6/api/jsonobject/begin_end/)
* [TMP friendly](https://en.wikipedia.org/wiki/Template_metaprogramming) * [TMP friendly](https://en.wikipedia.org/wiki/Template_metaprogramming)
* Handles [integer overflows](https://arduinojson.org/v6/api/jsonvariant/as/?utm_source=github&utm_medium=readme#integer-overflows) * Handles [integer overflows](https://arduinojson.org/v6/api/jsonvariant/as/#integer-overflows)
* Well tested * Well tested
* [Unit test coverage close to 100%](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x) * [Unit test coverage close to 100%](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x)
* Continuously tested on * Continuously tested on
@@ -87,12 +88,12 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
* [Continuously fuzzed with Google OSS Fuzz](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson) * [Continuously fuzzed with Google OSS Fuzz](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
* Passes all default checks of [clang-tidy](https://releases.llvm.org/10.0.0/tools/clang/tools/extra/docs/clang-tidy/) * Passes all default checks of [clang-tidy](https://releases.llvm.org/10.0.0/tools/clang/tools/extra/docs/clang-tidy/)
* Well documented * Well documented
* [Tutorials](https://arduinojson.org/v6/doc/deserialization/?utm_source=github&utm_medium=readme) * [Tutorials](https://arduinojson.org/v6/doc/deserialization/)
* [Examples](https://arduinojson.org/v6/example/?utm_source=github&utm_medium=readme) * [Examples](https://arduinojson.org/v6/example/)
* [How-tos](https://arduinojson.org/v6/example/?utm_source=github&utm_medium=readme) * [How-tos](https://arduinojson.org/v6/example/)
* [FAQ](https://arduinojson.org/v6/faq/?utm_source=github&utm_medium=readme) * [FAQ](https://arduinojson.org/v6/faq/)
* [Troubleshooter](https://arduinojson.org/v6/troubleshooter/?utm_source=github&utm_medium=readme) * [Troubleshooter](https://arduinojson.org/v6/troubleshooter/)
* [Book](https://arduinojson.org/book/?utm_source=github&utm_medium=readme) * [Book](https://arduinojson.org/book/)
* [Changelog](CHANGELOG.md) * [Changelog](CHANGELOG.md)
* Vibrant user community * Vibrant user community
* Most popular of all Arduino libraries on [GitHub](https://github.com/search?o=desc&q=arduino+library&s=stars&type=Repositories) * Most popular of all Arduino libraries on [GitHub](https://github.com/search?o=desc&q=arduino+library&s=stars&type=Repositories)
@@ -118,7 +119,7 @@ double latitude = doc["data"][0];
double longitude = doc["data"][1]; double longitude = doc["data"][1];
``` ```
See the [tutorial on arduinojson.org](https://arduinojson.org/doc/decoding/?utm_source=github&utm_medium=readme) See the [tutorial on arduinojson.org](https://arduinojson.org/v6/doc/deserialization/)
### Serialization ### Serialization
@@ -137,16 +138,13 @@ serializeJson(doc, Serial);
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]} // {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
``` ```
See the [tutorial on arduinojson.org](https://arduinojson.org/doc/encoding/?utm_source=github&utm_medium=readme) See the [tutorial on arduinojson.org](https://arduinojson.org/v6/doc/serialization/)
## Sponsors ## Sponsors
ArduinoJson is thankful to its sponsors. Please give them a visit; they deserve it! ArduinoJson is thankful to its sponsors. Please give them a visit; they deserve it!
<p> <p>
<a href="https://techexplorations.com/" rel="sponsored">
<img alt="Tech Explorations" src="https://arduinojson.org/images/2021/10/techexplorations.png" width="200">
</a>
<a href="https://www.programmingelectronics.com/" rel="sponsored"> <a href="https://www.programmingelectronics.com/" rel="sponsored">
<img src="https://arduinojson.org/images/2021/10/programmingeleactronicsacademy.png" alt="Programming Electronics Academy" width="200"> <img src="https://arduinojson.org/images/2021/10/programmingeleactronicsacademy.png" alt="Programming Electronics Academy" width="200">
</a> </a>

View File

@@ -21,19 +21,19 @@
# endif # endif
#endif #endif
#include "ArduinoJson/Array/ArrayRef.hpp" #include "ArduinoJson/Array/JsonArray.hpp"
#include "ArduinoJson/Object/ObjectRef.hpp" #include "ArduinoJson/Object/JsonObject.hpp"
#include "ArduinoJson/Variant/VariantRef.hpp" #include "ArduinoJson/Variant/JsonVariantConst.hpp"
#include "ArduinoJson/Document/DynamicJsonDocument.hpp" #include "ArduinoJson/Document/DynamicJsonDocument.hpp"
#include "ArduinoJson/Document/StaticJsonDocument.hpp" #include "ArduinoJson/Document/StaticJsonDocument.hpp"
#include "ArduinoJson/Array/ArrayImpl.hpp"
#include "ArduinoJson/Array/ElementProxy.hpp" #include "ArduinoJson/Array/ElementProxy.hpp"
#include "ArduinoJson/Array/JsonArrayImpl.hpp"
#include "ArduinoJson/Array/Utilities.hpp" #include "ArduinoJson/Array/Utilities.hpp"
#include "ArduinoJson/Collection/CollectionImpl.hpp" #include "ArduinoJson/Collection/CollectionImpl.hpp"
#include "ArduinoJson/Object/JsonObjectImpl.hpp"
#include "ArduinoJson/Object/MemberProxy.hpp" #include "ArduinoJson/Object/MemberProxy.hpp"
#include "ArduinoJson/Object/ObjectImpl.hpp"
#include "ArduinoJson/Variant/ConverterImpl.hpp" #include "ArduinoJson/Variant/ConverterImpl.hpp"
#include "ArduinoJson/Variant/VariantCompare.hpp" #include "ArduinoJson/Variant/VariantCompare.hpp"
#include "ArduinoJson/Variant/VariantImpl.hpp" #include "ArduinoJson/Variant/VariantImpl.hpp"
@@ -47,25 +47,25 @@
#include "ArduinoJson/compatibility.hpp" #include "ArduinoJson/compatibility.hpp"
namespace ArduinoJson { namespace ArduinoJson {
typedef ARDUINOJSON_NAMESPACE::ArrayConstRef JsonArrayConst;
typedef ARDUINOJSON_NAMESPACE::ArrayRef JsonArray;
typedef ARDUINOJSON_NAMESPACE::Float JsonFloat;
typedef ARDUINOJSON_NAMESPACE::Integer JsonInteger;
typedef ARDUINOJSON_NAMESPACE::ObjectConstRef JsonObjectConst;
typedef ARDUINOJSON_NAMESPACE::ObjectRef JsonObject;
typedef ARDUINOJSON_NAMESPACE::Pair JsonPair;
typedef ARDUINOJSON_NAMESPACE::PairConst JsonPairConst;
typedef ARDUINOJSON_NAMESPACE::String JsonString;
typedef ARDUINOJSON_NAMESPACE::UInt JsonUInt;
typedef ARDUINOJSON_NAMESPACE::VariantConstRef JsonVariantConst;
typedef ARDUINOJSON_NAMESPACE::VariantRef JsonVariant;
using ARDUINOJSON_NAMESPACE::BasicJsonDocument; using ARDUINOJSON_NAMESPACE::BasicJsonDocument;
using ARDUINOJSON_NAMESPACE::copyArray; using ARDUINOJSON_NAMESPACE::copyArray;
using ARDUINOJSON_NAMESPACE::DeserializationError; using ARDUINOJSON_NAMESPACE::DeserializationError;
using ARDUINOJSON_NAMESPACE::deserializeJson; using ARDUINOJSON_NAMESPACE::deserializeJson;
using ARDUINOJSON_NAMESPACE::deserializeMsgPack; using ARDUINOJSON_NAMESPACE::deserializeMsgPack;
using ARDUINOJSON_NAMESPACE::DynamicJsonDocument; using ARDUINOJSON_NAMESPACE::DynamicJsonDocument;
using ARDUINOJSON_NAMESPACE::JsonArray;
using ARDUINOJSON_NAMESPACE::JsonArrayConst;
using ARDUINOJSON_NAMESPACE::JsonDocument; using ARDUINOJSON_NAMESPACE::JsonDocument;
using ARDUINOJSON_NAMESPACE::JsonFloat;
using ARDUINOJSON_NAMESPACE::JsonInteger;
using ARDUINOJSON_NAMESPACE::JsonObject;
using ARDUINOJSON_NAMESPACE::JsonObjectConst;
using ARDUINOJSON_NAMESPACE::JsonPair;
using ARDUINOJSON_NAMESPACE::JsonPairConst;
using ARDUINOJSON_NAMESPACE::JsonString;
using ARDUINOJSON_NAMESPACE::JsonUInt;
using ARDUINOJSON_NAMESPACE::JsonVariant;
using ARDUINOJSON_NAMESPACE::JsonVariantConst;
using ARDUINOJSON_NAMESPACE::measureJson; using ARDUINOJSON_NAMESPACE::measureJson;
using ARDUINOJSON_NAMESPACE::serialized; using ARDUINOJSON_NAMESPACE::serialized;
using ARDUINOJSON_NAMESPACE::serializeJson; using ARDUINOJSON_NAMESPACE::serializeJson;

View File

@@ -1,31 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Collection/CollectionData.hpp>
namespace ARDUINOJSON_NAMESPACE {
inline VariantData *arrayAdd(CollectionData *arr, MemoryPool *pool) {
return arr ? arr->addElement(pool) : 0;
}
template <typename TVisitor>
inline typename TVisitor::result_type arrayAccept(const CollectionData *arr,
TVisitor &visitor) {
if (arr)
return visitor.visitArray(*arr);
else
return visitor.visitNull();
}
inline bool arrayEquals(const CollectionData *lhs, const CollectionData *rhs) {
if (lhs == rhs)
return true;
if (!lhs || !rhs)
return false;
return lhs->equalsArray(*rhs);
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -1,28 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/ArrayRef.hpp>
#include <ArduinoJson/Object/ObjectRef.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename TArray>
inline ArrayRef ArrayShortcuts<TArray>::createNestedArray() const {
return impl()->addElement().template to<ArrayRef>();
}
template <typename TArray>
inline ObjectRef ArrayShortcuts<TArray>::createNestedObject() const {
return impl()->addElement().template to<ObjectRef>();
}
template <typename TArray>
inline ElementProxy<TArray> ArrayShortcuts<TArray>::operator[](
size_t index) const {
return ElementProxy<TArray>(*impl(), index);
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -1,121 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Variant/SlotFunctions.hpp>
#include <ArduinoJson/Variant/VariantRef.hpp>
namespace ARDUINOJSON_NAMESPACE {
class VariantPtr {
public:
VariantPtr(MemoryPool *pool, VariantData *data) : _variant(pool, data) {}
VariantRef *operator->() {
return &_variant;
}
VariantRef &operator*() {
return _variant;
}
private:
VariantRef _variant;
};
class ArrayIterator {
public:
ArrayIterator() : _slot(0) {}
explicit ArrayIterator(MemoryPool *pool, VariantSlot *slot)
: _pool(pool), _slot(slot) {}
VariantRef operator*() const {
return VariantRef(_pool, _slot->data());
}
VariantPtr operator->() {
return VariantPtr(_pool, _slot->data());
}
bool operator==(const ArrayIterator &other) const {
return _slot == other._slot;
}
bool operator!=(const ArrayIterator &other) const {
return _slot != other._slot;
}
ArrayIterator &operator++() {
_slot = _slot->next();
return *this;
}
ArrayIterator &operator+=(size_t distance) {
_slot = _slot->next(distance);
return *this;
}
VariantSlot *internal() {
return _slot;
}
private:
MemoryPool *_pool;
VariantSlot *_slot;
};
class VariantConstPtr {
public:
VariantConstPtr(const VariantData *data) : _variant(data) {}
VariantConstRef *operator->() {
return &_variant;
}
VariantConstRef &operator*() {
return _variant;
}
private:
VariantConstRef _variant;
};
class ArrayConstRefIterator {
public:
ArrayConstRefIterator() : _slot(0) {}
explicit ArrayConstRefIterator(const VariantSlot *slot) : _slot(slot) {}
VariantConstRef operator*() const {
return VariantConstRef(_slot->data());
}
VariantConstPtr operator->() {
return VariantConstPtr(_slot->data());
}
bool operator==(const ArrayConstRefIterator &other) const {
return _slot == other._slot;
}
bool operator!=(const ArrayConstRefIterator &other) const {
return _slot != other._slot;
}
ArrayConstRefIterator &operator++() {
_slot = _slot->next();
return *this;
}
ArrayConstRefIterator &operator+=(size_t distance) {
_slot = _slot->next(distance);
return *this;
}
const VariantSlot *internal() {
return _slot;
}
private:
const VariantSlot *_slot;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -1,213 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/ArrayFunctions.hpp>
#include <ArduinoJson/Array/ArrayIterator.hpp>
#include <ArduinoJson/Variant/VariantData.hpp>
// Returns the size (in bytes) of an array with n elements.
// Can be very handy to determine the size of a StaticMemoryPool.
#define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \
((NUMBER_OF_ELEMENTS) * sizeof(ARDUINOJSON_NAMESPACE::VariantSlot))
namespace ARDUINOJSON_NAMESPACE {
class ObjectRef;
template <typename>
class ElementProxy;
template <typename TData>
class ArrayRefBase {
public:
operator VariantConstRef() const {
const void* data = _data; // prevent warning cast-align
return VariantConstRef(reinterpret_cast<const VariantData*>(data));
}
template <typename TVisitor>
FORCE_INLINE typename TVisitor::result_type accept(TVisitor& visitor) const {
return arrayAccept(_data, visitor);
}
FORCE_INLINE bool isNull() const {
return _data == 0;
}
FORCE_INLINE operator bool() const {
return _data != 0;
}
FORCE_INLINE size_t memoryUsage() const {
return _data ? _data->memoryUsage() : 0;
}
FORCE_INLINE size_t nesting() const {
return _data ? _data->nesting() : 0;
}
FORCE_INLINE size_t size() const {
return _data ? _data->size() : 0;
}
protected:
ArrayRefBase(TData* data) : _data(data) {}
TData* _data;
};
class ArrayConstRef : public ArrayRefBase<const CollectionData>,
public Visitable {
friend class ArrayRef;
typedef ArrayRefBase<const CollectionData> base_type;
public:
typedef ArrayConstRefIterator iterator;
FORCE_INLINE iterator begin() const {
if (!_data)
return iterator();
return iterator(_data->head());
}
FORCE_INLINE iterator end() const {
return iterator();
}
FORCE_INLINE ArrayConstRef() : base_type(0) {}
FORCE_INLINE ArrayConstRef(const CollectionData* data) : base_type(data) {}
FORCE_INLINE bool operator==(ArrayConstRef rhs) const {
return arrayEquals(_data, rhs._data);
}
FORCE_INLINE VariantConstRef operator[](size_t index) const {
return getElement(index);
}
FORCE_INLINE VariantConstRef getElement(size_t index) const {
return VariantConstRef(_data ? _data->getElement(index) : 0);
}
};
class ArrayRef : public ArrayRefBase<CollectionData>,
public ArrayShortcuts<ArrayRef>,
public Visitable {
typedef ArrayRefBase<CollectionData> base_type;
public:
typedef ArrayIterator iterator;
FORCE_INLINE ArrayRef() : base_type(0), _pool(0) {}
FORCE_INLINE ArrayRef(MemoryPool* pool, CollectionData* data)
: base_type(data), _pool(pool) {}
operator VariantRef() {
void* data = _data; // prevent warning cast-align
return VariantRef(_pool, reinterpret_cast<VariantData*>(data));
}
operator ArrayConstRef() const {
return ArrayConstRef(_data);
}
VariantRef addElement() const {
return VariantRef(_pool, arrayAdd(_data, _pool));
}
FORCE_INLINE iterator begin() const {
if (!_data)
return iterator();
return iterator(_pool, _data->head());
}
FORCE_INLINE iterator end() const {
return iterator();
}
// Copy a ArrayRef
FORCE_INLINE bool set(ArrayConstRef src) const {
if (!_data || !src._data)
return false;
return _data->copyFrom(*src._data, _pool);
}
FORCE_INLINE bool operator==(ArrayRef rhs) const {
return arrayEquals(_data, rhs._data);
}
// Internal use
FORCE_INLINE VariantRef getOrAddElement(size_t index) const {
return VariantRef(_pool, _data ? _data->getOrAddElement(index, _pool) : 0);
}
// Gets the value at the specified index.
FORCE_INLINE VariantRef getElement(size_t index) const {
return VariantRef(_pool, _data ? _data->getElement(index) : 0);
}
// Removes element at specified position.
FORCE_INLINE void remove(iterator it) const {
if (!_data)
return;
_data->removeSlot(it.internal());
}
// Removes element at specified index.
FORCE_INLINE void remove(size_t index) const {
if (!_data)
return;
_data->removeElement(index);
}
void clear() const {
if (!_data)
return;
_data->clear();
}
private:
MemoryPool* _pool;
};
template <>
struct Converter<ArrayConstRef> {
static void toJson(VariantConstRef src, VariantRef dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static ArrayConstRef fromJson(VariantConstRef src) {
return ArrayConstRef(variantAsArray(getData(src)));
}
static bool checkJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data && data->isArray();
}
};
template <>
struct Converter<ArrayRef> {
static void toJson(VariantConstRef src, VariantRef dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static ArrayRef fromJson(VariantRef src) {
VariantData* data = getData(src);
MemoryPool* pool = getPool(src);
return ArrayRef(pool, data != 0 ? data->asArray() : 0);
}
static InvalidConversion<VariantConstRef, ArrayRef> fromJson(VariantConstRef);
static bool checkJson(VariantConstRef) {
return false;
}
static bool checkJson(VariantRef src) {
VariantData* data = getData(src);
return data && data->isArray();
}
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -1,49 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Polyfills/attributes.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp>
namespace ARDUINOJSON_NAMESPACE {
// Forward declarations.
class ArrayRef;
class ObjectRef;
template <typename>
class ElementProxy;
template <typename TArray>
class ArrayShortcuts {
public:
// Returns the element at specified index if the variant is an array.
FORCE_INLINE ElementProxy<TArray> operator[](size_t index) const;
FORCE_INLINE ObjectRef createNestedObject() const;
FORCE_INLINE ArrayRef createNestedArray() const;
// Adds the specified value at the end of the array.
//
// bool add(TValue);
// TValue = bool, long, int, short, float, double, serialized, VariantRef,
// std::string, String, ObjectRef
template <typename T>
FORCE_INLINE bool add(const T &value) const {
return impl()->addElement().set(value);
}
//
// bool add(TValue);
// TValue = char*, const char*, const __FlashStringHelper*
template <typename T>
FORCE_INLINE bool add(T *value) const {
return impl()->addElement().set(value);
}
private:
const TArray *impl() const {
return static_cast<const TArray *>(this);
}
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -4,194 +4,57 @@
#pragma once #pragma once
#include <ArduinoJson/Configuration.hpp> #include <ArduinoJson/Variant/VariantRefBase.hpp>
#include <ArduinoJson/Variant/VariantOperators.hpp>
#include <ArduinoJson/Variant/VariantShortcuts.hpp>
#include <ArduinoJson/Variant/VariantTo.hpp>
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable : 4522)
#endif
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename TArray> // A proxy class to get or set an element of an array.
class ElementProxy : public VariantOperators<ElementProxy<TArray> >, // https://arduinojson.org/v6/api/jsonarray/subscript/
public VariantShortcuts<ElementProxy<TArray> >, template <typename TUpstream>
public Visitable, class ElementProxy : public VariantRefBase<ElementProxy<TUpstream> >,
public VariantTag { public VariantOperators<ElementProxy<TUpstream> > {
typedef ElementProxy<TArray> this_type; friend class VariantAttorney;
public: public:
typedef VariantRef variant_type; ElementProxy(TUpstream upstream, size_t index)
: _upstream(upstream), _index(index) {}
FORCE_INLINE ElementProxy(TArray array, size_t index) ElementProxy(const ElementProxy& src)
: _array(array), _index(index) {} : _upstream(src._upstream), _index(src._index) {}
FORCE_INLINE ElementProxy(const ElementProxy& src) FORCE_INLINE ElementProxy& operator=(const ElementProxy& src) {
: _array(src._array), _index(src._index) {} this->set(src);
FORCE_INLINE this_type& operator=(const this_type& src) {
getOrAddUpstreamElement().set(src.as<VariantConstRef>());
return *this; return *this;
} }
// Replaces the value
//
// operator=(const TValue&)
// TValue = bool, long, int, short, float, double, serialized, VariantRef,
// std::string, String, ArrayRef, ObjectRef
template <typename T> template <typename T>
FORCE_INLINE this_type& operator=(const T& src) { FORCE_INLINE ElementProxy& operator=(const T& src) {
getOrAddUpstreamElement().set(src); this->set(src);
return *this;
}
//
// operator=(TValue)
// TValue = char*, const char*, const __FlashStringHelper*
template <typename T>
FORCE_INLINE this_type& operator=(T* src) {
getOrAddUpstreamElement().set(src);
return *this; return *this;
} }
FORCE_INLINE void clear() const {
getUpstreamElement().clear();
}
FORCE_INLINE bool isNull() const {
return getUpstreamElement().isNull();
}
template <typename T> template <typename T>
FORCE_INLINE typename enable_if<!is_same<T, char*>::value, T>::type as() FORCE_INLINE ElementProxy& operator=(T* src) {
const { this->set(src);
return getUpstreamElement().template as<T>(); return *this;
}
template <typename T>
FORCE_INLINE typename enable_if<is_same<T, char*>::value, const char*>::type
ARDUINOJSON_DEPRECATED("Replace as<char*>() with as<const char*>()")
as() const {
return as<const char*>();
}
template <typename T>
FORCE_INLINE operator T() const {
return getUpstreamElement();
}
template <typename T>
FORCE_INLINE bool is() const {
return getUpstreamElement().template is<T>();
}
template <typename T>
FORCE_INLINE typename VariantTo<T>::type to() const {
return getOrAddUpstreamElement().template to<T>();
}
// Replaces the value
//
// bool set(const TValue&)
// TValue = bool, long, int, short, float, double, serialized, VariantRef,
// std::string, String, ArrayRef, ObjectRef
template <typename TValue>
FORCE_INLINE bool set(const TValue& value) const {
return getOrAddUpstreamElement().set(value);
}
//
// bool set(TValue)
// TValue = char*, const char*, const __FlashStringHelper*
template <typename TValue>
FORCE_INLINE bool set(TValue* value) const {
return getOrAddUpstreamElement().set(value);
}
template <typename TVisitor>
typename TVisitor::result_type accept(TVisitor& visitor) const {
return getUpstreamElement().accept(visitor);
}
FORCE_INLINE size_t size() const {
return getUpstreamElement().size();
}
FORCE_INLINE size_t memoryUsage() const {
return getUpstreamElement().memoryUsage();
}
template <typename TNestedKey>
VariantRef getMember(TNestedKey* key) const {
return getUpstreamElement().getMember(key);
}
template <typename TNestedKey>
VariantRef getMember(const TNestedKey& key) const {
return getUpstreamElement().getMember(key);
}
template <typename TNestedKey>
VariantRef getOrAddMember(TNestedKey* key) const {
return getOrAddUpstreamElement().getOrAddMember(key);
}
template <typename TNestedKey>
VariantRef getOrAddMember(const TNestedKey& key) const {
return getOrAddUpstreamElement().getOrAddMember(key);
}
VariantRef addElement() const {
return getOrAddUpstreamElement().addElement();
}
VariantRef getElement(size_t index) const {
return getOrAddUpstreamElement().getElement(index);
}
VariantRef getOrAddElement(size_t index) const {
return getOrAddUpstreamElement().getOrAddElement(index);
}
FORCE_INLINE void remove(size_t index) const {
getUpstreamElement().remove(index);
}
// remove(char*) const
// remove(const char*) const
// remove(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE typename enable_if<IsString<TChar*>::value>::type remove(
TChar* key) const {
getUpstreamElement().remove(key);
}
// remove(const std::string&) const
// remove(const String&) const
template <typename TString>
FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove(
const TString& key) const {
getUpstreamElement().remove(key);
} }
private: private:
FORCE_INLINE VariantRef getUpstreamElement() const { FORCE_INLINE MemoryPool* getPool() const {
return _array.getElement(_index); return VariantAttorney::getPool(_upstream);
} }
FORCE_INLINE VariantRef getOrAddUpstreamElement() const { FORCE_INLINE VariantData* getData() const {
return _array.getOrAddElement(_index); return variantGetElement(VariantAttorney::getData(_upstream), _index);
} }
friend void convertToJson(const this_type& src, VariantRef dst) { FORCE_INLINE VariantData* getOrCreateData() const {
dst.set(src.getUpstreamElement()); return variantGetOrAddElement(VariantAttorney::getOrCreateData(_upstream),
_index, VariantAttorney::getPool(_upstream));
} }
TArray _array; TUpstream _upstream;
const size_t _index; size_t _index;
}; };
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE
#ifdef _MSC_VER
# pragma warning(pop)
#endif

View File

@@ -0,0 +1,210 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/ElementProxy.hpp>
#include <ArduinoJson/Array/JsonArrayConst.hpp>
namespace ARDUINOJSON_NAMESPACE {
class JsonObject;
// A reference to an array in a JsonDocument
// https://arduinojson.org/v6/api/jsonarray/
class JsonArray : public VariantOperators<JsonArray> {
friend class VariantAttorney;
public:
typedef JsonArrayIterator iterator;
// Constructs an unbound reference.
FORCE_INLINE JsonArray() : _data(0), _pool(0) {}
// INTERNAL USE ONLY
FORCE_INLINE JsonArray(MemoryPool* pool, CollectionData* data)
: _data(data), _pool(pool) {}
// Returns a JsonVariant pointing to the array.
// https://arduinojson.org/v6/api/jsonvariant/
operator JsonVariant() {
void* data = _data; // prevent warning cast-align
return JsonVariant(_pool, reinterpret_cast<VariantData*>(data));
}
// Returns a read-only reference to the array.
// https://arduinojson.org/v6/api/jsonarrayconst/
operator JsonArrayConst() const {
return JsonArrayConst(_data);
}
// Appends a new (null) element to the array.
// Returns a reference to the new element.
// https://arduinojson.org/v6/api/jsonarray/add/
JsonVariant add() const {
if (!_data)
return JsonVariant();
return JsonVariant(_pool, _data->addElement(_pool));
}
// Appends a value to the array.
// https://arduinojson.org/v6/api/jsonarray/add/
template <typename T>
FORCE_INLINE bool add(const T& value) const {
return add().set(value);
}
// Appends a value to the array.
// https://arduinojson.org/v6/api/jsonarray/add/
template <typename T>
FORCE_INLINE bool add(T* value) const {
return add().set(value);
}
// Returns an iterator to the first element of the array.
// https://arduinojson.org/v6/api/jsonarray/begin/
FORCE_INLINE iterator begin() const {
if (!_data)
return iterator();
return iterator(_pool, _data->head());
}
// Returns an iterator following the last element of the array.
// https://arduinojson.org/v6/api/jsonarray/end/
FORCE_INLINE iterator end() const {
return iterator();
}
// Copies an array.
// https://arduinojson.org/v6/api/jsonarray/set/
FORCE_INLINE bool set(JsonArrayConst src) const {
if (!_data || !src._data)
return false;
return _data->copyFrom(*src._data, _pool);
}
// Compares the content of two arrays.
FORCE_INLINE bool operator==(JsonArray rhs) const {
return JsonArrayConst(_data) == JsonArrayConst(rhs._data);
}
// Removes the element at the specified iterator.
// ⚠️ Doesn't release the memory associated with the removed element.
// https://arduinojson.org/v6/api/jsonarray/remove/
FORCE_INLINE void remove(iterator it) const {
if (!_data)
return;
_data->removeSlot(it._slot);
}
// Removes the element at the specified index.
// ⚠️ Doesn't release the memory associated with the removed element.
// https://arduinojson.org/v6/api/jsonarray/remove/
FORCE_INLINE void remove(size_t index) const {
if (!_data)
return;
_data->removeElement(index);
}
// Removes all the elements of the array.
// ⚠️ Doesn't release the memory associated with the removed elements.
// https://arduinojson.org/v6/api/jsonarray/clear/
void clear() const {
if (!_data)
return;
_data->clear();
}
// Gets or sets the element at the specified index.
// https://arduinojson.org/v6/api/jsonarray/subscript/
FORCE_INLINE ElementProxy<JsonArray> operator[](size_t index) const {
return ElementProxy<JsonArray>(*this, index);
}
// Creates an object and appends it to the array.
// https://arduinojson.org/v6/api/jsonarray/createnestedobject/
FORCE_INLINE JsonObject createNestedObject() const;
// Creates an array and appends it to the array.
// https://arduinojson.org/v6/api/jsonarray/createnestedarray/
FORCE_INLINE JsonArray createNestedArray() const {
return add().to<JsonArray>();
}
operator JsonVariantConst() const {
return JsonVariantConst(collectionToVariant(_data));
}
// Returns true if the reference is unbound.
// https://arduinojson.org/v6/api/jsonarray/isnull/
FORCE_INLINE bool isNull() const {
return _data == 0;
}
// Returns true if the reference is bound.
// https://arduinojson.org/v6/api/jsonarray/isnull/
FORCE_INLINE operator bool() const {
return _data != 0;
}
// Returns the number of bytes occupied by the array.
// https://arduinojson.org/v6/api/jsonarray/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return _data ? _data->memoryUsage() : 0;
}
// Returns the depth (nesting level) of the array.
// https://arduinojson.org/v6/api/jsonarray/nesting/
FORCE_INLINE size_t nesting() const {
return variantNesting(collectionToVariant(_data));
}
// Returns the number of elements in the array.
// https://arduinojson.org/v6/api/jsonarray/size/
FORCE_INLINE size_t size() const {
return _data ? _data->size() : 0;
}
private:
MemoryPool* getPool() const {
return _pool;
}
VariantData* getData() const {
return collectionToVariant(_data);
}
VariantData* getOrCreateData() const {
return collectionToVariant(_data);
}
CollectionData* _data;
MemoryPool* _pool;
};
template <>
struct Converter<JsonArray> : private VariantAttorney {
static void toJson(JsonVariantConst src, JsonVariant dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static JsonArray fromJson(JsonVariant src) {
VariantData* data = getData(src);
MemoryPool* pool = getPool(src);
return JsonArray(pool, data != 0 ? data->asArray() : 0);
}
static InvalidConversion<JsonVariantConst, JsonArray> fromJson(
JsonVariantConst);
static bool checkJson(JsonVariantConst) {
return false;
}
static bool checkJson(JsonVariant src) {
VariantData* data = getData(src);
return data && data->isArray();
}
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -0,0 +1,134 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/JsonArrayIterator.hpp>
#include <ArduinoJson/Variant/VariantAttorney.hpp>
#include <ArduinoJson/Variant/VariantData.hpp>
namespace ARDUINOJSON_NAMESPACE {
class JsonObject;
// A read-only reference to an array in a JsonDocument
// https://arduinojson.org/v6/api/jsonarrayconst/
class JsonArrayConst : public VariantOperators<JsonArrayConst> {
friend class JsonArray;
friend class VariantAttorney;
public:
typedef JsonArrayConstIterator iterator;
// Returns an iterator to the first element of the array.
// https://arduinojson.org/v6/api/jsonarrayconst/begin/
FORCE_INLINE iterator begin() const {
if (!_data)
return iterator();
return iterator(_data->head());
}
// Returns an iterator to the element following the last element of the array.
// https://arduinojson.org/v6/api/jsonarrayconst/end/
FORCE_INLINE iterator end() const {
return iterator();
}
// Creates an unbound reference.
FORCE_INLINE JsonArrayConst() : _data(0) {}
// INTERNAL USE ONLY
FORCE_INLINE JsonArrayConst(const CollectionData* data) : _data(data) {}
// Compares the content of two arrays.
// Returns true if the two arrays are equal.
FORCE_INLINE bool operator==(JsonArrayConst rhs) const {
if (_data == rhs._data)
return true;
if (!_data || !rhs._data)
return false;
iterator it1 = begin();
iterator it2 = rhs.begin();
for (;;) {
bool end1 = it1 == end();
bool end2 = it2 == rhs.end();
if (end1 && end2)
return true;
if (end1 || end2)
return false;
if (*it1 != *it2)
return false;
++it1;
++it2;
}
}
// Returns the element at the specified index.
// https://arduinojson.org/v6/api/jsonarrayconst/subscript/
FORCE_INLINE JsonVariantConst operator[](size_t index) const {
return JsonVariantConst(_data ? _data->getElement(index) : 0);
}
operator JsonVariantConst() const {
return JsonVariantConst(collectionToVariant(_data));
}
// Returns true if the reference is unbound.
// https://arduinojson.org/v6/api/jsonarrayconst/isnull/
FORCE_INLINE bool isNull() const {
return _data == 0;
}
// Returns true if the reference is bound.
// https://arduinojson.org/v6/api/jsonarrayconst/isnull/
FORCE_INLINE operator bool() const {
return _data != 0;
}
// Returns the number of bytes occupied by the array.
// https://arduinojson.org/v6/api/jsonarrayconst/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return _data ? _data->memoryUsage() : 0;
}
// Returns the depth (nesting level) of the array.
// https://arduinojson.org/v6/api/jsonarrayconst/nesting/
FORCE_INLINE size_t nesting() const {
return variantNesting(collectionToVariant(_data));
}
// Returns the number of elements in the array.
// https://arduinojson.org/v6/api/jsonarrayconst/size/
FORCE_INLINE size_t size() const {
return _data ? _data->size() : 0;
}
private:
const VariantData* getData() const {
return collectionToVariant(_data);
}
const CollectionData* _data;
};
template <>
struct Converter<JsonArrayConst> : private VariantAttorney {
static void toJson(JsonVariantConst src, JsonVariant dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static JsonArrayConst fromJson(JsonVariantConst src) {
const VariantData* data = getData(src);
return data ? data->asArray() : 0;
}
static bool checkJson(JsonVariantConst src) {
const VariantData* data = getData(src);
return data && data->isArray();
}
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -0,0 +1,32 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/JsonArray.hpp>
#include <ArduinoJson/Object/JsonObject.hpp>
namespace ARDUINOJSON_NAMESPACE {
inline JsonObject JsonArray::createNestedObject() const {
return add().to<JsonObject>();
}
template <typename TDerived>
inline JsonArray VariantRefBase<TDerived>::createNestedArray() const {
return add().template to<JsonArray>();
}
template <typename TDerived>
inline JsonObject VariantRefBase<TDerived>::createNestedObject() const {
return add().template to<JsonObject>();
}
template <typename TDerived>
inline ElementProxy<TDerived> VariantRefBase<TDerived>::operator[](
size_t index) const {
return ElementProxy<TDerived>(derived(), index);
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -0,0 +1,117 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Variant/JsonVariant.hpp>
#include <ArduinoJson/Variant/SlotFunctions.hpp>
namespace ARDUINOJSON_NAMESPACE {
class VariantPtr {
public:
VariantPtr(MemoryPool* pool, VariantData* data) : _variant(pool, data) {}
JsonVariant* operator->() {
return &_variant;
}
JsonVariant& operator*() {
return _variant;
}
private:
JsonVariant _variant;
};
class JsonArrayIterator {
friend class JsonArray;
public:
JsonArrayIterator() : _slot(0) {}
explicit JsonArrayIterator(MemoryPool* pool, VariantSlot* slot)
: _pool(pool), _slot(slot) {}
JsonVariant operator*() const {
return JsonVariant(_pool, _slot->data());
}
VariantPtr operator->() {
return VariantPtr(_pool, _slot->data());
}
bool operator==(const JsonArrayIterator& other) const {
return _slot == other._slot;
}
bool operator!=(const JsonArrayIterator& other) const {
return _slot != other._slot;
}
JsonArrayIterator& operator++() {
_slot = _slot->next();
return *this;
}
JsonArrayIterator& operator+=(size_t distance) {
_slot = _slot->next(distance);
return *this;
}
private:
MemoryPool* _pool;
VariantSlot* _slot;
};
class VariantConstPtr {
public:
VariantConstPtr(const VariantData* data) : _variant(data) {}
JsonVariantConst* operator->() {
return &_variant;
}
JsonVariantConst& operator*() {
return _variant;
}
private:
JsonVariantConst _variant;
};
class JsonArrayConstIterator {
friend class JsonArray;
public:
JsonArrayConstIterator() : _slot(0) {}
explicit JsonArrayConstIterator(const VariantSlot* slot) : _slot(slot) {}
JsonVariantConst operator*() const {
return JsonVariantConst(_slot->data());
}
VariantConstPtr operator->() {
return VariantConstPtr(_slot->data());
}
bool operator==(const JsonArrayConstIterator& other) const {
return _slot == other._slot;
}
bool operator!=(const JsonArrayConstIterator& other) const {
return _slot != other._slot;
}
JsonArrayConstIterator& operator++() {
_slot = _slot->next();
return *this;
}
JsonArrayConstIterator& operator+=(size_t distance) {
_slot = _slot->next(distance);
return *this;
}
private:
const VariantSlot* _slot;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -4,19 +4,21 @@
#pragma once #pragma once
#include <ArduinoJson/Array/ArrayRef.hpp> #include <ArduinoJson/Array/JsonArray.hpp>
#include <ArduinoJson/Document/JsonDocument.hpp> #include <ArduinoJson/Document/JsonDocument.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
// Trivial form to stop the recursion // Copies a value to a JsonVariant.
// This is a degenerated form of copyArray() to stop the recursion.
template <typename T> template <typename T>
inline typename enable_if<!is_array<T>::value, bool>::type copyArray( inline typename enable_if<!is_array<T>::value, bool>::type copyArray(
const T& src, VariantRef dst) { const T& src, JsonVariant dst) {
return dst.set(src); return dst.set(src);
} }
// Copy array to a JsonArray/JsonVariant/MemberProxy/ElementProxy // Copies values from an array to a JsonArray or a JsonVariant.
// https://arduinojson.org/v6/api/misc/copyarray/
template <typename T, size_t N, typename TDestination> template <typename T, size_t N, typename TDestination>
inline typename enable_if<!is_base_of<JsonDocument, TDestination>::value, inline typename enable_if<!is_base_of<JsonDocument, TDestination>::value,
bool>::type bool>::type
@@ -24,64 +26,72 @@ copyArray(T (&src)[N], const TDestination& dst) {
return copyArray(src, N, dst); return copyArray(src, N, dst);
} }
// Copy ptr+size to a JsonArray/JsonVariant/MemberProxy/ElementProxy // Copies values from an array to a JsonArray or a JsonVariant.
// https://arduinojson.org/v6/api/misc/copyarray/
template <typename T, typename TDestination> template <typename T, typename TDestination>
inline typename enable_if<!is_base_of<JsonDocument, TDestination>::value, inline typename enable_if<!is_base_of<JsonDocument, TDestination>::value,
bool>::type bool>::type
copyArray(const T* src, size_t len, const TDestination& dst) { copyArray(const T* src, size_t len, const TDestination& dst) {
bool ok = true; bool ok = true;
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) {
ok &= copyArray(src[i], dst.addElement()); ok &= copyArray(src[i], dst.add());
} }
return ok; return ok;
} }
// Special case for char[] which much be treated as const char* // Copies a string to a JsonVariant.
// This is a degenerated form of copyArray() to handle strings.
template <typename TDestination> template <typename TDestination>
inline bool copyArray(const char* src, size_t, const TDestination& dst) { inline bool copyArray(const char* src, size_t, const TDestination& dst) {
return dst.set(src); return dst.set(src);
} }
// Copy array to a JsonDocument // Copies values from an array to a JsonDocument.
// https://arduinojson.org/v6/api/misc/copyarray/
template <typename T> template <typename T>
inline bool copyArray(const T& src, JsonDocument& dst) { inline bool copyArray(const T& src, JsonDocument& dst) {
return copyArray(src, dst.to<ArrayRef>()); return copyArray(src, dst.to<JsonArray>());
} }
// Copy a ptr+size array to a JsonDocument // Copies an array to a JsonDocument.
// https://arduinojson.org/v6/api/misc/copyarray/
template <typename T> template <typename T>
inline bool copyArray(const T* src, size_t len, JsonDocument& dst) { inline bool copyArray(const T* src, size_t len, JsonDocument& dst) {
return copyArray(src, len, dst.to<ArrayRef>()); return copyArray(src, len, dst.to<JsonArray>());
} }
// Trivial case form to stop the recursion // Copies a value from a JsonVariant.
// This is a degenerated form of copyArray() to stop the recursion.
template <typename T> template <typename T>
inline typename enable_if<!is_array<T>::value, size_t>::type copyArray( inline typename enable_if<!is_array<T>::value, size_t>::type copyArray(
VariantConstRef src, T& dst) { JsonVariantConst src, T& dst) {
dst = src.as<T>(); dst = src.as<T>();
return 1; return 1;
} }
// Copy a JsonArray to array // Copies values from a JsonArray or JsonVariant to an array.
// https://arduinojson.org/v6/api/misc/copyarray/
template <typename T, size_t N> template <typename T, size_t N>
inline size_t copyArray(ArrayConstRef src, T (&dst)[N]) { inline size_t copyArray(JsonArrayConst src, T (&dst)[N]) {
return copyArray(src, dst, N); return copyArray(src, dst, N);
} }
// Copy a JsonArray to ptr+size // Copies values from a JsonArray or JsonVariant to an array.
// https://arduinojson.org/v6/api/misc/copyarray/
template <typename T> template <typename T>
inline size_t copyArray(ArrayConstRef src, T* dst, size_t len) { inline size_t copyArray(JsonArrayConst src, T* dst, size_t len) {
size_t i = 0; size_t i = 0;
for (ArrayConstRef::iterator it = src.begin(); it != src.end() && i < len; for (JsonArrayConst::iterator it = src.begin(); it != src.end() && i < len;
++it) ++it)
copyArray(*it, dst[i++]); copyArray(*it, dst[i++]);
return i; return i;
} }
// Special case for char[] which must be treated as a string // Copies a string from a JsonVariant.
// This is a degenerated form of copyArray() to handle strings.
template <size_t N> template <size_t N>
inline size_t copyArray(VariantConstRef src, char (&dst)[N]) { inline size_t copyArray(JsonVariantConst src, char (&dst)[N]) {
String s = src; JsonString s = src;
size_t len = N - 1; size_t len = N - 1;
if (len > s.size()) if (len > s.size())
len = s.size(); len = s.size();
@@ -90,14 +100,14 @@ inline size_t copyArray(VariantConstRef src, char (&dst)[N]) {
return 1; return 1;
} }
// Copy a JsonDocument to an array // Copies values from a JsonDocument to an array.
// (JsonDocument doesn't implicitly convert to JsonArrayConst) // https://arduinojson.org/v6/api/misc/copyarray/
template <typename TSource, typename T> template <typename TSource, typename T>
inline typename enable_if<is_array<T>::value && inline typename enable_if<is_array<T>::value &&
is_base_of<JsonDocument, TSource>::value, is_base_of<JsonDocument, TSource>::value,
size_t>::type size_t>::type
copyArray(const TSource& src, T& dst) { copyArray(const TSource& src, T& dst) {
return copyArray(src.template as<ArrayConstRef>(), dst); return copyArray(src.template as<JsonArrayConst>(), dst);
} }
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -16,8 +16,8 @@ class VariantData;
class VariantSlot; class VariantSlot;
class CollectionData { class CollectionData {
VariantSlot *_head; VariantSlot* _head;
VariantSlot *_tail; VariantSlot* _tail;
public: public:
// Must be a POD! // Must be a POD!
@@ -28,27 +28,24 @@ class CollectionData {
// Array only // Array only
VariantData *addElement(MemoryPool *pool); VariantData* addElement(MemoryPool* pool);
VariantData *getElement(size_t index) const; VariantData* getElement(size_t index) const;
VariantData *getOrAddElement(size_t index, MemoryPool *pool); VariantData* getOrAddElement(size_t index, MemoryPool* pool);
void removeElement(size_t index); void removeElement(size_t index);
bool equalsArray(const CollectionData &other) const;
// Object only // Object only
template <typename TAdaptedString, typename TStoragePolicy> template <typename TAdaptedString>
VariantData *addMember(TAdaptedString key, MemoryPool *pool, TStoragePolicy); VariantData* addMember(TAdaptedString key, MemoryPool* pool);
template <typename TAdaptedString> template <typename TAdaptedString>
VariantData *getMember(TAdaptedString key) const; VariantData* getMember(TAdaptedString key) const;
template <typename TAdaptedString, typename TStoragePolicy> template <typename TAdaptedString>
VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool, VariantData* getOrAddMember(TAdaptedString key, MemoryPool* pool);
TStoragePolicy);
template <typename TAdaptedString> template <typename TAdaptedString>
void removeMember(TAdaptedString key) { void removeMember(TAdaptedString key) {
@@ -56,34 +53,42 @@ class CollectionData {
} }
template <typename TAdaptedString> template <typename TAdaptedString>
bool containsKey(const TAdaptedString &key) const; bool containsKey(const TAdaptedString& key) const;
bool equalsObject(const CollectionData &other) const;
// Generic // Generic
void clear(); void clear();
size_t memoryUsage() const; size_t memoryUsage() const;
size_t nesting() const;
size_t size() const; size_t size() const;
VariantSlot *addSlot(MemoryPool *); VariantSlot* addSlot(MemoryPool*);
void removeSlot(VariantSlot *slot); void removeSlot(VariantSlot* slot);
bool copyFrom(const CollectionData &src, MemoryPool *pool); bool copyFrom(const CollectionData& src, MemoryPool* pool);
VariantSlot *head() const { VariantSlot* head() const {
return _head; return _head;
} }
void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance); void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance);
private: private:
VariantSlot *getSlot(size_t index) const; VariantSlot* getSlot(size_t index) const;
template <typename TAdaptedString> template <typename TAdaptedString>
VariantSlot *getSlot(TAdaptedString key) const; VariantSlot* getSlot(TAdaptedString key) const;
VariantSlot *getPreviousSlot(VariantSlot *) const; VariantSlot* getPreviousSlot(VariantSlot*) const;
}; };
inline const VariantData* collectionToVariant(
const CollectionData* collection) {
const void* data = collection; // prevent warning cast-align
return reinterpret_cast<const VariantData*>(data);
}
inline VariantData* collectionToVariant(CollectionData* collection) {
void* data = collection; // prevent warning cast-align
return reinterpret_cast<VariantData*>(data);
}
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -11,16 +11,13 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
inline bool variantEquals(const VariantData* a, const VariantData* b) {
return variantCompare(a, b) == COMPARE_RESULT_EQUAL;
}
inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) { inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) {
VariantSlot* slot = pool->allocVariant(); VariantSlot* slot = pool->allocVariant();
if (!slot) if (!slot)
return 0; return 0;
if (_tail) { if (_tail) {
ARDUINOJSON_ASSERT(pool->owns(_tail)); // Can't alter a linked array/object
_tail->setNextNotNull(slot); _tail->setNextNotNull(slot);
_tail = slot; _tail = slot;
} else { } else {
@@ -36,12 +33,11 @@ inline VariantData* CollectionData::addElement(MemoryPool* pool) {
return slotData(addSlot(pool)); return slotData(addSlot(pool));
} }
template <typename TAdaptedString, typename TStoragePolicy> template <typename TAdaptedString>
inline VariantData* CollectionData::addMember(TAdaptedString key, inline VariantData* CollectionData::addMember(TAdaptedString key,
MemoryPool* pool, MemoryPool* pool) {
TStoragePolicy storage) {
VariantSlot* slot = addSlot(pool); VariantSlot* slot = addSlot(pool);
if (!slotSetKey(slot, key, pool, storage)) { if (!slotSetKey(slot, key, pool)) {
removeSlot(slot); removeSlot(slot);
return 0; return 0;
} }
@@ -64,8 +60,9 @@ inline bool CollectionData::copyFrom(const CollectionData& src,
for (VariantSlot* s = src._head; s; s = s->next()) { for (VariantSlot* s = src._head; s; s = s->next()) {
VariantData* var; VariantData* var;
if (s->key() != 0) { if (s->key() != 0) {
String key(s->key(), s->ownsKey() ? String::Copied : String::Linked); JsonString key(s->key(),
var = addMember(adaptString(key), pool, getStringStoragePolicy(key)); s->ownsKey() ? JsonString::Copied : JsonString::Linked);
var = addMember(adaptString(key), pool);
} else { } else {
var = addElement(pool); var = addElement(pool);
} }
@@ -77,33 +74,6 @@ inline bool CollectionData::copyFrom(const CollectionData& src,
return true; return true;
} }
inline bool CollectionData::equalsObject(const CollectionData& other) const {
size_t count = 0;
for (VariantSlot* slot = _head; slot; slot = slot->next()) {
VariantData* v1 = slot->data();
VariantData* v2 = other.getMember(adaptString(slot->key()));
if (!variantEquals(v1, v2))
return false;
count++;
}
return count == other.size();
}
inline bool CollectionData::equalsArray(const CollectionData& other) const {
VariantSlot* s1 = _head;
VariantSlot* s2 = other._head;
for (;;) {
if (s1 == s2)
return true;
if (!s1 || !s2)
return false;
if (!variantEquals(s1->data(), s2->data()))
return false;
s1 = s1->next();
s2 = s2->next();
}
}
template <typename TAdaptedString> template <typename TAdaptedString>
inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const { inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const {
if (key.isNull()) if (key.isNull())
@@ -140,9 +110,9 @@ inline VariantData* CollectionData::getMember(TAdaptedString key) const {
return slot ? slot->data() : 0; return slot ? slot->data() : 0;
} }
template <typename TAdaptedString, typename TStoragePolicy> template <typename TAdaptedString>
inline VariantData* CollectionData::getOrAddMember( inline VariantData* CollectionData::getOrAddMember(TAdaptedString key,
TAdaptedString key, MemoryPool* pool, TStoragePolicy storage_policy) { MemoryPool* pool) {
// ignore null key // ignore null key
if (key.isNull()) if (key.isNull())
return 0; return 0;
@@ -152,7 +122,7 @@ inline VariantData* CollectionData::getOrAddMember(
if (slot) if (slot)
return slot->data(); return slot->data();
return addMember(key, pool, storage_policy); return addMember(key, pool);
} }
inline VariantData* CollectionData::getElement(size_t index) const { inline VariantData* CollectionData::getElement(size_t index) const {
@@ -203,16 +173,6 @@ inline size_t CollectionData::memoryUsage() const {
return total; return total;
} }
inline size_t CollectionData::nesting() const {
size_t maxChildNesting = 0;
for (VariantSlot* s = _head; s; s = s->next()) {
size_t childNesting = s->data()->nesting();
if (childNesting > maxChildNesting)
maxChildNesting = childNesting;
}
return maxChildNesting + 1;
}
inline size_t CollectionData::size() const { inline size_t CollectionData::size() const {
return slotSize(_head); return slotSize(_head);
} }

View File

@@ -10,18 +10,18 @@ namespace ARDUINOJSON_NAMESPACE {
class Filter { class Filter {
public: public:
explicit Filter(VariantConstRef v) : _variant(v) {} explicit Filter(JsonVariantConst v) : _variant(v) {}
bool allow() const { bool allow() const {
return _variant; return _variant;
} }
bool allowArray() const { bool allowArray() const {
return _variant == true || _variant.is<ArrayConstRef>(); return _variant == true || _variant.is<JsonArrayConst>();
} }
bool allowObject() const { bool allowObject() const {
return _variant == true || _variant.is<ObjectConstRef>(); return _variant == true || _variant.is<JsonObjectConst>();
} }
bool allowValue() const { bool allowValue() const {
@@ -32,12 +32,12 @@ class Filter {
Filter operator[](const TKey& key) const { Filter operator[](const TKey& key) const {
if (_variant == true) // "true" means "allow recursively" if (_variant == true) // "true" means "allow recursively"
return *this; return *this;
VariantConstRef member = _variant[key]; JsonVariantConst member = _variant[key];
return Filter(member.isNull() ? _variant["*"] : member); return Filter(member.isNull() ? _variant["*"] : member);
} }
private: private:
VariantConstRef _variant; JsonVariantConst _variant;
}; };
struct AllowAllFilter { struct AllowAllFilter {

View File

@@ -23,7 +23,8 @@ class IteratorReader {
size_t readBytes(char* buffer, size_t length) { size_t readBytes(char* buffer, size_t length) {
size_t i = 0; size_t i = 0;
while (i < length && _ptr < _end) buffer[i++] = *_ptr++; while (i < length && _ptr < _end)
buffer[i++] = *_ptr++;
return i; return i;
} }
}; };

View File

@@ -32,7 +32,8 @@ struct Reader<TSource*,
} }
size_t readBytes(char* buffer, size_t length) { size_t readBytes(char* buffer, size_t length) {
for (size_t i = 0; i < length; i++) buffer[i] = *_ptr++; for (size_t i = 0; i < length; i++)
buffer[i] = *_ptr++;
return length; return length;
} }
}; };

View File

@@ -5,30 +5,15 @@
#pragma once #pragma once
#include <ArduinoJson/Object/MemberProxy.hpp> #include <ArduinoJson/Object/MemberProxy.hpp>
#include <ArduinoJson/Variant/VariantRef.hpp> #include <ArduinoJson/Variant/JsonVariantConst.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename TArray> template <typename TVariant>
struct Reader<ElementProxy<TArray>, void> : Reader<char*, void> { struct Reader<TVariant, typename enable_if<IsVariant<TVariant>::value>::type>
explicit Reader(const ElementProxy<TArray>& x) : Reader<char*, void> {
explicit Reader(const TVariant& x)
: Reader<char*, void>(x.template as<const char*>()) {} : Reader<char*, void>(x.template as<const char*>()) {}
}; };
template <typename TObject, typename TStringRef>
struct Reader<MemberProxy<TObject, TStringRef>, void> : Reader<char*, void> {
explicit Reader(const MemberProxy<TObject, TStringRef>& x)
: Reader<char*, void>(x.template as<const char*>()) {}
};
template <>
struct Reader<VariantRef, void> : Reader<char*, void> {
explicit Reader(VariantRef x) : Reader<char*, void>(x.as<const char*>()) {}
};
template <>
struct Reader<VariantConstRef, void> : Reader<char*, void> {
explicit Reader(VariantConstRef x)
: Reader<char*, void>(x.as<const char*>()) {}
};
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -14,9 +14,10 @@ namespace ARDUINOJSON_NAMESPACE {
template <template <typename, typename> class TDeserializer, typename TReader, template <template <typename, typename> class TDeserializer, typename TReader,
typename TWriter> typename TWriter>
TDeserializer<TReader, TWriter> makeDeserializer(MemoryPool &pool, TDeserializer<TReader, TWriter> makeDeserializer(MemoryPool* pool,
TReader reader, TReader reader,
TWriter writer) { TWriter writer) {
ARDUINOJSON_ASSERT(pool != 0);
return TDeserializer<TReader, TWriter>(pool, reader, writer); return TDeserializer<TReader, TWriter>(pool, reader, writer);
} }
@@ -28,14 +29,15 @@ TDeserializer<TReader, TWriter> makeDeserializer(MemoryPool &pool,
template <template <typename, typename> class TDeserializer, typename TString, template <template <typename, typename> class TDeserializer, typename TString,
typename TFilter> typename TFilter>
typename enable_if<!is_array<TString>::value, DeserializationError>::type typename enable_if<!is_array<TString>::value, DeserializationError>::type
deserialize(JsonDocument &doc, const TString &input, NestingLimit nestingLimit, deserialize(JsonDocument& doc, const TString& input, NestingLimit nestingLimit,
TFilter filter) { TFilter filter) {
Reader<TString> reader(input); Reader<TString> reader(input);
VariantData* data = VariantAttorney::getData(doc);
MemoryPool* pool = VariantAttorney::getPool(doc);
doc.clear(); doc.clear();
return makeDeserializer<TDeserializer>( return makeDeserializer<TDeserializer>(pool, reader,
doc.memoryPool(), reader, makeStringStorage(input, pool))
makeStringStorage(input, doc.memoryPool())) .parse(*data, filter, nestingLimit);
.parse(doc.data(), filter, nestingLimit);
} }
// //
// deserialize(JsonDocument&, char*, size_t, NestingLimit, Filter); // deserialize(JsonDocument&, char*, size_t, NestingLimit, Filter);
@@ -43,29 +45,31 @@ deserialize(JsonDocument &doc, const TString &input, NestingLimit nestingLimit,
// deserialize(JsonDocument&, const __FlashStringHelper*, size_t, NL, Filter); // deserialize(JsonDocument&, const __FlashStringHelper*, size_t, NL, Filter);
template <template <typename, typename> class TDeserializer, typename TChar, template <template <typename, typename> class TDeserializer, typename TChar,
typename TFilter> typename TFilter>
DeserializationError deserialize(JsonDocument &doc, TChar *input, DeserializationError deserialize(JsonDocument& doc, TChar* input,
size_t inputSize, NestingLimit nestingLimit, size_t inputSize, NestingLimit nestingLimit,
TFilter filter) { TFilter filter) {
BoundedReader<TChar *> reader(input, inputSize); BoundedReader<TChar*> reader(input, inputSize);
VariantData* data = VariantAttorney::getData(doc);
MemoryPool* pool = VariantAttorney::getPool(doc);
doc.clear(); doc.clear();
return makeDeserializer<TDeserializer>( return makeDeserializer<TDeserializer>(pool, reader,
doc.memoryPool(), reader, makeStringStorage(input, pool))
makeStringStorage(input, doc.memoryPool())) .parse(*data, filter, nestingLimit);
.parse(doc.data(), filter, nestingLimit);
} }
// //
// deserialize(JsonDocument&, std::istream&, NestingLimit, Filter); // deserialize(JsonDocument&, std::istream&, NestingLimit, Filter);
// deserialize(JsonDocument&, Stream&, NestingLimit, Filter); // deserialize(JsonDocument&, Stream&, NestingLimit, Filter);
template <template <typename, typename> class TDeserializer, typename TStream, template <template <typename, typename> class TDeserializer, typename TStream,
typename TFilter> typename TFilter>
DeserializationError deserialize(JsonDocument &doc, TStream &input, DeserializationError deserialize(JsonDocument& doc, TStream& input,
NestingLimit nestingLimit, TFilter filter) { NestingLimit nestingLimit, TFilter filter) {
Reader<TStream> reader(input); Reader<TStream> reader(input);
VariantData* data = VariantAttorney::getData(doc);
MemoryPool* pool = VariantAttorney::getPool(doc);
doc.clear(); doc.clear();
return makeDeserializer<TDeserializer>( return makeDeserializer<TDeserializer>(pool, reader,
doc.memoryPool(), reader, makeStringStorage(input, pool))
makeStringStorage(input, doc.memoryPool())) .parse(*data, filter, nestingLimit);
.parse(doc.data(), filter, nestingLimit);
} }
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -37,6 +37,8 @@ class AllocatorOwner {
TAllocator _allocator; TAllocator _allocator;
}; };
// A JsonDocument that uses the provided allocator to allocate its memory pool.
// https://arduinojson.org/v6/api/basicjsondocument/
template <typename TAllocator> template <typename TAllocator>
class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument { class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument {
public: public:
@@ -65,16 +67,16 @@ class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument {
BasicJsonDocument( BasicJsonDocument(
const T& src, const T& src,
typename enable_if< typename enable_if<
is_same<T, VariantRef>::value || is_same<T, VariantConstRef>::value || is_same<T, JsonVariant>::value ||
is_same<T, ArrayRef>::value || is_same<T, ArrayConstRef>::value || is_same<T, JsonVariantConst>::value || is_same<T, JsonArray>::value ||
is_same<T, ObjectRef>::value || is_same<T, JsonArrayConst>::value || is_same<T, JsonObject>::value ||
is_same<T, ObjectConstRef>::value>::type* = 0) is_same<T, JsonObjectConst>::value>::type* = 0)
: JsonDocument(allocPool(src.memoryUsage())) { : JsonDocument(allocPool(src.memoryUsage())) {
set(src); set(src);
} }
// disambiguate // disambiguate
BasicJsonDocument(VariantRef src) BasicJsonDocument(JsonVariant src)
: JsonDocument(allocPool(src.memoryUsage())) { : JsonDocument(allocPool(src.memoryUsage())) {
set(src); set(src);
} }
@@ -104,6 +106,8 @@ class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument {
return *this; return *this;
} }
// Reduces the capacity of the memory pool to match the current usage.
// https://arduinojson.org/v6/api/basicjsondocument/shrinktofit/
void shrinkToFit() { void shrinkToFit() {
ptrdiff_t bytes_reclaimed = _pool.squash(); ptrdiff_t bytes_reclaimed = _pool.squash();
if (bytes_reclaimed == 0) if (bytes_reclaimed == 0)
@@ -119,6 +123,8 @@ class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument {
_data.movePointers(ptr_offset, ptr_offset - bytes_reclaimed); _data.movePointers(ptr_offset, ptr_offset - bytes_reclaimed);
} }
// Reclaims the memory leaked when removing and replacing values.
// https://arduinojson.org/v6/api/jsondocument/garbagecollect/
bool garbageCollect() { bool garbageCollect() {
// make a temporary clone and move assign // make a temporary clone and move assign
BasicJsonDocument tmp(*this); BasicJsonDocument tmp(*this);
@@ -146,7 +152,7 @@ class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument {
} }
void freePool() { void freePool() {
this->deallocate(memoryPool().buffer()); this->deallocate(getPool()->buffer());
} }
void copyAssignFrom(const JsonDocument& src) { void copyAssignFrom(const JsonDocument& src) {

View File

@@ -10,6 +10,7 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
// The allocator of DynamicJsonDocument.
struct DefaultAllocator { struct DefaultAllocator {
void* allocate(size_t size) { void* allocate(size_t size) {
return malloc(size); return malloc(size);
@@ -24,6 +25,8 @@ struct DefaultAllocator {
} }
}; };
// A JsonDocument with a memory pool in the heap.
// https://arduinojson.org/v6/api/dynamicjsondocument/
typedef BasicJsonDocument<DefaultAllocator> DynamicJsonDocument; typedef BasicJsonDocument<DefaultAllocator> DynamicJsonDocument;
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -6,152 +6,169 @@
#include <ArduinoJson/Array/ElementProxy.hpp> #include <ArduinoJson/Array/ElementProxy.hpp>
#include <ArduinoJson/Memory/MemoryPool.hpp> #include <ArduinoJson/Memory/MemoryPool.hpp>
#include <ArduinoJson/Object/JsonObject.hpp>
#include <ArduinoJson/Object/MemberProxy.hpp> #include <ArduinoJson/Object/MemberProxy.hpp>
#include <ArduinoJson/Object/ObjectRef.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp> #include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Variant/VariantRef.hpp> #include <ArduinoJson/Variant/JsonVariantConst.hpp>
#include <ArduinoJson/Variant/VariantTo.hpp> #include <ArduinoJson/Variant/VariantTo.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
class JsonDocument : public Visitable, // A JSON document.
public VariantOperators<const JsonDocument&> { // https://arduinojson.org/v6/api/jsondocument/
public: class JsonDocument : public VariantOperators<const JsonDocument&> {
template <typename TVisitor> friend class VariantAttorney;
typename TVisitor::result_type accept(TVisitor& visitor) const {
return getVariant().accept(visitor);
}
public:
// Casts the root to the specified type.
// https://arduinojson.org/v6/api/jsondocument/as/
template <typename T> template <typename T>
T as() { T as() {
return getVariant().template as<T>(); return getVariant().template as<T>();
} }
// Casts the root to the specified type.
// https://arduinojson.org/v6/api/jsondocument/as/
template <typename T> template <typename T>
T as() const { T as() const {
return getVariant().template as<T>(); return getVariant().template as<T>();
} }
// Empties the document and resets the memory pool
// https://arduinojson.org/v6/api/jsondocument/clear/
void clear() { void clear() {
_pool.clear(); _pool.clear();
_data.init(); _data.init();
} }
// Returns true if the root is of the specified type.
// https://arduinojson.org/v6/api/jsondocument/is/
template <typename T> template <typename T>
bool is() { bool is() {
return getVariant().template is<T>(); return getVariant().template is<T>();
} }
// Returns true if the root is of the specified type.
// https://arduinojson.org/v6/api/jsondocument/is/
template <typename T> template <typename T>
bool is() const { bool is() const {
return getVariant().template is<T>(); return getVariant().template is<T>();
} }
// Returns true if the root is null.
// https://arduinojson.org/v6/api/jsondocument/isnull/
bool isNull() const { bool isNull() const {
return getVariant().isNull(); return getVariant().isNull();
} }
// Returns the number of used bytes in the memory pool.
// https://arduinojson.org/v6/api/jsondocument/memoryusage/
size_t memoryUsage() const { size_t memoryUsage() const {
return _pool.size(); return _pool.size();
} }
// Returns trues if the memory pool was too small.
// https://arduinojson.org/v6/api/jsondocument/overflowed/
bool overflowed() const { bool overflowed() const {
return _pool.overflowed(); return _pool.overflowed();
} }
// Returns the depth (nesting level) of the array.
// https://arduinojson.org/v6/api/jsondocument/nesting/
size_t nesting() const { size_t nesting() const {
return _data.nesting(); return variantNesting(&_data);
} }
// Returns the capacity of the memory pool.
// https://arduinojson.org/v6/api/jsondocument/capacity/
size_t capacity() const { size_t capacity() const {
return _pool.capacity(); return _pool.capacity();
} }
// Returns the number of elements in the root array or object.
// https://arduinojson.org/v6/api/jsondocument/size/
size_t size() const { size_t size() const {
return _data.size(); return _data.size();
} }
// Copies the specified document.
// https://arduinojson.org/v6/api/jsondocument/set/
bool set(const JsonDocument& src) { bool set(const JsonDocument& src) {
return to<VariantRef>().set(src.as<VariantConstRef>()); return to<JsonVariant>().set(src.as<JsonVariantConst>());
} }
// Replaces the root with the specified value.
// https://arduinojson.org/v6/api/jsondocument/set/
template <typename T> template <typename T>
typename enable_if<!is_base_of<JsonDocument, T>::value, bool>::type set( typename enable_if<!is_base_of<JsonDocument, T>::value, bool>::type set(
const T& src) { const T& src) {
return to<VariantRef>().set(src); return to<JsonVariant>().set(src);
} }
// Clears the document and converts it to the specified type.
// https://arduinojson.org/v6/api/jsondocument/to/
template <typename T> template <typename T>
typename VariantTo<T>::type to() { typename VariantTo<T>::type to() {
clear(); clear();
return getVariant().template to<T>(); return getVariant().template to<T>();
} }
// for internal use only // Creates an array and appends it to the root array.
MemoryPool& memoryPool() { // https://arduinojson.org/v6/api/jsondocument/createnestedarray/
return _pool; JsonArray createNestedArray() {
return add().to<JsonArray>();
} }
// for internal use only // Creates an array and adds it to the root object.
VariantData& data() { // https://arduinojson.org/v6/api/jsondocument/createnestedarray/
return _data;
}
ArrayRef createNestedArray() {
return addElement().to<ArrayRef>();
}
// createNestedArray(char*)
// createNestedArray(const char*)
// createNestedArray(const __FlashStringHelper*)
template <typename TChar> template <typename TChar>
ArrayRef createNestedArray(TChar* key) { JsonArray createNestedArray(TChar* key) {
return getOrAddMember(key).template to<ArrayRef>(); return operator[](key).template to<JsonArray>();
} }
// createNestedArray(const std::string&) // Creates an array and adds it to the root object.
// createNestedArray(const String&) // https://arduinojson.org/v6/api/jsondocument/createnestedarray/
template <typename TString> template <typename TString>
ArrayRef createNestedArray(const TString& key) { JsonArray createNestedArray(const TString& key) {
return getOrAddMember(key).template to<ArrayRef>(); return operator[](key).template to<JsonArray>();
} }
ObjectRef createNestedObject() { // Creates an object and appends it to the root array.
return addElement().to<ObjectRef>(); // https://arduinojson.org/v6/api/jsondocument/createnestedobject/
JsonObject createNestedObject() {
return add().to<JsonObject>();
} }
// createNestedObject(char*) // Creates an object and adds it to the root object.
// createNestedObject(const char*) // https://arduinojson.org/v6/api/jsondocument/createnestedobject/
// createNestedObject(const __FlashStringHelper*)
template <typename TChar> template <typename TChar>
ObjectRef createNestedObject(TChar* key) { JsonObject createNestedObject(TChar* key) {
return getOrAddMember(key).template to<ObjectRef>(); return operator[](key).template to<JsonObject>();
} }
// createNestedObject(const std::string&) // Creates an object and adds it to the root object.
// createNestedObject(const String&) // https://arduinojson.org/v6/api/jsondocument/createnestedobject/
template <typename TString> template <typename TString>
ObjectRef createNestedObject(const TString& key) { JsonObject createNestedObject(const TString& key) {
return getOrAddMember(key).template to<ObjectRef>(); return operator[](key).template to<JsonObject>();
} }
// containsKey(char*) const // Returns true if the root object contains the specified key.
// containsKey(const char*) const // https://arduinojson.org/v6/api/jsondocument/containskey/
// containsKey(const __FlashStringHelper*) const
template <typename TChar> template <typename TChar>
bool containsKey(TChar* key) const { bool containsKey(TChar* key) const {
return !getMember(key).isUnbound(); return _data.getMember(adaptString(key)) != 0;
} }
// containsKey(const std::string&) const // Returns true if the root object contains the specified key.
// containsKey(const String&) const // https://arduinojson.org/v6/api/jsondocument/containskey/
template <typename TString> template <typename TString>
bool containsKey(const TString& key) const { bool containsKey(const TString& key) const {
return !getMember(key).isUnbound(); return _data.getMember(adaptString(key)) != 0;
} }
// operator[](const std::string&) // Gets or sets a root object's member.
// operator[](const String&) // https://arduinojson.org/v6/api/jsondocument/subscript/
template <typename TString> template <typename TString>
FORCE_INLINE typename enable_if<IsString<TString>::value, FORCE_INLINE typename enable_if<IsString<TString>::value,
MemberProxy<JsonDocument&, TString> >::type MemberProxy<JsonDocument&, TString> >::type
@@ -159,9 +176,8 @@ class JsonDocument : public Visitable,
return MemberProxy<JsonDocument&, TString>(*this, key); return MemberProxy<JsonDocument&, TString>(*this, key);
} }
// operator[](char*) // Gets or sets a root object's member.
// operator[](const char*) // https://arduinojson.org/v6/api/jsondocument/subscript/
// operator[](const __FlashStringHelper*)
template <typename TChar> template <typename TChar>
FORCE_INLINE typename enable_if<IsString<TChar*>::value, FORCE_INLINE typename enable_if<IsString<TChar*>::value,
MemberProxy<JsonDocument&, TChar*> >::type MemberProxy<JsonDocument&, TChar*> >::type
@@ -169,138 +185,87 @@ class JsonDocument : public Visitable,
return MemberProxy<JsonDocument&, TChar*>(*this, key); return MemberProxy<JsonDocument&, TChar*>(*this, key);
} }
// operator[](const std::string&) const // Gets a root object's member.
// operator[](const String&) const // https://arduinojson.org/v6/api/jsondocument/subscript/
template <typename TString> template <typename TString>
FORCE_INLINE FORCE_INLINE
typename enable_if<IsString<TString>::value, VariantConstRef>::type typename enable_if<IsString<TString>::value, JsonVariantConst>::type
operator[](const TString& key) const { operator[](const TString& key) const {
return getMember(key); return JsonVariantConst(_data.getMember(adaptString(key)));
} }
// operator[](char*) const // Gets a root object's member.
// operator[](const char*) const // https://arduinojson.org/v6/api/jsondocument/subscript/
// operator[](const __FlashStringHelper*) const
template <typename TChar> template <typename TChar>
FORCE_INLINE FORCE_INLINE
typename enable_if<IsString<TChar*>::value, VariantConstRef>::type typename enable_if<IsString<TChar*>::value, JsonVariantConst>::type
operator[](TChar* key) const { operator[](TChar* key) const {
return getMember(key); return JsonVariantConst(_data.getMember(adaptString(key)));
} }
// Gets or sets a root array's element.
// https://arduinojson.org/v6/api/jsondocument/subscript/
FORCE_INLINE ElementProxy<JsonDocument&> operator[](size_t index) { FORCE_INLINE ElementProxy<JsonDocument&> operator[](size_t index) {
return ElementProxy<JsonDocument&>(*this, index); return ElementProxy<JsonDocument&>(*this, index);
} }
FORCE_INLINE VariantConstRef operator[](size_t index) const { // Gets a root array's member.
return getElement(index); // https://arduinojson.org/v6/api/jsondocument/subscript/
FORCE_INLINE JsonVariantConst operator[](size_t index) const {
return JsonVariantConst(_data.getElement(index));
} }
FORCE_INLINE VariantRef getElement(size_t index) { // Appends a new (null) element to the root array.
return VariantRef(&_pool, _data.getElement(index)); // Returns a reference to the new element.
} // https://arduinojson.org/v6/api/jsondocument/add/
FORCE_INLINE JsonVariant add() {
FORCE_INLINE VariantConstRef getElement(size_t index) const { return JsonVariant(&_pool, _data.addElement(&_pool));
return VariantConstRef(_data.getElement(index));
}
FORCE_INLINE VariantRef getOrAddElement(size_t index) {
return VariantRef(&_pool, _data.getOrAddElement(index, &_pool));
}
// JsonVariantConst getMember(char*) const
// JsonVariantConst getMember(const char*) const
// JsonVariantConst getMember(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE VariantConstRef getMember(TChar* key) const {
return VariantConstRef(_data.getMember(adaptString(key)));
}
// JsonVariantConst getMember(const std::string&) const
// JsonVariantConst getMember(const String&) const
template <typename TString>
FORCE_INLINE
typename enable_if<IsString<TString>::value, VariantConstRef>::type
getMember(const TString& key) const {
return VariantConstRef(_data.getMember(adaptString(key)));
}
// JsonVariant getMember(char*)
// JsonVariant getMember(const char*)
// JsonVariant getMember(const __FlashStringHelper*)
template <typename TChar>
FORCE_INLINE VariantRef getMember(TChar* key) {
return VariantRef(&_pool, _data.getMember(adaptString(key)));
}
// JsonVariant getMember(const std::string&)
// JsonVariant getMember(const String&)
template <typename TString>
FORCE_INLINE typename enable_if<IsString<TString>::value, VariantRef>::type
getMember(const TString& key) {
return VariantRef(&_pool, _data.getMember(adaptString(key)));
}
// getOrAddMember(char*)
// getOrAddMember(const char*)
// getOrAddMember(const __FlashStringHelper*)
template <typename TChar>
FORCE_INLINE VariantRef getOrAddMember(TChar* key) {
return VariantRef(&_pool,
_data.getOrAddMember(adaptString(key), &_pool,
getStringStoragePolicy(key)));
}
// getOrAddMember(const std::string&)
// getOrAddMember(const String&)
template <typename TString>
FORCE_INLINE VariantRef getOrAddMember(const TString& key) {
return VariantRef(&_pool,
_data.getOrAddMember(adaptString(key), &_pool,
getStringStoragePolicy(key)));
}
FORCE_INLINE VariantRef addElement() {
return VariantRef(&_pool, _data.addElement(&_pool));
} }
// Appends a value to the root array.
// https://arduinojson.org/v6/api/jsondocument/add/
template <typename TValue> template <typename TValue>
FORCE_INLINE bool add(const TValue& value) { FORCE_INLINE bool add(const TValue& value) {
return addElement().set(value); return add().set(value);
} }
// add(char*) const // Appends a value to the root array.
// add(const char*) const // https://arduinojson.org/v6/api/jsondocument/add/
// add(const __FlashStringHelper*) const
template <typename TChar> template <typename TChar>
FORCE_INLINE bool add(TChar* value) { FORCE_INLINE bool add(TChar* value) {
return addElement().set(value); return add().set(value);
} }
// Removes an element of the root array.
// ⚠️ Doesn't release the memory associated with the removed element.
// https://arduinojson.org/v6/api/jsondocument/remove/
FORCE_INLINE void remove(size_t index) { FORCE_INLINE void remove(size_t index) {
_data.remove(index); _data.remove(index);
} }
// remove(char*)
// remove(const char*) // Removes a member of the root object.
// remove(const __FlashStringHelper*) // ⚠️ Doesn't release the memory associated with the removed element.
// https://arduinojson.org/v6/api/jsondocument/remove/
template <typename TChar> template <typename TChar>
FORCE_INLINE typename enable_if<IsString<TChar*>::value>::type remove( FORCE_INLINE typename enable_if<IsString<TChar*>::value>::type remove(
TChar* key) { TChar* key) {
_data.remove(adaptString(key)); _data.remove(adaptString(key));
} }
// remove(const std::string&)
// remove(const String&) // Removes a member of the root object.
// ⚠️ Doesn't release the memory associated with the removed element.
// https://arduinojson.org/v6/api/jsondocument/remove/
template <typename TString> template <typename TString>
FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove( FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove(
const TString& key) { const TString& key) {
_data.remove(adaptString(key)); _data.remove(adaptString(key));
} }
FORCE_INLINE operator VariantRef() { FORCE_INLINE operator JsonVariant() {
return getVariant(); return getVariant();
} }
FORCE_INLINE operator VariantConstRef() const { FORCE_INLINE operator JsonVariantConst() const {
return getVariant(); return getVariant();
} }
@@ -323,12 +288,12 @@ class JsonDocument : public Visitable,
_pool = pool; _pool = pool;
} }
VariantRef getVariant() { JsonVariant getVariant() {
return VariantRef(&_pool, &_data); return JsonVariant(&_pool, &_data);
} }
VariantConstRef getVariant() const { JsonVariantConst getVariant() const {
return VariantConstRef(&_data); return JsonVariantConst(&_data);
} }
MemoryPool _pool; MemoryPool _pool;
@@ -337,10 +302,27 @@ class JsonDocument : public Visitable,
private: private:
JsonDocument(const JsonDocument&); JsonDocument(const JsonDocument&);
JsonDocument& operator=(const JsonDocument&); JsonDocument& operator=(const JsonDocument&);
protected:
MemoryPool* getPool() {
return &_pool;
}
VariantData* getData() {
return &_data;
}
const VariantData* getData() const {
return &_data;
}
VariantData* getOrCreateData() {
return &_data;
}
}; };
inline void convertToJson(const JsonDocument& src, VariantRef dst) { inline void convertToJson(const JsonDocument& src, JsonVariant dst) {
dst.set(src.as<VariantConstRef>()); dst.set(src.as<JsonVariantConst>());
} }
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -8,6 +8,7 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
// A JsonDocument with a memory pool on the stack.
template <size_t desiredCapacity> template <size_t desiredCapacity>
class StaticJsonDocument : public JsonDocument { class StaticJsonDocument : public JsonDocument {
static const size_t _capacity = static const size_t _capacity =
@@ -22,14 +23,15 @@ class StaticJsonDocument : public JsonDocument {
} }
template <typename T> template <typename T>
StaticJsonDocument(const T& src, StaticJsonDocument(
typename enable_if<IsVisitable<T>::value>::type* = 0) const T& src,
typename enable_if<is_convertible<T, JsonVariantConst>::value>::type* = 0)
: JsonDocument(_buffer, _capacity) { : JsonDocument(_buffer, _capacity) {
set(src); set(src);
} }
// disambiguate // disambiguate
StaticJsonDocument(VariantRef src) : JsonDocument(_buffer, _capacity) { StaticJsonDocument(JsonVariant src) : JsonDocument(_buffer, _capacity) {
set(src); set(src);
} }
@@ -44,6 +46,8 @@ class StaticJsonDocument : public JsonDocument {
return *this; return *this;
} }
// Reclaims the memory leaked when removing and replacing values.
// https://arduinojson.org/v6/api/jsondocument/garbagecollect/
void garbageCollect() { void garbageCollect() {
StaticJsonDocument tmp(*this); StaticJsonDocument tmp(*this);
set(tmp); set(tmp);

View File

@@ -12,7 +12,7 @@ class EscapeSequence {
public: public:
// Optimized for code size on a 8-bit AVR // Optimized for code size on a 8-bit AVR
static char escapeChar(char c) { static char escapeChar(char c) {
const char *p = escapeTable(true); const char* p = escapeTable(true);
while (p[0] && p[1] != c) { while (p[0] && p[1] != c) {
p += 2; p += 2;
} }
@@ -21,7 +21,7 @@ class EscapeSequence {
// Optimized for code size on a 8-bit AVR // Optimized for code size on a 8-bit AVR
static char unescapeChar(char c) { static char unescapeChar(char c) {
const char *p = escapeTable(false); const char* p = escapeTable(false);
for (;;) { for (;;) {
if (p[0] == '\0') if (p[0] == '\0')
return 0; return 0;
@@ -32,7 +32,7 @@ class EscapeSequence {
} }
private: private:
static const char *escapeTable(bool excludeSolidus) { static const char* escapeTable(bool excludeSolidus) {
return &"//\"\"\\\\b\bf\fn\nr\rt\t"[excludeSolidus ? 2 : 0]; return &"//\"\"\\\\b\bf\fn\nr\rt\t"[excludeSolidus ? 2 : 0];
} }
}; };

View File

@@ -20,25 +20,26 @@ namespace ARDUINOJSON_NAMESPACE {
template <typename TReader, typename TStringStorage> template <typename TReader, typename TStringStorage>
class JsonDeserializer { class JsonDeserializer {
public: public:
JsonDeserializer(MemoryPool &pool, TReader reader, JsonDeserializer(MemoryPool* pool, TReader reader,
TStringStorage stringStorage) TStringStorage stringStorage)
: _stringStorage(stringStorage), : _stringStorage(stringStorage),
_foundSomething(false), _foundSomething(false),
_latch(reader), _latch(reader),
_pool(&pool), _pool(pool) {}
_error(DeserializationError::Ok) {}
template <typename TFilter> template <typename TFilter>
DeserializationError parse(VariantData &variant, TFilter filter, DeserializationError parse(VariantData& variant, TFilter filter,
NestingLimit nestingLimit) { NestingLimit nestingLimit) {
parseVariant(variant, filter, nestingLimit); DeserializationError::Code err;
if (!_error && _latch.last() != 0 && !variant.isEnclosed()) { err = parseVariant(variant, filter, nestingLimit);
if (!err && _latch.last() != 0 && !variant.isEnclosed()) {
// We don't detect trailing characters earlier, so we need to check now // We don't detect trailing characters earlier, so we need to check now
return DeserializationError::InvalidInput; return DeserializationError::InvalidInput;
} }
return _error; return err;
} }
private: private:
@@ -58,10 +59,13 @@ class JsonDeserializer {
} }
template <typename TFilter> template <typename TFilter>
bool parseVariant(VariantData &variant, TFilter filter, DeserializationError::Code parseVariant(VariantData& variant, TFilter filter,
NestingLimit nestingLimit) { NestingLimit nestingLimit) {
if (!skipSpacesAndComments()) DeserializationError::Code err;
return false;
err = skipSpacesAndComments();
if (err)
return err;
switch (current()) { switch (current()) {
case '[': case '[':
@@ -81,7 +85,22 @@ class JsonDeserializer {
if (filter.allowValue()) if (filter.allowValue())
return parseStringValue(variant); return parseStringValue(variant);
else else
return skipString(); return skipQuotedString();
case 't':
if (filter.allowValue())
variant.setBoolean(true);
return skipKeyword("true");
case 'f':
if (filter.allowValue())
variant.setBoolean(false);
return skipKeyword("false");
case 'n':
// the variant should already by null, except if the same object key was
// used twice, as in {"a":1,"a":null}
return skipKeyword("null");
default: default:
if (filter.allowValue()) if (filter.allowValue())
@@ -91,9 +110,12 @@ class JsonDeserializer {
} }
} }
bool skipVariant(NestingLimit nestingLimit) { DeserializationError::Code skipVariant(NestingLimit nestingLimit) {
if (!skipSpacesAndComments()) DeserializationError::Code err;
return false;
err = skipSpacesAndComments();
if (err)
return err;
switch (current()) { switch (current()) {
case '[': case '[':
@@ -104,7 +126,16 @@ class JsonDeserializer {
case '\"': case '\"':
case '\'': case '\'':
return skipString(); return skipQuotedString();
case 't':
return skipKeyword("true");
case 'f':
return skipKeyword("false");
case 'n':
return skipKeyword("null");
default: default:
return skipNumericValue(); return skipNumericValue();
@@ -112,24 +143,25 @@ class JsonDeserializer {
} }
template <typename TFilter> template <typename TFilter>
bool parseArray(CollectionData &array, TFilter filter, DeserializationError::Code parseArray(CollectionData& array, TFilter filter,
NestingLimit nestingLimit) { NestingLimit nestingLimit) {
if (nestingLimit.reached()) { DeserializationError::Code err;
_error = DeserializationError::TooDeep;
return false; if (nestingLimit.reached())
} return DeserializationError::TooDeep;
// Skip opening braket // Skip opening braket
ARDUINOJSON_ASSERT(current() == '['); ARDUINOJSON_ASSERT(current() == '[');
move(); move();
// Skip spaces // Skip spaces
if (!skipSpacesAndComments()) err = skipSpacesAndComments();
return false; if (err)
return err;
// Empty array? // Empty array?
if (eat(']')) if (eat(']'))
return true; return DeserializationError::Ok;
TFilter memberFilter = filter[0UL]; TFilter memberFilter = filter[0UL];
@@ -137,39 +169,38 @@ class JsonDeserializer {
for (;;) { for (;;) {
if (memberFilter.allow()) { if (memberFilter.allow()) {
// Allocate slot in array // Allocate slot in array
VariantData *value = array.addElement(_pool); VariantData* value = array.addElement(_pool);
if (!value) { if (!value)
_error = DeserializationError::NoMemory; return DeserializationError::NoMemory;
return false;
}
// 1 - Parse value // 1 - Parse value
if (!parseVariant(*value, memberFilter, nestingLimit.decrement())) err = parseVariant(*value, memberFilter, nestingLimit.decrement());
return false; if (err)
return err;
} else { } else {
if (!skipVariant(nestingLimit.decrement())) err = skipVariant(nestingLimit.decrement());
return false; if (err)
return err;
} }
// 2 - Skip spaces // 2 - Skip spaces
if (!skipSpacesAndComments()) err = skipSpacesAndComments();
return false; if (err)
return err;
// 3 - More values? // 3 - More values?
if (eat(']')) if (eat(']'))
return true; return DeserializationError::Ok;
if (!eat(',')) { if (!eat(','))
_error = DeserializationError::InvalidInput; return DeserializationError::InvalidInput;
return false;
}
} }
} }
bool skipArray(NestingLimit nestingLimit) { DeserializationError::Code skipArray(NestingLimit nestingLimit) {
if (nestingLimit.reached()) { DeserializationError::Code err;
_error = DeserializationError::TooDeep;
return false; if (nestingLimit.reached())
} return DeserializationError::TooDeep;
// Skip opening braket // Skip opening braket
ARDUINOJSON_ASSERT(current() == '['); ARDUINOJSON_ASSERT(current() == '[');
@@ -178,76 +209,75 @@ class JsonDeserializer {
// Read each value // Read each value
for (;;) { for (;;) {
// 1 - Skip value // 1 - Skip value
if (!skipVariant(nestingLimit.decrement())) err = skipVariant(nestingLimit.decrement());
return false; if (err)
return err;
// 2 - Skip spaces // 2 - Skip spaces
if (!skipSpacesAndComments()) err = skipSpacesAndComments();
return false; if (err)
return err;
// 3 - More values? // 3 - More values?
if (eat(']')) if (eat(']'))
return true; return DeserializationError::Ok;
if (!eat(',')) { if (!eat(','))
_error = DeserializationError::InvalidInput; return DeserializationError::InvalidInput;
return false;
}
} }
} }
template <typename TFilter> template <typename TFilter>
bool parseObject(CollectionData &object, TFilter filter, DeserializationError::Code parseObject(CollectionData& object, TFilter filter,
NestingLimit nestingLimit) { NestingLimit nestingLimit) {
if (nestingLimit.reached()) { DeserializationError::Code err;
_error = DeserializationError::TooDeep;
return false; if (nestingLimit.reached())
} return DeserializationError::TooDeep;
// Skip opening brace // Skip opening brace
ARDUINOJSON_ASSERT(current() == '{'); ARDUINOJSON_ASSERT(current() == '{');
move(); move();
// Skip spaces // Skip spaces
if (!skipSpacesAndComments()) err = skipSpacesAndComments();
return false; if (err)
return err;
// Empty object? // Empty object?
if (eat('}')) if (eat('}'))
return true; return DeserializationError::Ok;
// Read each key value pair // Read each key value pair
for (;;) { for (;;) {
// Parse key // Parse key
if (!parseKey()) err = parseKey();
return false; if (err)
return err;
// Skip spaces // Skip spaces
if (!skipSpacesAndComments()) err = skipSpacesAndComments();
return false; if (err)
return err;
// Colon // Colon
if (!eat(':')) { if (!eat(':'))
_error = DeserializationError::InvalidInput; return DeserializationError::InvalidInput;
return false;
}
String key = _stringStorage.str(); JsonString key = _stringStorage.str();
TFilter memberFilter = filter[key.c_str()]; TFilter memberFilter = filter[key.c_str()];
if (memberFilter.allow()) { if (memberFilter.allow()) {
VariantData *variant = object.getMember(adaptString(key.c_str())); VariantData* variant = object.getMember(adaptString(key.c_str()));
if (!variant) { if (!variant) {
// Save key in memory pool. // Save key in memory pool.
// This MUST be done before adding the slot. // This MUST be done before adding the slot.
key = _stringStorage.save(); key = _stringStorage.save();
// Allocate slot in object // Allocate slot in object
VariantSlot *slot = object.addSlot(_pool); VariantSlot* slot = object.addSlot(_pool);
if (!slot) { if (!slot)
_error = DeserializationError::NoMemory; return DeserializationError::NoMemory;
return false;
}
slot->setKey(key); slot->setKey(key);
@@ -255,84 +285,91 @@ class JsonDeserializer {
} }
// Parse value // Parse value
if (!parseVariant(*variant, memberFilter, nestingLimit.decrement())) err = parseVariant(*variant, memberFilter, nestingLimit.decrement());
return false; if (err)
return err;
} else { } else {
if (!skipVariant(nestingLimit.decrement())) err = skipVariant(nestingLimit.decrement());
return false; if (err)
return err;
} }
// Skip spaces // Skip spaces
if (!skipSpacesAndComments()) err = skipSpacesAndComments();
return false; if (err)
return err;
// More keys/values? // More keys/values?
if (eat('}')) if (eat('}'))
return true; return DeserializationError::Ok;
if (!eat(',')) { if (!eat(','))
_error = DeserializationError::InvalidInput; return DeserializationError::InvalidInput;
return false;
}
// Skip spaces // Skip spaces
if (!skipSpacesAndComments()) err = skipSpacesAndComments();
return false; if (err)
return err;
} }
} }
bool skipObject(NestingLimit nestingLimit) { DeserializationError::Code skipObject(NestingLimit nestingLimit) {
if (nestingLimit.reached()) { DeserializationError::Code err;
_error = DeserializationError::TooDeep;
return false; if (nestingLimit.reached())
} return DeserializationError::TooDeep;
// Skip opening brace // Skip opening brace
ARDUINOJSON_ASSERT(current() == '{'); ARDUINOJSON_ASSERT(current() == '{');
move(); move();
// Skip spaces // Skip spaces
if (!skipSpacesAndComments()) err = skipSpacesAndComments();
return false; if (err)
return err;
// Empty object? // Empty object?
if (eat('}')) if (eat('}'))
return true; return DeserializationError::Ok;
// Read each key value pair // Read each key value pair
for (;;) { for (;;) {
// Skip key // Skip key
if (!skipVariant(nestingLimit.decrement())) err = skipKey();
return false; if (err)
return err;
// Skip spaces // Skip spaces
if (!skipSpacesAndComments()) err = skipSpacesAndComments();
return false; if (err)
return err;
// Colon // Colon
if (!eat(':')) { if (!eat(':'))
_error = DeserializationError::InvalidInput; return DeserializationError::InvalidInput;
return false;
}
// Skip value // Skip value
if (!skipVariant(nestingLimit.decrement())) err = skipVariant(nestingLimit.decrement());
return false; if (err)
return err;
// Skip spaces // Skip spaces
if (!skipSpacesAndComments()) err = skipSpacesAndComments();
return false; if (err)
return err;
// More keys/values? // More keys/values?
if (eat('}')) if (eat('}'))
return true; return DeserializationError::Ok;
if (!eat(',')) { if (!eat(','))
_error = DeserializationError::InvalidInput; return DeserializationError::InvalidInput;
return false;
} err = skipSpacesAndComments();
if (err)
return err;
} }
} }
bool parseKey() { DeserializationError::Code parseKey() {
_stringStorage.startString(); _stringStorage.startString();
if (isQuote(current())) { if (isQuote(current())) {
return parseQuotedString(); return parseQuotedString();
@@ -341,17 +378,24 @@ class JsonDeserializer {
} }
} }
bool parseStringValue(VariantData &variant) { DeserializationError::Code parseStringValue(VariantData& variant) {
DeserializationError::Code err;
_stringStorage.startString(); _stringStorage.startString();
if (!parseQuotedString())
return false; err = parseQuotedString();
if (err)
return err;
variant.setString(_stringStorage.save()); variant.setString(_stringStorage.save());
return true;
return DeserializationError::Ok;
} }
bool parseQuotedString() { DeserializationError::Code parseQuotedString() {
#if ARDUINOJSON_DECODE_UNICODE #if ARDUINOJSON_DECODE_UNICODE
Utf16::Codepoint codepoint; Utf16::Codepoint codepoint;
DeserializationError::Code err;
#endif #endif
const char stopChar = current(); const char stopChar = current();
@@ -362,25 +406,22 @@ class JsonDeserializer {
if (c == stopChar) if (c == stopChar)
break; break;
if (c == '\0') { if (c == '\0')
_error = DeserializationError::IncompleteInput; return DeserializationError::IncompleteInput;
return false;
}
if (c == '\\') { if (c == '\\') {
c = current(); c = current();
if (c == '\0') { if (c == '\0')
_error = DeserializationError::IncompleteInput; return DeserializationError::IncompleteInput;
return false;
}
if (c == 'u') { if (c == 'u') {
#if ARDUINOJSON_DECODE_UNICODE #if ARDUINOJSON_DECODE_UNICODE
move(); move();
uint16_t codeunit; uint16_t codeunit;
if (!parseHex4(codeunit)) err = parseHex4(codeunit);
return false; if (err)
return err;
if (codepoint.append(codeunit)) if (codepoint.append(codeunit))
Utf8::encodeCodepoint(codepoint.value(), _stringStorage); Utf8::encodeCodepoint(codepoint.value(), _stringStorage);
#else #else
@@ -391,25 +432,21 @@ class JsonDeserializer {
// replace char // replace char
c = EscapeSequence::unescapeChar(c); c = EscapeSequence::unescapeChar(c);
if (c == '\0') { if (c == '\0')
_error = DeserializationError::InvalidInput; return DeserializationError::InvalidInput;
return false;
}
move(); move();
} }
_stringStorage.append(c); _stringStorage.append(c);
} }
if (!_stringStorage.isValid()) { if (!_stringStorage.isValid())
_error = DeserializationError::NoMemory; return DeserializationError::NoMemory;
return false;
return DeserializationError::Ok;
} }
return true; DeserializationError::Code parseNonQuotedString() {
}
bool parseNonQuotedString() {
char c = current(); char c = current();
ARDUINOJSON_ASSERT(c); ARDUINOJSON_ASSERT(c);
@@ -420,19 +457,24 @@ class JsonDeserializer {
c = current(); c = current();
} while (canBeInNonQuotedString(c)); } while (canBeInNonQuotedString(c));
} else { } else {
_error = DeserializationError::InvalidInput; return DeserializationError::InvalidInput;
return false;
} }
if (!_stringStorage.isValid()) { if (!_stringStorage.isValid())
_error = DeserializationError::NoMemory; return DeserializationError::NoMemory;
return false;
return DeserializationError::Ok;
} }
return true; DeserializationError::Code skipKey() {
if (isQuote(current())) {
return skipQuotedString();
} else {
return skipNonQuotedString();
}
} }
bool skipString() { DeserializationError::Code skipQuotedString() {
const char stopChar = current(); const char stopChar = current();
move(); move();
@@ -441,99 +483,83 @@ class JsonDeserializer {
move(); move();
if (c == stopChar) if (c == stopChar)
break; break;
if (c == '\0') { if (c == '\0')
_error = DeserializationError::IncompleteInput; return DeserializationError::IncompleteInput;
return false;
}
if (c == '\\') { if (c == '\\') {
if (current() != '\0') if (current() != '\0')
move(); move();
} }
} }
return true; return DeserializationError::Ok;
} }
bool parseNumericValue(VariantData &result) { DeserializationError::Code skipNonQuotedString() {
char c = current();
while (canBeInNonQuotedString(c)) {
move();
c = current();
}
return DeserializationError::Ok;
}
DeserializationError::Code parseNumericValue(VariantData& result) {
uint8_t n = 0; uint8_t n = 0;
char c = current(); char c = current();
while (canBeInNonQuotedString(c) && n < 63) { while (canBeInNumber(c) && n < 63) {
move(); move();
_buffer[n++] = c; _buffer[n++] = c;
c = current(); c = current();
} }
_buffer[n] = 0; _buffer[n] = 0;
c = _buffer[0]; if (!parseNumber(_buffer, result))
if (c == 't') { // true return DeserializationError::InvalidInput;
result.setBoolean(true);
if (n != 4) { return DeserializationError::Ok;
_error = DeserializationError::IncompleteInput;
return false;
}
return true;
}
if (c == 'f') { // false
result.setBoolean(false);
if (n != 5) {
_error = DeserializationError::IncompleteInput;
return false;
}
return true;
}
if (c == 'n') { // null
// the variant is already null
if (n != 4) {
_error = DeserializationError::IncompleteInput;
return false;
}
return true;
} }
if (!parseNumber(_buffer, result)) { DeserializationError::Code skipNumericValue() {
_error = DeserializationError::InvalidInput;
return false;
}
return true;
}
bool skipNumericValue() {
char c = current(); char c = current();
while (canBeInNonQuotedString(c)) { while (canBeInNumber(c)) {
move(); move();
c = current(); c = current();
} }
return true; return DeserializationError::Ok;
} }
bool parseHex4(uint16_t &result) { DeserializationError::Code parseHex4(uint16_t& result) {
result = 0; result = 0;
for (uint8_t i = 0; i < 4; ++i) { for (uint8_t i = 0; i < 4; ++i) {
char digit = current(); char digit = current();
if (!digit) { if (!digit)
_error = DeserializationError::IncompleteInput; return DeserializationError::IncompleteInput;
return false;
}
uint8_t value = decodeHex(digit); uint8_t value = decodeHex(digit);
if (value > 0x0F) { if (value > 0x0F)
_error = DeserializationError::InvalidInput; return DeserializationError::InvalidInput;
return false;
}
result = uint16_t((result << 4) | value); result = uint16_t((result << 4) | value);
move(); move();
} }
return true; return DeserializationError::Ok;
} }
static inline bool isBetween(char c, char min, char max) { static inline bool isBetween(char c, char min, char max) {
return min <= c && c <= max; return min <= c && c <= max;
} }
static inline bool canBeInNumber(char c) {
return isBetween(c, '0', '9') || c == '+' || c == '-' || c == '.' ||
#if ARDUINOJSON_ENABLE_NAN || ARDUINOJSON_ENABLE_INFINITY
isBetween(c, 'A', 'Z') || isBetween(c, 'a', 'z');
#else
c == 'e' || c == 'E';
#endif
}
static inline bool canBeInNonQuotedString(char c) { static inline bool canBeInNonQuotedString(char c) {
return isBetween(c, '0', '9') || isBetween(c, '_', 'z') || return isBetween(c, '0', '9') || isBetween(c, '_', 'z') ||
isBetween(c, 'A', 'Z') || c == '+' || c == '-' || c == '.'; isBetween(c, 'A', 'Z');
} }
static inline bool isQuote(char c) { static inline bool isQuote(char c) {
@@ -547,14 +573,13 @@ class JsonDeserializer {
return uint8_t(c - 'A' + 10); return uint8_t(c - 'A' + 10);
} }
bool skipSpacesAndComments() { DeserializationError::Code skipSpacesAndComments() {
for (;;) { for (;;) {
switch (current()) { switch (current()) {
// end of string // end of string
case '\0': case '\0':
_error = _foundSomething ? DeserializationError::IncompleteInput return _foundSomething ? DeserializationError::IncompleteInput
: DeserializationError::EmptyInput; : DeserializationError::EmptyInput;
return false;
// spaces // spaces
case ' ': case ' ':
@@ -575,10 +600,8 @@ class JsonDeserializer {
bool wasStar = false; bool wasStar = false;
for (;;) { for (;;) {
char c = current(); char c = current();
if (c == '\0') { if (c == '\0')
_error = DeserializationError::IncompleteInput; return DeserializationError::IncompleteInput;
return false;
}
if (c == '/' && wasStar) { if (c == '/' && wasStar) {
move(); move();
break; break;
@@ -595,10 +618,8 @@ class JsonDeserializer {
for (;;) { for (;;) {
move(); move();
char c = current(); char c = current();
if (c == '\0') { if (c == '\0')
_error = DeserializationError::IncompleteInput; return DeserializationError::IncompleteInput;
return false;
}
if (c == '\n') if (c == '\n')
break; break;
} }
@@ -606,126 +627,145 @@ class JsonDeserializer {
// not a comment, just a '/' // not a comment, just a '/'
default: default:
_error = DeserializationError::InvalidInput; return DeserializationError::InvalidInput;
return false;
} }
break; break;
#endif #endif
default: default:
_foundSomething = true; _foundSomething = true;
return true; return DeserializationError::Ok;
} }
} }
} }
DeserializationError::Code skipKeyword(const char* s) {
while (*s) {
char c = current();
if (c == '\0')
return DeserializationError::IncompleteInput;
if (*s != c)
return DeserializationError::InvalidInput;
++s;
move();
}
return DeserializationError::Ok;
}
TStringStorage _stringStorage; TStringStorage _stringStorage;
bool _foundSomething; bool _foundSomething;
Latch<TReader> _latch; Latch<TReader> _latch;
MemoryPool *_pool; MemoryPool* _pool;
char _buffer[64]; // using a member instead of a local variable because it char _buffer[64]; // using a member instead of a local variable because it
// ended in the recursive path after compiler inlined the // ended in the recursive path after compiler inlined the
// code // code
DeserializationError _error;
}; };
// // Parses a JSON input and puts the result in a JsonDocument.
// deserializeJson(JsonDocument&, const std::string&, ...) // https://arduinojson.org/v6/api/json/deserializejson/
//
// ... = NestingLimit
template <typename TString> template <typename TString>
DeserializationError deserializeJson( DeserializationError deserializeJson(
JsonDocument &doc, const TString &input, JsonDocument& doc, const TString& input,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, return deserialize<JsonDeserializer>(doc, input, nestingLimit,
AllowAllFilter()); AllowAllFilter());
} }
// ... = Filter, NestingLimit
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TString> template <typename TString>
DeserializationError deserializeJson( DeserializationError deserializeJson(
JsonDocument &doc, const TString &input, Filter filter, JsonDocument& doc, const TString& input, Filter filter,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
} }
// ... = NestingLimit, Filter
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TString> template <typename TString>
DeserializationError deserializeJson(JsonDocument &doc, const TString &input, DeserializationError deserializeJson(JsonDocument& doc, const TString& input,
NestingLimit nestingLimit, Filter filter) { NestingLimit nestingLimit, Filter filter) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
} }
// // Parses a JSON input and puts the result in a JsonDocument.
// deserializeJson(JsonDocument&, std::istream&, ...) // https://arduinojson.org/v6/api/json/deserializejson/
//
// ... = NestingLimit
template <typename TStream> template <typename TStream>
DeserializationError deserializeJson( DeserializationError deserializeJson(
JsonDocument &doc, TStream &input, JsonDocument& doc, TStream& input,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, return deserialize<JsonDeserializer>(doc, input, nestingLimit,
AllowAllFilter()); AllowAllFilter());
} }
// ... = Filter, NestingLimit
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TStream> template <typename TStream>
DeserializationError deserializeJson( DeserializationError deserializeJson(
JsonDocument &doc, TStream &input, Filter filter, JsonDocument& doc, TStream& input, Filter filter,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
} }
// ... = NestingLimit, Filter
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TStream> template <typename TStream>
DeserializationError deserializeJson(JsonDocument &doc, TStream &input, DeserializationError deserializeJson(JsonDocument& doc, TStream& input,
NestingLimit nestingLimit, Filter filter) { NestingLimit nestingLimit, Filter filter) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
} }
// // Parses a JSON input and puts the result in a JsonDocument.
// deserializeJson(JsonDocument&, char*, ...) // https://arduinojson.org/v6/api/json/deserializejson/
//
// ... = NestingLimit
template <typename TChar> template <typename TChar>
DeserializationError deserializeJson( DeserializationError deserializeJson(
JsonDocument &doc, TChar *input, JsonDocument& doc, TChar* input,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, return deserialize<JsonDeserializer>(doc, input, nestingLimit,
AllowAllFilter()); AllowAllFilter());
} }
// ... = Filter, NestingLimit
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TChar> template <typename TChar>
DeserializationError deserializeJson( DeserializationError deserializeJson(
JsonDocument &doc, TChar *input, Filter filter, JsonDocument& doc, TChar* input, Filter filter,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
} }
// ... = NestingLimit, Filter
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TChar> template <typename TChar>
DeserializationError deserializeJson(JsonDocument &doc, TChar *input, DeserializationError deserializeJson(JsonDocument& doc, TChar* input,
NestingLimit nestingLimit, Filter filter) { NestingLimit nestingLimit, Filter filter) {
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter); return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
} }
// // Parses a JSON input and puts the result in a JsonDocument.
// deserializeJson(JsonDocument&, char*, size_t, ...) // https://arduinojson.org/v6/api/json/deserializejson/
//
// ... = NestingLimit
template <typename TChar> template <typename TChar>
DeserializationError deserializeJson( DeserializationError deserializeJson(
JsonDocument &doc, TChar *input, size_t inputSize, JsonDocument& doc, TChar* input, size_t inputSize,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit, return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit,
AllowAllFilter()); AllowAllFilter());
} }
// ... = Filter, NestingLimit
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TChar> template <typename TChar>
DeserializationError deserializeJson( DeserializationError deserializeJson(
JsonDocument &doc, TChar *input, size_t inputSize, Filter filter, JsonDocument& doc, TChar* input, size_t inputSize, Filter filter,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit, return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit,
filter); filter);
} }
// ... = NestingLimit, Filter
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TChar> template <typename TChar>
DeserializationError deserializeJson(JsonDocument &doc, TChar *input, DeserializationError deserializeJson(JsonDocument& doc, TChar* input,
size_t inputSize, size_t inputSize,
NestingLimit nestingLimit, Filter filter) { NestingLimit nestingLimit, Filter filter) {
return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit, return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit,

View File

@@ -5,7 +5,6 @@
#pragma once #pragma once
#include <ArduinoJson/Json/TextFormatter.hpp> #include <ArduinoJson/Json/TextFormatter.hpp>
#include <ArduinoJson/Misc/Visitable.hpp>
#include <ArduinoJson/Serialization/measure.hpp> #include <ArduinoJson/Serialization/measure.hpp>
#include <ArduinoJson/Serialization/serialize.hpp> #include <ArduinoJson/Serialization/serialize.hpp>
#include <ArduinoJson/Variant/Visitor.hpp> #include <ArduinoJson/Variant/Visitor.hpp>
@@ -19,10 +18,10 @@ class JsonSerializer : public Visitor<size_t> {
JsonSerializer(TWriter writer) : _formatter(writer) {} JsonSerializer(TWriter writer) : _formatter(writer) {}
FORCE_INLINE size_t visitArray(const CollectionData &array) { FORCE_INLINE size_t visitArray(const CollectionData& array) {
write('['); write('[');
VariantSlot *slot = array.head(); const VariantSlot* slot = array.head();
while (slot != 0) { while (slot != 0) {
slot->data()->accept(*this); slot->data()->accept(*this);
@@ -38,10 +37,10 @@ class JsonSerializer : public Visitor<size_t> {
return bytesWritten(); return bytesWritten();
} }
size_t visitObject(const CollectionData &object) { size_t visitObject(const CollectionData& object) {
write('{'); write('{');
VariantSlot *slot = object.head(); const VariantSlot* slot = object.head();
while (slot != 0) { while (slot != 0) {
_formatter.writeString(slot->key()); _formatter.writeString(slot->key());
@@ -59,32 +58,32 @@ class JsonSerializer : public Visitor<size_t> {
return bytesWritten(); return bytesWritten();
} }
size_t visitFloat(Float value) { size_t visitFloat(JsonFloat value) {
_formatter.writeFloat(value); _formatter.writeFloat(value);
return bytesWritten(); return bytesWritten();
} }
size_t visitString(const char *value) { size_t visitString(const char* value) {
_formatter.writeString(value); _formatter.writeString(value);
return bytesWritten(); return bytesWritten();
} }
size_t visitString(const char *value, size_t n) { size_t visitString(const char* value, size_t n) {
_formatter.writeString(value, n); _formatter.writeString(value, n);
return bytesWritten(); return bytesWritten();
} }
size_t visitRawJson(const char *data, size_t n) { size_t visitRawJson(const char* data, size_t n) {
_formatter.writeRaw(data, n); _formatter.writeRaw(data, n);
return bytesWritten(); return bytesWritten();
} }
size_t visitSignedInteger(Integer value) { size_t visitSignedInteger(JsonInteger value) {
_formatter.writeInteger(value); _formatter.writeInteger(value);
return bytesWritten(); return bytesWritten();
} }
size_t visitUnsignedInteger(UInt value) { size_t visitUnsignedInteger(JsonUInt value) {
_formatter.writeInteger(value); _formatter.writeInteger(value);
return bytesWritten(); return bytesWritten();
} }
@@ -108,7 +107,7 @@ class JsonSerializer : public Visitor<size_t> {
_formatter.writeRaw(c); _formatter.writeRaw(c);
} }
void write(const char *s) { void write(const char* s) {
_formatter.writeRaw(s); _formatter.writeRaw(s);
} }
@@ -116,25 +115,31 @@ class JsonSerializer : public Visitor<size_t> {
TextFormatter<TWriter> _formatter; TextFormatter<TWriter> _formatter;
}; };
template <typename TSource, typename TDestination> // Produces a minified JSON document.
size_t serializeJson(const TSource &source, TDestination &destination) { // https://arduinojson.org/v6/api/json/serializejson/
template <typename TDestination>
size_t serializeJson(JsonVariantConst source, TDestination& destination) {
return serialize<JsonSerializer>(source, destination); return serialize<JsonSerializer>(source, destination);
} }
template <typename TSource> // Produces a minified JSON document.
size_t serializeJson(const TSource &source, void *buffer, size_t bufferSize) { // https://arduinojson.org/v6/api/json/serializejson/
inline size_t serializeJson(JsonVariantConst source, void* buffer,
size_t bufferSize) {
return serialize<JsonSerializer>(source, buffer, bufferSize); return serialize<JsonSerializer>(source, buffer, bufferSize);
} }
template <typename TSource> // Computes the length of the document that serializeJson() produces.
size_t measureJson(const TSource &source) { // https://arduinojson.org/v6/api/json/measurejson/
inline size_t measureJson(JsonVariantConst source) {
return measure<JsonSerializer>(source); return measure<JsonSerializer>(source);
} }
#if ARDUINOJSON_ENABLE_STD_STREAM #if ARDUINOJSON_ENABLE_STD_STREAM
template <typename T> template <typename T>
inline typename enable_if<IsVisitable<T>::value, std::ostream &>::type inline typename enable_if<is_convertible<T, JsonVariantConst>::value,
operator<<(std::ostream &os, const T &source) { std::ostream&>::type
operator<<(std::ostream& os, const T& source) {
serializeJson(source, os); serializeJson(source, os);
return os; return os;
} }

View File

@@ -18,8 +18,8 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
public: public:
PrettyJsonSerializer(TWriter writer) : base(writer), _nesting(0) {} PrettyJsonSerializer(TWriter writer) : base(writer), _nesting(0) {}
size_t visitArray(const CollectionData &array) { size_t visitArray(const CollectionData& array) {
VariantSlot *slot = array.head(); const VariantSlot* slot = array.head();
if (slot) { if (slot) {
base::write("[\r\n"); base::write("[\r\n");
_nesting++; _nesting++;
@@ -39,8 +39,8 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
return this->bytesWritten(); return this->bytesWritten();
} }
size_t visitObject(const CollectionData &object) { size_t visitObject(const CollectionData& object) {
VariantSlot *slot = object.head(); const VariantSlot* slot = object.head();
if (slot) { if (slot) {
base::write("{\r\n"); base::write("{\r\n");
_nesting++; _nesting++;
@@ -64,25 +64,30 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
private: private:
void indent() { void indent() {
for (uint8_t i = 0; i < _nesting; i++) base::write(ARDUINOJSON_TAB); for (uint8_t i = 0; i < _nesting; i++)
base::write(ARDUINOJSON_TAB);
} }
uint8_t _nesting; uint8_t _nesting;
}; };
template <typename TSource, typename TDestination> // Produces JsonDocument to create a prettified JSON document.
size_t serializeJsonPretty(const TSource &source, TDestination &destination) { // https://arduinojson.org/v6/api/json/serializejsonpretty/
template <typename TDestination>
size_t serializeJsonPretty(JsonVariantConst source, TDestination& destination) {
return serialize<PrettyJsonSerializer>(source, destination); return serialize<PrettyJsonSerializer>(source, destination);
} }
template <typename TSource> // Produces JsonDocument to create a prettified JSON document.
size_t serializeJsonPretty(const TSource &source, void *buffer, // https://arduinojson.org/v6/api/json/serializejsonpretty/
inline size_t serializeJsonPretty(JsonVariantConst source, void* buffer,
size_t bufferSize) { size_t bufferSize) {
return serialize<PrettyJsonSerializer>(source, buffer, bufferSize); return serialize<PrettyJsonSerializer>(source, buffer, bufferSize);
} }
template <typename TSource> // Computes the length of the document that serializeJsonPretty() produces.
size_t measureJsonPretty(const TSource &source) { // https://arduinojson.org/v6/api/json/measurejsonpretty/
inline size_t measureJsonPretty(JsonVariantConst source) {
return measure<PrettyJsonSerializer>(source); return measure<PrettyJsonSerializer>(source);
} }

View File

@@ -9,7 +9,7 @@
#include <ArduinoJson/Json/EscapeSequence.hpp> #include <ArduinoJson/Json/EscapeSequence.hpp>
#include <ArduinoJson/Numbers/FloatParts.hpp> #include <ArduinoJson/Numbers/FloatParts.hpp>
#include <ArduinoJson/Numbers/Integer.hpp> #include <ArduinoJson/Numbers/JsonInteger.hpp>
#include <ArduinoJson/Polyfills/assert.hpp> #include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/attributes.hpp> #include <ArduinoJson/Polyfills/attributes.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp>
@@ -34,17 +34,19 @@ class TextFormatter {
writeRaw("false"); writeRaw("false");
} }
void writeString(const char *value) { void writeString(const char* value) {
ARDUINOJSON_ASSERT(value != NULL); ARDUINOJSON_ASSERT(value != NULL);
writeRaw('\"'); writeRaw('\"');
while (*value) writeChar(*value++); while (*value)
writeChar(*value++);
writeRaw('\"'); writeRaw('\"');
} }
void writeString(const char *value, size_t n) { void writeString(const char* value, size_t n) {
ARDUINOJSON_ASSERT(value != NULL); ARDUINOJSON_ASSERT(value != NULL);
writeRaw('\"'); writeRaw('\"');
while (n--) writeChar(*value++); while (n--)
writeChar(*value++);
writeRaw('\"'); writeRaw('\"');
} }
@@ -111,8 +113,8 @@ class TextFormatter {
template <typename T> template <typename T>
typename enable_if<is_unsigned<T>::value>::type writeInteger(T value) { typename enable_if<is_unsigned<T>::value>::type writeInteger(T value) {
char buffer[22]; char buffer[22];
char *end = buffer + sizeof(buffer); char* end = buffer + sizeof(buffer);
char *begin = end; char* begin = end;
// write the string in reverse order // write the string in reverse order
do { do {
@@ -127,8 +129,8 @@ class TextFormatter {
void writeDecimals(uint32_t value, int8_t width) { void writeDecimals(uint32_t value, int8_t width) {
// buffer should be big enough for all digits and the dot // buffer should be big enough for all digits and the dot
char buffer[16]; char buffer[16];
char *end = buffer + sizeof(buffer); char* end = buffer + sizeof(buffer);
char *begin = end; char* begin = end;
// write the string in reverse order // write the string in reverse order
while (width--) { while (width--) {
@@ -141,22 +143,22 @@ class TextFormatter {
writeRaw(begin, end); writeRaw(begin, end);
} }
void writeRaw(const char *s) { void writeRaw(const char* s) {
_writer.write(reinterpret_cast<const uint8_t *>(s), strlen(s)); _writer.write(reinterpret_cast<const uint8_t*>(s), strlen(s));
} }
void writeRaw(const char *s, size_t n) { void writeRaw(const char* s, size_t n) {
_writer.write(reinterpret_cast<const uint8_t *>(s), n); _writer.write(reinterpret_cast<const uint8_t*>(s), n);
} }
void writeRaw(const char *begin, const char *end) { void writeRaw(const char* begin, const char* end) {
_writer.write(reinterpret_cast<const uint8_t *>(begin), _writer.write(reinterpret_cast<const uint8_t*>(begin),
static_cast<size_t>(end - begin)); static_cast<size_t>(end - begin));
} }
template <size_t N> template <size_t N>
void writeRaw(const char (&s)[N]) { void writeRaw(const char (&s)[N]) {
_writer.write(reinterpret_cast<const uint8_t *>(s), N - 1); _writer.write(reinterpret_cast<const uint8_t*>(s), N - 1);
} }
void writeRaw(char c) { void writeRaw(char c) {
_writer.write(static_cast<uint8_t>(c)); _writer.write(static_cast<uint8_t>(c));
@@ -166,6 +168,6 @@ class TextFormatter {
CountingDecorator<TWriter> _writer; CountingDecorator<TWriter> _writer;
private: private:
TextFormatter &operator=(const TextFormatter &); // cannot be assigned TextFormatter& operator=(const TextFormatter&); // cannot be assigned
}; };
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -13,19 +13,19 @@ namespace ARDUINOJSON_NAMESPACE {
#if ARDUINOJSON_ENABLE_ALIGNMENT #if ARDUINOJSON_ENABLE_ALIGNMENT
inline bool isAligned(size_t value) { inline bool isAligned(size_t value) {
const size_t mask = sizeof(void *) - 1; const size_t mask = sizeof(void*) - 1;
size_t addr = value; size_t addr = value;
return (addr & mask) == 0; return (addr & mask) == 0;
} }
inline size_t addPadding(size_t bytes) { inline size_t addPadding(size_t bytes) {
const size_t mask = sizeof(void *) - 1; const size_t mask = sizeof(void*) - 1;
return (bytes + mask) & ~mask; return (bytes + mask) & ~mask;
} }
template <size_t bytes> template <size_t bytes>
struct AddPadding { struct AddPadding {
static const size_t mask = sizeof(void *) - 1; static const size_t mask = sizeof(void*) - 1;
static const size_t value = (bytes + mask) & ~mask; static const size_t value = (bytes + mask) & ~mask;
}; };
@@ -47,14 +47,14 @@ struct AddPadding {
#endif #endif
template <typename T> template <typename T>
inline bool isAligned(T *ptr) { inline bool isAligned(T* ptr) {
return isAligned(reinterpret_cast<size_t>(ptr)); return isAligned(reinterpret_cast<size_t>(ptr));
} }
template <typename T> template <typename T>
inline T *addPadding(T *p) { inline T* addPadding(T* p) {
size_t address = addPadding(reinterpret_cast<size_t>(p)); size_t address = addPadding(reinterpret_cast<size_t>(p));
return reinterpret_cast<T *>(address); return reinterpret_cast<T*>(address);
} }
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -14,6 +14,16 @@
#define JSON_STRING_SIZE(SIZE) (SIZE + 1) #define JSON_STRING_SIZE(SIZE) (SIZE + 1)
// Computes the size required to store an array in a JsonDocument.
// https://arduinojson.org/v6/how-to/determine-the-capacity-of-the-jsondocument/
#define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \
((NUMBER_OF_ELEMENTS) * sizeof(ARDUINOJSON_NAMESPACE::VariantSlot))
// Returns the size (in bytes) of an object with n elements.
// Can be very handy to determine the size of a StaticMemoryPool.
#define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \
((NUMBER_OF_ELEMENTS) * sizeof(ARDUINOJSON_NAMESPACE::VariantSlot))
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
// _begin _end // _begin _end
@@ -173,7 +183,8 @@ class MemoryPool {
return next; return next;
// jump to next terminator // jump to next terminator
while (*next) ++next; while (*next)
++next;
} }
return 0; return 0;
} }
@@ -208,4 +219,35 @@ class MemoryPool {
bool _overflowed; bool _overflowed;
}; };
template <typename TAdaptedString, typename TCallback>
bool storeString(MemoryPool* pool, TAdaptedString str,
StringStoragePolicy::Copy, TCallback callback) {
const char* copy = pool->saveString(str);
JsonString storedString(copy, str.size(), JsonString::Copied);
callback(storedString);
return copy != 0;
}
template <typename TAdaptedString, typename TCallback>
bool storeString(MemoryPool*, TAdaptedString str, StringStoragePolicy::Link,
TCallback callback) {
JsonString storedString(str.data(), str.size(), JsonString::Linked);
callback(storedString);
return !str.isNull();
}
template <typename TAdaptedString, typename TCallback>
bool storeString(MemoryPool* pool, TAdaptedString str,
StringStoragePolicy::LinkOrCopy policy, TCallback callback) {
if (policy.link)
return storeString(pool, str, StringStoragePolicy::Link(), callback);
else
return storeString(pool, str, StringStoragePolicy::Copy(), callback);
}
template <typename TAdaptedString, typename TCallback>
bool storeString(MemoryPool* pool, TAdaptedString str, TCallback callback) {
return storeString(pool, str, str.storagePolicy(), callback);
}
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -1,21 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Polyfills/type_traits.hpp>
namespace ARDUINOJSON_NAMESPACE {
struct Visitable {
// template<Visitor>
// void accept(Visitor&) const;
};
template <typename T>
struct IsVisitable : is_base_of<Visitable, T> {};
template <typename T>
struct IsVisitable<T &> : IsVisitable<T> {};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -16,33 +16,31 @@ namespace ARDUINOJSON_NAMESPACE {
template <typename TReader, typename TStringStorage> template <typename TReader, typename TStringStorage>
class MsgPackDeserializer { class MsgPackDeserializer {
public: public:
MsgPackDeserializer(MemoryPool &pool, TReader reader, MsgPackDeserializer(MemoryPool* pool, TReader reader,
TStringStorage stringStorage) TStringStorage stringStorage)
: _pool(&pool), : _pool(pool),
_reader(reader), _reader(reader),
_stringStorage(stringStorage), _stringStorage(stringStorage),
_error(DeserializationError::Ok),
_foundSomething(false) {} _foundSomething(false) {}
template <typename TFilter> template <typename TFilter>
DeserializationError parse(VariantData &variant, TFilter filter, DeserializationError parse(VariantData& variant, TFilter filter,
NestingLimit nestingLimit) { NestingLimit nestingLimit) {
parseVariant(&variant, filter, nestingLimit); DeserializationError::Code err;
return _foundSomething ? _error : DeserializationError::EmptyInput; err = parseVariant(&variant, filter, nestingLimit);
return _foundSomething ? err : DeserializationError::EmptyInput;
} }
private: private:
bool invalidInput() {
_error = DeserializationError::InvalidInput;
return false;
}
template <typename TFilter> template <typename TFilter>
bool parseVariant(VariantData *variant, TFilter filter, DeserializationError::Code parseVariant(VariantData* variant, TFilter filter,
NestingLimit nestingLimit) { NestingLimit nestingLimit) {
DeserializationError::Code err;
uint8_t code = 0; // TODO: why do we need to initialize this variable? uint8_t code = 0; // TODO: why do we need to initialize this variable?
if (!readByte(code)) err = readByte(code);
return false; if (err)
return err;
_foundSomething = true; _foundSomething = true;
@@ -56,20 +54,20 @@ class MsgPackDeserializer {
switch (code) { switch (code) {
case 0xc0: case 0xc0:
// already null // already null
return true; return DeserializationError::Ok;
case 0xc1: case 0xc1:
return invalidInput(); return DeserializationError::InvalidInput;
case 0xc2: case 0xc2:
if (allowValue) if (allowValue)
variant->setBoolean(false); variant->setBoolean(false);
return true; return DeserializationError::Ok;
case 0xc3: case 0xc3:
if (allowValue) if (allowValue)
variant->setBoolean(true); variant->setBoolean(true);
return true; return DeserializationError::Ok;
case 0xc4: // bin 8 (not supported) case 0xc4: // bin 8 (not supported)
return skipString<uint8_t>(); return skipString<uint8_t>();
@@ -221,210 +219,260 @@ class MsgPackDeserializer {
if (allowValue) if (allowValue)
variant->setInteger(static_cast<int8_t>(code)); variant->setInteger(static_cast<int8_t>(code));
return true; return DeserializationError::Ok;
} }
bool readByte(uint8_t &value) { DeserializationError::Code readByte(uint8_t& value) {
int c = _reader.read(); int c = _reader.read();
if (c < 0) { if (c < 0)
_error = DeserializationError::IncompleteInput; return DeserializationError::IncompleteInput;
return false;
}
value = static_cast<uint8_t>(c); value = static_cast<uint8_t>(c);
return true; return DeserializationError::Ok;
} }
bool readBytes(uint8_t *p, size_t n) { DeserializationError::Code readBytes(uint8_t* p, size_t n) {
if (_reader.readBytes(reinterpret_cast<char *>(p), n) == n) if (_reader.readBytes(reinterpret_cast<char*>(p), n) == n)
return true; return DeserializationError::Ok;
_error = DeserializationError::IncompleteInput; return DeserializationError::IncompleteInput;
return false;
} }
template <typename T> template <typename T>
bool readBytes(T &value) { DeserializationError::Code readBytes(T& value) {
return readBytes(reinterpret_cast<uint8_t *>(&value), sizeof(value)); return readBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
} }
bool skipBytes(size_t n) { DeserializationError::Code skipBytes(size_t n) {
for (; n; --n) { for (; n; --n) {
if (_reader.read() < 0) { if (_reader.read() < 0)
_error = DeserializationError::IncompleteInput; return DeserializationError::IncompleteInput;
return false;
} }
} return DeserializationError::Ok;
return true;
} }
template <typename T> template <typename T>
bool readInteger(T &value) { DeserializationError::Code readInteger(T& value) {
if (!readBytes(value)) DeserializationError::Code err;
return false;
err = readBytes(value);
if (err)
return err;
fixEndianess(value); fixEndianess(value);
return true;
return DeserializationError::Ok;
} }
template <typename T> template <typename T>
bool readInteger(VariantData *variant) { DeserializationError::Code readInteger(VariantData* variant) {
DeserializationError::Code err;
T value; T value;
if (!readInteger(value))
return false; err = readInteger(value);
if (err)
return err;
variant->setInteger(value); variant->setInteger(value);
return true;
return DeserializationError::Ok;
} }
template <typename T> template <typename T>
typename enable_if<sizeof(T) == 4, bool>::type readFloat( typename enable_if<sizeof(T) == 4, DeserializationError::Code>::type
VariantData *variant) { readFloat(VariantData* variant) {
DeserializationError::Code err;
T value; T value;
if (!readBytes(value))
return false; err = readBytes(value);
if (err)
return err;
fixEndianess(value); fixEndianess(value);
variant->setFloat(value); variant->setFloat(value);
return true;
return DeserializationError::Ok;
} }
template <typename T> template <typename T>
typename enable_if<sizeof(T) == 8, bool>::type readDouble( typename enable_if<sizeof(T) == 8, DeserializationError::Code>::type
VariantData *variant) { readDouble(VariantData* variant) {
DeserializationError::Code err;
T value; T value;
if (!readBytes(value))
return false; err = readBytes(value);
if (err)
return err;
fixEndianess(value); fixEndianess(value);
variant->setFloat(value); variant->setFloat(value);
return true;
return DeserializationError::Ok;
} }
template <typename T> template <typename T>
typename enable_if<sizeof(T) == 4, bool>::type readDouble( typename enable_if<sizeof(T) == 4, DeserializationError::Code>::type
VariantData *variant) { readDouble(VariantData* variant) {
DeserializationError::Code err;
uint8_t i[8]; // input is 8 bytes uint8_t i[8]; // input is 8 bytes
T value; // output is 4 bytes T value; // output is 4 bytes
uint8_t *o = reinterpret_cast<uint8_t *>(&value); uint8_t* o = reinterpret_cast<uint8_t*>(&value);
if (!readBytes(i, 8))
return false; err = readBytes(i, 8);
if (err)
return err;
doubleToFloat(i, o); doubleToFloat(i, o);
fixEndianess(value); fixEndianess(value);
variant->setFloat(value); variant->setFloat(value);
return true;
return DeserializationError::Ok;
} }
template <typename T> template <typename T>
bool readString(VariantData *variant) { DeserializationError::Code readString(VariantData* variant) {
DeserializationError::Code err;
T size; T size;
if (!readInteger(size))
return false; err = readInteger(size);
if (err)
return err;
return readString(variant, size); return readString(variant, size);
} }
template <typename T> template <typename T>
bool readString() { DeserializationError::Code readString() {
DeserializationError::Code err;
T size; T size;
if (!readInteger(size))
return false; err = readInteger(size);
if (err)
return err;
return readString(size); return readString(size);
} }
template <typename T> template <typename T>
bool skipString() { DeserializationError::Code skipString() {
DeserializationError::Code err;
T size; T size;
if (!readInteger(size))
return false; err = readInteger(size);
if (err)
return err;
return skipBytes(size); return skipBytes(size);
} }
bool readString(VariantData *variant, size_t n) { DeserializationError::Code readString(VariantData* variant, size_t n) {
if (!readString(n)) DeserializationError::Code err;
return false;
err = readString(n);
if (err)
return err;
variant->setString(_stringStorage.save()); variant->setString(_stringStorage.save());
return true; return DeserializationError::Ok;
} }
bool readString(size_t n) { DeserializationError::Code readString(size_t n) {
DeserializationError::Code err;
_stringStorage.startString(); _stringStorage.startString();
for (; n; --n) { for (; n; --n) {
uint8_t c; uint8_t c;
if (!readBytes(c))
return false; err = readBytes(c);
if (err)
return err;
_stringStorage.append(static_cast<char>(c)); _stringStorage.append(static_cast<char>(c));
} }
if (!_stringStorage.isValid()) {
_error = DeserializationError::NoMemory;
return false;
}
return true; if (!_stringStorage.isValid())
return DeserializationError::NoMemory;
return DeserializationError::Ok;
} }
template <typename TSize, typename TFilter> template <typename TSize, typename TFilter>
bool readArray(VariantData *variant, TFilter filter, DeserializationError::Code readArray(VariantData* variant, TFilter filter,
NestingLimit nestingLimit) { NestingLimit nestingLimit) {
DeserializationError::Code err;
TSize size; TSize size;
if (!readInteger(size))
return false; err = readInteger(size);
if (err)
return err;
return readArray(variant, size, filter, nestingLimit); return readArray(variant, size, filter, nestingLimit);
} }
template <typename TFilter> template <typename TFilter>
bool readArray(VariantData *variant, size_t n, TFilter filter, DeserializationError::Code readArray(VariantData* variant, size_t n,
TFilter filter,
NestingLimit nestingLimit) { NestingLimit nestingLimit) {
if (nestingLimit.reached()) { DeserializationError::Code err;
_error = DeserializationError::TooDeep;
return false; if (nestingLimit.reached())
} return DeserializationError::TooDeep;
bool allowArray = filter.allowArray(); bool allowArray = filter.allowArray();
CollectionData *array = allowArray ? &variant->toArray() : 0; CollectionData* array = allowArray ? &variant->toArray() : 0;
TFilter memberFilter = filter[0U]; TFilter memberFilter = filter[0U];
for (; n; --n) { for (; n; --n) {
VariantData *value; VariantData* value;
if (memberFilter.allow()) { if (memberFilter.allow()) {
value = array->addElement(_pool); value = array->addElement(_pool);
if (!value) { if (!value)
_error = DeserializationError::NoMemory; return DeserializationError::NoMemory;
return false;
}
} else { } else {
value = 0; value = 0;
} }
if (!parseVariant(value, memberFilter, nestingLimit.decrement())) err = parseVariant(value, memberFilter, nestingLimit.decrement());
return false; if (err)
return err;
} }
return true; return DeserializationError::Ok;
} }
template <typename TSize, typename TFilter> template <typename TSize, typename TFilter>
bool readObject(VariantData *variant, TFilter filter, DeserializationError::Code readObject(VariantData* variant, TFilter filter,
NestingLimit nestingLimit) { NestingLimit nestingLimit) {
DeserializationError::Code err;
TSize size; TSize size;
if (!readInteger(size))
return false; err = readInteger(size);
if (err)
return err;
return readObject(variant, size, filter, nestingLimit); return readObject(variant, size, filter, nestingLimit);
} }
template <typename TFilter> template <typename TFilter>
bool readObject(VariantData *variant, size_t n, TFilter filter, DeserializationError::Code readObject(VariantData* variant, size_t n,
TFilter filter,
NestingLimit nestingLimit) { NestingLimit nestingLimit) {
if (nestingLimit.reached()) { DeserializationError::Code err;
_error = DeserializationError::TooDeep;
return false;
}
CollectionData *object = filter.allowObject() ? &variant->toObject() : 0; if (nestingLimit.reached())
return DeserializationError::TooDeep;
CollectionData* object = filter.allowObject() ? &variant->toObject() : 0;
for (; n; --n) { for (; n; --n) {
if (!readKey()) err = readKey();
return false; if (err)
return err;
String key = _stringStorage.str(); JsonString key = _stringStorage.str();
TFilter memberFilter = filter[key.c_str()]; TFilter memberFilter = filter[key.c_str()];
VariantData *member; VariantData* member;
if (memberFilter.allow()) { if (memberFilter.allow()) {
ARDUINOJSON_ASSERT(object); ARDUINOJSON_ASSERT(object);
@@ -433,11 +481,9 @@ class MsgPackDeserializer {
// This MUST be done before adding the slot. // This MUST be done before adding the slot.
key = _stringStorage.save(); key = _stringStorage.save();
VariantSlot *slot = object->addSlot(_pool); VariantSlot* slot = object->addSlot(_pool);
if (!slot) { if (!slot)
_error = DeserializationError::NoMemory; return DeserializationError::NoMemory;
return false;
}
slot->setKey(key); slot->setKey(key);
@@ -446,17 +492,21 @@ class MsgPackDeserializer {
member = 0; member = 0;
} }
if (!parseVariant(member, memberFilter, nestingLimit.decrement())) err = parseVariant(member, memberFilter, nestingLimit.decrement());
return false; if (err)
return err;
} }
return true; return DeserializationError::Ok;
} }
bool readKey() { DeserializationError::Code readKey() {
DeserializationError::Code err;
uint8_t code; uint8_t code;
if (!readByte(code))
return false; err = readByte(code);
if (err)
return err;
if ((code & 0xe0) == 0xa0) if ((code & 0xe0) == 0xa0)
return readString(code & 0x1f); return readString(code & 0x1f);
@@ -472,125 +522,136 @@ class MsgPackDeserializer {
return readString<uint32_t>(); return readString<uint32_t>();
default: default:
return invalidInput(); return DeserializationError::InvalidInput;
} }
} }
template <typename T> template <typename T>
bool skipExt() { DeserializationError::Code skipExt() {
DeserializationError::Code err;
T size; T size;
if (!readInteger(size))
return false; err = readInteger(size);
if (err)
return err;
return skipBytes(size + 1U); return skipBytes(size + 1U);
} }
MemoryPool *_pool; MemoryPool* _pool;
TReader _reader; TReader _reader;
TStringStorage _stringStorage; TStringStorage _stringStorage;
DeserializationError _error;
bool _foundSomething; bool _foundSomething;
}; };
// // Parses a MessagePack input and puts the result in a JsonDocument.
// deserializeMsgPack(JsonDocument&, const std::string&, ...) // https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
//
// ... = NestingLimit
template <typename TString> template <typename TString>
DeserializationError deserializeMsgPack( DeserializationError deserializeMsgPack(
JsonDocument &doc, const TString &input, JsonDocument& doc, const TString& input,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, return deserialize<MsgPackDeserializer>(doc, input, nestingLimit,
AllowAllFilter()); AllowAllFilter());
} }
// ... = Filter, NestingLimit
// Parses a MessagePack input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename TString> template <typename TString>
DeserializationError deserializeMsgPack( DeserializationError deserializeMsgPack(
JsonDocument &doc, const TString &input, Filter filter, JsonDocument& doc, const TString& input, Filter filter,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
} }
// ... = NestingLimit, Filter
// Parses a MessagePack input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename TString> template <typename TString>
DeserializationError deserializeMsgPack(JsonDocument &doc, const TString &input, DeserializationError deserializeMsgPack(JsonDocument& doc, const TString& input,
NestingLimit nestingLimit, NestingLimit nestingLimit,
Filter filter) { Filter filter) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
} }
// // Parses a MessagePack input and puts the result in a JsonDocument.
// deserializeMsgPack(JsonDocument&, std::istream&, ...) // https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
//
// ... = NestingLimit
template <typename TStream> template <typename TStream>
DeserializationError deserializeMsgPack( DeserializationError deserializeMsgPack(
JsonDocument &doc, TStream &input, JsonDocument& doc, TStream& input,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, return deserialize<MsgPackDeserializer>(doc, input, nestingLimit,
AllowAllFilter()); AllowAllFilter());
} }
// ... = Filter, NestingLimit
// Parses a MessagePack input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename TStream> template <typename TStream>
DeserializationError deserializeMsgPack( DeserializationError deserializeMsgPack(
JsonDocument &doc, TStream &input, Filter filter, JsonDocument& doc, TStream& input, Filter filter,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
} }
// ... = NestingLimit, Filter
// Parses a MessagePack input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename TStream> template <typename TStream>
DeserializationError deserializeMsgPack(JsonDocument &doc, TStream &input, DeserializationError deserializeMsgPack(JsonDocument& doc, TStream& input,
NestingLimit nestingLimit, NestingLimit nestingLimit,
Filter filter) { Filter filter) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
} }
// // Parses a MessagePack input and puts the result in a JsonDocument.
// deserializeMsgPack(JsonDocument&, char*, ...) // https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
//
// ... = NestingLimit
template <typename TChar> template <typename TChar>
DeserializationError deserializeMsgPack( DeserializationError deserializeMsgPack(
JsonDocument &doc, TChar *input, JsonDocument& doc, TChar* input,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, return deserialize<MsgPackDeserializer>(doc, input, nestingLimit,
AllowAllFilter()); AllowAllFilter());
} }
// ... = Filter, NestingLimit
// Parses a MessagePack input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename TChar> template <typename TChar>
DeserializationError deserializeMsgPack( DeserializationError deserializeMsgPack(
JsonDocument &doc, TChar *input, Filter filter, JsonDocument& doc, TChar* input, Filter filter,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
} }
// ... = NestingLimit, Filter
// Parses a MessagePack input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename TChar> template <typename TChar>
DeserializationError deserializeMsgPack(JsonDocument &doc, TChar *input, DeserializationError deserializeMsgPack(JsonDocument& doc, TChar* input,
NestingLimit nestingLimit, NestingLimit nestingLimit,
Filter filter) { Filter filter) {
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter); return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
} }
// // Parses a MessagePack input and puts the result in a JsonDocument.
// deserializeMsgPack(JsonDocument&, char*, size_t, ...) // https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
//
// ... = NestingLimit
template <typename TChar> template <typename TChar>
DeserializationError deserializeMsgPack( DeserializationError deserializeMsgPack(
JsonDocument &doc, TChar *input, size_t inputSize, JsonDocument& doc, TChar* input, size_t inputSize,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit, return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit,
AllowAllFilter()); AllowAllFilter());
} }
// ... = Filter, NestingLimit
// Parses a MessagePack input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename TChar> template <typename TChar>
DeserializationError deserializeMsgPack( DeserializationError deserializeMsgPack(
JsonDocument &doc, TChar *input, size_t inputSize, Filter filter, JsonDocument& doc, TChar* input, size_t inputSize, Filter filter,
NestingLimit nestingLimit = NestingLimit()) { NestingLimit nestingLimit = NestingLimit()) {
return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit, return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit,
filter); filter);
} }
// ... = NestingLimit, Filter
// Parses a MessagePack input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename TChar> template <typename TChar>
DeserializationError deserializeMsgPack(JsonDocument &doc, TChar *input, DeserializationError deserializeMsgPack(JsonDocument& doc, TChar* input,
size_t inputSize, size_t inputSize,
NestingLimit nestingLimit, NestingLimit nestingLimit,
Filter filter) { Filter filter) {

View File

@@ -23,8 +23,8 @@ class MsgPackSerializer : public Visitor<size_t> {
template <typename T> template <typename T>
typename enable_if<sizeof(T) == 4, size_t>::type visitFloat(T value32) { typename enable_if<sizeof(T) == 4, size_t>::type visitFloat(T value32) {
if (canConvertNumber<Integer>(value32)) { if (canConvertNumber<JsonInteger>(value32)) {
Integer truncatedValue = Integer(value32); JsonInteger truncatedValue = JsonInteger(value32);
if (value32 == T(truncatedValue)) if (value32 == T(truncatedValue))
return visitSignedInteger(truncatedValue); return visitSignedInteger(truncatedValue);
} }
@@ -55,7 +55,7 @@ class MsgPackSerializer : public Visitor<size_t> {
writeByte(0xDD); writeByte(0xDD);
writeInteger(uint32_t(n)); writeInteger(uint32_t(n));
} }
for (VariantSlot* slot = array.head(); slot; slot = slot->next()) { for (const VariantSlot* slot = array.head(); slot; slot = slot->next()) {
slot->data()->accept(*this); slot->data()->accept(*this);
} }
return bytesWritten(); return bytesWritten();
@@ -72,7 +72,7 @@ class MsgPackSerializer : public Visitor<size_t> {
writeByte(0xDF); writeByte(0xDF);
writeInteger(uint32_t(n)); writeInteger(uint32_t(n));
} }
for (VariantSlot* slot = object.head(); slot; slot = slot->next()) { for (const VariantSlot* slot = object.head(); slot; slot = slot->next()) {
visitString(slot->key()); visitString(slot->key());
slot->data()->accept(*this); slot->data()->accept(*this);
} }
@@ -107,9 +107,9 @@ class MsgPackSerializer : public Visitor<size_t> {
return bytesWritten(); return bytesWritten();
} }
size_t visitSignedInteger(Integer value) { size_t visitSignedInteger(JsonInteger value) {
if (value > 0) { if (value > 0) {
visitUnsignedInteger(static_cast<UInt>(value)); visitUnsignedInteger(static_cast<JsonUInt>(value));
} else if (value >= -0x20) { } else if (value >= -0x20) {
writeInteger(int8_t(value)); writeInteger(int8_t(value));
} else if (value >= -0x80) { } else if (value >= -0x80) {
@@ -137,7 +137,7 @@ class MsgPackSerializer : public Visitor<size_t> {
return bytesWritten(); return bytesWritten();
} }
size_t visitUnsignedInteger(UInt value) { size_t visitUnsignedInteger(JsonUInt value) {
if (value <= 0x7F) { if (value <= 0x7F) {
writeInteger(uint8_t(value)); writeInteger(uint8_t(value));
} else if (value <= 0xFF) { } else if (value <= 0xFF) {
@@ -197,19 +197,23 @@ class MsgPackSerializer : public Visitor<size_t> {
CountingDecorator<TWriter> _writer; CountingDecorator<TWriter> _writer;
}; };
template <typename TSource, typename TDestination> // Produces a MessagePack document.
inline size_t serializeMsgPack(const TSource& source, TDestination& output) { // https://arduinojson.org/v6/api/msgpack/serializemsgpack/
template <typename TDestination>
inline size_t serializeMsgPack(JsonVariantConst source, TDestination& output) {
return serialize<MsgPackSerializer>(source, output); return serialize<MsgPackSerializer>(source, output);
} }
template <typename TSource> // Produces a MessagePack document.
inline size_t serializeMsgPack(const TSource& source, void* output, // https://arduinojson.org/v6/api/msgpack/serializemsgpack/
inline size_t serializeMsgPack(JsonVariantConst source, void* output,
size_t size) { size_t size) {
return serialize<MsgPackSerializer>(source, output, size); return serialize<MsgPackSerializer>(source, output, size);
} }
template <typename TSource> // Computes the length of the document that serializeMsgPack() produces.
inline size_t measureMsgPack(const TSource& source) { // https://arduinojson.org/v6/api/msgpack/measuremsgpack/
inline size_t measureMsgPack(JsonVariantConst source) {
return measure<MsgPackSerializer>(source); return measure<MsgPackSerializer>(source);
} }

View File

@@ -9,38 +9,38 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
#if ARDUINOJSON_LITTLE_ENDIAN #if ARDUINOJSON_LITTLE_ENDIAN
inline void swapBytes(uint8_t &a, uint8_t &b) { inline void swapBytes(uint8_t& a, uint8_t& b) {
uint8_t t(a); uint8_t t(a);
a = b; a = b;
b = t; b = t;
} }
inline void fixEndianess(uint8_t *p, integral_constant<size_t, 8>) { inline void fixEndianess(uint8_t* p, integral_constant<size_t, 8>) {
swapBytes(p[0], p[7]); swapBytes(p[0], p[7]);
swapBytes(p[1], p[6]); swapBytes(p[1], p[6]);
swapBytes(p[2], p[5]); swapBytes(p[2], p[5]);
swapBytes(p[3], p[4]); swapBytes(p[3], p[4]);
} }
inline void fixEndianess(uint8_t *p, integral_constant<size_t, 4>) { inline void fixEndianess(uint8_t* p, integral_constant<size_t, 4>) {
swapBytes(p[0], p[3]); swapBytes(p[0], p[3]);
swapBytes(p[1], p[2]); swapBytes(p[1], p[2]);
} }
inline void fixEndianess(uint8_t *p, integral_constant<size_t, 2>) { inline void fixEndianess(uint8_t* p, integral_constant<size_t, 2>) {
swapBytes(p[0], p[1]); swapBytes(p[0], p[1]);
} }
inline void fixEndianess(uint8_t *, integral_constant<size_t, 1>) {} inline void fixEndianess(uint8_t*, integral_constant<size_t, 1>) {}
template <typename T> template <typename T>
inline void fixEndianess(T &value) { inline void fixEndianess(T& value) {
fixEndianess(reinterpret_cast<uint8_t *>(&value), fixEndianess(reinterpret_cast<uint8_t*>(&value),
integral_constant<size_t, sizeof(T)>()); integral_constant<size_t, sizeof(T)>());
} }
#else #else
template <typename T> template <typename T>
inline void fixEndianess(T &) {} inline void fixEndianess(T&) {}
#endif #endif
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -12,6 +12,7 @@
#include <ArduinoJson/Polyfills/math.hpp> #include <ArduinoJson/Polyfills/math.hpp>
#include <ArduinoJson/Polyfills/preprocessor.hpp> #include <ArduinoJson/Polyfills/preprocessor.hpp>
#include <ArduinoJson/Polyfills/static_array.hpp> #include <ArduinoJson/Polyfills/static_array.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
@@ -116,6 +117,22 @@ struct FloatTraits<T, 8 /*64bits*/> {
return forge(0x7FEFFFFF, 0xFFFFFFFF); return forge(0x7FEFFFFF, 0xFFFFFFFF);
} }
template <typename TOut> // int64_t
static T highest_for(
typename enable_if<is_integral<TOut>::value && is_signed<TOut>::value &&
sizeof(TOut) == 8,
signed>::type* = 0) {
return forge(0x43DFFFFF, 0xFFFFFFFF); // 9.2233720368547748e+18
}
template <typename TOut> // uint64_t
static T highest_for(
typename enable_if<is_integral<TOut>::value && is_unsigned<TOut>::value &&
sizeof(TOut) == 8,
unsigned>::type* = 0) {
return forge(0x43EFFFFF, 0xFFFFFFFF); // 1.8446744073709549568e+19
}
static T lowest() { static T lowest() {
return forge(0xFFEFFFFF, 0xFFFFFFFF); return forge(0xFFEFFFFF, 0xFFFFFFFF);
} }
@@ -212,6 +229,38 @@ struct FloatTraits<T, 4 /*32bits*/> {
return forge(0x7f7fffff); return forge(0x7f7fffff);
} }
template <typename TOut> // int32_t
static T highest_for(
typename enable_if<is_integral<TOut>::value && is_signed<TOut>::value &&
sizeof(TOut) == 4,
signed>::type* = 0) {
return forge(0x4EFFFFFF); // 2.14748352E9
}
template <typename TOut> // uint32_t
static T highest_for(
typename enable_if<is_integral<TOut>::value && is_unsigned<TOut>::value &&
sizeof(TOut) == 4,
unsigned>::type* = 0) {
return forge(0x4F7FFFFF); // 4.29496704E9
}
template <typename TOut> // int64_t
static T highest_for(
typename enable_if<is_integral<TOut>::value && is_signed<TOut>::value &&
sizeof(TOut) == 8,
signed>::type* = 0) {
return forge(0x5EFFFFFF); // 9.22337148709896192E18
}
template <typename TOut> // uint64_t
static T highest_for(
typename enable_if<is_integral<TOut>::value && is_unsigned<TOut>::value &&
sizeof(TOut) == 8,
unsigned>::type* = 0) {
return forge(0x5F7FFFFF); // 1.844674297419792384E19
}
static T lowest() { static T lowest() {
return forge(0xFf7fffff); return forge(0xFf7fffff);
} }

View File

@@ -10,8 +10,8 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
#if ARDUINOJSON_USE_DOUBLE #if ARDUINOJSON_USE_DOUBLE
typedef double Float; typedef double JsonFloat;
#else #else
typedef float Float; typedef float JsonFloat;
#endif #endif
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -12,18 +12,18 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
#if ARDUINOJSON_USE_LONG_LONG #if ARDUINOJSON_USE_LONG_LONG
typedef int64_t Integer; typedef int64_t JsonInteger;
typedef uint64_t UInt; typedef uint64_t JsonUInt;
#else #else
typedef long Integer; typedef long JsonInteger;
typedef unsigned long UInt; typedef unsigned long JsonUInt;
#endif #endif
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE
#if ARDUINOJSON_HAS_LONG_LONG && !ARDUINOJSON_USE_LONG_LONG #if ARDUINOJSON_HAS_LONG_LONG && !ARDUINOJSON_USE_LONG_LONG
# define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) \ # define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) \
static_assert(sizeof(T) <= sizeof(ARDUINOJSON_NAMESPACE::Integer), \ static_assert(sizeof(T) <= sizeof(ARDUINOJSON_NAMESPACE::JsonInteger), \
"To use 64-bit integers with ArduinoJson, you must set " \ "To use 64-bit integers with ArduinoJson, you must set " \
"ARDUINOJSON_USE_LONG_LONG to 1. See " \ "ARDUINOJSON_USE_LONG_LONG to 1. See " \
"https://arduinojson.org/v6/api/config/use_long_long/"); "https://arduinojson.org/v6/api/config/use_long_long/");

View File

@@ -4,7 +4,7 @@
#pragma once #pragma once
#include <ArduinoJson/Numbers/Integer.hpp> #include <ArduinoJson/Numbers/JsonInteger.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
@@ -20,7 +20,7 @@ enum CompareResult {
}; };
template <typename T> template <typename T>
CompareResult arithmeticCompare(const T &lhs, const T &rhs) { CompareResult arithmeticCompare(const T& lhs, const T& rhs) {
if (lhs < rhs) if (lhs < rhs)
return COMPARE_RESULT_LESS; return COMPARE_RESULT_LESS;
else if (lhs > rhs) else if (lhs > rhs)
@@ -31,38 +31,38 @@ CompareResult arithmeticCompare(const T &lhs, const T &rhs) {
template <typename T1, typename T2> template <typename T1, typename T2>
CompareResult arithmeticCompare( CompareResult arithmeticCompare(
const T1 &lhs, const T2 &rhs, const T1& lhs, const T2& rhs,
typename enable_if<is_integral<T1>::value && is_integral<T2>::value && typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
sizeof(T1) < sizeof(T2), sizeof(T1) < sizeof(T2),
int // Using int instead of void to avoid C2572 on int // Using int instead of void to avoid C2572 on
// Visual Studio 2012, 2013, and 2015 // Visual Studio 2012, 2013, and 2015
>::type * = 0) { >::type* = 0) {
return arithmeticCompare<T2>(static_cast<T2>(lhs), rhs); return arithmeticCompare<T2>(static_cast<T2>(lhs), rhs);
} }
template <typename T1, typename T2> template <typename T1, typename T2>
CompareResult arithmeticCompare( CompareResult arithmeticCompare(
const T1 &lhs, const T2 &rhs, const T1& lhs, const T2& rhs,
typename enable_if<is_integral<T1>::value && is_integral<T2>::value && typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
sizeof(T2) < sizeof(T1)>::type * = 0) { sizeof(T2) < sizeof(T1)>::type* = 0) {
return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs)); return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs));
} }
template <typename T1, typename T2> template <typename T1, typename T2>
CompareResult arithmeticCompare( CompareResult arithmeticCompare(
const T1 &lhs, const T2 &rhs, const T1& lhs, const T2& rhs,
typename enable_if<is_integral<T1>::value && is_integral<T2>::value && typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
is_signed<T1>::value == is_signed<T2>::value && is_signed<T1>::value == is_signed<T2>::value &&
sizeof(T2) == sizeof(T1)>::type * = 0) { sizeof(T2) == sizeof(T1)>::type* = 0) {
return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs)); return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs));
} }
template <typename T1, typename T2> template <typename T1, typename T2>
CompareResult arithmeticCompare( CompareResult arithmeticCompare(
const T1 &lhs, const T2 &rhs, const T1& lhs, const T2& rhs,
typename enable_if<is_integral<T1>::value && is_integral<T2>::value && typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
is_unsigned<T1>::value && is_signed<T2>::value && is_unsigned<T1>::value && is_signed<T2>::value &&
sizeof(T2) == sizeof(T1)>::type * = 0) { sizeof(T2) == sizeof(T1)>::type* = 0) {
if (rhs < 0) if (rhs < 0)
return COMPARE_RESULT_GREATER; return COMPARE_RESULT_GREATER;
return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs)); return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs));
@@ -70,10 +70,10 @@ CompareResult arithmeticCompare(
template <typename T1, typename T2> template <typename T1, typename T2>
CompareResult arithmeticCompare( CompareResult arithmeticCompare(
const T1 &lhs, const T2 &rhs, const T1& lhs, const T2& rhs,
typename enable_if<is_integral<T1>::value && is_integral<T2>::value && typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
is_signed<T1>::value && is_unsigned<T2>::value && is_signed<T1>::value && is_unsigned<T2>::value &&
sizeof(T2) == sizeof(T1)>::type * = 0) { sizeof(T2) == sizeof(T1)>::type* = 0) {
if (lhs < 0) if (lhs < 0)
return COMPARE_RESULT_LESS; return COMPARE_RESULT_LESS;
return arithmeticCompare<T2>(static_cast<T2>(lhs), rhs); return arithmeticCompare<T2>(static_cast<T2>(lhs), rhs);
@@ -81,23 +81,24 @@ CompareResult arithmeticCompare(
template <typename T1, typename T2> template <typename T1, typename T2>
CompareResult arithmeticCompare( CompareResult arithmeticCompare(
const T1 &lhs, const T2 &rhs, const T1& lhs, const T2& rhs,
typename enable_if<is_floating_point<T1>::value || typename enable_if<is_floating_point<T1>::value ||
is_floating_point<T2>::value>::type * = 0) { is_floating_point<T2>::value>::type* = 0) {
return arithmeticCompare<double>(static_cast<double>(lhs), return arithmeticCompare<double>(static_cast<double>(lhs),
static_cast<double>(rhs)); static_cast<double>(rhs));
} }
template <typename T2> template <typename T2>
CompareResult arithmeticCompareNegateLeft( CompareResult arithmeticCompareNegateLeft(
UInt, const T2 &, typename enable_if<is_unsigned<T2>::value>::type * = 0) { JsonUInt, const T2&,
typename enable_if<is_unsigned<T2>::value>::type* = 0) {
return COMPARE_RESULT_LESS; return COMPARE_RESULT_LESS;
} }
template <typename T2> template <typename T2>
CompareResult arithmeticCompareNegateLeft( CompareResult arithmeticCompareNegateLeft(
UInt lhs, const T2 &rhs, JsonUInt lhs, const T2& rhs,
typename enable_if<is_signed<T2>::value>::type * = 0) { typename enable_if<is_signed<T2>::value>::type* = 0) {
if (rhs > 0) if (rhs > 0)
return COMPARE_RESULT_LESS; return COMPARE_RESULT_LESS;
return arithmeticCompare(-rhs, static_cast<T2>(lhs)); return arithmeticCompare(-rhs, static_cast<T2>(lhs));
@@ -105,14 +106,15 @@ CompareResult arithmeticCompareNegateLeft(
template <typename T1> template <typename T1>
CompareResult arithmeticCompareNegateRight( CompareResult arithmeticCompareNegateRight(
const T1 &, UInt, typename enable_if<is_unsigned<T1>::value>::type * = 0) { const T1&, JsonUInt,
typename enable_if<is_unsigned<T1>::value>::type* = 0) {
return COMPARE_RESULT_GREATER; return COMPARE_RESULT_GREATER;
} }
template <typename T1> template <typename T1>
CompareResult arithmeticCompareNegateRight( CompareResult arithmeticCompareNegateRight(
const T1 &lhs, UInt rhs, const T1& lhs, JsonUInt rhs,
typename enable_if<is_signed<T1>::value>::type * = 0) { typename enable_if<is_signed<T1>::value>::type* = 0) {
if (lhs > 0) if (lhs > 0)
return COMPARE_RESULT_GREATER; return COMPARE_RESULT_GREATER;
return arithmeticCompare(static_cast<T1>(rhs), -lhs); return arithmeticCompare(static_cast<T1>(rhs), -lhs);

View File

@@ -14,7 +14,8 @@
# pragma GCC diagnostic ignored "-Wconversion" # pragma GCC diagnostic ignored "-Wconversion"
#endif #endif
#include <ArduinoJson/Numbers/Float.hpp> #include <ArduinoJson/Numbers/FloatTraits.hpp>
#include <ArduinoJson/Numbers/JsonFloat.hpp>
#include <ArduinoJson/Polyfills/limits.hpp> #include <ArduinoJson/Polyfills/limits.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp>
@@ -95,17 +96,34 @@ canConvertNumber(TIn value) {
return value <= TIn(numeric_limits<TOut>::highest()); return value <= TIn(numeric_limits<TOut>::highest());
} }
// float -> int32 // float32 -> int16
// float -> int64 // float64 -> int32
template <typename TOut, typename TIn> template <typename TOut, typename TIn>
typename enable_if<is_floating_point<TIn>::value && typename enable_if<is_floating_point<TIn>::value && is_integral<TOut>::value &&
!is_floating_point<TOut>::value, sizeof(TOut) < sizeof(TIn),
bool>::type bool>::type
canConvertNumber(TIn value) { canConvertNumber(TIn value) {
return value >= numeric_limits<TOut>::lowest() && return value >= numeric_limits<TOut>::lowest() &&
value <= numeric_limits<TOut>::highest(); value <= numeric_limits<TOut>::highest();
} }
// float32 -> int32
// float32 -> uint32
// float32 -> int64
// float32 -> uint64
// float64 -> int64
// float64 -> uint64
template <typename TOut, typename TIn>
typename enable_if<is_floating_point<TIn>::value && is_integral<TOut>::value &&
sizeof(TOut) >= sizeof(TIn),
bool>::type
canConvertNumber(TIn value) {
// Avoid error "9.22337e+18 is outside the range of representable values of
// type 'long'"
return value >= numeric_limits<TOut>::lowest() &&
value <= FloatTraits<TIn>::template highest_for<TOut>();
}
template <typename TOut, typename TIn> template <typename TOut, typename TIn>
TOut convertNumber(TIn value) { TOut convertNumber(TIn value) {
return canConvertNumber<TOut>(value) ? TOut(value) : 0; return canConvertNumber<TOut>(value) ? TOut(value) : 0;

View File

@@ -19,8 +19,8 @@ template <typename A, typename B>
struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> {}; struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> {};
inline bool parseNumber(const char* s, VariantData& result) { inline bool parseNumber(const char* s, VariantData& result) {
typedef FloatTraits<Float> traits; typedef FloatTraits<JsonFloat> traits;
typedef choose_largest<traits::mantissa_type, UInt>::type mantissa_t; typedef choose_largest<traits::mantissa_type, JsonUInt>::type mantissa_t;
typedef traits::exponent_type exponent_t; typedef traits::exponent_type exponent_t;
ARDUINOJSON_ASSERT(s != 0); ARDUINOJSON_ASSERT(s != 0);
@@ -55,7 +55,7 @@ inline bool parseNumber(const char* s, VariantData& result) {
mantissa_t mantissa = 0; mantissa_t mantissa = 0;
exponent_t exponent_offset = 0; exponent_t exponent_offset = 0;
const mantissa_t maxUint = UInt(-1); const mantissa_t maxUint = JsonUInt(-1);
while (isdigit(*s)) { while (isdigit(*s)) {
uint8_t digit = uint8_t(*s - '0'); uint8_t digit = uint8_t(*s - '0');
@@ -71,13 +71,13 @@ inline bool parseNumber(const char* s, VariantData& result) {
if (*s == '\0') { if (*s == '\0') {
if (is_negative) { if (is_negative) {
const mantissa_t sintMantissaMax = mantissa_t(1) const mantissa_t sintMantissaMax = mantissa_t(1)
<< (sizeof(Integer) * 8 - 1); << (sizeof(JsonInteger) * 8 - 1);
if (mantissa <= sintMantissaMax) { if (mantissa <= sintMantissaMax) {
result.setInteger(Integer(~mantissa + 1)); result.setInteger(JsonInteger(~mantissa + 1));
return true; return true;
} }
} else { } else {
result.setInteger(UInt(mantissa)); result.setInteger(JsonUInt(mantissa));
return true; return true;
} }
} }
@@ -136,8 +136,8 @@ inline bool parseNumber(const char* s, VariantData& result) {
if (*s != '\0') if (*s != '\0')
return false; return false;
Float final_result = JsonFloat final_result =
traits::make_float(static_cast<Float>(mantissa), exponent); traits::make_float(static_cast<JsonFloat>(mantissa), exponent);
result.setFloat(is_negative ? -final_result : final_result); result.setFloat(is_negative ? -final_result : final_result);
return true; return true;
@@ -148,6 +148,6 @@ inline T parseNumber(const char* s) {
VariantData value; VariantData value;
value.init(); // VariantData is a POD, so it has no constructor value.init(); // VariantData is a POD, so it has no constructor
parseNumber(s, value); parseNumber(s, value);
return Converter<T>::fromJson(VariantConstRef(&value)); return Converter<T>::fromJson(JsonVariantConst(&value));
} }
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -0,0 +1,246 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Object/JsonObjectConst.hpp>
#include <ArduinoJson/Object/MemberProxy.hpp>
namespace ARDUINOJSON_NAMESPACE {
class JsonArray;
// A reference to an object in a JsonDocument.
// https://arduinojson.org/v6/api/jsonobject/
class JsonObject : public VariantOperators<JsonObject> {
friend class VariantAttorney;
public:
typedef JsonObjectIterator iterator;
// Creates an unbound reference.
FORCE_INLINE JsonObject() : _data(0), _pool(0) {}
// INTERNAL USE ONLY
FORCE_INLINE JsonObject(MemoryPool* buf, CollectionData* data)
: _data(data), _pool(buf) {}
operator JsonVariant() const {
void* data = _data; // prevent warning cast-align
return JsonVariant(_pool, reinterpret_cast<VariantData*>(data));
}
operator JsonObjectConst() const {
return JsonObjectConst(_data);
}
operator JsonVariantConst() const {
return JsonVariantConst(collectionToVariant(_data));
}
// Returns true if the reference is unbound.
// https://arduinojson.org/v6/api/jsonobject/isnull/
FORCE_INLINE bool isNull() const {
return _data == 0;
}
// Returns true if the reference is bound.
// https://arduinojson.org/v6/api/jsonobject/isnull/
FORCE_INLINE operator bool() const {
return _data != 0;
}
// Returns the number of bytes occupied by the object.
// https://arduinojson.org/v6/api/jsonobject/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return _data ? _data->memoryUsage() : 0;
}
// Returns the depth (nesting level) of the object.
// https://arduinojson.org/v6/api/jsonobject/nesting/
FORCE_INLINE size_t nesting() const {
return variantNesting(collectionToVariant(_data));
}
// Returns the number of members in the object.
// https://arduinojson.org/v6/api/jsonobject/size/
FORCE_INLINE size_t size() const {
return _data ? _data->size() : 0;
}
// Returns an iterator to the first key-value pair of the object.
// https://arduinojson.org/v6/api/jsonobject/begin/
FORCE_INLINE iterator begin() const {
if (!_data)
return iterator();
return iterator(_pool, _data->head());
}
// Returns an iterator following the last key-value pair of the object.
// https://arduinojson.org/v6/api/jsonobject/end/
FORCE_INLINE iterator end() const {
return iterator();
}
// Removes all the members of the object.
// ⚠️ Doesn't release the memory associated with the removed members.
// https://arduinojson.org/v6/api/jsonobject/clear/
void clear() const {
if (!_data)
return;
_data->clear();
}
// Copies an object.
// https://arduinojson.org/v6/api/jsonobject/set/
FORCE_INLINE bool set(JsonObjectConst src) {
if (!_data || !src._data)
return false;
return _data->copyFrom(*src._data, _pool);
}
// Compares the content of two objects.
FORCE_INLINE bool operator==(JsonObject rhs) const {
return JsonObjectConst(_data) == JsonObjectConst(rhs._data);
}
// Gets or sets the member with specified key.
// https://arduinojson.org/v6/api/jsonobject/subscript/
template <typename TString>
FORCE_INLINE typename enable_if<IsString<TString>::value,
MemberProxy<JsonObject, TString> >::type
operator[](const TString& key) const {
return MemberProxy<JsonObject, TString>(*this, key);
}
// Gets or sets the member with specified key.
// https://arduinojson.org/v6/api/jsonobject/subscript/
template <typename TChar>
FORCE_INLINE typename enable_if<IsString<TChar*>::value,
MemberProxy<JsonObject, TChar*> >::type
operator[](TChar* key) const {
return MemberProxy<JsonObject, TChar*>(*this, key);
}
// Removes the member at the specified iterator.
// ⚠️ Doesn't release the memory associated with the removed member.
// https://arduinojson.org/v6/api/jsonobject/remove/
FORCE_INLINE void remove(iterator it) const {
if (!_data)
return;
_data->removeSlot(it._slot);
}
// Removes the member with the specified key.
// ⚠️ Doesn't release the memory associated with the removed member.
// https://arduinojson.org/v6/api/jsonobject/remove/
template <typename TString>
FORCE_INLINE void remove(const TString& key) const {
removeMember(adaptString(key));
}
// Removes the member with the specified key.
// ⚠️ Doesn't release the memory associated with the removed member.
// https://arduinojson.org/v6/api/jsonobject/remove/
template <typename TChar>
FORCE_INLINE void remove(TChar* key) const {
removeMember(adaptString(key));
}
// Returns true if the object contains the specified key.
// https://arduinojson.org/v6/api/jsonobject/containskey/
template <typename TString>
FORCE_INLINE typename enable_if<IsString<TString>::value, bool>::type
containsKey(const TString& key) const {
return getMember(adaptString(key)) != 0;
}
// Returns true if the object contains the specified key.
// https://arduinojson.org/v6/api/jsonobject/containskey/
template <typename TChar>
FORCE_INLINE typename enable_if<IsString<TChar*>::value, bool>::type
containsKey(TChar* key) const {
return getMember(adaptString(key)) != 0;
}
// Creates an array and adds it to the object.
// https://arduinojson.org/v6/api/jsonobject/createnestedarray/
template <typename TString>
FORCE_INLINE JsonArray createNestedArray(const TString& key) const;
// Creates an array and adds it to the object.
// https://arduinojson.org/v6/api/jsonobject/createnestedarray/
template <typename TChar>
FORCE_INLINE JsonArray createNestedArray(TChar* key) const;
// Creates an object and adds it to the object.
// https://arduinojson.org/v6/api/jsonobject/createnestedobject/
template <typename TString>
JsonObject createNestedObject(const TString& key) const {
return operator[](key).template to<JsonObject>();
}
// Creates an object and adds it to the object.
// https://arduinojson.org/v6/api/jsonobject/createnestedobject/
template <typename TChar>
JsonObject createNestedObject(TChar* key) const {
return operator[](key).template to<JsonObject>();
}
private:
MemoryPool* getPool() const {
return _pool;
}
VariantData* getData() const {
return collectionToVariant(_data);
}
VariantData* getOrCreateData() const {
return collectionToVariant(_data);
}
template <typename TAdaptedString>
inline VariantData* getMember(TAdaptedString key) const {
if (!_data)
return 0;
return _data->getMember(key);
}
template <typename TAdaptedString>
void removeMember(TAdaptedString key) const {
if (!_data)
return;
_data->removeMember(key);
}
CollectionData* _data;
MemoryPool* _pool;
};
template <>
struct Converter<JsonObject> : private VariantAttorney {
static void toJson(JsonVariantConst src, JsonVariant dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static JsonObject fromJson(JsonVariant src) {
VariantData* data = getData(src);
MemoryPool* pool = getPool(src);
return JsonObject(pool, data != 0 ? data->asObject() : 0);
}
static InvalidConversion<JsonVariantConst, JsonObject> fromJson(
JsonVariantConst);
static bool checkJson(JsonVariantConst) {
return false;
}
static bool checkJson(JsonVariant src) {
VariantData* data = getData(src);
return data && data->isObject();
}
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -0,0 +1,156 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Object/JsonObjectIterator.hpp>
#include <ArduinoJson/Variant/VariantOperators.hpp>
namespace ARDUINOJSON_NAMESPACE {
// A read-only reference to an object in a JsonDocument.
// https://arduinojson.org/v6/api/jsonobjectconst/
class JsonObjectConst : public VariantOperators<JsonObjectConst> {
friend class JsonObject;
friend class VariantAttorney;
public:
typedef JsonObjectConstIterator iterator;
// Creates an unbound reference.
JsonObjectConst() : _data(0) {}
// INTERNAL USE ONLY
JsonObjectConst(const CollectionData* data) : _data(data) {}
operator JsonVariantConst() const {
return JsonVariantConst(collectionToVariant(_data));
}
// Returns true if the reference is unbound.
// https://arduinojson.org/v6/api/jsonobjectconst/isnull/
FORCE_INLINE bool isNull() const {
return _data == 0;
}
// Returns true if the reference is bound.
// https://arduinojson.org/v6/api/jsonobjectconst/isnull/
FORCE_INLINE operator bool() const {
return _data != 0;
}
// Returns the number of bytes occupied by the object.
// https://arduinojson.org/v6/api/jsonobjectconst/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return _data ? _data->memoryUsage() : 0;
}
// Returns the depth (nesting level) of the object.
// https://arduinojson.org/v6/api/jsonobjectconst/nesting/
FORCE_INLINE size_t nesting() const {
return variantNesting(collectionToVariant(_data));
}
// Returns the number of members in the object.
// https://arduinojson.org/v6/api/jsonobjectconst/size/
FORCE_INLINE size_t size() const {
return _data ? _data->size() : 0;
}
// Returns an iterator to the first key-value pair of the object.
// https://arduinojson.org/v6/api/jsonobjectconst/begin/
FORCE_INLINE iterator begin() const {
if (!_data)
return iterator();
return iterator(_data->head());
}
// Returns an iterator following the last key-value pair of the object.
// https://arduinojson.org/v6/api/jsonobjectconst/end/
FORCE_INLINE iterator end() const {
return iterator();
}
// Returns true if the object contains the specified key.
// https://arduinojson.org/v6/api/jsonobjectconst/containskey/
template <typename TString>
FORCE_INLINE bool containsKey(const TString& key) const {
return getMember(adaptString(key)) != 0;
}
// Returns true if the object contains the specified key.
// https://arduinojson.org/v6/api/jsonobjectconst/containskey/
template <typename TChar>
FORCE_INLINE bool containsKey(TChar* key) const {
return getMember(adaptString(key)) != 0;
}
// Gets the member with specified key.
// https://arduinojson.org/v6/api/jsonobjectconst/subscript/
template <typename TString>
FORCE_INLINE
typename enable_if<IsString<TString>::value, JsonVariantConst>::type
operator[](const TString& key) const {
return JsonVariantConst(getMember(adaptString(key)));
}
// Gets the member with specified key.
// https://arduinojson.org/v6/api/jsonobjectconst/subscript/
template <typename TChar>
FORCE_INLINE
typename enable_if<IsString<TChar*>::value, JsonVariantConst>::type
operator[](TChar* key) const {
return JsonVariantConst(getMember(adaptString(key)));
}
// Compares objects.
FORCE_INLINE bool operator==(JsonObjectConst rhs) const {
if (_data == rhs._data)
return true;
if (!_data || !rhs._data)
return false;
size_t count = 0;
for (iterator it = begin(); it != end(); ++it) {
if (it->value() != rhs[it->key()])
return false;
count++;
}
return count == rhs.size();
}
private:
const VariantData* getData() const {
return collectionToVariant(_data);
}
template <typename TAdaptedString>
const VariantData* getMember(TAdaptedString key) const {
if (!_data)
return 0;
return _data->getMember(key);
}
const CollectionData* _data;
};
template <>
struct Converter<JsonObjectConst> : private VariantAttorney {
static void toJson(JsonVariantConst src, JsonVariant dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static JsonObjectConst fromJson(JsonVariantConst src) {
const VariantData* data = getData(src);
return data != 0 ? data->asObject() : 0;
}
static bool checkJson(JsonVariantConst src) {
const VariantData* data = getData(src);
return data && data->isObject();
}
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -0,0 +1,81 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/JsonArray.hpp>
#include <ArduinoJson/Object/JsonObject.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename TString>
inline JsonArray JsonObject::createNestedArray(const TString& key) const {
return operator[](key).template to<JsonArray>();
}
template <typename TChar>
inline JsonArray JsonObject::createNestedArray(TChar* key) const {
return operator[](key).template to<JsonArray>();
}
template <typename TDerived>
template <typename TString>
inline JsonArray VariantRefBase<TDerived>::createNestedArray(
const TString& key) const {
return operator[](key).template to<JsonArray>();
}
template <typename TDerived>
template <typename TChar>
inline JsonArray VariantRefBase<TDerived>::createNestedArray(TChar* key) const {
return operator[](key).template to<JsonArray>();
}
template <typename TDerived>
template <typename TString>
inline JsonObject VariantRefBase<TDerived>::createNestedObject(
const TString& key) const {
return operator[](key).template to<JsonObject>();
}
template <typename TDerived>
template <typename TChar>
inline JsonObject VariantRefBase<TDerived>::createNestedObject(
TChar* key) const {
return operator[](key).template to<JsonObject>();
}
template <typename TDerived>
template <typename TString>
inline typename enable_if<IsString<TString>::value, bool>::type
VariantRefBase<TDerived>::containsKey(const TString& key) const {
return variantGetMember(VariantAttorney::getData(derived()),
adaptString(key)) != 0;
}
template <typename TDerived>
template <typename TChar>
inline typename enable_if<IsString<TChar*>::value, bool>::type
VariantRefBase<TDerived>::containsKey(TChar* key) const {
return variantGetMember(VariantAttorney::getData(derived()),
adaptString(key)) != 0;
}
template <typename TDerived>
template <typename TString>
inline typename enable_if<IsString<TString*>::value,
MemberProxy<TDerived, TString*> >::type
VariantRefBase<TDerived>::operator[](TString* key) const {
return MemberProxy<TDerived, TString*>(derived(), key);
}
template <typename TDerived>
template <typename TString>
inline typename enable_if<IsString<TString>::value,
MemberProxy<TDerived, TString> >::type
VariantRefBase<TDerived>::operator[](const TString& key) const {
return MemberProxy<TDerived, TString>(derived(), key);
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -0,0 +1,119 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Object/JsonPair.hpp>
#include <ArduinoJson/Variant/SlotFunctions.hpp>
namespace ARDUINOJSON_NAMESPACE {
class JsonPairPtr {
public:
JsonPairPtr(MemoryPool* pool, VariantSlot* slot) : _pair(pool, slot) {}
const JsonPair* operator->() const {
return &_pair;
}
const JsonPair& operator*() const {
return _pair;
}
private:
JsonPair _pair;
};
class JsonObjectIterator {
friend class JsonObject;
public:
JsonObjectIterator() : _slot(0) {}
explicit JsonObjectIterator(MemoryPool* pool, VariantSlot* slot)
: _pool(pool), _slot(slot) {}
JsonPair operator*() const {
return JsonPair(_pool, _slot);
}
JsonPairPtr operator->() {
return JsonPairPtr(_pool, _slot);
}
bool operator==(const JsonObjectIterator& other) const {
return _slot == other._slot;
}
bool operator!=(const JsonObjectIterator& other) const {
return _slot != other._slot;
}
JsonObjectIterator& operator++() {
_slot = _slot->next();
return *this;
}
JsonObjectIterator& operator+=(size_t distance) {
_slot = _slot->next(distance);
return *this;
}
private:
MemoryPool* _pool;
VariantSlot* _slot;
};
class JsonPairConstPtr {
public:
JsonPairConstPtr(const VariantSlot* slot) : _pair(slot) {}
const JsonPairConst* operator->() const {
return &_pair;
}
const JsonPairConst& operator*() const {
return _pair;
}
private:
JsonPairConst _pair;
};
class JsonObjectConstIterator {
friend class JsonObject;
public:
JsonObjectConstIterator() : _slot(0) {}
explicit JsonObjectConstIterator(const VariantSlot* slot) : _slot(slot) {}
JsonPairConst operator*() const {
return JsonPairConst(_slot);
}
JsonPairConstPtr operator->() {
return JsonPairConstPtr(_slot);
}
bool operator==(const JsonObjectConstIterator& other) const {
return _slot == other._slot;
}
bool operator!=(const JsonObjectConstIterator& other) const {
return _slot != other._slot;
}
JsonObjectConstIterator& operator++() {
_slot = _slot->next();
return *this;
}
JsonObjectConstIterator& operator+=(size_t distance) {
_slot = _slot->next(distance);
return *this;
}
private:
const VariantSlot* _slot;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -0,0 +1,67 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Strings/JsonString.hpp>
#include <ArduinoJson/Variant/JsonVariant.hpp>
#include <ArduinoJson/Variant/JsonVariantConst.hpp>
namespace ARDUINOJSON_NAMESPACE {
// A key-value pair.
// https://arduinojson.org/v6/api/jsonobject/begin_end/
class JsonPair {
public:
// INTERNAL USE ONLY
JsonPair(MemoryPool* pool, VariantSlot* slot) {
if (slot) {
_key = JsonString(slot->key(), slot->ownsKey() ? JsonString::Copied
: JsonString::Linked);
_value = JsonVariant(pool, slot->data());
}
}
// Returns the key.
JsonString key() const {
return _key;
}
// Returns the value.
JsonVariant value() const {
return _value;
}
private:
JsonString _key;
JsonVariant _value;
};
// A read-only key-value pair.
// https://arduinojson.org/v6/api/jsonobjectconst/begin_end/
class JsonPairConst {
public:
JsonPairConst(const VariantSlot* slot) {
if (slot) {
_key = JsonString(slot->key(), slot->ownsKey() ? JsonString::Copied
: JsonString::Linked);
_value = JsonVariantConst(slot->data());
}
}
// Returns the key.
JsonString key() const {
return _key;
}
// Returns the value.
JsonVariantConst value() const {
return _value;
}
private:
JsonString _key;
JsonVariantConst _value;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -4,203 +4,61 @@
#pragma once #pragma once
#include <ArduinoJson/Configuration.hpp> #include <ArduinoJson/Variant/VariantRefBase.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Variant/VariantOperators.hpp>
#include <ArduinoJson/Variant/VariantRef.hpp>
#include <ArduinoJson/Variant/VariantShortcuts.hpp>
#include <ArduinoJson/Variant/VariantTo.hpp>
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable : 4522)
#endif
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename TObject, typename TStringRef> // A proxy class to get or set a member of an object.
class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >, // https://arduinojson.org/v6/api/jsonobject/subscript/
public VariantShortcuts<MemberProxy<TObject, TStringRef> >, template <typename TUpstream, typename TStringRef>
public Visitable, class MemberProxy
public VariantTag { : public VariantRefBase<MemberProxy<TUpstream, TStringRef> >,
typedef MemberProxy<TObject, TStringRef> this_type; public VariantOperators<MemberProxy<TUpstream, TStringRef> > {
friend class VariantAttorney;
public: public:
typedef VariantRef variant_type; FORCE_INLINE MemberProxy(TUpstream upstream, TStringRef key)
: _upstream(upstream), _key(key) {}
FORCE_INLINE MemberProxy(TObject variant, TStringRef key) MemberProxy(const MemberProxy& src)
: _object(variant), _key(key) {} : _upstream(src._upstream), _key(src._key) {}
FORCE_INLINE MemberProxy(const MemberProxy &src) FORCE_INLINE MemberProxy& operator=(const MemberProxy& src) {
: _object(src._object), _key(src._key) {} this->set(src);
FORCE_INLINE operator VariantConstRef() const {
return getUpstreamMember();
}
FORCE_INLINE this_type &operator=(const this_type &src) {
getOrAddUpstreamMember().set(src);
return *this; return *this;
} }
template <typename TValue> template <typename T>
FORCE_INLINE typename enable_if<!is_array<TValue>::value, this_type &>::type FORCE_INLINE MemberProxy& operator=(const T& src) {
operator=(const TValue &src) { this->set(src);
getOrAddUpstreamMember().set(src);
return *this; return *this;
} }
// operator=(char*) template <typename T>
// operator=(const char*) FORCE_INLINE MemberProxy& operator=(T* src) {
// operator=(const __FlashStringHelper*) this->set(src);
template <typename TChar>
FORCE_INLINE this_type &operator=(TChar *src) {
getOrAddUpstreamMember().set(src);
return *this; return *this;
} }
FORCE_INLINE void clear() const {
getUpstreamMember().clear();
}
FORCE_INLINE bool isNull() const {
return getUpstreamMember().isNull();
}
template <typename T>
FORCE_INLINE typename enable_if<!is_same<T, char *>::value, T>::type as()
const {
return getUpstreamMember().template as<T>();
}
template <typename T>
FORCE_INLINE typename enable_if<is_same<T, char *>::value, const char *>::type
ARDUINOJSON_DEPRECATED("Replace as<char*>() with as<const char*>()")
as() const {
return as<const char *>();
}
template <typename T>
FORCE_INLINE operator T() const {
return getUpstreamMember();
}
template <typename TValue>
FORCE_INLINE bool is() const {
return getUpstreamMember().template is<TValue>();
}
FORCE_INLINE size_t size() const {
return getUpstreamMember().size();
}
FORCE_INLINE size_t memoryUsage() const {
return getUpstreamMember().memoryUsage();
}
FORCE_INLINE void remove(size_t index) const {
getUpstreamMember().remove(index);
}
// remove(char*) const
// remove(const char*) const
// remove(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE typename enable_if<IsString<TChar *>::value>::type remove(
TChar *key) const {
getUpstreamMember().remove(key);
}
// remove(const std::string&) const
// remove(const String&) const
template <typename TString>
FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove(
const TString &key) const {
getUpstreamMember().remove(key);
}
template <typename TValue>
FORCE_INLINE typename VariantTo<TValue>::type to() {
return getOrAddUpstreamMember().template to<TValue>();
}
template <typename TValue>
FORCE_INLINE bool set(const TValue &value) {
return getOrAddUpstreamMember().set(value);
}
// set(char*) const
// set(const char*) const
// set(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE bool set(TChar *value) {
return getOrAddUpstreamMember().set(value);
}
template <typename TVisitor>
typename TVisitor::result_type accept(TVisitor &visitor) const {
return getUpstreamMember().accept(visitor);
}
FORCE_INLINE VariantRef addElement() const {
return getOrAddUpstreamMember().addElement();
}
FORCE_INLINE VariantRef getElement(size_t index) const {
return getUpstreamMember().getElement(index);
}
FORCE_INLINE VariantRef getOrAddElement(size_t index) const {
return getOrAddUpstreamMember().getOrAddElement(index);
}
// getMember(char*) const
// getMember(const char*) const
// getMember(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE VariantRef getMember(TChar *key) const {
return getUpstreamMember().getMember(key);
}
// getMember(const std::string&) const
// getMember(const String&) const
template <typename TString>
FORCE_INLINE VariantRef getMember(const TString &key) const {
return getUpstreamMember().getMember(key);
}
// getOrAddMember(char*) const
// getOrAddMember(const char*) const
// getOrAddMember(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE VariantRef getOrAddMember(TChar *key) const {
return getOrAddUpstreamMember().getOrAddMember(key);
}
// getOrAddMember(const std::string&) const
// getOrAddMember(const String&) const
template <typename TString>
FORCE_INLINE VariantRef getOrAddMember(const TString &key) const {
return getOrAddUpstreamMember().getOrAddMember(key);
}
private: private:
FORCE_INLINE VariantRef getUpstreamMember() const { FORCE_INLINE MemoryPool* getPool() const {
return _object.getMember(_key); return VariantAttorney::getPool(_upstream);
} }
FORCE_INLINE VariantRef getOrAddUpstreamMember() const { FORCE_INLINE VariantData* getData() const {
return _object.getOrAddMember(_key); return variantGetMember(VariantAttorney::getData(_upstream),
adaptString(_key));
} }
friend void convertToJson(const this_type &src, VariantRef dst) { FORCE_INLINE VariantData* getOrCreateData() const {
dst.set(src.getUpstreamMember()); return variantGetOrAddMember(VariantAttorney::getOrCreateData(_upstream),
adaptString(_key),
VariantAttorney::getPool(_upstream));
} }
TObject _object; private:
TUpstream _upstream;
TStringRef _key; TStringRef _key;
}; };
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE
#ifdef _MSC_VER
# pragma warning(pop)
#endif

View File

@@ -1,52 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Collection/CollectionData.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename TVisitor>
typename TVisitor::result_type objectAccept(const CollectionData *obj,
TVisitor &visitor) {
if (obj)
return visitor.visitObject(*obj);
else
return visitor.visitNull();
}
inline bool objectEquals(const CollectionData *lhs, const CollectionData *rhs) {
if (lhs == rhs)
return true;
if (!lhs || !rhs)
return false;
return lhs->equalsObject(*rhs);
}
template <typename TAdaptedString>
inline VariantData *objectGetMember(const CollectionData *obj,
TAdaptedString key) {
if (!obj)
return 0;
return obj->getMember(key);
}
template <typename TAdaptedString>
void objectRemove(CollectionData *obj, TAdaptedString key) {
if (!obj)
return;
obj->removeMember(key);
}
template <typename TAdaptedString, typename TStoragePolicy>
inline VariantData *objectGetOrAddMember(CollectionData *obj,
TAdaptedString key, MemoryPool *pool,
TStoragePolicy storage_policy) {
if (!obj)
return 0;
return obj->getOrAddMember(key, pool, storage_policy);
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -1,69 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/ArrayRef.hpp>
#include <ArduinoJson/Object/ObjectRef.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename TObject>
template <typename TString>
inline ArrayRef ObjectShortcuts<TObject>::createNestedArray(
const TString& key) const {
return impl()->getOrAddMember(key).template to<ArrayRef>();
}
template <typename TObject>
template <typename TChar>
inline ArrayRef ObjectShortcuts<TObject>::createNestedArray(TChar* key) const {
return impl()->getOrAddMember(key).template to<ArrayRef>();
}
template <typename TObject>
template <typename TString>
inline ObjectRef ObjectShortcuts<TObject>::createNestedObject(
const TString& key) const {
return impl()->getOrAddMember(key).template to<ObjectRef>();
}
template <typename TObject>
template <typename TChar>
inline ObjectRef ObjectShortcuts<TObject>::createNestedObject(
TChar* key) const {
return impl()->getOrAddMember(key).template to<ObjectRef>();
}
template <typename TObject>
template <typename TString>
inline typename enable_if<IsString<TString>::value, bool>::type
ObjectShortcuts<TObject>::containsKey(const TString& key) const {
return !impl()->getMember(key).isUnbound();
}
template <typename TObject>
template <typename TChar>
inline typename enable_if<IsString<TChar*>::value, bool>::type
ObjectShortcuts<TObject>::containsKey(TChar* key) const {
return !impl()->getMember(key).isUnbound();
}
template <typename TObject>
template <typename TString>
inline typename enable_if<IsString<TString*>::value,
MemberProxy<TObject, TString*> >::type
ObjectShortcuts<TObject>::operator[](TString* key) const {
return MemberProxy<TObject, TString*>(*impl(), key);
}
template <typename TObject>
template <typename TString>
inline typename enable_if<IsString<TString>::value,
MemberProxy<TObject, TString> >::type
ObjectShortcuts<TObject>::operator[](const TString& key) const {
return MemberProxy<TObject, TString>(*impl(), key);
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -1,123 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Object/Pair.hpp>
#include <ArduinoJson/Variant/SlotFunctions.hpp>
namespace ARDUINOJSON_NAMESPACE {
class PairPtr {
public:
PairPtr(MemoryPool *pool, VariantSlot *slot) : _pair(pool, slot) {}
const Pair *operator->() const {
return &_pair;
}
const Pair &operator*() const {
return _pair;
}
private:
Pair _pair;
};
class ObjectIterator {
public:
ObjectIterator() : _slot(0) {}
explicit ObjectIterator(MemoryPool *pool, VariantSlot *slot)
: _pool(pool), _slot(slot) {}
Pair operator*() const {
return Pair(_pool, _slot);
}
PairPtr operator->() {
return PairPtr(_pool, _slot);
}
bool operator==(const ObjectIterator &other) const {
return _slot == other._slot;
}
bool operator!=(const ObjectIterator &other) const {
return _slot != other._slot;
}
ObjectIterator &operator++() {
_slot = _slot->next();
return *this;
}
ObjectIterator &operator+=(size_t distance) {
_slot = _slot->next(distance);
return *this;
}
VariantSlot *internal() {
return _slot;
}
private:
MemoryPool *_pool;
VariantSlot *_slot;
};
class PairConstPtr {
public:
PairConstPtr(const VariantSlot *slot) : _pair(slot) {}
const PairConst *operator->() const {
return &_pair;
}
const PairConst &operator*() const {
return _pair;
}
private:
PairConst _pair;
};
class ObjectConstIterator {
public:
ObjectConstIterator() : _slot(0) {}
explicit ObjectConstIterator(const VariantSlot *slot) : _slot(slot) {}
PairConst operator*() const {
return PairConst(_slot);
}
PairConstPtr operator->() {
return PairConstPtr(_slot);
}
bool operator==(const ObjectConstIterator &other) const {
return _slot == other._slot;
}
bool operator!=(const ObjectConstIterator &other) const {
return _slot != other._slot;
}
ObjectConstIterator &operator++() {
_slot = _slot->next();
return *this;
}
ObjectConstIterator &operator+=(size_t distance) {
_slot = _slot->next(distance);
return *this;
}
const VariantSlot *internal() {
return _slot;
}
private:
const VariantSlot *_slot;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -1,282 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Object/ObjectFunctions.hpp>
#include <ArduinoJson/Object/ObjectIterator.hpp>
// Returns the size (in bytes) of an object with n elements.
// Can be very handy to determine the size of a StaticMemoryPool.
#define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \
((NUMBER_OF_ELEMENTS) * sizeof(ARDUINOJSON_NAMESPACE::VariantSlot))
namespace ARDUINOJSON_NAMESPACE {
template <typename TData>
class ObjectRefBase {
public:
operator VariantConstRef() const {
const void* data = _data; // prevent warning cast-align
return VariantConstRef(reinterpret_cast<const VariantData*>(data));
}
template <typename TVisitor>
typename TVisitor::result_type accept(TVisitor& visitor) const {
return objectAccept(_data, visitor);
}
FORCE_INLINE bool isNull() const {
return _data == 0;
}
FORCE_INLINE operator bool() const {
return _data != 0;
}
FORCE_INLINE size_t memoryUsage() const {
return _data ? _data->memoryUsage() : 0;
}
FORCE_INLINE size_t nesting() const {
return _data ? _data->nesting() : 0;
}
FORCE_INLINE size_t size() const {
return _data ? _data->size() : 0;
}
protected:
ObjectRefBase(TData* data) : _data(data) {}
TData* _data;
};
class ObjectConstRef : public ObjectRefBase<const CollectionData>,
public Visitable {
friend class ObjectRef;
typedef ObjectRefBase<const CollectionData> base_type;
public:
typedef ObjectConstIterator iterator;
ObjectConstRef() : base_type(0) {}
ObjectConstRef(const CollectionData* data) : base_type(data) {}
FORCE_INLINE iterator begin() const {
if (!_data)
return iterator();
return iterator(_data->head());
}
FORCE_INLINE iterator end() const {
return iterator();
}
// containsKey(const std::string&) const
// containsKey(const String&) const
template <typename TString>
FORCE_INLINE bool containsKey(const TString& key) const {
return !getMember(key).isUnbound();
}
// containsKey(char*) const
// containsKey(const char*) const
// containsKey(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE bool containsKey(TChar* key) const {
return !getMember(key).isUnbound();
}
// getMember(const std::string&) const
// getMember(const String&) const
template <typename TString>
FORCE_INLINE VariantConstRef getMember(const TString& key) const {
return get_impl(adaptString(key));
}
// getMember(char*) const
// getMember(const char*) const
// getMember(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE VariantConstRef getMember(TChar* key) const {
return get_impl(adaptString(key));
}
// operator[](const std::string&) const
// operator[](const String&) const
template <typename TString>
FORCE_INLINE
typename enable_if<IsString<TString>::value, VariantConstRef>::type
operator[](const TString& key) const {
return get_impl(adaptString(key));
}
// operator[](char*) const
// operator[](const char*) const
// operator[](const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE
typename enable_if<IsString<TChar*>::value, VariantConstRef>::type
operator[](TChar* key) const {
return get_impl(adaptString(key));
}
FORCE_INLINE bool operator==(ObjectConstRef rhs) const {
return objectEquals(_data, rhs._data);
}
private:
template <typename TAdaptedString>
FORCE_INLINE VariantConstRef get_impl(TAdaptedString key) const {
return VariantConstRef(objectGetMember(_data, key));
}
};
class ObjectRef : public ObjectRefBase<CollectionData>,
public ObjectShortcuts<ObjectRef>,
public Visitable {
typedef ObjectRefBase<CollectionData> base_type;
public:
typedef ObjectIterator iterator;
FORCE_INLINE ObjectRef() : base_type(0), _pool(0) {}
FORCE_INLINE ObjectRef(MemoryPool* buf, CollectionData* data)
: base_type(data), _pool(buf) {}
operator VariantRef() const {
void* data = _data; // prevent warning cast-align
return VariantRef(_pool, reinterpret_cast<VariantData*>(data));
}
operator ObjectConstRef() const {
return ObjectConstRef(_data);
}
FORCE_INLINE iterator begin() const {
if (!_data)
return iterator();
return iterator(_pool, _data->head());
}
FORCE_INLINE iterator end() const {
return iterator();
}
void clear() const {
if (!_data)
return;
_data->clear();
}
FORCE_INLINE bool set(ObjectConstRef src) {
if (!_data || !src._data)
return false;
return _data->copyFrom(*src._data, _pool);
}
// getMember(const std::string&) const
// getMember(const String&) const
template <typename TString>
FORCE_INLINE VariantRef getMember(const TString& key) const {
return VariantRef(_pool, objectGetMember(_data, adaptString(key)));
}
// getMember(char*) const
// getMember(const char*) const
// getMember(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE VariantRef getMember(TChar* key) const {
return VariantRef(_pool, objectGetMember(_data, adaptString(key)));
}
// getOrAddMember(const std::string&) const
// getOrAddMember(const String&) const
template <typename TString>
FORCE_INLINE VariantRef getOrAddMember(const TString& key) const {
return VariantRef(_pool,
objectGetOrAddMember(_data, adaptString(key), _pool,
getStringStoragePolicy(key)));
}
// getOrAddMember(char*) const
// getOrAddMember(const char*) const
// getOrAddMember(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE VariantRef getOrAddMember(TChar* key) const {
return VariantRef(_pool,
objectGetOrAddMember(_data, adaptString(key), _pool,
getStringStoragePolicy(key)));
}
FORCE_INLINE bool operator==(ObjectRef rhs) const {
return objectEquals(_data, rhs._data);
}
FORCE_INLINE void remove(iterator it) const {
if (!_data)
return;
_data->removeSlot(it.internal());
}
// remove(const std::string&) const
// remove(const String&) const
template <typename TString>
FORCE_INLINE void remove(const TString& key) const {
objectRemove(_data, adaptString(key));
}
// remove(char*) const
// remove(const char*) const
// remove(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE void remove(TChar* key) const {
objectRemove(_data, adaptString(key));
}
private:
MemoryPool* _pool;
};
template <>
struct Converter<ObjectConstRef> {
static void toJson(VariantConstRef src, VariantRef dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static ObjectConstRef fromJson(VariantConstRef src) {
return ObjectConstRef(variantAsObject(getData(src)));
}
static bool checkJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data && data->isObject();
}
};
template <>
struct Converter<ObjectRef> {
static void toJson(VariantConstRef src, VariantRef dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static ObjectRef fromJson(VariantRef src) {
VariantData* data = getData(src);
MemoryPool* pool = getPool(src);
return ObjectRef(pool, data != 0 ? data->asObject() : 0);
}
static InvalidConversion<VariantConstRef, ObjectRef> fromJson(
VariantConstRef);
static bool checkJson(VariantConstRef) {
return false;
}
static bool checkJson(VariantRef src) {
VariantData* data = getData(src);
return data && data->isObject();
}
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -1,73 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Polyfills/attributes.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename TParent, typename TStringRef>
class MemberProxy;
template <typename TObject>
class ObjectShortcuts {
public:
// containsKey(const std::string&) const
// containsKey(const String&) const
template <typename TString>
FORCE_INLINE typename enable_if<IsString<TString>::value, bool>::type
containsKey(const TString &key) const;
// containsKey(char*) const
// containsKey(const char*) const
// containsKey(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE typename enable_if<IsString<TChar *>::value, bool>::type
containsKey(TChar *key) const;
// operator[](const std::string&) const
// operator[](const String&) const
template <typename TString>
FORCE_INLINE typename enable_if<IsString<TString>::value,
MemberProxy<TObject, TString> >::type
operator[](const TString &key) const;
// operator[](char*) const
// operator[](const char*) const
// operator[](const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE typename enable_if<IsString<TChar *>::value,
MemberProxy<TObject, TChar *> >::type
operator[](TChar *key) const;
// createNestedArray(const std::string&) const
// createNestedArray(const String&) const
template <typename TString>
FORCE_INLINE ArrayRef createNestedArray(const TString &key) const;
// createNestedArray(char*) const
// createNestedArray(const char*) const
// createNestedArray(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE ArrayRef createNestedArray(TChar *key) const;
// createNestedObject(const std::string&) const
// createNestedObject(const String&) const
template <typename TString>
ObjectRef createNestedObject(const TString &key) const;
// createNestedObject(char*) const
// createNestedObject(const char*) const
// createNestedObject(const __FlashStringHelper*) const
template <typename TChar>
ObjectRef createNestedObject(TChar *key) const;
private:
const TObject *impl() const {
return static_cast<const TObject *>(this);
}
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -1,57 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Strings/String.hpp>
#include <ArduinoJson/Variant/VariantRef.hpp>
namespace ARDUINOJSON_NAMESPACE {
// A key value pair for CollectionData.
class Pair {
public:
Pair(MemoryPool* pool, VariantSlot* slot) {
if (slot) {
_key = String(slot->key(),
slot->ownsKey() ? String::Copied : String::Linked);
_value = VariantRef(pool, slot->data());
}
}
String key() const {
return _key;
}
VariantRef value() const {
return _value;
}
private:
String _key;
VariantRef _value;
};
class PairConst {
public:
PairConst(const VariantSlot* slot) {
if (slot) {
_key = String(slot->key(),
slot->ownsKey() ? String::Copied : String::Linked);
_value = VariantConstRef(slot->data());
}
}
String key() const {
return _key;
}
VariantConstRef value() const {
return _value;
}
private:
String _key;
VariantConstRef _value;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -9,32 +9,16 @@
# define FORCE_INLINE // __forceinline causes C4714 when returning std::string # define FORCE_INLINE // __forceinline causes C4714 when returning std::string
# define NO_INLINE __declspec(noinline) # define NO_INLINE __declspec(noinline)
# ifndef ARDUINOJSON_DEPRECATED
# define ARDUINOJSON_DEPRECATED(msg) __declspec(deprecated(msg))
# endif
#elif defined(__GNUC__) // GCC or Clang #elif defined(__GNUC__) // GCC or Clang
# define FORCE_INLINE __attribute__((always_inline)) # define FORCE_INLINE __attribute__((always_inline))
# define NO_INLINE __attribute__((noinline)) # define NO_INLINE __attribute__((noinline))
# ifndef ARDUINOJSON_DEPRECATED
# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
# define ARDUINOJSON_DEPRECATED(msg) __attribute__((deprecated(msg)))
# else
# define ARDUINOJSON_DEPRECATED(msg) __attribute__((deprecated))
# endif
# endif
#else // Other compilers #else // Other compilers
# define FORCE_INLINE # define FORCE_INLINE
# define NO_INLINE # define NO_INLINE
# ifndef ARDUINOJSON_DEPRECATED
# define ARDUINOJSON_DEPRECATED(msg)
# endif
#endif #endif
#if __cplusplus >= 201103L #if __cplusplus >= 201103L

View File

@@ -23,7 +23,8 @@ struct pgm_p {
inline size_t strlen_P(ARDUINOJSON_NAMESPACE::pgm_p s) { inline size_t strlen_P(ARDUINOJSON_NAMESPACE::pgm_p s) {
const char* p = s.address; const char* p = s.address;
ARDUINOJSON_ASSERT(p != NULL); ARDUINOJSON_ASSERT(p != NULL);
while (pgm_read_byte(p)) p++; while (pgm_read_byte(p))
p++;
return size_t(p - s.address); return size_t(p - s.address);
} }
#endif #endif

View File

@@ -13,14 +13,11 @@ namespace ARDUINOJSON_NAMESPACE {
template <typename TBase, typename TDerived> template <typename TBase, typename TDerived>
class is_base_of { class is_base_of {
protected: // <- to avoid GCC's "all member functions in class are private" protected: // <- to avoid GCC's "all member functions in class are private"
typedef char Yes[1]; static int probe(const TBase*);
typedef char No[2]; static char probe(...);
static Yes &probe(const TBase *);
static No &probe(...);
public: public:
static const bool value = static const bool value =
sizeof(probe(reinterpret_cast<TDerived *>(0))) == sizeof(Yes); sizeof(probe(reinterpret_cast<TDerived*>(0))) == sizeof(int);
}; };
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -11,16 +11,13 @@ namespace ARDUINOJSON_NAMESPACE {
template <typename T> template <typename T>
struct is_class { struct is_class {
protected: // <- to avoid GCC's "all member functions in class are private" protected: // <- to avoid GCC's "all member functions in class are private"
typedef char Yes[1];
typedef char No[2];
template <typename U> template <typename U>
static Yes &probe(void (U::*)(void)); static int probe(void (U::*)(void));
template <typename> template <typename>
static No &probe(...); static char probe(...);
public: public:
static const bool value = sizeof(probe<T>(0)) == sizeof(Yes); static const bool value = sizeof(probe<T>(0)) == sizeof(int);
}; };
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -24,14 +24,13 @@ namespace ARDUINOJSON_NAMESPACE {
template <typename From, typename To> template <typename From, typename To>
struct is_convertible { struct is_convertible {
protected: // <- to avoid GCC's "all member functions in class are private" protected: // <- to avoid GCC's "all member functions in class are private"
typedef char Yes[1]; static int probe(To);
typedef char No[2]; static char probe(...);
static Yes &probe(To); static From& _from;
static No &probe(...);
public: public:
static const bool value = sizeof(probe(declval<From>())) == sizeof(Yes); static const bool value = sizeof(probe(_from)) == sizeof(int);
}; };
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -13,7 +13,7 @@ class Writer< ::String, void> {
static const size_t bufferCapacity = ARDUINOJSON_STRING_BUFFER_SIZE; static const size_t bufferCapacity = ARDUINOJSON_STRING_BUFFER_SIZE;
public: public:
explicit Writer(::String &str) : _destination(&str) { explicit Writer(::String& str) : _destination(&str) {
_size = 0; _size = 0;
} }
@@ -29,7 +29,7 @@ class Writer< ::String, void> {
return 1; return 1;
} }
size_t write(const uint8_t *s, size_t n) { size_t write(const uint8_t* s, size_t n) {
for (size_t i = 0; i < n; i++) { for (size_t i = 0; i < n; i++) {
write(s[i]); write(s[i]);
} }
@@ -45,7 +45,7 @@ class Writer< ::String, void> {
} }
private: private:
::String *_destination; ::String* _destination;
char _buffer[bufferCapacity]; char _buffer[bufferCapacity];
size_t _size; size_t _size;
}; };

View File

@@ -10,7 +10,7 @@ namespace ARDUINOJSON_NAMESPACE {
class StaticStringWriter { class StaticStringWriter {
public: public:
StaticStringWriter(char *buf, size_t size) : end(buf + size), p(buf) {} StaticStringWriter(char* buf, size_t size) : end(buf + size), p(buf) {}
size_t write(uint8_t c) { size_t write(uint8_t c) {
if (p >= end) if (p >= end)
@@ -19,8 +19,8 @@ class StaticStringWriter {
return 1; return 1;
} }
size_t write(const uint8_t *s, size_t n) { size_t write(const uint8_t* s, size_t n) {
char *begin = p; char* begin = p;
while (p < end && n > 0) { while (p < end && n > 0) {
*p++ = static_cast<char>(*s++); *p++ = static_cast<char>(*s++);
n--; n--;
@@ -29,7 +29,7 @@ class StaticStringWriter {
} }
private: private:
char *end; char* end;
char *p; char* p;
}; };
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -22,19 +22,19 @@ template <typename TDestination>
class Writer<TDestination, class Writer<TDestination,
typename enable_if<is_std_string<TDestination>::value>::type> { typename enable_if<is_std_string<TDestination>::value>::type> {
public: public:
Writer(TDestination &str) : _str(&str) {} Writer(TDestination& str) : _str(&str) {}
size_t write(uint8_t c) { size_t write(uint8_t c) {
_str->operator+=(static_cast<char>(c)); _str->operator+=(static_cast<char>(c));
return 1; return 1;
} }
size_t write(const uint8_t *s, size_t n) { size_t write(const uint8_t* s, size_t n) {
_str->append(reinterpret_cast<const char *>(s), n); _str->append(reinterpret_cast<const char*>(s), n);
return n; return n;
} }
private: private:
TDestination *_str; TDestination* _str;
}; };
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -5,14 +5,15 @@
#pragma once #pragma once
#include <ArduinoJson/Serialization/Writers/DummyWriter.hpp> #include <ArduinoJson/Serialization/Writers/DummyWriter.hpp>
#include <ArduinoJson/Variant/VariantFunctions.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <template <typename> class TSerializer, typename TSource> template <template <typename> class TSerializer>
size_t measure(const TSource &source) { size_t measure(JsonVariantConst source) {
DummyWriter dp; DummyWriter dp;
TSerializer<DummyWriter> serializer(dp); TSerializer<DummyWriter> serializer(dp);
return source.accept(serializer); return variantAccept(VariantAttorney::getData(source), serializer);
} }
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -5,49 +5,43 @@
#pragma once #pragma once
#include <ArduinoJson/Serialization/Writer.hpp> #include <ArduinoJson/Serialization/Writer.hpp>
#include <ArduinoJson/Variant/VariantFunctions.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <template <typename> class TSerializer, typename TSource, template <template <typename> class TSerializer, typename TWriter>
typename TWriter> size_t doSerialize(JsonVariantConst source, TWriter writer) {
size_t doSerialize(const TSource &source, TWriter writer) {
TSerializer<TWriter> serializer(writer); TSerializer<TWriter> serializer(writer);
return source.accept(serializer); return variantAccept(VariantAttorney::getData(source), serializer);
} }
template <template <typename> class TSerializer, typename TSource, template <template <typename> class TSerializer, typename TDestination>
typename TDestination> size_t serialize(JsonVariantConst source, TDestination& destination) {
size_t serialize(const TSource &source, TDestination &destination) {
Writer<TDestination> writer(destination); Writer<TDestination> writer(destination);
return doSerialize<TSerializer>(source, writer); return doSerialize<TSerializer>(source, writer);
} }
template <template <typename> class TSerializer, typename TSource> template <template <typename> class TSerializer>
typename enable_if<!TSerializer<StaticStringWriter>::producesText, size_t>::type typename enable_if<!TSerializer<StaticStringWriter>::producesText, size_t>::type
serialize(const TSource &source, void *buffer, size_t bufferSize) { serialize(JsonVariantConst source, void* buffer, size_t bufferSize) {
StaticStringWriter writer(reinterpret_cast<char *>(buffer), bufferSize); StaticStringWriter writer(reinterpret_cast<char*>(buffer), bufferSize);
return doSerialize<TSerializer>(source, writer); return doSerialize<TSerializer>(source, writer);
} }
template <template <typename> class TSerializer, typename TSource> template <template <typename> class TSerializer>
typename enable_if<TSerializer<StaticStringWriter>::producesText, size_t>::type typename enable_if<TSerializer<StaticStringWriter>::producesText, size_t>::type
serialize(const TSource &source, void *buffer, size_t bufferSize) { serialize(JsonVariantConst source, void* buffer, size_t bufferSize) {
StaticStringWriter writer(reinterpret_cast<char *>(buffer), bufferSize); StaticStringWriter writer(reinterpret_cast<char*>(buffer), bufferSize);
size_t n = doSerialize<TSerializer>(source, writer); size_t n = doSerialize<TSerializer>(source, writer);
// add null-terminator for text output (not counted in the size) // add null-terminator for text output (not counted in the size)
if (n < bufferSize) if (n < bufferSize)
reinterpret_cast<char *>(buffer)[n] = 0; reinterpret_cast<char*>(buffer)[n] = 0;
return n; return n;
} }
template <template <typename> class TSerializer, typename TSource, template <template <typename> class TSerializer, typename TChar, size_t N>
typename TChar, size_t N> typename enable_if<IsChar<TChar>::value, size_t>::type serialize(
#if defined _MSC_VER && _MSC_VER < 1900 JsonVariantConst source, TChar (&buffer)[N]) {
typename enable_if<sizeof(remove_reference<TChar>::type) == 1, size_t>::type
#else
typename enable_if<sizeof(TChar) == 1, size_t>::type
#endif
serialize(const TSource &source, TChar (&buffer)[N]) {
return serialize<TSerializer>(source, buffer, N); return serialize<TSerializer>(source, buffer, N);
} }

View File

@@ -10,7 +10,7 @@ namespace ARDUINOJSON_NAMESPACE {
class StringCopier { class StringCopier {
public: public:
StringCopier(MemoryPool& pool) : _pool(&pool) {} StringCopier(MemoryPool* pool) : _pool(pool) {}
void startString() { void startString() {
_pool->getFreeZone(&_ptr, &_capacity); _pool->getFreeZone(&_ptr, &_capacity);
@@ -19,18 +19,21 @@ class StringCopier {
_pool->markAsOverflowed(); _pool->markAsOverflowed();
} }
String save() { JsonString save() {
ARDUINOJSON_ASSERT(_ptr); ARDUINOJSON_ASSERT(_ptr);
ARDUINOJSON_ASSERT(_size < _capacity); // needs room for the terminator ARDUINOJSON_ASSERT(_size < _capacity); // needs room for the terminator
return String(_pool->saveStringFromFreeZone(_size), _size, String::Copied); return JsonString(_pool->saveStringFromFreeZone(_size), _size,
JsonString::Copied);
} }
void append(const char* s) { void append(const char* s) {
while (*s) append(*s++); while (*s)
append(*s++);
} }
void append(const char* s, size_t n) { void append(const char* s, size_t n) {
while (n-- > 0) append(*s++); while (n-- > 0)
append(*s++);
} }
void append(char c) { void append(char c) {
@@ -48,11 +51,11 @@ class StringCopier {
return _size; return _size;
} }
String str() const { JsonString str() const {
ARDUINOJSON_ASSERT(_ptr); ARDUINOJSON_ASSERT(_ptr);
ARDUINOJSON_ASSERT(_size < _capacity); ARDUINOJSON_ASSERT(_size < _capacity);
_ptr[_size] = 0; _ptr[_size] = 0;
return String(_ptr, _size, String::Copied); return JsonString(_ptr, _size, JsonString::Copied);
} }
private: private:

View File

@@ -5,7 +5,7 @@
#pragma once #pragma once
#include <ArduinoJson/Namespace.hpp> #include <ArduinoJson/Namespace.hpp>
#include <ArduinoJson/Strings/String.hpp> #include <ArduinoJson/Strings/JsonString.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
@@ -17,8 +17,8 @@ class StringMover {
_startPtr = _writePtr; _startPtr = _writePtr;
} }
FORCE_INLINE String save() { FORCE_INLINE JsonString save() {
String s = str(); JsonString s = str();
_writePtr++; _writePtr++;
return s; return s;
} }
@@ -31,9 +31,9 @@ class StringMover {
return true; return true;
} }
String str() const { JsonString str() const {
_writePtr[0] = 0; // terminator _writePtr[0] = 0; // terminator
return String(_startPtr, size(), String::Linked); return JsonString(_startPtr, size(), JsonString::Linked);
} }
size_t size() const { size_t size() const {

View File

@@ -10,13 +10,14 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename TInput> template <typename TInput>
StringCopier makeStringStorage(TInput&, MemoryPool& pool) { StringCopier makeStringStorage(TInput&, MemoryPool* pool) {
ARDUINOJSON_ASSERT(pool != 0);
return StringCopier(pool); return StringCopier(pool);
} }
template <typename TChar> template <typename TChar>
StringMover makeStringStorage( StringMover makeStringStorage(
TChar* input, MemoryPool&, TChar* input, MemoryPool*,
typename enable_if<!is_const<TChar>::value>::type* = 0) { typename enable_if<!is_const<TChar>::value>::type* = 0) {
return StringMover(reinterpret_cast<char*>(input)); return StringMover(reinterpret_cast<char*>(input));
} }

View File

@@ -7,18 +7,19 @@
#include <Arduino.h> #include <Arduino.h>
#include <ArduinoJson/Strings/Adapters/RamString.hpp> #include <ArduinoJson/Strings/Adapters/RamString.hpp>
#include <ArduinoJson/Strings/IsString.hpp> #include <ArduinoJson/Strings/StringAdapter.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
inline SizedRamString adaptString(const ::String& s) { template <typename T>
return SizedRamString(s.c_str(), s.length()); struct StringAdapter<
} T, typename enable_if<is_same<T, ::String>::value ||
is_same<T, ::StringSumHelper>::value>::type> {
typedef SizedRamString AdaptedString;
template <> static AdaptedString adapt(const ::String& s) {
struct IsString< ::String> : true_type {}; return AdaptedString(s.c_str(), s.length());
}
template <> };
struct IsString< ::StringSumHelper> : true_type {};
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -7,7 +7,7 @@
#include <Arduino.h> #include <Arduino.h>
#include <ArduinoJson/Polyfills/pgmspace.hpp> #include <ArduinoJson/Polyfills/pgmspace.hpp>
#include <ArduinoJson/Strings/IsString.hpp> #include <ArduinoJson/Strings/StringAdapter.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
@@ -61,20 +61,31 @@ class FlashString {
::memcpy_P(p, s._str, n); ::memcpy_P(p, s._str, n);
} }
StringStoragePolicy::Copy storagePolicy() const {
return StringStoragePolicy::Copy();
}
private: private:
const char* _str; const char* _str;
size_t _size; size_t _size;
}; };
inline FlashString adaptString(const __FlashStringHelper* s) { template <>
return FlashString(s, s ? strlen_P(reinterpret_cast<const char*>(s)) : 0); struct StringAdapter<const __FlashStringHelper*, void> {
} typedef FlashString AdaptedString;
inline FlashString adaptString(const __FlashStringHelper* s, size_t n) { static AdaptedString adapt(const __FlashStringHelper* s) {
return FlashString(s, n); return AdaptedString(s, s ? strlen_P(reinterpret_cast<const char*>(s)) : 0);
} }
};
template <> template <>
struct IsString<const __FlashStringHelper*> : true_type {}; struct SizedStringAdapter<const __FlashStringHelper*, void> {
typedef FlashString AdaptedString;
static AdaptedString adapt(const __FlashStringHelper* s, size_t n) {
return AdaptedString(s, n);
}
};
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -5,16 +5,32 @@
#pragma once #pragma once
#include <ArduinoJson/Strings/Adapters/RamString.hpp> #include <ArduinoJson/Strings/Adapters/RamString.hpp>
#include <ArduinoJson/Strings/IsString.hpp> #include <ArduinoJson/Strings/JsonString.hpp>
#include <ArduinoJson/Strings/String.hpp> #include <ArduinoJson/Strings/StringAdapter.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
inline SizedRamString adaptString(const String& s) { class JsonStringAdapter : public SizedRamString {
return SizedRamString(s.c_str(), s.size()); public:
} JsonStringAdapter(const JsonString& s)
: SizedRamString(s.c_str(), s.size()), _linked(s.isLinked()) {}
StringStoragePolicy::LinkOrCopy storagePolicy() const {
StringStoragePolicy::LinkOrCopy policy = {_linked};
return policy;
}
private:
bool _linked;
};
template <> template <>
struct IsString<String> : true_type {}; struct StringAdapter<JsonString> {
typedef JsonStringAdapter AdaptedString;
static AdaptedString adapt(const JsonString& s) {
return AdaptedString(s);
}
};
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -8,10 +8,15 @@
#include <string.h> // strcmp #include <string.h> // strcmp
#include <ArduinoJson/Polyfills/assert.hpp> #include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Strings/IsString.hpp> #include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Strings/StringAdapter.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename T>
struct IsChar
: integral_constant<bool, is_integral<T>::value && sizeof(T) == 1> {};
class ZeroTerminatedRamString { class ZeroTerminatedRamString {
public: public:
static const size_t typeSortKey = 3; static const size_t typeSortKey = 3;
@@ -48,30 +53,49 @@ class ZeroTerminatedRamString {
return stringCompare(a, b) == 0; return stringCompare(a, b) == 0;
} }
StringStoragePolicy::Copy storagePolicy() const {
return StringStoragePolicy::Copy();
}
protected: protected:
const char* _str; const char* _str;
}; };
template <> template <typename TChar>
struct IsString<char*> : true_type {}; struct StringAdapter<TChar*, typename enable_if<IsChar<TChar>::value>::type> {
typedef ZeroTerminatedRamString AdaptedString;
inline ZeroTerminatedRamString adaptString(const char* s) { static AdaptedString adapt(const TChar* p) {
return ZeroTerminatedRamString(s); return AdaptedString(reinterpret_cast<const char*>(p));
} }
};
template <typename TChar, size_t N>
struct StringAdapter<TChar[N], typename enable_if<IsChar<TChar>::value>::type> {
typedef ZeroTerminatedRamString AdaptedString;
static AdaptedString adapt(const TChar* p) {
return AdaptedString(reinterpret_cast<const char*>(p));
}
};
class StaticStringAdapter : public ZeroTerminatedRamString {
public:
StaticStringAdapter(const char* str) : ZeroTerminatedRamString(str) {}
StringStoragePolicy::Link storagePolicy() const {
return StringStoragePolicy::Link();
}
};
template <> template <>
struct IsString<unsigned char*> : true_type {}; struct StringAdapter<const char*, void> {
typedef StaticStringAdapter AdaptedString;
inline ZeroTerminatedRamString adaptString(const unsigned char* s) { static AdaptedString adapt(const char* p) {
return adaptString(reinterpret_cast<const char*>(s)); return AdaptedString(p);
} }
};
template <>
struct IsString<signed char*> : true_type {};
inline ZeroTerminatedRamString adaptString(const signed char* s) {
return adaptString(reinterpret_cast<const char*>(s));
}
class SizedRamString { class SizedRamString {
public: public:
@@ -97,23 +121,23 @@ class SizedRamString {
return _str; return _str;
} }
StringStoragePolicy::Copy storagePolicy() const {
return StringStoragePolicy::Copy();
}
protected: protected:
const char* _str; const char* _str;
size_t _size; size_t _size;
}; };
inline SizedRamString adaptString(const char* s, size_t n) { template <typename TChar>
return SizedRamString(s, n); struct SizedStringAdapter<TChar*,
} typename enable_if<IsChar<TChar>::value>::type> {
typedef SizedRamString AdaptedString;
template <size_t N> static AdaptedString adapt(const TChar* p, size_t n) {
struct IsString<char[N]> : true_type {}; return AdaptedString(reinterpret_cast<const char*>(p), n);
}
};
template <size_t N>
struct IsString<const char[N]> : true_type {};
template <size_t N>
inline SizedRamString adaptString(char s[N]) {
return SizedRamString(s, strlen(s));
}
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -11,13 +11,13 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename TCharTraits, typename TAllocator> template <typename TCharTraits, typename TAllocator>
inline SizedRamString adaptString( struct StringAdapter<std::basic_string<char, TCharTraits, TAllocator>, void> {
const std::basic_string<char, TCharTraits, TAllocator>& s) { typedef SizedRamString AdaptedString;
return SizedRamString(s.c_str(), s.size());
}
template <typename TCharTraits, typename TAllocator> static AdaptedString adapt(
struct IsString<std::basic_string<char, TCharTraits, TAllocator> > : true_type { const std::basic_string<char, TCharTraits, TAllocator>& s) {
return AdaptedString(s.c_str(), s.size());
}
}; };
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -10,11 +10,13 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
inline SizedRamString adaptString(const std::string_view& s) {
return SizedRamString(s.data(), s.size());
}
template <> template <>
struct IsString<std::string_view> : true_type {}; struct StringAdapter<std::string_view, void> {
typedef SizedRamString AdaptedString;
static AdaptedString adapt(const std::string_view& s) {
return AdaptedString(s.data(), s.size());
}
};
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -5,13 +5,16 @@
#pragma once #pragma once
#include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Strings/StringAdapter.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename T, typename Enable = void> template <typename T, typename Enable = void>
struct IsString : false_type {}; struct IsString : false_type {};
template <typename TChar> template <typename T>
struct IsString<const TChar*> : IsString<TChar*> {}; struct IsString<
T, typename make_void<typename StringAdapter<T>::AdaptedString>::type>
: true_type {};
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -12,30 +12,37 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
class String : public SafeBoolIdom<String> { // A string.
// https://arduinojson.org/v6/api/jsonstring/
class JsonString : public SafeBoolIdom<JsonString> {
public: public:
enum Ownership { Copied, Linked }; enum Ownership { Copied, Linked };
String() : _data(0), _size(0), _ownership(Linked) {} JsonString() : _data(0), _size(0), _ownership(Linked) {}
String(const char* data, Ownership ownership = Linked) JsonString(const char* data, Ownership ownership = Linked)
: _data(data), _size(data ? ::strlen(data) : 0), _ownership(ownership) {} : _data(data), _size(data ? ::strlen(data) : 0), _ownership(ownership) {}
String(const char* data, size_t sz, Ownership ownership = Linked) JsonString(const char* data, size_t sz, Ownership ownership = Linked)
: _data(data), _size(sz), _ownership(ownership) {} : _data(data), _size(sz), _ownership(ownership) {}
// Returns a pointer to the characters.
const char* c_str() const { const char* c_str() const {
return _data; return _data;
} }
// Returns true if the string is null.
bool isNull() const { bool isNull() const {
return !_data; return !_data;
} }
// Returns true if the string is stored by address.
// Returns false if the string is stored by copy.
bool isLinked() const { bool isLinked() const {
return _ownership == Linked; return _ownership == Linked;
} }
// Returns length of the string.
size_t size() const { size_t size() const {
return _size; return _size;
} }
@@ -45,7 +52,8 @@ class String : public SafeBoolIdom<String> {
return _data ? safe_true() : safe_false(); return _data ? safe_true() : safe_false();
} }
friend bool operator==(String lhs, String rhs) { // Returns true if strings are equal.
friend bool operator==(JsonString lhs, JsonString rhs) {
if (lhs._size != rhs._size) if (lhs._size != rhs._size)
return false; return false;
if (lhs._data == rhs._data) if (lhs._data == rhs._data)
@@ -57,12 +65,13 @@ class String : public SafeBoolIdom<String> {
return memcmp(lhs._data, rhs._data, lhs._size) == 0; return memcmp(lhs._data, rhs._data, lhs._size) == 0;
} }
friend bool operator!=(String lhs, String rhs) { // Returns true if strings differs.
friend bool operator!=(JsonString lhs, JsonString rhs) {
return !(lhs == rhs); return !(lhs == rhs);
} }
#if ARDUINOJSON_ENABLE_STD_STREAM #if ARDUINOJSON_ENABLE_STD_STREAM
friend std::ostream& operator<<(std::ostream& lhs, const String& rhs) { friend std::ostream& operator<<(std::ostream& lhs, const JsonString& rhs) {
lhs.write(rhs.c_str(), static_cast<std::streamsize>(rhs.size())); lhs.write(rhs.c_str(), static_cast<std::streamsize>(rhs.size()));
return lhs; return lhs;
} }

View File

@@ -4,53 +4,15 @@
#pragma once #pragma once
#include <ArduinoJson/Memory/MemoryPool.hpp>
#include <ArduinoJson/Strings/String.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
struct LinkStringStoragePolicy { namespace StringStoragePolicy {
template <typename TAdaptedString, typename TCallback>
bool store(TAdaptedString str, MemoryPool *, TCallback callback) { struct Link {};
String storedString(str.data(), str.size(), String::Linked); struct Copy {};
callback(storedString); struct LinkOrCopy {
return !str.isNull(); bool link;
}
}; };
} // namespace StringStoragePolicy
struct CopyStringStoragePolicy {
template <typename TAdaptedString, typename TCallback>
bool store(TAdaptedString str, MemoryPool *pool, TCallback callback);
};
class LinkOrCopyStringStoragePolicy : LinkStringStoragePolicy,
CopyStringStoragePolicy {
public:
LinkOrCopyStringStoragePolicy(bool link) : _link(link) {}
template <typename TAdaptedString, typename TCallback>
bool store(TAdaptedString str, MemoryPool *pool, TCallback callback) {
if (_link)
return LinkStringStoragePolicy::store(str, pool, callback);
else
return CopyStringStoragePolicy::store(str, pool, callback);
}
private:
bool _link;
};
template <typename T>
inline CopyStringStoragePolicy getStringStoragePolicy(const T &) {
return CopyStringStoragePolicy();
}
inline LinkStringStoragePolicy getStringStoragePolicy(const char *) {
return LinkStringStoragePolicy();
}
inline LinkOrCopyStringStoragePolicy getStringStoragePolicy(const String &s) {
return LinkOrCopyStringStoragePolicy(s.isLinked());
}
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -0,0 +1,31 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
namespace ARDUINOJSON_NAMESPACE {
template <typename TString, typename Enable = void>
struct StringAdapter;
template <typename TString, typename Enable = void>
struct SizedStringAdapter;
template <typename TString>
typename StringAdapter<TString>::AdaptedString adaptString(const TString& s) {
return StringAdapter<TString>::adapt(s);
}
template <typename TChar>
typename StringAdapter<TChar*>::AdaptedString adaptString(TChar* p) {
return StringAdapter<TChar*>::adapt(p);
}
template <typename TChar>
typename SizedStringAdapter<TChar*>::AdaptedString adaptString(TChar* p,
size_t n) {
return SizedStringAdapter<TChar*>::adapt(p, n);
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -4,6 +4,8 @@
#pragma once #pragma once
#include <ArduinoJson/Namespace.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename T, typename Enable = void> template <typename T, typename Enable = void>
@@ -14,4 +16,7 @@ template <typename T1, typename T2>
class InvalidConversion; // Error here? See https://arduinojson.org/v6/invalid-conversion/ class InvalidConversion; // Error here? See https://arduinojson.org/v6/invalid-conversion/
// clang-format on // clang-format on
template <typename T>
struct ConverterNeedsWriteableRef;
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -5,20 +5,20 @@
#pragma once #pragma once
#include <ArduinoJson/Json/JsonSerializer.hpp> #include <ArduinoJson/Json/JsonSerializer.hpp>
#include <ArduinoJson/Variant/JsonVariantConst.hpp>
#include <ArduinoJson/Variant/VariantFunctions.hpp> #include <ArduinoJson/Variant/VariantFunctions.hpp>
#include <ArduinoJson/Variant/VariantRef.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename T, typename Enable> template <typename T, typename Enable>
struct Converter { struct Converter {
static void toJson(const T& src, VariantRef dst) { static void toJson(const T& src, JsonVariant dst) {
// clang-format off // clang-format off
convertToJson(src, dst); // Error here? See https://arduinojson.org/v6/unsupported-set/ convertToJson(src, dst); // Error here? See https://arduinojson.org/v6/unsupported-set/
// clang-format on // clang-format on
} }
static T fromJson(VariantConstRef src) { static T fromJson(JsonVariantConst src) {
// clang-format off // clang-format off
T result; // Error here? See https://arduinojson.org/v6/non-default-constructible/ T result; // Error here? See https://arduinojson.org/v6/non-default-constructible/
convertFromJson(src, result); // Error here? See https://arduinojson.org/v6/unsupported-as/ convertFromJson(src, result); // Error here? See https://arduinojson.org/v6/unsupported-as/
@@ -26,7 +26,7 @@ struct Converter {
return result; return result;
} }
static bool checkJson(VariantConstRef src) { static bool checkJson(JsonVariantConst src) {
T dummy = T(); T dummy = T();
// clang-format off // clang-format off
return canConvertFromJson(src, dummy); // Error here? See https://arduinojson.org/v6/unsupported-is/ return canConvertFromJson(src, dummy); // Error here? See https://arduinojson.org/v6/unsupported-is/
@@ -37,112 +37,113 @@ struct Converter {
template <typename T> template <typename T>
struct Converter< struct Converter<
T, typename enable_if<is_integral<T>::value && !is_same<bool, T>::value && T, typename enable_if<is_integral<T>::value && !is_same<bool, T>::value &&
!is_same<char, T>::value>::type> { !is_same<char, T>::value>::type>
static void toJson(T src, VariantRef dst) { : private VariantAttorney {
static void toJson(T src, JsonVariant dst) {
VariantData* data = getData(dst); VariantData* data = getData(dst);
ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T);
if (data) if (data)
data->setInteger(src); data->setInteger(src);
} }
static T fromJson(VariantConstRef src) { static T fromJson(JsonVariantConst src) {
ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T);
const VariantData* data = getData(src); const VariantData* data = getData(src);
return data ? data->asIntegral<T>() : T(); return data ? data->asIntegral<T>() : T();
} }
static bool checkJson(VariantConstRef src) { static bool checkJson(JsonVariantConst src) {
const VariantData* data = getData(src); const VariantData* data = getData(src);
return data && data->isInteger<T>(); return data && data->isInteger<T>();
} }
}; };
template <typename T> template <typename T>
struct Converter<T, typename enable_if<is_enum<T>::value>::type> { struct Converter<T, typename enable_if<is_enum<T>::value>::type>
static void toJson(T src, VariantRef dst) { : private VariantAttorney {
dst.set(static_cast<Integer>(src)); static void toJson(T src, JsonVariant dst) {
dst.set(static_cast<JsonInteger>(src));
} }
static T fromJson(VariantConstRef src) { static T fromJson(JsonVariantConst src) {
const VariantData* data = getData(src); const VariantData* data = getData(src);
return data ? static_cast<T>(data->asIntegral<int>()) : T(); return data ? static_cast<T>(data->asIntegral<int>()) : T();
} }
static bool checkJson(VariantConstRef src) { static bool checkJson(JsonVariantConst src) {
const VariantData* data = getData(src); const VariantData* data = getData(src);
return data && data->isInteger<int>(); return data && data->isInteger<int>();
} }
}; };
template <> template <>
struct Converter<bool> { struct Converter<bool> : private VariantAttorney {
static void toJson(bool src, VariantRef dst) { static void toJson(bool src, JsonVariant dst) {
VariantData* data = getData(dst); VariantData* data = getData(dst);
if (data) if (data)
data->setBoolean(src); data->setBoolean(src);
} }
static bool fromJson(VariantConstRef src) { static bool fromJson(JsonVariantConst src) {
const VariantData* data = getData(src); const VariantData* data = getData(src);
return data ? data->asBoolean() : false; return data ? data->asBoolean() : false;
} }
static bool checkJson(VariantConstRef src) { static bool checkJson(JsonVariantConst src) {
const VariantData* data = getData(src); const VariantData* data = getData(src);
return data && data->isBoolean(); return data && data->isBoolean();
} }
}; };
template <typename T> template <typename T>
struct Converter<T, typename enable_if<is_floating_point<T>::value>::type> { struct Converter<T, typename enable_if<is_floating_point<T>::value>::type>
static void toJson(T src, VariantRef dst) { : private VariantAttorney {
static void toJson(T src, JsonVariant dst) {
VariantData* data = getData(dst); VariantData* data = getData(dst);
if (data) if (data)
data->setFloat(static_cast<Float>(src)); data->setFloat(static_cast<JsonFloat>(src));
} }
static T fromJson(VariantConstRef src) { static T fromJson(JsonVariantConst src) {
const VariantData* data = getData(src); const VariantData* data = getData(src);
return data ? data->asFloat<T>() : false; return data ? data->asFloat<T>() : 0;
} }
static bool checkJson(VariantConstRef src) { static bool checkJson(JsonVariantConst src) {
const VariantData* data = getData(src); const VariantData* data = getData(src);
return data && data->isFloat(); return data && data->isFloat();
} }
}; };
template <> template <>
struct Converter<const char*> { struct Converter<const char*> : private VariantAttorney {
static void toJson(const char* src, VariantRef dst) { static void toJson(const char* src, JsonVariant dst) {
variantSetString(getData(dst), adaptString(src), getPool(dst), variantSetString(getData(dst), adaptString(src), getPool(dst));
getStringStoragePolicy(src));
} }
static const char* fromJson(VariantConstRef src) { static const char* fromJson(JsonVariantConst src) {
const VariantData* data = getData(src); const VariantData* data = getData(src);
return data ? data->asString().c_str() : 0; return data ? data->asString().c_str() : 0;
} }
static bool checkJson(VariantConstRef src) { static bool checkJson(JsonVariantConst src) {
const VariantData* data = getData(src); const VariantData* data = getData(src);
return data && data->isString(); return data && data->isString();
} }
}; };
template <> template <>
struct Converter<String> { struct Converter<JsonString> : private VariantAttorney {
static void toJson(String src, VariantRef dst) { static void toJson(JsonString src, JsonVariant dst) {
variantSetString(getData(dst), adaptString(src), getPool(dst), variantSetString(getData(dst), adaptString(src), getPool(dst));
getStringStoragePolicy(src));
} }
static String fromJson(VariantConstRef src) { static JsonString fromJson(JsonVariantConst src) {
const VariantData* data = getData(src); const VariantData* data = getData(src);
return data ? data->asString() : 0; return data ? data->asString() : 0;
} }
static bool checkJson(VariantConstRef src) { static bool checkJson(JsonVariantConst src) {
const VariantData* data = getData(src); const VariantData* data = getData(src);
return data && data->isString(); return data && data->isString();
} }
@@ -150,17 +151,16 @@ struct Converter<String> {
template <typename T> template <typename T>
inline typename enable_if<IsString<T>::value, bool>::type convertToJson( inline typename enable_if<IsString<T>::value, bool>::type convertToJson(
const T& src, VariantRef dst) { const T& src, JsonVariant dst) {
VariantData* data = getData(dst); VariantData* data = VariantAttorney::getData(dst);
MemoryPool* pool = getPool(dst); MemoryPool* pool = VariantAttorney::getPool(dst);
return variantSetString(data, adaptString(src), pool, return variantSetString(data, adaptString(src), pool);
getStringStoragePolicy(src));
} }
template <> template <>
struct Converter<SerializedValue<const char*> > { struct Converter<SerializedValue<const char*> > {
static void toJson(SerializedValue<const char*> src, VariantRef dst) { static void toJson(SerializedValue<const char*> src, JsonVariant dst) {
VariantData* data = getData(dst); VariantData* data = VariantAttorney::getData(dst);
if (data) if (data)
data->setLinkedRaw(src); data->setLinkedRaw(src);
} }
@@ -171,8 +171,9 @@ struct Converter<SerializedValue<const char*> > {
// SerializedValue<const __FlashStringHelper*> // SerializedValue<const __FlashStringHelper*>
template <typename T> template <typename T>
struct Converter<SerializedValue<T>, struct Converter<SerializedValue<T>,
typename enable_if<!is_same<const char*, T>::value>::type> { typename enable_if<!is_same<const char*, T>::value>::type>
static void toJson(SerializedValue<T> src, VariantRef dst) { : private VariantAttorney {
static void toJson(SerializedValue<T> src, JsonVariant dst) {
VariantData* data = getData(dst); VariantData* data = getData(dst);
MemoryPool* pool = getPool(dst); MemoryPool* pool = getPool(dst);
if (data) if (data)
@@ -183,14 +184,14 @@ struct Converter<SerializedValue<T>,
#if ARDUINOJSON_HAS_NULLPTR #if ARDUINOJSON_HAS_NULLPTR
template <> template <>
struct Converter<decltype(nullptr)> { struct Converter<decltype(nullptr)> : private VariantAttorney {
static void toJson(decltype(nullptr), VariantRef dst) { static void toJson(decltype(nullptr), JsonVariant dst) {
variantSetNull(getData(dst)); variantSetNull(getData(dst));
} }
static decltype(nullptr) fromJson(VariantConstRef) { static decltype(nullptr) fromJson(JsonVariantConst) {
return nullptr; return nullptr;
} }
static bool checkJson(VariantConstRef src) { static bool checkJson(JsonVariantConst src) {
const VariantData* data = getData(src); const VariantData* data = getData(src);
return data == 0 || data->isNull(); return data == 0 || data->isNull();
} }
@@ -206,9 +207,10 @@ class MemoryPoolPrint : public Print {
pool->getFreeZone(&_string, &_capacity); pool->getFreeZone(&_string, &_capacity);
} }
String str() { JsonString str() {
ARDUINOJSON_ASSERT(_size < _capacity); ARDUINOJSON_ASSERT(_size < _capacity);
return String(_pool->saveStringFromFreeZone(_size), _size, String::Copied); return JsonString(_pool->saveStringFromFreeZone(_size), _size,
JsonString::Copied);
} }
size_t write(uint8_t c) { size_t write(uint8_t c) {
@@ -240,9 +242,9 @@ class MemoryPoolPrint : public Print {
size_t _capacity; size_t _capacity;
}; };
inline void convertToJson(const ::Printable& src, VariantRef dst) { inline void convertToJson(const ::Printable& src, JsonVariant dst) {
MemoryPool* pool = getPool(dst); MemoryPool* pool = VariantAttorney::getPool(dst);
VariantData* data = getData(dst); VariantData* data = VariantAttorney::getData(dst);
if (!pool || !data) if (!pool || !data)
return; return;
MemoryPoolPrint print(pool); MemoryPoolPrint print(pool);
@@ -259,48 +261,59 @@ inline void convertToJson(const ::Printable& src, VariantRef dst) {
#if ARDUINOJSON_ENABLE_ARDUINO_STRING #if ARDUINOJSON_ENABLE_ARDUINO_STRING
inline void convertFromJson(VariantConstRef src, ::String& dst) { inline void convertFromJson(JsonVariantConst src, ::String& dst) {
String str = src.as<String>(); JsonString str = src.as<JsonString>();
if (str) if (str)
dst = str.c_str(); dst = str.c_str();
else else
serializeJson(src, dst); serializeJson(src, dst);
} }
inline bool canConvertFromJson(VariantConstRef src, const ::String&) { inline bool canConvertFromJson(JsonVariantConst src, const ::String&) {
return src.is<String>(); return src.is<JsonString>();
} }
#endif #endif
#if ARDUINOJSON_ENABLE_STD_STRING #if ARDUINOJSON_ENABLE_STD_STRING
inline void convertFromJson(VariantConstRef src, std::string& dst) { inline void convertFromJson(JsonVariantConst src, std::string& dst) {
String str = src.as<String>(); JsonString str = src.as<JsonString>();
if (str) if (str)
dst.assign(str.c_str(), str.size()); dst.assign(str.c_str(), str.size());
else else
serializeJson(src, dst); serializeJson(src, dst);
} }
inline bool canConvertFromJson(VariantConstRef src, const std::string&) { inline bool canConvertFromJson(JsonVariantConst src, const std::string&) {
return src.is<String>(); return src.is<JsonString>();
} }
#endif #endif
#if ARDUINOJSON_ENABLE_STRING_VIEW #if ARDUINOJSON_ENABLE_STRING_VIEW
inline void convertFromJson(VariantConstRef src, std::string_view& dst) { inline void convertFromJson(JsonVariantConst src, std::string_view& dst) {
String str = src.as<String>(); JsonString str = src.as<JsonString>();
if (str) // the standard doesn't allow passing null to the constructor if (str) // the standard doesn't allow passing null to the constructor
dst = std::string_view(str.c_str(), str.size()); dst = std::string_view(str.c_str(), str.size());
} }
inline bool canConvertFromJson(VariantConstRef src, const std::string_view&) { inline bool canConvertFromJson(JsonVariantConst src, const std::string_view&) {
return src.is<String>(); return src.is<JsonString>();
} }
#endif #endif
template <typename T>
struct ConverterNeedsWriteableRef {
protected: // <- to avoid GCC's "all member functions in class are private"
static int probe(T (*f)(JsonVariant));
static char probe(T (*f)(JsonVariantConst));
public:
static const bool value =
sizeof(probe(Converter<T>::fromJson)) == sizeof(int);
};
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -0,0 +1,80 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Variant/VariantRefBase.hpp>
namespace ARDUINOJSON_NAMESPACE {
// A reference to a value in a JsonDocument.
// https://arduinojson.org/v6/api/jsonvariant/
class JsonVariant : public VariantRefBase<JsonVariant>,
public VariantOperators<JsonVariant> {
friend class VariantAttorney;
public:
// Creates an unbound reference.
JsonVariant() : _data(0), _pool(0) {}
// INTERNAL USE ONLY
JsonVariant(MemoryPool* pool, VariantData* data) : _data(data), _pool(pool) {}
private:
FORCE_INLINE MemoryPool* getPool() const {
return _pool;
}
FORCE_INLINE VariantData* getData() const {
return _data;
}
FORCE_INLINE VariantData* getOrCreateData() const {
return _data;
}
VariantData* _data;
MemoryPool* _pool;
};
template <>
struct Converter<JsonVariant> : private VariantAttorney {
static void toJson(JsonVariant src, JsonVariant dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static JsonVariant fromJson(JsonVariant src) {
return src;
}
static InvalidConversion<JsonVariantConst, JsonVariant> fromJson(
JsonVariantConst);
static bool checkJson(JsonVariant src) {
VariantData* data = getData(src);
return !!data;
}
static bool checkJson(JsonVariantConst) {
return false;
}
};
template <>
struct Converter<JsonVariantConst> : private VariantAttorney {
static void toJson(JsonVariantConst src, JsonVariant dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static JsonVariantConst fromJson(JsonVariantConst src) {
return JsonVariantConst(getData(src));
}
static bool checkJson(JsonVariantConst src) {
const VariantData* data = getData(src);
return !!data;
}
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -0,0 +1,141 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <stddef.h>
#include <stdint.h> // for uint8_t
#include <ArduinoJson/Memory/MemoryPool.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Strings/IsString.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp>
#include <ArduinoJson/Variant/VariantAttorney.hpp>
#include <ArduinoJson/Variant/VariantFunctions.hpp>
#include <ArduinoJson/Variant/VariantOperators.hpp>
#include <ArduinoJson/Variant/VariantTag.hpp>
namespace ARDUINOJSON_NAMESPACE {
// Forward declarations.
class JsonArray;
class JsonObject;
// A read-only reference to a value in a JsonDocument
// https://arduinojson.org/v6/api/jsonarrayconst/
class JsonVariantConst : public VariantTag,
public VariantOperators<JsonVariantConst> {
friend class VariantAttorney;
public:
// Creates an unbound reference.
JsonVariantConst() : _data(0) {}
// INTERNAL USE ONLY
explicit JsonVariantConst(const VariantData* data) : _data(data) {}
// Returns true if the value is null or the reference is unbound.
// https://arduinojson.org/v6/api/jsonvariantconst/isnull/
FORCE_INLINE bool isNull() const {
return variantIsNull(_data);
}
// Returns true if the reference is unbound.
FORCE_INLINE bool isUnbound() const {
return !_data;
}
// Returns the number of bytes occupied by the value.
// https://arduinojson.org/v6/api/jsonvariantconst/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return _data ? _data->memoryUsage() : 0;
}
// Returns the depth (nesting level) of the value.
// https://arduinojson.org/v6/api/jsonvariantconst/nesting/
FORCE_INLINE size_t nesting() const {
return variantNesting(_data);
}
// Returns the size of the array or object.
// https://arduinojson.org/v6/api/jsonvariantconst/size/
size_t size() const {
return variantSize(_data);
}
// Casts the value to the specified type.
// https://arduinojson.org/v6/api/jsonvariantconst/as/
template <typename T>
FORCE_INLINE
typename enable_if<!is_same<T, char*>::value && !is_same<T, char>::value,
T>::type
as() const {
return Converter<T>::fromJson(*this);
}
// Returns true if the value is of the specified type.
// https://arduinojson.org/v6/api/jsonvariantconst/is/
template <typename T>
FORCE_INLINE
typename enable_if<!is_same<T, char*>::value && !is_same<T, char>::value,
bool>::type
is() const {
return Converter<T>::checkJson(*this);
}
template <typename T>
FORCE_INLINE operator T() const {
return as<T>();
}
// Gets array's element at specified index.
// https://arduinojson.org/v6/api/jsonvariantconst/subscript/
FORCE_INLINE JsonVariantConst operator[](size_t index) const {
return JsonVariantConst(variantGetElement(_data, index));
}
// Gets object's member with specified key.
// https://arduinojson.org/v6/api/jsonvariantconst/subscript/
template <typename TString>
FORCE_INLINE
typename enable_if<IsString<TString>::value, JsonVariantConst>::type
operator[](const TString& key) const {
return JsonVariantConst(variantGetMember(_data, adaptString(key)));
}
// Gets object's member with specified key.
// https://arduinojson.org/v6/api/jsonvariantconst/subscript/
template <typename TChar>
FORCE_INLINE
typename enable_if<IsString<TChar*>::value, JsonVariantConst>::type
operator[](TChar* key) const {
return JsonVariantConst(variantGetMember(_data, adaptString(key)));
}
// Returns true if tge object contains the specified key.
// https://arduinojson.org/v6/api/jsonvariantconst/containskey/
template <typename TString>
FORCE_INLINE typename enable_if<IsString<TString>::value, bool>::type
containsKey(const TString& key) const {
return variantGetMember(getData(), adaptString(key)) != 0;
}
// Returns true if tge object contains the specified key.
// https://arduinojson.org/v6/api/jsonvariantconst/containskey/
template <typename TChar>
FORCE_INLINE typename enable_if<IsString<TChar*>::value, bool>::type
containsKey(TChar* key) const {
return variantGetMember(getData(), adaptString(key)) != 0;
}
protected:
const VariantData* getData() const {
return _data;
}
private:
const VariantData* _data;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -23,12 +23,11 @@ struct SlotKeySetter {
VariantSlot* _instance; VariantSlot* _instance;
}; };
template <typename TAdaptedString, typename TStoragePolicy> template <typename TAdaptedString>
inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool, inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool) {
TStoragePolicy storage) {
if (!var) if (!var)
return false; return false;
return storage.store(key, pool, SlotKeySetter(var)); return storeString(pool, key, SlotKeySetter(var));
} }
inline size_t slotSize(const VariantSlot* var) { inline size_t slotSize(const VariantSlot* var) {

View File

@@ -0,0 +1,48 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Polyfills/attributes.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Variant/VariantTo.hpp>
#include "JsonVariantConst.hpp"
namespace ARDUINOJSON_NAMESPACE {
// Grants access to the internal variant API
class VariantAttorney {
// Tells whether getData() returns a const pointer
template <typename TClient>
struct ResultOfGetData {
protected: // <- to avoid GCC's "all member functions in class are private"
static int probe(const VariantData*);
static char probe(VariantData*);
static TClient& client;
public:
typedef typename conditional<sizeof(probe(client.getData())) == sizeof(int),
const VariantData*, VariantData*>::type type;
};
public:
template <typename TClient>
FORCE_INLINE static MemoryPool* getPool(TClient& client) {
return client.getPool();
}
template <typename TClient>
FORCE_INLINE static typename ResultOfGetData<TClient>::type getData(
TClient& client) {
return client.getData();
}
template <typename TClient>
FORCE_INLINE static VariantData* getOrCreateData(TClient& client) {
return client.getOrCreateData();
}
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -5,7 +5,6 @@
#pragma once #pragma once
#include <ArduinoJson/Configuration.hpp> #include <ArduinoJson/Configuration.hpp>
#include <ArduinoJson/Misc/Visitable.hpp>
#include <ArduinoJson/Numbers/arithmeticCompare.hpp> #include <ArduinoJson/Numbers/arithmeticCompare.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp> #include <ArduinoJson/Strings/StringAdapters.hpp>
@@ -27,7 +26,7 @@ struct Comparer<T, typename enable_if<IsString<T>::value>::type>
explicit Comparer(T value) : rhs(value) {} explicit Comparer(T value) : rhs(value) {}
CompareResult visitString(const char *lhs, size_t n) { CompareResult visitString(const char* lhs, size_t n) {
int i = stringCompare(adaptString(rhs), adaptString(lhs, n)); int i = stringCompare(adaptString(rhs), adaptString(lhs, n));
if (i < 0) if (i < 0)
return COMPARE_RESULT_GREATER; return COMPARE_RESULT_GREATER;
@@ -53,20 +52,20 @@ struct Comparer<T, typename enable_if<is_integral<T>::value ||
explicit Comparer(T value) : rhs(value) {} explicit Comparer(T value) : rhs(value) {}
CompareResult visitFloat(Float lhs) { CompareResult visitFloat(JsonFloat lhs) {
return arithmeticCompare(lhs, rhs); return arithmeticCompare(lhs, rhs);
} }
CompareResult visitSignedInteger(Integer lhs) { CompareResult visitSignedInteger(JsonInteger lhs) {
return arithmeticCompare(lhs, rhs); return arithmeticCompare(lhs, rhs);
} }
CompareResult visitUnsignedInteger(UInt lhs) { CompareResult visitUnsignedInteger(JsonUInt lhs) {
return arithmeticCompare(lhs, rhs); return arithmeticCompare(lhs, rhs);
} }
CompareResult visitBoolean(bool lhs) { CompareResult visitBoolean(bool lhs) {
return visitUnsignedInteger(static_cast<UInt>(lhs)); return visitUnsignedInteger(static_cast<JsonUInt>(lhs));
} }
}; };
@@ -84,12 +83,12 @@ struct Comparer<decltype(nullptr), void> : NullComparer {
#endif #endif
struct ArrayComparer : ComparerBase { struct ArrayComparer : ComparerBase {
const CollectionData *_rhs; const CollectionData* _rhs;
explicit ArrayComparer(const CollectionData &rhs) : _rhs(&rhs) {} explicit ArrayComparer(const CollectionData& rhs) : _rhs(&rhs) {}
CompareResult visitArray(const CollectionData &lhs) { CompareResult visitArray(const CollectionData& lhs) {
if (lhs.equalsArray(*_rhs)) if (JsonArrayConst(&lhs) == JsonArrayConst(_rhs))
return COMPARE_RESULT_EQUAL; return COMPARE_RESULT_EQUAL;
else else
return COMPARE_RESULT_DIFFER; return COMPARE_RESULT_DIFFER;
@@ -97,12 +96,12 @@ struct ArrayComparer : ComparerBase {
}; };
struct ObjectComparer : ComparerBase { struct ObjectComparer : ComparerBase {
const CollectionData *_rhs; const CollectionData* _rhs;
explicit ObjectComparer(const CollectionData &rhs) : _rhs(&rhs) {} explicit ObjectComparer(const CollectionData& rhs) : _rhs(&rhs) {}
CompareResult visitObject(const CollectionData &lhs) { CompareResult visitObject(const CollectionData& lhs) {
if (lhs.equalsObject(*_rhs)) if (JsonObjectConst(&lhs) == JsonObjectConst(_rhs))
return COMPARE_RESULT_EQUAL; return COMPARE_RESULT_EQUAL;
else else
return COMPARE_RESULT_DIFFER; return COMPARE_RESULT_DIFFER;
@@ -110,13 +109,13 @@ struct ObjectComparer : ComparerBase {
}; };
struct RawComparer : ComparerBase { struct RawComparer : ComparerBase {
const char *_rhsData; const char* _rhsData;
size_t _rhsSize; size_t _rhsSize;
explicit RawComparer(const char *rhsData, size_t rhsSize) explicit RawComparer(const char* rhsData, size_t rhsSize)
: _rhsData(rhsData), _rhsSize(rhsSize) {} : _rhsData(rhsData), _rhsSize(rhsSize) {}
CompareResult visitRawJson(const char *lhsData, size_t lhsSize) { CompareResult visitRawJson(const char* lhsData, size_t lhsSize) {
size_t size = _rhsSize < lhsSize ? _rhsSize : lhsSize; size_t size = _rhsSize < lhsSize ? _rhsSize : lhsSize;
int n = memcmp(lhsData, _rhsData, size); int n = memcmp(lhsData, _rhsData, size);
if (n < 0) if (n < 0)
@@ -128,45 +127,43 @@ struct RawComparer : ComparerBase {
} }
}; };
template <typename T> struct VariantComparer : ComparerBase {
struct Comparer<T, typename enable_if<IsVisitable<T>::value>::type> const VariantData* rhs;
: ComparerBase {
const T *rhs; // TODO: should be a VariantConstRef
explicit Comparer(const T &value) : rhs(&value) {} explicit VariantComparer(const VariantData* value) : rhs(value) {}
CompareResult visitArray(const CollectionData &lhs) { CompareResult visitArray(const CollectionData& lhs) {
ArrayComparer comparer(lhs); ArrayComparer comparer(lhs);
return accept(comparer); return accept(comparer);
} }
CompareResult visitObject(const CollectionData &lhs) { CompareResult visitObject(const CollectionData& lhs) {
ObjectComparer comparer(lhs); ObjectComparer comparer(lhs);
return accept(comparer); return accept(comparer);
} }
CompareResult visitFloat(Float lhs) { CompareResult visitFloat(JsonFloat lhs) {
Comparer<Float> comparer(lhs); Comparer<JsonFloat> comparer(lhs);
return accept(comparer); return accept(comparer);
} }
CompareResult visitString(const char *lhs, size_t) { CompareResult visitString(const char* lhs, size_t) {
Comparer<const char *> comparer(lhs); Comparer<const char*> comparer(lhs);
return accept(comparer); return accept(comparer);
} }
CompareResult visitRawJson(const char *lhsData, size_t lhsSize) { CompareResult visitRawJson(const char* lhsData, size_t lhsSize) {
RawComparer comparer(lhsData, lhsSize); RawComparer comparer(lhsData, lhsSize);
return accept(comparer); return accept(comparer);
} }
CompareResult visitSignedInteger(Integer lhs) { CompareResult visitSignedInteger(JsonInteger lhs) {
Comparer<Integer> comparer(lhs); Comparer<JsonInteger> comparer(lhs);
return accept(comparer); return accept(comparer);
} }
CompareResult visitUnsignedInteger(UInt lhs) { CompareResult visitUnsignedInteger(JsonUInt lhs) {
Comparer<UInt> comparer(lhs); Comparer<JsonUInt> comparer(lhs);
return accept(comparer); return accept(comparer);
} }
@@ -182,8 +179,8 @@ struct Comparer<T, typename enable_if<IsVisitable<T>::value>::type>
private: private:
template <typename TComparer> template <typename TComparer>
CompareResult accept(TComparer &comparer) { CompareResult accept(TComparer& comparer) {
CompareResult reversedResult = rhs->accept(comparer); CompareResult reversedResult = variantAccept(rhs, comparer);
switch (reversedResult) { switch (reversedResult) {
case COMPARE_RESULT_GREATER: case COMPARE_RESULT_GREATER:
return COMPARE_RESULT_LESS; return COMPARE_RESULT_LESS;
@@ -195,14 +192,18 @@ struct Comparer<T, typename enable_if<IsVisitable<T>::value>::type>
} }
}; };
template <typename T1, typename T2> template <typename T>
CompareResult compare(const T1 &lhs, const T2 &rhs) { struct Comparer<
Comparer<T2> comparer(rhs); T, typename enable_if<is_convertible<T, JsonVariantConst>::value>::type>
return lhs.accept(comparer); : VariantComparer {
} explicit Comparer(const T& value)
: VariantComparer(VariantAttorney::getData(value)) {}
};
inline int variantCompare(const VariantData *a, const VariantData *b) { template <typename T>
return compare(VariantConstRef(a), VariantConstRef(b)); CompareResult compare(JsonVariantConst lhs, const T& rhs) {
Comparer<T> comparer(rhs);
return variantAccept(VariantAttorney::getData(lhs), comparer);
} }
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -7,8 +7,8 @@
#include <stddef.h> // size_t #include <stddef.h> // size_t
#include <ArduinoJson/Collection/CollectionData.hpp> #include <ArduinoJson/Collection/CollectionData.hpp>
#include <ArduinoJson/Numbers/Float.hpp> #include <ArduinoJson/Numbers/JsonFloat.hpp>
#include <ArduinoJson/Numbers/Integer.hpp> #include <ArduinoJson/Numbers/JsonInteger.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
@@ -39,18 +39,18 @@ enum {
}; };
struct RawData { struct RawData {
const char *data; const char* data;
size_t size; size_t size;
}; };
union VariantContent { union VariantContent {
Float asFloat; JsonFloat asFloat;
bool asBoolean; bool asBoolean;
UInt asUnsignedInteger; JsonUInt asUnsignedInteger;
Integer asSignedInteger; JsonInteger asSignedInteger;
CollectionData asCollection; CollectionData asCollection;
struct { struct {
const char *data; const char* data;
size_t size; size_t size;
} asString; } asString;
}; };

View File

@@ -7,7 +7,7 @@
#include <ArduinoJson/Memory/MemoryPool.hpp> #include <ArduinoJson/Memory/MemoryPool.hpp>
#include <ArduinoJson/Misc/SerializedValue.hpp> #include <ArduinoJson/Misc/SerializedValue.hpp>
#include <ArduinoJson/Numbers/convertNumber.hpp> #include <ArduinoJson/Numbers/convertNumber.hpp>
#include <ArduinoJson/Strings/String.hpp> #include <ArduinoJson/Strings/JsonString.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp> #include <ArduinoJson/Strings/StringAdapters.hpp>
#include <ArduinoJson/Variant/VariantContent.hpp> #include <ArduinoJson/Variant/VariantContent.hpp>
@@ -37,8 +37,13 @@ class VariantData {
_flags = VALUE_IS_NULL; _flags = VALUE_IS_NULL;
} }
void operator=(const VariantData& src) {
_content = src._content;
_flags = uint8_t((_flags & OWNED_KEY_BIT) | (src._flags & ~OWNED_KEY_BIT));
}
template <typename TVisitor> template <typename TVisitor>
typename TVisitor::result_type accept(TVisitor &visitor) const { typename TVisitor::result_type accept(TVisitor& visitor) const {
switch (type()) { switch (type()) {
case VALUE_IS_FLOAT: case VALUE_IS_FLOAT:
return visitor.visitFloat(_content.asFloat); return visitor.visitFloat(_content.asFloat);
@@ -79,27 +84,31 @@ class VariantData {
template <typename T> template <typename T>
T asFloat() const; T asFloat() const;
String asString() const; JsonString asString() const;
bool asBoolean() const; bool asBoolean() const;
CollectionData *asArray() { CollectionData* asArray() {
return isArray() ? &_content.asCollection : 0; return isArray() ? &_content.asCollection : 0;
} }
const CollectionData *asArray() const { const CollectionData* asArray() const {
return const_cast<VariantData *>(this)->asArray(); return const_cast<VariantData*>(this)->asArray();
} }
CollectionData *asObject() { const CollectionData* asCollection() const {
return isCollection() ? &_content.asCollection : 0;
}
CollectionData* asObject() {
return isObject() ? &_content.asCollection : 0; return isObject() ? &_content.asCollection : 0;
} }
const CollectionData *asObject() const { const CollectionData* asObject() const {
return const_cast<VariantData *>(this)->asObject(); return const_cast<VariantData*>(this)->asObject();
} }
bool copyFrom(const VariantData &src, MemoryPool *pool); bool copyFrom(const VariantData& src, MemoryPool* pool);
bool isArray() const { bool isArray() const {
return (_flags & VALUE_IS_ARRAY) != 0; return (_flags & VALUE_IS_ARRAY) != 0;
@@ -163,12 +172,12 @@ class VariantData {
_content.asBoolean = value; _content.asBoolean = value;
} }
void setFloat(Float value) { void setFloat(JsonFloat value) {
setType(VALUE_IS_FLOAT); setType(VALUE_IS_FLOAT);
_content.asFloat = value; _content.asFloat = value;
} }
void setLinkedRaw(SerializedValue<const char *> value) { void setLinkedRaw(SerializedValue<const char*> value) {
if (value.data()) { if (value.data()) {
setType(VALUE_IS_LINKED_RAW); setType(VALUE_IS_LINKED_RAW);
_content.asString.data = value.data(); _content.asString.data = value.data();
@@ -179,8 +188,8 @@ class VariantData {
} }
template <typename T> template <typename T>
bool storeOwnedRaw(SerializedValue<T> value, MemoryPool *pool) { bool storeOwnedRaw(SerializedValue<T> value, MemoryPool* pool) {
const char *dup = pool->saveString(adaptString(value.data(), value.size())); const char* dup = pool->saveString(adaptString(value.data(), value.size()));
if (dup) { if (dup) {
setType(VALUE_IS_OWNED_RAW); setType(VALUE_IS_OWNED_RAW);
_content.asString.data = dup; _content.asString.data = dup;
@@ -195,7 +204,7 @@ class VariantData {
template <typename T> template <typename T>
typename enable_if<is_unsigned<T>::value>::type setInteger(T value) { typename enable_if<is_unsigned<T>::value>::type setInteger(T value) {
setType(VALUE_IS_UNSIGNED_INTEGER); setType(VALUE_IS_UNSIGNED_INTEGER);
_content.asUnsignedInteger = static_cast<UInt>(value); _content.asUnsignedInteger = static_cast<JsonUInt>(value);
} }
template <typename T> template <typename T>
@@ -208,7 +217,7 @@ class VariantData {
setType(VALUE_IS_NULL); setType(VALUE_IS_NULL);
} }
void setString(String s) { void setString(JsonString s) {
ARDUINOJSON_ASSERT(s); ARDUINOJSON_ASSERT(s);
if (s.isLinked()) if (s.isLinked())
setType(VALUE_IS_LINKED_STRING); setType(VALUE_IS_LINKED_STRING);
@@ -218,13 +227,13 @@ class VariantData {
_content.asString.size = s.size(); _content.asString.size = s.size();
} }
CollectionData &toArray() { CollectionData& toArray() {
setType(VALUE_IS_ARRAY); setType(VALUE_IS_ARRAY);
_content.asCollection.clear(); _content.asCollection.clear();
return _content.asCollection; return _content.asCollection;
} }
CollectionData &toObject() { CollectionData& toObject() {
setType(VALUE_IS_OBJECT); setType(VALUE_IS_OBJECT);
_content.asCollection.clear(); _content.asCollection.clear();
return _content.asCollection; return _content.asCollection;
@@ -245,15 +254,11 @@ class VariantData {
} }
} }
size_t nesting() const {
return isCollection() ? _content.asCollection.nesting() : 0;
}
size_t size() const { size_t size() const {
return isCollection() ? _content.asCollection.size() : 0; return isCollection() ? _content.asCollection.size() : 0;
} }
VariantData *addElement(MemoryPool *pool) { VariantData* addElement(MemoryPool* pool) {
if (isNull()) if (isNull())
toArray(); toArray();
if (!isArray()) if (!isArray())
@@ -261,11 +266,12 @@ class VariantData {
return _content.asCollection.addElement(pool); return _content.asCollection.addElement(pool);
} }
VariantData *getElement(size_t index) const { VariantData* getElement(size_t index) const {
return isArray() ? _content.asCollection.getElement(index) : 0; const CollectionData* col = asArray();
return col ? col->getElement(index) : 0;
} }
VariantData *getOrAddElement(size_t index, MemoryPool *pool) { VariantData* getOrAddElement(size_t index, MemoryPool* pool) {
if (isNull()) if (isNull())
toArray(); toArray();
if (!isArray()) if (!isArray())
@@ -274,18 +280,18 @@ class VariantData {
} }
template <typename TAdaptedString> template <typename TAdaptedString>
VariantData *getMember(TAdaptedString key) const { VariantData* getMember(TAdaptedString key) const {
return isObject() ? _content.asCollection.getMember(key) : 0; const CollectionData* col = asObject();
return col ? col->getMember(key) : 0;
} }
template <typename TAdaptedString, typename TStoragePolicy> template <typename TAdaptedString>
VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool, VariantData* getOrAddMember(TAdaptedString key, MemoryPool* pool) {
TStoragePolicy storage_policy) {
if (isNull()) if (isNull())
toObject(); toObject();
if (!isObject()) if (!isObject())
return 0; return 0;
return _content.asCollection.getOrAddMember(key, pool, storage_policy); return _content.asCollection.getOrAddMember(key, pool);
} }
void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) { void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) {
@@ -299,15 +305,14 @@ class VariantData {
return _flags & VALUE_MASK; return _flags & VALUE_MASK;
} }
template <typename TAdaptedString, typename TStoragePolicy> template <typename TAdaptedString>
inline bool storeString(TAdaptedString value, MemoryPool *pool, inline bool setString(TAdaptedString value, MemoryPool* pool) {
TStoragePolicy storage) {
if (value.isNull()) { if (value.isNull()) {
setNull(); setNull();
return true; return true;
} }
return storage.store(value, pool, VariantStringSetter(this)); return storeString(pool, value, VariantStringSetter(this));
} }
private: private:
@@ -317,7 +322,7 @@ class VariantData {
} }
struct VariantStringSetter { struct VariantStringSetter {
VariantStringSetter(VariantData *instance) : _instance(instance) {} VariantStringSetter(VariantData* instance) : _instance(instance) {}
template <typename TStoredString> template <typename TStoredString>
void operator()(TStoredString s) { void operator()(TStoredString s) {
@@ -327,7 +332,7 @@ class VariantData {
_instance->setNull(); _instance->setNull();
} }
VariantData *_instance; VariantData* _instance;
}; };
}; };

View File

@@ -7,32 +7,21 @@
#include <ArduinoJson/Polyfills/attributes.hpp> #include <ArduinoJson/Polyfills/attributes.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp> #include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Variant/VariantData.hpp> #include <ArduinoJson/Variant/VariantData.hpp>
#include <ArduinoJson/Variant/Visitor.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename TVisitor> template <typename TVisitor>
inline typename TVisitor::result_type variantAccept(const VariantData *var, inline typename TVisitor::result_type variantAccept(const VariantData* var,
TVisitor &visitor) { TVisitor& visitor) {
if (var != 0) if (var != 0)
return var->accept(visitor); return var->accept(visitor);
else else
return visitor.visitNull(); return visitor.visitNull();
} }
inline const CollectionData *variantAsArray(const VariantData *var) { inline bool variantCopyFrom(VariantData* dst, const VariantData* src,
return var != 0 ? var->asArray() : 0; MemoryPool* pool) {
}
inline const CollectionData *variantAsObject(const VariantData *var) {
return var != 0 ? var->asObject() : 0;
}
inline CollectionData *variantAsObject(VariantData *var) {
return var != 0 ? var->asObject() : 0;
}
inline bool variantCopyFrom(VariantData *dst, const VariantData *src,
MemoryPool *pool) {
if (!dst) if (!dst)
return false; return false;
if (!src) { if (!src) {
@@ -42,68 +31,83 @@ inline bool variantCopyFrom(VariantData *dst, const VariantData *src,
return dst->copyFrom(*src, pool); return dst->copyFrom(*src, pool);
} }
inline int variantCompare(const VariantData *a, const VariantData *b); inline void variantSetNull(VariantData* var) {
inline void variantSetNull(VariantData *var) {
if (!var) if (!var)
return; return;
var->setNull(); var->setNull();
} }
template <typename TAdaptedString, typename TStoragePolicy> template <typename TAdaptedString>
inline bool variantSetString(VariantData *var, TAdaptedString value, inline bool variantSetString(VariantData* var, TAdaptedString value,
MemoryPool *pool, TStoragePolicy storage_policy) { MemoryPool* pool) {
return var != 0 ? var->storeString(value, pool, storage_policy) : 0; return var != 0 ? var->setString(value, pool) : 0;
} }
inline size_t variantSize(const VariantData *var) { inline size_t variantSize(const VariantData* var) {
return var != 0 ? var->size() : 0; return var != 0 ? var->size() : 0;
} }
inline CollectionData *variantToArray(VariantData *var) { inline CollectionData* variantToArray(VariantData* var) {
if (!var) if (!var)
return 0; return 0;
return &var->toArray(); return &var->toArray();
} }
inline CollectionData *variantToObject(VariantData *var) { inline CollectionData* variantToObject(VariantData* var) {
if (!var) if (!var)
return 0; return 0;
return &var->toObject(); return &var->toObject();
} }
inline NO_INLINE VariantData *variantAddElement(VariantData *var, inline VariantData* variantGetElement(const VariantData* var, size_t index) {
MemoryPool *pool) { return var != 0 ? var->getElement(index) : 0;
}
inline NO_INLINE VariantData* variantAddElement(VariantData* var,
MemoryPool* pool) {
return var != 0 ? var->addElement(pool) : 0; return var != 0 ? var->addElement(pool) : 0;
} }
inline NO_INLINE VariantData *variantGetOrAddElement(VariantData *var, inline NO_INLINE VariantData* variantGetOrAddElement(VariantData* var,
size_t index, size_t index,
MemoryPool *pool) { MemoryPool* pool) {
return var != 0 ? var->getOrAddElement(index, pool) : 0; return var != 0 ? var->getOrAddElement(index, pool) : 0;
} }
template <typename TChar> template <typename TAdaptedString>
NO_INLINE VariantData *variantGetOrAddMember(VariantData *var, TChar *key, VariantData* variantGetMember(const VariantData* var, TAdaptedString key) {
MemoryPool *pool) {
if (!var) if (!var)
return 0; return 0;
return var->getOrAddMember(adaptString(key), pool, return var->getMember(key);
getStringStoragePolicy(key));
} }
template <typename TString> template <typename TAdaptedString>
NO_INLINE VariantData *variantGetOrAddMember(VariantData *var, VariantData* variantGetOrAddMember(VariantData* var, TAdaptedString key,
const TString &key, MemoryPool* pool) {
MemoryPool *pool) {
if (!var) if (!var)
return 0; return 0;
return var->getOrAddMember(adaptString(key), pool, return var->getOrAddMember(key, pool);
getStringStoragePolicy(key));
} }
inline bool variantIsNull(const VariantData *var) { inline bool variantIsNull(const VariantData* var) {
return var == 0 || var->isNull(); return var == 0 || var->isNull();
} }
inline size_t variantNesting(const VariantData* var) {
if (!var)
return 0;
const CollectionData* collection = var->asCollection();
if (!collection)
return 0;
size_t maxChildNesting = 0;
for (const VariantSlot* s = collection->head(); s; s = s->next()) {
size_t childNesting = variantNesting(s->data());
if (childNesting > maxChildNesting)
maxChildNesting = childNesting;
}
return maxChildNesting + 1;
}
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -4,12 +4,12 @@
#pragma once #pragma once
#include <ArduinoJson/Array/ArrayRef.hpp> #include <ArduinoJson/Array/JsonArray.hpp>
#include <ArduinoJson/Configuration.hpp> #include <ArduinoJson/Configuration.hpp>
#include <ArduinoJson/Numbers/convertNumber.hpp> #include <ArduinoJson/Numbers/convertNumber.hpp>
#include <ArduinoJson/Numbers/parseNumber.hpp> #include <ArduinoJson/Numbers/parseNumber.hpp>
#include <ArduinoJson/Object/ObjectRef.hpp> #include <ArduinoJson/Object/JsonObject.hpp>
#include <ArduinoJson/Variant/VariantRef.hpp> #include <ArduinoJson/Variant/JsonVariant.hpp>
#include <string.h> // for strcmp #include <string.h> // for strcmp
@@ -70,29 +70,28 @@ inline T VariantData::asFloat() const {
} }
} }
inline String VariantData::asString() const { inline JsonString VariantData::asString() const {
switch (type()) { switch (type()) {
case VALUE_IS_LINKED_STRING: case VALUE_IS_LINKED_STRING:
return String(_content.asString.data, _content.asString.size, return JsonString(_content.asString.data, _content.asString.size,
String::Linked); JsonString::Linked);
case VALUE_IS_OWNED_STRING: case VALUE_IS_OWNED_STRING:
return String(_content.asString.data, _content.asString.size, return JsonString(_content.asString.data, _content.asString.size,
String::Copied); JsonString::Copied);
default: default:
return String(); return JsonString();
} }
} }
inline bool VariantData::copyFrom(const VariantData &src, MemoryPool *pool) { inline bool VariantData::copyFrom(const VariantData& src, MemoryPool* pool) {
switch (src.type()) { switch (src.type()) {
case VALUE_IS_ARRAY: case VALUE_IS_ARRAY:
return toArray().copyFrom(src._content.asCollection, pool); return toArray().copyFrom(src._content.asCollection, pool);
case VALUE_IS_OBJECT: case VALUE_IS_OBJECT:
return toObject().copyFrom(src._content.asCollection, pool); return toObject().copyFrom(src._content.asCollection, pool);
case VALUE_IS_OWNED_STRING: { case VALUE_IS_OWNED_STRING: {
String value = src.asString(); JsonString value = src.asString();
return storeString(adaptString(value), pool, return setString(adaptString(value), pool);
getStringStoragePolicy(value));
} }
case VALUE_IS_OWNED_RAW: case VALUE_IS_OWNED_RAW:
return storeOwnedRaw( return storeOwnedRaw(
@@ -105,80 +104,48 @@ inline bool VariantData::copyFrom(const VariantData &src, MemoryPool *pool) {
} }
} }
template <typename T> template <typename TDerived>
inline typename enable_if<is_same<T, ArrayRef>::value, ArrayRef>::type inline JsonVariant VariantRefBase<TDerived>::add() const {
VariantRef::to() const { return JsonVariant(getPool(),
return ArrayRef(_pool, variantToArray(_data)); variantAddElement(getOrCreateData(), getPool()));
} }
template <typename T> template <typename TDerived>
typename enable_if<is_same<T, ObjectRef>::value, ObjectRef>::type inline JsonVariant VariantRefBase<TDerived>::getVariant() const {
VariantRef::to() const { return JsonVariant(getPool(), getData());
return ObjectRef(_pool, variantToObject(_data));
} }
template <typename TDerived>
inline JsonVariant VariantRefBase<TDerived>::getOrCreateVariant() const {
return JsonVariant(getPool(), getOrCreateData());
}
template <typename TDerived>
template <typename T> template <typename T>
typename enable_if<is_same<T, VariantRef>::value, VariantRef>::type inline typename enable_if<is_same<T, JsonArray>::value, JsonArray>::type
VariantRef::to() const { VariantRefBase<TDerived>::to() const {
variantSetNull(_data); return JsonArray(getPool(), variantToArray(getOrCreateData()));
}
template <typename TDerived>
template <typename T>
typename enable_if<is_same<T, JsonObject>::value, JsonObject>::type
VariantRefBase<TDerived>::to() const {
return JsonObject(getPool(), variantToObject(getOrCreateData()));
}
template <typename TDerived>
template <typename T>
typename enable_if<is_same<T, JsonVariant>::value, JsonVariant>::type
VariantRefBase<TDerived>::to() const {
variantSetNull(getOrCreateData());
return *this; return *this;
} }
inline VariantConstRef VariantConstRef::getElement(size_t index) const { template <typename TDerived>
return ArrayConstRef(_data != 0 ? _data->asArray() : 0)[index]; inline void convertToJson(const VariantRefBase<TDerived>& src,
} JsonVariant dst) {
dst.set(src.template as<JsonVariantConst>());
inline VariantRef VariantRef::addElement() const {
return VariantRef(_pool, variantAddElement(_data, _pool));
}
inline VariantRef VariantRef::getElement(size_t index) const {
return VariantRef(_pool, _data != 0 ? _data->getElement(index) : 0);
}
inline VariantRef VariantRef::getOrAddElement(size_t index) const {
return VariantRef(_pool, variantGetOrAddElement(_data, index, _pool));
}
template <typename TChar>
inline VariantRef VariantRef::getMember(TChar *key) const {
return VariantRef(_pool, _data != 0 ? _data->getMember(adaptString(key)) : 0);
}
template <typename TString>
inline typename enable_if<IsString<TString>::value, VariantRef>::type
VariantRef::getMember(const TString &key) const {
return VariantRef(_pool, _data != 0 ? _data->getMember(adaptString(key)) : 0);
}
template <typename TChar>
inline VariantRef VariantRef::getOrAddMember(TChar *key) const {
return VariantRef(_pool, variantGetOrAddMember(_data, key, _pool));
}
template <typename TString>
inline VariantRef VariantRef::getOrAddMember(const TString &key) const {
return VariantRef(_pool, variantGetOrAddMember(_data, key, _pool));
}
inline VariantConstRef operator|(VariantConstRef preferedValue,
VariantConstRef defaultValue) {
return preferedValue ? preferedValue : defaultValue;
}
// Out of class definition to avoid #1560
inline bool VariantRef::set(char value) const {
return set(static_cast<signed char>(value));
}
// TODO: move somewhere else
template <typename TAdaptedString, typename TCallback>
bool CopyStringStoragePolicy::store(TAdaptedString str, MemoryPool *pool,
TCallback callback) {
const char *copy = pool->saveString(str);
String storedString(copy, str.size(), String::Copied);
callback(storedString);
return copy != 0;
} }
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -4,7 +4,6 @@
#pragma once #pragma once
#include <ArduinoJson/Misc/Visitable.hpp>
#include <ArduinoJson/Numbers/arithmeticCompare.hpp> #include <ArduinoJson/Numbers/arithmeticCompare.hpp>
#include <ArduinoJson/Polyfills/attributes.hpp> #include <ArduinoJson/Polyfills/attributes.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp>
@@ -12,12 +11,17 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename T1, typename T2> class JsonVariantConst;
CompareResult compare(const T1 &lhs, const T2 &rhs); // VariantCompare.cpp
template <typename T>
CompareResult compare(JsonVariantConst lhs,
const T& rhs); // VariantCompare.cpp
struct VariantOperatorTag {};
template <typename TVariant> template <typename TVariant>
struct VariantOperators { struct VariantOperators : VariantOperatorTag {
// Returns the default value if the VariantRef is unbound or incompatible // Returns the default value if the JsonVariant is unbound or incompatible
// //
// int operator|(JsonVariant, int) // int operator|(JsonVariant, int)
// float operator|(JsonVariant, float) // float operator|(JsonVariant, float)
@@ -25,7 +29,7 @@ struct VariantOperators {
template <typename T> template <typename T>
friend friend
typename enable_if<!IsVariant<T>::value && !is_array<T>::value, T>::type typename enable_if<!IsVariant<T>::value && !is_array<T>::value, T>::type
operator|(const TVariant &variant, const T &defaultValue) { operator|(const TVariant& variant, const T& defaultValue) {
if (variant.template is<T>()) if (variant.template is<T>())
return variant.template as<T>(); return variant.template as<T>();
else else
@@ -33,18 +37,18 @@ struct VariantOperators {
} }
// //
// const char* operator|(JsonVariant, const char*) // const char* operator|(JsonVariant, const char*)
friend const char *operator|(const TVariant &variant, friend const char* operator|(const TVariant& variant,
const char *defaultValue) { const char* defaultValue) {
if (variant.template is<const char *>()) if (variant.template is<const char*>())
return variant.template as<const char *>(); return variant.template as<const char*>();
else else
return defaultValue; return defaultValue;
} }
// //
// JsonVariant operator|(JsonVariant, JsonVariant) // JsonVariant operator|(JsonVariant, JsonVariant)
template <typename T> template <typename T>
friend typename enable_if<IsVariant<T>::value, typename T::variant_type>::type friend typename enable_if<IsVariant<T>::value, JsonVariantConst>::type
operator|(const TVariant &variant, T defaultValue) { operator|(const TVariant& variant, T defaultValue) {
if (variant) if (variant)
return variant; return variant;
else else
@@ -53,127 +57,133 @@ struct VariantOperators {
// value == TVariant // value == TVariant
template <typename T> template <typename T>
friend bool operator==(T *lhs, TVariant rhs) { friend bool operator==(T* lhs, TVariant rhs) {
return compare(rhs, lhs) == COMPARE_RESULT_EQUAL; return compare(rhs, lhs) == COMPARE_RESULT_EQUAL;
} }
template <typename T> template <typename T>
friend bool operator==(const T &lhs, TVariant rhs) { friend bool operator==(const T& lhs, TVariant rhs) {
return compare(rhs, lhs) == COMPARE_RESULT_EQUAL; return compare(rhs, lhs) == COMPARE_RESULT_EQUAL;
} }
// TVariant == value // TVariant == value
template <typename T> template <typename T>
friend bool operator==(TVariant lhs, T *rhs) { friend bool operator==(TVariant lhs, T* rhs) {
return compare(lhs, rhs) == COMPARE_RESULT_EQUAL; return compare(lhs, rhs) == COMPARE_RESULT_EQUAL;
} }
template <typename T> template <typename T>
friend typename enable_if<!IsVisitable<T>::value, bool>::type operator==( friend
TVariant lhs, const T &rhs) { typename enable_if<!is_base_of<VariantOperatorTag, T>::value, bool>::type
operator==(TVariant lhs, const T& rhs) {
return compare(lhs, rhs) == COMPARE_RESULT_EQUAL; return compare(lhs, rhs) == COMPARE_RESULT_EQUAL;
} }
// value != TVariant // value != TVariant
template <typename T> template <typename T>
friend bool operator!=(T *lhs, TVariant rhs) { friend bool operator!=(T* lhs, TVariant rhs) {
return compare(rhs, lhs) != COMPARE_RESULT_EQUAL; return compare(rhs, lhs) != COMPARE_RESULT_EQUAL;
} }
template <typename T> template <typename T>
friend bool operator!=(const T &lhs, TVariant rhs) { friend bool operator!=(const T& lhs, TVariant rhs) {
return compare(rhs, lhs) != COMPARE_RESULT_EQUAL; return compare(rhs, lhs) != COMPARE_RESULT_EQUAL;
} }
// TVariant != value // TVariant != value
template <typename T> template <typename T>
friend bool operator!=(TVariant lhs, T *rhs) { friend bool operator!=(TVariant lhs, T* rhs) {
return compare(lhs, rhs) != COMPARE_RESULT_EQUAL; return compare(lhs, rhs) != COMPARE_RESULT_EQUAL;
} }
template <typename T> template <typename T>
friend typename enable_if<!IsVisitable<T>::value, bool>::type operator!=( friend
TVariant lhs, const T &rhs) { typename enable_if<!is_base_of<VariantOperatorTag, T>::value, bool>::type
operator!=(TVariant lhs, const T& rhs) {
return compare(lhs, rhs) != COMPARE_RESULT_EQUAL; return compare(lhs, rhs) != COMPARE_RESULT_EQUAL;
} }
// value < TVariant // value < TVariant
template <typename T> template <typename T>
friend bool operator<(T *lhs, TVariant rhs) { friend bool operator<(T* lhs, TVariant rhs) {
return compare(rhs, lhs) == COMPARE_RESULT_GREATER; return compare(rhs, lhs) == COMPARE_RESULT_GREATER;
} }
template <typename T> template <typename T>
friend bool operator<(const T &lhs, TVariant rhs) { friend bool operator<(const T& lhs, TVariant rhs) {
return compare(rhs, lhs) == COMPARE_RESULT_GREATER; return compare(rhs, lhs) == COMPARE_RESULT_GREATER;
} }
// TVariant < value // TVariant < value
template <typename T> template <typename T>
friend bool operator<(TVariant lhs, T *rhs) { friend bool operator<(TVariant lhs, T* rhs) {
return compare(lhs, rhs) == COMPARE_RESULT_LESS; return compare(lhs, rhs) == COMPARE_RESULT_LESS;
} }
template <typename T> template <typename T>
friend typename enable_if<!IsVisitable<T>::value, bool>::type operator<( friend
TVariant lhs, const T &rhs) { typename enable_if<!is_base_of<VariantOperatorTag, T>::value, bool>::type
operator<(TVariant lhs, const T& rhs) {
return compare(lhs, rhs) == COMPARE_RESULT_LESS; return compare(lhs, rhs) == COMPARE_RESULT_LESS;
} }
// value <= TVariant // value <= TVariant
template <typename T> template <typename T>
friend bool operator<=(T *lhs, TVariant rhs) { friend bool operator<=(T* lhs, TVariant rhs) {
return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0;
} }
template <typename T> template <typename T>
friend bool operator<=(const T &lhs, TVariant rhs) { friend bool operator<=(const T& lhs, TVariant rhs) {
return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0;
} }
// TVariant <= value // TVariant <= value
template <typename T> template <typename T>
friend bool operator<=(TVariant lhs, T *rhs) { friend bool operator<=(TVariant lhs, T* rhs) {
return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0;
} }
template <typename T> template <typename T>
friend typename enable_if<!IsVisitable<T>::value, bool>::type operator<=( friend
TVariant lhs, const T &rhs) { typename enable_if<!is_base_of<VariantOperatorTag, T>::value, bool>::type
operator<=(TVariant lhs, const T& rhs) {
return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0;
} }
// value > TVariant // value > TVariant
template <typename T> template <typename T>
friend bool operator>(T *lhs, TVariant rhs) { friend bool operator>(T* lhs, TVariant rhs) {
return compare(rhs, lhs) == COMPARE_RESULT_LESS; return compare(rhs, lhs) == COMPARE_RESULT_LESS;
} }
template <typename T> template <typename T>
friend bool operator>(const T &lhs, TVariant rhs) { friend bool operator>(const T& lhs, TVariant rhs) {
return compare(rhs, lhs) == COMPARE_RESULT_LESS; return compare(rhs, lhs) == COMPARE_RESULT_LESS;
} }
// TVariant > value // TVariant > value
template <typename T> template <typename T>
friend bool operator>(TVariant lhs, T *rhs) { friend bool operator>(TVariant lhs, T* rhs) {
return compare(lhs, rhs) == COMPARE_RESULT_GREATER; return compare(lhs, rhs) == COMPARE_RESULT_GREATER;
} }
template <typename T> template <typename T>
friend typename enable_if<!IsVisitable<T>::value, bool>::type operator>( friend
TVariant lhs, const T &rhs) { typename enable_if<!is_base_of<VariantOperatorTag, T>::value, bool>::type
operator>(TVariant lhs, const T& rhs) {
return compare(lhs, rhs) == COMPARE_RESULT_GREATER; return compare(lhs, rhs) == COMPARE_RESULT_GREATER;
} }
// value >= TVariant // value >= TVariant
template <typename T> template <typename T>
friend bool operator>=(T *lhs, TVariant rhs) { friend bool operator>=(T* lhs, TVariant rhs) {
return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0;
} }
template <typename T> template <typename T>
friend bool operator>=(const T &lhs, TVariant rhs) { friend bool operator>=(const T& lhs, TVariant rhs) {
return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0;
} }
// TVariant >= value // TVariant >= value
template <typename T> template <typename T>
friend bool operator>=(TVariant lhs, T *rhs) { friend bool operator>=(TVariant lhs, T* rhs) {
return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0;
} }
template <typename T> template <typename T>
friend typename enable_if<!IsVisitable<T>::value, bool>::type operator>=( friend
TVariant lhs, const T &rhs) { typename enable_if<!is_base_of<VariantOperatorTag, T>::value, bool>::type
operator>=(TVariant lhs, const T& rhs) {
return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0;
} }
}; };

View File

@@ -1,381 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <stddef.h>
#include <stdint.h> // for uint8_t
#include <ArduinoJson/Memory/MemoryPool.hpp>
#include <ArduinoJson/Misc/Visitable.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp>
#include <ArduinoJson/Variant/Converter.hpp>
#include <ArduinoJson/Variant/VariantFunctions.hpp>
#include <ArduinoJson/Variant/VariantOperators.hpp>
#include <ArduinoJson/Variant/VariantRef.hpp>
#include <ArduinoJson/Variant/VariantShortcuts.hpp>
#include <ArduinoJson/Variant/VariantTag.hpp>
namespace ARDUINOJSON_NAMESPACE {
// Forward declarations.
class ArrayRef;
class ObjectRef;
// Contains the methods shared by VariantRef and VariantConstRef
template <typename TData>
class VariantRefBase : public VariantTag {
public:
FORCE_INLINE bool isNull() const {
return variantIsNull(_data);
}
FORCE_INLINE bool isUnbound() const {
return !_data;
}
FORCE_INLINE size_t memoryUsage() const {
return _data ? _data->memoryUsage() : 0;
}
FORCE_INLINE size_t nesting() const {
return _data ? _data->nesting() : 0;
}
size_t size() const {
return variantSize(_data);
}
protected:
VariantRefBase(TData *data) : _data(data) {}
TData *_data;
friend TData *getData(const VariantRefBase &variant) {
return variant._data;
}
};
// A variant that can be a any value serializable to a JSON value.
//
// It can be set to:
// - a boolean
// - a char, short, int or a long (signed or unsigned)
// - a string (const char*)
// - a reference to a ArrayRef or ObjectRef
class VariantRef : public VariantRefBase<VariantData>,
public VariantOperators<VariantRef>,
public VariantShortcuts<VariantRef>,
public Visitable {
typedef VariantRefBase<VariantData> base_type;
friend class VariantConstRef;
public:
// Intenal use only
FORCE_INLINE VariantRef(MemoryPool *pool, VariantData *data)
: base_type(data), _pool(pool) {}
// Creates an uninitialized VariantRef
FORCE_INLINE VariantRef() : base_type(0), _pool(0) {}
FORCE_INLINE void clear() const {
return variantSetNull(_data);
}
template <typename T>
FORCE_INLINE bool set(const T &value) const {
Converter<T>::toJson(value, *this);
return _pool && !_pool->overflowed();
}
bool ARDUINOJSON_DEPRECATED(
"Support for char is deprecated, use int8_t or uint8_t instead")
set(char value) const;
template <typename T>
FORCE_INLINE bool set(T *value) const {
Converter<T *>::toJson(value, *this);
return _pool && !_pool->overflowed();
}
template <typename T>
FORCE_INLINE
typename enable_if<!is_same<T, char *>::value && !is_same<T, char>::value,
T>::type
as() const {
return Converter<T>::fromJson(*this);
}
template <typename T>
FORCE_INLINE typename enable_if<is_same<T, char *>::value, const char *>::type
ARDUINOJSON_DEPRECATED("Replace as<char*>() with as<const char*>()")
as() const {
return as<const char *>();
}
template <typename T>
FORCE_INLINE typename enable_if<is_same<T, char>::value, char>::type
ARDUINOJSON_DEPRECATED(
"Support for char is deprecated, use int8_t or uint8_t instead")
as() const {
return static_cast<char>(as<signed char>());
}
template <typename T>
FORCE_INLINE
typename enable_if<!is_same<T, char *>::value && !is_same<T, char>::value,
bool>::type
is() const {
return Converter<T>::checkJson(*this);
}
template <typename T>
FORCE_INLINE typename enable_if<is_same<T, char *>::value, bool>::type
ARDUINOJSON_DEPRECATED("Replace is<char*>() with is<const char*>()")
is() const {
return is<const char *>();
}
template <typename T>
FORCE_INLINE typename enable_if<is_same<T, char>::value, bool>::type
ARDUINOJSON_DEPRECATED(
"Support for char is deprecated, use int8_t or uint8_t instead")
is() const {
return is<signed char>();
}
template <typename T>
FORCE_INLINE operator T() const {
return as<T>();
}
template <typename TVisitor>
typename TVisitor::result_type accept(TVisitor &visitor) const {
return variantAccept(_data, visitor);
}
// Change the type of the variant
//
// ArrayRef to<ArrayRef>()
template <typename T>
typename enable_if<is_same<T, ArrayRef>::value, ArrayRef>::type to() const;
//
// ObjectRef to<ObjectRef>()
template <typename T>
typename enable_if<is_same<T, ObjectRef>::value, ObjectRef>::type to() const;
//
// ObjectRef to<VariantRef>()
template <typename T>
typename enable_if<is_same<T, VariantRef>::value, VariantRef>::type to()
const;
VariantRef addElement() const;
FORCE_INLINE VariantRef getElement(size_t) const;
FORCE_INLINE VariantRef getOrAddElement(size_t) const;
// getMember(const char*) const
// getMember(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE VariantRef getMember(TChar *) const;
// getMember(const std::string&) const
// getMember(const String&) const
template <typename TString>
FORCE_INLINE typename enable_if<IsString<TString>::value, VariantRef>::type
getMember(const TString &) const;
// getOrAddMember(char*) const
// getOrAddMember(const char*) const
// getOrAddMember(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE VariantRef getOrAddMember(TChar *) const;
// getOrAddMember(const std::string&) const
// getOrAddMember(const String&) const
template <typename TString>
FORCE_INLINE VariantRef getOrAddMember(const TString &) const;
FORCE_INLINE void remove(size_t index) const {
if (_data)
_data->remove(index);
}
// remove(char*) const
// remove(const char*) const
// remove(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE typename enable_if<IsString<TChar *>::value>::type remove(
TChar *key) const {
if (_data)
_data->remove(adaptString(key));
}
// remove(const std::string&) const
// remove(const String&) const
template <typename TString>
FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove(
const TString &key) const {
if (_data)
_data->remove(adaptString(key));
}
private:
MemoryPool *_pool;
friend MemoryPool *getPool(const VariantRef &variant) {
return variant._pool;
}
};
class VariantConstRef : public VariantRefBase<const VariantData>,
public VariantOperators<VariantConstRef>,
public VariantShortcuts<VariantConstRef>,
public Visitable {
typedef VariantRefBase<const VariantData> base_type;
friend class VariantRef;
public:
VariantConstRef() : base_type(0) {}
VariantConstRef(const VariantData *data) : base_type(data) {}
VariantConstRef(VariantRef var) : base_type(var._data) {}
template <typename TVisitor>
typename TVisitor::result_type accept(TVisitor &visitor) const {
return variantAccept(_data, visitor);
}
template <typename T>
FORCE_INLINE
typename enable_if<!is_same<T, char *>::value && !is_same<T, char>::value,
T>::type
as() const {
return Converter<T>::fromJson(*this);
}
template <typename T>
FORCE_INLINE typename enable_if<is_same<T, char *>::value, const char *>::type
ARDUINOJSON_DEPRECATED("Replace as<char*>() with as<const char*>()")
as() const {
return as<const char *>();
}
template <typename T>
FORCE_INLINE typename enable_if<is_same<T, char>::value, char>::type
ARDUINOJSON_DEPRECATED(
"Support for char is deprecated, use int8_t or uint8_t instead")
as() const {
return static_cast<char>(as<signed char>());
}
template <typename T>
FORCE_INLINE
typename enable_if<!is_same<T, char *>::value && !is_same<T, char>::value,
bool>::type
is() const {
return Converter<T>::checkJson(*this);
}
template <typename T>
FORCE_INLINE typename enable_if<is_same<T, char *>::value, bool>::type
ARDUINOJSON_DEPRECATED("Replace is<char*>() with is<const char*>()")
is() const {
return is<const char *>();
}
template <typename T>
FORCE_INLINE typename enable_if<is_same<T, char>::value, bool>::type
ARDUINOJSON_DEPRECATED(
"Support for char is deprecated, use int8_t or uint8_t instead")
is() const {
return is<signed char>();
}
template <typename T>
FORCE_INLINE operator T() const {
return as<T>();
}
FORCE_INLINE VariantConstRef getElement(size_t) const;
FORCE_INLINE VariantConstRef operator[](size_t index) const {
return getElement(index);
}
// getMember(const std::string&) const
// getMember(const String&) const
template <typename TString>
FORCE_INLINE VariantConstRef getMember(const TString &key) const {
return VariantConstRef(
objectGetMember(variantAsObject(_data), adaptString(key)));
}
// getMember(char*) const
// getMember(const char*) const
// getMember(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE VariantConstRef getMember(TChar *key) const {
const CollectionData *obj = variantAsObject(_data);
return VariantConstRef(obj ? obj->getMember(adaptString(key)) : 0);
}
// operator[](const std::string&) const
// operator[](const String&) const
template <typename TString>
FORCE_INLINE
typename enable_if<IsString<TString>::value, VariantConstRef>::type
operator[](const TString &key) const {
return getMember(key);
}
// operator[](char*) const
// operator[](const char*) const
// operator[](const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE
typename enable_if<IsString<TChar *>::value, VariantConstRef>::type
operator[](TChar *key) const {
return getMember(key);
}
};
template <>
struct Converter<VariantRef> {
static void toJson(VariantRef src, VariantRef dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static VariantRef fromJson(VariantRef src) {
return src;
}
static InvalidConversion<VariantConstRef, VariantRef> fromJson(
VariantConstRef);
static bool checkJson(VariantRef src) {
VariantData *data = getData(src);
return !!data;
}
static bool checkJson(VariantConstRef) {
return false;
}
};
template <>
struct Converter<VariantConstRef> {
static void toJson(VariantConstRef src, VariantRef dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static VariantConstRef fromJson(VariantConstRef src) {
return VariantConstRef(getData(src));
}
static bool checkJson(VariantConstRef src) {
const VariantData *data = getData(src);
return !!data;
}
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -0,0 +1,299 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Configuration.hpp>
#include <ArduinoJson/Variant/Converter.hpp>
#include <ArduinoJson/Variant/JsonVariantConst.hpp>
#include <ArduinoJson/Variant/VariantOperators.hpp>
#include <ArduinoJson/Variant/VariantTo.hpp>
namespace ARDUINOJSON_NAMESPACE {
class JsonVariant;
template <typename>
class ElementProxy;
template <typename, typename>
class MemberProxy;
template <typename TDerived>
class VariantRefBase : public VariantTag {
friend class VariantAttorney;
public:
// Sets the value to null.
// ⚠️ Doesn't release the memory associated with the previous value.
// https://arduinojson.org/v6/api/jsonvariant/clear/
FORCE_INLINE void clear() const {
variantSetNull(getData());
}
// Returns true if the value is null or the reference is unbound.
// https://arduinojson.org/v6/api/jsonvariant/isnull/
FORCE_INLINE bool isNull() const {
return variantIsNull(getData());
}
// Returns true if the reference is unbound.
FORCE_INLINE bool isUnbound() const {
return !getData();
}
// Casts the value to the specified type.
// https://arduinojson.org/v6/api/jsonvariant/as/
template <typename T>
FORCE_INLINE typename enable_if<!is_same<T, char*>::value &&
!is_same<T, char>::value &&
!ConverterNeedsWriteableRef<T>::value,
T>::type
as() const {
return Converter<T>::fromJson(getVariantConst());
}
// Casts the value to the specified type.
// https://arduinojson.org/v6/api/jsonvariant/as/
template <typename T>
FORCE_INLINE typename enable_if<ConverterNeedsWriteableRef<T>::value, T>::type
as() const {
return Converter<T>::fromJson(getVariant());
}
template <typename T>
FORCE_INLINE operator T() const {
return as<T>();
}
// Sets the value to an empty array.
// ⚠️ Doesn't release the memory associated with the previous value.
// https://arduinojson.org/v6/api/jsonvariant/to/
template <typename T>
typename enable_if<is_same<T, JsonArray>::value, JsonArray>::type to() const;
// Sets the value to an empty object.
// ⚠️ Doesn't release the memory associated with the previous value.
// https://arduinojson.org/v6/api/jsonvariant/to/
template <typename T>
typename enable_if<is_same<T, JsonObject>::value, JsonObject>::type to()
const;
// Sets the value to null.
// ⚠️ Doesn't release the memory associated with the previous value.
// https://arduinojson.org/v6/api/jsonvariant/to/
template <typename T>
typename enable_if<is_same<T, JsonVariant>::value, JsonVariant>::type to()
const;
// Returns true if the value is of the specified type.
// https://arduinojson.org/v6/api/jsonvariant/is/
template <typename T>
FORCE_INLINE
typename enable_if<ConverterNeedsWriteableRef<T>::value, bool>::type
is() const {
return Converter<T>::checkJson(getVariant());
}
// Returns true if the value is of the specified type.
// https://arduinojson.org/v6/api/jsonvariant/is/
template <typename T>
FORCE_INLINE typename enable_if<!ConverterNeedsWriteableRef<T>::value &&
!is_same<T, char*>::value &&
!is_same<T, char>::value,
bool>::type
is() const {
return Converter<T>::checkJson(getVariantConst());
}
// Shallow copies the specified value.
// https://arduinojson.org/v6/api/jsonvariant/shallowcopy/
FORCE_INLINE void shallowCopy(JsonVariantConst target) {
VariantData* data = getOrCreateData();
if (!data)
return;
const VariantData* targetData = VariantAttorney::getData(target);
if (targetData)
*data = *targetData;
else
data->setNull();
}
// Copies the specified value.
// https://arduinojson.org/v6/api/jsonvariant/set/
template <typename T>
FORCE_INLINE bool set(const T& value) const {
Converter<T>::toJson(value, getOrCreateVariant());
MemoryPool* pool = getPool();
return pool && !pool->overflowed();
}
// Copies the specified value.
// https://arduinojson.org/v6/api/jsonvariant/set/
template <typename T>
FORCE_INLINE bool set(T* value) const {
Converter<T*>::toJson(value, getOrCreateVariant());
MemoryPool* pool = getPool();
return pool && !pool->overflowed();
}
// Returns the size of the array or object.
// https://arduinojson.org/v6/api/jsonvariant/size/
FORCE_INLINE size_t size() const {
return variantSize(getData());
}
// Returns the number of bytes occupied by the value.
// https://arduinojson.org/v6/api/jsonvariant/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
VariantData* data = getData();
return data ? data->memoryUsage() : 0;
}
// Returns the depth (nesting level) of the value.
// https://arduinojson.org/v6/api/jsonvariant/nesting/
FORCE_INLINE size_t nesting() const {
return variantNesting(getData());
}
// Appends a new (null) element to the array.
// Returns a reference to the new element.
// https://arduinojson.org/v6/api/jsonvariant/add/
FORCE_INLINE JsonVariant add() const;
// Appends a value to the array.
// https://arduinojson.org/v6/api/jsonvariant/add/
template <typename T>
FORCE_INLINE bool add(const T& value) const {
return add().set(value);
}
// Appends a value to the array.
// https://arduinojson.org/v6/api/jsonvariant/add/
template <typename T>
FORCE_INLINE bool add(T* value) const {
return add().set(value);
}
// Removes an element of the array.
// ⚠️ Doesn't release the memory associated with the removed element.
// https://arduinojson.org/v6/api/jsonvariant/remove/
FORCE_INLINE void remove(size_t index) const {
VariantData* data = getData();
if (data)
data->remove(index);
}
// Removes a member of the object.
// ⚠️ Doesn't release the memory associated with the removed element.
// https://arduinojson.org/v6/api/jsonvariant/remove/
template <typename TChar>
FORCE_INLINE typename enable_if<IsString<TChar*>::value>::type remove(
TChar* key) const {
VariantData* data = getData();
if (data)
data->remove(adaptString(key));
}
// Removes a member of the object.
// ⚠️ Doesn't release the memory associated with the removed element.
// https://arduinojson.org/v6/api/jsonvariant/remove/
template <typename TString>
FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove(
const TString& key) const {
VariantData* data = getData();
if (data)
data->remove(adaptString(key));
}
// Creates an array and appends it to the array.
// https://arduinojson.org/v6/api/jsonvariant/createnestedarray/
FORCE_INLINE JsonArray createNestedArray() const;
// Creates an object and appends it to the array.
// https://arduinojson.org/v6/api/jsonvariant/createnestedobject/
FORCE_INLINE JsonObject createNestedObject() const;
// Gets or sets an array element.
// https://arduinojson.org/v6/api/jsonvariant/subscript/
FORCE_INLINE ElementProxy<TDerived> operator[](size_t index) const;
// Returns true if the object contains the specified key.
// https://arduinojson.org/v6/api/jsonvariant/containskey/
template <typename TString>
FORCE_INLINE typename enable_if<IsString<TString>::value, bool>::type
containsKey(const TString& key) const;
// Returns true if the object contains the specified key.
// https://arduinojson.org/v6/api/jsonvariant/containskey/
template <typename TChar>
FORCE_INLINE typename enable_if<IsString<TChar*>::value, bool>::type
containsKey(TChar* key) const;
// Gets or sets an object member.
// https://arduinojson.org/v6/api/jsonvariant/subscript/
template <typename TString>
FORCE_INLINE typename enable_if<IsString<TString>::value,
MemberProxy<TDerived, TString> >::type
operator[](const TString& key) const;
// Gets or sets an object member.
// https://arduinojson.org/v6/api/jsonvariant/subscript/
template <typename TChar>
FORCE_INLINE typename enable_if<IsString<TChar*>::value,
MemberProxy<TDerived, TChar*> >::type
operator[](TChar* key) const;
// Creates an array and adds it to the object.
// https://arduinojson.org/v6/api/jsonvariant/createnestedarray/
template <typename TString>
FORCE_INLINE JsonArray createNestedArray(const TString& key) const;
// Creates an array and adds it to the object.
// https://arduinojson.org/v6/api/jsonvariant/createnestedarray/
template <typename TChar>
FORCE_INLINE JsonArray createNestedArray(TChar* key) const;
// Creates an object and adds it to the object.
// https://arduinojson.org/v6/api/jsonvariant/createnestedobject/
template <typename TString>
JsonObject createNestedObject(const TString& key) const;
// Creates an object and adds it to the object.
// https://arduinojson.org/v6/api/jsonvariant/createnestedobject/
template <typename TChar>
JsonObject createNestedObject(TChar* key) const;
private:
TDerived& derived() {
return static_cast<TDerived&>(*this);
}
const TDerived& derived() const {
return static_cast<const TDerived&>(*this);
}
FORCE_INLINE MemoryPool* getPool() const {
return VariantAttorney::getPool(derived());
}
FORCE_INLINE VariantData* getData() const {
return VariantAttorney::getData(derived());
}
FORCE_INLINE VariantData* getOrCreateData() const {
return VariantAttorney::getOrCreateData(derived());
}
private:
FORCE_INLINE JsonVariant getVariant() const;
FORCE_INLINE JsonVariantConst getVariantConst() const {
return JsonVariantConst(getData());
}
FORCE_INLINE JsonVariant getOrCreateVariant() const;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -1,23 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/ArrayShortcuts.hpp>
#include <ArduinoJson/Object/ObjectShortcuts.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename TVariant>
class VariantShortcuts : public ObjectShortcuts<TVariant>,
public ArrayShortcuts<TVariant> {
public:
using ArrayShortcuts<TVariant>::createNestedArray;
using ArrayShortcuts<TVariant>::createNestedObject;
using ArrayShortcuts<TVariant>::operator[];
using ObjectShortcuts<TVariant>::createNestedArray;
using ObjectShortcuts<TVariant>::createNestedObject;
using ObjectShortcuts<TVariant>::operator[];
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -76,7 +76,7 @@ class VariantSlot {
_next = VariantSlotDiff(slot - this); _next = VariantSlotDiff(slot - this);
} }
void setKey(String k) { void setKey(JsonString k) {
ARDUINOJSON_ASSERT(k); ARDUINOJSON_ASSERT(k);
if (k.isLinked()) if (k.isLinked())
_flags &= VALUE_MASK; _flags &= VALUE_MASK;

View File

@@ -7,26 +7,26 @@
#include <ArduinoJson/Namespace.hpp> #include <ArduinoJson/Namespace.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
class ArrayRef; class JsonArray;
class ObjectRef; class JsonObject;
class VariantRef; class JsonVariant;
// A metafunction that returns the type of the value returned by // A metafunction that returns the type of the value returned by
// VariantRef::to<T>() // JsonVariant::to<T>()
template <typename T> template <typename T>
struct VariantTo {}; struct VariantTo {};
template <> template <>
struct VariantTo<ArrayRef> { struct VariantTo<JsonArray> {
typedef ArrayRef type; typedef JsonArray type;
}; };
template <> template <>
struct VariantTo<ObjectRef> { struct VariantTo<JsonObject> {
typedef ObjectRef type; typedef JsonObject type;
}; };
template <> template <>
struct VariantTo<VariantRef> { struct VariantTo<JsonVariant> {
typedef VariantRef type; typedef JsonVariant type;
}; };
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -5,8 +5,8 @@
#pragma once #pragma once
#include <ArduinoJson/Collection/CollectionData.hpp> #include <ArduinoJson/Collection/CollectionData.hpp>
#include <ArduinoJson/Numbers/Float.hpp> #include <ArduinoJson/Numbers/JsonFloat.hpp>
#include <ArduinoJson/Numbers/Integer.hpp> #include <ArduinoJson/Numbers/JsonInteger.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
@@ -14,7 +14,7 @@ template <typename TResult>
struct Visitor { struct Visitor {
typedef TResult result_type; typedef TResult result_type;
TResult visitArray(const CollectionData &) { TResult visitArray(const CollectionData&) {
return TResult(); return TResult();
} }
@@ -22,11 +22,11 @@ struct Visitor {
return TResult(); return TResult();
} }
TResult visitFloat(Float) { TResult visitFloat(JsonFloat) {
return TResult(); return TResult();
} }
TResult visitSignedInteger(Integer) { TResult visitSignedInteger(JsonInteger) {
return TResult(); return TResult();
} }
@@ -34,19 +34,19 @@ struct Visitor {
return TResult(); return TResult();
} }
TResult visitObject(const CollectionData &) { TResult visitObject(const CollectionData&) {
return TResult(); return TResult();
} }
TResult visitUnsignedInteger(UInt) { TResult visitUnsignedInteger(JsonUInt) {
return TResult(); return TResult();
} }
TResult visitRawJson(const char *, size_t) { TResult visitRawJson(const char*, size_t) {
return TResult(); return TResult();
} }
TResult visitString(const char *, size_t) { TResult visitString(const char*, size_t) {
return TResult(); return TResult();
} }
}; };

View File

@@ -4,7 +4,7 @@
#pragma once #pragma once
#define ARDUINOJSON_VERSION "6.19.4" #define ARDUINOJSON_VERSION "6.20.0"
#define ARDUINOJSON_VERSION_MAJOR 6 #define ARDUINOJSON_VERSION_MAJOR 6
#define ARDUINOJSON_VERSION_MINOR 19 #define ARDUINOJSON_VERSION_MINOR 20
#define ARDUINOJSON_VERSION_REVISION 4 #define ARDUINOJSON_VERSION_REVISION 0