V2.1
This commit is contained in:
@ -1 +1 @@
|
||||
{"type": "library", "name": "ArduinoJson", "version": "6.21.5", "spec": {"owner": "bblanchon", "id": 64, "name": "ArduinoJson", "requirements": null, "uri": null}}
|
||||
{"type": "library", "name": "ArduinoJson", "version": "7.4.2", "spec": {"owner": "bblanchon", "id": 64, "name": "ArduinoJson", "requirements": null, "uri": null}}
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#include "src/ArduinoJson.h"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
The MIT License (MIT)
|
||||
---------------------
|
||||
|
||||
Copyright © 2014-2023, Benoit BLANCHON
|
||||
Copyright © 2014-2025, Benoit BLANCHON
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
|
||||
@ -4,13 +4,10 @@
|
||||
|
||||
---
|
||||
|
||||
[](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A6.x)
|
||||
[](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x)
|
||||
[](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A7.x)
|
||||
[](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/7.x)
|
||||
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
|
||||
[](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x)
|
||||
[](https://www.ardu-badge.com/ArduinoJson/6.21.5)
|
||||
[](https://registry.platformio.org/packages/libraries/bblanchon/ArduinoJson?version=6.21.5)
|
||||
[](https://components.espressif.com/components/bblanchon/arduinojson)
|
||||
[](https://coveralls.io/github/bblanchon/ArduinoJson?branch=7.x)
|
||||
[](https://github.com/bblanchon/ArduinoJson/stargazers)
|
||||
[](https://github.com/sponsors/bblanchon)
|
||||
|
||||
@ -18,31 +15,28 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
|
||||
|
||||
## Features
|
||||
|
||||
* [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/)
|
||||
* [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/)
|
||||
* [Optionally filters the input to keep only desired values](https://arduinojson.org/v6/api/json/deserializejson/#filtering)
|
||||
* [JSON deserialization](https://arduinojson.org/v7/api/json/deserializejson/)
|
||||
* [Optionally decodes UTF-16 escape sequences to UTF-8](https://arduinojson.org/v7/api/config/decode_unicode/)
|
||||
* [Optionally supports comments in the input](https://arduinojson.org/v7/api/config/enable_comments/)
|
||||
* [Optionally filters the input to keep only desired values](https://arduinojson.org/v7/api/json/deserializejson/#filtering)
|
||||
* Supports single quotes as a string delimiter
|
||||
* Compatible with [NDJSON](http://ndjson.org/) and [JSON Lines](https://jsonlines.org/)
|
||||
* [JSON serialization](https://arduinojson.org/v6/api/json/serializejson/)
|
||||
* [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/)
|
||||
* [MessagePack serialization](https://arduinojson.org/v6/api/msgpack/serializemsgpack/)
|
||||
* [MessagePack deserialization](https://arduinojson.org/v6/api/msgpack/deserializemsgpack/)
|
||||
* [JSON serialization](https://arduinojson.org/v7/api/json/serializejson/)
|
||||
* [Can write to a buffer or a stream](https://arduinojson.org/v7/api/json/serializejson/)
|
||||
* [Optionally indents the document (prettified JSON)](https://arduinojson.org/v7/api/json/serializejsonpretty/)
|
||||
* [MessagePack serialization](https://arduinojson.org/v7/api/msgpack/serializemsgpack/)
|
||||
* [MessagePack deserialization](https://arduinojson.org/v7/api/msgpack/deserializemsgpack/)
|
||||
* Efficient
|
||||
* [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/)
|
||||
* [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/)
|
||||
* [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/)
|
||||
* Versatile
|
||||
* 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/), [`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/) 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/)
|
||||
* 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 allocators (to use external RAM chip, for example)](https://arduinojson.org/v7/how-to/use-external-ram-on-esp32/)
|
||||
* Supports [`String`](https://arduinojson.org/v7/api/config/enable_arduino_string/), [`std::string`](https://arduinojson.org/v7/api/config/enable_std_string/), and [`std::string_view`](https://arduinojson.org/v7/api/config/enable_string_view/)
|
||||
* Supports [`Stream`](https://arduinojson.org/v7/api/config/enable_arduino_stream/) and [`std::istream`/`std::ostream`](https://arduinojson.org/v7/api/config/enable_std_stream/)
|
||||
* Supports [Flash strings](https://arduinojson.org/v7/api/config/enable_progmem/)
|
||||
* Supports [custom readers](https://arduinojson.org/v7/api/json/deserializejson/#custom-reader) and [custom writers](https://arduinojson.org/v7/api/json/serializejson/#custom-writer)
|
||||
* Supports [custom converters](https://arduinojson.org/news/2021/05/04/version-6-18-0/)
|
||||
* Portable
|
||||
* Usable on any C++ project (not limited to Arduino)
|
||||
@ -72,29 +66,29 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
|
||||
* [Visual Micro](http://www.visualmicro.com/)
|
||||
* [Visual Studio](https://www.visualstudio.com/)
|
||||
* [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/)
|
||||
* [CMake friendly](https://arduinojson.org/v7/how-to/use-arduinojson-with-cmake/)
|
||||
* Well designed
|
||||
* [Elegant API](http://arduinojson.org/v6/example/)
|
||||
* [Elegant API](http://arduinojson.org/v7/example/)
|
||||
* [Thread-safe](https://en.wikipedia.org/wiki/Thread_safety)
|
||||
* Self-contained (no external dependency)
|
||||
* `const` friendly
|
||||
* [`for` friendly](https://arduinojson.org/v6/api/jsonobject/begin_end/)
|
||||
* [`for` friendly](https://arduinojson.org/v7/api/jsonobject/begin_end/)
|
||||
* [TMP friendly](https://en.wikipedia.org/wiki/Template_metaprogramming)
|
||||
* Handles [integer overflows](https://arduinojson.org/v6/api/jsonvariant/as/#integer-overflows)
|
||||
* Handles [integer overflows](https://arduinojson.org/v7/api/jsonvariant/as/#integer-overflows)
|
||||
* 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=7.x)
|
||||
* Continuously tested on
|
||||
* [Visual Studio 2017, 2019, 2022](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x)
|
||||
* [GCC 5, 6, 7, 8, 9, 10, 11](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
|
||||
* [Clang 3.8, 3.9, 4.0, 5.0, 6.0, 7, 8, 9, 10](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
|
||||
* [Visual Studio 2017, 2019, 2022](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/7.x)
|
||||
* [GCC 4.8, 5, 6, 7, 8, 9, 10, 11, 12](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
|
||||
* [Clang 7 to 19](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
|
||||
* [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/)
|
||||
* Well documented
|
||||
* [Tutorials](https://arduinojson.org/v6/doc/deserialization/)
|
||||
* [Examples](https://arduinojson.org/v6/example/)
|
||||
* [How-tos](https://arduinojson.org/v6/example/)
|
||||
* [FAQ](https://arduinojson.org/v6/faq/)
|
||||
* [Troubleshooter](https://arduinojson.org/v6/troubleshooter/)
|
||||
* [Tutorials](https://arduinojson.org/v7/doc/deserialization/)
|
||||
* [Examples](https://arduinojson.org/v7/example/)
|
||||
* [How-tos](https://arduinojson.org/v7/example/)
|
||||
* [FAQ](https://arduinojson.org/v7/faq/)
|
||||
* [Troubleshooter](https://arduinojson.org/v7/troubleshooter/)
|
||||
* [Book](https://arduinojson.org/book/)
|
||||
* [Changelog](CHANGELOG.md)
|
||||
* Vibrant user community
|
||||
@ -109,9 +103,9 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
|
||||
Here is a program that parses a JSON document with ArduinoJson.
|
||||
|
||||
```c++
|
||||
char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
|
||||
const char* json = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
|
||||
|
||||
DynamicJsonDocument doc(1024);
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, json);
|
||||
|
||||
const char* sensor = doc["sensor"];
|
||||
@ -120,14 +114,14 @@ double latitude = doc["data"][0];
|
||||
double longitude = doc["data"][1];
|
||||
```
|
||||
|
||||
See the [tutorial on arduinojson.org](https://arduinojson.org/v6/doc/deserialization/)
|
||||
See the [tutorial on arduinojson.org](https://arduinojson.org/v7/doc/deserialization/)
|
||||
|
||||
### Serialization
|
||||
|
||||
Here is a program that generates a JSON document with ArduinoJson:
|
||||
|
||||
```c++
|
||||
DynamicJsonDocument doc(1024);
|
||||
JsonDocument doc;
|
||||
|
||||
doc["sensor"] = "gps";
|
||||
doc["time"] = 1351824120;
|
||||
@ -139,21 +133,19 @@ serializeJson(doc, Serial);
|
||||
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
|
||||
```
|
||||
|
||||
See the [tutorial on arduinojson.org](https://arduinojson.org/v6/doc/serialization/)
|
||||
See the [tutorial on arduinojson.org](https://arduinojson.org/v7/doc/serialization/)
|
||||
|
||||
## Sponsors
|
||||
|
||||
ArduinoJson is thankful to its sponsors. Please give them a visit; they deserve it!
|
||||
|
||||
<p>
|
||||
<a href="https://www.programmingelectronics.com/" rel="sponsored">
|
||||
<img src="https://arduinojson.org/images/2021/10/programmingeleactronicsacademy.png" alt="Programming Electronics Academy" width="200">
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://github.com/1technophile" rel="sponsored">
|
||||
<img alt="1technophile" src="https://avatars.githubusercontent.com/u/12672732?s=40&v=4">
|
||||
</a>
|
||||
<a href="https://github.com/LArkema" rel="sponsored">
|
||||
<img alt="LArkema" src="https://avatars.githubusercontent.com/u/38381313?s=40&v=4">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
If you run a commercial project that embeds ArduinoJson, think about [sponsoring the library's development](https://github.com/sponsors/bblanchon): it ensures the code that your products rely on stays actively maintained. It can also give your project some exposure to the makers' community.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows how to store your project configuration in a file.
|
||||
@ -17,35 +17,28 @@
|
||||
// * CLK <-> pin 13
|
||||
// * CS <-> pin 4
|
||||
//
|
||||
// https://arduinojson.org/v6/example/config/
|
||||
// https://arduinojson.org/v7/example/config/
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <SD.h>
|
||||
#include <SPI.h>
|
||||
|
||||
// Our configuration structure.
|
||||
//
|
||||
// Never use a JsonDocument to store the configuration!
|
||||
// A JsonDocument is *not* a permanent storage; it's only a temporary storage
|
||||
// used during the serialization phase. See:
|
||||
// https://arduinojson.org/v6/faq/why-must-i-create-a-separate-config-object/
|
||||
struct Config {
|
||||
char hostname[64];
|
||||
int port;
|
||||
};
|
||||
|
||||
const char *filename = "/config.txt"; // <- SD library uses 8.3 filenames
|
||||
const char* filename = "/config.txt"; // <- SD library uses 8.3 filenames
|
||||
Config config; // <- global configuration object
|
||||
|
||||
// Loads the configuration from a file
|
||||
void loadConfiguration(const char *filename, Config &config) {
|
||||
void loadConfiguration(const char* filename, Config& config) {
|
||||
// Open file for reading
|
||||
File file = SD.open(filename);
|
||||
|
||||
// Allocate a temporary JsonDocument
|
||||
// Don't forget to change the capacity to match your requirements.
|
||||
// Use https://arduinojson.org/v6/assistant to compute the capacity.
|
||||
StaticJsonDocument<512> doc;
|
||||
JsonDocument doc;
|
||||
|
||||
// Deserialize the JSON document
|
||||
DeserializationError error = deserializeJson(doc, file);
|
||||
@ -63,7 +56,7 @@ void loadConfiguration(const char *filename, Config &config) {
|
||||
}
|
||||
|
||||
// Saves the configuration to a file
|
||||
void saveConfiguration(const char *filename, const Config &config) {
|
||||
void saveConfiguration(const char* filename, const Config& config) {
|
||||
// Delete existing file, otherwise the configuration is appended to the file
|
||||
SD.remove(filename);
|
||||
|
||||
@ -75,9 +68,7 @@ void saveConfiguration(const char *filename, const Config &config) {
|
||||
}
|
||||
|
||||
// Allocate a temporary JsonDocument
|
||||
// Don't forget to change the capacity to match your requirements.
|
||||
// Use https://arduinojson.org/assistant to compute the capacity.
|
||||
StaticJsonDocument<256> doc;
|
||||
JsonDocument doc;
|
||||
|
||||
// Set the values in the document
|
||||
doc["hostname"] = config.hostname;
|
||||
@ -93,7 +84,7 @@ void saveConfiguration(const char *filename, const Config &config) {
|
||||
}
|
||||
|
||||
// Prints the content of a file to the Serial
|
||||
void printFile(const char *filename) {
|
||||
void printFile(const char* filename) {
|
||||
// Open file for reading
|
||||
File file = SD.open(filename);
|
||||
if (!file) {
|
||||
@ -114,7 +105,8 @@ void printFile(const char *filename) {
|
||||
void setup() {
|
||||
// Initialize serial port
|
||||
Serial.begin(9600);
|
||||
while (!Serial) continue;
|
||||
while (!Serial)
|
||||
continue;
|
||||
|
||||
// Initialize SD library
|
||||
const int chipSelect = 4;
|
||||
@ -144,7 +136,7 @@ void loop() {
|
||||
// ------------------
|
||||
//
|
||||
// File is an unbuffered stream, which is not optimal for ArduinoJson.
|
||||
// See: https://arduinojson.org/v6/how-to/improve-speed/
|
||||
// See: https://arduinojson.org/v7/how-to/improve-speed/
|
||||
|
||||
// See also
|
||||
// --------
|
||||
|
||||
@ -1,17 +1,18 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows how to use DeserializationOption::Filter
|
||||
//
|
||||
// https://arduinojson.org/v6/example/filter/
|
||||
// https://arduinojson.org/v7/example/filter/
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
void setup() {
|
||||
// Initialize serial port
|
||||
Serial.begin(9600);
|
||||
while (!Serial) continue;
|
||||
while (!Serial)
|
||||
continue;
|
||||
|
||||
// The huge input: an extract from OpenWeatherMap response
|
||||
auto input_json = F(
|
||||
@ -33,12 +34,12 @@ void setup() {
|
||||
"1000000,\"timezone\":0,\"sunrise\":1581492085,\"sunset\":1581527294}}");
|
||||
|
||||
// The filter: it contains "true" for each value we want to keep
|
||||
StaticJsonDocument<200> filter;
|
||||
JsonDocument filter;
|
||||
filter["list"][0]["dt"] = true;
|
||||
filter["list"][0]["main"]["temp"] = true;
|
||||
|
||||
// Deserialize the document
|
||||
StaticJsonDocument<400> doc;
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, input_json, DeserializationOption::Filter(filter));
|
||||
|
||||
// Print the result
|
||||
|
||||
@ -1,43 +1,32 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows how to generate a JSON document with ArduinoJson.
|
||||
//
|
||||
// https://arduinojson.org/v6/example/generator/
|
||||
// https://arduinojson.org/v7/example/generator/
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
void setup() {
|
||||
// Initialize Serial port
|
||||
Serial.begin(9600);
|
||||
while (!Serial) continue;
|
||||
while (!Serial)
|
||||
continue;
|
||||
|
||||
// Allocate the JSON document
|
||||
//
|
||||
// Inside the brackets, 200 is the RAM allocated to this document.
|
||||
// Don't forget to change this value to match your requirement.
|
||||
// Use https://arduinojson.org/v6/assistant to compute the capacity.
|
||||
StaticJsonDocument<200> doc;
|
||||
|
||||
// StaticJsonObject allocates memory on the stack, it can be
|
||||
// replaced by DynamicJsonDocument which allocates in the heap.
|
||||
//
|
||||
// DynamicJsonDocument doc(200);
|
||||
JsonDocument doc;
|
||||
|
||||
// Add values in the document
|
||||
//
|
||||
doc["sensor"] = "gps";
|
||||
doc["time"] = 1351824120;
|
||||
|
||||
// Add an array.
|
||||
//
|
||||
JsonArray data = doc.createNestedArray("data");
|
||||
// Add an array
|
||||
JsonArray data = doc["data"].to<JsonArray>();
|
||||
data.add(48.756080);
|
||||
data.add(2.302038);
|
||||
|
||||
// Generate the minified JSON and send it to the Serial port.
|
||||
//
|
||||
// Generate the minified JSON and send it to the Serial port
|
||||
serializeJson(doc, Serial);
|
||||
// The above line prints:
|
||||
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
|
||||
@ -45,8 +34,7 @@ void setup() {
|
||||
// Start a new line
|
||||
Serial.println();
|
||||
|
||||
// Generate the prettified JSON and send it to the Serial port.
|
||||
//
|
||||
// Generate the prettified JSON and send it to the Serial port
|
||||
serializeJsonPretty(doc, Serial);
|
||||
// The above line prints:
|
||||
// {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows how to parse a JSON document in an HTTP response.
|
||||
@ -16,7 +16,7 @@
|
||||
// ]
|
||||
// }
|
||||
//
|
||||
// https://arduinojson.org/v6/example/http-client/
|
||||
// https://arduinojson.org/v7/example/http-client/
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <Ethernet.h>
|
||||
@ -25,7 +25,8 @@
|
||||
void setup() {
|
||||
// Initialize Serial port
|
||||
Serial.begin(9600);
|
||||
while (!Serial) continue;
|
||||
while (!Serial)
|
||||
continue;
|
||||
|
||||
// Initialize Ethernet library
|
||||
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
|
||||
@ -77,9 +78,7 @@ void setup() {
|
||||
}
|
||||
|
||||
// Allocate the JSON document
|
||||
// Use https://arduinojson.org/v6/assistant to compute the capacity.
|
||||
const size_t capacity = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 60;
|
||||
DynamicJsonDocument doc(capacity);
|
||||
JsonDocument doc;
|
||||
|
||||
// Parse JSON object
|
||||
DeserializationError error = deserializeJson(doc, client);
|
||||
@ -109,7 +108,7 @@ void loop() {
|
||||
// ------------------
|
||||
//
|
||||
// EthernetClient is an unbuffered stream, which is not optimal for ArduinoJson.
|
||||
// See: https://arduinojson.org/v6/how-to/improve-speed/
|
||||
// See: https://arduinojson.org/v7/how-to/improve-speed/
|
||||
|
||||
// See also
|
||||
// --------
|
||||
|
||||
@ -1,52 +1,37 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows how to deserialize a JSON document with ArduinoJson.
|
||||
//
|
||||
// https://arduinojson.org/v6/example/parser/
|
||||
// https://arduinojson.org/v7/example/parser/
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
void setup() {
|
||||
// Initialize serial port
|
||||
Serial.begin(9600);
|
||||
while (!Serial) continue;
|
||||
while (!Serial)
|
||||
continue;
|
||||
|
||||
// Allocate the JSON document
|
||||
//
|
||||
// Inside the brackets, 200 is the capacity of the memory pool in bytes.
|
||||
// Don't forget to change this value to match your JSON document.
|
||||
// Use https://arduinojson.org/v6/assistant to compute the capacity.
|
||||
StaticJsonDocument<200> doc;
|
||||
|
||||
// StaticJsonDocument<N> allocates memory on the stack, it can be
|
||||
// replaced by DynamicJsonDocument which allocates in the heap.
|
||||
//
|
||||
// DynamicJsonDocument doc(200);
|
||||
JsonDocument doc;
|
||||
|
||||
// JSON input string.
|
||||
//
|
||||
// Using a char[], as shown here, enables the "zero-copy" mode. This mode uses
|
||||
// the minimal amount of memory because the JsonDocument stores pointers to
|
||||
// the input buffer.
|
||||
// If you use another type of input, ArduinoJson must copy the strings from
|
||||
// the input to the JsonDocument, so you need to increase the capacity of the
|
||||
// JsonDocument.
|
||||
char json[] =
|
||||
const char* json =
|
||||
"{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
|
||||
|
||||
// Deserialize the JSON document
|
||||
DeserializationError error = deserializeJson(doc, json);
|
||||
|
||||
// Test if parsing succeeds.
|
||||
// Test if parsing succeeds
|
||||
if (error) {
|
||||
Serial.print(F("deserializeJson() failed: "));
|
||||
Serial.println(error.f_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch values.
|
||||
// Fetch the values
|
||||
//
|
||||
// Most of the time, you can rely on the implicit casts.
|
||||
// In other case, you can do doc["time"].as<long>();
|
||||
@ -55,7 +40,7 @@ void setup() {
|
||||
double latitude = doc["data"][0];
|
||||
double longitude = doc["data"][1];
|
||||
|
||||
// Print values.
|
||||
// Print the values
|
||||
Serial.println(sensor);
|
||||
Serial.println(time);
|
||||
Serial.println(latitude, 6);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows how to implement an HTTP server that sends a JSON document
|
||||
@ -13,7 +13,7 @@
|
||||
// "digital": [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0]
|
||||
// }
|
||||
//
|
||||
// https://arduinojson.org/v6/example/http-server/
|
||||
// https://arduinojson.org/v7/example/http-server/
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <Ethernet.h>
|
||||
@ -25,7 +25,8 @@ EthernetServer server(80);
|
||||
void setup() {
|
||||
// Initialize serial port
|
||||
Serial.begin(9600);
|
||||
while (!Serial) continue;
|
||||
while (!Serial)
|
||||
continue;
|
||||
|
||||
// Initialize Ethernet libary
|
||||
if (!Ethernet.begin(mac)) {
|
||||
@ -52,14 +53,14 @@ void loop() {
|
||||
Serial.println(F("New client"));
|
||||
|
||||
// Read the request (we ignore the content in this example)
|
||||
while (client.available()) client.read();
|
||||
while (client.available())
|
||||
client.read();
|
||||
|
||||
// Allocate a temporary JsonDocument
|
||||
// Use https://arduinojson.org/v6/assistant to compute the capacity.
|
||||
StaticJsonDocument<500> doc;
|
||||
JsonDocument doc;
|
||||
|
||||
// Create the "analog" array
|
||||
JsonArray analogValues = doc.createNestedArray("analog");
|
||||
JsonArray analogValues = doc["analog"].to<JsonArray>();
|
||||
for (int pin = 0; pin < 6; pin++) {
|
||||
// Read the analog input
|
||||
int value = analogRead(pin);
|
||||
@ -69,7 +70,7 @@ void loop() {
|
||||
}
|
||||
|
||||
// Create the "digital" array
|
||||
JsonArray digitalValues = doc.createNestedArray("digital");
|
||||
JsonArray digitalValues = doc["digital"].to<JsonArray>();
|
||||
for (int pin = 0; pin < 14; pin++) {
|
||||
// Read the digital input
|
||||
int value = digitalRead(pin);
|
||||
@ -101,7 +102,7 @@ void loop() {
|
||||
// ------------------
|
||||
//
|
||||
// EthernetClient is an unbuffered stream, which is not optimal for ArduinoJson.
|
||||
// See: https://arduinojson.org/v6/how-to/improve-speed/
|
||||
// See: https://arduinojson.org/v7/how-to/improve-speed/
|
||||
|
||||
// See also
|
||||
// --------
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows how to send a JSON document to a UDP socket.
|
||||
@ -17,7 +17,7 @@
|
||||
// $ ncat -ulp 8888
|
||||
// See https://nmap.org/ncat/
|
||||
//
|
||||
// https://arduinojson.org/v6/example/udp-beacon/
|
||||
// https://arduinojson.org/v7/example/udp-beacon/
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <Ethernet.h>
|
||||
@ -32,7 +32,8 @@ EthernetUDP udp;
|
||||
void setup() {
|
||||
// Initialize serial port
|
||||
Serial.begin(9600);
|
||||
while (!Serial) continue;
|
||||
while (!Serial)
|
||||
continue;
|
||||
|
||||
// Initialize Ethernet libary
|
||||
if (!Ethernet.begin(mac)) {
|
||||
@ -46,11 +47,10 @@ void setup() {
|
||||
|
||||
void loop() {
|
||||
// Allocate a temporary JsonDocument
|
||||
// Use https://arduinojson.org/v6/assistant to compute the capacity.
|
||||
StaticJsonDocument<500> doc;
|
||||
JsonDocument doc;
|
||||
|
||||
// Create the "analog" array
|
||||
JsonArray analogValues = doc.createNestedArray("analog");
|
||||
JsonArray analogValues = doc["analog"].to<JsonArray>();
|
||||
for (int pin = 0; pin < 6; pin++) {
|
||||
// Read the analog input
|
||||
int value = analogRead(pin);
|
||||
@ -60,7 +60,7 @@ void loop() {
|
||||
}
|
||||
|
||||
// Create the "digital" array
|
||||
JsonArray digitalValues = doc.createNestedArray("digital");
|
||||
JsonArray digitalValues = doc["digital"].to<JsonArray>();
|
||||
for (int pin = 0; pin < 14; pin++) {
|
||||
// Read the digital input
|
||||
int value = digitalRead(pin);
|
||||
@ -90,7 +90,7 @@ void loop() {
|
||||
// ------------------
|
||||
//
|
||||
// EthernetUDP is an unbuffered stream, which is not optimal for ArduinoJson.
|
||||
// See: https://arduinojson.org/v6/how-to/improve-speed/
|
||||
// See: https://arduinojson.org/v7/how-to/improve-speed/
|
||||
|
||||
// See also
|
||||
// --------
|
||||
|
||||
@ -1,39 +1,24 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows how to deserialize a MessagePack document with
|
||||
// ArduinoJson.
|
||||
//
|
||||
// https://arduinojson.org/v6/example/msgpack-parser/
|
||||
// https://arduinojson.org/v7/example/msgpack-parser/
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
void setup() {
|
||||
// Initialize serial port
|
||||
Serial.begin(9600);
|
||||
while (!Serial) continue;
|
||||
while (!Serial)
|
||||
continue;
|
||||
|
||||
// Allocate the JSON document
|
||||
//
|
||||
// Inside the brackets, 200 is the capacity of the memory pool in bytes.
|
||||
// Don't forget to change this value to match your JSON document.
|
||||
// Use https://arduinojson.org/v6/assistant to compute the capacity.
|
||||
StaticJsonDocument<200> doc;
|
||||
JsonDocument doc;
|
||||
|
||||
// StaticJsonObject allocates memory on the stack, it can be
|
||||
// replaced by DynamicJsonObject which allocates in the heap.
|
||||
//
|
||||
// DynamicJsonObject doc(200);
|
||||
|
||||
// MessagePack input string.
|
||||
//
|
||||
// Using a char[], as shown here, enables the "zero-copy" mode. This mode uses
|
||||
// the minimal amount of memory because the JsonDocument stores pointers to
|
||||
// the input buffer.
|
||||
// If you use another type of input, ArduinoJson must copy the strings from
|
||||
// the input to the JsonDocument, so you need to increase the capacity of the
|
||||
// JsonDocument.
|
||||
// The MessagePack input string
|
||||
uint8_t input[] = {131, 166, 115, 101, 110, 115, 111, 114, 163, 103, 112, 115,
|
||||
164, 116, 105, 109, 101, 206, 80, 147, 50, 248, 164, 100,
|
||||
97, 116, 97, 146, 203, 64, 72, 96, 199, 58, 188, 148,
|
||||
@ -45,16 +30,17 @@ void setup() {
|
||||
// "data": [48.75608, 2.302038]
|
||||
// }
|
||||
|
||||
// Parse the input
|
||||
DeserializationError error = deserializeMsgPack(doc, input);
|
||||
|
||||
// Test if parsing succeeded.
|
||||
// Test if parsing succeeded
|
||||
if (error) {
|
||||
Serial.print("deserializeMsgPack() failed: ");
|
||||
Serial.println(error.f_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch values.
|
||||
// Fetch the values
|
||||
//
|
||||
// Most of the time, you can rely on the implicit casts.
|
||||
// In other case, you can do doc["time"].as<long>();
|
||||
@ -63,7 +49,7 @@ void setup() {
|
||||
double latitude = doc["data"][0];
|
||||
double longitude = doc["data"][1];
|
||||
|
||||
// Print values.
|
||||
// Print the values
|
||||
Serial.println(sensor);
|
||||
Serial.println(time);
|
||||
Serial.println(latitude, 6);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows the different ways you can use Flash strings with
|
||||
@ -9,12 +9,12 @@
|
||||
// JsonDocument. Prefer plain old char*, as they are more efficient in term of
|
||||
// code size, speed, and memory usage.
|
||||
//
|
||||
// https://arduinojson.org/v6/example/progmem/
|
||||
// https://arduinojson.org/v7/example/progmem/
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
void setup() {
|
||||
DynamicJsonDocument doc(1024);
|
||||
JsonDocument doc;
|
||||
|
||||
// You can use a Flash String as your JSON input.
|
||||
// WARNING: the strings in the input will be duplicated in the JsonDocument.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows the different ways you can use String with ArduinoJson.
|
||||
@ -8,12 +8,12 @@
|
||||
// JsonDocument. Prefer plain old char[], as they are more efficient in term of
|
||||
// code size, speed, and memory usage.
|
||||
//
|
||||
// https://arduinojson.org/v6/example/string/
|
||||
// https://arduinojson.org/v7/example/string/
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
void setup() {
|
||||
DynamicJsonDocument doc(1024);
|
||||
JsonDocument doc;
|
||||
|
||||
// You can use a String as your JSON input.
|
||||
// WARNING: the string in the input will be duplicated in the JsonDocument.
|
||||
@ -55,7 +55,6 @@ void setup() {
|
||||
}
|
||||
|
||||
// Lastly, you can print the resulting JSON to a String
|
||||
// WARNING: it doesn't replace the content but appends to it
|
||||
String output;
|
||||
serializeJson(doc, output);
|
||||
}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "ArduinoJson",
|
||||
"keywords": "json, rest, http, web",
|
||||
"description": "A simple and efficient JSON library for embedded C++. ArduinoJson supports ✔ serialization, ✔ deserialization, ✔ MessagePack, ✔ fixed allocation, ✔ zero-copy, ✔ streams, ✔ filtering, and more. It is the most popular Arduino library on GitHub ❤❤❤❤❤. Check out arduinojson.org for a comprehensive documentation.",
|
||||
"description": "A simple and efficient JSON library for embedded C++. ⭐ 6953 stars on GitHub! Supports serialization, deserialization, MessagePack, streams, filtering, and more. Fully tested and documented.",
|
||||
"homepage": "https://arduinojson.org/?utm_source=meta&utm_medium=library.json",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bblanchon/ArduinoJson.git"
|
||||
},
|
||||
"version": "6.21.5",
|
||||
"version": "7.4.2",
|
||||
"authors": {
|
||||
"name": "Benoit Blanchon",
|
||||
"url": "https://blog.benoitblanchon.fr"
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
name=ArduinoJson
|
||||
version=6.21.5
|
||||
version=7.4.2
|
||||
author=Benoit Blanchon <blog.benoitblanchon.fr>
|
||||
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
|
||||
sentence=A simple and efficient JSON library for embedded C++.
|
||||
paragraph=ArduinoJson supports ✔ serialization, ✔ deserialization, ✔ MessagePack, ✔ fixed allocation, ✔ zero-copy, ✔ streams, ✔ filtering, and more. It is the most popular Arduino library on GitHub ❤❤❤❤❤. Check out arduinojson.org for a comprehensive documentation.
|
||||
paragraph=⭐ 6953 stars on GitHub! Supports serialization, deserialization, MessagePack, streams, filtering, and more. Fully tested and documented.
|
||||
category=Data Processing
|
||||
url=https://arduinojson.org/?utm_source=meta&utm_medium=library.properties
|
||||
architectures=*
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -26,27 +26,40 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Remove true and false macros defined by some cores, such as Arduino Due's
|
||||
// See issues #2181 and arduino/ArduinoCore-sam#50
|
||||
#ifdef true
|
||||
# undef true
|
||||
#endif
|
||||
#ifdef false
|
||||
# undef false
|
||||
#endif
|
||||
|
||||
#include "ArduinoJson/Array/JsonArray.hpp"
|
||||
#include "ArduinoJson/Object/JsonObject.hpp"
|
||||
#include "ArduinoJson/Variant/JsonVariantConst.hpp"
|
||||
|
||||
#include "ArduinoJson/Document/DynamicJsonDocument.hpp"
|
||||
#include "ArduinoJson/Document/StaticJsonDocument.hpp"
|
||||
#include "ArduinoJson/Document/JsonDocument.hpp"
|
||||
|
||||
#include "ArduinoJson/Array/ArrayImpl.hpp"
|
||||
#include "ArduinoJson/Array/ElementProxy.hpp"
|
||||
#include "ArduinoJson/Array/JsonArrayImpl.hpp"
|
||||
#include "ArduinoJson/Array/Utilities.hpp"
|
||||
#include "ArduinoJson/Collection/CollectionImpl.hpp"
|
||||
#include "ArduinoJson/Object/JsonObjectImpl.hpp"
|
||||
#include "ArduinoJson/Memory/ResourceManagerImpl.hpp"
|
||||
#include "ArduinoJson/Object/MemberProxy.hpp"
|
||||
#include "ArduinoJson/Object/ObjectImpl.hpp"
|
||||
#include "ArduinoJson/Variant/ConverterImpl.hpp"
|
||||
#include "ArduinoJson/Variant/JsonVariantCopier.hpp"
|
||||
#include "ArduinoJson/Variant/VariantCompare.hpp"
|
||||
#include "ArduinoJson/Variant/VariantImpl.hpp"
|
||||
#include "ArduinoJson/Variant/VariantRefBaseImpl.hpp"
|
||||
|
||||
#include "ArduinoJson/Json/JsonDeserializer.hpp"
|
||||
#include "ArduinoJson/Json/JsonSerializer.hpp"
|
||||
#include "ArduinoJson/Json/PrettyJsonSerializer.hpp"
|
||||
#include "ArduinoJson/MsgPack/MsgPackBinary.hpp"
|
||||
#include "ArduinoJson/MsgPack/MsgPackDeserializer.hpp"
|
||||
#include "ArduinoJson/MsgPack/MsgPackExtension.hpp"
|
||||
#include "ArduinoJson/MsgPack/MsgPackSerializer.hpp"
|
||||
|
||||
#include "ArduinoJson/compatibility.hpp"
|
||||
|
||||
@ -0,0 +1,66 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Collection/CollectionData.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
class ArrayData : public CollectionData {
|
||||
public:
|
||||
VariantData* addElement(ResourceManager* resources);
|
||||
|
||||
static VariantData* addElement(ArrayData* array, ResourceManager* resources) {
|
||||
if (!array)
|
||||
return nullptr;
|
||||
return array->addElement(resources);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool addValue(const T& value, ResourceManager* resources);
|
||||
|
||||
template <typename T>
|
||||
static bool addValue(ArrayData* array, const T& value,
|
||||
ResourceManager* resources) {
|
||||
if (!array)
|
||||
return false;
|
||||
return array->addValue(value, resources);
|
||||
}
|
||||
|
||||
VariantData* getOrAddElement(size_t index, ResourceManager* resources);
|
||||
|
||||
VariantData* getElement(size_t index, const ResourceManager* resources) const;
|
||||
|
||||
static VariantData* getElement(const ArrayData* array, size_t index,
|
||||
const ResourceManager* resources) {
|
||||
if (!array)
|
||||
return nullptr;
|
||||
return array->getElement(index, resources);
|
||||
}
|
||||
|
||||
void removeElement(size_t index, ResourceManager* resources);
|
||||
|
||||
static void removeElement(ArrayData* array, size_t index,
|
||||
ResourceManager* resources) {
|
||||
if (!array)
|
||||
return;
|
||||
array->removeElement(index, resources);
|
||||
}
|
||||
|
||||
void remove(iterator it, ResourceManager* resources) {
|
||||
CollectionData::removeOne(it, resources);
|
||||
}
|
||||
|
||||
static void remove(ArrayData* array, iterator it,
|
||||
ResourceManager* resources) {
|
||||
if (array)
|
||||
return array->remove(it, resources);
|
||||
}
|
||||
|
||||
private:
|
||||
iterator at(size_t index, const ResourceManager* resources) const;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@ -0,0 +1,79 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Array/ArrayData.hpp>
|
||||
#include <ArduinoJson/Variant/VariantCompare.hpp>
|
||||
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
inline ArrayData::iterator ArrayData::at(
|
||||
size_t index, const ResourceManager* resources) const {
|
||||
auto it = createIterator(resources);
|
||||
while (!it.done() && index) {
|
||||
it.next(resources);
|
||||
--index;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
inline VariantData* ArrayData::addElement(ResourceManager* resources) {
|
||||
auto slot = resources->allocVariant();
|
||||
if (!slot)
|
||||
return nullptr;
|
||||
CollectionData::appendOne(slot, resources);
|
||||
return slot.ptr();
|
||||
}
|
||||
|
||||
inline VariantData* ArrayData::getOrAddElement(size_t index,
|
||||
ResourceManager* resources) {
|
||||
auto it = createIterator(resources);
|
||||
while (!it.done() && index > 0) {
|
||||
it.next(resources);
|
||||
index--;
|
||||
}
|
||||
if (it.done())
|
||||
index++;
|
||||
VariantData* element = it.data();
|
||||
while (index > 0) {
|
||||
element = addElement(resources);
|
||||
if (!element)
|
||||
return nullptr;
|
||||
index--;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
inline VariantData* ArrayData::getElement(
|
||||
size_t index, const ResourceManager* resources) const {
|
||||
return at(index, resources).data();
|
||||
}
|
||||
|
||||
inline void ArrayData::removeElement(size_t index, ResourceManager* resources) {
|
||||
remove(at(index, resources), resources);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool ArrayData::addValue(const T& value, ResourceManager* resources) {
|
||||
ARDUINOJSON_ASSERT(resources != nullptr);
|
||||
auto slot = resources->allocVariant();
|
||||
if (!slot)
|
||||
return false;
|
||||
JsonVariant variant(slot.ptr(), resources);
|
||||
if (!variant.set(value)) {
|
||||
resources->freeVariant(slot);
|
||||
return false;
|
||||
}
|
||||
CollectionData::appendOne(slot, resources);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns the size (in bytes) of an array with n elements.
|
||||
constexpr size_t sizeofArray(size_t n) {
|
||||
return n * ResourceManager::slotSize;
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -9,48 +9,63 @@
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
// A proxy class to get or set an element of an array.
|
||||
// https://arduinojson.org/v6/api/jsonarray/subscript/
|
||||
// https://arduinojson.org/v7/api/jsonarray/subscript/
|
||||
template <typename TUpstream>
|
||||
class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>,
|
||||
public VariantOperators<ElementProxy<TUpstream>> {
|
||||
friend class VariantAttorney;
|
||||
|
||||
friend class VariantRefBase<ElementProxy<TUpstream>>;
|
||||
|
||||
template <typename, typename>
|
||||
friend class MemberProxy;
|
||||
|
||||
template <typename>
|
||||
friend class ElementProxy;
|
||||
|
||||
public:
|
||||
ElementProxy(TUpstream upstream, size_t index)
|
||||
: upstream_(upstream), index_(index) {}
|
||||
|
||||
ElementProxy(const ElementProxy& src)
|
||||
: upstream_(src.upstream_), index_(src.index_) {}
|
||||
|
||||
FORCE_INLINE ElementProxy& operator=(const ElementProxy& src) {
|
||||
ElementProxy& operator=(const ElementProxy& src) {
|
||||
this->set(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
FORCE_INLINE ElementProxy& operator=(const T& src) {
|
||||
ElementProxy& operator=(const T& src) {
|
||||
this->set(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
FORCE_INLINE ElementProxy& operator=(T* src) {
|
||||
ElementProxy& operator=(T* src) {
|
||||
this->set(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
FORCE_INLINE MemoryPool* getPool() const {
|
||||
return VariantAttorney::getPool(upstream_);
|
||||
// clang-format off
|
||||
ElementProxy(const ElementProxy& src) // Error here? See https://arduinojson.org/v7/proxy-non-copyable/
|
||||
: upstream_(src.upstream_), index_(src.index_) {}
|
||||
// clang-format on
|
||||
|
||||
ResourceManager* getResourceManager() const {
|
||||
return VariantAttorney::getResourceManager(upstream_);
|
||||
}
|
||||
|
||||
FORCE_INLINE VariantData* getData() const {
|
||||
return variantGetElement(VariantAttorney::getData(upstream_), index_);
|
||||
return VariantData::getElement(
|
||||
VariantAttorney::getData(upstream_), index_,
|
||||
VariantAttorney::getResourceManager(upstream_));
|
||||
}
|
||||
|
||||
FORCE_INLINE VariantData* getOrCreateData() const {
|
||||
return variantGetOrAddElement(VariantAttorney::getOrCreateData(upstream_),
|
||||
index_, VariantAttorney::getPool(upstream_));
|
||||
VariantData* getOrCreateData() const {
|
||||
auto data = VariantAttorney::getOrCreateData(upstream_);
|
||||
if (!data)
|
||||
return nullptr;
|
||||
return data->getOrAddElement(
|
||||
index_, VariantAttorney::getResourceManager(upstream_));
|
||||
}
|
||||
|
||||
TUpstream upstream_;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -12,163 +12,196 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
class JsonObject;
|
||||
|
||||
// A reference to an array in a JsonDocument
|
||||
// https://arduinojson.org/v6/api/jsonarray/
|
||||
// https://arduinojson.org/v7/api/jsonarray/
|
||||
class JsonArray : public detail::VariantOperators<JsonArray> {
|
||||
friend class detail::VariantAttorney;
|
||||
|
||||
public:
|
||||
typedef JsonArrayIterator iterator;
|
||||
using iterator = JsonArrayIterator;
|
||||
|
||||
// Constructs an unbound reference.
|
||||
FORCE_INLINE JsonArray() : data_(0), pool_(0) {}
|
||||
JsonArray() : data_(0), resources_(0) {}
|
||||
|
||||
// INTERNAL USE ONLY
|
||||
FORCE_INLINE JsonArray(detail::MemoryPool* pool, detail::CollectionData* data)
|
||||
: data_(data), pool_(pool) {}
|
||||
JsonArray(detail::ArrayData* data, detail::ResourceManager* resources)
|
||||
: data_(data), resources_(resources) {}
|
||||
|
||||
// Returns a JsonVariant pointing to the array.
|
||||
// https://arduinojson.org/v6/api/jsonvariant/
|
||||
// https://arduinojson.org/v7/api/jsonvariant/
|
||||
operator JsonVariant() {
|
||||
void* data = data_; // prevent warning cast-align
|
||||
return JsonVariant(pool_, reinterpret_cast<detail::VariantData*>(data));
|
||||
return JsonVariant(reinterpret_cast<detail::VariantData*>(data),
|
||||
resources_);
|
||||
}
|
||||
|
||||
// Returns a read-only reference to the array.
|
||||
// https://arduinojson.org/v6/api/jsonarrayconst/
|
||||
// https://arduinojson.org/v7/api/jsonarrayconst/
|
||||
operator JsonArrayConst() const {
|
||||
return JsonArrayConst(data_);
|
||||
return JsonArrayConst(data_, resources_);
|
||||
}
|
||||
|
||||
// Appends a new (empty) element to the array.
|
||||
// Returns a reference to the new element.
|
||||
// https://arduinojson.org/v7/api/jsonarray/add/
|
||||
template <typename T, detail::enable_if_t<
|
||||
!detail::is_same<T, JsonVariant>::value, int> = 0>
|
||||
T add() const {
|
||||
return add<JsonVariant>().to<T>();
|
||||
}
|
||||
|
||||
// Appends a new (null) element to the array.
|
||||
// Returns a reference to the new element.
|
||||
// https://arduinojson.org/v6/api/jsonarray/add/
|
||||
// https://arduinojson.org/v7/api/jsonarray/add/
|
||||
template <typename T, detail::enable_if_t<
|
||||
detail::is_same<T, JsonVariant>::value, int> = 0>
|
||||
JsonVariant add() const {
|
||||
if (!data_)
|
||||
return JsonVariant();
|
||||
return JsonVariant(pool_, data_->addElement(pool_));
|
||||
return JsonVariant(detail::ArrayData::addElement(data_, resources_),
|
||||
resources_);
|
||||
}
|
||||
|
||||
// Appends a value to the array.
|
||||
// https://arduinojson.org/v6/api/jsonarray/add/
|
||||
// https://arduinojson.org/v7/api/jsonarray/add/
|
||||
template <typename T>
|
||||
FORCE_INLINE bool add(const T& value) const {
|
||||
return add().set(value);
|
||||
bool add(const T& value) const {
|
||||
return detail::ArrayData::addValue(data_, value, resources_);
|
||||
}
|
||||
|
||||
// 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);
|
||||
// https://arduinojson.org/v7/api/jsonarray/add/
|
||||
template <typename T,
|
||||
detail::enable_if_t<!detail::is_const<T>::value, int> = 0>
|
||||
bool add(T* value) const {
|
||||
return detail::ArrayData::addValue(data_, value, resources_);
|
||||
}
|
||||
|
||||
// Returns an iterator to the first element of the array.
|
||||
// https://arduinojson.org/v6/api/jsonarray/begin/
|
||||
FORCE_INLINE iterator begin() const {
|
||||
// https://arduinojson.org/v7/api/jsonarray/begin/
|
||||
iterator begin() const {
|
||||
if (!data_)
|
||||
return iterator();
|
||||
return iterator(pool_, data_->head());
|
||||
return iterator(data_->createIterator(resources_), resources_);
|
||||
}
|
||||
|
||||
// Returns an iterator following the last element of the array.
|
||||
// https://arduinojson.org/v6/api/jsonarray/end/
|
||||
FORCE_INLINE iterator end() const {
|
||||
// https://arduinojson.org/v7/api/jsonarray/end/
|
||||
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_)
|
||||
// https://arduinojson.org/v7/api/jsonarray/set/
|
||||
bool set(JsonArrayConst src) const {
|
||||
if (!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_);
|
||||
clear();
|
||||
for (auto element : src) {
|
||||
if (!add(element))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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_);
|
||||
// https://arduinojson.org/v7/api/jsonarray/remove/
|
||||
void remove(iterator it) const {
|
||||
detail::ArrayData::remove(data_, it.iterator_, resources_);
|
||||
}
|
||||
|
||||
// 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);
|
||||
// https://arduinojson.org/v7/api/jsonarray/remove/
|
||||
void remove(size_t index) const {
|
||||
detail::ArrayData::removeElement(data_, index, resources_);
|
||||
}
|
||||
|
||||
// Removes the element at the specified index.
|
||||
// https://arduinojson.org/v7/api/jsonarray/remove/
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
void remove(const TVariant& variant) const {
|
||||
if (variant.template is<size_t>())
|
||||
remove(variant.template as<size_t>());
|
||||
}
|
||||
|
||||
// Removes all the elements of the array.
|
||||
// ⚠️ Doesn't release the memory associated with the removed elements.
|
||||
// https://arduinojson.org/v6/api/jsonarray/clear/
|
||||
// https://arduinojson.org/v7/api/jsonarray/clear/
|
||||
void clear() const {
|
||||
if (!data_)
|
||||
return;
|
||||
data_->clear();
|
||||
detail::ArrayData::clear(data_, resources_);
|
||||
}
|
||||
|
||||
// Gets or sets the element at the specified index.
|
||||
// https://arduinojson.org/v6/api/jsonarray/subscript/
|
||||
FORCE_INLINE detail::ElementProxy<JsonArray> operator[](size_t index) const {
|
||||
return {*this, index};
|
||||
// https://arduinojson.org/v7/api/jsonarray/subscript/
|
||||
template <typename T,
|
||||
detail::enable_if_t<detail::is_integral<T>::value, int> = 0>
|
||||
detail::ElementProxy<JsonArray> operator[](T index) const {
|
||||
return {*this, size_t(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>();
|
||||
// Gets or sets the element at the specified index.
|
||||
// https://arduinojson.org/v7/api/jsonarray/subscript/
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
detail::ElementProxy<JsonArray> operator[](const TVariant& variant) const {
|
||||
if (variant.template is<size_t>())
|
||||
return {*this, variant.template as<size_t>()};
|
||||
else
|
||||
return {*this, size_t(-1)};
|
||||
}
|
||||
|
||||
operator JsonVariantConst() const {
|
||||
return JsonVariantConst(collectionToVariant(data_));
|
||||
return JsonVariantConst(collectionToVariant(data_), resources_);
|
||||
}
|
||||
|
||||
// Returns true if the reference is unbound.
|
||||
// https://arduinojson.org/v6/api/jsonarray/isnull/
|
||||
FORCE_INLINE bool isNull() const {
|
||||
// https://arduinojson.org/v7/api/jsonarray/isnull/
|
||||
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 {
|
||||
// https://arduinojson.org/v7/api/jsonarray/isnull/
|
||||
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_));
|
||||
// https://arduinojson.org/v7/api/jsonarray/nesting/
|
||||
size_t nesting() const {
|
||||
return detail::VariantData::nesting(collectionToVariant(data_), resources_);
|
||||
}
|
||||
|
||||
// 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;
|
||||
// https://arduinojson.org/v7/api/jsonarray/size/
|
||||
size_t size() const {
|
||||
return data_ ? data_->size(resources_) : 0;
|
||||
}
|
||||
|
||||
// DEPRECATED: use add<JsonVariant>() instead
|
||||
ARDUINOJSON_DEPRECATED("use add<JsonVariant>() instead")
|
||||
JsonVariant add() const {
|
||||
return add<JsonVariant>();
|
||||
}
|
||||
|
||||
// DEPRECATED: use add<JsonArray>() instead
|
||||
ARDUINOJSON_DEPRECATED("use add<JsonArray>() instead")
|
||||
JsonArray createNestedArray() const {
|
||||
return add<JsonArray>();
|
||||
}
|
||||
|
||||
// DEPRECATED: use add<JsonObject>() instead
|
||||
ARDUINOJSON_DEPRECATED("use add<JsonObject>() instead")
|
||||
JsonObject createNestedObject() const;
|
||||
|
||||
// DEPRECATED: always returns zero
|
||||
ARDUINOJSON_DEPRECATED("always returns zero")
|
||||
size_t memoryUsage() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
detail::MemoryPool* getPool() const {
|
||||
return pool_;
|
||||
detail::ResourceManager* getResourceManager() const {
|
||||
return resources_;
|
||||
}
|
||||
|
||||
detail::VariantData* getData() const {
|
||||
@ -179,33 +212,8 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
|
||||
return collectionToVariant(data_);
|
||||
}
|
||||
|
||||
detail::CollectionData* data_;
|
||||
detail::MemoryPool* pool_;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<JsonArray> : private detail::VariantAttorney {
|
||||
static void toJson(JsonVariantConst src, JsonVariant dst) {
|
||||
variantCopyFrom(getData(dst), getData(src), getPool(dst));
|
||||
}
|
||||
|
||||
static JsonArray fromJson(JsonVariant src) {
|
||||
auto data = getData(src);
|
||||
auto pool = getPool(src);
|
||||
return JsonArray(pool, data != 0 ? data->asArray() : 0);
|
||||
}
|
||||
|
||||
static detail::InvalidConversion<JsonVariantConst, JsonArray> fromJson(
|
||||
JsonVariantConst);
|
||||
|
||||
static bool checkJson(JsonVariantConst) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool checkJson(JsonVariant src) {
|
||||
auto data = getData(src);
|
||||
return data && data->isArray();
|
||||
}
|
||||
detail::ArrayData* data_;
|
||||
detail::ResourceManager* resources_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -13,98 +13,89 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
class JsonObject;
|
||||
|
||||
// A read-only reference to an array in a JsonDocument
|
||||
// https://arduinojson.org/v6/api/jsonarrayconst/
|
||||
// https://arduinojson.org/v7/api/jsonarrayconst/
|
||||
class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
|
||||
friend class JsonArray;
|
||||
friend class detail::VariantAttorney;
|
||||
|
||||
public:
|
||||
typedef JsonArrayConstIterator iterator;
|
||||
using iterator = JsonArrayConstIterator;
|
||||
|
||||
// Returns an iterator to the first element of the array.
|
||||
// https://arduinojson.org/v6/api/jsonarrayconst/begin/
|
||||
FORCE_INLINE iterator begin() const {
|
||||
// https://arduinojson.org/v7/api/jsonarrayconst/begin/
|
||||
iterator begin() const {
|
||||
if (!data_)
|
||||
return iterator();
|
||||
return iterator(data_->head());
|
||||
return iterator(data_->createIterator(resources_), resources_);
|
||||
}
|
||||
|
||||
// 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 {
|
||||
// https://arduinojson.org/v7/api/jsonarrayconst/end/
|
||||
iterator end() const {
|
||||
return iterator();
|
||||
}
|
||||
|
||||
// Creates an unbound reference.
|
||||
FORCE_INLINE JsonArrayConst() : data_(0) {}
|
||||
JsonArrayConst() : data_(0), resources_(0) {}
|
||||
|
||||
// INTERNAL USE ONLY
|
||||
FORCE_INLINE JsonArrayConst(const detail::CollectionData* data)
|
||||
: data_(data) {}
|
||||
JsonArrayConst(const detail::ArrayData* data,
|
||||
const detail::ResourceManager* resources)
|
||||
: data_(data), resources_(resources) {}
|
||||
|
||||
// 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/v7/api/jsonarrayconst/subscript/
|
||||
template <typename T,
|
||||
detail::enable_if_t<detail::is_integral<T>::value, int> = 0>
|
||||
JsonVariantConst operator[](T index) const {
|
||||
return JsonVariantConst(
|
||||
detail::ArrayData::getElement(data_, size_t(index), resources_),
|
||||
resources_);
|
||||
}
|
||||
|
||||
// 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);
|
||||
// https://arduinojson.org/v7/api/jsonarrayconst/subscript/
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
JsonVariantConst operator[](const TVariant& variant) const {
|
||||
if (variant.template is<size_t>())
|
||||
return operator[](variant.template as<size_t>());
|
||||
else
|
||||
return JsonVariantConst();
|
||||
}
|
||||
|
||||
operator JsonVariantConst() const {
|
||||
return JsonVariantConst(collectionToVariant(data_));
|
||||
return JsonVariantConst(getData(), resources_);
|
||||
}
|
||||
|
||||
// Returns true if the reference is unbound.
|
||||
// https://arduinojson.org/v6/api/jsonarrayconst/isnull/
|
||||
FORCE_INLINE bool isNull() const {
|
||||
// https://arduinojson.org/v7/api/jsonarrayconst/isnull/
|
||||
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 {
|
||||
// https://arduinojson.org/v7/api/jsonarrayconst/isnull/
|
||||
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_));
|
||||
// https://arduinojson.org/v7/api/jsonarrayconst/nesting/
|
||||
size_t nesting() const {
|
||||
return detail::VariantData::nesting(getData(), resources_);
|
||||
}
|
||||
|
||||
// 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;
|
||||
// https://arduinojson.org/v7/api/jsonarrayconst/size/
|
||||
size_t size() const {
|
||||
return data_ ? data_->size(resources_) : 0;
|
||||
}
|
||||
|
||||
// DEPRECATED: always returns zero
|
||||
ARDUINOJSON_DEPRECATED("always returns zero")
|
||||
size_t memoryUsage() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -112,24 +103,31 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
|
||||
return collectionToVariant(data_);
|
||||
}
|
||||
|
||||
const detail::CollectionData* data_;
|
||||
const detail::ArrayData* data_;
|
||||
const detail::ResourceManager* resources_;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<JsonArrayConst> : private detail::VariantAttorney {
|
||||
static void toJson(JsonVariantConst src, JsonVariant dst) {
|
||||
variantCopyFrom(getData(dst), getData(src), getPool(dst));
|
||||
}
|
||||
// Compares the content of two arrays.
|
||||
// Returns true if the two arrays are equal.
|
||||
inline bool operator==(JsonArrayConst lhs, JsonArrayConst rhs) {
|
||||
if (!lhs && !rhs)
|
||||
return true;
|
||||
if (!lhs || !rhs)
|
||||
return false;
|
||||
|
||||
static JsonArrayConst fromJson(JsonVariantConst src) {
|
||||
auto data = getData(src);
|
||||
return data ? data->asArray() : 0;
|
||||
}
|
||||
auto a = lhs.begin();
|
||||
auto b = rhs.begin();
|
||||
|
||||
static bool checkJson(JsonVariantConst src) {
|
||||
auto data = getData(src);
|
||||
return data && data->isArray();
|
||||
for (;;) {
|
||||
if (a == b) // same pointer or both null
|
||||
return true;
|
||||
if (a == lhs.end() || b == rhs.end())
|
||||
return false;
|
||||
if (*a != *b)
|
||||
return false;
|
||||
++a;
|
||||
++b;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Array/JsonArray.hpp>
|
||||
#include <ArduinoJson/Object/JsonObject.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
inline JsonObject JsonArray::createNestedObject() const {
|
||||
return add().to<JsonObject>();
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@ -1,121 +1,96 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Variant/JsonVariant.hpp>
|
||||
#include <ArduinoJson/Variant/SlotFunctions.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
class VariantPtr {
|
||||
template <typename T>
|
||||
class Ptr {
|
||||
public:
|
||||
VariantPtr(detail::MemoryPool* pool, detail::VariantData* data)
|
||||
: variant_(pool, data) {}
|
||||
Ptr(T value) : value_(value) {}
|
||||
|
||||
JsonVariant* operator->() {
|
||||
return &variant_;
|
||||
T* operator->() {
|
||||
return &value_;
|
||||
}
|
||||
|
||||
JsonVariant& operator*() {
|
||||
return variant_;
|
||||
T& operator*() {
|
||||
return value_;
|
||||
}
|
||||
|
||||
private:
|
||||
JsonVariant variant_;
|
||||
T value_;
|
||||
};
|
||||
|
||||
class JsonArrayIterator {
|
||||
friend class JsonArray;
|
||||
|
||||
public:
|
||||
JsonArrayIterator() : slot_(0) {}
|
||||
explicit JsonArrayIterator(detail::MemoryPool* pool,
|
||||
detail::VariantSlot* slot)
|
||||
: pool_(pool), slot_(slot) {}
|
||||
JsonArrayIterator() {}
|
||||
explicit JsonArrayIterator(detail::ArrayData::iterator iterator,
|
||||
detail::ResourceManager* resources)
|
||||
: iterator_(iterator), resources_(resources) {}
|
||||
|
||||
JsonVariant operator*() const {
|
||||
return JsonVariant(pool_, slot_->data());
|
||||
JsonVariant operator*() {
|
||||
return JsonVariant(iterator_.data(), resources_);
|
||||
}
|
||||
VariantPtr operator->() {
|
||||
return VariantPtr(pool_, slot_->data());
|
||||
Ptr<JsonVariant> operator->() {
|
||||
return operator*();
|
||||
}
|
||||
|
||||
bool operator==(const JsonArrayIterator& other) const {
|
||||
return slot_ == other.slot_;
|
||||
return iterator_ == other.iterator_;
|
||||
}
|
||||
|
||||
bool operator!=(const JsonArrayIterator& other) const {
|
||||
return slot_ != other.slot_;
|
||||
return iterator_ != other.iterator_;
|
||||
}
|
||||
|
||||
JsonArrayIterator& operator++() {
|
||||
slot_ = slot_->next();
|
||||
return *this;
|
||||
}
|
||||
|
||||
JsonArrayIterator& operator+=(size_t distance) {
|
||||
slot_ = slot_->next(distance);
|
||||
iterator_.next(resources_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
detail::MemoryPool* pool_;
|
||||
detail::VariantSlot* slot_;
|
||||
};
|
||||
|
||||
class VariantConstPtr {
|
||||
public:
|
||||
VariantConstPtr(const detail::VariantData* data) : variant_(data) {}
|
||||
|
||||
JsonVariantConst* operator->() {
|
||||
return &variant_;
|
||||
}
|
||||
|
||||
JsonVariantConst& operator*() {
|
||||
return variant_;
|
||||
}
|
||||
|
||||
private:
|
||||
JsonVariantConst variant_;
|
||||
detail::ArrayData::iterator iterator_;
|
||||
detail::ResourceManager* resources_;
|
||||
};
|
||||
|
||||
class JsonArrayConstIterator {
|
||||
friend class JsonArray;
|
||||
|
||||
public:
|
||||
JsonArrayConstIterator() : slot_(0) {}
|
||||
explicit JsonArrayConstIterator(const detail::VariantSlot* slot)
|
||||
: slot_(slot) {}
|
||||
JsonArrayConstIterator() {}
|
||||
explicit JsonArrayConstIterator(detail::ArrayData::iterator iterator,
|
||||
const detail::ResourceManager* resources)
|
||||
: iterator_(iterator), resources_(resources) {}
|
||||
|
||||
JsonVariantConst operator*() const {
|
||||
return JsonVariantConst(slot_->data());
|
||||
return JsonVariantConst(iterator_.data(), resources_);
|
||||
}
|
||||
VariantConstPtr operator->() {
|
||||
return VariantConstPtr(slot_->data());
|
||||
Ptr<JsonVariantConst> operator->() {
|
||||
return operator*();
|
||||
}
|
||||
|
||||
bool operator==(const JsonArrayConstIterator& other) const {
|
||||
return slot_ == other.slot_;
|
||||
return iterator_ == other.iterator_;
|
||||
}
|
||||
|
||||
bool operator!=(const JsonArrayConstIterator& other) const {
|
||||
return slot_ != other.slot_;
|
||||
return iterator_ != other.iterator_;
|
||||
}
|
||||
|
||||
JsonArrayConstIterator& operator++() {
|
||||
slot_ = slot_->next();
|
||||
return *this;
|
||||
}
|
||||
|
||||
JsonArrayConstIterator& operator+=(size_t distance) {
|
||||
slot_ = slot_->next(distance);
|
||||
iterator_.next(resources_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
const detail::VariantSlot* slot_;
|
||||
detail::ArrayData::iterator iterator_;
|
||||
const detail::ResourceManager* resources_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -11,30 +11,29 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// Copies a value to a JsonVariant.
|
||||
// This is a degenerated form of copyArray() to stop the recursion.
|
||||
template <typename T>
|
||||
inline typename detail::enable_if<!detail::is_array<T>::value, bool>::type
|
||||
copyArray(const T& src, JsonVariant dst) {
|
||||
template <typename T, detail::enable_if_t<!detail::is_array<T>::value, int> = 0>
|
||||
inline bool copyArray(const T& src, JsonVariant dst) {
|
||||
return dst.set(src);
|
||||
}
|
||||
|
||||
// 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>
|
||||
inline typename detail::enable_if<
|
||||
!detail::is_base_of<JsonDocument, TDestination>::value, bool>::type
|
||||
copyArray(T (&src)[N], const TDestination& dst) {
|
||||
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||
template <typename T, size_t N, typename TDestination,
|
||||
detail::enable_if_t<
|
||||
!detail::is_base_of<JsonDocument, TDestination>::value, int> = 0>
|
||||
inline bool copyArray(T (&src)[N], const TDestination& dst) {
|
||||
return copyArray(src, N, dst);
|
||||
}
|
||||
|
||||
// Copies values from an array to a JsonArray or a JsonVariant.
|
||||
// https://arduinojson.org/v6/api/misc/copyarray/
|
||||
template <typename T, typename TDestination>
|
||||
inline typename detail::enable_if<
|
||||
!detail::is_base_of<JsonDocument, TDestination>::value, bool>::type
|
||||
copyArray(const T* src, size_t len, const TDestination& dst) {
|
||||
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||
template <typename T, typename TDestination,
|
||||
detail::enable_if_t<
|
||||
!detail::is_base_of<JsonDocument, TDestination>::value, int> = 0>
|
||||
inline bool copyArray(const T* src, size_t len, const TDestination& dst) {
|
||||
bool ok = true;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
ok &= copyArray(src[i], dst.add());
|
||||
ok &= copyArray(src[i], dst.template add<JsonVariant>());
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
@ -47,14 +46,14 @@ inline bool copyArray(const char* src, size_t, const TDestination& dst) {
|
||||
}
|
||||
|
||||
// Copies values from an array to a JsonDocument.
|
||||
// https://arduinojson.org/v6/api/misc/copyarray/
|
||||
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||
template <typename T>
|
||||
inline bool copyArray(const T& src, JsonDocument& dst) {
|
||||
return copyArray(src, dst.to<JsonArray>());
|
||||
}
|
||||
|
||||
// Copies an array to a JsonDocument.
|
||||
// https://arduinojson.org/v6/api/misc/copyarray/
|
||||
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||
template <typename T>
|
||||
inline bool copyArray(const T* src, size_t len, JsonDocument& dst) {
|
||||
return copyArray(src, len, dst.to<JsonArray>());
|
||||
@ -62,22 +61,21 @@ inline bool copyArray(const T* src, size_t len, JsonDocument& dst) {
|
||||
|
||||
// Copies a value from a JsonVariant.
|
||||
// This is a degenerated form of copyArray() to stop the recursion.
|
||||
template <typename T>
|
||||
inline typename detail::enable_if<!detail::is_array<T>::value, size_t>::type
|
||||
copyArray(JsonVariantConst src, T& dst) {
|
||||
template <typename T, detail::enable_if_t<!detail::is_array<T>::value, int> = 0>
|
||||
inline size_t copyArray(JsonVariantConst src, T& dst) {
|
||||
dst = src.as<T>();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Copies values from a JsonArray or JsonVariant to an array.
|
||||
// https://arduinojson.org/v6/api/misc/copyarray/
|
||||
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||
template <typename T, size_t N>
|
||||
inline size_t copyArray(JsonArrayConst src, T (&dst)[N]) {
|
||||
return copyArray(src, dst, N);
|
||||
}
|
||||
|
||||
// Copies values from a JsonArray or JsonVariant to an array.
|
||||
// https://arduinojson.org/v6/api/misc/copyarray/
|
||||
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||
template <typename T>
|
||||
inline size_t copyArray(JsonArrayConst src, T* dst, size_t len) {
|
||||
size_t i = 0;
|
||||
@ -101,13 +99,13 @@ inline size_t copyArray(JsonVariantConst src, char (&dst)[N]) {
|
||||
}
|
||||
|
||||
// Copies values from a JsonDocument to an array.
|
||||
// https://arduinojson.org/v6/api/misc/copyarray/
|
||||
template <typename TSource, typename T>
|
||||
inline typename detail::enable_if<
|
||||
detail::is_array<T>::value &&
|
||||
detail::is_base_of<JsonDocument, TSource>::value,
|
||||
size_t>::type
|
||||
copyArray(const TSource& src, T& dst) {
|
||||
// https://arduinojson.org/v7/api/misc/copyarray/
|
||||
template <
|
||||
typename TSource, typename T,
|
||||
detail::enable_if_t<detail::is_array<T>::value &&
|
||||
detail::is_base_of<JsonDocument, TSource>::value,
|
||||
int> = 0>
|
||||
inline size_t copyArray(const TSource& src, T& dst) {
|
||||
return copyArray(src.template as<JsonArrayConst>(), dst);
|
||||
}
|
||||
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Memory/MemoryPool.hpp>
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
|
||||
@ -11,74 +12,100 @@
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
class MemoryPool;
|
||||
class VariantData;
|
||||
class VariantSlot;
|
||||
class ResourceManager;
|
||||
|
||||
class CollectionData {
|
||||
VariantSlot* head_;
|
||||
VariantSlot* tail_;
|
||||
class CollectionIterator {
|
||||
friend class CollectionData;
|
||||
|
||||
public:
|
||||
// Must be a POD!
|
||||
// - no constructor
|
||||
// - no destructor
|
||||
// - no virtual
|
||||
// - no inheritance
|
||||
CollectionIterator() : slot_(nullptr), currentId_(NULL_SLOT) {}
|
||||
|
||||
// Array only
|
||||
void next(const ResourceManager* resources);
|
||||
|
||||
VariantData* addElement(MemoryPool* pool);
|
||||
|
||||
VariantData* getElement(size_t index) const;
|
||||
|
||||
VariantData* getOrAddElement(size_t index, MemoryPool* pool);
|
||||
|
||||
void removeElement(size_t index);
|
||||
|
||||
// Object only
|
||||
|
||||
template <typename TAdaptedString>
|
||||
VariantData* addMember(TAdaptedString key, MemoryPool* pool);
|
||||
|
||||
template <typename TAdaptedString>
|
||||
VariantData* getMember(TAdaptedString key) const;
|
||||
|
||||
template <typename TAdaptedString>
|
||||
VariantData* getOrAddMember(TAdaptedString key, MemoryPool* pool);
|
||||
|
||||
template <typename TAdaptedString>
|
||||
void removeMember(TAdaptedString key) {
|
||||
removeSlot(getSlot(key));
|
||||
bool done() const {
|
||||
return slot_ == nullptr;
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
bool containsKey(const TAdaptedString& key) const;
|
||||
bool operator==(const CollectionIterator& other) const {
|
||||
return slot_ == other.slot_;
|
||||
}
|
||||
|
||||
// Generic
|
||||
bool operator!=(const CollectionIterator& other) const {
|
||||
return slot_ != other.slot_;
|
||||
}
|
||||
|
||||
void clear();
|
||||
size_t memoryUsage() const;
|
||||
size_t size() const;
|
||||
VariantData* operator->() {
|
||||
ARDUINOJSON_ASSERT(slot_ != nullptr);
|
||||
return data();
|
||||
}
|
||||
|
||||
VariantSlot* addSlot(MemoryPool*);
|
||||
void removeSlot(VariantSlot* slot);
|
||||
VariantData& operator*() {
|
||||
ARDUINOJSON_ASSERT(slot_ != nullptr);
|
||||
return *data();
|
||||
}
|
||||
|
||||
bool copyFrom(const CollectionData& src, MemoryPool* pool);
|
||||
const VariantData& operator*() const {
|
||||
ARDUINOJSON_ASSERT(slot_ != nullptr);
|
||||
return *data();
|
||||
}
|
||||
|
||||
VariantSlot* head() const {
|
||||
VariantData* data() {
|
||||
return reinterpret_cast<VariantData*>(slot_);
|
||||
}
|
||||
|
||||
const VariantData* data() const {
|
||||
return reinterpret_cast<const VariantData*>(slot_);
|
||||
}
|
||||
|
||||
private:
|
||||
CollectionIterator(VariantData* slot, SlotId slotId);
|
||||
|
||||
VariantData* slot_;
|
||||
SlotId currentId_, nextId_;
|
||||
};
|
||||
|
||||
class CollectionData {
|
||||
SlotId head_ = NULL_SLOT;
|
||||
SlotId tail_ = NULL_SLOT;
|
||||
|
||||
public:
|
||||
// Placement new
|
||||
static void* operator new(size_t, void* p) noexcept {
|
||||
return p;
|
||||
}
|
||||
|
||||
static void operator delete(void*, void*) noexcept {}
|
||||
|
||||
using iterator = CollectionIterator;
|
||||
|
||||
iterator createIterator(const ResourceManager* resources) const;
|
||||
|
||||
size_t size(const ResourceManager*) const;
|
||||
size_t nesting(const ResourceManager*) const;
|
||||
|
||||
void clear(ResourceManager* resources);
|
||||
|
||||
static void clear(CollectionData* collection, ResourceManager* resources) {
|
||||
if (!collection)
|
||||
return;
|
||||
collection->clear(resources);
|
||||
}
|
||||
|
||||
SlotId head() const {
|
||||
return head_;
|
||||
}
|
||||
|
||||
void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance);
|
||||
protected:
|
||||
void appendOne(Slot<VariantData> slot, const ResourceManager* resources);
|
||||
void appendPair(Slot<VariantData> key, Slot<VariantData> value,
|
||||
const ResourceManager* resources);
|
||||
|
||||
void removeOne(iterator it, ResourceManager* resources);
|
||||
void removePair(iterator it, ResourceManager* resources);
|
||||
|
||||
private:
|
||||
VariantSlot* getSlot(size_t index) const;
|
||||
|
||||
template <typename TAdaptedString>
|
||||
VariantSlot* getSlot(TAdaptedString key) const;
|
||||
|
||||
VariantSlot* getPreviousSlot(VariantSlot*) const;
|
||||
Slot<VariantData> getPreviousSlot(VariantData*, const ResourceManager*) const;
|
||||
};
|
||||
|
||||
inline const VariantData* collectionToVariant(
|
||||
|
||||
@ -1,197 +1,137 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Collection/CollectionData.hpp>
|
||||
#include <ArduinoJson/Strings/StoragePolicy.hpp>
|
||||
#include <ArduinoJson/Memory/Alignment.hpp>
|
||||
#include <ArduinoJson/Strings/StringAdapters.hpp>
|
||||
#include <ArduinoJson/Variant/VariantCompare.hpp>
|
||||
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) {
|
||||
VariantSlot* slot = pool->allocVariant();
|
||||
if (!slot)
|
||||
return 0;
|
||||
inline CollectionIterator::CollectionIterator(VariantData* slot, SlotId slotId)
|
||||
: slot_(slot), currentId_(slotId) {
|
||||
nextId_ = slot_ ? slot_->next() : NULL_SLOT;
|
||||
}
|
||||
|
||||
if (tail_) {
|
||||
ARDUINOJSON_ASSERT(pool->owns(tail_)); // Can't alter a linked array/object
|
||||
tail_->setNextNotNull(slot);
|
||||
tail_ = slot;
|
||||
inline void CollectionIterator::next(const ResourceManager* resources) {
|
||||
ARDUINOJSON_ASSERT(currentId_ != NULL_SLOT);
|
||||
slot_ = resources->getVariant(nextId_);
|
||||
currentId_ = nextId_;
|
||||
if (slot_)
|
||||
nextId_ = slot_->next();
|
||||
}
|
||||
|
||||
inline CollectionData::iterator CollectionData::createIterator(
|
||||
const ResourceManager* resources) const {
|
||||
return iterator(resources->getVariant(head_), head_);
|
||||
}
|
||||
|
||||
inline void CollectionData::appendOne(Slot<VariantData> slot,
|
||||
const ResourceManager* resources) {
|
||||
if (tail_ != NULL_SLOT) {
|
||||
auto tail = resources->getVariant(tail_);
|
||||
tail->setNext(slot.id());
|
||||
tail_ = slot.id();
|
||||
} else {
|
||||
head_ = slot;
|
||||
tail_ = slot;
|
||||
head_ = slot.id();
|
||||
tail_ = slot.id();
|
||||
}
|
||||
}
|
||||
|
||||
inline void CollectionData::appendPair(Slot<VariantData> key,
|
||||
Slot<VariantData> value,
|
||||
const ResourceManager* resources) {
|
||||
key->setNext(value.id());
|
||||
|
||||
if (tail_ != NULL_SLOT) {
|
||||
auto tail = resources->getVariant(tail_);
|
||||
tail->setNext(key.id());
|
||||
tail_ = value.id();
|
||||
} else {
|
||||
head_ = key.id();
|
||||
tail_ = value.id();
|
||||
}
|
||||
}
|
||||
|
||||
inline void CollectionData::clear(ResourceManager* resources) {
|
||||
auto next = head_;
|
||||
while (next != NULL_SLOT) {
|
||||
auto currId = next;
|
||||
auto slot = resources->getVariant(next);
|
||||
next = slot->next();
|
||||
resources->freeVariant({slot, currId});
|
||||
}
|
||||
|
||||
slot->clear();
|
||||
return slot;
|
||||
head_ = NULL_SLOT;
|
||||
tail_ = NULL_SLOT;
|
||||
}
|
||||
|
||||
inline VariantData* CollectionData::addElement(MemoryPool* pool) {
|
||||
return slotData(addSlot(pool));
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline VariantData* CollectionData::addMember(TAdaptedString key,
|
||||
MemoryPool* pool) {
|
||||
VariantSlot* slot = addSlot(pool);
|
||||
if (!slotSetKey(slot, key, pool)) {
|
||||
removeSlot(slot);
|
||||
return 0;
|
||||
}
|
||||
return slot->data();
|
||||
}
|
||||
|
||||
inline void CollectionData::clear() {
|
||||
head_ = 0;
|
||||
tail_ = 0;
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline bool CollectionData::containsKey(const TAdaptedString& key) const {
|
||||
return getSlot(key) != 0;
|
||||
}
|
||||
|
||||
inline bool CollectionData::copyFrom(const CollectionData& src,
|
||||
MemoryPool* pool) {
|
||||
clear();
|
||||
for (VariantSlot* s = src.head_; s; s = s->next()) {
|
||||
VariantData* var;
|
||||
if (s->key() != 0) {
|
||||
JsonString key(s->key(),
|
||||
s->ownsKey() ? JsonString::Copied : JsonString::Linked);
|
||||
var = addMember(adaptString(key), pool);
|
||||
} else {
|
||||
var = addElement(pool);
|
||||
}
|
||||
if (!var)
|
||||
return false;
|
||||
if (!var->copyFrom(*s->data(), pool))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const {
|
||||
if (key.isNull())
|
||||
return 0;
|
||||
VariantSlot* slot = head_;
|
||||
while (slot) {
|
||||
if (stringEquals(key, adaptString(slot->key())))
|
||||
inline Slot<VariantData> CollectionData::getPreviousSlot(
|
||||
VariantData* target, const ResourceManager* resources) const {
|
||||
auto prev = Slot<VariantData>();
|
||||
auto currentId = head_;
|
||||
while (currentId != NULL_SLOT) {
|
||||
auto currentSlot = resources->getVariant(currentId);
|
||||
if (currentSlot == target)
|
||||
break;
|
||||
slot = slot->next();
|
||||
prev = Slot<VariantData>(currentSlot, currentId);
|
||||
currentId = currentSlot->next();
|
||||
}
|
||||
return slot;
|
||||
return prev;
|
||||
}
|
||||
|
||||
inline VariantSlot* CollectionData::getSlot(size_t index) const {
|
||||
if (!head_)
|
||||
return 0;
|
||||
return head_->next(index);
|
||||
}
|
||||
|
||||
inline VariantSlot* CollectionData::getPreviousSlot(VariantSlot* target) const {
|
||||
VariantSlot* current = head_;
|
||||
while (current) {
|
||||
VariantSlot* next = current->next();
|
||||
if (next == target)
|
||||
return current;
|
||||
current = next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline VariantData* CollectionData::getMember(TAdaptedString key) const {
|
||||
VariantSlot* slot = getSlot(key);
|
||||
return slot ? slot->data() : 0;
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline VariantData* CollectionData::getOrAddMember(TAdaptedString key,
|
||||
MemoryPool* pool) {
|
||||
// ignore null key
|
||||
if (key.isNull())
|
||||
return 0;
|
||||
|
||||
// search a matching key
|
||||
VariantSlot* slot = getSlot(key);
|
||||
if (slot)
|
||||
return slot->data();
|
||||
|
||||
return addMember(key, pool);
|
||||
}
|
||||
|
||||
inline VariantData* CollectionData::getElement(size_t index) const {
|
||||
VariantSlot* slot = getSlot(index);
|
||||
return slot ? slot->data() : 0;
|
||||
}
|
||||
|
||||
inline VariantData* CollectionData::getOrAddElement(size_t index,
|
||||
MemoryPool* pool) {
|
||||
VariantSlot* slot = head_;
|
||||
while (slot && index > 0) {
|
||||
slot = slot->next();
|
||||
index--;
|
||||
}
|
||||
if (!slot)
|
||||
index++;
|
||||
while (index > 0) {
|
||||
slot = addSlot(pool);
|
||||
index--;
|
||||
}
|
||||
return slotData(slot);
|
||||
}
|
||||
|
||||
inline void CollectionData::removeSlot(VariantSlot* slot) {
|
||||
if (!slot)
|
||||
inline void CollectionData::removeOne(iterator it, ResourceManager* resources) {
|
||||
if (it.done())
|
||||
return;
|
||||
VariantSlot* prev = getPreviousSlot(slot);
|
||||
VariantSlot* next = slot->next();
|
||||
auto curr = it.slot_;
|
||||
auto prev = getPreviousSlot(curr, resources);
|
||||
auto next = curr->next();
|
||||
if (prev)
|
||||
prev->setNext(next);
|
||||
else
|
||||
head_ = next;
|
||||
if (!next)
|
||||
tail_ = prev;
|
||||
if (next == NULL_SLOT)
|
||||
tail_ = prev.id();
|
||||
resources->freeVariant({it.slot_, it.currentId_});
|
||||
}
|
||||
|
||||
inline void CollectionData::removeElement(size_t index) {
|
||||
removeSlot(getSlot(index));
|
||||
}
|
||||
|
||||
inline size_t CollectionData::memoryUsage() const {
|
||||
size_t total = 0;
|
||||
for (VariantSlot* s = head_; s; s = s->next()) {
|
||||
total += sizeof(VariantSlot) + s->data()->memoryUsage();
|
||||
if (s->ownsKey())
|
||||
total += strlen(s->key()) + 1;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
inline size_t CollectionData::size() const {
|
||||
return slotSize(head_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void movePointer(T*& p, ptrdiff_t offset) {
|
||||
if (!p)
|
||||
inline void CollectionData::removePair(ObjectData::iterator it,
|
||||
ResourceManager* resources) {
|
||||
if (it.done())
|
||||
return;
|
||||
p = reinterpret_cast<T*>(
|
||||
reinterpret_cast<void*>(reinterpret_cast<char*>(p) + offset));
|
||||
ARDUINOJSON_ASSERT(isAligned(p));
|
||||
|
||||
auto keySlot = it.slot_;
|
||||
|
||||
auto valueId = it.nextId_;
|
||||
auto valueSlot = resources->getVariant(valueId);
|
||||
|
||||
// remove value slot
|
||||
keySlot->setNext(valueSlot->next());
|
||||
resources->freeVariant({valueSlot, valueId});
|
||||
|
||||
// remove key slot
|
||||
removeOne(it, resources);
|
||||
}
|
||||
|
||||
inline void CollectionData::movePointers(ptrdiff_t stringDistance,
|
||||
ptrdiff_t variantDistance) {
|
||||
movePointer(head_, variantDistance);
|
||||
movePointer(tail_, variantDistance);
|
||||
for (VariantSlot* slot = head_; slot; slot = slot->next())
|
||||
slot->movePointers(stringDistance, variantDistance);
|
||||
inline size_t CollectionData::nesting(const ResourceManager* resources) const {
|
||||
size_t maxChildNesting = 0;
|
||||
for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
|
||||
size_t childNesting = it->nesting(resources);
|
||||
if (childNesting > maxChildNesting)
|
||||
maxChildNesting = childNesting;
|
||||
}
|
||||
return maxChildNesting + 1;
|
||||
}
|
||||
|
||||
inline size_t CollectionData::size(const ResourceManager* resources) const {
|
||||
size_t count = 0;
|
||||
for (auto it = createIterator(resources); !it.done(); it.next(resources))
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
// Support std::istream and std::ostream
|
||||
// https://arduinojson.org/v7/config/enable_std_stream/
|
||||
#ifndef ARDUINOJSON_ENABLE_STD_STREAM
|
||||
# ifdef __has_include
|
||||
# if __has_include(<istream>) && \
|
||||
@ -25,6 +26,7 @@
|
||||
#endif
|
||||
|
||||
// Support std::string
|
||||
// https://arduinojson.org/v7/config/enable_std_string/
|
||||
#ifndef ARDUINOJSON_ENABLE_STD_STRING
|
||||
# ifdef __has_include
|
||||
# if __has_include(<string>) && !defined(min) && !defined(max)
|
||||
@ -54,51 +56,105 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Pointer size: a heuristic to set sensible defaults
|
||||
#ifndef ARDUINOJSON_SIZEOF_POINTER
|
||||
# if defined(__SIZEOF_POINTER__)
|
||||
# define ARDUINOJSON_SIZEOF_POINTER __SIZEOF_POINTER__
|
||||
# elif defined(_WIN64) && _WIN64
|
||||
# define ARDUINOJSON_SIZEOF_POINTER 8 // 64 bits
|
||||
# else
|
||||
# define ARDUINOJSON_SIZEOF_POINTER 4 // assume 32 bits otherwise
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Store floating-point values with float (0) or double (1)
|
||||
// https://arduinojson.org/v7/config/use_double/
|
||||
#ifndef ARDUINOJSON_USE_DOUBLE
|
||||
# define ARDUINOJSON_USE_DOUBLE 1
|
||||
# if ARDUINOJSON_SIZEOF_POINTER >= 4 // 32 & 64 bits systems
|
||||
# define ARDUINOJSON_USE_DOUBLE 1
|
||||
# else
|
||||
# define ARDUINOJSON_USE_DOUBLE 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Store integral values with long (0) or long long (1)
|
||||
// https://arduinojson.org/v7/config/use_long_long/
|
||||
#ifndef ARDUINOJSON_USE_LONG_LONG
|
||||
# if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ >= 4 || \
|
||||
defined(_MSC_VER)
|
||||
# if ARDUINOJSON_SIZEOF_POINTER >= 4 // 32 & 64 bits systems
|
||||
# define ARDUINOJSON_USE_LONG_LONG 1
|
||||
# else
|
||||
# define ARDUINOJSON_USE_LONG_LONG 0
|
||||
# endif
|
||||
#endif
|
||||
#ifndef ARDUINOJSON_USE_LONG_LONG
|
||||
# define ARDUINOJSON_USE_LONG_LONG 0
|
||||
#endif
|
||||
|
||||
// Limit nesting as the stack is likely to be small
|
||||
// https://arduinojson.org/v7/config/default_nesting_limit/
|
||||
#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT
|
||||
# define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10
|
||||
#endif
|
||||
|
||||
// Number of bits to store the pointer to next node
|
||||
// (saves RAM but limits the number of values in a document)
|
||||
#ifndef ARDUINOJSON_SLOT_OFFSET_SIZE
|
||||
# if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ <= 2
|
||||
// Address space == 16-bit => max 127 values
|
||||
# define ARDUINOJSON_SLOT_OFFSET_SIZE 1
|
||||
# elif defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ >= 8 || \
|
||||
defined(_WIN64) && _WIN64
|
||||
// Address space == 64-bit => max 2147483647 values
|
||||
# define ARDUINOJSON_SLOT_OFFSET_SIZE 4
|
||||
// Number of bytes to store a slot id
|
||||
// https://arduinojson.org/v7/config/slot_id_size/
|
||||
#ifndef ARDUINOJSON_SLOT_ID_SIZE
|
||||
# if ARDUINOJSON_SIZEOF_POINTER <= 2
|
||||
// 8-bit and 16-bit archs => up to 255 slots
|
||||
# define ARDUINOJSON_SLOT_ID_SIZE 1
|
||||
# elif ARDUINOJSON_SIZEOF_POINTER == 4
|
||||
// 32-bit arch => up to 65535 slots
|
||||
# define ARDUINOJSON_SLOT_ID_SIZE 2
|
||||
# else
|
||||
// Address space == 32-bit => max 32767 values
|
||||
# define ARDUINOJSON_SLOT_OFFSET_SIZE 2
|
||||
// 64-bit arch => up to 4294967295 slots
|
||||
# define ARDUINOJSON_SLOT_ID_SIZE 4
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Capacity of each variant pool (in slots)
|
||||
#ifndef ARDUINOJSON_POOL_CAPACITY
|
||||
# if ARDUINOJSON_SLOT_ID_SIZE == 1
|
||||
# define ARDUINOJSON_POOL_CAPACITY 16 // 96 bytes
|
||||
# elif ARDUINOJSON_SLOT_ID_SIZE == 2
|
||||
# define ARDUINOJSON_POOL_CAPACITY 128 // 1024 bytes
|
||||
# else
|
||||
# define ARDUINOJSON_POOL_CAPACITY 256 // 4096 bytes
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Initial capacity of the pool list
|
||||
#ifndef ARDUINOJSON_INITIAL_POOL_COUNT
|
||||
# define ARDUINOJSON_INITIAL_POOL_COUNT 4
|
||||
#endif
|
||||
|
||||
// Automatically call shrinkToFit() from deserializeXxx()
|
||||
// Disabled by default on 8-bit platforms because it's not worth the increase in
|
||||
// code size
|
||||
#ifndef ARDUINOJSON_AUTO_SHRINK
|
||||
# if ARDUINOJSON_SIZEOF_POINTER <= 2
|
||||
# define ARDUINOJSON_AUTO_SHRINK 0
|
||||
# else
|
||||
# define ARDUINOJSON_AUTO_SHRINK 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Number of bytes to store the length of a string
|
||||
// https://arduinojson.org/v7/config/string_length_size/
|
||||
#ifndef ARDUINOJSON_STRING_LENGTH_SIZE
|
||||
# if ARDUINOJSON_SIZEOF_POINTER <= 2
|
||||
# define ARDUINOJSON_STRING_LENGTH_SIZE 1 // up to 255 characters
|
||||
# else
|
||||
# define ARDUINOJSON_STRING_LENGTH_SIZE 2 // up to 65535 characters
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO
|
||||
|
||||
// Enable support for Arduino's String class
|
||||
// https://arduinojson.org/v7/config/enable_arduino_string/
|
||||
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
|
||||
# define ARDUINOJSON_ENABLE_ARDUINO_STRING 1
|
||||
# endif
|
||||
|
||||
// Enable support for Arduino's Stream class
|
||||
// https://arduinojson.org/v7/config/enable_arduino_stream/
|
||||
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
|
||||
# define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1
|
||||
# endif
|
||||
@ -109,6 +165,7 @@
|
||||
# endif
|
||||
|
||||
// Enable support for PROGMEM
|
||||
// https://arduinojson.org/v7/config/enable_progmem/
|
||||
# ifndef ARDUINOJSON_ENABLE_PROGMEM
|
||||
# define ARDUINOJSON_ENABLE_PROGMEM 1
|
||||
# endif
|
||||
@ -116,11 +173,13 @@
|
||||
#else // ARDUINO
|
||||
|
||||
// Disable support for Arduino's String class
|
||||
// https://arduinojson.org/v7/config/enable_arduino_string/
|
||||
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
|
||||
# define ARDUINOJSON_ENABLE_ARDUINO_STRING 0
|
||||
# endif
|
||||
|
||||
// Disable support for Arduino's Stream class
|
||||
// https://arduinojson.org/v7/config/enable_arduino_stream/
|
||||
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
|
||||
# define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0
|
||||
# endif
|
||||
@ -131,6 +190,7 @@
|
||||
# endif
|
||||
|
||||
// Enable PROGMEM support on AVR only
|
||||
// https://arduinojson.org/v7/config/enable_progmem/
|
||||
# ifndef ARDUINOJSON_ENABLE_PROGMEM
|
||||
# ifdef __AVR__
|
||||
# define ARDUINOJSON_ENABLE_PROGMEM 1
|
||||
@ -142,32 +202,38 @@
|
||||
#endif // ARDUINO
|
||||
|
||||
// Convert unicode escape sequence (\u0123) to UTF-8
|
||||
// https://arduinojson.org/v7/config/decode_unicode/
|
||||
#ifndef ARDUINOJSON_DECODE_UNICODE
|
||||
# define ARDUINOJSON_DECODE_UNICODE 1
|
||||
#endif
|
||||
|
||||
// Ignore comments in input
|
||||
// https://arduinojson.org/v7/config/enable_comments/
|
||||
#ifndef ARDUINOJSON_ENABLE_COMMENTS
|
||||
# define ARDUINOJSON_ENABLE_COMMENTS 0
|
||||
#endif
|
||||
|
||||
// Support NaN in JSON
|
||||
// https://arduinojson.org/v7/config/enable_nan/
|
||||
#ifndef ARDUINOJSON_ENABLE_NAN
|
||||
# define ARDUINOJSON_ENABLE_NAN 0
|
||||
#endif
|
||||
|
||||
// Support Infinity in JSON
|
||||
// https://arduinojson.org/v7/config/enable_infinity/
|
||||
#ifndef ARDUINOJSON_ENABLE_INFINITY
|
||||
# define ARDUINOJSON_ENABLE_INFINITY 0
|
||||
#endif
|
||||
|
||||
// Control the exponentiation threshold for big numbers
|
||||
// CAUTION: cannot be more that 1e9 !!!!
|
||||
// https://arduinojson.org/v7/config/positive_exponentiation_threshold/
|
||||
#ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD
|
||||
# define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e7
|
||||
#endif
|
||||
|
||||
// Control the exponentiation threshold for small numbers
|
||||
// https://arduinojson.org/v7/config/negative_exponentiation_threshold/
|
||||
#ifndef ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD
|
||||
# define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5
|
||||
#endif
|
||||
@ -195,10 +261,6 @@
|
||||
# define ARDUINOJSON_TAB " "
|
||||
#endif
|
||||
|
||||
#ifndef ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
|
||||
# define ARDUINOJSON_ENABLE_STRING_DEDUPLICATION 1
|
||||
#endif
|
||||
|
||||
#ifndef ARDUINOJSON_STRING_BUFFER_SIZE
|
||||
# define ARDUINOJSON_STRING_BUFFER_SIZE 32
|
||||
#endif
|
||||
@ -211,6 +273,12 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_DOUBLE
|
||||
# define ARDUINOJSON_USE_EXTENSIONS 1
|
||||
#else
|
||||
# define ARDUINOJSON_USE_EXTENSIONS 0
|
||||
#endif
|
||||
|
||||
#if defined(nullptr)
|
||||
# error nullptr is defined as a macro. Remove the faulty #define or #undef nullptr
|
||||
// See https://github.com/bblanchon/ArduinoJson/issues/1355
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -1,17 +1,24 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
#include <ArduinoJson/Variant/JsonVariant.hpp>
|
||||
#include <ArduinoJson/Variant/VariantAttorney.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
namespace DeserializationOption {
|
||||
class Filter {
|
||||
public:
|
||||
explicit Filter(JsonVariantConst v) : variant_(v) {}
|
||||
#if ARDUINOJSON_AUTO_SHRINK
|
||||
explicit Filter(JsonDocument& doc) : variant_(doc) {
|
||||
doc.shrinkToFit();
|
||||
}
|
||||
#endif
|
||||
|
||||
explicit Filter(JsonVariantConst variant) : variant_(variant) {}
|
||||
|
||||
bool allow() const {
|
||||
return variant_;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
// The default reader is a simple wrapper for Readers that are not copiable
|
||||
// The default reader is a simple wrapper for Readers that are not copyable
|
||||
template <typename TSource, typename Enable = void>
|
||||
struct Reader {
|
||||
public:
|
||||
@ -19,7 +19,7 @@ struct Reader {
|
||||
|
||||
int read() {
|
||||
// clang-format off
|
||||
return source_->read(); // Error here? See https://arduinojson.org/v6/invalid-input/
|
||||
return source_->read(); // Error here? See https://arduinojson.org/v7/invalid-input/
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
@ -62,9 +62,8 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TInput>
|
||||
Reader<typename remove_reference<TInput>::type> makeReader(TInput&& input) {
|
||||
return Reader<typename remove_reference<TInput>::type>{
|
||||
detail::forward<TInput>(input)};
|
||||
Reader<remove_reference_t<TInput>> makeReader(TInput&& input) {
|
||||
return Reader<remove_reference_t<TInput>>{detail::forward<TInput>(input)};
|
||||
}
|
||||
|
||||
template <typename TChar>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -9,13 +9,12 @@
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TSource>
|
||||
struct Reader<TSource,
|
||||
typename enable_if<is_base_of<Stream, TSource>::value>::type> {
|
||||
struct Reader<TSource, enable_if_t<is_base_of<Stream, TSource>::value>> {
|
||||
public:
|
||||
explicit Reader(Stream& stream) : stream_(&stream) {}
|
||||
|
||||
int read() {
|
||||
// don't use stream_.read() as it ignores the timeout
|
||||
// don't use stream_->read() as it ignores the timeout
|
||||
char c;
|
||||
return stream_->readBytes(&c, 1) ? static_cast<unsigned char>(c) : -1;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -9,8 +9,7 @@
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TSource>
|
||||
struct Reader<TSource,
|
||||
typename enable_if<is_base_of<::String, TSource>::value>::type>
|
||||
struct Reader<TSource, enable_if_t<is_base_of<::String, TSource>::value>>
|
||||
: BoundedReader<const char*> {
|
||||
explicit Reader(const ::String& s)
|
||||
: BoundedReader<const char*>(s.c_str(), s.length()) {}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TIterator>
|
||||
@ -29,13 +31,8 @@ class IteratorReader {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct void_ {
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
template <typename TSource>
|
||||
struct Reader<TSource, typename void_<typename TSource::const_iterator>::type>
|
||||
struct Reader<TSource, void_t<typename TSource::const_iterator>>
|
||||
: IteratorReader<typename TSource::const_iterator> {
|
||||
explicit Reader(const TSource& source)
|
||||
: IteratorReader<typename TSource::const_iterator>(source.begin(),
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -19,8 +19,7 @@ template <typename T>
|
||||
struct IsCharOrVoid<const T> : IsCharOrVoid<T> {};
|
||||
|
||||
template <typename TSource>
|
||||
struct Reader<TSource*,
|
||||
typename enable_if<IsCharOrVoid<TSource>::value>::type> {
|
||||
struct Reader<TSource*, enable_if_t<IsCharOrVoid<TSource>::value>> {
|
||||
const char* ptr_;
|
||||
|
||||
public:
|
||||
@ -39,8 +38,7 @@ struct Reader<TSource*,
|
||||
};
|
||||
|
||||
template <typename TSource>
|
||||
struct BoundedReader<TSource*,
|
||||
typename enable_if<IsCharOrVoid<TSource>::value>::type>
|
||||
struct BoundedReader<TSource*, enable_if_t<IsCharOrVoid<TSource>::value>>
|
||||
: public IteratorReader<const char*> {
|
||||
public:
|
||||
explicit BoundedReader(const void* ptr, size_t len)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -9,8 +9,7 @@
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TSource>
|
||||
struct Reader<TSource, typename enable_if<
|
||||
is_base_of<std::istream, TSource>::value>::type> {
|
||||
struct Reader<TSource, enable_if_t<is_base_of<std::istream, TSource>::value>> {
|
||||
public:
|
||||
explicit Reader(std::istream& stream) : stream_(&stream) {}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -10,7 +10,7 @@
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TVariant>
|
||||
struct Reader<TVariant, typename enable_if<IsVariant<TVariant>::value>::type>
|
||||
struct Reader<TVariant, enable_if_t<IsVariant<TVariant>::value>>
|
||||
: Reader<char*, void> {
|
||||
explicit Reader(const TVariant& x)
|
||||
: Reader<char*, void>(x.template as<const char*>()) {}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -8,7 +8,6 @@
|
||||
#include <ArduinoJson/Deserialization/DeserializationOptions.hpp>
|
||||
#include <ArduinoJson/Deserialization/Reader.hpp>
|
||||
#include <ArduinoJson/Polyfills/utility.hpp>
|
||||
#include <ArduinoJson/StringStorage/StringStorage.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
@ -23,44 +22,58 @@ struct first_or_void<T, Rest...> {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <template <typename, typename> class TDeserializer, typename TReader,
|
||||
typename TWriter>
|
||||
TDeserializer<TReader, TWriter> makeDeserializer(MemoryPool* pool,
|
||||
TReader reader,
|
||||
TWriter writer) {
|
||||
ARDUINOJSON_ASSERT(pool != 0);
|
||||
return TDeserializer<TReader, TWriter>(pool, reader, writer);
|
||||
// A meta-function that returns true if T is a valid destination type for
|
||||
// deserialize()
|
||||
template <class T>
|
||||
using is_deserialize_destination =
|
||||
bool_constant<is_base_of<JsonDocument, remove_cv_t<T>>::value ||
|
||||
IsVariant<T>::value>;
|
||||
|
||||
template <typename TDestination>
|
||||
inline void shrinkJsonDocument(TDestination&) {
|
||||
// no-op by default
|
||||
}
|
||||
|
||||
template <template <typename, typename> class TDeserializer, typename TStream,
|
||||
typename... Args,
|
||||
typename = typename enable_if< // issue #1897
|
||||
!is_integral<typename first_or_void<Args...>::type>::value>::type>
|
||||
DeserializationError deserialize(JsonDocument& doc, TStream&& input,
|
||||
#if ARDUINOJSON_AUTO_SHRINK
|
||||
inline void shrinkJsonDocument(JsonDocument& doc) {
|
||||
doc.shrinkToFit();
|
||||
}
|
||||
#endif
|
||||
|
||||
template <template <typename> class TDeserializer, typename TDestination,
|
||||
typename TReader, typename TOptions>
|
||||
DeserializationError doDeserialize(TDestination&& dst, TReader reader,
|
||||
TOptions options) {
|
||||
auto data = VariantAttorney::getOrCreateData(dst);
|
||||
if (!data)
|
||||
return DeserializationError::NoMemory;
|
||||
auto resources = VariantAttorney::getResourceManager(dst);
|
||||
dst.clear();
|
||||
auto err = TDeserializer<TReader>(resources, reader)
|
||||
.parse(*data, options.filter, options.nestingLimit);
|
||||
shrinkJsonDocument(dst);
|
||||
return err;
|
||||
}
|
||||
|
||||
template <
|
||||
template <typename> class TDeserializer, typename TDestination,
|
||||
typename TStream, typename... Args,
|
||||
enable_if_t< // issue #1897
|
||||
!is_integral<typename first_or_void<Args...>::type>::value, int> = 0>
|
||||
DeserializationError deserialize(TDestination&& dst, TStream&& input,
|
||||
Args... args) {
|
||||
auto reader = makeReader(detail::forward<TStream>(input));
|
||||
auto data = VariantAttorney::getData(doc);
|
||||
auto pool = VariantAttorney::getPool(doc);
|
||||
auto options = makeDeserializationOptions(args...);
|
||||
doc.clear();
|
||||
return makeDeserializer<TDeserializer>(pool, reader,
|
||||
makeStringStorage(input, pool))
|
||||
.parse(*data, options.filter, options.nestingLimit);
|
||||
return doDeserialize<TDeserializer>(
|
||||
dst, makeReader(detail::forward<TStream>(input)),
|
||||
makeDeserializationOptions(args...));
|
||||
}
|
||||
|
||||
template <template <typename, typename> class TDeserializer, typename TChar,
|
||||
typename Size, typename... Args,
|
||||
typename = typename enable_if<is_integral<Size>::value>::type>
|
||||
DeserializationError deserialize(JsonDocument& doc, TChar* input,
|
||||
template <template <typename> class TDeserializer, typename TDestination,
|
||||
typename TChar, typename Size, typename... Args,
|
||||
enable_if_t<is_integral<Size>::value, int> = 0>
|
||||
DeserializationError deserialize(TDestination&& dst, TChar* input,
|
||||
Size inputSize, Args... args) {
|
||||
auto reader = makeReader(input, size_t(inputSize));
|
||||
auto data = VariantAttorney::getData(doc);
|
||||
auto pool = VariantAttorney::getPool(doc);
|
||||
auto options = makeDeserializationOptions(args...);
|
||||
doc.clear();
|
||||
return makeDeserializer<TDeserializer>(pool, reader,
|
||||
makeStringStorage(input, pool))
|
||||
.parse(*data, options.filter, options.nestingLimit);
|
||||
return doDeserialize<TDeserializer>(dst, makeReader(input, size_t(inputSize)),
|
||||
makeDeserializationOptions(args...));
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
||||
@ -1,168 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Document/JsonDocument.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// Helper to implement the "base-from-member" idiom
|
||||
// (we need to store the allocator before constructing JsonDocument)
|
||||
template <typename TAllocator>
|
||||
class AllocatorOwner {
|
||||
public:
|
||||
AllocatorOwner() {}
|
||||
AllocatorOwner(TAllocator a) : allocator_(a) {}
|
||||
|
||||
void* allocate(size_t size) {
|
||||
return allocator_.allocate(size);
|
||||
}
|
||||
|
||||
void deallocate(void* ptr) {
|
||||
if (ptr)
|
||||
allocator_.deallocate(ptr);
|
||||
}
|
||||
|
||||
void* reallocate(void* ptr, size_t new_size) {
|
||||
return allocator_.reallocate(ptr, new_size);
|
||||
}
|
||||
|
||||
TAllocator& allocator() {
|
||||
return allocator_;
|
||||
}
|
||||
|
||||
private:
|
||||
TAllocator allocator_;
|
||||
};
|
||||
|
||||
// A JsonDocument that uses the provided allocator to allocate its memory pool.
|
||||
// https://arduinojson.org/v6/api/basicjsondocument/
|
||||
template <typename TAllocator>
|
||||
class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument {
|
||||
public:
|
||||
explicit BasicJsonDocument(size_t capa, TAllocator alloc = TAllocator())
|
||||
: AllocatorOwner<TAllocator>(alloc), JsonDocument(allocPool(capa)) {}
|
||||
|
||||
// Copy-constructor
|
||||
BasicJsonDocument(const BasicJsonDocument& src)
|
||||
: AllocatorOwner<TAllocator>(src), JsonDocument() {
|
||||
copyAssignFrom(src);
|
||||
}
|
||||
|
||||
// Move-constructor
|
||||
BasicJsonDocument(BasicJsonDocument&& src) : AllocatorOwner<TAllocator>(src) {
|
||||
moveAssignFrom(src);
|
||||
}
|
||||
|
||||
BasicJsonDocument(const JsonDocument& src) {
|
||||
copyAssignFrom(src);
|
||||
}
|
||||
|
||||
// Construct from variant, array, or object
|
||||
template <typename T>
|
||||
BasicJsonDocument(const T& src,
|
||||
typename detail::enable_if<
|
||||
detail::is_same<T, JsonVariant>::value ||
|
||||
detail::is_same<T, JsonVariantConst>::value ||
|
||||
detail::is_same<T, JsonArray>::value ||
|
||||
detail::is_same<T, JsonArrayConst>::value ||
|
||||
detail::is_same<T, JsonObject>::value ||
|
||||
detail::is_same<T, JsonObjectConst>::value>::type* = 0)
|
||||
: JsonDocument(allocPool(src.memoryUsage())) {
|
||||
set(src);
|
||||
}
|
||||
|
||||
// disambiguate
|
||||
BasicJsonDocument(JsonVariant src)
|
||||
: JsonDocument(allocPool(src.memoryUsage())) {
|
||||
set(src);
|
||||
}
|
||||
|
||||
~BasicJsonDocument() {
|
||||
freePool();
|
||||
}
|
||||
|
||||
BasicJsonDocument& operator=(const BasicJsonDocument& src) {
|
||||
copyAssignFrom(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
BasicJsonDocument& operator=(BasicJsonDocument&& src) {
|
||||
moveAssignFrom(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
BasicJsonDocument& operator=(const T& src) {
|
||||
size_t requiredSize = src.memoryUsage();
|
||||
if (requiredSize > capacity())
|
||||
reallocPool(requiredSize);
|
||||
set(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Reduces the capacity of the memory pool to match the current usage.
|
||||
// https://arduinojson.org/v6/api/basicjsondocument/shrinktofit/
|
||||
void shrinkToFit() {
|
||||
ptrdiff_t bytes_reclaimed = pool_.squash();
|
||||
if (bytes_reclaimed == 0)
|
||||
return;
|
||||
|
||||
void* old_ptr = pool_.buffer();
|
||||
void* new_ptr = this->reallocate(old_ptr, pool_.capacity());
|
||||
|
||||
ptrdiff_t ptr_offset =
|
||||
static_cast<char*>(new_ptr) - static_cast<char*>(old_ptr);
|
||||
|
||||
pool_.movePointers(ptr_offset);
|
||||
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() {
|
||||
// make a temporary clone and move assign
|
||||
BasicJsonDocument tmp(*this);
|
||||
if (!tmp.capacity())
|
||||
return false;
|
||||
moveAssignFrom(tmp);
|
||||
return true;
|
||||
}
|
||||
|
||||
using AllocatorOwner<TAllocator>::allocator;
|
||||
|
||||
private:
|
||||
detail::MemoryPool allocPool(size_t requiredSize) {
|
||||
size_t capa = detail::addPadding(requiredSize);
|
||||
return {reinterpret_cast<char*>(this->allocate(capa)), capa};
|
||||
}
|
||||
|
||||
void reallocPool(size_t requiredSize) {
|
||||
size_t capa = detail::addPadding(requiredSize);
|
||||
if (capa == pool_.capacity())
|
||||
return;
|
||||
freePool();
|
||||
replacePool(allocPool(detail::addPadding(requiredSize)));
|
||||
}
|
||||
|
||||
void freePool() {
|
||||
this->deallocate(getPool()->buffer());
|
||||
}
|
||||
|
||||
void copyAssignFrom(const JsonDocument& src) {
|
||||
reallocPool(src.capacity());
|
||||
set(src);
|
||||
}
|
||||
|
||||
void moveAssignFrom(BasicJsonDocument& src) {
|
||||
freePool();
|
||||
data_ = src.data_;
|
||||
pool_ = src.pool_;
|
||||
src.data_.setNull();
|
||||
src.pool_ = {0, 0};
|
||||
}
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@ -1,32 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Document/BasicJsonDocument.hpp>
|
||||
|
||||
#include <stdlib.h> // malloc, free
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// The allocator of DynamicJsonDocument.
|
||||
struct DefaultAllocator {
|
||||
void* allocate(size_t size) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void deallocate(void* ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void* reallocate(void* ptr, size_t new_size) {
|
||||
return realloc(ptr, new_size);
|
||||
}
|
||||
};
|
||||
|
||||
// A JsonDocument with a memory pool in the heap.
|
||||
// https://arduinojson.org/v6/api/dynamicjsondocument/
|
||||
typedef BasicJsonDocument<DefaultAllocator> DynamicJsonDocument;
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@ -1,308 +1,406 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Array/ElementProxy.hpp>
|
||||
#include <ArduinoJson/Memory/MemoryPool.hpp>
|
||||
#include <ArduinoJson/Memory/Allocator.hpp>
|
||||
#include <ArduinoJson/Memory/ResourceManager.hpp>
|
||||
#include <ArduinoJson/Object/JsonObject.hpp>
|
||||
#include <ArduinoJson/Object/MemberProxy.hpp>
|
||||
#include <ArduinoJson/Strings/StoragePolicy.hpp>
|
||||
#include <ArduinoJson/Polyfills/utility.hpp>
|
||||
#include <ArduinoJson/Variant/JsonVariantConst.hpp>
|
||||
#include <ArduinoJson/Variant/VariantTo.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// A JSON document.
|
||||
// https://arduinojson.org/v6/api/jsondocument/
|
||||
// https://arduinojson.org/v7/api/jsondocument/
|
||||
class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
friend class detail::VariantAttorney;
|
||||
|
||||
public:
|
||||
JsonDocument(const JsonDocument&) = delete;
|
||||
JsonDocument& operator=(const JsonDocument&) = delete;
|
||||
explicit JsonDocument(Allocator* alloc = detail::DefaultAllocator::instance())
|
||||
: resources_(alloc) {}
|
||||
|
||||
// Copy-constructor
|
||||
JsonDocument(const JsonDocument& src) : JsonDocument(src.allocator()) {
|
||||
set(src);
|
||||
}
|
||||
|
||||
// Move-constructor
|
||||
JsonDocument(JsonDocument&& src)
|
||||
: JsonDocument(detail::DefaultAllocator::instance()) {
|
||||
swap(*this, src);
|
||||
}
|
||||
|
||||
// Construct from variant, array, or object
|
||||
template <typename T,
|
||||
detail::enable_if_t<detail::IsVariant<T>::value ||
|
||||
detail::is_same<T, JsonArray>::value ||
|
||||
detail::is_same<T, JsonArrayConst>::value ||
|
||||
detail::is_same<T, JsonObject>::value ||
|
||||
detail::is_same<T, JsonObjectConst>::value,
|
||||
int> = 0>
|
||||
JsonDocument(const T& src,
|
||||
Allocator* alloc = detail::DefaultAllocator::instance())
|
||||
: JsonDocument(alloc) {
|
||||
set(src);
|
||||
}
|
||||
|
||||
JsonDocument& operator=(JsonDocument src) {
|
||||
swap(*this, src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
JsonDocument& operator=(const T& src) {
|
||||
set(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Allocator* allocator() const {
|
||||
return resources_.allocator();
|
||||
}
|
||||
|
||||
// Reduces the capacity of the memory pool to match the current usage.
|
||||
// https://arduinojson.org/v7/api/jsondocument/shrinktofit/
|
||||
void shrinkToFit() {
|
||||
resources_.shrinkToFit();
|
||||
}
|
||||
|
||||
// Casts the root to the specified type.
|
||||
// https://arduinojson.org/v6/api/jsondocument/as/
|
||||
// https://arduinojson.org/v7/api/jsondocument/as/
|
||||
template <typename T>
|
||||
T as() {
|
||||
return getVariant().template as<T>();
|
||||
}
|
||||
|
||||
// Casts the root to the specified type.
|
||||
// https://arduinojson.org/v6/api/jsondocument/as/
|
||||
// https://arduinojson.org/v7/api/jsondocument/as/
|
||||
template <typename T>
|
||||
T as() const {
|
||||
return getVariant().template as<T>();
|
||||
}
|
||||
|
||||
// Empties the document and resets the memory pool
|
||||
// https://arduinojson.org/v6/api/jsondocument/clear/
|
||||
// https://arduinojson.org/v7/api/jsondocument/clear/
|
||||
void clear() {
|
||||
pool_.clear();
|
||||
data_.setNull();
|
||||
resources_.clear();
|
||||
data_.reset();
|
||||
}
|
||||
|
||||
// Returns true if the root is of the specified type.
|
||||
// https://arduinojson.org/v6/api/jsondocument/is/
|
||||
// https://arduinojson.org/v7/api/jsondocument/is/
|
||||
template <typename T>
|
||||
bool is() {
|
||||
return getVariant().template is<T>();
|
||||
}
|
||||
|
||||
// Returns true if the root is of the specified type.
|
||||
// https://arduinojson.org/v6/api/jsondocument/is/
|
||||
// https://arduinojson.org/v7/api/jsondocument/is/
|
||||
template <typename T>
|
||||
bool is() const {
|
||||
return getVariant().template is<T>();
|
||||
}
|
||||
|
||||
// Returns true if the root is null.
|
||||
// https://arduinojson.org/v6/api/jsondocument/isnull/
|
||||
// https://arduinojson.org/v7/api/jsondocument/isnull/
|
||||
bool isNull() const {
|
||||
return getVariant().isNull();
|
||||
}
|
||||
|
||||
// Returns the number of used bytes in the memory pool.
|
||||
// https://arduinojson.org/v6/api/jsondocument/memoryusage/
|
||||
size_t memoryUsage() const {
|
||||
return pool_.size();
|
||||
}
|
||||
|
||||
// Returns trues if the memory pool was too small.
|
||||
// https://arduinojson.org/v6/api/jsondocument/overflowed/
|
||||
// https://arduinojson.org/v7/api/jsondocument/overflowed/
|
||||
bool overflowed() const {
|
||||
return pool_.overflowed();
|
||||
return resources_.overflowed();
|
||||
}
|
||||
|
||||
// Returns the depth (nesting level) of the array.
|
||||
// https://arduinojson.org/v6/api/jsondocument/nesting/
|
||||
// https://arduinojson.org/v7/api/jsondocument/nesting/
|
||||
size_t nesting() const {
|
||||
return variantNesting(&data_);
|
||||
}
|
||||
|
||||
// Returns the capacity of the memory pool.
|
||||
// https://arduinojson.org/v6/api/jsondocument/capacity/
|
||||
size_t capacity() const {
|
||||
return pool_.capacity();
|
||||
return data_.nesting(&resources_);
|
||||
}
|
||||
|
||||
// Returns the number of elements in the root array or object.
|
||||
// https://arduinojson.org/v6/api/jsondocument/size/
|
||||
// https://arduinojson.org/v7/api/jsondocument/size/
|
||||
size_t size() const {
|
||||
return data_.size();
|
||||
return data_.size(&resources_);
|
||||
}
|
||||
|
||||
// Copies the specified document.
|
||||
// https://arduinojson.org/v6/api/jsondocument/set/
|
||||
// https://arduinojson.org/v7/api/jsondocument/set/
|
||||
bool set(const JsonDocument& src) {
|
||||
return to<JsonVariant>().set(src.as<JsonVariantConst>());
|
||||
}
|
||||
|
||||
// Replaces the root with the specified value.
|
||||
// https://arduinojson.org/v6/api/jsondocument/set/
|
||||
template <typename T>
|
||||
typename detail::enable_if<!detail::is_base_of<JsonDocument, T>::value,
|
||||
bool>::type
|
||||
set(const T& src) {
|
||||
// https://arduinojson.org/v7/api/jsondocument/set/
|
||||
template <
|
||||
typename T,
|
||||
detail::enable_if_t<!detail::is_base_of<JsonDocument, T>::value, int> = 0>
|
||||
bool set(const T& src) {
|
||||
return to<JsonVariant>().set(src);
|
||||
}
|
||||
|
||||
// Replaces the root with the specified value.
|
||||
// https://arduinojson.org/v7/api/jsondocument/set/
|
||||
template <typename TChar,
|
||||
detail::enable_if_t<!detail::is_const<TChar>::value, int> = 0>
|
||||
bool set(TChar* src) {
|
||||
return to<JsonVariant>().set(src);
|
||||
}
|
||||
|
||||
// Clears the document and converts it to the specified type.
|
||||
// https://arduinojson.org/v6/api/jsondocument/to/
|
||||
// https://arduinojson.org/v7/api/jsondocument/to/
|
||||
template <typename T>
|
||||
typename detail::VariantTo<T>::type to() {
|
||||
clear();
|
||||
return getVariant().template to<T>();
|
||||
}
|
||||
|
||||
// Creates an array and appends it to the root array.
|
||||
// https://arduinojson.org/v6/api/jsondocument/createnestedarray/
|
||||
JsonArray createNestedArray() {
|
||||
return add().to<JsonArray>();
|
||||
}
|
||||
|
||||
// Creates an array and adds it to the root object.
|
||||
// https://arduinojson.org/v6/api/jsondocument/createnestedarray/
|
||||
template <typename TChar>
|
||||
JsonArray createNestedArray(TChar* key) {
|
||||
return operator[](key).template to<JsonArray>();
|
||||
}
|
||||
|
||||
// Creates an array and adds it to the root object.
|
||||
// https://arduinojson.org/v6/api/jsondocument/createnestedarray/
|
||||
template <typename TString>
|
||||
JsonArray createNestedArray(const TString& key) {
|
||||
return operator[](key).template to<JsonArray>();
|
||||
}
|
||||
|
||||
// Creates an object and appends it to the root array.
|
||||
// https://arduinojson.org/v6/api/jsondocument/createnestedobject/
|
||||
JsonObject createNestedObject() {
|
||||
return add().to<JsonObject>();
|
||||
}
|
||||
|
||||
// Creates an object and adds it to the root object.
|
||||
// https://arduinojson.org/v6/api/jsondocument/createnestedobject/
|
||||
template <typename TChar>
|
||||
JsonObject createNestedObject(TChar* key) {
|
||||
return operator[](key).template to<JsonObject>();
|
||||
}
|
||||
|
||||
// Creates an object and adds it to the root object.
|
||||
// https://arduinojson.org/v6/api/jsondocument/createnestedobject/
|
||||
template <typename TString>
|
||||
JsonObject createNestedObject(const TString& key) {
|
||||
return operator[](key).template to<JsonObject>();
|
||||
}
|
||||
|
||||
// Returns true if the root object contains the specified key.
|
||||
// https://arduinojson.org/v6/api/jsondocument/containskey/
|
||||
// DEPRECATED: use obj["key"].is<T>() instead
|
||||
// https://arduinojson.org/v7/api/jsondocument/containskey/
|
||||
template <typename TChar>
|
||||
ARDUINOJSON_DEPRECATED("use doc[\"key\"].is<T>() instead")
|
||||
bool containsKey(TChar* key) const {
|
||||
return data_.getMember(detail::adaptString(key)) != 0;
|
||||
return data_.getMember(detail::adaptString(key), &resources_) != 0;
|
||||
}
|
||||
|
||||
// Returns true if the root object contains the specified key.
|
||||
// https://arduinojson.org/v6/api/jsondocument/containskey/
|
||||
template <typename TString>
|
||||
// DEPRECATED: use obj[key].is<T>() instead
|
||||
// https://arduinojson.org/v7/api/jsondocument/containskey/
|
||||
template <typename TString,
|
||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||
ARDUINOJSON_DEPRECATED("use doc[key].is<T>() instead")
|
||||
bool containsKey(const TString& key) const {
|
||||
return data_.getMember(detail::adaptString(key)) != 0;
|
||||
return data_.getMember(detail::adaptString(key), &resources_) != 0;
|
||||
}
|
||||
|
||||
// DEPRECATED: use obj[key].is<T>() instead
|
||||
// https://arduinojson.org/v7/api/jsondocument/containskey/
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
ARDUINOJSON_DEPRECATED("use doc[key].is<T>() instead")
|
||||
bool containsKey(const TVariant& key) const {
|
||||
return containsKey(key.template as<const char*>());
|
||||
}
|
||||
|
||||
// Gets or sets a root object's member.
|
||||
// https://arduinojson.org/v6/api/jsondocument/subscript/
|
||||
template <typename TString>
|
||||
FORCE_INLINE typename detail::enable_if<
|
||||
detail::IsString<TString>::value,
|
||||
detail::MemberProxy<JsonDocument&, TString>>::type
|
||||
operator[](const TString& key) {
|
||||
return {*this, key};
|
||||
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||
template <typename TString,
|
||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||
detail::MemberProxy<JsonDocument&, detail::AdaptedString<TString>> operator[](
|
||||
const TString& key) {
|
||||
return {*this, detail::adaptString(key)};
|
||||
}
|
||||
|
||||
// Gets or sets a root object's member.
|
||||
// https://arduinojson.org/v6/api/jsondocument/subscript/
|
||||
template <typename TChar>
|
||||
FORCE_INLINE typename detail::enable_if<
|
||||
detail::IsString<TChar*>::value,
|
||||
detail::MemberProxy<JsonDocument&, TChar*>>::type
|
||||
operator[](TChar* key) {
|
||||
return {*this, key};
|
||||
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||
template <typename TChar,
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value &&
|
||||
!detail::is_const<TChar>::value,
|
||||
int> = 0>
|
||||
detail::MemberProxy<JsonDocument&, detail::AdaptedString<TChar*>> operator[](
|
||||
TChar* key) {
|
||||
return {*this, detail::adaptString(key)};
|
||||
}
|
||||
|
||||
// Gets a root object's member.
|
||||
// https://arduinojson.org/v6/api/jsondocument/subscript/
|
||||
template <typename TString>
|
||||
FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value,
|
||||
JsonVariantConst>::type
|
||||
operator[](const TString& key) const {
|
||||
return JsonVariantConst(data_.getMember(detail::adaptString(key)));
|
||||
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||
template <typename TString,
|
||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||
JsonVariantConst operator[](const TString& key) const {
|
||||
return JsonVariantConst(
|
||||
data_.getMember(detail::adaptString(key), &resources_), &resources_);
|
||||
}
|
||||
|
||||
// Gets a root object's member.
|
||||
// https://arduinojson.org/v6/api/jsondocument/subscript/
|
||||
template <typename TChar>
|
||||
FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value,
|
||||
JsonVariantConst>::type
|
||||
operator[](TChar* key) const {
|
||||
return JsonVariantConst(data_.getMember(detail::adaptString(key)));
|
||||
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||
template <typename TChar,
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value &&
|
||||
!detail::is_const<TChar>::value,
|
||||
int> = 0>
|
||||
JsonVariantConst operator[](TChar* key) const {
|
||||
return JsonVariantConst(
|
||||
data_.getMember(detail::adaptString(key), &resources_), &resources_);
|
||||
}
|
||||
|
||||
// Gets or sets a root array's element.
|
||||
// https://arduinojson.org/v6/api/jsondocument/subscript/
|
||||
FORCE_INLINE detail::ElementProxy<JsonDocument&> operator[](size_t index) {
|
||||
return {*this, index};
|
||||
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||
template <typename T,
|
||||
detail::enable_if_t<detail::is_integral<T>::value, int> = 0>
|
||||
detail::ElementProxy<JsonDocument&> operator[](T index) {
|
||||
return {*this, size_t(index)};
|
||||
}
|
||||
|
||||
// Gets a root array's member.
|
||||
// https://arduinojson.org/v6/api/jsondocument/subscript/
|
||||
FORCE_INLINE JsonVariantConst operator[](size_t index) const {
|
||||
return JsonVariantConst(data_.getElement(index));
|
||||
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||
JsonVariantConst operator[](size_t index) const {
|
||||
return JsonVariantConst(data_.getElement(index, &resources_), &resources_);
|
||||
}
|
||||
|
||||
// Gets or sets a root object's member.
|
||||
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
JsonVariantConst operator[](const TVariant& key) const {
|
||||
if (key.template is<JsonString>())
|
||||
return operator[](key.template as<JsonString>());
|
||||
if (key.template is<size_t>())
|
||||
return operator[](key.template as<size_t>());
|
||||
return {};
|
||||
}
|
||||
|
||||
// Appends a new (empty) element to the root array.
|
||||
// Returns a reference to the new element.
|
||||
// https://arduinojson.org/v7/api/jsondocument/add/
|
||||
template <typename T, detail::enable_if_t<
|
||||
!detail::is_same<T, JsonVariant>::value, int> = 0>
|
||||
T add() {
|
||||
return add<JsonVariant>().to<T>();
|
||||
}
|
||||
|
||||
// Appends a new (null) element to the root array.
|
||||
// Returns a reference to the new element.
|
||||
// https://arduinojson.org/v6/api/jsondocument/add/
|
||||
FORCE_INLINE JsonVariant add() {
|
||||
return JsonVariant(&pool_, data_.addElement(&pool_));
|
||||
// https://arduinojson.org/v7/api/jsondocument/add/
|
||||
template <typename T, detail::enable_if_t<
|
||||
detail::is_same<T, JsonVariant>::value, int> = 0>
|
||||
JsonVariant add() {
|
||||
return JsonVariant(data_.addElement(&resources_), &resources_);
|
||||
}
|
||||
|
||||
// Appends a value to the root array.
|
||||
// https://arduinojson.org/v6/api/jsondocument/add/
|
||||
// https://arduinojson.org/v7/api/jsondocument/add/
|
||||
template <typename TValue>
|
||||
FORCE_INLINE bool add(const TValue& value) {
|
||||
return add().set(value);
|
||||
bool add(const TValue& value) {
|
||||
return data_.addValue(value, &resources_);
|
||||
}
|
||||
|
||||
// Appends a value to the root array.
|
||||
// https://arduinojson.org/v6/api/jsondocument/add/
|
||||
template <typename TChar>
|
||||
FORCE_INLINE bool add(TChar* value) {
|
||||
return add().set(value);
|
||||
// https://arduinojson.org/v7/api/jsondocument/add/
|
||||
template <typename TChar,
|
||||
detail::enable_if_t<!detail::is_const<TChar>::value, int> = 0>
|
||||
bool add(TChar* value) {
|
||||
return data_.addValue(value, &resources_);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
data_.remove(index);
|
||||
// https://arduinojson.org/v7/api/jsondocument/remove/
|
||||
template <typename T,
|
||||
detail::enable_if_t<detail::is_integral<T>::value, int> = 0>
|
||||
void remove(T index) {
|
||||
detail::VariantData::removeElement(getData(), size_t(index),
|
||||
getResourceManager());
|
||||
}
|
||||
|
||||
// Removes a member of the root object.
|
||||
// ⚠️ Doesn't release the memory associated with the removed element.
|
||||
// https://arduinojson.org/v6/api/jsondocument/remove/
|
||||
// https://arduinojson.org/v7/api/jsondocument/remove/
|
||||
template <typename TChar,
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value &&
|
||||
!detail::is_const<TChar>::value,
|
||||
int> = 0>
|
||||
void remove(TChar* key) {
|
||||
detail::VariantData::removeMember(getData(), detail::adaptString(key),
|
||||
getResourceManager());
|
||||
}
|
||||
|
||||
// Removes a member of the root object.
|
||||
// https://arduinojson.org/v7/api/jsondocument/remove/
|
||||
template <typename TString,
|
||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||
void remove(const TString& key) {
|
||||
detail::VariantData::removeMember(getData(), detail::adaptString(key),
|
||||
getResourceManager());
|
||||
}
|
||||
|
||||
// Removes a member of the root object or an element of the root array.
|
||||
// https://arduinojson.org/v7/api/jsondocument/remove/
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
void remove(const TVariant& key) {
|
||||
if (key.template is<const char*>())
|
||||
remove(key.template as<const char*>());
|
||||
if (key.template is<size_t>())
|
||||
remove(key.template as<size_t>());
|
||||
}
|
||||
|
||||
operator JsonVariant() {
|
||||
return getVariant();
|
||||
}
|
||||
|
||||
operator JsonVariantConst() const {
|
||||
return getVariant();
|
||||
}
|
||||
|
||||
friend void swap(JsonDocument& a, JsonDocument& b) {
|
||||
swap(a.resources_, b.resources_);
|
||||
swap_(a.data_, b.data_);
|
||||
}
|
||||
|
||||
// DEPRECATED: use add<JsonVariant>() instead
|
||||
ARDUINOJSON_DEPRECATED("use add<JsonVariant>() instead")
|
||||
JsonVariant add() {
|
||||
return add<JsonVariant>();
|
||||
}
|
||||
|
||||
// DEPRECATED: use add<JsonArray>() instead
|
||||
ARDUINOJSON_DEPRECATED("use add<JsonArray>() instead")
|
||||
JsonArray createNestedArray() {
|
||||
return add<JsonArray>();
|
||||
}
|
||||
|
||||
// DEPRECATED: use doc[key].to<JsonArray>() instead
|
||||
template <typename TChar>
|
||||
FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value>::type
|
||||
remove(TChar* key) {
|
||||
data_.remove(detail::adaptString(key));
|
||||
ARDUINOJSON_DEPRECATED("use doc[key].to<JsonArray>() instead")
|
||||
JsonArray createNestedArray(TChar* key) {
|
||||
return operator[](key).template to<JsonArray>();
|
||||
}
|
||||
|
||||
// Removes a member of the root object.
|
||||
// ⚠️ Doesn't release the memory associated with the removed element.
|
||||
// https://arduinojson.org/v6/api/jsondocument/remove/
|
||||
// DEPRECATED: use doc[key].to<JsonArray>() instead
|
||||
template <typename TString>
|
||||
FORCE_INLINE
|
||||
typename detail::enable_if<detail::IsString<TString>::value>::type
|
||||
remove(const TString& key) {
|
||||
data_.remove(detail::adaptString(key));
|
||||
ARDUINOJSON_DEPRECATED("use doc[key].to<JsonArray>() instead")
|
||||
JsonArray createNestedArray(const TString& key) {
|
||||
return operator[](key).template to<JsonArray>();
|
||||
}
|
||||
|
||||
FORCE_INLINE operator JsonVariant() {
|
||||
return getVariant();
|
||||
// DEPRECATED: use add<JsonObject>() instead
|
||||
ARDUINOJSON_DEPRECATED("use add<JsonObject>() instead")
|
||||
JsonObject createNestedObject() {
|
||||
return add<JsonObject>();
|
||||
}
|
||||
|
||||
FORCE_INLINE operator JsonVariantConst() const {
|
||||
return getVariant();
|
||||
// DEPRECATED: use doc[key].to<JsonObject>() instead
|
||||
template <typename TChar>
|
||||
ARDUINOJSON_DEPRECATED("use doc[key].to<JsonObject>() instead")
|
||||
JsonObject createNestedObject(TChar* key) {
|
||||
return operator[](key).template to<JsonObject>();
|
||||
}
|
||||
|
||||
protected:
|
||||
JsonDocument() : pool_(0, 0) {}
|
||||
|
||||
JsonDocument(detail::MemoryPool pool) : pool_(pool) {}
|
||||
|
||||
JsonDocument(char* buf, size_t capa) : pool_(buf, capa) {}
|
||||
|
||||
~JsonDocument() {}
|
||||
|
||||
void replacePool(detail::MemoryPool pool) {
|
||||
pool_ = pool;
|
||||
// DEPRECATED: use doc[key].to<JsonObject>() instead
|
||||
template <typename TString>
|
||||
ARDUINOJSON_DEPRECATED("use doc[key].to<JsonObject>() instead")
|
||||
JsonObject createNestedObject(const TString& key) {
|
||||
return operator[](key).template to<JsonObject>();
|
||||
}
|
||||
|
||||
// DEPRECATED: always returns zero
|
||||
ARDUINOJSON_DEPRECATED("always returns zero")
|
||||
size_t memoryUsage() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
JsonVariant getVariant() {
|
||||
return JsonVariant(&pool_, &data_);
|
||||
return JsonVariant(&data_, &resources_);
|
||||
}
|
||||
|
||||
JsonVariantConst getVariant() const {
|
||||
return JsonVariantConst(&data_);
|
||||
return JsonVariantConst(&data_, &resources_);
|
||||
}
|
||||
|
||||
detail::MemoryPool pool_;
|
||||
detail::VariantData data_;
|
||||
|
||||
protected:
|
||||
detail::MemoryPool* getPool() {
|
||||
return &pool_;
|
||||
detail::ResourceManager* getResourceManager() {
|
||||
return &resources_;
|
||||
}
|
||||
|
||||
detail::VariantData* getData() {
|
||||
@ -316,6 +414,9 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
detail::VariantData* getOrCreateData() {
|
||||
return &data_;
|
||||
}
|
||||
|
||||
detail::ResourceManager resources_;
|
||||
detail::VariantData data_;
|
||||
};
|
||||
|
||||
inline void convertToJson(const JsonDocument& src, JsonVariant dst) {
|
||||
|
||||
@ -1,61 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Document/JsonDocument.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// A JsonDocument with a memory pool on the stack.
|
||||
template <size_t desiredCapacity>
|
||||
class StaticJsonDocument : public JsonDocument {
|
||||
static const size_t capacity_ =
|
||||
detail::AddPadding<detail::Max<1, desiredCapacity>::value>::value;
|
||||
|
||||
public:
|
||||
StaticJsonDocument() : JsonDocument(buffer_, capacity_) {}
|
||||
|
||||
StaticJsonDocument(const StaticJsonDocument& src)
|
||||
: JsonDocument(buffer_, capacity_) {
|
||||
set(src);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
StaticJsonDocument(
|
||||
const T& src,
|
||||
typename detail::enable_if<
|
||||
detail::is_convertible<T, JsonVariantConst>::value>::type* = 0)
|
||||
: JsonDocument(buffer_, capacity_) {
|
||||
set(src);
|
||||
}
|
||||
|
||||
// disambiguate
|
||||
StaticJsonDocument(JsonVariant src) : JsonDocument(buffer_, capacity_) {
|
||||
set(src);
|
||||
}
|
||||
|
||||
StaticJsonDocument& operator=(const StaticJsonDocument& src) {
|
||||
set(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
StaticJsonDocument& operator=(const T& src) {
|
||||
set(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Reclaims the memory leaked when removing and replacing values.
|
||||
// https://arduinojson.org/v6/api/jsondocument/garbagecollect/
|
||||
void garbageCollect() {
|
||||
StaticJsonDocument tmp(*this);
|
||||
set(tmp);
|
||||
}
|
||||
|
||||
private:
|
||||
char buffer_[capacity_];
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -32,8 +32,8 @@ class EscapeSequence {
|
||||
}
|
||||
|
||||
private:
|
||||
static const char* escapeTable(bool excludeSolidus) {
|
||||
return &"//\"\"\\\\b\bf\fn\nr\rt\t"[excludeSolidus ? 2 : 0];
|
||||
static const char* escapeTable(bool isSerializing) {
|
||||
return &"//''\"\"\\\\b\bf\fn\nr\rt\t"[isSerializing ? 4 : 0];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -9,7 +9,7 @@
|
||||
#include <ArduinoJson/Json/Latch.hpp>
|
||||
#include <ArduinoJson/Json/Utf16.hpp>
|
||||
#include <ArduinoJson/Json/Utf8.hpp>
|
||||
#include <ArduinoJson/Memory/MemoryPool.hpp>
|
||||
#include <ArduinoJson/Memory/ResourceManager.hpp>
|
||||
#include <ArduinoJson/Numbers/parseNumber.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||
@ -18,15 +18,14 @@
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TReader, typename TStringStorage>
|
||||
template <typename TReader>
|
||||
class JsonDeserializer {
|
||||
public:
|
||||
JsonDeserializer(MemoryPool* pool, TReader reader,
|
||||
TStringStorage stringStorage)
|
||||
: stringStorage_(stringStorage),
|
||||
JsonDeserializer(ResourceManager* resources, TReader reader)
|
||||
: stringBuilder_(resources),
|
||||
foundSomething_(false),
|
||||
latch_(reader),
|
||||
pool_(pool) {}
|
||||
resources_(resources) {}
|
||||
|
||||
template <typename TFilter>
|
||||
DeserializationError parse(VariantData& variant, TFilter filter,
|
||||
@ -35,7 +34,7 @@ class JsonDeserializer {
|
||||
|
||||
err = parseVariant(variant, filter, nestingLimit);
|
||||
|
||||
if (!err && latch_.last() != 0 && !variant.isEnclosed()) {
|
||||
if (!err && latch_.last() != 0 && variant.isFloat()) {
|
||||
// We don't detect trailing characters earlier, so we need to check now
|
||||
return DeserializationError::InvalidInput;
|
||||
}
|
||||
@ -147,7 +146,7 @@ class JsonDeserializer {
|
||||
|
||||
template <typename TFilter>
|
||||
DeserializationError::Code parseArray(
|
||||
CollectionData& array, TFilter filter,
|
||||
ArrayData& array, TFilter filter,
|
||||
DeserializationOption::NestingLimit nestingLimit) {
|
||||
DeserializationError::Code err;
|
||||
|
||||
@ -167,18 +166,18 @@ class JsonDeserializer {
|
||||
if (eat(']'))
|
||||
return DeserializationError::Ok;
|
||||
|
||||
TFilter memberFilter = filter[0UL];
|
||||
TFilter elementFilter = filter[0UL];
|
||||
|
||||
// Read each value
|
||||
for (;;) {
|
||||
if (memberFilter.allow()) {
|
||||
if (elementFilter.allow()) {
|
||||
// Allocate slot in array
|
||||
VariantData* value = array.addElement(pool_);
|
||||
VariantData* value = array.addElement(resources_);
|
||||
if (!value)
|
||||
return DeserializationError::NoMemory;
|
||||
|
||||
// 1 - Parse value
|
||||
err = parseVariant(*value, memberFilter, nestingLimit.decrement());
|
||||
err = parseVariant(*value, elementFilter, nestingLimit.decrement());
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
@ -233,7 +232,7 @@ class JsonDeserializer {
|
||||
|
||||
template <typename TFilter>
|
||||
DeserializationError::Code parseObject(
|
||||
CollectionData& object, TFilter filter,
|
||||
ObjectData& object, TFilter filter,
|
||||
DeserializationOption::NestingLimit nestingLimit) {
|
||||
DeserializationError::Code err;
|
||||
|
||||
@ -269,29 +268,24 @@ class JsonDeserializer {
|
||||
if (!eat(':'))
|
||||
return DeserializationError::InvalidInput;
|
||||
|
||||
JsonString key = stringStorage_.str();
|
||||
JsonString key = stringBuilder_.str();
|
||||
|
||||
TFilter memberFilter = filter[key.c_str()];
|
||||
TFilter memberFilter = filter[key];
|
||||
|
||||
if (memberFilter.allow()) {
|
||||
VariantData* variant = object.getMember(adaptString(key.c_str()));
|
||||
if (!variant) {
|
||||
// Save key in memory pool.
|
||||
// This MUST be done before adding the slot.
|
||||
key = stringStorage_.save();
|
||||
|
||||
// Allocate slot in object
|
||||
VariantSlot* slot = object.addSlot(pool_);
|
||||
if (!slot)
|
||||
auto member = object.getMember(adaptString(key), resources_);
|
||||
if (!member) {
|
||||
auto keyVariant = object.addPair(&member, resources_);
|
||||
if (!keyVariant)
|
||||
return DeserializationError::NoMemory;
|
||||
|
||||
slot->setKey(key);
|
||||
|
||||
variant = slot->data();
|
||||
stringBuilder_.save(keyVariant);
|
||||
} else {
|
||||
member->clear(resources_);
|
||||
}
|
||||
|
||||
// Parse value
|
||||
err = parseVariant(*variant, memberFilter, nestingLimit.decrement());
|
||||
err = parseVariant(*member, memberFilter, nestingLimit.decrement());
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
@ -377,7 +371,7 @@ class JsonDeserializer {
|
||||
}
|
||||
|
||||
DeserializationError::Code parseKey() {
|
||||
stringStorage_.startString();
|
||||
stringBuilder_.startString();
|
||||
if (isQuote(current())) {
|
||||
return parseQuotedString();
|
||||
} else {
|
||||
@ -388,13 +382,13 @@ class JsonDeserializer {
|
||||
DeserializationError::Code parseStringValue(VariantData& variant) {
|
||||
DeserializationError::Code err;
|
||||
|
||||
stringStorage_.startString();
|
||||
stringBuilder_.startString();
|
||||
|
||||
err = parseQuotedString();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
variant.setString(stringStorage_.save());
|
||||
stringBuilder_.save(&variant);
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
@ -430,9 +424,9 @@ class JsonDeserializer {
|
||||
if (err)
|
||||
return err;
|
||||
if (codepoint.append(codeunit))
|
||||
Utf8::encodeCodepoint(codepoint.value(), stringStorage_);
|
||||
Utf8::encodeCodepoint(codepoint.value(), stringBuilder_);
|
||||
#else
|
||||
stringStorage_.append('\\');
|
||||
stringBuilder_.append('\\');
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
@ -444,10 +438,10 @@ class JsonDeserializer {
|
||||
move();
|
||||
}
|
||||
|
||||
stringStorage_.append(c);
|
||||
stringBuilder_.append(c);
|
||||
}
|
||||
|
||||
if (!stringStorage_.isValid())
|
||||
if (!stringBuilder_.isValid())
|
||||
return DeserializationError::NoMemory;
|
||||
|
||||
return DeserializationError::Ok;
|
||||
@ -460,14 +454,14 @@ class JsonDeserializer {
|
||||
if (canBeInNonQuotedString(c)) { // no quotes
|
||||
do {
|
||||
move();
|
||||
stringStorage_.append(c);
|
||||
stringBuilder_.append(c);
|
||||
c = current();
|
||||
} while (canBeInNonQuotedString(c));
|
||||
} else {
|
||||
return DeserializationError::InvalidInput;
|
||||
}
|
||||
|
||||
if (!stringStorage_.isValid())
|
||||
if (!stringBuilder_.isValid())
|
||||
return DeserializationError::NoMemory;
|
||||
|
||||
return DeserializationError::Ok;
|
||||
@ -521,10 +515,37 @@ class JsonDeserializer {
|
||||
}
|
||||
buffer_[n] = 0;
|
||||
|
||||
if (!parseNumber(buffer_, result))
|
||||
return DeserializationError::InvalidInput;
|
||||
auto number = parseNumber(buffer_);
|
||||
switch (number.type()) {
|
||||
case NumberType::UnsignedInteger:
|
||||
if (result.setInteger(number.asUnsignedInteger(), resources_))
|
||||
return DeserializationError::Ok;
|
||||
else
|
||||
return DeserializationError::NoMemory;
|
||||
|
||||
return DeserializationError::Ok;
|
||||
case NumberType::SignedInteger:
|
||||
if (result.setInteger(number.asSignedInteger(), resources_))
|
||||
return DeserializationError::Ok;
|
||||
else
|
||||
return DeserializationError::NoMemory;
|
||||
|
||||
case NumberType::Float:
|
||||
if (result.setFloat(number.asFloat(), resources_))
|
||||
return DeserializationError::Ok;
|
||||
else
|
||||
return DeserializationError::NoMemory;
|
||||
|
||||
#if ARDUINOJSON_USE_DOUBLE
|
||||
case NumberType::Double:
|
||||
if (result.setFloat(number.asDouble(), resources_))
|
||||
return DeserializationError::Ok;
|
||||
else
|
||||
return DeserializationError::NoMemory;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return DeserializationError::InvalidInput;
|
||||
}
|
||||
}
|
||||
|
||||
DeserializationError::Code skipNumericValue() {
|
||||
@ -659,10 +680,10 @@ class JsonDeserializer {
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
TStringStorage stringStorage_;
|
||||
StringBuilder stringBuilder_;
|
||||
bool foundSomething_;
|
||||
Latch<TReader> latch_;
|
||||
MemoryPool* pool_;
|
||||
ResourceManager* resources_;
|
||||
char buffer_[64]; // using a member instead of a local variable because it
|
||||
// ended in the recursive path after compiler inlined the
|
||||
// code
|
||||
@ -673,21 +694,27 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// Parses a JSON input, filters, and puts the result in a JsonDocument.
|
||||
// https://arduinojson.org/v6/api/json/deserializejson/
|
||||
template <typename... Args>
|
||||
DeserializationError deserializeJson(JsonDocument& doc, Args&&... args) {
|
||||
// https://arduinojson.org/v7/api/json/deserializejson/
|
||||
template <typename TDestination, typename... Args,
|
||||
detail::enable_if_t<
|
||||
detail::is_deserialize_destination<TDestination>::value, int> = 0>
|
||||
inline DeserializationError deserializeJson(TDestination&& dst,
|
||||
Args&&... args) {
|
||||
using namespace detail;
|
||||
return deserialize<JsonDeserializer>(doc, detail::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Parses a JSON input, filters, and puts the result in a JsonDocument.
|
||||
// https://arduinojson.org/v6/api/json/deserializejson/
|
||||
template <typename TChar, typename... Args>
|
||||
DeserializationError deserializeJson(JsonDocument& doc, TChar* input,
|
||||
Args&&... args) {
|
||||
using namespace detail;
|
||||
return deserialize<JsonDeserializer>(doc, input,
|
||||
return deserialize<JsonDeserializer>(detail::forward<TDestination>(dst),
|
||||
detail::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Parses a JSON input, filters, and puts the result in a JsonDocument.
|
||||
// https://arduinojson.org/v7/api/json/deserializejson/
|
||||
template <typename TDestination, typename TChar, typename... Args,
|
||||
detail::enable_if_t<
|
||||
detail::is_deserialize_destination<TDestination>::value, int> = 0>
|
||||
inline DeserializationError deserializeJson(TDestination&& dst, TChar* input,
|
||||
Args&&... args) {
|
||||
using namespace detail;
|
||||
return deserialize<JsonDeserializer>(detail::forward<TDestination>(dst),
|
||||
input, detail::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -7,93 +7,98 @@
|
||||
#include <ArduinoJson/Json/TextFormatter.hpp>
|
||||
#include <ArduinoJson/Serialization/measure.hpp>
|
||||
#include <ArduinoJson/Serialization/serialize.hpp>
|
||||
#include <ArduinoJson/Variant/Visitor.hpp>
|
||||
#include <ArduinoJson/Variant/VariantDataVisitor.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TWriter>
|
||||
class JsonSerializer : public Visitor<size_t> {
|
||||
class JsonSerializer : public VariantDataVisitor<size_t> {
|
||||
public:
|
||||
static const bool producesText = true;
|
||||
|
||||
JsonSerializer(TWriter writer) : formatter_(writer) {}
|
||||
JsonSerializer(TWriter writer, const ResourceManager* resources)
|
||||
: formatter_(writer), resources_(resources) {}
|
||||
|
||||
FORCE_INLINE size_t visitArray(const CollectionData& array) {
|
||||
size_t visit(const ArrayData& array) {
|
||||
write('[');
|
||||
|
||||
const VariantSlot* slot = array.head();
|
||||
auto slotId = array.head();
|
||||
|
||||
while (slot != 0) {
|
||||
slot->data()->accept(*this);
|
||||
while (slotId != NULL_SLOT) {
|
||||
auto slot = resources_->getVariant(slotId);
|
||||
|
||||
slot = slot->next();
|
||||
if (slot == 0)
|
||||
break;
|
||||
slot->accept(*this, resources_);
|
||||
|
||||
write(',');
|
||||
slotId = slot->next();
|
||||
|
||||
if (slotId != NULL_SLOT)
|
||||
write(',');
|
||||
}
|
||||
|
||||
write(']');
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitObject(const CollectionData& object) {
|
||||
size_t visit(const ObjectData& object) {
|
||||
write('{');
|
||||
|
||||
const VariantSlot* slot = object.head();
|
||||
auto slotId = object.head();
|
||||
|
||||
while (slot != 0) {
|
||||
formatter_.writeString(slot->key());
|
||||
write(':');
|
||||
slot->data()->accept(*this);
|
||||
bool isKey = true;
|
||||
|
||||
slot = slot->next();
|
||||
if (slot == 0)
|
||||
break;
|
||||
while (slotId != NULL_SLOT) {
|
||||
auto slot = resources_->getVariant(slotId);
|
||||
slot->accept(*this, resources_);
|
||||
|
||||
write(',');
|
||||
slotId = slot->next();
|
||||
|
||||
if (slotId != NULL_SLOT)
|
||||
write(isKey ? ':' : ',');
|
||||
|
||||
isKey = !isKey;
|
||||
}
|
||||
|
||||
write('}');
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitFloat(JsonFloat value) {
|
||||
template <typename T>
|
||||
enable_if_t<is_floating_point<T>::value, size_t> visit(T value) {
|
||||
formatter_.writeFloat(value);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitString(const char* value) {
|
||||
size_t visit(const char* value) {
|
||||
formatter_.writeString(value);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitString(const char* value, size_t n) {
|
||||
formatter_.writeString(value, n);
|
||||
size_t visit(JsonString value) {
|
||||
formatter_.writeString(value.c_str(), value.size());
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitRawJson(const char* data, size_t n) {
|
||||
formatter_.writeRaw(data, n);
|
||||
size_t visit(RawString value) {
|
||||
formatter_.writeRaw(value.data(), value.size());
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitSignedInteger(JsonInteger value) {
|
||||
size_t visit(JsonInteger value) {
|
||||
formatter_.writeInteger(value);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitUnsignedInteger(JsonUInt value) {
|
||||
size_t visit(JsonUInt value) {
|
||||
formatter_.writeInteger(value);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitBoolean(bool value) {
|
||||
size_t visit(bool value) {
|
||||
formatter_.writeBoolean(value);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitNull() {
|
||||
size_t visit(nullptr_t) {
|
||||
formatter_.writeRaw("null");
|
||||
return bytesWritten();
|
||||
}
|
||||
@ -113,6 +118,9 @@ class JsonSerializer : public Visitor<size_t> {
|
||||
|
||||
private:
|
||||
TextFormatter<TWriter> formatter_;
|
||||
|
||||
protected:
|
||||
const ResourceManager* resources_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@ -120,15 +128,17 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// Produces a minified JSON document.
|
||||
// https://arduinojson.org/v6/api/json/serializejson/
|
||||
template <typename TDestination>
|
||||
// https://arduinojson.org/v7/api/json/serializejson/
|
||||
template <
|
||||
typename TDestination,
|
||||
detail::enable_if_t<!detail::is_pointer<TDestination>::value, int> = 0>
|
||||
size_t serializeJson(JsonVariantConst source, TDestination& destination) {
|
||||
using namespace detail;
|
||||
return serialize<JsonSerializer>(source, destination);
|
||||
}
|
||||
|
||||
// Produces a minified JSON document.
|
||||
// https://arduinojson.org/v6/api/json/serializejson/
|
||||
// https://arduinojson.org/v7/api/json/serializejson/
|
||||
inline size_t serializeJson(JsonVariantConst source, void* buffer,
|
||||
size_t bufferSize) {
|
||||
using namespace detail;
|
||||
@ -136,17 +146,17 @@ inline size_t serializeJson(JsonVariantConst source, void* buffer,
|
||||
}
|
||||
|
||||
// Computes the length of the document that serializeJson() produces.
|
||||
// https://arduinojson.org/v6/api/json/measurejson/
|
||||
// https://arduinojson.org/v7/api/json/measurejson/
|
||||
inline size_t measureJson(JsonVariantConst source) {
|
||||
using namespace detail;
|
||||
return measure<JsonSerializer>(source);
|
||||
}
|
||||
|
||||
#if ARDUINOJSON_ENABLE_STD_STREAM
|
||||
template <typename T>
|
||||
inline typename detail::enable_if<
|
||||
detail::is_convertible<T, JsonVariantConst>::value, std::ostream&>::type
|
||||
operator<<(std::ostream& os, const T& source) {
|
||||
template <typename T,
|
||||
detail::enable_if_t<
|
||||
detail::is_convertible<T, JsonVariantConst>::value, int> = 0>
|
||||
inline std::ostream& operator<<(std::ostream& os, const T& source) {
|
||||
serializeJson(source, os);
|
||||
return os;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -13,22 +13,23 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TWriter>
|
||||
class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
||||
typedef JsonSerializer<TWriter> base;
|
||||
using base = JsonSerializer<TWriter>;
|
||||
|
||||
public:
|
||||
PrettyJsonSerializer(TWriter writer) : base(writer), nesting_(0) {}
|
||||
PrettyJsonSerializer(TWriter writer, const ResourceManager* resources)
|
||||
: base(writer, resources), nesting_(0) {}
|
||||
|
||||
size_t visitArray(const CollectionData& array) {
|
||||
const VariantSlot* slot = array.head();
|
||||
if (slot) {
|
||||
size_t visit(const ArrayData& array) {
|
||||
auto it = array.createIterator(base::resources_);
|
||||
if (!it.done()) {
|
||||
base::write("[\r\n");
|
||||
nesting_++;
|
||||
while (slot != 0) {
|
||||
while (!it.done()) {
|
||||
indent();
|
||||
slot->data()->accept(*this);
|
||||
it->accept(*this, base::resources_);
|
||||
|
||||
slot = slot->next();
|
||||
base::write(slot ? ",\r\n" : "\r\n");
|
||||
it.next(base::resources_);
|
||||
base::write(it.done() ? "\r\n" : ",\r\n");
|
||||
}
|
||||
nesting_--;
|
||||
indent();
|
||||
@ -39,19 +40,22 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
||||
return this->bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitObject(const CollectionData& object) {
|
||||
const VariantSlot* slot = object.head();
|
||||
if (slot) {
|
||||
size_t visit(const ObjectData& object) {
|
||||
auto it = object.createIterator(base::resources_);
|
||||
if (!it.done()) {
|
||||
base::write("{\r\n");
|
||||
nesting_++;
|
||||
while (slot != 0) {
|
||||
indent();
|
||||
base::visitString(slot->key());
|
||||
base::write(": ");
|
||||
slot->data()->accept(*this);
|
||||
|
||||
slot = slot->next();
|
||||
base::write(slot ? ",\r\n" : "\r\n");
|
||||
bool isKey = true;
|
||||
while (!it.done()) {
|
||||
if (isKey)
|
||||
indent();
|
||||
it->accept(*this, base::resources_);
|
||||
it.next(base::resources_);
|
||||
if (isKey)
|
||||
base::write(": ");
|
||||
else
|
||||
base::write(it.done() ? "\r\n" : ",\r\n");
|
||||
isKey = !isKey;
|
||||
}
|
||||
nesting_--;
|
||||
indent();
|
||||
@ -62,6 +66,8 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
||||
return this->bytesWritten();
|
||||
}
|
||||
|
||||
using base::visit;
|
||||
|
||||
private:
|
||||
void indent() {
|
||||
for (uint8_t i = 0; i < nesting_; i++)
|
||||
@ -76,15 +82,18 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// Produces JsonDocument to create a prettified JSON document.
|
||||
// https://arduinojson.org/v6/api/json/serializejsonpretty/
|
||||
template <typename TDestination>
|
||||
size_t serializeJsonPretty(JsonVariantConst source, TDestination& destination) {
|
||||
// https://arduinojson.org/v7/api/json/serializejsonpretty/
|
||||
template <
|
||||
typename TDestination,
|
||||
detail::enable_if_t<!detail::is_pointer<TDestination>::value, int> = 0>
|
||||
inline size_t serializeJsonPretty(JsonVariantConst source,
|
||||
TDestination& destination) {
|
||||
using namespace ArduinoJson::detail;
|
||||
return serialize<PrettyJsonSerializer>(source, destination);
|
||||
}
|
||||
|
||||
// Produces JsonDocument to create a prettified JSON document.
|
||||
// https://arduinojson.org/v6/api/json/serializejsonpretty/
|
||||
// https://arduinojson.org/v7/api/json/serializejsonpretty/
|
||||
inline size_t serializeJsonPretty(JsonVariantConst source, void* buffer,
|
||||
size_t bufferSize) {
|
||||
using namespace ArduinoJson::detail;
|
||||
@ -92,7 +101,7 @@ inline size_t serializeJsonPretty(JsonVariantConst source, void* buffer,
|
||||
}
|
||||
|
||||
// Computes the length of the document that serializeJsonPretty() produces.
|
||||
// https://arduinojson.org/v6/api/json/measurejsonpretty/
|
||||
// https://arduinojson.org/v7/api/json/measurejsonpretty/
|
||||
inline size_t measureJsonPretty(JsonVariantConst source) {
|
||||
using namespace ArduinoJson::detail;
|
||||
return measure<PrettyJsonSerializer>(source);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -66,6 +66,10 @@ class TextFormatter {
|
||||
|
||||
template <typename T>
|
||||
void writeFloat(T value) {
|
||||
writeFloat(JsonFloat(value), sizeof(T) >= 8 ? 9 : 6);
|
||||
}
|
||||
|
||||
void writeFloat(JsonFloat value, int8_t decimalPlaces) {
|
||||
if (isnan(value))
|
||||
return writeRaw(ARDUINOJSON_ENABLE_NAN ? "NaN" : "null");
|
||||
|
||||
@ -87,7 +91,7 @@ class TextFormatter {
|
||||
}
|
||||
#endif
|
||||
|
||||
FloatParts<T> parts(value);
|
||||
auto parts = decomposeFloat(value, decimalPlaces);
|
||||
|
||||
writeInteger(parts.integral);
|
||||
if (parts.decimalPlaces)
|
||||
@ -100,8 +104,8 @@ class TextFormatter {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<is_signed<T>::value>::type writeInteger(T value) {
|
||||
typedef typename make_unsigned<T>::type unsigned_type;
|
||||
enable_if_t<is_signed<T>::value> writeInteger(T value) {
|
||||
using unsigned_type = make_unsigned_t<T>;
|
||||
unsigned_type unsigned_value;
|
||||
if (value < 0) {
|
||||
writeRaw('-');
|
||||
@ -113,7 +117,7 @@ class TextFormatter {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<is_unsigned<T>::value>::type writeInteger(T value) {
|
||||
enable_if_t<is_unsigned<T>::value> writeInteger(T value) {
|
||||
char buffer[22];
|
||||
char* end = buffer + sizeof(buffer);
|
||||
char* begin = end;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -0,0 +1,49 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
|
||||
#include <stdlib.h> // malloc, free
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
class Allocator {
|
||||
public:
|
||||
virtual void* allocate(size_t size) = 0;
|
||||
virtual void deallocate(void* ptr) = 0;
|
||||
virtual void* reallocate(void* ptr, size_t new_size) = 0;
|
||||
|
||||
protected:
|
||||
~Allocator() = default;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
class DefaultAllocator : public Allocator {
|
||||
public:
|
||||
void* allocate(size_t size) override {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void deallocate(void* ptr) override {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void* reallocate(void* ptr, size_t new_size) override {
|
||||
return realloc(ptr, new_size);
|
||||
}
|
||||
|
||||
static Allocator* instance() {
|
||||
static DefaultAllocator allocator;
|
||||
return &allocator;
|
||||
}
|
||||
|
||||
private:
|
||||
DefaultAllocator() = default;
|
||||
~DefaultAllocator() = default;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@ -1,253 +1,110 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Memory/Alignment.hpp>
|
||||
#include <ArduinoJson/Memory/Allocator.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
#include <ArduinoJson/Polyfills/mpl/max.hpp>
|
||||
#include <ArduinoJson/Strings/StringAdapters.hpp>
|
||||
#include <ArduinoJson/Variant/VariantSlot.hpp>
|
||||
|
||||
#include <string.h> // memmove
|
||||
|
||||
#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::detail::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::detail::VariantSlot))
|
||||
#include <ArduinoJson/Polyfills/integer.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
// begin_ end_
|
||||
// v v
|
||||
// +-------------+--------------+--------------+
|
||||
// | strings... | (free) | ...variants |
|
||||
// +-------------+--------------+--------------+
|
||||
// ^ ^
|
||||
// left_ right_
|
||||
using SlotId = uint_t<ARDUINOJSON_SLOT_ID_SIZE * 8>;
|
||||
using SlotCount = SlotId;
|
||||
const SlotId NULL_SLOT = SlotId(-1);
|
||||
|
||||
class MemoryPool {
|
||||
template <typename T>
|
||||
class Slot {
|
||||
public:
|
||||
MemoryPool(char* buf, size_t capa)
|
||||
: begin_(buf),
|
||||
left_(buf),
|
||||
right_(buf ? buf + capa : 0),
|
||||
end_(buf ? buf + capa : 0),
|
||||
overflowed_(false) {
|
||||
ARDUINOJSON_ASSERT(isAligned(begin_));
|
||||
ARDUINOJSON_ASSERT(isAligned(right_));
|
||||
ARDUINOJSON_ASSERT(isAligned(end_));
|
||||
Slot() : ptr_(nullptr), id_(NULL_SLOT) {}
|
||||
Slot(T* p, SlotId id) : ptr_(p), id_(id) {
|
||||
ARDUINOJSON_ASSERT((p == nullptr) == (id == NULL_SLOT));
|
||||
}
|
||||
|
||||
void* buffer() {
|
||||
return begin_; // NOLINT(clang-analyzer-unix.Malloc)
|
||||
// movePointers() alters this pointer
|
||||
explicit operator bool() const {
|
||||
return ptr_ != nullptr;
|
||||
}
|
||||
|
||||
// Gets the capacity of the memoryPool in bytes
|
||||
size_t capacity() const {
|
||||
return size_t(end_ - begin_);
|
||||
SlotId id() const {
|
||||
return id_;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return size_t(left_ - begin_ + end_ - right_);
|
||||
T* ptr() const {
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
bool overflowed() const {
|
||||
return overflowed_;
|
||||
}
|
||||
|
||||
VariantSlot* allocVariant() {
|
||||
return allocRight<VariantSlot>();
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
const char* saveString(TAdaptedString str) {
|
||||
if (str.isNull())
|
||||
return 0;
|
||||
|
||||
#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
|
||||
const char* existingCopy = findString(str);
|
||||
if (existingCopy)
|
||||
return existingCopy;
|
||||
#endif
|
||||
|
||||
size_t n = str.size();
|
||||
|
||||
char* newCopy = allocString(n + 1);
|
||||
if (newCopy) {
|
||||
stringGetChars(str, newCopy, n);
|
||||
newCopy[n] = 0; // force null-terminator
|
||||
}
|
||||
return newCopy;
|
||||
}
|
||||
|
||||
void getFreeZone(char** zoneStart, size_t* zoneSize) const {
|
||||
*zoneStart = left_;
|
||||
*zoneSize = size_t(right_ - left_);
|
||||
}
|
||||
|
||||
const char* saveStringFromFreeZone(size_t len) {
|
||||
#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
|
||||
const char* dup = findString(adaptString(left_, len));
|
||||
if (dup)
|
||||
return dup;
|
||||
#endif
|
||||
|
||||
const char* str = left_;
|
||||
left_ += len;
|
||||
*left_++ = 0;
|
||||
checkInvariants();
|
||||
return str;
|
||||
}
|
||||
|
||||
void markAsOverflowed() {
|
||||
overflowed_ = true;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
left_ = begin_;
|
||||
right_ = end_;
|
||||
overflowed_ = false;
|
||||
}
|
||||
|
||||
bool canAlloc(size_t bytes) const {
|
||||
return left_ + bytes <= right_;
|
||||
}
|
||||
|
||||
bool owns(void* p) const {
|
||||
return begin_ <= p && p < end_;
|
||||
}
|
||||
|
||||
// Workaround for missing placement new
|
||||
void* operator new(size_t, void* p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
// Squash the free space between strings and variants
|
||||
//
|
||||
// begin_ end_
|
||||
// v v
|
||||
// +-------------+--------------+
|
||||
// | strings... | ...variants |
|
||||
// +-------------+--------------+
|
||||
// ^
|
||||
// left_ right_
|
||||
//
|
||||
// This funcion is called before a realloc.
|
||||
ptrdiff_t squash() {
|
||||
char* new_right = addPadding(left_);
|
||||
if (new_right >= right_)
|
||||
return 0;
|
||||
|
||||
size_t right_size = static_cast<size_t>(end_ - right_);
|
||||
memmove(new_right, right_, right_size);
|
||||
|
||||
ptrdiff_t bytes_reclaimed = right_ - new_right;
|
||||
right_ = new_right;
|
||||
end_ = new_right + right_size;
|
||||
return bytes_reclaimed;
|
||||
}
|
||||
|
||||
// Move all pointers together
|
||||
// This funcion is called after a realloc.
|
||||
void movePointers(ptrdiff_t offset) {
|
||||
begin_ += offset;
|
||||
left_ += offset;
|
||||
right_ += offset;
|
||||
end_ += offset;
|
||||
T* operator->() const {
|
||||
ARDUINOJSON_ASSERT(ptr_ != nullptr);
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
private:
|
||||
void checkInvariants() {
|
||||
ARDUINOJSON_ASSERT(begin_ <= left_);
|
||||
ARDUINOJSON_ASSERT(left_ <= right_);
|
||||
ARDUINOJSON_ASSERT(right_ <= end_);
|
||||
ARDUINOJSON_ASSERT(isAligned(right_));
|
||||
}
|
||||
|
||||
#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
|
||||
template <typename TAdaptedString>
|
||||
const char* findString(const TAdaptedString& str) const {
|
||||
size_t n = str.size();
|
||||
for (char* next = begin_; next + n < left_; ++next) {
|
||||
if (next[n] == '\0' && stringEquals(str, adaptString(next, n)))
|
||||
return next;
|
||||
|
||||
// jump to next terminator
|
||||
while (*next)
|
||||
++next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
char* allocString(size_t n) {
|
||||
if (!canAlloc(n)) {
|
||||
overflowed_ = true;
|
||||
return 0;
|
||||
}
|
||||
char* s = left_;
|
||||
left_ += n;
|
||||
checkInvariants();
|
||||
return s;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* allocRight() {
|
||||
return reinterpret_cast<T*>(allocRight(sizeof(T)));
|
||||
}
|
||||
|
||||
void* allocRight(size_t bytes) {
|
||||
if (!canAlloc(bytes)) {
|
||||
overflowed_ = true;
|
||||
return 0;
|
||||
}
|
||||
right_ -= bytes;
|
||||
return right_;
|
||||
}
|
||||
|
||||
char *begin_, *left_, *right_, *end_;
|
||||
bool overflowed_;
|
||||
T* ptr_;
|
||||
SlotId id_;
|
||||
};
|
||||
|
||||
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 T>
|
||||
class MemoryPool {
|
||||
public:
|
||||
void create(SlotCount cap, Allocator* allocator) {
|
||||
ARDUINOJSON_ASSERT(cap > 0);
|
||||
slots_ = reinterpret_cast<T*>(allocator->allocate(slotsToBytes(cap)));
|
||||
capacity_ = slots_ ? cap : 0;
|
||||
usage_ = 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();
|
||||
}
|
||||
void destroy(Allocator* allocator) {
|
||||
if (slots_)
|
||||
allocator->deallocate(slots_);
|
||||
slots_ = nullptr;
|
||||
capacity_ = 0;
|
||||
usage_ = 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
Slot<T> allocSlot() {
|
||||
if (!slots_)
|
||||
return {};
|
||||
if (usage_ >= capacity_)
|
||||
return {};
|
||||
auto index = usage_++;
|
||||
return {slots_ + index, SlotId(index)};
|
||||
}
|
||||
|
||||
template <typename TAdaptedString, typename TCallback>
|
||||
bool storeString(MemoryPool* pool, TAdaptedString str, TCallback callback) {
|
||||
return storeString(pool, str, str.storagePolicy(), callback);
|
||||
}
|
||||
T* getSlot(SlotId id) const {
|
||||
ARDUINOJSON_ASSERT(id < usage_);
|
||||
return slots_ + id;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
usage_ = 0;
|
||||
}
|
||||
|
||||
void shrinkToFit(Allocator* allocator) {
|
||||
auto newSlots = reinterpret_cast<T*>(
|
||||
allocator->reallocate(slots_, slotsToBytes(usage_)));
|
||||
if (newSlots) {
|
||||
slots_ = newSlots;
|
||||
capacity_ = usage_;
|
||||
}
|
||||
}
|
||||
|
||||
SlotCount usage() const {
|
||||
return usage_;
|
||||
}
|
||||
|
||||
static SlotCount bytesToSlots(size_t n) {
|
||||
return static_cast<SlotCount>(n / sizeof(T));
|
||||
}
|
||||
|
||||
static size_t slotsToBytes(SlotCount n) {
|
||||
return n * sizeof(T);
|
||||
}
|
||||
|
||||
private:
|
||||
SlotCount capacity_;
|
||||
SlotCount usage_;
|
||||
T* slots_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
||||
@ -0,0 +1,214 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Memory/MemoryPool.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
#include <ArduinoJson/Polyfills/utility.hpp>
|
||||
|
||||
#include <string.h> // memcpy
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
using PoolCount = SlotId;
|
||||
|
||||
template <typename T>
|
||||
class MemoryPoolList {
|
||||
struct FreeSlot {
|
||||
SlotId next;
|
||||
};
|
||||
|
||||
static_assert(sizeof(FreeSlot) <= sizeof(T), "T is too small");
|
||||
|
||||
public:
|
||||
using Pool = MemoryPool<T>;
|
||||
|
||||
MemoryPoolList() = default;
|
||||
|
||||
~MemoryPoolList() {
|
||||
ARDUINOJSON_ASSERT(count_ == 0);
|
||||
}
|
||||
|
||||
friend void swap(MemoryPoolList& a, MemoryPoolList& b) {
|
||||
bool aUsedPreallocated = a.pools_ == a.preallocatedPools_;
|
||||
bool bUsedPreallocated = b.pools_ == b.preallocatedPools_;
|
||||
|
||||
// Who is using preallocated pools?
|
||||
if (aUsedPreallocated && bUsedPreallocated) {
|
||||
// both of us => swap preallocated pools
|
||||
for (PoolCount i = 0; i < ARDUINOJSON_INITIAL_POOL_COUNT; i++)
|
||||
swap_(a.preallocatedPools_[i], b.preallocatedPools_[i]);
|
||||
} else if (bUsedPreallocated) {
|
||||
// only b => copy b's preallocated pools and give him a's pointer
|
||||
for (PoolCount i = 0; i < b.count_; i++)
|
||||
a.preallocatedPools_[i] = b.preallocatedPools_[i];
|
||||
b.pools_ = a.pools_;
|
||||
a.pools_ = a.preallocatedPools_;
|
||||
} else if (aUsedPreallocated) {
|
||||
// only a => copy a's preallocated pools and give him b's pointer
|
||||
for (PoolCount i = 0; i < a.count_; i++)
|
||||
b.preallocatedPools_[i] = a.preallocatedPools_[i];
|
||||
a.pools_ = b.pools_;
|
||||
b.pools_ = b.preallocatedPools_;
|
||||
} else {
|
||||
// neither => swap pointers
|
||||
swap_(a.pools_, b.pools_);
|
||||
}
|
||||
|
||||
swap_(a.count_, b.count_);
|
||||
swap_(a.capacity_, b.capacity_);
|
||||
swap_(a.freeList_, b.freeList_);
|
||||
}
|
||||
|
||||
MemoryPoolList& operator=(MemoryPoolList&& src) {
|
||||
ARDUINOJSON_ASSERT(count_ == 0);
|
||||
if (src.pools_ == src.preallocatedPools_) {
|
||||
memcpy(preallocatedPools_, src.preallocatedPools_,
|
||||
sizeof(preallocatedPools_));
|
||||
pools_ = preallocatedPools_;
|
||||
} else {
|
||||
pools_ = src.pools_;
|
||||
src.pools_ = nullptr;
|
||||
}
|
||||
count_ = src.count_;
|
||||
capacity_ = src.capacity_;
|
||||
src.count_ = 0;
|
||||
src.capacity_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Slot<T> allocSlot(Allocator* allocator) {
|
||||
// try to allocate from free list
|
||||
if (freeList_ != NULL_SLOT) {
|
||||
return allocFromFreeList();
|
||||
}
|
||||
|
||||
// try to allocate from last pool (other pools are full)
|
||||
if (count_) {
|
||||
auto slot = allocFromLastPool();
|
||||
if (slot)
|
||||
return slot;
|
||||
}
|
||||
|
||||
// create a new pool and try again
|
||||
auto pool = addPool(allocator);
|
||||
if (!pool)
|
||||
return {};
|
||||
|
||||
return allocFromLastPool();
|
||||
}
|
||||
|
||||
void freeSlot(Slot<T> slot) {
|
||||
reinterpret_cast<FreeSlot*>(slot.ptr())->next = freeList_;
|
||||
freeList_ = slot.id();
|
||||
}
|
||||
|
||||
T* getSlot(SlotId id) const {
|
||||
if (id == NULL_SLOT)
|
||||
return nullptr;
|
||||
auto poolIndex = SlotId(id / ARDUINOJSON_POOL_CAPACITY);
|
||||
auto indexInPool = SlotId(id % ARDUINOJSON_POOL_CAPACITY);
|
||||
ARDUINOJSON_ASSERT(poolIndex < count_);
|
||||
return pools_[poolIndex].getSlot(indexInPool);
|
||||
}
|
||||
|
||||
void clear(Allocator* allocator) {
|
||||
for (PoolCount i = 0; i < count_; i++)
|
||||
pools_[i].destroy(allocator);
|
||||
count_ = 0;
|
||||
freeList_ = NULL_SLOT;
|
||||
if (pools_ != preallocatedPools_) {
|
||||
allocator->deallocate(pools_);
|
||||
pools_ = preallocatedPools_;
|
||||
capacity_ = ARDUINOJSON_INITIAL_POOL_COUNT;
|
||||
}
|
||||
}
|
||||
|
||||
SlotCount usage() const {
|
||||
SlotCount total = 0;
|
||||
for (PoolCount i = 0; i < count_; i++)
|
||||
total = SlotCount(total + pools_[i].usage());
|
||||
return total;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return Pool::slotsToBytes(usage());
|
||||
}
|
||||
|
||||
void shrinkToFit(Allocator* allocator) {
|
||||
if (count_ > 0)
|
||||
pools_[count_ - 1].shrinkToFit(allocator);
|
||||
if (pools_ != preallocatedPools_ && count_ != capacity_) {
|
||||
pools_ = static_cast<Pool*>(
|
||||
allocator->reallocate(pools_, count_ * sizeof(Pool)));
|
||||
ARDUINOJSON_ASSERT(pools_ != nullptr); // realloc to smaller can't fail
|
||||
capacity_ = count_;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Slot<T> allocFromFreeList() {
|
||||
ARDUINOJSON_ASSERT(freeList_ != NULL_SLOT);
|
||||
auto id = freeList_;
|
||||
auto slot = getSlot(freeList_);
|
||||
freeList_ = reinterpret_cast<FreeSlot*>(slot)->next;
|
||||
return {slot, id};
|
||||
}
|
||||
|
||||
Slot<T> allocFromLastPool() {
|
||||
ARDUINOJSON_ASSERT(count_ > 0);
|
||||
auto poolIndex = SlotId(count_ - 1);
|
||||
auto slot = pools_[poolIndex].allocSlot();
|
||||
if (!slot)
|
||||
return {};
|
||||
return {slot.ptr(),
|
||||
SlotId(poolIndex * ARDUINOJSON_POOL_CAPACITY + slot.id())};
|
||||
}
|
||||
|
||||
Pool* addPool(Allocator* allocator) {
|
||||
if (count_ == capacity_ && !increaseCapacity(allocator))
|
||||
return nullptr;
|
||||
auto pool = &pools_[count_++];
|
||||
SlotCount poolCapacity = ARDUINOJSON_POOL_CAPACITY;
|
||||
if (count_ == maxPools) // last pool is smaller because of NULL_SLOT
|
||||
poolCapacity--;
|
||||
pool->create(poolCapacity, allocator);
|
||||
return pool;
|
||||
}
|
||||
|
||||
bool increaseCapacity(Allocator* allocator) {
|
||||
if (capacity_ == maxPools)
|
||||
return false;
|
||||
void* newPools;
|
||||
auto newCapacity = PoolCount(capacity_ * 2);
|
||||
|
||||
if (pools_ == preallocatedPools_) {
|
||||
newPools = allocator->allocate(newCapacity * sizeof(Pool));
|
||||
if (!newPools)
|
||||
return false;
|
||||
memcpy(newPools, preallocatedPools_, sizeof(preallocatedPools_));
|
||||
} else {
|
||||
newPools = allocator->reallocate(pools_, newCapacity * sizeof(Pool));
|
||||
if (!newPools)
|
||||
return false;
|
||||
}
|
||||
|
||||
pools_ = static_cast<Pool*>(newPools);
|
||||
capacity_ = newCapacity;
|
||||
return true;
|
||||
}
|
||||
|
||||
Pool preallocatedPools_[ARDUINOJSON_INITIAL_POOL_COUNT];
|
||||
Pool* pools_ = preallocatedPools_;
|
||||
PoolCount count_ = 0;
|
||||
PoolCount capacity_ = ARDUINOJSON_INITIAL_POOL_COUNT;
|
||||
SlotId freeList_ = NULL_SLOT;
|
||||
|
||||
public:
|
||||
static const PoolCount maxPools =
|
||||
PoolCount(NULL_SLOT / ARDUINOJSON_POOL_CAPACITY + 1);
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@ -0,0 +1,131 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Memory/Allocator.hpp>
|
||||
#include <ArduinoJson/Memory/MemoryPoolList.hpp>
|
||||
#include <ArduinoJson/Memory/StringPool.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
#include <ArduinoJson/Polyfills/utility.hpp>
|
||||
#include <ArduinoJson/Strings/StringAdapters.hpp>
|
||||
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
class VariantData;
|
||||
class VariantWithId;
|
||||
|
||||
class ResourceManager {
|
||||
union SlotData {
|
||||
VariantData variant;
|
||||
#if ARDUINOJSON_USE_EXTENSIONS
|
||||
VariantExtension extension;
|
||||
#endif
|
||||
};
|
||||
|
||||
public:
|
||||
constexpr static size_t slotSize = sizeof(SlotData);
|
||||
|
||||
ResourceManager(Allocator* allocator = DefaultAllocator::instance())
|
||||
: allocator_(allocator), overflowed_(false) {}
|
||||
|
||||
~ResourceManager() {
|
||||
stringPool_.clear(allocator_);
|
||||
variantPools_.clear(allocator_);
|
||||
}
|
||||
|
||||
ResourceManager(const ResourceManager&) = delete;
|
||||
ResourceManager& operator=(const ResourceManager& src) = delete;
|
||||
|
||||
friend void swap(ResourceManager& a, ResourceManager& b) {
|
||||
swap(a.stringPool_, b.stringPool_);
|
||||
swap(a.variantPools_, b.variantPools_);
|
||||
swap_(a.allocator_, b.allocator_);
|
||||
swap_(a.overflowed_, b.overflowed_);
|
||||
}
|
||||
|
||||
Allocator* allocator() const {
|
||||
return allocator_;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return variantPools_.size() + stringPool_.size();
|
||||
}
|
||||
|
||||
bool overflowed() const {
|
||||
return overflowed_;
|
||||
}
|
||||
|
||||
Slot<VariantData> allocVariant();
|
||||
void freeVariant(Slot<VariantData> slot);
|
||||
VariantData* getVariant(SlotId id) const;
|
||||
|
||||
#if ARDUINOJSON_USE_EXTENSIONS
|
||||
Slot<VariantExtension> allocExtension();
|
||||
void freeExtension(SlotId slot);
|
||||
VariantExtension* getExtension(SlotId id) const;
|
||||
#endif
|
||||
|
||||
template <typename TAdaptedString>
|
||||
StringNode* saveString(TAdaptedString str) {
|
||||
if (str.isNull())
|
||||
return 0;
|
||||
|
||||
auto node = stringPool_.add(str, allocator_);
|
||||
if (!node)
|
||||
overflowed_ = true;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void saveString(StringNode* node) {
|
||||
stringPool_.add(node);
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
StringNode* getString(const TAdaptedString& str) const {
|
||||
return stringPool_.get(str);
|
||||
}
|
||||
|
||||
StringNode* createString(size_t length) {
|
||||
auto node = StringNode::create(length, allocator_);
|
||||
if (!node)
|
||||
overflowed_ = true;
|
||||
return node;
|
||||
}
|
||||
|
||||
StringNode* resizeString(StringNode* node, size_t length) {
|
||||
node = StringNode::resize(node, length, allocator_);
|
||||
if (!node)
|
||||
overflowed_ = true;
|
||||
return node;
|
||||
}
|
||||
|
||||
void destroyString(StringNode* node) {
|
||||
StringNode::destroy(node, allocator_);
|
||||
}
|
||||
|
||||
void dereferenceString(const char* s) {
|
||||
stringPool_.dereference(s, allocator_);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
variantPools_.clear(allocator_);
|
||||
overflowed_ = false;
|
||||
stringPool_.clear(allocator_);
|
||||
}
|
||||
|
||||
void shrinkToFit() {
|
||||
variantPools_.shrinkToFit(allocator_);
|
||||
}
|
||||
|
||||
private:
|
||||
Allocator* allocator_;
|
||||
bool overflowed_;
|
||||
StringPool stringPool_;
|
||||
MemoryPoolList<SlotData> variantPools_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@ -0,0 +1,52 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Collection/CollectionData.hpp>
|
||||
#include <ArduinoJson/Memory/ResourceManager.hpp>
|
||||
#include <ArduinoJson/Polyfills/alias_cast.hpp>
|
||||
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
inline Slot<VariantData> ResourceManager::allocVariant() {
|
||||
auto p = variantPools_.allocSlot(allocator_);
|
||||
if (!p) {
|
||||
overflowed_ = true;
|
||||
return {};
|
||||
}
|
||||
return {new (&p->variant) VariantData, p.id()};
|
||||
}
|
||||
|
||||
inline void ResourceManager::freeVariant(Slot<VariantData> variant) {
|
||||
variant->clear(this);
|
||||
variantPools_.freeSlot({alias_cast<SlotData*>(variant.ptr()), variant.id()});
|
||||
}
|
||||
|
||||
inline VariantData* ResourceManager::getVariant(SlotId id) const {
|
||||
return reinterpret_cast<VariantData*>(variantPools_.getSlot(id));
|
||||
}
|
||||
|
||||
#if ARDUINOJSON_USE_EXTENSIONS
|
||||
inline Slot<VariantExtension> ResourceManager::allocExtension() {
|
||||
auto p = variantPools_.allocSlot(allocator_);
|
||||
if (!p) {
|
||||
overflowed_ = true;
|
||||
return {};
|
||||
}
|
||||
return {&p->extension, p.id()};
|
||||
}
|
||||
|
||||
inline void ResourceManager::freeExtension(SlotId id) {
|
||||
auto p = getExtension(id);
|
||||
variantPools_.freeSlot({reinterpret_cast<SlotData*>(p), id});
|
||||
}
|
||||
|
||||
inline VariantExtension* ResourceManager::getExtension(SlotId id) const {
|
||||
return &variantPools_.getSlot(id)->extension;
|
||||
}
|
||||
#endif
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@ -0,0 +1,79 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Memory/ResourceManager.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
class StringBuffer {
|
||||
public:
|
||||
StringBuffer(ResourceManager* resources) : resources_(resources) {}
|
||||
|
||||
~StringBuffer() {
|
||||
if (node_)
|
||||
resources_->destroyString(node_);
|
||||
}
|
||||
|
||||
char* reserve(size_t capacity) {
|
||||
if (node_ && capacity > node_->length) {
|
||||
// existing buffer is too small, we need to reallocate
|
||||
resources_->destroyString(node_);
|
||||
node_ = nullptr;
|
||||
}
|
||||
if (!node_)
|
||||
node_ = resources_->createString(capacity);
|
||||
if (!node_)
|
||||
return nullptr;
|
||||
size_ = capacity;
|
||||
node_->data[capacity] = 0; // null-terminate the string
|
||||
return node_->data;
|
||||
}
|
||||
|
||||
JsonString str() const {
|
||||
ARDUINOJSON_ASSERT(node_ != nullptr);
|
||||
return JsonString(node_->data, node_->length);
|
||||
}
|
||||
|
||||
void save(VariantData* data) {
|
||||
ARDUINOJSON_ASSERT(node_ != nullptr);
|
||||
const char* s = node_->data;
|
||||
if (isTinyString(s, size_))
|
||||
data->setTinyString(adaptString(s, size_));
|
||||
else
|
||||
data->setOwnedString(commitStringNode());
|
||||
}
|
||||
|
||||
void saveRaw(VariantData* data) {
|
||||
data->setRawString(commitStringNode());
|
||||
}
|
||||
|
||||
private:
|
||||
StringNode* commitStringNode() {
|
||||
ARDUINOJSON_ASSERT(node_ != nullptr);
|
||||
node_->data[size_] = 0;
|
||||
auto node = resources_->getString(adaptString(node_->data, size_));
|
||||
if (node) {
|
||||
node->references++;
|
||||
return node;
|
||||
}
|
||||
|
||||
if (node_->length != size_) {
|
||||
node = resources_->resizeString(node_, size_);
|
||||
ARDUINOJSON_ASSERT(node != nullptr); // realloc to smaller can't fail
|
||||
} else {
|
||||
node = node_;
|
||||
}
|
||||
node_ = nullptr;
|
||||
resources_->saveString(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
ResourceManager* resources_;
|
||||
StringNode* node_ = nullptr;
|
||||
size_t size_ = 0;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@ -0,0 +1,88 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Memory/ResourceManager.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
class StringBuilder {
|
||||
public:
|
||||
static const size_t initialCapacity = 31;
|
||||
|
||||
StringBuilder(ResourceManager* resources) : resources_(resources) {}
|
||||
|
||||
~StringBuilder() {
|
||||
if (node_)
|
||||
resources_->destroyString(node_);
|
||||
}
|
||||
|
||||
void startString() {
|
||||
size_ = 0;
|
||||
if (!node_)
|
||||
node_ = resources_->createString(initialCapacity);
|
||||
}
|
||||
|
||||
void save(VariantData* variant) {
|
||||
ARDUINOJSON_ASSERT(variant != nullptr);
|
||||
ARDUINOJSON_ASSERT(node_ != nullptr);
|
||||
|
||||
char* p = node_->data;
|
||||
if (isTinyString(p, size_)) {
|
||||
variant->setTinyString(adaptString(p, size_));
|
||||
return;
|
||||
}
|
||||
|
||||
p[size_] = 0;
|
||||
StringNode* node = resources_->getString(adaptString(p, size_));
|
||||
if (!node) {
|
||||
node = resources_->resizeString(node_, size_);
|
||||
ARDUINOJSON_ASSERT(node != nullptr); // realloc to smaller can't fail
|
||||
resources_->saveString(node);
|
||||
node_ = nullptr; // next time we need a new string
|
||||
} else {
|
||||
node->references++;
|
||||
}
|
||||
variant->setOwnedString(node);
|
||||
}
|
||||
|
||||
void append(const char* s) {
|
||||
while (*s)
|
||||
append(*s++);
|
||||
}
|
||||
|
||||
void append(const char* s, size_t n) {
|
||||
while (n-- > 0) // TODO: memcpy
|
||||
append(*s++);
|
||||
}
|
||||
|
||||
void append(char c) {
|
||||
if (node_ && size_ == node_->length)
|
||||
node_ = resources_->resizeString(node_, size_ * 2U + 1);
|
||||
if (node_)
|
||||
node_->data[size_++] = c;
|
||||
}
|
||||
|
||||
bool isValid() const {
|
||||
return node_ != nullptr;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return size_;
|
||||
}
|
||||
|
||||
JsonString str() const {
|
||||
ARDUINOJSON_ASSERT(node_ != nullptr);
|
||||
node_->data[size_] = 0;
|
||||
return JsonString(node_->data, size_);
|
||||
}
|
||||
|
||||
private:
|
||||
ResourceManager* resources_;
|
||||
StringNode* node_ = nullptr;
|
||||
size_t size_ = 0;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@ -0,0 +1,75 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Memory/Allocator.hpp>
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
#include <ArduinoJson/Polyfills/integer.hpp>
|
||||
#include <ArduinoJson/Polyfills/limits.hpp>
|
||||
|
||||
#include <stddef.h> // offsetof
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
struct StringNode {
|
||||
// Use the same type as SlotId to store the reference count
|
||||
// (there can never be more references than slots)
|
||||
using references_type = uint_t<ARDUINOJSON_SLOT_ID_SIZE * 8>;
|
||||
|
||||
using length_type = uint_t<ARDUINOJSON_STRING_LENGTH_SIZE * 8>;
|
||||
|
||||
struct StringNode* next;
|
||||
references_type references;
|
||||
length_type length;
|
||||
char data[1];
|
||||
|
||||
static constexpr size_t maxLength = numeric_limits<length_type>::highest();
|
||||
|
||||
static constexpr size_t sizeForLength(size_t n) {
|
||||
return n + 1 + offsetof(StringNode, data);
|
||||
}
|
||||
|
||||
static StringNode* create(size_t length, Allocator* allocator) {
|
||||
if (length > maxLength)
|
||||
return nullptr;
|
||||
auto size = sizeForLength(length);
|
||||
if (size < length) // integer overflow
|
||||
return nullptr; // (not testable on 64-bit)
|
||||
auto node = reinterpret_cast<StringNode*>(allocator->allocate(size));
|
||||
if (node) {
|
||||
node->length = length_type(length);
|
||||
node->references = 1;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static StringNode* resize(StringNode* node, size_t length,
|
||||
Allocator* allocator) {
|
||||
ARDUINOJSON_ASSERT(node != nullptr);
|
||||
StringNode* newNode;
|
||||
if (length <= maxLength)
|
||||
newNode = reinterpret_cast<StringNode*>(
|
||||
allocator->reallocate(node, sizeForLength(length)));
|
||||
else
|
||||
newNode = nullptr;
|
||||
if (newNode)
|
||||
newNode->length = length_type(length);
|
||||
else
|
||||
allocator->deallocate(node);
|
||||
return newNode;
|
||||
}
|
||||
|
||||
static void destroy(StringNode* node, Allocator* allocator) {
|
||||
allocator->deallocate(node);
|
||||
}
|
||||
};
|
||||
|
||||
// Returns the size (in bytes) of an string with n characters.
|
||||
constexpr size_t sizeofString(size_t n) {
|
||||
return StringNode::sizeForLength(n);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@ -0,0 +1,102 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Memory/Allocator.hpp>
|
||||
#include <ArduinoJson/Memory/StringNode.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
#include <ArduinoJson/Polyfills/utility.hpp>
|
||||
#include <ArduinoJson/Strings/StringAdapters.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
class StringPool {
|
||||
public:
|
||||
StringPool() = default;
|
||||
StringPool(const StringPool&) = delete;
|
||||
void operator=(StringPool&& src) = delete;
|
||||
|
||||
~StringPool() {
|
||||
ARDUINOJSON_ASSERT(strings_ == nullptr);
|
||||
}
|
||||
|
||||
friend void swap(StringPool& a, StringPool& b) {
|
||||
swap_(a.strings_, b.strings_);
|
||||
}
|
||||
|
||||
void clear(Allocator* allocator) {
|
||||
while (strings_) {
|
||||
auto node = strings_;
|
||||
strings_ = node->next;
|
||||
StringNode::destroy(node, allocator);
|
||||
}
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
size_t total = 0;
|
||||
for (auto node = strings_; node; node = node->next)
|
||||
total += sizeofString(node->length);
|
||||
return total;
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
StringNode* add(TAdaptedString str, Allocator* allocator) {
|
||||
ARDUINOJSON_ASSERT(str.isNull() == false);
|
||||
|
||||
auto node = get(str);
|
||||
if (node) {
|
||||
node->references++;
|
||||
return node;
|
||||
}
|
||||
|
||||
size_t n = str.size();
|
||||
|
||||
node = StringNode::create(n, allocator);
|
||||
if (!node)
|
||||
return nullptr;
|
||||
|
||||
stringGetChars(str, node->data, n);
|
||||
node->data[n] = 0; // force NUL terminator
|
||||
add(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
void add(StringNode* node) {
|
||||
ARDUINOJSON_ASSERT(node != nullptr);
|
||||
node->next = strings_;
|
||||
strings_ = node;
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
StringNode* get(const TAdaptedString& str) const {
|
||||
for (auto node = strings_; node; node = node->next) {
|
||||
if (stringEquals(str, adaptString(node->data, node->length)))
|
||||
return node;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void dereference(const char* s, Allocator* allocator) {
|
||||
StringNode* prev = nullptr;
|
||||
for (auto node = strings_; node; node = node->next) {
|
||||
if (node->data == s) {
|
||||
if (--node->references == 0) {
|
||||
if (prev)
|
||||
prev->next = node->next;
|
||||
else
|
||||
strings_ = node->next;
|
||||
StringNode::destroy(node, allocator);
|
||||
}
|
||||
return;
|
||||
}
|
||||
prev = node;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
StringNode* strings_ = nullptr;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -51,6 +51,8 @@ class SerializedValue<TChar*> {
|
||||
size_t size_;
|
||||
};
|
||||
|
||||
using RawString = SerializedValue<const char*>;
|
||||
|
||||
template <typename T>
|
||||
inline SerializedValue<T> serialized(T str) {
|
||||
return SerializedValue<T>(str);
|
||||
|
||||
@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Variant/Converter.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
class MsgPackBinary {
|
||||
public:
|
||||
MsgPackBinary() : data_(nullptr), size_(0) {}
|
||||
explicit MsgPackBinary(const void* c, size_t size) : data_(c), size_(size) {}
|
||||
|
||||
const void* data() const {
|
||||
return data_;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return size_;
|
||||
}
|
||||
|
||||
private:
|
||||
const void* data_;
|
||||
size_t size_;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<MsgPackBinary> : private detail::VariantAttorney {
|
||||
static void toJson(MsgPackBinary src, JsonVariant dst) {
|
||||
auto data = VariantAttorney::getData(dst);
|
||||
if (!data)
|
||||
return;
|
||||
auto resources = getResourceManager(dst);
|
||||
data->clear(resources);
|
||||
if (src.data()) {
|
||||
size_t headerSize = src.size() >= 0x10000 ? 5
|
||||
: src.size() >= 0x100 ? 3
|
||||
: 2;
|
||||
auto str = resources->createString(src.size() + headerSize);
|
||||
if (str) {
|
||||
resources->saveString(str);
|
||||
auto ptr = reinterpret_cast<uint8_t*>(str->data);
|
||||
switch (headerSize) {
|
||||
case 2:
|
||||
ptr[0] = uint8_t(0xc4);
|
||||
ptr[1] = uint8_t(src.size() & 0xff);
|
||||
break;
|
||||
case 3:
|
||||
ptr[0] = uint8_t(0xc5);
|
||||
ptr[1] = uint8_t(src.size() >> 8 & 0xff);
|
||||
ptr[2] = uint8_t(src.size() & 0xff);
|
||||
break;
|
||||
case 5:
|
||||
ptr[0] = uint8_t(0xc6);
|
||||
ptr[1] = uint8_t(src.size() >> 24 & 0xff);
|
||||
ptr[2] = uint8_t(src.size() >> 16 & 0xff);
|
||||
ptr[3] = uint8_t(src.size() >> 8 & 0xff);
|
||||
ptr[4] = uint8_t(src.size() & 0xff);
|
||||
break;
|
||||
default:
|
||||
ARDUINOJSON_ASSERT(false);
|
||||
}
|
||||
memcpy(ptr + headerSize, src.data(), src.size());
|
||||
data->setRawString(str);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static MsgPackBinary fromJson(JsonVariantConst src) {
|
||||
auto data = getData(src);
|
||||
if (!data)
|
||||
return {};
|
||||
auto rawstr = data->asRawString();
|
||||
auto p = reinterpret_cast<const uint8_t*>(rawstr.c_str());
|
||||
auto n = rawstr.size();
|
||||
if (n >= 2 && p[0] == 0xc4) { // bin 8
|
||||
size_t size = p[1];
|
||||
if (size + 2 == n)
|
||||
return MsgPackBinary(p + 2, size);
|
||||
} else if (n >= 3 && p[0] == 0xc5) { // bin 16
|
||||
size_t size = size_t(p[1] << 8) | p[2];
|
||||
if (size + 3 == n)
|
||||
return MsgPackBinary(p + 3, size);
|
||||
} else if (n >= 5 && p[0] == 0xc6) { // bin 32
|
||||
size_t size =
|
||||
size_t(p[1] << 24) | size_t(p[2] << 16) | size_t(p[3] << 8) | p[4];
|
||||
if (size + 5 == n)
|
||||
return MsgPackBinary(p + 5, size);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static bool checkJson(JsonVariantConst src) {
|
||||
return fromJson(src).data() != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@ -1,26 +1,26 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Deserialization/deserialize.hpp>
|
||||
#include <ArduinoJson/Memory/MemoryPool.hpp>
|
||||
#include <ArduinoJson/MsgPack/endianess.hpp>
|
||||
#include <ArduinoJson/Memory/ResourceManager.hpp>
|
||||
#include <ArduinoJson/Memory/StringBuffer.hpp>
|
||||
#include <ArduinoJson/MsgPack/endianness.hpp>
|
||||
#include <ArduinoJson/MsgPack/ieee754.hpp>
|
||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TReader, typename TStringStorage>
|
||||
template <typename TReader>
|
||||
class MsgPackDeserializer {
|
||||
public:
|
||||
MsgPackDeserializer(MemoryPool* pool, TReader reader,
|
||||
TStringStorage stringStorage)
|
||||
: pool_(pool),
|
||||
MsgPackDeserializer(ResourceManager* resources, TReader reader)
|
||||
: resources_(resources),
|
||||
reader_(reader),
|
||||
stringStorage_(stringStorage),
|
||||
stringBuffer_(resources),
|
||||
foundSomething_(false) {}
|
||||
|
||||
template <typename TFilter>
|
||||
@ -38,11 +38,13 @@ class MsgPackDeserializer {
|
||||
DeserializationOption::NestingLimit nestingLimit) {
|
||||
DeserializationError::Code err;
|
||||
|
||||
uint8_t code = 0; // TODO: why do we need to initialize this variable?
|
||||
err = readByte(code);
|
||||
uint8_t header[5];
|
||||
err = readBytes(header, 1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
const uint8_t& code = header[0];
|
||||
|
||||
foundSomething_ = true;
|
||||
|
||||
bool allowValue = filter.allowValue();
|
||||
@ -52,6 +54,14 @@ class MsgPackDeserializer {
|
||||
ARDUINOJSON_ASSERT(variant != 0);
|
||||
}
|
||||
|
||||
if (code >= 0xcc && code <= 0xd3) {
|
||||
auto width = uint8_t(1U << ((code - 0xcc) % 4));
|
||||
if (allowValue)
|
||||
return readInteger(variant, width, code >= 0xd0);
|
||||
else
|
||||
return skipBytes(width);
|
||||
}
|
||||
|
||||
switch (code) {
|
||||
case 0xc0:
|
||||
// already null
|
||||
@ -61,33 +71,11 @@ class MsgPackDeserializer {
|
||||
return DeserializationError::InvalidInput;
|
||||
|
||||
case 0xc2:
|
||||
if (allowValue)
|
||||
variant->setBoolean(false);
|
||||
return DeserializationError::Ok;
|
||||
|
||||
case 0xc3:
|
||||
if (allowValue)
|
||||
variant->setBoolean(true);
|
||||
variant->setBoolean(code == 0xc3);
|
||||
return DeserializationError::Ok;
|
||||
|
||||
case 0xc4: // bin 8 (not supported)
|
||||
return skipString<uint8_t>();
|
||||
|
||||
case 0xc5: // bin 16 (not supported)
|
||||
return skipString<uint16_t>();
|
||||
|
||||
case 0xc6: // bin 32 (not supported)
|
||||
return skipString<uint32_t>();
|
||||
|
||||
case 0xc7: // ext 8 (not supported)
|
||||
return skipExt<uint8_t>();
|
||||
|
||||
case 0xc8: // ext 16 (not supported)
|
||||
return skipExt<uint16_t>();
|
||||
|
||||
case 0xc9: // ext 32 (not supported)
|
||||
return skipExt<uint32_t>();
|
||||
|
||||
case 0xca:
|
||||
if (allowValue)
|
||||
return readFloat<float>(variant);
|
||||
@ -99,128 +87,97 @@ class MsgPackDeserializer {
|
||||
return readDouble<double>(variant);
|
||||
else
|
||||
return skipBytes(8);
|
||||
}
|
||||
|
||||
case 0xcc:
|
||||
if (allowValue)
|
||||
return readInteger<uint8_t>(variant);
|
||||
else
|
||||
return skipBytes(1);
|
||||
if (code <= 0x7f || code >= 0xe0) { // fixint
|
||||
if (allowValue)
|
||||
variant->setInteger(static_cast<int8_t>(code), resources_);
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
case 0xcd:
|
||||
if (allowValue)
|
||||
return readInteger<uint16_t>(variant);
|
||||
else
|
||||
return skipBytes(2);
|
||||
uint8_t sizeBytes = 0;
|
||||
size_t size = 0;
|
||||
bool isExtension = code >= 0xc7 && code <= 0xc9;
|
||||
|
||||
case 0xce:
|
||||
if (allowValue)
|
||||
return readInteger<uint32_t>(variant);
|
||||
else
|
||||
return skipBytes(4);
|
||||
switch (code) {
|
||||
case 0xc4: // bin 8
|
||||
case 0xc7: // ext 8
|
||||
case 0xd9: // str 8
|
||||
sizeBytes = 1;
|
||||
break;
|
||||
|
||||
case 0xcf:
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
if (allowValue)
|
||||
return readInteger<uint64_t>(variant);
|
||||
else
|
||||
return skipBytes(8);
|
||||
#else
|
||||
return skipBytes(8); // not supported
|
||||
#endif
|
||||
case 0xc5: // bin 16
|
||||
case 0xc8: // ext 16
|
||||
case 0xda: // str 16
|
||||
case 0xdc: // array 16
|
||||
case 0xde: // map 16
|
||||
sizeBytes = 2;
|
||||
break;
|
||||
|
||||
case 0xd0:
|
||||
if (allowValue)
|
||||
return readInteger<int8_t>(variant);
|
||||
else
|
||||
return skipBytes(1);
|
||||
case 0xc6: // bin 32
|
||||
case 0xc9: // ext 32
|
||||
case 0xdb: // str 32
|
||||
case 0xdd: // array 32
|
||||
case 0xdf: // map 32
|
||||
sizeBytes = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xd1:
|
||||
if (allowValue)
|
||||
return readInteger<int16_t>(variant);
|
||||
else
|
||||
return skipBytes(2);
|
||||
|
||||
case 0xd2:
|
||||
if (allowValue)
|
||||
return readInteger<int32_t>(variant);
|
||||
else
|
||||
return skipBytes(4);
|
||||
|
||||
case 0xd3:
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
if (allowValue)
|
||||
return readInteger<int64_t>(variant);
|
||||
else
|
||||
return skipBytes(8); // not supported
|
||||
#else
|
||||
return skipBytes(8);
|
||||
#endif
|
||||
|
||||
case 0xd4: // fixext 1 (not supported)
|
||||
return skipBytes(2);
|
||||
|
||||
case 0xd5: // fixext 2 (not supported)
|
||||
return skipBytes(3);
|
||||
|
||||
case 0xd6: // fixext 4 (not supported)
|
||||
return skipBytes(5);
|
||||
|
||||
case 0xd7: // fixext 8 (not supported)
|
||||
return skipBytes(9);
|
||||
|
||||
case 0xd8: // fixext 16 (not supported)
|
||||
return skipBytes(17);
|
||||
|
||||
case 0xd9:
|
||||
if (allowValue)
|
||||
return readString<uint8_t>(variant);
|
||||
else
|
||||
return skipString<uint8_t>();
|
||||
|
||||
case 0xda:
|
||||
if (allowValue)
|
||||
return readString<uint16_t>(variant);
|
||||
else
|
||||
return skipString<uint16_t>();
|
||||
|
||||
case 0xdb:
|
||||
if (allowValue)
|
||||
return readString<uint32_t>(variant);
|
||||
else
|
||||
return skipString<uint32_t>();
|
||||
|
||||
case 0xdc:
|
||||
return readArray<uint16_t>(variant, filter, nestingLimit);
|
||||
|
||||
case 0xdd:
|
||||
return readArray<uint32_t>(variant, filter, nestingLimit);
|
||||
|
||||
case 0xde:
|
||||
return readObject<uint16_t>(variant, filter, nestingLimit);
|
||||
|
||||
case 0xdf:
|
||||
return readObject<uint32_t>(variant, filter, nestingLimit);
|
||||
if (code >= 0xd4 && code <= 0xd8) { // fixext
|
||||
size = size_t(1) << (code - 0xd4);
|
||||
isExtension = true;
|
||||
}
|
||||
|
||||
switch (code & 0xf0) {
|
||||
case 0x80:
|
||||
return readObject(variant, code & 0x0F, filter, nestingLimit);
|
||||
|
||||
case 0x90:
|
||||
return readArray(variant, code & 0x0F, filter, nestingLimit);
|
||||
case 0x90: // fixarray
|
||||
case 0x80: // fixmap
|
||||
size = code & 0x0F;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((code & 0xe0) == 0xa0) {
|
||||
switch (code & 0xe0) {
|
||||
case 0xa0: // fixstr
|
||||
size = code & 0x1f;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sizeBytes) {
|
||||
err = readBytes(header + 1, sizeBytes);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
uint32_t size32 = 0;
|
||||
for (uint8_t i = 0; i < sizeBytes; i++)
|
||||
size32 = (size32 << 8) | header[i + 1];
|
||||
|
||||
size = size_t(size32);
|
||||
if (size < size32) // integer overflow
|
||||
return DeserializationError::NoMemory; // (not testable on 32/64-bit)
|
||||
}
|
||||
|
||||
// array 16, 32 and fixarray
|
||||
if (code == 0xdc || code == 0xdd || (code & 0xf0) == 0x90)
|
||||
return readArray(variant, size, filter, nestingLimit);
|
||||
|
||||
// map 16, 32 and fixmap
|
||||
if (code == 0xde || code == 0xdf || (code & 0xf0) == 0x80)
|
||||
return readObject(variant, size, filter, nestingLimit);
|
||||
|
||||
// str 8, 16, 32 and fixstr
|
||||
if (code == 0xd9 || code == 0xda || code == 0xdb || (code & 0xe0) == 0xa0) {
|
||||
if (allowValue)
|
||||
return readString(variant, code & 0x1f);
|
||||
return readString(variant, size);
|
||||
else
|
||||
return skipBytes(code & 0x1f);
|
||||
return skipBytes(size);
|
||||
}
|
||||
|
||||
if (isExtension)
|
||||
size++; // to include the type
|
||||
|
||||
if (allowValue)
|
||||
variant->setInteger(static_cast<int8_t>(code));
|
||||
|
||||
return DeserializationError::Ok;
|
||||
return readRawString(variant, header, uint8_t(1 + sizeBytes), size);
|
||||
else
|
||||
return skipBytes(size);
|
||||
}
|
||||
|
||||
DeserializationError::Code readByte(uint8_t& value) {
|
||||
@ -231,7 +188,7 @@ class MsgPackDeserializer {
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
DeserializationError::Code readBytes(uint8_t* p, size_t n) {
|
||||
DeserializationError::Code readBytes(void* p, size_t n) {
|
||||
if (reader_.readBytes(reinterpret_cast<char*>(p), n) == n)
|
||||
return DeserializationError::Ok;
|
||||
return DeserializationError::IncompleteInput;
|
||||
@ -239,7 +196,7 @@ class MsgPackDeserializer {
|
||||
|
||||
template <typename T>
|
||||
DeserializationError::Code readBytes(T& value) {
|
||||
return readBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
|
||||
return readBytes(&value, sizeof(value));
|
||||
}
|
||||
|
||||
DeserializationError::Code skipBytes(size_t n) {
|
||||
@ -250,36 +207,48 @@ class MsgPackDeserializer {
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DeserializationError::Code readInteger(T& value) {
|
||||
DeserializationError::Code err;
|
||||
DeserializationError::Code readInteger(VariantData* variant, uint8_t width,
|
||||
bool isSigned) {
|
||||
uint8_t buffer[8];
|
||||
|
||||
err = readBytes(value);
|
||||
auto err = readBytes(buffer, width);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
fixEndianess(value);
|
||||
union {
|
||||
int64_t signedValue;
|
||||
uint64_t unsignedValue;
|
||||
};
|
||||
|
||||
if (isSigned)
|
||||
signedValue = static_cast<int8_t>(buffer[0]); // propagate sign bit
|
||||
else
|
||||
unsignedValue = static_cast<uint8_t>(buffer[0]);
|
||||
|
||||
for (uint8_t i = 1; i < width; i++)
|
||||
unsignedValue = (unsignedValue << 8) | buffer[i];
|
||||
|
||||
if (isSigned) {
|
||||
auto truncatedValue = static_cast<JsonInteger>(signedValue);
|
||||
if (truncatedValue == signedValue) {
|
||||
if (!variant->setInteger(truncatedValue, resources_))
|
||||
return DeserializationError::NoMemory;
|
||||
}
|
||||
// else set null on overflow
|
||||
} else {
|
||||
auto truncatedValue = static_cast<JsonUInt>(unsignedValue);
|
||||
if (truncatedValue == unsignedValue)
|
||||
if (!variant->setInteger(truncatedValue, resources_))
|
||||
return DeserializationError::NoMemory;
|
||||
// else set null on overflow
|
||||
}
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DeserializationError::Code readInteger(VariantData* variant) {
|
||||
DeserializationError::Code err;
|
||||
T value;
|
||||
|
||||
err = readInteger(value);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
variant->setInteger(value);
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<sizeof(T) == 4, DeserializationError::Code>::type
|
||||
readFloat(VariantData* variant) {
|
||||
enable_if_t<sizeof(T) == 4, DeserializationError::Code> readFloat(
|
||||
VariantData* variant) {
|
||||
DeserializationError::Code err;
|
||||
T value;
|
||||
|
||||
@ -287,15 +256,15 @@ class MsgPackDeserializer {
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
fixEndianess(value);
|
||||
variant->setFloat(value);
|
||||
fixEndianness(value);
|
||||
variant->setFloat(value, resources_);
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<sizeof(T) == 8, DeserializationError::Code>::type
|
||||
readDouble(VariantData* variant) {
|
||||
enable_if_t<sizeof(T) == 8, DeserializationError::Code> readDouble(
|
||||
VariantData* variant) {
|
||||
DeserializationError::Code err;
|
||||
T value;
|
||||
|
||||
@ -303,15 +272,16 @@ class MsgPackDeserializer {
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
fixEndianess(value);
|
||||
variant->setFloat(value);
|
||||
|
||||
return DeserializationError::Ok;
|
||||
fixEndianness(value);
|
||||
if (variant->setFloat(value, resources_))
|
||||
return DeserializationError::Ok;
|
||||
else
|
||||
return DeserializationError::NoMemory;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<sizeof(T) == 4, DeserializationError::Code>::type
|
||||
readDouble(VariantData* variant) {
|
||||
enable_if_t<sizeof(T) == 4, DeserializationError::Code> readDouble(
|
||||
VariantData* variant) {
|
||||
DeserializationError::Code err;
|
||||
uint8_t i[8]; // input is 8 bytes
|
||||
T value; // output is 4 bytes
|
||||
@ -322,48 +292,12 @@ class MsgPackDeserializer {
|
||||
return err;
|
||||
|
||||
doubleToFloat(i, o);
|
||||
fixEndianess(value);
|
||||
variant->setFloat(value);
|
||||
fixEndianness(value);
|
||||
variant->setFloat(value, resources_);
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DeserializationError::Code readString(VariantData* variant) {
|
||||
DeserializationError::Code err;
|
||||
T size;
|
||||
|
||||
err = readInteger(size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return readString(variant, size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DeserializationError::Code readString() {
|
||||
DeserializationError::Code err;
|
||||
T size;
|
||||
|
||||
err = readInteger(size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return readString(size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DeserializationError::Code skipString() {
|
||||
DeserializationError::Code err;
|
||||
T size;
|
||||
|
||||
err = readInteger(size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return skipBytes(size);
|
||||
}
|
||||
|
||||
DeserializationError::Code readString(VariantData* variant, size_t n) {
|
||||
DeserializationError::Code err;
|
||||
|
||||
@ -371,42 +305,37 @@ class MsgPackDeserializer {
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
variant->setString(stringStorage_.save());
|
||||
stringBuffer_.save(variant);
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
DeserializationError::Code readString(size_t n) {
|
||||
DeserializationError::Code err;
|
||||
|
||||
stringStorage_.startString();
|
||||
for (; n; --n) {
|
||||
uint8_t c;
|
||||
|
||||
err = readBytes(c);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
stringStorage_.append(static_cast<char>(c));
|
||||
}
|
||||
|
||||
if (!stringStorage_.isValid())
|
||||
char* p = stringBuffer_.reserve(n);
|
||||
if (!p)
|
||||
return DeserializationError::NoMemory;
|
||||
|
||||
return DeserializationError::Ok;
|
||||
return readBytes(p, n);
|
||||
}
|
||||
|
||||
template <typename TSize, typename TFilter>
|
||||
DeserializationError::Code readArray(
|
||||
VariantData* variant, TFilter filter,
|
||||
DeserializationOption::NestingLimit nestingLimit) {
|
||||
DeserializationError::Code err;
|
||||
TSize size;
|
||||
DeserializationError::Code readRawString(VariantData* variant,
|
||||
const void* header,
|
||||
uint8_t headerSize, size_t n) {
|
||||
auto totalSize = size_t(headerSize + n);
|
||||
if (totalSize < n) // integer overflow
|
||||
return DeserializationError::NoMemory; // (not testable on 64-bit)
|
||||
|
||||
err = readInteger(size);
|
||||
char* p = stringBuffer_.reserve(totalSize);
|
||||
if (!p)
|
||||
return DeserializationError::NoMemory;
|
||||
|
||||
memcpy(p, header, headerSize);
|
||||
|
||||
auto err = readBytes(p + headerSize, n);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return readArray(variant, size, filter, nestingLimit);
|
||||
stringBuffer_.saveRaw(variant);
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename TFilter>
|
||||
@ -420,7 +349,7 @@ class MsgPackDeserializer {
|
||||
|
||||
bool allowArray = filter.allowArray();
|
||||
|
||||
CollectionData* array;
|
||||
ArrayData* array;
|
||||
if (allowArray) {
|
||||
ARDUINOJSON_ASSERT(variant != 0);
|
||||
array = &variant->toArray();
|
||||
@ -428,21 +357,21 @@ class MsgPackDeserializer {
|
||||
array = 0;
|
||||
}
|
||||
|
||||
TFilter memberFilter = filter[0U];
|
||||
TFilter elementFilter = filter[0U];
|
||||
|
||||
for (; n; --n) {
|
||||
VariantData* value;
|
||||
|
||||
if (memberFilter.allow()) {
|
||||
if (elementFilter.allow()) {
|
||||
ARDUINOJSON_ASSERT(array != 0);
|
||||
value = array->addElement(pool_);
|
||||
value = array->addElement(resources_);
|
||||
if (!value)
|
||||
return DeserializationError::NoMemory;
|
||||
} else {
|
||||
value = 0;
|
||||
}
|
||||
|
||||
err = parseVariant(value, memberFilter, nestingLimit.decrement());
|
||||
err = parseVariant(value, elementFilter, nestingLimit.decrement());
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@ -450,20 +379,6 @@ class MsgPackDeserializer {
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename TSize, typename TFilter>
|
||||
DeserializationError::Code readObject(
|
||||
VariantData* variant, TFilter filter,
|
||||
DeserializationOption::NestingLimit nestingLimit) {
|
||||
DeserializationError::Code err;
|
||||
TSize size;
|
||||
|
||||
err = readInteger(size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return readObject(variant, size, filter, nestingLimit);
|
||||
}
|
||||
|
||||
template <typename TFilter>
|
||||
DeserializationError::Code readObject(
|
||||
VariantData* variant, size_t n, TFilter filter,
|
||||
@ -473,7 +388,7 @@ class MsgPackDeserializer {
|
||||
if (nestingLimit.reached())
|
||||
return DeserializationError::TooDeep;
|
||||
|
||||
CollectionData* object;
|
||||
ObjectData* object;
|
||||
if (filter.allowObject()) {
|
||||
ARDUINOJSON_ASSERT(variant != 0);
|
||||
object = &variant->toObject();
|
||||
@ -486,26 +401,18 @@ class MsgPackDeserializer {
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
JsonString key = stringStorage_.str();
|
||||
JsonString key = stringBuffer_.str();
|
||||
TFilter memberFilter = filter[key.c_str()];
|
||||
VariantData* member;
|
||||
VariantData* member = 0;
|
||||
|
||||
if (memberFilter.allow()) {
|
||||
ARDUINOJSON_ASSERT(object != 0);
|
||||
|
||||
// Save key in memory pool.
|
||||
// This MUST be done before adding the slot.
|
||||
key = stringStorage_.save();
|
||||
|
||||
VariantSlot* slot = object->addSlot(pool_);
|
||||
if (!slot)
|
||||
auto keyVariant = object->addPair(&member, resources_);
|
||||
if (!keyVariant)
|
||||
return DeserializationError::NoMemory;
|
||||
|
||||
slot->setKey(key);
|
||||
|
||||
member = slot->data();
|
||||
} else {
|
||||
member = 0;
|
||||
stringBuffer_.save(keyVariant);
|
||||
}
|
||||
|
||||
err = parseVariant(member, memberFilter, nestingLimit.decrement());
|
||||
@ -527,36 +434,24 @@ class MsgPackDeserializer {
|
||||
if ((code & 0xe0) == 0xa0)
|
||||
return readString(code & 0x1f);
|
||||
|
||||
switch (code) {
|
||||
case 0xd9:
|
||||
return readString<uint8_t>();
|
||||
|
||||
case 0xda:
|
||||
return readString<uint16_t>();
|
||||
|
||||
case 0xdb:
|
||||
return readString<uint32_t>();
|
||||
|
||||
default:
|
||||
return DeserializationError::InvalidInput;
|
||||
if (code >= 0xd9 && code <= 0xdb) {
|
||||
uint8_t sizeBytes = uint8_t(1U << (code - 0xd9));
|
||||
uint32_t size = 0;
|
||||
for (uint8_t i = 0; i < sizeBytes; i++) {
|
||||
err = readByte(code);
|
||||
if (err)
|
||||
return err;
|
||||
size = (size << 8) | code;
|
||||
}
|
||||
return readString(size);
|
||||
}
|
||||
|
||||
return DeserializationError::InvalidInput;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DeserializationError::Code skipExt() {
|
||||
DeserializationError::Code err;
|
||||
T size;
|
||||
|
||||
err = readInteger(size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return skipBytes(size + 1U);
|
||||
}
|
||||
|
||||
MemoryPool* pool_;
|
||||
ResourceManager* resources_;
|
||||
TReader reader_;
|
||||
TStringStorage stringStorage_;
|
||||
StringBuffer stringBuffer_;
|
||||
bool foundSomething_;
|
||||
};
|
||||
|
||||
@ -565,20 +460,27 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// Parses a MessagePack input and puts the result in a JsonDocument.
|
||||
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
|
||||
template <typename... Args>
|
||||
DeserializationError deserializeMsgPack(JsonDocument& doc, Args&&... args) {
|
||||
// https://arduinojson.org/v7/api/msgpack/deserializemsgpack/
|
||||
template <typename TDestination, typename... Args,
|
||||
detail::enable_if_t<
|
||||
detail::is_deserialize_destination<TDestination>::value, int> = 0>
|
||||
inline DeserializationError deserializeMsgPack(TDestination&& dst,
|
||||
Args&&... args) {
|
||||
using namespace detail;
|
||||
return deserialize<MsgPackDeserializer>(doc, detail::forward<Args>(args)...);
|
||||
return deserialize<MsgPackDeserializer>(detail::forward<TDestination>(dst),
|
||||
detail::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Parses a MessagePack input and puts the result in a JsonDocument.
|
||||
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
|
||||
template <typename TChar, typename... Args>
|
||||
DeserializationError deserializeMsgPack(JsonDocument& doc, TChar* input,
|
||||
Args&&... args) {
|
||||
// https://arduinojson.org/v7/api/msgpack/deserializemsgpack/
|
||||
template <typename TDestination, typename TChar, typename... Args,
|
||||
detail::enable_if_t<
|
||||
detail::is_deserialize_destination<TDestination>::value, int> = 0>
|
||||
inline DeserializationError deserializeMsgPack(TDestination&& dst, TChar* input,
|
||||
Args&&... args) {
|
||||
using namespace detail;
|
||||
return deserialize<MsgPackDeserializer>(doc, input,
|
||||
return deserialize<MsgPackDeserializer>(detail::forward<TDestination>(dst),
|
||||
input,
|
||||
detail::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,120 @@
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Variant/Converter.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
class MsgPackExtension {
|
||||
public:
|
||||
MsgPackExtension() : data_(nullptr), size_(0), type_(0) {}
|
||||
explicit MsgPackExtension(int8_t type, const void* data, size_t size)
|
||||
: data_(data), size_(size), type_(type) {}
|
||||
|
||||
int8_t type() const {
|
||||
return type_;
|
||||
}
|
||||
|
||||
const void* data() const {
|
||||
return data_;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return size_;
|
||||
}
|
||||
|
||||
private:
|
||||
const void* data_;
|
||||
size_t size_;
|
||||
int8_t type_;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<MsgPackExtension> : private detail::VariantAttorney {
|
||||
static void toJson(MsgPackExtension src, JsonVariant dst) {
|
||||
auto data = VariantAttorney::getData(dst);
|
||||
if (!data)
|
||||
return;
|
||||
auto resources = getResourceManager(dst);
|
||||
data->clear(resources);
|
||||
if (src.data()) {
|
||||
uint8_t format, sizeBytes;
|
||||
if (src.size() >= 0x10000) {
|
||||
format = 0xc9; // ext 32
|
||||
sizeBytes = 4;
|
||||
} else if (src.size() >= 0x100) {
|
||||
format = 0xc8; // ext 16
|
||||
sizeBytes = 2;
|
||||
} else if (src.size() == 16) {
|
||||
format = 0xd8; // fixext 16
|
||||
sizeBytes = 0;
|
||||
} else if (src.size() == 8) {
|
||||
format = 0xd7; // fixext 8
|
||||
sizeBytes = 0;
|
||||
} else if (src.size() == 4) {
|
||||
format = 0xd6; // fixext 4
|
||||
sizeBytes = 0;
|
||||
} else if (src.size() == 2) {
|
||||
format = 0xd5; // fixext 2
|
||||
sizeBytes = 0;
|
||||
} else if (src.size() == 1) {
|
||||
format = 0xd4; // fixext 1
|
||||
sizeBytes = 0;
|
||||
} else {
|
||||
format = 0xc7; // ext 8
|
||||
sizeBytes = 1;
|
||||
}
|
||||
|
||||
auto str = resources->createString(src.size() + 2 + sizeBytes);
|
||||
if (str) {
|
||||
resources->saveString(str);
|
||||
auto ptr = reinterpret_cast<uint8_t*>(str->data);
|
||||
*ptr++ = uint8_t(format);
|
||||
for (uint8_t i = 0; i < sizeBytes; i++)
|
||||
*ptr++ = uint8_t(src.size() >> (sizeBytes - i - 1) * 8 & 0xff);
|
||||
*ptr++ = uint8_t(src.type());
|
||||
memcpy(ptr, src.data(), src.size());
|
||||
data->setRawString(str);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static MsgPackExtension fromJson(JsonVariantConst src) {
|
||||
auto data = getData(src);
|
||||
if (!data)
|
||||
return {};
|
||||
auto rawstr = data->asRawString();
|
||||
if (rawstr.size() == 0)
|
||||
return {};
|
||||
auto p = reinterpret_cast<const uint8_t*>(rawstr.c_str());
|
||||
|
||||
size_t payloadSize = 0;
|
||||
uint8_t headerSize = 0;
|
||||
|
||||
const uint8_t& code = p[0];
|
||||
|
||||
if (code >= 0xd4 && code <= 0xd8) { // fixext 1
|
||||
headerSize = 2;
|
||||
payloadSize = size_t(1) << (code - 0xd4);
|
||||
}
|
||||
|
||||
if (code >= 0xc7 && code <= 0xc9) {
|
||||
uint8_t sizeBytes = uint8_t(1 << (code - 0xc7));
|
||||
for (uint8_t i = 0; i < sizeBytes; i++)
|
||||
payloadSize = (payloadSize << 8) | p[1 + i];
|
||||
headerSize = uint8_t(2 + sizeBytes);
|
||||
}
|
||||
|
||||
if (rawstr.size() == headerSize + payloadSize)
|
||||
return MsgPackExtension(int8_t(p[headerSize - 1]), p + headerSize,
|
||||
payloadSize);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static bool checkJson(JsonVariantConst src) {
|
||||
return fromJson(src).data() != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@ -1,10 +1,10 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/MsgPack/endianess.hpp>
|
||||
#include <ArduinoJson/MsgPack/endianness.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||
#include <ArduinoJson/Serialization/CountingDecorator.hpp>
|
||||
@ -15,18 +15,20 @@
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TWriter>
|
||||
class MsgPackSerializer : public Visitor<size_t> {
|
||||
class MsgPackSerializer : public VariantDataVisitor<size_t> {
|
||||
public:
|
||||
static const bool producesText = false;
|
||||
|
||||
MsgPackSerializer(TWriter writer) : writer_(writer) {}
|
||||
MsgPackSerializer(TWriter writer, const ResourceManager* resources)
|
||||
: writer_(writer), resources_(resources) {}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<sizeof(T) == 4, size_t>::type visitFloat(T value32) {
|
||||
enable_if_t<is_floating_point<T>::value && sizeof(T) == 4, size_t> visit(
|
||||
T value32) {
|
||||
if (canConvertNumber<JsonInteger>(value32)) {
|
||||
JsonInteger truncatedValue = JsonInteger(value32);
|
||||
if (value32 == T(truncatedValue))
|
||||
return visitSignedInteger(truncatedValue);
|
||||
return visit(truncatedValue);
|
||||
}
|
||||
writeByte(0xCA);
|
||||
writeInteger(value32);
|
||||
@ -35,17 +37,18 @@ class MsgPackSerializer : public Visitor<size_t> {
|
||||
|
||||
template <typename T>
|
||||
ARDUINOJSON_NO_SANITIZE("float-cast-overflow")
|
||||
typename enable_if<sizeof(T) == 8, size_t>::type visitFloat(T value64) {
|
||||
enable_if_t<is_floating_point<T>::value && sizeof(T) == 8, size_t> visit(
|
||||
T value64) {
|
||||
float value32 = float(value64);
|
||||
if (value32 == value64)
|
||||
return visitFloat(value32);
|
||||
return visit(value32);
|
||||
writeByte(0xCB);
|
||||
writeInteger(value64);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitArray(const CollectionData& array) {
|
||||
size_t n = array.size();
|
||||
size_t visit(const ArrayData& array) {
|
||||
size_t n = array.size(resources_);
|
||||
if (n < 0x10) {
|
||||
writeByte(uint8_t(0x90 + n));
|
||||
} else if (n < 0x10000) {
|
||||
@ -55,14 +58,19 @@ class MsgPackSerializer : public Visitor<size_t> {
|
||||
writeByte(0xDD);
|
||||
writeInteger(uint32_t(n));
|
||||
}
|
||||
for (const VariantSlot* slot = array.head(); slot; slot = slot->next()) {
|
||||
slot->data()->accept(*this);
|
||||
|
||||
auto slotId = array.head();
|
||||
while (slotId != NULL_SLOT) {
|
||||
auto slot = resources_->getVariant(slotId);
|
||||
slot->accept(*this, resources_);
|
||||
slotId = slot->next();
|
||||
}
|
||||
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitObject(const CollectionData& object) {
|
||||
size_t n = object.size();
|
||||
size_t visit(const ObjectData& object) {
|
||||
size_t n = object.size(resources_);
|
||||
if (n < 0x10) {
|
||||
writeByte(uint8_t(0x80 + n));
|
||||
} else if (n < 0x10000) {
|
||||
@ -72,19 +80,25 @@ class MsgPackSerializer : public Visitor<size_t> {
|
||||
writeByte(0xDF);
|
||||
writeInteger(uint32_t(n));
|
||||
}
|
||||
for (const VariantSlot* slot = object.head(); slot; slot = slot->next()) {
|
||||
visitString(slot->key());
|
||||
slot->data()->accept(*this);
|
||||
|
||||
auto slotId = object.head();
|
||||
while (slotId != NULL_SLOT) {
|
||||
auto slot = resources_->getVariant(slotId);
|
||||
slot->accept(*this, resources_);
|
||||
slotId = slot->next();
|
||||
}
|
||||
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitString(const char* value) {
|
||||
return visitString(value, strlen(value));
|
||||
size_t visit(const char* value) {
|
||||
return visit(JsonString(value));
|
||||
}
|
||||
|
||||
size_t visitString(const char* value, size_t n) {
|
||||
ARDUINOJSON_ASSERT(value != NULL);
|
||||
size_t visit(JsonString value) {
|
||||
ARDUINOJSON_ASSERT(!value.isNull());
|
||||
|
||||
auto n = value.size();
|
||||
|
||||
if (n < 0x20) {
|
||||
writeByte(uint8_t(0xA0 + n));
|
||||
@ -98,18 +112,18 @@ class MsgPackSerializer : public Visitor<size_t> {
|
||||
writeByte(0xDB);
|
||||
writeInteger(uint32_t(n));
|
||||
}
|
||||
writeBytes(reinterpret_cast<const uint8_t*>(value), n);
|
||||
writeBytes(reinterpret_cast<const uint8_t*>(value.c_str()), n);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitRawJson(const char* data, size_t size) {
|
||||
writeBytes(reinterpret_cast<const uint8_t*>(data), size);
|
||||
size_t visit(RawString value) {
|
||||
writeBytes(reinterpret_cast<const uint8_t*>(value.data()), value.size());
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitSignedInteger(JsonInteger value) {
|
||||
size_t visit(JsonInteger value) {
|
||||
if (value > 0) {
|
||||
visitUnsignedInteger(static_cast<JsonUInt>(value));
|
||||
visit(static_cast<JsonUInt>(value));
|
||||
} else if (value >= -0x20) {
|
||||
writeInteger(int8_t(value));
|
||||
} else if (value >= -0x80) {
|
||||
@ -137,7 +151,7 @@ class MsgPackSerializer : public Visitor<size_t> {
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitUnsignedInteger(JsonUInt value) {
|
||||
size_t visit(JsonUInt value) {
|
||||
if (value <= 0x7F) {
|
||||
writeInteger(uint8_t(value));
|
||||
} else if (value <= 0xFF) {
|
||||
@ -165,12 +179,12 @@ class MsgPackSerializer : public Visitor<size_t> {
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitBoolean(bool value) {
|
||||
size_t visit(bool value) {
|
||||
writeByte(value ? 0xC3 : 0xC2);
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visitNull() {
|
||||
size_t visit(nullptr_t) {
|
||||
writeByte(0xC0);
|
||||
return bytesWritten();
|
||||
}
|
||||
@ -190,11 +204,12 @@ class MsgPackSerializer : public Visitor<size_t> {
|
||||
|
||||
template <typename T>
|
||||
void writeInteger(T value) {
|
||||
fixEndianess(value);
|
||||
fixEndianness(value);
|
||||
writeBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
|
||||
}
|
||||
|
||||
CountingDecorator<TWriter> writer_;
|
||||
const ResourceManager* resources_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@ -202,15 +217,17 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// Produces a MessagePack document.
|
||||
// https://arduinojson.org/v6/api/msgpack/serializemsgpack/
|
||||
template <typename TDestination>
|
||||
// https://arduinojson.org/v7/api/msgpack/serializemsgpack/
|
||||
template <
|
||||
typename TDestination,
|
||||
detail::enable_if_t<!detail::is_pointer<TDestination>::value, int> = 0>
|
||||
inline size_t serializeMsgPack(JsonVariantConst source, TDestination& output) {
|
||||
using namespace ArduinoJson::detail;
|
||||
return serialize<MsgPackSerializer>(source, output);
|
||||
}
|
||||
|
||||
// Produces a MessagePack document.
|
||||
// https://arduinojson.org/v6/api/msgpack/serializemsgpack/
|
||||
// https://arduinojson.org/v7/api/msgpack/serializemsgpack/
|
||||
inline size_t serializeMsgPack(JsonVariantConst source, void* output,
|
||||
size_t size) {
|
||||
using namespace ArduinoJson::detail;
|
||||
@ -218,7 +235,7 @@ inline size_t serializeMsgPack(JsonVariantConst source, void* output,
|
||||
}
|
||||
|
||||
// Computes the length of the document that serializeMsgPack() produces.
|
||||
// https://arduinojson.org/v6/api/msgpack/measuremsgpack/
|
||||
// https://arduinojson.org/v7/api/msgpack/measuremsgpack/
|
||||
inline size_t measureMsgPack(JsonVariantConst source) {
|
||||
using namespace ArduinoJson::detail;
|
||||
return measure<MsgPackSerializer>(source);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -15,32 +15,32 @@ inline void swapBytes(uint8_t& a, uint8_t& b) {
|
||||
b = t;
|
||||
}
|
||||
|
||||
inline void fixEndianess(uint8_t* p, integral_constant<size_t, 8>) {
|
||||
inline void fixEndianness(uint8_t* p, integral_constant<size_t, 8>) {
|
||||
swapBytes(p[0], p[7]);
|
||||
swapBytes(p[1], p[6]);
|
||||
swapBytes(p[2], p[5]);
|
||||
swapBytes(p[3], p[4]);
|
||||
}
|
||||
|
||||
inline void fixEndianess(uint8_t* p, integral_constant<size_t, 4>) {
|
||||
inline void fixEndianness(uint8_t* p, integral_constant<size_t, 4>) {
|
||||
swapBytes(p[0], p[3]);
|
||||
swapBytes(p[1], p[2]);
|
||||
}
|
||||
|
||||
inline void fixEndianess(uint8_t* p, integral_constant<size_t, 2>) {
|
||||
inline void fixEndianness(uint8_t* p, integral_constant<size_t, 2>) {
|
||||
swapBytes(p[0], p[1]);
|
||||
}
|
||||
|
||||
inline void fixEndianess(uint8_t*, integral_constant<size_t, 1>) {}
|
||||
inline void fixEndianness(uint8_t*, integral_constant<size_t, 1>) {}
|
||||
|
||||
template <typename T>
|
||||
inline void fixEndianess(T& value) {
|
||||
fixEndianess(reinterpret_cast<uint8_t*>(&value),
|
||||
integral_constant<size_t, sizeof(T)>());
|
||||
inline void fixEndianness(T& value) {
|
||||
fixEndianness(reinterpret_cast<uint8_t*>(&value),
|
||||
integral_constant<size_t, sizeof(T)>());
|
||||
}
|
||||
#else
|
||||
template <typename T>
|
||||
inline void fixEndianess(T&) {}
|
||||
inline void fixEndianness(T&) {}
|
||||
#endif
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -10,16 +10,16 @@
|
||||
|
||||
#ifndef ARDUINOJSON_VERSION_NAMESPACE
|
||||
|
||||
# define ARDUINOJSON_VERSION_NAMESPACE \
|
||||
ARDUINOJSON_CONCAT4( \
|
||||
ARDUINOJSON_VERSION_MACRO, \
|
||||
ARDUINOJSON_BIN2ALPHA( \
|
||||
ARDUINOJSON_ENABLE_PROGMEM, ARDUINOJSON_USE_LONG_LONG, \
|
||||
ARDUINOJSON_USE_DOUBLE, ARDUINOJSON_ENABLE_STRING_DEDUPLICATION), \
|
||||
ARDUINOJSON_BIN2ALPHA( \
|
||||
ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY, \
|
||||
ARDUINOJSON_ENABLE_COMMENTS, ARDUINOJSON_DECODE_UNICODE), \
|
||||
ARDUINOJSON_SLOT_OFFSET_SIZE)
|
||||
# define ARDUINOJSON_VERSION_NAMESPACE \
|
||||
ARDUINOJSON_CONCAT5( \
|
||||
ARDUINOJSON_VERSION_MACRO, \
|
||||
ARDUINOJSON_BIN2ALPHA(ARDUINOJSON_ENABLE_PROGMEM, \
|
||||
ARDUINOJSON_USE_LONG_LONG, \
|
||||
ARDUINOJSON_USE_DOUBLE, 1), \
|
||||
ARDUINOJSON_BIN2ALPHA( \
|
||||
ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY, \
|
||||
ARDUINOJSON_ENABLE_COMMENTS, ARDUINOJSON_DECODE_UNICODE), \
|
||||
ARDUINOJSON_SLOT_ID_SIZE, ARDUINOJSON_STRING_LENGTH_SIZE)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,88 +1,95 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Configuration.hpp>
|
||||
#include <ArduinoJson/Numbers/FloatTraits.hpp>
|
||||
#include <ArduinoJson/Numbers/JsonFloat.hpp>
|
||||
#include <ArduinoJson/Polyfills/math.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TFloat>
|
||||
struct FloatParts {
|
||||
uint32_t integral;
|
||||
uint32_t decimal;
|
||||
int16_t exponent;
|
||||
int8_t decimalPlaces;
|
||||
|
||||
FloatParts(TFloat value) {
|
||||
uint32_t maxDecimalPart = sizeof(TFloat) >= 8 ? 1000000000 : 1000000;
|
||||
decimalPlaces = sizeof(TFloat) >= 8 ? 9 : 6;
|
||||
|
||||
exponent = normalize(value);
|
||||
|
||||
integral = uint32_t(value);
|
||||
// reduce number of decimal places by the number of integral places
|
||||
for (uint32_t tmp = integral; tmp >= 10; tmp /= 10) {
|
||||
maxDecimalPart /= 10;
|
||||
decimalPlaces--;
|
||||
}
|
||||
|
||||
TFloat remainder = (value - TFloat(integral)) * TFloat(maxDecimalPart);
|
||||
|
||||
decimal = uint32_t(remainder);
|
||||
remainder = remainder - TFloat(decimal);
|
||||
|
||||
// rounding:
|
||||
// increment by 1 if remainder >= 0.5
|
||||
decimal += uint32_t(remainder * 2);
|
||||
if (decimal >= maxDecimalPart) {
|
||||
decimal = 0;
|
||||
integral++;
|
||||
if (exponent && integral >= 10) {
|
||||
exponent++;
|
||||
integral = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// remove trailing zeros
|
||||
while (decimal % 10 == 0 && decimalPlaces > 0) {
|
||||
decimal /= 10;
|
||||
decimalPlaces--;
|
||||
}
|
||||
}
|
||||
|
||||
static int16_t normalize(TFloat& value) {
|
||||
typedef FloatTraits<TFloat> traits;
|
||||
int16_t powersOf10 = 0;
|
||||
|
||||
int8_t index = sizeof(TFloat) == 8 ? 8 : 5;
|
||||
int bit = 1 << index;
|
||||
|
||||
if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) {
|
||||
for (; index >= 0; index--) {
|
||||
if (value >= traits::positiveBinaryPowersOfTen()[index]) {
|
||||
value *= traits::negativeBinaryPowersOfTen()[index];
|
||||
powersOf10 = int16_t(powersOf10 + bit);
|
||||
}
|
||||
bit >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) {
|
||||
for (; index >= 0; index--) {
|
||||
if (value < traits::negativeBinaryPowersOfTen()[index] * 10) {
|
||||
value *= traits::positiveBinaryPowersOfTen()[index];
|
||||
powersOf10 = int16_t(powersOf10 - bit);
|
||||
}
|
||||
bit >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return powersOf10;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TFloat>
|
||||
inline int16_t normalize(TFloat& value) {
|
||||
using traits = FloatTraits<TFloat>;
|
||||
int16_t powersOf10 = 0;
|
||||
|
||||
int8_t index = sizeof(TFloat) == 8 ? 8 : 5;
|
||||
int bit = 1 << index;
|
||||
|
||||
if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) {
|
||||
for (; index >= 0; index--) {
|
||||
if (value >= traits::positiveBinaryPowersOfTen()[index]) {
|
||||
value *= traits::negativeBinaryPowersOfTen()[index];
|
||||
powersOf10 = int16_t(powersOf10 + bit);
|
||||
}
|
||||
bit >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) {
|
||||
for (; index >= 0; index--) {
|
||||
if (value < traits::negativeBinaryPowersOfTen()[index] * 10) {
|
||||
value *= traits::positiveBinaryPowersOfTen()[index];
|
||||
powersOf10 = int16_t(powersOf10 - bit);
|
||||
}
|
||||
bit >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return powersOf10;
|
||||
}
|
||||
|
||||
constexpr uint32_t pow10(int exponent) {
|
||||
return (exponent == 0) ? 1 : 10 * pow10(exponent - 1);
|
||||
}
|
||||
|
||||
inline FloatParts decomposeFloat(JsonFloat value, int8_t decimalPlaces) {
|
||||
uint32_t maxDecimalPart = pow10(decimalPlaces);
|
||||
|
||||
int16_t exponent = normalize(value);
|
||||
|
||||
uint32_t integral = uint32_t(value);
|
||||
// reduce number of decimal places by the number of integral places
|
||||
for (uint32_t tmp = integral; tmp >= 10; tmp /= 10) {
|
||||
maxDecimalPart /= 10;
|
||||
decimalPlaces--;
|
||||
}
|
||||
|
||||
JsonFloat remainder =
|
||||
(value - JsonFloat(integral)) * JsonFloat(maxDecimalPart);
|
||||
|
||||
uint32_t decimal = uint32_t(remainder);
|
||||
remainder = remainder - JsonFloat(decimal);
|
||||
|
||||
// rounding:
|
||||
// increment by 1 if remainder >= 0.5
|
||||
decimal += uint32_t(remainder * 2);
|
||||
if (decimal >= maxDecimalPart) {
|
||||
decimal = 0;
|
||||
integral++;
|
||||
if (exponent && integral >= 10) {
|
||||
exponent++;
|
||||
integral = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// remove trailing zeros
|
||||
while (decimal % 10 == 0 && decimalPlaces > 0) {
|
||||
decimal /= 10;
|
||||
decimalPlaces--;
|
||||
}
|
||||
|
||||
return {integral, decimal, exponent, decimalPlaces};
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -21,12 +21,12 @@ struct FloatTraits {};
|
||||
|
||||
template <typename T>
|
||||
struct FloatTraits<T, 8 /*64bits*/> {
|
||||
typedef uint64_t mantissa_type;
|
||||
using mantissa_type = uint64_t;
|
||||
static const short mantissa_bits = 52;
|
||||
static const mantissa_type mantissa_max =
|
||||
(mantissa_type(1) << mantissa_bits) - 1;
|
||||
|
||||
typedef int16_t exponent_type;
|
||||
using exponent_type = int16_t;
|
||||
static const exponent_type exponent_max = 308;
|
||||
|
||||
static pgm_ptr<T> positiveBinaryPowersOfTen() {
|
||||
@ -77,17 +77,17 @@ struct FloatTraits<T, 8 /*64bits*/> {
|
||||
|
||||
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) {
|
||||
enable_if_t<is_integral<TOut>::value && is_signed<TOut>::value &&
|
||||
sizeof(TOut) == 8,
|
||||
signed>* = 0) {
|
||||
return forge(0x43DFFFFFFFFFFFFF); // 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) {
|
||||
enable_if_t<is_integral<TOut>::value && is_unsigned<TOut>::value &&
|
||||
sizeof(TOut) == 8,
|
||||
unsigned>* = 0) {
|
||||
return forge(0x43EFFFFFFFFFFFFF); // 1.8446744073709549568e+19
|
||||
}
|
||||
|
||||
@ -105,12 +105,12 @@ struct FloatTraits<T, 8 /*64bits*/> {
|
||||
|
||||
template <typename T>
|
||||
struct FloatTraits<T, 4 /*32bits*/> {
|
||||
typedef uint32_t mantissa_type;
|
||||
using mantissa_type = uint32_t;
|
||||
static const short mantissa_bits = 23;
|
||||
static const mantissa_type mantissa_max =
|
||||
(mantissa_type(1) << mantissa_bits) - 1;
|
||||
|
||||
typedef int8_t exponent_type;
|
||||
using exponent_type = int8_t;
|
||||
static const exponent_type exponent_max = 38;
|
||||
|
||||
static pgm_ptr<T> positiveBinaryPowersOfTen() {
|
||||
@ -157,33 +157,33 @@ struct FloatTraits<T, 4 /*32bits*/> {
|
||||
|
||||
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) {
|
||||
enable_if_t<is_integral<TOut>::value && is_signed<TOut>::value &&
|
||||
sizeof(TOut) == 4,
|
||||
signed>* = 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) {
|
||||
enable_if_t<is_integral<TOut>::value && is_unsigned<TOut>::value &&
|
||||
sizeof(TOut) == 4,
|
||||
unsigned>* = 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) {
|
||||
enable_if_t<is_integral<TOut>::value && is_signed<TOut>::value &&
|
||||
sizeof(TOut) == 8,
|
||||
signed>* = 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) {
|
||||
enable_if_t<is_integral<TOut>::value && is_unsigned<TOut>::value &&
|
||||
sizeof(TOut) == 8,
|
||||
unsigned>* = 0) {
|
||||
return forge(0x5F7FFFFF); // 1.844674297419792384E19
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -10,9 +10,9 @@
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
#if ARDUINOJSON_USE_DOUBLE
|
||||
typedef double JsonFloat;
|
||||
using JsonFloat = double;
|
||||
#else
|
||||
typedef float JsonFloat;
|
||||
using JsonFloat = float;
|
||||
#endif
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -12,11 +12,11 @@
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
typedef int64_t JsonInteger;
|
||||
typedef uint64_t JsonUInt;
|
||||
using JsonInteger = int64_t;
|
||||
using JsonUInt = uint64_t;
|
||||
#else
|
||||
typedef long JsonInteger;
|
||||
typedef unsigned long JsonUInt;
|
||||
using JsonInteger = long;
|
||||
using JsonUInt = unsigned long;
|
||||
#endif
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
@ -25,4 +25,4 @@ ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
static_assert(sizeof(T) <= sizeof(ArduinoJson::JsonInteger), \
|
||||
"To use 64-bit integers with ArduinoJson, you must set " \
|
||||
"ARDUINOJSON_USE_LONG_LONG to 1. See " \
|
||||
"https://arduinojson.org/v6/api/config/use_long_long/");
|
||||
"https://arduinojson.org/v7/api/config/use_long_long/");
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -32,34 +32,34 @@ CompareResult arithmeticCompare(const T& lhs, const T& rhs) {
|
||||
template <typename T1, typename T2>
|
||||
CompareResult arithmeticCompare(
|
||||
const T1& lhs, const T2& rhs,
|
||||
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||
sizeof(T1) < sizeof(T2)>::type* = 0) {
|
||||
enable_if_t<is_integral<T1>::value && is_integral<T2>::value &&
|
||||
sizeof(T1) < sizeof(T2)>* = 0) {
|
||||
return arithmeticCompare<T2>(static_cast<T2>(lhs), rhs);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
CompareResult arithmeticCompare(
|
||||
const T1& lhs, const T2& rhs,
|
||||
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||
sizeof(T2) < sizeof(T1)>::type* = 0) {
|
||||
enable_if_t<is_integral<T1>::value && is_integral<T2>::value &&
|
||||
sizeof(T2) < sizeof(T1)>* = 0) {
|
||||
return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs));
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
CompareResult arithmeticCompare(
|
||||
const T1& lhs, const T2& rhs,
|
||||
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||
is_signed<T1>::value == is_signed<T2>::value &&
|
||||
sizeof(T2) == sizeof(T1)>::type* = 0) {
|
||||
enable_if_t<is_integral<T1>::value && is_integral<T2>::value &&
|
||||
is_signed<T1>::value == is_signed<T2>::value &&
|
||||
sizeof(T2) == sizeof(T1)>* = 0) {
|
||||
return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs));
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
CompareResult arithmeticCompare(
|
||||
const T1& lhs, const T2& rhs,
|
||||
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||
is_unsigned<T1>::value && is_signed<T2>::value &&
|
||||
sizeof(T2) == sizeof(T1)>::type* = 0) {
|
||||
enable_if_t<is_integral<T1>::value && is_integral<T2>::value &&
|
||||
is_unsigned<T1>::value && is_signed<T2>::value &&
|
||||
sizeof(T2) == sizeof(T1)>* = 0) {
|
||||
if (rhs < 0)
|
||||
return COMPARE_RESULT_GREATER;
|
||||
return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs));
|
||||
@ -68,9 +68,9 @@ CompareResult arithmeticCompare(
|
||||
template <typename T1, typename T2>
|
||||
CompareResult arithmeticCompare(
|
||||
const T1& lhs, const T2& rhs,
|
||||
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||
is_signed<T1>::value && is_unsigned<T2>::value &&
|
||||
sizeof(T2) == sizeof(T1)>::type* = 0) {
|
||||
enable_if_t<is_integral<T1>::value && is_integral<T2>::value &&
|
||||
is_signed<T1>::value && is_unsigned<T2>::value &&
|
||||
sizeof(T2) == sizeof(T1)>* = 0) {
|
||||
if (lhs < 0)
|
||||
return COMPARE_RESULT_LESS;
|
||||
return arithmeticCompare<T2>(static_cast<T2>(lhs), rhs);
|
||||
@ -79,23 +79,21 @@ CompareResult arithmeticCompare(
|
||||
template <typename T1, typename T2>
|
||||
CompareResult arithmeticCompare(
|
||||
const T1& lhs, const T2& rhs,
|
||||
typename enable_if<is_floating_point<T1>::value ||
|
||||
is_floating_point<T2>::value>::type* = 0) {
|
||||
enable_if_t<is_floating_point<T1>::value || is_floating_point<T2>::value>* =
|
||||
0) {
|
||||
return arithmeticCompare<double>(static_cast<double>(lhs),
|
||||
static_cast<double>(rhs));
|
||||
}
|
||||
|
||||
template <typename T2>
|
||||
CompareResult arithmeticCompareNegateLeft(
|
||||
JsonUInt, const T2&,
|
||||
typename enable_if<is_unsigned<T2>::value>::type* = 0) {
|
||||
JsonUInt, const T2&, enable_if_t<is_unsigned<T2>::value>* = 0) {
|
||||
return COMPARE_RESULT_LESS;
|
||||
}
|
||||
|
||||
template <typename T2>
|
||||
CompareResult arithmeticCompareNegateLeft(
|
||||
JsonUInt lhs, const T2& rhs,
|
||||
typename enable_if<is_signed<T2>::value>::type* = 0) {
|
||||
JsonUInt lhs, const T2& rhs, enable_if_t<is_signed<T2>::value>* = 0) {
|
||||
if (rhs > 0)
|
||||
return COMPARE_RESULT_LESS;
|
||||
return arithmeticCompare(-rhs, static_cast<T2>(lhs));
|
||||
@ -103,15 +101,13 @@ CompareResult arithmeticCompareNegateLeft(
|
||||
|
||||
template <typename T1>
|
||||
CompareResult arithmeticCompareNegateRight(
|
||||
const T1&, JsonUInt,
|
||||
typename enable_if<is_unsigned<T1>::value>::type* = 0) {
|
||||
const T1&, JsonUInt, enable_if_t<is_unsigned<T1>::value>* = 0) {
|
||||
return COMPARE_RESULT_GREATER;
|
||||
}
|
||||
|
||||
template <typename T1>
|
||||
CompareResult arithmeticCompareNegateRight(
|
||||
const T1& lhs, JsonUInt rhs,
|
||||
typename enable_if<is_signed<T1>::value>::type* = 0) {
|
||||
const T1& lhs, JsonUInt rhs, enable_if_t<is_signed<T1>::value>* = 0) {
|
||||
if (lhs > 0)
|
||||
return COMPARE_RESULT_GREATER;
|
||||
return arithmeticCompare(static_cast<T1>(rhs), -lhs);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -22,18 +22,18 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
// uint32 -> int32
|
||||
// uint64 -> int32
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_integral<TIn>::value && is_unsigned<TIn>::value &&
|
||||
is_integral<TOut>::value && sizeof(TOut) <= sizeof(TIn),
|
||||
bool>::type
|
||||
enable_if_t<is_integral<TIn>::value && is_unsigned<TIn>::value &&
|
||||
is_integral<TOut>::value && sizeof(TOut) <= sizeof(TIn),
|
||||
bool>
|
||||
canConvertNumber(TIn value) {
|
||||
return value <= TIn(numeric_limits<TOut>::highest());
|
||||
}
|
||||
|
||||
// uint32 -> int64
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_integral<TIn>::value && is_unsigned<TIn>::value &&
|
||||
is_integral<TOut>::value && sizeof(TIn) < sizeof(TOut),
|
||||
bool>::type
|
||||
enable_if_t<is_integral<TIn>::value && is_unsigned<TIn>::value &&
|
||||
is_integral<TOut>::value && sizeof(TIn) < sizeof(TOut),
|
||||
bool>
|
||||
canConvertNumber(TIn) {
|
||||
return true;
|
||||
}
|
||||
@ -41,18 +41,17 @@ canConvertNumber(TIn) {
|
||||
// uint32 -> float
|
||||
// int32 -> float
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_integral<TIn>::value && is_floating_point<TOut>::value,
|
||||
bool>::type
|
||||
enable_if_t<is_integral<TIn>::value && is_floating_point<TOut>::value, bool>
|
||||
canConvertNumber(TIn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// int64 -> int32
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value &&
|
||||
is_integral<TOut>::value && is_signed<TOut>::value &&
|
||||
sizeof(TOut) < sizeof(TIn),
|
||||
bool>::type
|
||||
enable_if_t<is_integral<TIn>::value && is_signed<TIn>::value &&
|
||||
is_integral<TOut>::value && is_signed<TOut>::value &&
|
||||
sizeof(TOut) < sizeof(TIn),
|
||||
bool>
|
||||
canConvertNumber(TIn value) {
|
||||
return value >= TIn(numeric_limits<TOut>::lowest()) &&
|
||||
value <= TIn(numeric_limits<TOut>::highest());
|
||||
@ -61,10 +60,10 @@ canConvertNumber(TIn value) {
|
||||
// int32 -> int32
|
||||
// int32 -> int64
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value &&
|
||||
is_integral<TOut>::value && is_signed<TOut>::value &&
|
||||
sizeof(TIn) <= sizeof(TOut),
|
||||
bool>::type
|
||||
enable_if_t<is_integral<TIn>::value && is_signed<TIn>::value &&
|
||||
is_integral<TOut>::value && is_signed<TOut>::value &&
|
||||
sizeof(TIn) <= sizeof(TOut),
|
||||
bool>
|
||||
canConvertNumber(TIn) {
|
||||
return true;
|
||||
}
|
||||
@ -72,10 +71,10 @@ canConvertNumber(TIn) {
|
||||
// int32 -> uint32
|
||||
// int32 -> uint64
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value &&
|
||||
is_integral<TOut>::value && is_unsigned<TOut>::value &&
|
||||
sizeof(TOut) >= sizeof(TIn),
|
||||
bool>::type
|
||||
enable_if_t<is_integral<TIn>::value && is_signed<TIn>::value &&
|
||||
is_integral<TOut>::value && is_unsigned<TOut>::value &&
|
||||
sizeof(TOut) >= sizeof(TIn),
|
||||
bool>
|
||||
canConvertNumber(TIn value) {
|
||||
if (value < 0)
|
||||
return false;
|
||||
@ -84,10 +83,10 @@ canConvertNumber(TIn value) {
|
||||
|
||||
// int32 -> uint16
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value &&
|
||||
is_integral<TOut>::value && is_unsigned<TOut>::value &&
|
||||
sizeof(TOut) < sizeof(TIn),
|
||||
bool>::type
|
||||
enable_if_t<is_integral<TIn>::value && is_signed<TIn>::value &&
|
||||
is_integral<TOut>::value && is_unsigned<TOut>::value &&
|
||||
sizeof(TOut) < sizeof(TIn),
|
||||
bool>
|
||||
canConvertNumber(TIn value) {
|
||||
if (value < 0)
|
||||
return false;
|
||||
@ -97,9 +96,9 @@ canConvertNumber(TIn value) {
|
||||
// float32 -> int16
|
||||
// float64 -> int32
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_floating_point<TIn>::value && is_integral<TOut>::value &&
|
||||
sizeof(TOut) < sizeof(TIn),
|
||||
bool>::type
|
||||
enable_if_t<is_floating_point<TIn>::value && is_integral<TOut>::value &&
|
||||
sizeof(TOut) < sizeof(TIn),
|
||||
bool>
|
||||
canConvertNumber(TIn value) {
|
||||
return value >= numeric_limits<TOut>::lowest() &&
|
||||
value <= numeric_limits<TOut>::highest();
|
||||
@ -112,9 +111,9 @@ canConvertNumber(TIn value) {
|
||||
// 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
|
||||
enable_if_t<is_floating_point<TIn>::value && is_integral<TOut>::value &&
|
||||
sizeof(TOut) >= sizeof(TIn),
|
||||
bool>
|
||||
canConvertNumber(TIn value) {
|
||||
// Avoid error "9.22337e+18 is outside the range of representable values of
|
||||
// type 'long'"
|
||||
@ -122,10 +121,21 @@ canConvertNumber(TIn value) {
|
||||
value <= FloatTraits<TIn>::template highest_for<TOut>();
|
||||
}
|
||||
|
||||
// float32 -> float32
|
||||
// float64 -> float64
|
||||
// float64 -> float32
|
||||
template <typename TOut, typename TIn>
|
||||
enable_if_t<is_floating_point<TIn>::value && is_floating_point<TOut>::value,
|
||||
bool>
|
||||
canConvertNumber(TIn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename TOut, typename TIn>
|
||||
TOut convertNumber(TIn value) {
|
||||
return canConvertNumber<TOut>(value) ? TOut(value) : 0;
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
||||
#if defined(__clang__)
|
||||
|
||||
@ -1,27 +1,111 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Numbers/FloatTraits.hpp>
|
||||
#include <ArduinoJson/Numbers/JsonFloat.hpp>
|
||||
#include <ArduinoJson/Numbers/convertNumber.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
#include <ArduinoJson/Polyfills/ctype.hpp>
|
||||
#include <ArduinoJson/Polyfills/math.hpp>
|
||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||
#include <ArduinoJson/Variant/Converter.hpp>
|
||||
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename A, typename B>
|
||||
struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> {};
|
||||
using largest_type = conditional_t<(sizeof(A) > sizeof(B)), A, B>;
|
||||
|
||||
inline bool parseNumber(const char* s, VariantData& result) {
|
||||
typedef FloatTraits<JsonFloat> traits;
|
||||
typedef choose_largest<traits::mantissa_type, JsonUInt>::type mantissa_t;
|
||||
typedef traits::exponent_type exponent_t;
|
||||
enum class NumberType : uint8_t {
|
||||
Invalid,
|
||||
Float,
|
||||
SignedInteger,
|
||||
UnsignedInteger,
|
||||
#if ARDUINOJSON_USE_DOUBLE
|
||||
Double,
|
||||
#endif
|
||||
};
|
||||
|
||||
union NumberValue {
|
||||
NumberValue() {}
|
||||
NumberValue(float x) : asFloat(x) {}
|
||||
NumberValue(JsonInteger x) : asSignedInteger(x) {}
|
||||
NumberValue(JsonUInt x) : asUnsignedInteger(x) {}
|
||||
#if ARDUINOJSON_USE_DOUBLE
|
||||
NumberValue(double x) : asDouble(x) {}
|
||||
#endif
|
||||
|
||||
JsonInteger asSignedInteger;
|
||||
JsonUInt asUnsignedInteger;
|
||||
float asFloat;
|
||||
#if ARDUINOJSON_USE_DOUBLE
|
||||
double asDouble;
|
||||
#endif
|
||||
};
|
||||
|
||||
class Number {
|
||||
NumberType type_;
|
||||
NumberValue value_;
|
||||
|
||||
public:
|
||||
Number() : type_(NumberType::Invalid) {}
|
||||
Number(float value) : type_(NumberType::Float), value_(value) {}
|
||||
Number(JsonInteger value) : type_(NumberType::SignedInteger), value_(value) {}
|
||||
Number(JsonUInt value) : type_(NumberType::UnsignedInteger), value_(value) {}
|
||||
#if ARDUINOJSON_USE_DOUBLE
|
||||
Number(double value) : type_(NumberType::Double), value_(value) {}
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
T convertTo() const {
|
||||
switch (type_) {
|
||||
case NumberType::Float:
|
||||
return convertNumber<T>(value_.asFloat);
|
||||
case NumberType::SignedInteger:
|
||||
return convertNumber<T>(value_.asSignedInteger);
|
||||
case NumberType::UnsignedInteger:
|
||||
return convertNumber<T>(value_.asUnsignedInteger);
|
||||
#if ARDUINOJSON_USE_DOUBLE
|
||||
case NumberType::Double:
|
||||
return convertNumber<T>(value_.asDouble);
|
||||
#endif
|
||||
default:
|
||||
return T();
|
||||
}
|
||||
}
|
||||
|
||||
NumberType type() const {
|
||||
return type_;
|
||||
}
|
||||
|
||||
JsonInteger asSignedInteger() const {
|
||||
ARDUINOJSON_ASSERT(type_ == NumberType::SignedInteger);
|
||||
return value_.asSignedInteger;
|
||||
}
|
||||
|
||||
JsonUInt asUnsignedInteger() const {
|
||||
ARDUINOJSON_ASSERT(type_ == NumberType::UnsignedInteger);
|
||||
return value_.asUnsignedInteger;
|
||||
}
|
||||
|
||||
float asFloat() const {
|
||||
ARDUINOJSON_ASSERT(type_ == NumberType::Float);
|
||||
return value_.asFloat;
|
||||
}
|
||||
|
||||
#if ARDUINOJSON_USE_DOUBLE
|
||||
double asDouble() const {
|
||||
ARDUINOJSON_ASSERT(type_ == NumberType::Double);
|
||||
return value_.asDouble;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
inline Number parseNumber(const char* s) {
|
||||
using traits = FloatTraits<JsonFloat>;
|
||||
using mantissa_t = largest_type<traits::mantissa_type, JsonUInt>;
|
||||
using exponent_t = traits::exponent_type;
|
||||
|
||||
ARDUINOJSON_ASSERT(s != 0);
|
||||
|
||||
@ -38,20 +122,18 @@ inline bool parseNumber(const char* s, VariantData& result) {
|
||||
|
||||
#if ARDUINOJSON_ENABLE_NAN
|
||||
if (*s == 'n' || *s == 'N') {
|
||||
result.setFloat(traits::nan());
|
||||
return true;
|
||||
return Number(traits::nan());
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ARDUINOJSON_ENABLE_INFINITY
|
||||
if (*s == 'i' || *s == 'I') {
|
||||
result.setFloat(is_negative ? -traits::inf() : traits::inf());
|
||||
return true;
|
||||
return Number(is_negative ? -traits::inf() : traits::inf());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!isdigit(*s) && *s != '.')
|
||||
return false;
|
||||
return Number();
|
||||
|
||||
mantissa_t mantissa = 0;
|
||||
exponent_t exponent_offset = 0;
|
||||
@ -73,12 +155,10 @@ inline bool parseNumber(const char* s, VariantData& result) {
|
||||
const mantissa_t sintMantissaMax = mantissa_t(1)
|
||||
<< (sizeof(JsonInteger) * 8 - 1);
|
||||
if (mantissa <= sintMantissaMax) {
|
||||
result.setInteger(JsonInteger(~mantissa + 1));
|
||||
return true;
|
||||
return Number(JsonInteger(~mantissa + 1));
|
||||
}
|
||||
} else {
|
||||
result.setInteger(JsonUInt(mantissa));
|
||||
return true;
|
||||
return Number(JsonUInt(mantissa));
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,10 +200,9 @@ inline bool parseNumber(const char* s, VariantData& result) {
|
||||
exponent = exponent * 10 + (*s - '0');
|
||||
if (exponent + exponent_offset > traits::exponent_max) {
|
||||
if (negative_exponent)
|
||||
result.setFloat(is_negative ? -0.0f : 0.0f);
|
||||
return Number(is_negative ? -0.0f : 0.0f);
|
||||
else
|
||||
result.setFloat(is_negative ? -traits::inf() : traits::inf());
|
||||
return true;
|
||||
return Number(is_negative ? -traits::inf() : traits::inf());
|
||||
}
|
||||
s++;
|
||||
}
|
||||
@ -134,19 +213,26 @@ inline bool parseNumber(const char* s, VariantData& result) {
|
||||
|
||||
// we should be at the end of the string, otherwise it's an error
|
||||
if (*s != '\0')
|
||||
return false;
|
||||
return Number();
|
||||
|
||||
JsonFloat final_result =
|
||||
make_float(static_cast<JsonFloat>(mantissa), exponent);
|
||||
|
||||
result.setFloat(is_negative ? -final_result : final_result);
|
||||
return true;
|
||||
#if ARDUINOJSON_USE_DOUBLE
|
||||
bool isDouble = exponent < -FloatTraits<float>::exponent_max ||
|
||||
exponent > FloatTraits<float>::exponent_max ||
|
||||
mantissa > FloatTraits<float>::mantissa_max;
|
||||
if (isDouble) {
|
||||
auto final_result = make_float(double(mantissa), exponent);
|
||||
return Number(is_negative ? -final_result : final_result);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
auto final_result = make_float(float(mantissa), exponent);
|
||||
return Number(is_negative ? -final_result : final_result);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T parseNumber(const char* s) {
|
||||
VariantData value;
|
||||
parseNumber(s, value);
|
||||
return Converter<T>::fromJson(JsonVariantConst(&value));
|
||||
return parseNumber(s).convertTo<T>();
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -12,189 +12,222 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
class JsonArray;
|
||||
|
||||
// A reference to an object in a JsonDocument.
|
||||
// https://arduinojson.org/v6/api/jsonobject/
|
||||
// https://arduinojson.org/v7/api/jsonobject/
|
||||
class JsonObject : public detail::VariantOperators<JsonObject> {
|
||||
friend class detail::VariantAttorney;
|
||||
|
||||
public:
|
||||
typedef JsonObjectIterator iterator;
|
||||
using iterator = JsonObjectIterator;
|
||||
|
||||
// Creates an unbound reference.
|
||||
FORCE_INLINE JsonObject() : data_(0), pool_(0) {}
|
||||
JsonObject() : data_(0), resources_(0) {}
|
||||
|
||||
// INTERNAL USE ONLY
|
||||
FORCE_INLINE JsonObject(detail::MemoryPool* buf, detail::CollectionData* data)
|
||||
: data_(data), pool_(buf) {}
|
||||
JsonObject(detail::ObjectData* data, detail::ResourceManager* resource)
|
||||
: data_(data), resources_(resource) {}
|
||||
|
||||
operator JsonVariant() const {
|
||||
void* data = data_; // prevent warning cast-align
|
||||
return JsonVariant(pool_, reinterpret_cast<detail::VariantData*>(data));
|
||||
return JsonVariant(reinterpret_cast<detail::VariantData*>(data),
|
||||
resources_);
|
||||
}
|
||||
|
||||
operator JsonObjectConst() const {
|
||||
return JsonObjectConst(data_);
|
||||
return JsonObjectConst(data_, resources_);
|
||||
}
|
||||
|
||||
operator JsonVariantConst() const {
|
||||
return JsonVariantConst(collectionToVariant(data_));
|
||||
return JsonVariantConst(collectionToVariant(data_), resources_);
|
||||
}
|
||||
|
||||
// Returns true if the reference is unbound.
|
||||
// https://arduinojson.org/v6/api/jsonobject/isnull/
|
||||
FORCE_INLINE bool isNull() const {
|
||||
// https://arduinojson.org/v7/api/jsonobject/isnull/
|
||||
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 {
|
||||
// https://arduinojson.org/v7/api/jsonobject/isnull/
|
||||
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_));
|
||||
// https://arduinojson.org/v7/api/jsonobject/nesting/
|
||||
size_t nesting() const {
|
||||
return detail::VariantData::nesting(collectionToVariant(data_), resources_);
|
||||
}
|
||||
|
||||
// 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;
|
||||
// https://arduinojson.org/v7/api/jsonobject/size/
|
||||
size_t size() const {
|
||||
return data_ ? data_->size(resources_) : 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 {
|
||||
// https://arduinojson.org/v7/api/jsonobject/begin/
|
||||
iterator begin() const {
|
||||
if (!data_)
|
||||
return iterator();
|
||||
return iterator(pool_, data_->head());
|
||||
return iterator(data_->createIterator(resources_), resources_);
|
||||
}
|
||||
|
||||
// Returns an iterator following the last key-value pair of the object.
|
||||
// https://arduinojson.org/v6/api/jsonobject/end/
|
||||
FORCE_INLINE iterator end() const {
|
||||
// https://arduinojson.org/v7/api/jsonobject/end/
|
||||
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/
|
||||
// https://arduinojson.org/v7/api/jsonobject/clear/
|
||||
void clear() const {
|
||||
if (!data_)
|
||||
return;
|
||||
data_->clear();
|
||||
detail::ObjectData::clear(data_, resources_);
|
||||
}
|
||||
|
||||
// Copies an object.
|
||||
// https://arduinojson.org/v6/api/jsonobject/set/
|
||||
FORCE_INLINE bool set(JsonObjectConst src) {
|
||||
// https://arduinojson.org/v7/api/jsonobject/set/
|
||||
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_);
|
||||
clear();
|
||||
for (auto kvp : src) {
|
||||
if (!operator[](kvp.key()).set(kvp.value()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Gets or sets the member with specified key.
|
||||
// https://arduinojson.org/v6/api/jsonobject/subscript/
|
||||
template <typename TString>
|
||||
FORCE_INLINE
|
||||
typename detail::enable_if<detail::IsString<TString>::value,
|
||||
detail::MemberProxy<JsonObject, TString>>::type
|
||||
operator[](const TString& key) const {
|
||||
return {*this, key};
|
||||
// https://arduinojson.org/v7/api/jsonobject/subscript/
|
||||
template <typename TString,
|
||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||
detail::MemberProxy<JsonObject, detail::AdaptedString<TString>> operator[](
|
||||
const TString& key) const {
|
||||
return {*this, detail::adaptString(key)};
|
||||
}
|
||||
|
||||
// Gets or sets the member with specified key.
|
||||
// https://arduinojson.org/v6/api/jsonobject/subscript/
|
||||
template <typename TChar>
|
||||
FORCE_INLINE
|
||||
typename detail::enable_if<detail::IsString<TChar*>::value,
|
||||
detail::MemberProxy<JsonObject, TChar*>>::type
|
||||
operator[](TChar* key) const {
|
||||
return {*this, key};
|
||||
// https://arduinojson.org/v7/api/jsonobject/subscript/
|
||||
template <typename TChar,
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value &&
|
||||
!detail::is_const<TChar>::value,
|
||||
int> = 0>
|
||||
detail::MemberProxy<JsonObject, detail::AdaptedString<TChar*>> operator[](
|
||||
TChar* key) const {
|
||||
return {*this, detail::adaptString(key)};
|
||||
}
|
||||
|
||||
// Gets or sets the member with specified key.
|
||||
// https://arduinojson.org/v7/api/jsonobject/subscript/
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
detail::MemberProxy<JsonObject, detail::AdaptedString<JsonString>> operator[](
|
||||
const TVariant& key) const {
|
||||
return {*this, detail::adaptString(key.template as<JsonString>())};
|
||||
}
|
||||
|
||||
// Removes the member at the specified iterator.
|
||||
// ⚠️ Doesn't release the memory associated with the removed member.
|
||||
// https://arduinojson.org/v6/api/jsonobject/remove/
|
||||
// https://arduinojson.org/v7/api/jsonobject/remove/
|
||||
FORCE_INLINE void remove(iterator it) const {
|
||||
if (!data_)
|
||||
return;
|
||||
data_->removeSlot(it.slot_);
|
||||
detail::ObjectData::remove(data_, it.iterator_, resources_);
|
||||
}
|
||||
|
||||
// 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(detail::adaptString(key));
|
||||
// https://arduinojson.org/v7/api/jsonobject/remove/
|
||||
template <typename TString,
|
||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||
void remove(const TString& key) const {
|
||||
detail::ObjectData::removeMember(data_, detail::adaptString(key),
|
||||
resources_);
|
||||
}
|
||||
|
||||
// Removes the member with the specified key.
|
||||
// ⚠️ Doesn't release the memory associated with the removed member.
|
||||
// https://arduinojson.org/v6/api/jsonobject/remove/
|
||||
// https://arduinojson.org/v7/api/jsonobject/remove/
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
void remove(const TVariant& key) const {
|
||||
if (key.template is<const char*>())
|
||||
remove(key.template as<const char*>());
|
||||
}
|
||||
|
||||
// Removes the member with the specified key.
|
||||
// https://arduinojson.org/v7/api/jsonobject/remove/
|
||||
template <typename TChar>
|
||||
FORCE_INLINE void remove(TChar* key) const {
|
||||
removeMember(detail::adaptString(key));
|
||||
detail::ObjectData::removeMember(data_, detail::adaptString(key),
|
||||
resources_);
|
||||
}
|
||||
|
||||
// Returns true if the object contains the specified key.
|
||||
// https://arduinojson.org/v6/api/jsonobject/containskey/
|
||||
template <typename TString>
|
||||
FORCE_INLINE
|
||||
typename detail::enable_if<detail::IsString<TString>::value, bool>::type
|
||||
containsKey(const TString& key) const {
|
||||
return getMember(detail::adaptString(key)) != 0;
|
||||
// DEPRECATED: use obj[key].is<T>() instead
|
||||
// https://arduinojson.org/v7/api/jsonobject/containskey/
|
||||
template <typename TString,
|
||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||
ARDUINOJSON_DEPRECATED("use obj[key].is<T>() instead")
|
||||
bool containsKey(const TString& key) const {
|
||||
return detail::ObjectData::getMember(data_, detail::adaptString(key),
|
||||
resources_) != 0;
|
||||
}
|
||||
|
||||
// Returns true if the object contains the specified key.
|
||||
// https://arduinojson.org/v6/api/jsonobject/containskey/
|
||||
// DEPRECATED: use obj["key"].is<T>() instead
|
||||
// https://arduinojson.org/v7/api/jsonobject/containskey/
|
||||
template <typename TChar,
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value &&
|
||||
!detail::is_const<TChar>::value,
|
||||
int> = 0>
|
||||
ARDUINOJSON_DEPRECATED("use obj[\"key\"].is<T>() instead")
|
||||
bool containsKey(TChar* key) const {
|
||||
return detail::ObjectData::getMember(data_, detail::adaptString(key),
|
||||
resources_) != 0;
|
||||
}
|
||||
|
||||
// DEPRECATED: use obj[key].is<T>() instead
|
||||
// https://arduinojson.org/v7/api/jsonobject/containskey/
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
ARDUINOJSON_DEPRECATED("use obj[key].is<T>() instead")
|
||||
bool containsKey(const TVariant& key) const {
|
||||
return containsKey(key.template as<const char*>());
|
||||
}
|
||||
|
||||
// DEPRECATED: use obj[key].to<JsonArray>() instead
|
||||
template <typename TChar>
|
||||
FORCE_INLINE
|
||||
typename detail::enable_if<detail::IsString<TChar*>::value, bool>::type
|
||||
containsKey(TChar* key) const {
|
||||
return getMember(detail::adaptString(key)) != 0;
|
||||
ARDUINOJSON_DEPRECATED("use obj[key].to<JsonArray>() instead")
|
||||
JsonArray createNestedArray(TChar* key) const {
|
||||
return operator[](key).template to<JsonArray>();
|
||||
}
|
||||
|
||||
// Creates an array and adds it to the object.
|
||||
// https://arduinojson.org/v6/api/jsonobject/createnestedarray/
|
||||
// DEPRECATED: use obj[key].to<JsonArray>() instead
|
||||
template <typename TString>
|
||||
FORCE_INLINE JsonArray createNestedArray(const TString& key) const;
|
||||
ARDUINOJSON_DEPRECATED("use obj[key].to<JsonArray>() instead")
|
||||
JsonArray createNestedArray(const TString& key) const {
|
||||
return operator[](key).template to<JsonArray>();
|
||||
}
|
||||
|
||||
// Creates an array and adds it to the object.
|
||||
// https://arduinojson.org/v6/api/jsonobject/createnestedarray/
|
||||
// DEPRECATED: use obj[key].to<JsonObject>() instead
|
||||
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 {
|
||||
ARDUINOJSON_DEPRECATED("use obj[key].to<JsonObject>() instead")
|
||||
JsonObject createNestedObject(TChar* key) {
|
||||
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 {
|
||||
// DEPRECATED: use obj[key].to<JsonObject>() instead
|
||||
template <typename TString>
|
||||
ARDUINOJSON_DEPRECATED("use obj[key].to<JsonObject>() instead")
|
||||
JsonObject createNestedObject(const TString& key) {
|
||||
return operator[](key).template to<JsonObject>();
|
||||
}
|
||||
|
||||
// DEPRECATED: always returns zero
|
||||
ARDUINOJSON_DEPRECATED("always returns zero")
|
||||
size_t memoryUsage() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
detail::MemoryPool* getPool() const {
|
||||
return pool_;
|
||||
detail::ResourceManager* getResourceManager() const {
|
||||
return resources_;
|
||||
}
|
||||
|
||||
detail::VariantData* getData() const {
|
||||
@ -205,47 +238,8 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
|
||||
return detail::collectionToVariant(data_);
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline detail::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);
|
||||
}
|
||||
|
||||
detail::CollectionData* data_;
|
||||
detail::MemoryPool* pool_;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<JsonObject> : private detail::VariantAttorney {
|
||||
static void toJson(JsonVariantConst src, JsonVariant dst) {
|
||||
variantCopyFrom(getData(dst), getData(src), getPool(dst));
|
||||
}
|
||||
|
||||
static JsonObject fromJson(JsonVariant src) {
|
||||
auto data = getData(src);
|
||||
auto pool = getPool(src);
|
||||
return JsonObject(pool, data != 0 ? data->asObject() : 0);
|
||||
}
|
||||
|
||||
static detail::InvalidConversion<JsonVariantConst, JsonObject> fromJson(
|
||||
JsonVariantConst);
|
||||
|
||||
static bool checkJson(JsonVariantConst) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool checkJson(JsonVariant src) {
|
||||
auto data = getData(src);
|
||||
return data && data->isObject();
|
||||
}
|
||||
detail::ObjectData* data_;
|
||||
detail::ResourceManager* resources_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -10,115 +10,129 @@
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// A read-only reference to an object in a JsonDocument.
|
||||
// https://arduinojson.org/v6/api/jsonobjectconst/
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/
|
||||
class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
|
||||
friend class JsonObject;
|
||||
friend class detail::VariantAttorney;
|
||||
|
||||
public:
|
||||
typedef JsonObjectConstIterator iterator;
|
||||
using iterator = JsonObjectConstIterator;
|
||||
|
||||
// Creates an unbound reference.
|
||||
JsonObjectConst() : data_(0) {}
|
||||
JsonObjectConst() : data_(0), resources_(0) {}
|
||||
|
||||
// INTERNAL USE ONLY
|
||||
JsonObjectConst(const detail::CollectionData* data) : data_(data) {}
|
||||
JsonObjectConst(const detail::ObjectData* data,
|
||||
const detail::ResourceManager* resources)
|
||||
: data_(data), resources_(resources) {}
|
||||
|
||||
operator JsonVariantConst() const {
|
||||
return JsonVariantConst(collectionToVariant(data_));
|
||||
return JsonVariantConst(getData(), resources_);
|
||||
}
|
||||
|
||||
// Returns true if the reference is unbound.
|
||||
// https://arduinojson.org/v6/api/jsonobjectconst/isnull/
|
||||
FORCE_INLINE bool isNull() const {
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/isnull/
|
||||
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 {
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/isnull/
|
||||
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_));
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/nesting/
|
||||
size_t nesting() const {
|
||||
return detail::VariantData::nesting(getData(), resources_);
|
||||
}
|
||||
|
||||
// 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;
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/size/
|
||||
size_t size() const {
|
||||
return data_ ? data_->size(resources_) : 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 {
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/begin/
|
||||
iterator begin() const {
|
||||
if (!data_)
|
||||
return iterator();
|
||||
return iterator(data_->head());
|
||||
return iterator(data_->createIterator(resources_), resources_);
|
||||
}
|
||||
|
||||
// Returns an iterator following the last key-value pair of the object.
|
||||
// https://arduinojson.org/v6/api/jsonobjectconst/end/
|
||||
FORCE_INLINE iterator end() const {
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/end/
|
||||
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(detail::adaptString(key)) != 0;
|
||||
// DEPRECATED: use obj[key].is<T>() instead
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/containskey/
|
||||
template <typename TString,
|
||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||
ARDUINOJSON_DEPRECATED("use obj[key].is<T>() instead")
|
||||
bool containsKey(const TString& key) const {
|
||||
return detail::ObjectData::getMember(data_, detail::adaptString(key),
|
||||
resources_) != 0;
|
||||
}
|
||||
|
||||
// Returns true if the object contains the specified key.
|
||||
// https://arduinojson.org/v6/api/jsonobjectconst/containskey/
|
||||
// DEPRECATED: use obj["key"].is<T>() instead
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/containskey/
|
||||
template <typename TChar>
|
||||
FORCE_INLINE bool containsKey(TChar* key) const {
|
||||
return getMember(detail::adaptString(key)) != 0;
|
||||
ARDUINOJSON_DEPRECATED("use obj[\"key\"].is<T>() instead")
|
||||
bool containsKey(TChar* key) const {
|
||||
return detail::ObjectData::getMember(data_, detail::adaptString(key),
|
||||
resources_) != 0;
|
||||
}
|
||||
|
||||
// DEPRECATED: use obj[key].is<T>() instead
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/containskey/
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
ARDUINOJSON_DEPRECATED("use obj[key].is<T>() instead")
|
||||
bool containsKey(const TVariant& key) const {
|
||||
return containsKey(key.template as<const char*>());
|
||||
}
|
||||
|
||||
// Gets the member with specified key.
|
||||
// https://arduinojson.org/v6/api/jsonobjectconst/subscript/
|
||||
template <typename TString>
|
||||
FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value,
|
||||
JsonVariantConst>::type
|
||||
operator[](const TString& key) const {
|
||||
return JsonVariantConst(getMember(detail::adaptString(key)));
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/subscript/
|
||||
template <typename TString,
|
||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||
JsonVariantConst operator[](const TString& key) const {
|
||||
return JsonVariantConst(detail::ObjectData::getMember(
|
||||
data_, detail::adaptString(key), resources_),
|
||||
resources_);
|
||||
}
|
||||
|
||||
// Gets the member with specified key.
|
||||
// https://arduinojson.org/v6/api/jsonobjectconst/subscript/
|
||||
template <typename TChar>
|
||||
FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value,
|
||||
JsonVariantConst>::type
|
||||
operator[](TChar* key) const {
|
||||
return JsonVariantConst(getMember(detail::adaptString(key)));
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/subscript/
|
||||
template <typename TChar,
|
||||
detail::enable_if_t<detail::IsString<TChar*>::value &&
|
||||
!detail::is_const<TChar>::value,
|
||||
int> = 0>
|
||||
JsonVariantConst operator[](TChar* key) const {
|
||||
return JsonVariantConst(detail::ObjectData::getMember(
|
||||
data_, detail::adaptString(key), resources_),
|
||||
resources_);
|
||||
}
|
||||
|
||||
// Compares objects.
|
||||
FORCE_INLINE bool operator==(JsonObjectConst rhs) const {
|
||||
if (data_ == rhs.data_)
|
||||
return true;
|
||||
// Gets the member with specified key.
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/subscript/
|
||||
template <typename TVariant,
|
||||
detail::enable_if_t<detail::IsVariant<TVariant>::value, int> = 0>
|
||||
JsonVariantConst operator[](const TVariant& key) const {
|
||||
if (key.template is<JsonString>())
|
||||
return operator[](key.template as<JsonString>());
|
||||
else
|
||||
return JsonVariantConst();
|
||||
}
|
||||
|
||||
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();
|
||||
// DEPRECATED: always returns zero
|
||||
ARDUINOJSON_DEPRECATED("always returns zero")
|
||||
size_t memoryUsage() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -126,31 +140,27 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
|
||||
return collectionToVariant(data_);
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
const detail::VariantData* getMember(TAdaptedString key) const {
|
||||
if (!data_)
|
||||
return 0;
|
||||
return data_->getMember(key);
|
||||
}
|
||||
|
||||
const detail::CollectionData* data_;
|
||||
const detail::ObjectData* data_;
|
||||
const detail::ResourceManager* resources_;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<JsonObjectConst> : private detail::VariantAttorney {
|
||||
static void toJson(JsonVariantConst src, JsonVariant dst) {
|
||||
variantCopyFrom(getData(dst), getData(src), getPool(dst));
|
||||
}
|
||||
inline bool operator==(JsonObjectConst lhs, JsonObjectConst rhs) {
|
||||
if (!lhs && !rhs) // both are null
|
||||
return true;
|
||||
|
||||
static JsonObjectConst fromJson(JsonVariantConst src) {
|
||||
auto data = getData(src);
|
||||
return data != 0 ? data->asObject() : 0;
|
||||
}
|
||||
if (!lhs || !rhs) // only one is null
|
||||
return false;
|
||||
|
||||
static bool checkJson(JsonVariantConst src) {
|
||||
auto data = getData(src);
|
||||
return data && data->isObject();
|
||||
size_t count = 0;
|
||||
for (auto kvp : lhs) {
|
||||
auto rhsValue = rhs[kvp.key()];
|
||||
if (rhsValue.isUnbound())
|
||||
return false;
|
||||
if (kvp.value() != rhsValue)
|
||||
return false;
|
||||
count++;
|
||||
}
|
||||
};
|
||||
return count == rhs.size();
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
|
||||
@ -1,85 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Array/JsonArray.hpp>
|
||||
#include <ArduinoJson/Object/JsonObject.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_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>();
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@ -1,123 +1,83 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Object/JsonPair.hpp>
|
||||
#include <ArduinoJson/Variant/SlotFunctions.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
class JsonPairPtr {
|
||||
public:
|
||||
JsonPairPtr(detail::MemoryPool* pool, detail::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) {}
|
||||
JsonObjectIterator() {}
|
||||
|
||||
explicit JsonObjectIterator(detail::MemoryPool* pool,
|
||||
detail::VariantSlot* slot)
|
||||
: pool_(pool), slot_(slot) {}
|
||||
explicit JsonObjectIterator(detail::ObjectData::iterator iterator,
|
||||
detail::ResourceManager* resources)
|
||||
: iterator_(iterator), resources_(resources) {}
|
||||
|
||||
JsonPair operator*() const {
|
||||
return JsonPair(pool_, slot_);
|
||||
return JsonPair(iterator_, resources_);
|
||||
}
|
||||
JsonPairPtr operator->() {
|
||||
return JsonPairPtr(pool_, slot_);
|
||||
Ptr<JsonPair> operator->() {
|
||||
return operator*();
|
||||
}
|
||||
|
||||
bool operator==(const JsonObjectIterator& other) const {
|
||||
return slot_ == other.slot_;
|
||||
return iterator_ == other.iterator_;
|
||||
}
|
||||
|
||||
bool operator!=(const JsonObjectIterator& other) const {
|
||||
return slot_ != other.slot_;
|
||||
return iterator_ != other.iterator_;
|
||||
}
|
||||
|
||||
JsonObjectIterator& operator++() {
|
||||
slot_ = slot_->next();
|
||||
return *this;
|
||||
}
|
||||
|
||||
JsonObjectIterator& operator+=(size_t distance) {
|
||||
slot_ = slot_->next(distance);
|
||||
iterator_.next(resources_); // key
|
||||
iterator_.next(resources_); // value
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
detail::MemoryPool* pool_;
|
||||
detail::VariantSlot* slot_;
|
||||
};
|
||||
|
||||
class JsonPairConstPtr {
|
||||
public:
|
||||
JsonPairConstPtr(const detail::VariantSlot* slot) : pair_(slot) {}
|
||||
|
||||
const JsonPairConst* operator->() const {
|
||||
return &pair_;
|
||||
}
|
||||
|
||||
const JsonPairConst& operator*() const {
|
||||
return pair_;
|
||||
}
|
||||
|
||||
private:
|
||||
JsonPairConst pair_;
|
||||
detail::ObjectData::iterator iterator_;
|
||||
detail::ResourceManager* resources_;
|
||||
};
|
||||
|
||||
class JsonObjectConstIterator {
|
||||
friend class JsonObject;
|
||||
|
||||
public:
|
||||
JsonObjectConstIterator() : slot_(0) {}
|
||||
JsonObjectConstIterator() {}
|
||||
|
||||
explicit JsonObjectConstIterator(const detail::VariantSlot* slot)
|
||||
: slot_(slot) {}
|
||||
explicit JsonObjectConstIterator(detail::ObjectData::iterator iterator,
|
||||
const detail::ResourceManager* resources)
|
||||
: iterator_(iterator), resources_(resources) {}
|
||||
|
||||
JsonPairConst operator*() const {
|
||||
return JsonPairConst(slot_);
|
||||
return JsonPairConst(iterator_, resources_);
|
||||
}
|
||||
JsonPairConstPtr operator->() {
|
||||
return JsonPairConstPtr(slot_);
|
||||
Ptr<JsonPairConst> operator->() {
|
||||
return operator*();
|
||||
}
|
||||
|
||||
bool operator==(const JsonObjectConstIterator& other) const {
|
||||
return slot_ == other.slot_;
|
||||
return iterator_ == other.iterator_;
|
||||
}
|
||||
|
||||
bool operator!=(const JsonObjectConstIterator& other) const {
|
||||
return slot_ != other.slot_;
|
||||
return iterator_ != other.iterator_;
|
||||
}
|
||||
|
||||
JsonObjectConstIterator& operator++() {
|
||||
slot_ = slot_->next();
|
||||
return *this;
|
||||
}
|
||||
|
||||
JsonObjectConstIterator& operator+=(size_t distance) {
|
||||
slot_ = slot_->next(distance);
|
||||
iterator_.next(resources_); // key
|
||||
iterator_.next(resources_); // value
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
const detail::VariantSlot* slot_;
|
||||
detail::ObjectData::iterator iterator_;
|
||||
const detail::ResourceManager* resources_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -11,15 +11,16 @@
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
// A key-value pair.
|
||||
// https://arduinojson.org/v6/api/jsonobject/begin_end/
|
||||
// https://arduinojson.org/v7/api/jsonobject/begin_end/
|
||||
class JsonPair {
|
||||
public:
|
||||
// INTERNAL USE ONLY
|
||||
JsonPair(detail::MemoryPool* pool, detail::VariantSlot* slot) {
|
||||
if (slot) {
|
||||
key_ = JsonString(slot->key(), slot->ownsKey() ? JsonString::Copied
|
||||
: JsonString::Linked);
|
||||
value_ = JsonVariant(pool, slot->data());
|
||||
JsonPair(detail::ObjectData::iterator iterator,
|
||||
detail::ResourceManager* resources) {
|
||||
if (!iterator.done()) {
|
||||
key_ = iterator->asString();
|
||||
iterator.next(resources);
|
||||
value_ = JsonVariant(iterator.data(), resources);
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,7 +30,7 @@ class JsonPair {
|
||||
}
|
||||
|
||||
// Returns the value.
|
||||
JsonVariant value() const {
|
||||
JsonVariant value() {
|
||||
return value_;
|
||||
}
|
||||
|
||||
@ -39,14 +40,15 @@ class JsonPair {
|
||||
};
|
||||
|
||||
// A read-only key-value pair.
|
||||
// https://arduinojson.org/v6/api/jsonobjectconst/begin_end/
|
||||
// https://arduinojson.org/v7/api/jsonobjectconst/begin_end/
|
||||
class JsonPairConst {
|
||||
public:
|
||||
JsonPairConst(const detail::VariantSlot* slot) {
|
||||
if (slot) {
|
||||
key_ = JsonString(slot->key(), slot->ownsKey() ? JsonString::Copied
|
||||
: JsonString::Linked);
|
||||
value_ = JsonVariantConst(slot->data());
|
||||
JsonPairConst(detail::ObjectData::iterator iterator,
|
||||
const detail::ResourceManager* resources) {
|
||||
if (!iterator.done()) {
|
||||
key_ = iterator->asString();
|
||||
iterator.next(resources);
|
||||
value_ = JsonVariantConst(iterator.data(), resources);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -9,56 +9,69 @@
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
// A proxy class to get or set a member of an object.
|
||||
// https://arduinojson.org/v6/api/jsonobject/subscript/
|
||||
template <typename TUpstream, typename TStringRef>
|
||||
// https://arduinojson.org/v7/api/jsonobject/subscript/
|
||||
template <typename TUpstream, typename AdaptedString>
|
||||
class MemberProxy
|
||||
: public VariantRefBase<MemberProxy<TUpstream, TStringRef>>,
|
||||
public VariantOperators<MemberProxy<TUpstream, TStringRef>> {
|
||||
: public VariantRefBase<MemberProxy<TUpstream, AdaptedString>>,
|
||||
public VariantOperators<MemberProxy<TUpstream, AdaptedString>> {
|
||||
friend class VariantAttorney;
|
||||
|
||||
friend class VariantRefBase<MemberProxy<TUpstream, AdaptedString>>;
|
||||
|
||||
template <typename, typename>
|
||||
friend class MemberProxy;
|
||||
|
||||
template <typename>
|
||||
friend class ElementProxy;
|
||||
|
||||
public:
|
||||
FORCE_INLINE MemberProxy(TUpstream upstream, TStringRef key)
|
||||
MemberProxy(TUpstream upstream, AdaptedString key)
|
||||
: upstream_(upstream), key_(key) {}
|
||||
|
||||
MemberProxy(const MemberProxy& src)
|
||||
: upstream_(src.upstream_), key_(src.key_) {}
|
||||
|
||||
FORCE_INLINE MemberProxy& operator=(const MemberProxy& src) {
|
||||
MemberProxy& operator=(const MemberProxy& src) {
|
||||
this->set(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
FORCE_INLINE MemberProxy& operator=(const T& src) {
|
||||
MemberProxy& operator=(const T& src) {
|
||||
this->set(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
FORCE_INLINE MemberProxy& operator=(T* src) {
|
||||
template <typename T, enable_if_t<!is_const<T>::value, int> = 0>
|
||||
MemberProxy& operator=(T* src) {
|
||||
this->set(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
FORCE_INLINE MemoryPool* getPool() const {
|
||||
return VariantAttorney::getPool(upstream_);
|
||||
// clang-format off
|
||||
MemberProxy(const MemberProxy& src) // Error here? See https://arduinojson.org/v7/proxy-non-copyable/
|
||||
: upstream_(src.upstream_), key_(src.key_) {}
|
||||
// clang-format on
|
||||
|
||||
ResourceManager* getResourceManager() const {
|
||||
return VariantAttorney::getResourceManager(upstream_);
|
||||
}
|
||||
|
||||
FORCE_INLINE VariantData* getData() const {
|
||||
return variantGetMember(VariantAttorney::getData(upstream_),
|
||||
adaptString(key_));
|
||||
VariantData* getData() const {
|
||||
return VariantData::getMember(
|
||||
VariantAttorney::getData(upstream_), key_,
|
||||
VariantAttorney::getResourceManager(upstream_));
|
||||
}
|
||||
|
||||
FORCE_INLINE VariantData* getOrCreateData() const {
|
||||
return variantGetOrAddMember(VariantAttorney::getOrCreateData(upstream_),
|
||||
adaptString(key_),
|
||||
VariantAttorney::getPool(upstream_));
|
||||
VariantData* getOrCreateData() const {
|
||||
auto data = VariantAttorney::getOrCreateData(upstream_);
|
||||
if (!data)
|
||||
return nullptr;
|
||||
return data->getOrAddMember(key_,
|
||||
VariantAttorney::getResourceManager(upstream_));
|
||||
}
|
||||
|
||||
private:
|
||||
TUpstream upstream_;
|
||||
TStringRef key_;
|
||||
AdaptedString key_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
||||
@ -0,0 +1,70 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Collection/CollectionData.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
class ObjectData : public CollectionData {
|
||||
public:
|
||||
template <typename TAdaptedString>
|
||||
VariantData* addMember(TAdaptedString key, ResourceManager* resources);
|
||||
|
||||
VariantData* addPair(VariantData** value, ResourceManager* resources);
|
||||
|
||||
template <typename TAdaptedString>
|
||||
VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources);
|
||||
|
||||
template <typename TAdaptedString>
|
||||
VariantData* getMember(TAdaptedString key,
|
||||
const ResourceManager* resources) const;
|
||||
|
||||
template <typename TAdaptedString>
|
||||
static VariantData* getMember(const ObjectData* object, TAdaptedString key,
|
||||
const ResourceManager* resources) {
|
||||
if (!object)
|
||||
return nullptr;
|
||||
return object->getMember(key, resources);
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
void removeMember(TAdaptedString key, ResourceManager* resources);
|
||||
|
||||
template <typename TAdaptedString>
|
||||
static void removeMember(ObjectData* obj, TAdaptedString key,
|
||||
ResourceManager* resources) {
|
||||
if (!obj)
|
||||
return;
|
||||
obj->removeMember(key, resources);
|
||||
}
|
||||
|
||||
void remove(iterator it, ResourceManager* resources) {
|
||||
CollectionData::removePair(it, resources);
|
||||
}
|
||||
|
||||
static void remove(ObjectData* obj, ObjectData::iterator it,
|
||||
ResourceManager* resources) {
|
||||
if (!obj)
|
||||
return;
|
||||
obj->remove(it, resources);
|
||||
}
|
||||
|
||||
size_t size(const ResourceManager* resources) const {
|
||||
return CollectionData::size(resources) / 2;
|
||||
}
|
||||
|
||||
static size_t size(const ObjectData* obj, const ResourceManager* resources) {
|
||||
if (!obj)
|
||||
return 0;
|
||||
return obj->size(resources);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename TAdaptedString>
|
||||
iterator findKey(TAdaptedString key, const ResourceManager* resources) const;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@ -0,0 +1,92 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Object/ObjectData.hpp>
|
||||
#include <ArduinoJson/Variant/VariantCompare.hpp>
|
||||
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline VariantData* ObjectData::getMember(
|
||||
TAdaptedString key, const ResourceManager* resources) const {
|
||||
auto it = findKey(key, resources);
|
||||
if (it.done())
|
||||
return nullptr;
|
||||
it.next(resources);
|
||||
return it.data();
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
VariantData* ObjectData::getOrAddMember(TAdaptedString key,
|
||||
ResourceManager* resources) {
|
||||
auto data = getMember(key, resources);
|
||||
if (data)
|
||||
return data;
|
||||
return addMember(key, resources);
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline ObjectData::iterator ObjectData::findKey(
|
||||
TAdaptedString key, const ResourceManager* resources) const {
|
||||
if (key.isNull())
|
||||
return iterator();
|
||||
bool isKey = true;
|
||||
for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
|
||||
if (isKey && stringEquals(key, adaptString(it->asString())))
|
||||
return it;
|
||||
isKey = !isKey;
|
||||
}
|
||||
return iterator();
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline void ObjectData::removeMember(TAdaptedString key,
|
||||
ResourceManager* resources) {
|
||||
remove(findKey(key, resources), resources);
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline VariantData* ObjectData::addMember(TAdaptedString key,
|
||||
ResourceManager* resources) {
|
||||
auto keySlot = resources->allocVariant();
|
||||
if (!keySlot)
|
||||
return nullptr;
|
||||
|
||||
auto valueSlot = resources->allocVariant();
|
||||
if (!valueSlot)
|
||||
return nullptr;
|
||||
|
||||
if (!keySlot->setString(key, resources))
|
||||
return nullptr;
|
||||
|
||||
CollectionData::appendPair(keySlot, valueSlot, resources);
|
||||
|
||||
return valueSlot.ptr();
|
||||
}
|
||||
|
||||
inline VariantData* ObjectData::addPair(VariantData** value,
|
||||
ResourceManager* resources) {
|
||||
auto keySlot = resources->allocVariant();
|
||||
if (!keySlot)
|
||||
return nullptr;
|
||||
|
||||
auto valueSlot = resources->allocVariant();
|
||||
if (!valueSlot)
|
||||
return nullptr;
|
||||
*value = valueSlot.ptr();
|
||||
|
||||
CollectionData::appendPair(keySlot, valueSlot, resources);
|
||||
|
||||
return keySlot.ptr();
|
||||
}
|
||||
|
||||
// Returns the size (in bytes) of an object with n members.
|
||||
constexpr size_t sizeofObject(size_t n) {
|
||||
return 2 * n * ResourceManager::slotSize;
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -7,17 +7,30 @@
|
||||
#ifdef _MSC_VER // Visual Studio
|
||||
|
||||
# define FORCE_INLINE // __forceinline causes C4714 when returning std::string
|
||||
# define NO_INLINE __declspec(noinline)
|
||||
|
||||
# ifndef ARDUINOJSON_DEPRECATED
|
||||
# define ARDUINOJSON_DEPRECATED(msg) __declspec(deprecated(msg))
|
||||
# endif
|
||||
|
||||
#elif defined(__GNUC__) // GCC or Clang
|
||||
|
||||
# define FORCE_INLINE __attribute__((always_inline))
|
||||
# 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
|
||||
|
||||
# define FORCE_INLINE
|
||||
# define NO_INLINE
|
||||
|
||||
# ifndef ARDUINOJSON_DEPRECATED
|
||||
# define ARDUINOJSON_DEPRECATED(msg)
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -11,21 +11,24 @@
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <int Bits>
|
||||
struct int_t;
|
||||
struct uint_;
|
||||
|
||||
template <>
|
||||
struct int_t<8> {
|
||||
typedef int8_t type;
|
||||
struct uint_<8> {
|
||||
using type = uint8_t;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct int_t<16> {
|
||||
typedef int16_t type;
|
||||
struct uint_<16> {
|
||||
using type = uint16_t;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct int_t<32> {
|
||||
typedef int32_t type;
|
||||
struct uint_<32> {
|
||||
using type = uint32_t;
|
||||
};
|
||||
|
||||
template <int Bits>
|
||||
using uint_t = typename uint_<Bits>::type;
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -18,22 +18,22 @@ template <typename T, typename Enable = void>
|
||||
struct numeric_limits;
|
||||
|
||||
template <typename T>
|
||||
struct numeric_limits<T, typename enable_if<is_unsigned<T>::value>::type> {
|
||||
static T lowest() {
|
||||
struct numeric_limits<T, enable_if_t<is_unsigned<T>::value>> {
|
||||
static constexpr T lowest() {
|
||||
return 0;
|
||||
}
|
||||
static T highest() {
|
||||
static constexpr T highest() {
|
||||
return T(-1);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct numeric_limits<
|
||||
T, typename enable_if<is_integral<T>::value && is_signed<T>::value>::type> {
|
||||
static T lowest() {
|
||||
T, enable_if_t<is_integral<T>::value && is_signed<T>::value>> {
|
||||
static constexpr T lowest() {
|
||||
return T(T(1) << (sizeof(T) * 8 - 1));
|
||||
}
|
||||
static T highest() {
|
||||
static constexpr T highest() {
|
||||
return T(~lowest());
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -1,13 +1,17 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#define ARDUINOJSON_CONCAT_(A, B) A##B
|
||||
#define ARDUINOJSON_CONCAT2(A, B) ARDUINOJSON_CONCAT_(A, B)
|
||||
#define ARDUINOJSON_CONCAT3(A, B, C) \
|
||||
ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT2(A, B), C)
|
||||
#define ARDUINOJSON_CONCAT4(A, B, C, D) \
|
||||
ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT2(A, B), ARDUINOJSON_CONCAT2(C, D))
|
||||
ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT3(A, B, C), D)
|
||||
#define ARDUINOJSON_CONCAT5(A, B, C, D, E) \
|
||||
ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT4(A, B, C, D), E)
|
||||
|
||||
#define ARDUINOJSON_BIN2ALPHA_0000() A
|
||||
#define ARDUINOJSON_BIN2ALPHA_0001() B
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "type_traits/conditional.hpp"
|
||||
#include "type_traits/decay.hpp"
|
||||
#include "type_traits/enable_if.hpp"
|
||||
#include "type_traits/function_traits.hpp"
|
||||
#include "type_traits/integral_constant.hpp"
|
||||
#include "type_traits/is_array.hpp"
|
||||
#include "type_traits/is_base_of.hpp"
|
||||
@ -20,6 +22,6 @@
|
||||
#include "type_traits/is_signed.hpp"
|
||||
#include "type_traits/is_unsigned.hpp"
|
||||
#include "type_traits/make_unsigned.hpp"
|
||||
#include "type_traits/make_void.hpp"
|
||||
#include "type_traits/remove_const.hpp"
|
||||
#include "type_traits/remove_reference.hpp"
|
||||
#include "type_traits/void_t.hpp"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// Copyright © 2014-2025, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
@ -10,12 +10,16 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <bool Condition, class TrueType, class FalseType>
|
||||
struct conditional {
|
||||
typedef TrueType type;
|
||||
using type = TrueType;
|
||||
};
|
||||
|
||||
template <class TrueType, class FalseType>
|
||||
struct conditional<false, TrueType, FalseType> {
|
||||
typedef FalseType type;
|
||||
using type = FalseType;
|
||||
};
|
||||
|
||||
template <bool Condition, class TrueType, class FalseType>
|
||||
using conditional_t =
|
||||
typename conditional<Condition, TrueType, FalseType>::type;
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user