Compare commits

..

52 Commits

Author SHA1 Message Date
a0a451195b Set version to 6.11.1 2019-06-21 08:49:02 +02:00
ce247a5637 Fixed serialized() not working with Flash strings (fixes #1030) 2019-06-21 08:46:32 +02:00
59f9c9747f Add sponsor button on GitHub 2019-06-04 09:14:37 +02:00
fec088e3ed Set version to 6.11.0 2019-05-26 21:11:40 +02:00
4980ee8fb9 Fixed unexpected HTTP/1.0 (closes #944) 2019-05-26 21:07:01 +02:00
2ed77d2cc3 Added support for nullptr (closes #998) 2019-05-26 11:31:51 +02:00
630107ae8a Removed implicit conversion in comparison operators (issue #998) 2019-05-23 21:54:42 +02:00
4eb8074358 Set ARDUINOJSON_ENABLE_NAN and ARDUINOJSON_ENABLE_INFINITY to 0 2019-05-19 17:46:20 +02:00
80a02cd90d Added ARDUINOJSON_ENABLE_INFINITY to enable Infinity in JSON 2019-05-19 15:48:27 +02:00
7427888e05 Added ARDUINOJSON_ENABLE_NAN to enable NaN in JSON (closes #973) 2019-05-18 12:15:36 +02:00
90c1d549a8 Made deserializeJson() more picky about trailing characters (closes #980) 2019-05-16 20:41:07 +02:00
2af003e4e2 Fixed deserializeJson() silently accepting a Stream* (issue #978) 2019-05-09 08:33:09 +02:00
eaf55e174b Fixed invalid result from operator| (closes #981) 2019-05-07 08:12:18 +02:00
0588e578d5 Set version to 6.10.1 2019-04-23 08:47:54 +02:00
12f9aac4ea Fixed "no matching function for call to write(uint8_t)" (closes #972) 2019-04-23 08:46:18 +02:00
81bb3fce97 Fixed build on platformio 2019-04-21 14:35:23 +02:00
6011a2f51a Fixed deserializeJson() not being picky enough (fixes #969) 2019-04-21 14:35:13 +02:00
6071bd07ec Added a link to the FAQ 2019-04-20 12:10:29 +02:00
1c814d3bb6 Fixed warning on Clang 8 2019-03-24 19:39:23 +01:00
9862048a58 Fixed error "attributes are not allowed on a function-definition" 2019-03-24 19:00:23 +01:00
ebc52a5a65 Travis: Added Clang 8 2019-03-24 19:00:23 +01:00
eacad922df Travis: Added Clang 7 2019-03-24 19:00:23 +01:00
d910996613 Travis: Added GCC 8 2019-03-24 19:00:23 +01:00
2fc220fa33 Fixed code samples in the README 2019-03-24 18:21:58 +01:00
8cabda551d Fixed publish.sh not committing appveyor.yml 2019-03-22 22:04:03 +01:00
afd033e9c9 Set version to 6.10.0 2019-03-22 22:01:46 +01:00
6ec5ba521b Added JsonVariant::containsKey() 2019-03-22 21:58:12 +01:00
c8e49a7e4e Added JsonDocument::containsKey() (issue #938) 2019-03-22 08:40:46 +01:00
dee8c8e242 Added BasicJsonDocument to support custom allocator (issue #876) 2019-03-17 21:48:10 +01:00
576543c4b4 Added overflow handling in JsonVariant::as<T>() and JsonVariant::is<T>() 2019-03-06 15:31:37 +01:00
746f2882f7 Removed member call on null 2019-03-05 14:48:33 +01:00
c4cbf9d0bb Don't mark as a "system header" when debugging 2019-03-05 09:19:58 +01:00
49bd51b5f9 Updated version in AppVeyor 2019-03-04 12:21:58 +01:00
e53ae0f9bb Fixed the continuous integration 2019-03-04 12:18:11 +01:00
afdd913a2f Added links to the book page in each example 2019-03-04 12:17:41 +01:00
3df4efd512 Set version to 6.9.1 2019-03-01 18:16:45 +01:00
91dd45c387 Fixed naming conflict with "CAPACITY" (issue #839) 2019-03-01 18:14:23 +01:00
136ee0d576 Marked ArduinoJson.h as a "system header" 2019-03-01 17:31:55 +01:00
1ea8d92cc3 Muted warning "will change in GCC 7.1" (issue #914) 2019-03-01 12:12:47 +01:00
20fcb99830 Fixed warning "conversion may alter value" (issue #914) 2019-03-01 09:15:43 +01:00
f3265d2111 Fixed warning "cast-align" (issue #914) 2019-03-01 09:15:43 +01:00
d6e7709866 Travis: Add g++-arm-linux-gnueabihf 2019-03-01 09:15:43 +01:00
d11019d9e1 Travis: Split build and test scripts 2019-03-01 09:15:43 +01:00
cfd924622e Travis: Define CC and CXX in yaml 2019-03-01 09:15:41 +01:00
27c08b785d Travis: Assume CMake is installed 2019-02-28 17:33:24 +01:00
77f38e4449 Travis: restore build on GCC 4.4 2019-02-28 16:31:08 +01:00
16ddfbc4e0 Fixed strict-aliasing warning in FloatTraits.hpp 2019-02-28 15:37:42 +01:00
8dea900869 Travis: build in Release mode 2019-02-28 15:34:32 +01:00
f342dee2b4 Fixed warning "unused variable" with GCC 4.4 (issue #912) 2019-02-28 15:34:21 +01:00
1d5721f3bd Add an empty cpp file to detect warnings muted by catch.hpp 2019-02-28 15:32:29 +01:00
3170558d6d Added a clear error message for StaticJsonBuffer and DynamicJsonBuffer 2019-02-27 16:38:03 +01:00
3530aa88d6 Updated the examples on wandbox.org 2019-02-26 10:02:52 +01:00
127 changed files with 2467 additions and 990 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
custom: https://arduinojson.org/book/

View File

@ -2,122 +2,124 @@ sudo: false
language: cpp
matrix:
include:
- compiler: gcc
addons:
- addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.4']
env: SCRIPT=test _CC=gcc-4.4 _CXX=g++-4.4
- addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.6']
env: SCRIPT=cmake GCC=4.6
- compiler: gcc
addons:
env: SCRIPT=test _CC=gcc-4.6 _CXX=g++-4.6
- addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.7']
env: SCRIPT=cmake GCC=4.7
- compiler: gcc
addons:
env: SCRIPT=test _CC=gcc-4.7 _CXX=g++-4.7
- addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.8']
env: SCRIPT=cmake GCC=4.8 SANITIZE=address
- compiler: gcc
addons:
env: SCRIPT=test _CC=gcc-4.8 _CXX=g++-4.8 SANITIZE=address
- addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.9']
env: SCRIPT=cmake GCC=4.9 SANITIZE=leak
- compiler: gcc
addons:
env: SCRIPT=test _CC=gcc-4.9 _CXX=g++-4.9 SANITIZE=leak
- addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-5']
env: SCRIPT=cmake GCC=5 # SANITIZE=undefined
- compiler: gcc
addons:
env: SCRIPT=test _CC=gcc-5 _CXX=g++-5 # SANITIZE=undefined
- addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-6']
env: SCRIPT=cmake GCC=6
- compiler: gcc
addons:
env: SCRIPT=test _CC=gcc-6 _CXX=g++-6
- addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-7']
env: SCRIPT=cmake GCC=7
- compiler: clang
env: SCRIPT=cmake
- compiler: clang
addons:
env: SCRIPT=test _CC=gcc-7 _CXX=g++-7
- addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-8']
env: SCRIPT=test _CC=gcc-8 _CXX=g++-8
- addons:
apt:
packages: ['g++-arm-linux-gnueabihf']
env: SCRIPT=build _CC=arm-linux-gnueabihf-gcc _CXX=arm-linux-gnueabihf-g++
- env: SCRIPT=test _CC=clang _CXX=clang++
- addons:
apt:
sources: ['ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5']
packages: ['clang-3.5']
env: SCRIPT=cmake CLANG=3.5 SANITIZE=address
- compiler: clang
addons:
env: SCRIPT=test _CC=clang-3.5 _CXX=clang++-3.5 SANITIZE=address
- addons:
apt:
sources: ['ubuntu-toolchain-r-test','llvm-toolchain-precise-3.6']
packages: ['clang-3.6']
env: SCRIPT=cmake CLANG=3.6 SANITIZE=leak
- compiler: clang
addons:
env: SCRIPT=test _CC=clang-3.6 _CXX=clang++-3.6 SANITIZE=leak
- addons:
apt:
sources: ['ubuntu-toolchain-r-test','llvm-toolchain-precise-3.7']
packages: ['clang-3.7']
env: SCRIPT=cmake CLANG=3.7
- compiler: clang
addons:
env: SCRIPT=test _CC=clang-3.7 _CXX=clang++-3.7
- addons:
apt:
sources: ['ubuntu-toolchain-r-test','llvm-toolchain-precise-3.8']
packages: ['clang-3.8']
env: SCRIPT=cmake CLANG=3.8 SANITIZE=undefined
- compiler: clang
addons:
env: SCRIPT=test _CC=clang-3.8 _CXX=clang++-3.8 SANITIZE=undefined
- addons:
apt:
sources: ['ubuntu-toolchain-r-test','llvm-toolchain-trusty-3.9']
packages: ['clang-3.9']
env: SCRIPT=cmake CLANG=3.9
- compiler: clang
addons:
env: SCRIPT=test _CC=clang-3.9 _CXX=clang++-3.9
- addons:
apt:
sources: ['ubuntu-toolchain-r-test','llvm-toolchain-trusty-4.0']
packages: ['clang-4.0']
env: SCRIPT=cmake CLANG=4.0
- compiler: clang
addons:
env: SCRIPT=test _CC=clang-4.0 _CXX=clang++-4.0
- addons:
apt:
sources: ['ubuntu-toolchain-r-test','llvm-toolchain-trusty-5.0']
packages: ['clang-5.0']
env: SCRIPT=cmake CLANG=5.0
- compiler: clang
addons:
env: SCRIPT=test _CC=clang-5.0 _CXX=clang++-5.0
- addons:
apt:
sources: ['ubuntu-toolchain-r-test','llvm-toolchain-trusty-6.0']
packages: ['clang-6.0']
env: SCRIPT=cmake CLANG=6.0
- compiler: gcc
env: SCRIPT=coverage
env: SCRIPT=test _CC=clang-6.0 _CXX=clang++-6.0
- addons:
apt:
sources: ['ubuntu-toolchain-r-test','llvm-toolchain-trusty-7']
packages: ['clang-7']
env: SCRIPT=test _CC=clang-7 _CXX=clang++-7
- addons:
apt:
sources: ['ubuntu-toolchain-r-test','llvm-toolchain-trusty-8']
packages: ['clang-8']
env: SCRIPT=test _CC=clang-8 _CXX=clang++-8
- env: SCRIPT=coverage
- os: osx
osx_image: xcode7.3
compiler: clang
env: SCRIPT=cmake
env: SCRIPT=test
- os: osx
osx_image: xcode8.3
compiler: clang
env: SCRIPT=cmake
env: SCRIPT=test
- os: osx
osx_image: xcode9.4
compiler: clang
env: SCRIPT=cmake
env: SCRIPT=test
- os: osx
osx_image: xcode10
compiler: clang
env: SCRIPT=cmake SANITIZE=address
env: SCRIPT=test SANITIZE=address
- env: SCRIPT=arduino VERSION=1.6.7 BOARD=arduino:avr:uno
- env: SCRIPT=arduino VERSION=1.8.2 BOARD=arduino:samd:mkr1000
- env: SCRIPT=platformio BOARD=uno
- env: SCRIPT=platformio BOARD=esp01
- compiler: clang
addons:
- addons:
apt:
sources: ['ubuntu-toolchain-r-test','llvm-toolchain-trusty-6.0']
packages: ['clang-6.0','llvm-6.0']

View File

@ -1,6 +1,94 @@
ArduinoJson: change log
=======================
v6.11.1 (2019-06-21)
-------
* Fixed `serialized()` not working with Flash strings (issue #1030)
v6.11.0 (2019-05-26)
-------
* Fixed `deserializeJson()` silently accepting a `Stream*` (issue #978)
* Fixed invalid result from `operator|` (issue #981)
* Made `deserializeJson()` more picky about trailing characters (issue #980)
* Added `ARDUINOJSON_ENABLE_NAN` (default=0) to enable NaN in JSON (issue #973)
* Added `ARDUINOJSON_ENABLE_INFINITY` (default=0) to enable Infinity in JSON
* Removed implicit conversion in comparison operators (issue #998)
* Added lexicographical comparison for `JsonVariant`
* Added support for `nullptr` (issue #998)
> ### BREAKING CHANGES
>
> #### NaN and Infinity
>
> The JSON specification allows neither NaN not Infinity, but previous
> versions of ArduinoJson supported it. Now, ArduinoJson behaves like most
> other libraries: a NaN or and Infinity in the `JsonDocument`, becomes
> a `null` in the output JSON. Also, `deserializeJson()` returns
> `InvalidInput` if the JSON document contains NaN or Infinity.
>
> This version still supports NaN and Infinity in JSON documents, but
> it's disabled by default to be compatible with other JSON parsers.
> If you need the old behavior back, define `ARDUINOJSON_ENABLE_NAN` and
> `ARDUINOJSON_ENABLE_INFINITY` to `1`;:
>
> ```c++
> #define ARDUINOJSON_ENABLE_NAN 1
> #define ARDUINOJSON_ENABLE_INFINITY 1
> #include <ArduinoJson.h>
> ```
>
> #### The "or" operator
>
> This version slightly changes the behavior of the | operator when the
> variant contains a float and the user requests an integer.
>
> Older versions returned the floating point value truncated.
> Now, it returns the default value.
>
> ```c++
> // suppose variant contains 1.2
> int value = variant | 3;
>
> // old behavior:
> value == 1
>
> // new behavior
> value == 3
> ```
>
> If you need the old behavior, you must add `if (variant.is<float>())`.
v6.10.1 (2019-04-23)
-------
* Fixed error "attributes are not allowed on a function-definition"
* Fixed `deserializeJson()` not being picky enough (issue #969)
* Fixed error "no matching function for call to write(uint8_t)" (issue #972)
v6.10.0 (2019-03-22)
-------
* Fixed an integer overflow in the JSON deserializer
* Added overflow handling in `JsonVariant::as<T>()` and `JsonVariant::is<T>()`.
- `as<T>()` returns `0` if the integer `T` overflows
- `is<T>()` returns `false` if the integer `T` overflows
* Added `BasicJsonDocument` to support custom allocator (issue #876)
* Added `JsonDocument::containsKey()` (issue #938)
* Added `JsonVariant::containsKey()`
v6.9.1 (2019-03-01)
------
* Fixed warning "unused variable" with GCC 4.4 (issue #912)
* Fixed warning "cast increases required alignment" (issue #914)
* Fixed warning "conversion may alter value" (issue #914)
* Fixed naming conflict with "CAPACITY" (issue #839)
* Muted warning "will change in GCC 7.1" (issue #914)
* Added a clear error message for `StaticJsonBuffer` and `DynamicJsonBuffer`
* Marked ArduinoJson.h as a "system header"
v6.9.0 (2019-02-26)
------

View File

@ -2,7 +2,7 @@
---
[![arduino-library-badge](https://www.ardu-badge.com/badge/ArduinoJson.svg?version=6.9.0)](https://www.ardu-badge.com/ArduinoJson/6.9.0)
[![arduino-library-badge](https://www.ardu-badge.com/badge/ArduinoJson.svg?version=6.11.1)](https://www.ardu-badge.com/ArduinoJson/6.11.1)
[![Build Status](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/6.x?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x)
[![Build Status](https://travis-ci.org/bblanchon/ArduinoJson.svg?branch=6.x)](https://travis-ci.org/bblanchon/ArduinoJson)
[![Coverage Status](https://coveralls.io/repos/github/bblanchon/ArduinoJson/badge.svg?branch=6.x)](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x)
@ -67,11 +67,10 @@ char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302
DynamicJsonDocument doc(1024);
deserializeJson(doc, json);
JsonObjectRef root = doc.as<JsonObject>();
const char* sensor = root["sensor"];
long time = root["time"];
double latitude = root["data"][0];
double longitude = root["data"][1];
const char* sensor = doc["sensor"];
long time = doc["time"];
double latitude = doc["data"][0];
double longitude = doc["data"][1];
```
See the [tutorial on arduinojson.org](https://arduinojson.org/doc/decoding/?utm_source=github&utm_medium=readme)
@ -83,11 +82,10 @@ Here is a program that generates a JSON document with ArduinoJson:
```c++
DynamicJsonDocument doc(1024);
JsonObject root = doc.to<JsonObject>();
root["sensor"] = "gps";
root["time"] = 1351824120;
doc["sensor"] = "gps";
doc["time"] = 1351824120;
JsonArray data = root.createNestedArray("data");
JsonArray data = doc.createNestedArray("data");
data.add(48.756080);
data.add(2.302038);

View File

@ -1,4 +1,4 @@
version: 6.4.0.{build}
version: 6.11.1.{build}
environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
@ -17,4 +17,4 @@ before_build:
build_script:
- cmake --build . --config %CONFIGURATION%
test_script:
- ctest --output-on-failure .
- ctest -C %CONFIGURATION% --output-on-failure .

View File

@ -10,6 +10,8 @@
// "hostname": "examples.com",
// "port": 2731
// }
//
// https://arduinojson.org/v6/example/config/
#include <ArduinoJson.h>
#include <SD.h>
@ -19,7 +21,8 @@
//
// 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.
// 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;
@ -130,4 +133,15 @@ void loop() {
// not used in this example
}
// Visit https://arduinojson.org/v6/example/config/ for more.
// See also
// --------
//
// https://arduinojson.org/ contains the documentation for all the functions
// used above. It also includes an FAQ that will help you solve any
// serialization or deserialization problem.
//
// The book "Mastering ArduinoJson" contains a case study of a project that has
// a complex configuration with nested members.
// Contrary to this example, the project in the book uses the SPIFFS filesystem.
// Learn more at https://arduinojson.org/book/
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤

View File

@ -3,6 +3,8 @@
// MIT License
//
// This example shows how to generate a JSON document with ArduinoJson.
//
// https://arduinojson.org/v6/example/generator/
#include <ArduinoJson.h>
@ -61,4 +63,15 @@ void loop() {
// not used in this example
}
// Visit https://arduinojson.org/v6/example/generator/ for more.
// See also
// --------
//
// https://arduinojson.org/ contains the documentation for all the functions
// used above. It also includes an FAQ that will help you solve any
// serialization problem.
//
// The book "Mastering ArduinoJson" contains a tutorial on serialization.
// It begins with a simple example, like the one above, and then adds more
// features like serializing directly to a file or an HTTP request.
// Learn more at https://arduinojson.org/book/
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤

View File

@ -15,6 +15,8 @@
// 2.302038
// ]
// }
//
// https://arduinojson.org/v6/example/http-client/
#include <ArduinoJson.h>
#include <Ethernet.h>
@ -57,7 +59,8 @@ void setup() {
// Check HTTP status
char status[32] = {0};
client.readBytesUntil('\r', status, sizeof(status));
if (strcmp(status, "HTTP/1.1 200 OK") != 0) {
// It should be "HTTP/1.0 200 OK" or "HTTP/1.1 200 OK"
if (strcmp(status + 9, "200 OK") != 0) {
Serial.print(F("Unexpected response: "));
Serial.println(status);
return;
@ -98,4 +101,16 @@ void loop() {
// not used in this example
}
// Visit https://arduinojson.org/v6/example/http-client/ for more.
// See also
// --------
//
// https://arduinojson.org/ contains the documentation for all the functions
// used above. It also includes an FAQ that will help you solve any
// serialization problem.
//
// The book "Mastering ArduinoJson" contains a tutorial on deserialization
// showing how to parse the response from GitHub's API. In the last chapter,
// it shows how to parse the huge documents from OpenWeatherMap
// and Reddit.
// Learn more at https://arduinojson.org/book/
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤

View File

@ -3,6 +3,8 @@
// MIT License
//
// This example shows how to deserialize a JSON document with ArduinoJson.
//
// https://arduinojson.org/v6/example/parser/
#include <ArduinoJson.h>
@ -64,4 +66,15 @@ void loop() {
// not used in this example
}
// Visit https://arduinojson.org/v6/example/parser/ for more.
// See also
// --------
//
// https://arduinojson.org/ contains the documentation for all the functions
// used above. It also includes an FAQ that will help you solve any
// deserialization problem.
//
// The book "Mastering ArduinoJson" contains a tutorial on deserialization.
// It begins with a simple example, like the one above, and then adds more
// features like deserializing directly from a file or an HTTP request.
// Learn more at https://arduinojson.org/book/
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤

View File

@ -12,6 +12,8 @@
// "analog": [0, 76, 123, 158, 192, 205],
// "digital": [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0]
// }
//
// https://arduinojson.org/v6/example/http-server/
#include <ArduinoJson.h>
#include <Ethernet.h>
@ -94,4 +96,15 @@ void loop() {
client.stop();
}
// Visit https://arduinojson.org/v6/example/http-server/ for more.
// See also
// --------
//
// https://arduinojson.org/ contains the documentation for all the functions
// used above. It also includes an FAQ that will help you solve any
// serialization problem.
//
// The book "Mastering ArduinoJson" contains a tutorial on serialization.
// It begins with a simple example, then adds more features like serializing
// directly to a file or an HTTP client.
// Learn more at https://arduinojson.org/book/
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤

View File

@ -16,6 +16,8 @@
// For example, you can run netcat on your computer
// $ ncat -ulp 8888
// See https://nmap.org/ncat/
//
// https://arduinojson.org/v6/example/udp-beacon/
#include <ArduinoJson.h>
#include <Ethernet.h>
@ -84,4 +86,15 @@ void loop() {
delay(10000);
}
// Visit https://arduinojson.org/v6/example/udp-beacon/ for more.
// See also
// --------
//
// https://arduinojson.org/ contains the documentation for all the functions
// used above. It also includes an FAQ that will help you solve any
// serialization problem.
//
// The book "Mastering ArduinoJson" contains a tutorial on serialization.
// It begins with a simple example, then adds more features like serializing
// directly to a file or any stream.
// Learn more at https://arduinojson.org/book/
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤

View File

@ -4,6 +4,8 @@
//
// This example shows how to deserialize a MessagePack document with
// ArduinoJson.
//
// https://arduinojson.org/v6/example/msgpack-parser/
#include <ArduinoJson.h>
@ -71,5 +73,3 @@ void setup() {
void loop() {
// not used in this example
}
// Visit https://arduinojson.org/v6/example/msgpack-parser/ for more.

View File

@ -8,6 +8,8 @@
// Use Flash strings sparingly, because ArduinoJson duplicates them in the
// 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/
#include <ArduinoJson.h>
@ -56,4 +58,15 @@ void loop() {
// not used in this example
}
// Visit https://arduinojson.org/v6/example/progmem/ for more.
// See also
// --------
//
// https://arduinojson.org/ contains the documentation for all the functions
// used above. It also includes an FAQ that will help you solve any memory
// problem.
//
// The book "Mastering ArduinoJson" contains a quick C++ course that explains
// how your microcontroller stores strings in memory. It also tells why you
// should not abuse Flash strings with ArduinoJson.
// Learn more at https://arduinojson.org/book/
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤

View File

@ -7,6 +7,8 @@
// Use String objects sparingly, because ArduinoJson duplicates them in the
// 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/
#include <ArduinoJson.h>
@ -62,4 +64,14 @@ void loop() {
// not used in this example
}
// Visit https://arduinojson.org/v6/example/string/ for more.
// See also
// --------
//
// https://arduinojson.org/ contains the documentation for all the functions
// used above. It also includes an FAQ that will help you solve any problem.
//
// The book "Mastering ArduinoJson" contains a quick C++ course that explains
// how your microcontroller stores strings in memory. On several occasions, it
// shows how you can avoid String in your program.
// Learn more at https://arduinojson.org/book/
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤

View File

@ -0,0 +1 @@
9720730739393920739

View File

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

View File

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

View File

@ -18,12 +18,16 @@ update_version_in_source () {
sed -i~ -bE "4s/HEAD/$TAG ($DATE)/; 5s/-+/$UNDERLINE/" CHANGELOG.md
rm CHANGELOG.md*~
sed -i~ -bE "s/\"version\":.*$/\"version\": \"$VERSION\",/" library.json
rm library.json*~
sed -i~ -bE "s/version=.*$/version=$VERSION/" library.properties
rm library.properties*~
sed -i~ -bE "s/version: .*$/version: $VERSION.{build}/" appveyor.yml
rm appveyor.yml*~
sed -i~ -bE \
-e "s/ARDUINOJSON_VERSION .*$/ARDUINOJSON_VERSION \"$VERSION\"/" \
-e "s/ARDUINOJSON_VERSION_MAJOR .*$/ARDUINOJSON_VERSION_MAJOR $MAJOR/" \
@ -34,7 +38,7 @@ update_version_in_source () {
}
commit_new_version () {
git add src/ArduinoJson/version.hpp README.md CHANGELOG.md library.json library.properties
git add src/ArduinoJson/version.hpp README.md CHANGELOG.md library.json library.properties appveyor.yml
git commit -m "Set version to $VERSION"
}

14
scripts/travis/build.sh Executable file
View File

@ -0,0 +1,14 @@
#!/bin/sh -ex
export CC="$_CC"
export CXX="$_CXX"
if [ -n "$SANITIZE" ]; then
export CXXFLAGS="-fsanitize=$SANITIZE"
BUILD_TYPE="Debug"
else
BUILD_TYPE="Release"
fi
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE .
cmake --build .

View File

@ -1,30 +0,0 @@
#!/bin/sh -ex
if [ $(uname) = 'Darwin' ]; then
URL=https://cmake.org/files/v3.4/cmake-3.4.3-Darwin-x86_64.tar.gz
CMAKE=/tmp/CMake.app/Contents/bin/cmake
CTEST=/tmp/CMake.app/Contents/bin/ctest
else
URL=https://cmake.org/files/v3.4/cmake-3.4.3-Linux-x86_64.tar.gz
CMAKE=/tmp/bin/cmake
CTEST=/tmp/bin/ctest
fi
curl -sS $URL | tar xz -C /tmp --strip 1
if [ -n "$GCC" ]; then
export CC="gcc-$GCC"
export CXX="g++-$GCC"
fi
if [ -n "$CLANG" ]; then
export CC="clang-$CLANG"
export CXX="clang++-$CLANG"
fi
if [ -n "$SANITIZE" ]; then
export CXXFLAGS="-fsanitize=$SANITIZE"
fi
$CMAKE .
$CMAKE --build .
$CTEST --output-on-failure .

View File

@ -1,8 +1,6 @@
#!/bin/sh -eux
curl https://cmake.org/files/v3.4/cmake-3.4.0-Linux-x86_64.tar.gz | tar xz -C /tmp --strip 1
/tmp/bin/cmake -DCOVERAGE=true .
cmake -DCOVERAGE=true .
make
make test

View File

@ -3,7 +3,7 @@
ROOT_DIR=$(dirname $0)/../../
INCLUDE_DIR=${ROOT_DIR}/src/
FUZZING_DIR=${ROOT_DIR}/fuzzing/
CXXFLAGS="-g -fprofile-instr-generate -fcoverage-mapping -fsanitize=address,fuzzer"
CXXFLAGS="-g -fprofile-instr-generate -fcoverage-mapping -fsanitize=address,undefined,fuzzer -fno-sanitize-recover=all"
fuzz() {
NAME="$1"

View File

@ -4,6 +4,18 @@ pip install --user platformio
rm -r test
case $BOARD in
uno)
platformio lib install 868 # SD library
platformio lib install 872 # Ethernet library
;;
esp01)
platformio lib uninstall 161 || true
platformio lib uninstall 868 || true
platformio lib uninstall 872 || true
;;
esac
for EXAMPLE in $PWD/examples/*/*.ino;
do
platformio ci $EXAMPLE -l '.' -b $BOARD

4
scripts/travis/test.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/sh -ex
"$(dirname "$0")/build.sh"
ctest --output-on-failure .

View File

@ -8,11 +8,11 @@
#include "ArduinoJson.h"
int main() {
// The JSON document
// 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 arduinojson.org/assistant to compute the capacity.
// Use arduinojson.org/v6/assistant to compute the capacity.
StaticJsonDocument<200> doc;
// StaticJsonObject allocates memory on the stack, it can be
@ -20,30 +20,35 @@ int main() {
//
// DynamicJsonDocument doc(200);
// Make our document be an object
JsonObject root = doc.to<JsonObject>();
// Add values in the object
// StaticJsonObject allocates memory on the stack, it can be
// replaced by DynamicJsonDocument which allocates in the heap.
//
// Most of the time, you can rely on the implicit casts.
// In other case, you can do root.set<long>("time", 1351824120);
root["sensor"] = "gps";
root["time"] = 1351824120;
// DynamicJsonDocument doc(200);
// Add values in the document
//
doc["sensor"] = "gps";
doc["time"] = 1351824120;
// Add an array.
//
JsonArray data = root.createNestedArray("data");
JsonArray data = doc.createNestedArray("data");
data.add(48.756080);
data.add(2.302038);
serializeJson(root, std::cout);
// This prints:
// Generate the minified JSON and send it to STDOUT
//
serializeJson(doc, std::cout);
// The above line prints:
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
// Start a new line
std::cout << std::endl;
serializeJsonPretty(root, std::cout);
// This prints:
// Generate the prettified JSON and send it to STDOUT
//
serializeJsonPretty(doc, std::cout);
// The above line prints:
// {
// "sensor": "gps",
// "time": 1351824120,
@ -52,6 +57,4 @@ int main() {
// 2.302038
// ]
// }
return 0;
}

View File

@ -8,23 +8,26 @@
#include "ArduinoJson.h"
int main() {
// Root JSON object
// Allocate the JSON document
//
// Inside the brackets, 300 is the size of the memory pool in bytes.
// 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 arduinojson.org/assistant to compute the capacity.
// Use arduinojson.org/v6/assistant to compute the capacity.
StaticJsonDocument<300> doc;
// StaticJsonDocument<N> allocates memory on the stack, it can be
// replaced by DynamicJsonObject which allocates in the heap.
// replaced by DynamicJsonDocument which allocates in the heap.
//
// DynamicJsonObject doc(200);
// DynamicJsonDocument doc(200);
// JSON input string.
//
// It's better to use a char[] as shown here.
// If you use a const char* or a String, ArduinoJson will
// have to make a copy of the input in the JsonBuffer.
// 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[] =
"{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
@ -37,17 +40,14 @@ int main() {
return 1;
}
// Get the root object in the document
JsonObject root = doc.as<JsonObject>();
// Fetch values.
//
// Most of the time, you can rely on the implicit casts.
// In other case, you can do doc["time"].as<long>();
const char* sensor = root["sensor"];
long time = root["time"];
double latitude = root["data"][0];
double longitude = root["data"][1];
const char* sensor = doc["sensor"];
long time = doc["time"];
double latitude = doc["data"][0];
double longitude = doc["data"][1];
// Print values.
std::cout << sensor << std::endl;

View File

@ -49,17 +49,14 @@ int main() {
return 1;
}
// Get the root object in the document
JsonObject root = doc.as<JsonObject>();
// Fetch values.
//
// Most of the time, you can rely on the implicit casts.
// In other case, you can do doc["time"].as<long>();
const char* sensor = root["sensor"];
long time = root["time"];
double latitude = root["data"][0];
double longitude = root["data"][1];
const char* sensor = doc["sensor"];
long time = doc["time"];
double latitude = doc["data"][0];
double longitude = doc["data"][1];
// Print values.
std::cout << sensor << std::endl;

View File

@ -4,6 +4,14 @@
#pragma once
#ifndef ARDUINOJSON_DEBUG
#ifdef __clang__
#pragma clang system_header
#elif defined __GNUC__
#pragma GCC system_header
#endif
#endif
#include "ArduinoJson/Namespace.hpp"
#include "ArduinoJson/Array/ArrayRef.hpp"
@ -28,6 +36,8 @@
#include "ArduinoJson/MsgPack/MsgPackDeserializer.hpp"
#include "ArduinoJson/MsgPack/MsgPackSerializer.hpp"
#include "ArduinoJson/compatibility.hpp"
namespace ArduinoJson {
typedef ARDUINOJSON_NAMESPACE::ArrayConstRef JsonArrayConst;
typedef ARDUINOJSON_NAMESPACE::ArrayRef JsonArray;
@ -40,6 +50,7 @@ typedef ARDUINOJSON_NAMESPACE::String JsonString;
typedef ARDUINOJSON_NAMESPACE::UInt JsonUInt;
typedef ARDUINOJSON_NAMESPACE::VariantConstRef JsonVariantConst;
typedef ARDUINOJSON_NAMESPACE::VariantRef JsonVariant;
using ARDUINOJSON_NAMESPACE::BasicJsonDocument;
using ARDUINOJSON_NAMESPACE::copyArray;
using ARDUINOJSON_NAMESPACE::DeserializationError;
using ARDUINOJSON_NAMESPACE::deserializeJson;

View File

@ -23,7 +23,8 @@ template <typename TData>
class ArrayRefBase {
public:
operator VariantConstRef() const {
return VariantConstRef(reinterpret_cast<const VariantData*>(_data));
const void* data = _data; // prevent warning cast-align
return VariantConstRef(reinterpret_cast<const VariantData*>(data));
}
template <typename Visitor>
@ -77,6 +78,10 @@ class ArrayConstRef : public ArrayRefBase<const CollectionData>,
}
FORCE_INLINE VariantConstRef operator[](size_t index) const {
return getElement(index);
}
FORCE_INLINE VariantConstRef getElement(size_t index) const {
return VariantConstRef(_data ? _data->get(index) : 0);
}
};
@ -94,7 +99,8 @@ class ArrayRef : public ArrayRefBase<CollectionData>,
: base_type(data), _pool(pool) {}
operator VariantRef() {
return VariantRef(_pool, reinterpret_cast<VariantData*>(_data));
void* data = _data; // prevent warning cast-align
return VariantRef(_pool, reinterpret_cast<VariantData*>(data));
}
operator ArrayConstRef() const {

View File

@ -26,7 +26,7 @@ inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) {
}
inline VariantData* CollectionData::add(MemoryPool* pool) {
return addSlot(pool)->data();
return slotData(addSlot(pool));
}
template <typename TAdaptedString>

View File

@ -12,8 +12,10 @@
#if __cplusplus >= 201103L
#define ARDUINOJSON_HAS_LONG_LONG 1
#define ARDUINOJSON_HAS_NULLPTR 1
#else
#define ARDUINOJSON_HAS_LONG_LONG 0
#define ARDUINOJSON_HAS_NULLPTR 0
#endif
// Small or big machine?
@ -88,28 +90,38 @@
#ifdef ARDUINO
// Enable support for Arduino String
// Enable support for Arduino's String class
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
#define ARDUINOJSON_ENABLE_ARDUINO_STRING 1
#endif
// Enable support for Arduino Stream
// Enable support for Arduino's Stream class
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1
#endif
// Enable support for Arduino's Print class
#ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT
#define ARDUINOJSON_ENABLE_ARDUINO_PRINT 1
#endif
#else // ARDUINO
// Disable support for Arduino String
// Enable support for Arduino's String class
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
#define ARDUINOJSON_ENABLE_ARDUINO_STRING 0
#endif
// Disable support for Arduino Stream
// Enable support for Arduino's Stream class
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0
#endif
// Enable support for Arduino's Print class
#ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT
#define ARDUINOJSON_ENABLE_ARDUINO_PRINT 0
#endif
#endif // ARDUINO
#ifndef ARDUINOJSON_ENABLE_PROGMEM
@ -125,6 +137,16 @@
#define ARDUINOJSON_DECODE_UNICODE 0
#endif
// Support NaN in JSON
#ifndef ARDUINOJSON_ENABLE_NAN
#define ARDUINOJSON_ENABLE_NAN 0
#endif
// Support Infinity in JSON
#ifndef ARDUINOJSON_ENABLE_INFINITY
#define ARDUINOJSON_ENABLE_INFINITY 0
#endif
// Control the exponentiation threshold for big numbers
// CAUTION: cannot be more that 1e9 !!!!
#ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD
@ -139,7 +161,7 @@
#ifndef ARDUINOJSON_LITTLE_ENDIAN
#if defined(_MSC_VER) || \
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \
(defined(__LITTLE_ENDIAN__))
defined(__LITTLE_ENDIAN__) || defined(__i386) || defined(__x86_64)
#define ARDUINOJSON_LITTLE_ENDIAN 1
#else
#define ARDUINOJSON_LITTLE_ENDIAN 0

View File

@ -12,22 +12,14 @@ namespace ARDUINOJSON_NAMESPACE {
struct ArduinoStreamReader {
Stream& _stream;
char _current;
bool _ended;
public:
explicit ArduinoStreamReader(Stream& stream)
: _stream(stream), _current(0), _ended(false) {}
explicit ArduinoStreamReader(Stream& stream) : _stream(stream) {}
char read() {
int read() {
// don't use _stream.read() as it ignores the timeout
char c = 0;
_ended = _stream.readBytes(&c, 1) == 0;
return c;
}
bool ended() const {
return _ended;
uint8_t c;
return _stream.readBytes(&c, 1) ? c : -1;
}
};

View File

@ -6,6 +6,16 @@
namespace ARDUINOJSON_NAMESPACE {
template <typename T>
struct IsCharOrVoid {
static const bool value =
is_same<T, void>::value || is_same<T, char>::value ||
is_same<T, unsigned char>::value || is_same<T, signed char>::value;
};
template <typename T>
struct IsCharOrVoid<const T> : IsCharOrVoid<T> {};
class UnsafeCharPointerReader {
const char* _ptr;
@ -13,13 +23,8 @@ class UnsafeCharPointerReader {
explicit UnsafeCharPointerReader(const char* ptr)
: _ptr(ptr ? ptr : reinterpret_cast<const char*>("")) {}
char read() {
return static_cast<char>(*_ptr++);
}
bool ended() const {
// we cannot know, that's why it's unsafe
return false;
int read() {
return static_cast<unsigned char>(*_ptr++);
}
};
@ -31,22 +36,25 @@ class SafeCharPointerReader {
explicit SafeCharPointerReader(const char* ptr, size_t len)
: _ptr(ptr ? ptr : reinterpret_cast<const char*>("")), _end(_ptr + len) {}
char read() {
return static_cast<char>(*_ptr++);
}
bool ended() const {
return _ptr == _end;
int read() {
if (_ptr < _end)
return static_cast<unsigned char>(*_ptr++);
else
return -1;
}
};
template <typename TChar>
inline UnsafeCharPointerReader makeReader(TChar* input) {
inline typename enable_if<IsCharOrVoid<TChar>::value,
UnsafeCharPointerReader>::type
makeReader(TChar* input) {
return UnsafeCharPointerReader(reinterpret_cast<const char*>(input));
}
template <typename TChar>
inline SafeCharPointerReader makeReader(TChar* input, size_t n) {
inline
typename enable_if<IsCharOrVoid<TChar>::value, SafeCharPointerReader>::type
makeReader(TChar* input, size_t n) {
return SafeCharPointerReader(reinterpret_cast<const char*>(input), n);
}

View File

@ -14,14 +14,9 @@ class UnsafeFlashStringReader {
explicit UnsafeFlashStringReader(const __FlashStringHelper* ptr)
: _ptr(reinterpret_cast<const char*>(ptr)) {}
char read() {
int read() {
return pgm_read_byte_near(_ptr++);
}
bool ended() const {
// this reader cannot detect the end
return false;
}
};
class SafeFlashStringReader {
@ -32,12 +27,11 @@ class SafeFlashStringReader {
explicit SafeFlashStringReader(const __FlashStringHelper* ptr, size_t size)
: _ptr(reinterpret_cast<const char*>(ptr)), _end(_ptr + size) {}
char read() {
return pgm_read_byte_near(_ptr++);
}
bool ended() const {
return _ptr == _end;
int read() {
if (_ptr < _end)
return pgm_read_byte_near(_ptr++);
else
return -1;
}
};

View File

@ -14,12 +14,11 @@ class IteratorReader {
explicit IteratorReader(TIterator begin, TIterator end)
: _ptr(begin), _end(end) {}
bool ended() const {
return _ptr == _end;
}
char read() {
return char(*_ptr++);
int read() {
if (_ptr < _end)
return static_cast<unsigned char>(*_ptr++);
else
return -1;
}
};

View File

@ -18,12 +18,8 @@ class StdStreamReader {
explicit StdStreamReader(std::istream& stream)
: _stream(stream), _current(0) {}
bool ended() const {
return _stream.eof();
}
char read() {
return static_cast<char>(_stream.get());
int read() {
return _stream.get();
}
private:

View File

@ -0,0 +1,89 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2019
// MIT License
#pragma once
#include "JsonDocument.hpp"
namespace ARDUINOJSON_NAMESPACE {
template <typename TAllocator>
class AllocatorOwner {
protected:
AllocatorOwner() {}
AllocatorOwner(const AllocatorOwner& src) : _allocator(src._allocator) {}
AllocatorOwner(TAllocator allocator) : _allocator(allocator) {}
void* allocate(size_t n) {
return _allocator.allocate(n);
}
void deallocate(void* p) {
_allocator.deallocate(p);
}
private:
TAllocator _allocator;
};
template <typename TAllocator>
class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument {
public:
explicit BasicJsonDocument(size_t capa, TAllocator allocator = TAllocator())
: AllocatorOwner<TAllocator>(allocator), JsonDocument(allocPool(capa)) {}
BasicJsonDocument(const BasicJsonDocument& src)
: AllocatorOwner<TAllocator>(src),
JsonDocument(allocPool(src.memoryUsage())) {
set(src);
}
template <typename T>
BasicJsonDocument(const T& src,
typename enable_if<IsVisitable<T>::value>::type* = 0)
: JsonDocument(allocPool(src.memoryUsage())) {
set(src);
}
// disambiguate
BasicJsonDocument(VariantRef src)
: JsonDocument(allocPool(src.memoryUsage())) {
set(src);
}
~BasicJsonDocument() {
freePool();
}
BasicJsonDocument& operator=(const BasicJsonDocument& src) {
reallocPoolIfTooSmall(src.memoryUsage());
set(src);
return *this;
}
template <typename T>
BasicJsonDocument& operator=(const T& src) {
reallocPoolIfTooSmall(src.memoryUsage());
set(src);
return *this;
}
private:
MemoryPool allocPool(size_t requiredSize) {
size_t capa = addPadding(requiredSize);
return MemoryPool(reinterpret_cast<char*>(this->allocate(capa)), capa);
}
void reallocPoolIfTooSmall(size_t requiredSize) {
if (requiredSize <= capacity()) return;
freePool();
replacePool(allocPool(addPadding(requiredSize)));
}
void freePool() {
this->deallocate(memoryPool().buffer());
}
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -4,66 +4,22 @@
#pragma once
#include "JsonDocument.hpp"
#include "BasicJsonDocument.hpp"
#include <stdlib.h> // malloc, free
namespace ARDUINOJSON_NAMESPACE {
class DynamicJsonDocument : public JsonDocument {
public:
explicit DynamicJsonDocument(size_t capa) : JsonDocument(allocPool(capa)) {}
DynamicJsonDocument(const DynamicJsonDocument& src)
: JsonDocument(allocPool(src.memoryUsage())) {
set(src);
struct DefaultAllocator {
void* allocate(size_t n) {
return malloc(n);
}
template <typename T>
DynamicJsonDocument(const T& src,
typename enable_if<IsVisitable<T>::value>::type* = 0)
: JsonDocument(allocPool(src.memoryUsage())) {
set(src);
}
// disambiguate
DynamicJsonDocument(VariantRef src)
: JsonDocument(allocPool(src.memoryUsage())) {
set(src);
}
~DynamicJsonDocument() {
freePool();
}
DynamicJsonDocument& operator=(const DynamicJsonDocument& src) {
reallocPoolIfTooSmall(src.memoryUsage());
set(src);
return *this;
}
template <typename T>
DynamicJsonDocument& operator=(const T& src) {
reallocPoolIfTooSmall(src.memoryUsage());
set(src);
return *this;
}
private:
MemoryPool allocPool(size_t requiredSize) {
size_t capa = addPadding(requiredSize);
return MemoryPool(reinterpret_cast<char*>(malloc(capa)), capa);
}
void reallocPoolIfTooSmall(size_t requiredSize) {
if (requiredSize <= capacity()) return;
freePool();
replacePool(allocPool(addPadding(requiredSize)));
}
void freePool() {
free(memoryPool().buffer());
void deallocate(void* p) {
free(p);
}
};
typedef BasicJsonDocument<DefaultAllocator> DynamicJsonDocument;
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -124,6 +124,21 @@ class JsonDocument : public Visitable {
return getOrAddMember(key).template to<ObjectRef>();
}
// containsKey(char*) const
// containsKey(const char*) const
// containsKey(const __FlashStringHelper*) const
template <typename TChar>
bool containsKey(TChar* key) const {
return !getMember(key).isUndefined();
}
// containsKey(const std::string&) const
// containsKey(const String&) const
template <typename TString>
bool containsKey(const TString& key) const {
return !getMember(key).isUndefined();
}
// operator[](const std::string&)
// operator[](const String&)
template <typename TString>
@ -150,7 +165,7 @@ class JsonDocument : public Visitable {
FORCE_INLINE
typename enable_if<IsString<TString>::value, VariantConstRef>::type
operator[](const TString& key) const {
return getVariant()[key];
return getMember(key);
}
// operator[](char*) const
@ -160,7 +175,7 @@ class JsonDocument : public Visitable {
FORCE_INLINE
typename enable_if<IsString<TChar*>::value, VariantConstRef>::type
operator[](TChar* key) const {
return getVariant()[key];
return getMember(key);
}
FORCE_INLINE ElementProxy<JsonDocument&> operator[](size_t index) {
@ -168,23 +183,44 @@ class JsonDocument : public Visitable {
}
FORCE_INLINE VariantConstRef operator[](size_t index) const {
return VariantConstRef(_data.getElement(index));
return getElement(index);
}
FORCE_INLINE VariantRef getElement(size_t index) {
return VariantRef(&_pool, _data.getElement(index));
}
// getMember(char*) const
// getMember(const char*) const
// getMember(const __FlashStringHelper*) const
FORCE_INLINE VariantConstRef getElement(size_t index) const {
return VariantConstRef(_data.getElement(index));
}
// JsonVariantConst getMember(char*) const
// JsonVariantConst getMember(const char*) const
// JsonVariantConst getMember(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE VariantConstRef getMember(TChar* key) const {
return VariantConstRef(_data.getMember(adaptString(key)));
}
// JsonVariantConst getMember(const std::string&) const
// JsonVariantConst getMember(const String&) const
template <typename TString>
FORCE_INLINE
typename enable_if<IsString<TString>::value, VariantConstRef>::type
getMember(const TString& key) const {
return VariantConstRef(_data.getMember(adaptString(key)));
}
// JsonVariant getMember(char*)
// JsonVariant getMember(const char*)
// JsonVariant getMember(const __FlashStringHelper*)
template <typename TChar>
FORCE_INLINE VariantRef getMember(TChar* key) {
return VariantRef(&_pool, _data.getMember(adaptString(key)));
}
// getMember(const std::string&) const
// getMember(const String&) const
// JsonVariant getMember(const std::string&)
// JsonVariant getMember(const String&)
template <typename TString>
FORCE_INLINE typename enable_if<IsString<TString>::value, VariantRef>::type
getMember(const TString& key) {

View File

@ -8,28 +8,28 @@
namespace ARDUINOJSON_NAMESPACE {
template <size_t CAPACITY>
template <size_t desiredCapacity>
class StaticJsonDocument : public JsonDocument {
static const size_t ACTUAL_CAPACITY =
AddPadding<Max<1, CAPACITY>::value>::value;
static const size_t _capacity =
AddPadding<Max<1, desiredCapacity>::value>::value;
public:
StaticJsonDocument() : JsonDocument(_buffer, ACTUAL_CAPACITY) {}
StaticJsonDocument() : JsonDocument(_buffer, _capacity) {}
StaticJsonDocument(const StaticJsonDocument& src)
: JsonDocument(_buffer, ACTUAL_CAPACITY) {
: JsonDocument(_buffer, _capacity) {
set(src);
}
template <typename T>
StaticJsonDocument(const T& src,
typename enable_if<IsVisitable<T>::value>::type* = 0)
: JsonDocument(_buffer, ACTUAL_CAPACITY) {
: JsonDocument(_buffer, _capacity) {
set(src);
}
// disambiguate
StaticJsonDocument(VariantRef src) : JsonDocument(_buffer, ACTUAL_CAPACITY) {
StaticJsonDocument(VariantRef src) : JsonDocument(_buffer, _capacity) {
set(src);
}
@ -45,7 +45,7 @@ class StaticJsonDocument : public JsonDocument {
}
private:
char _buffer[ACTUAL_CAPACITY];
char _buffer[_capacity];
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -6,8 +6,7 @@
#include "../Deserialization/deserialize.hpp"
#include "../Memory/MemoryPool.hpp"
#include "../Numbers/isFloat.hpp"
#include "../Numbers/isInteger.hpp"
#include "../Numbers/parseNumber.hpp"
#include "../Polyfills/type_traits.hpp"
#include "../Variant/VariantData.hpp"
#include "EscapeSequence.hpp"
@ -29,19 +28,14 @@ class JsonDeserializer {
_nestingLimit(nestingLimit),
_loaded(false) {}
DeserializationError parse(VariantData &variant) {
DeserializationError err = skipSpacesAndComments();
if (err) return err;
DeserializationError err = parseVariant(variant);
switch (current()) {
case '[':
return parseArray(variant.toArray());
case '{':
return parseObject(variant.toObject());
default:
return parseValue(variant);
if (!err && _current != 0 && !variant.isEnclosed()) {
// We don't detect trailing characters earlier, so we need to check now
err = DeserializationError::InvalidInput;
}
return err;
}
private:
@ -49,10 +43,8 @@ class JsonDeserializer {
char current() {
if (!_loaded) {
if (_reader.ended())
_current = 0;
else
_current = _reader.read();
int c = _reader.read();
_current = static_cast<char>(c > 0 ? c : 0);
_loaded = true;
}
return _current;
@ -68,6 +60,26 @@ class JsonDeserializer {
return true;
}
DeserializationError parseVariant(VariantData &variant) {
DeserializationError err = skipSpacesAndComments();
if (err) return err;
switch (current()) {
case '[':
return parseArray(variant.toArray());
case '{':
return parseObject(variant.toObject());
case '\"':
case '\'':
return parseStringValue(variant);
default:
return parseNumericValue(variant);
}
}
DeserializationError parseArray(CollectionData &array) {
if (_nestingLimit == 0) return DeserializationError::TooDeep;
@ -89,7 +101,7 @@ class JsonDeserializer {
// 1 - Parse value
_nestingLimit--;
err = parse(*value);
err = parseVariant(*value);
_nestingLimit++;
if (err) return err;
@ -135,7 +147,7 @@ class JsonDeserializer {
// Parse value
_nestingLimit--;
err = parse(*slot->data());
err = parseVariant(*slot->data());
_nestingLimit++;
if (err) return err;
@ -153,14 +165,6 @@ class JsonDeserializer {
}
}
DeserializationError parseValue(VariantData &variant) {
if (isQuote(current())) {
return parseStringValue(variant);
} else {
return parseNumericValue(variant);
}
}
DeserializationError parseKey(const char *&key) {
if (isQuote(current())) {
return parseQuotedString(key);
@ -251,14 +255,6 @@ class JsonDeserializer {
}
buffer[n] = 0;
if (isInteger(buffer)) {
result.setInteger(parseInteger<Integer>(buffer));
return DeserializationError::Ok;
}
if (isFloat(buffer)) {
result.setFloat(parseFloat<Float>(buffer));
return DeserializationError::Ok;
}
c = buffer[0];
if (c == 't') { // true
result.setBoolean(true);
@ -275,6 +271,23 @@ class JsonDeserializer {
return n == 4 ? DeserializationError::Ok
: DeserializationError::IncompleteInput;
}
ParsedNumber<Float, UInt> num = parseNumber<Float, UInt>(buffer);
switch (num.type()) {
case VALUE_IS_NEGATIVE_INTEGER:
result.setNegativeInteger(num.uintValue);
return DeserializationError::Ok;
case VALUE_IS_POSITIVE_INTEGER:
result.setPositiveInteger(num.uintValue);
return DeserializationError::Ok;
case VALUE_IS_FLOAT:
result.setFloat(num.floatValue);
return DeserializationError::Ok;
}
return DeserializationError::InvalidInput;
}
@ -306,7 +319,7 @@ class JsonDeserializer {
static inline uint8_t decodeHex(char c) {
if (c < 'A') return uint8_t(c - '0');
c &= ~0x20; // uppercase
c = char(c & ~0x20); // uppercase
return uint8_t(c - 'A' + 10);
}

View File

@ -52,14 +52,23 @@ class TextFormatter {
template <typename T>
void writeFloat(T value) {
if (isnan(value)) return writeRaw("NaN");
if (isnan(value)) return writeRaw(ARDUINOJSON_ENABLE_NAN ? "NaN" : "null");
#if ARDUINOJSON_ENABLE_INFINITY
if (value < 0.0) {
writeRaw('-');
value = -value;
}
if (isinf(value)) return writeRaw("Infinity");
#else
if (isinf(value)) return writeRaw("null");
if (value < 0.0) {
writeRaw('-');
value = -value;
}
#endif
FloatParts<T> parts(value);

View File

@ -91,7 +91,7 @@ class MemoryPool {
return reinterpret_cast<T*>(allocRight(sizeof(T)));
}
char* allocRight(size_t bytes) {
void* allocRight(size_t bytes) {
if (!canAlloc(bytes)) return 0;
_right -= bytes;
return _right;

View File

@ -79,8 +79,7 @@ class MsgPackDeserializer {
#if ARDUINOJSON_USE_LONG_LONG
return readInteger<uint64_t>(variant);
#else
readInteger<uint32_t>();
return readInteger<uint32_t>(variant);
return DeserializationError::NotSupported;
#endif
case 0xd0:
@ -96,8 +95,7 @@ class MsgPackDeserializer {
#if ARDUINOJSON_USE_LONG_LONG
return readInteger<int64_t>(variant);
#else
if (!skip(4)) return DeserializationError::IncompleteInput;
return readInteger<int32_t>(variant);
return DeserializationError::NotSupported;
#endif
case 0xca:
@ -136,17 +134,10 @@ class MsgPackDeserializer {
// Prevent VS warning "assignment operator could not be generated"
MsgPackDeserializer &operator=(const MsgPackDeserializer &);
bool skip(uint8_t n) {
while (n--) {
if (_reader.ended()) return false;
_reader.read();
}
return true;
}
bool readByte(uint8_t &value) {
if (_reader.ended()) return false;
value = static_cast<uint8_t>(_reader.read());
int c = _reader.read();
if (c < 0) return false;
value = static_cast<uint8_t>(c);
return true;
}

View File

@ -24,6 +24,7 @@ class MsgPackSerializer {
}
template <typename T>
ARDUINOJSON_NO_SANITIZE("float-cast-overflow")
typename enable_if<sizeof(T) == 8>::type visitFloat(T value64) {
float value32 = float(value64);
if (value32 == value64) {

View File

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

View File

@ -10,14 +10,19 @@
#define ARDUINOJSON_DO_CONCAT(A, B) A##B
#define ARDUINOJSON_CONCAT2(A, B) ARDUINOJSON_DO_CONCAT(A, B)
#define ARDUINOJSON_CONCAT3(A, B, C) \
ARDUINOJSON_CONCAT2(A, ARDUINOJSON_CONCAT2(B, C))
#define ARDUINOJSON_CONCAT4(A, B, C, D) \
ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT2(A, B), ARDUINOJSON_CONCAT2(C, D))
#define ARDUINOJSON_CONCAT8(A, B, C, D, E, F, G, H) \
ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT4(A, B, C, D), \
ARDUINOJSON_CONCAT4(E, F, G, H))
#define ARDUINOJSON_CONCAT10(A, B, C, D, E, F, G, H, I, J) \
ARDUINOJSON_CONCAT8(A, B, C, D, E, F, G, ARDUINOJSON_CONCAT3(H, I, J))
#define ARDUINOJSON_NAMESPACE \
ARDUINOJSON_CONCAT8(ArduinoJson, ARDUINOJSON_VERSION_MAJOR, \
ARDUINOJSON_VERSION_MINOR, ARDUINOJSON_VERSION_REVISION, \
_, ARDUINOJSON_USE_LONG_LONG, ARDUINOJSON_USE_DOUBLE, \
ARDUINOJSON_DECODE_UNICODE)
#define ARDUINOJSON_NAMESPACE \
ARDUINOJSON_CONCAT10( \
ArduinoJson, ARDUINOJSON_VERSION_MAJOR, ARDUINOJSON_VERSION_MINOR, \
ARDUINOJSON_VERSION_REVISION, _, ARDUINOJSON_USE_LONG_LONG, \
ARDUINOJSON_USE_DOUBLE, ARDUINOJSON_DECODE_UNICODE, \
ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY)

View File

@ -7,6 +7,7 @@
#include <stddef.h> // for size_t
#include <stdint.h>
#include "../Configuration.hpp"
#include "../Polyfills/alias_cast.hpp"
#include "../Polyfills/math.hpp"
namespace ARDUINOJSON_NAMESPACE {
@ -16,10 +17,10 @@ struct FloatTraits {};
template <typename T>
struct FloatTraits<T, 8 /*64bits*/> {
typedef int64_t mantissa_type;
typedef uint64_t mantissa_type;
static const short mantissa_bits = 52;
static const mantissa_type mantissa_max =
(static_cast<mantissa_type>(1) << mantissa_bits) - 1;
(mantissa_type(1) << mantissa_bits) - 1;
typedef int16_t exponent_type;
static const exponent_type exponent_max = 308;
@ -94,25 +95,28 @@ struct FloatTraits<T, 8 /*64bits*/> {
return forge(0x7ff00000, 0x00000000);
}
static T highest() {
return forge(0x7FEFFFFF, 0xFFFFFFFF);
}
static T lowest() {
return forge(0xFFEFFFFF, 0xFFFFFFFF);
}
// constructs a double floating point values from its binary representation
// we use this function to workaround platforms with single precision literals
// (for example, when -fsingle-precision-constant is passed to GCC)
static T forge(uint32_t msb, uint32_t lsb) {
union {
uint64_t integerBits;
T floatBits;
};
integerBits = (uint64_t(msb) << 32) | lsb;
return floatBits;
return alias_cast<T>((uint64_t(msb) << 32) | lsb);
}
};
template <typename T>
struct FloatTraits<T, 4 /*32bits*/> {
typedef int32_t mantissa_type;
typedef uint32_t mantissa_type;
static const short mantissa_bits = 23;
static const mantissa_type mantissa_max =
(static_cast<mantissa_type>(1) << mantissa_bits) - 1;
(mantissa_type(1) << mantissa_bits) - 1;
typedef int8_t exponent_type;
static const exponent_type exponent_max = 38;
@ -150,12 +154,7 @@ struct FloatTraits<T, 4 /*32bits*/> {
}
static T forge(uint32_t bits) {
union {
uint32_t integerBits;
T floatBits;
};
integerBits = bits;
return floatBits;
return alias_cast<T>(bits);
}
static T nan() {
@ -165,5 +164,13 @@ struct FloatTraits<T, 4 /*32bits*/> {
static T inf() {
return forge(0x7f800000);
}
static T highest() {
return forge(0x7f7fffff);
}
static T lowest() {
return forge(0xFf7fffff);
}
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -0,0 +1,105 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2019
// MIT License
#pragma once
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#elif defined(__GNUC__)
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
#pragma GCC diagnostic push
#endif
#pragma GCC diagnostic ignored "-Wconversion"
#endif
#include "../Polyfills/limits.hpp"
#include "Float.hpp"
#include "FloatTraits.hpp"
#include "Integer.hpp"
namespace ARDUINOJSON_NAMESPACE {
template <typename TOut, typename TIn>
typename enable_if<is_integral<TOut>::value && sizeof(TOut) <= sizeof(TIn),
bool>::type
canStorePositiveInteger(TIn value) {
return value <= TIn(numeric_limits<TOut>::highest());
}
template <typename TOut, typename TIn>
typename enable_if<is_integral<TOut>::value && sizeof(TIn) < sizeof(TOut),
bool>::type
canStorePositiveInteger(TIn) {
return true;
}
template <typename TOut, typename TIn>
typename enable_if<is_floating_point<TOut>::value, bool>::type
canStorePositiveInteger(TIn) {
return true;
}
template <typename TOut, typename TIn>
typename enable_if<is_floating_point<TOut>::value, bool>::type
canStoreNegativeInteger(TIn) {
return true;
}
template <typename TOut, typename TIn>
typename enable_if<is_integral<TOut>::value && is_signed<TOut>::value &&
sizeof(TOut) <= sizeof(TIn),
bool>::type
canStoreNegativeInteger(TIn value) {
return value <= TIn(numeric_limits<TOut>::highest()) + 1;
}
template <typename TOut, typename TIn>
typename enable_if<is_integral<TOut>::value && is_signed<TOut>::value &&
sizeof(TIn) < sizeof(TOut),
bool>::type
canStoreNegativeInteger(TIn) {
return true;
}
template <typename TOut, typename TIn>
typename enable_if<is_integral<TOut>::value && is_unsigned<TOut>::value,
bool>::type
canStoreNegativeInteger(TIn) {
return false;
}
template <typename TOut, typename TIn>
TOut convertPositiveInteger(TIn value) {
return canStorePositiveInteger<TOut>(value) ? TOut(value) : 0;
}
template <typename TOut, typename TIn>
TOut convertNegativeInteger(TIn value) {
return canStoreNegativeInteger<TOut>(value) ? TOut(~value + 1) : 0;
}
template <typename TOut, typename TIn>
typename enable_if<is_floating_point<TOut>::value, TOut>::type convertFloat(
TIn value) {
return TOut(value);
}
template <typename TOut, typename TIn>
typename enable_if<!is_floating_point<TOut>::value, TOut>::type convertFloat(
TIn value) {
return value >= numeric_limits<TOut>::lowest() &&
value <= numeric_limits<TOut>::highest()
? TOut(value)
: 0;
}
} // namespace ARDUINOJSON_NAMESPACE
#if defined(__clang__)
#pragma clang diagnostic pop
#elif defined(__GNUC__)
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
#pragma GCC diagnostic pop
#endif
#endif

View File

@ -1,36 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2019
// MIT License
#pragma once
#include <string.h> // for strcmp
#include "../Polyfills/ctype.hpp"
namespace ARDUINOJSON_NAMESPACE {
inline bool isFloat(const char* s) {
if (!s) return false;
if (!strcmp(s, "NaN")) return true;
if (issign(*s)) s++;
if (!strcmp(s, "Infinity")) return true;
if (*s == '\0') return false;
while (isdigit(*s)) s++;
if (*s == '.') {
s++;
while (isdigit(*s)) s++;
}
if (*s == 'e' || *s == 'E') {
s++;
if (issign(*s)) s++;
if (!isdigit(*s)) return false;
while (isdigit(*s)) s++;
}
return *s == '\0';
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -1,17 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2019
// MIT License
#pragma once
#include "../Polyfills/ctype.hpp"
namespace ARDUINOJSON_NAMESPACE {
inline bool isInteger(const char* s) {
if (!s || !*s) return false;
if (issign(*s)) s++;
while (isdigit(*s)) s++;
return *s == '\0';
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -4,85 +4,15 @@
#pragma once
#include "../Numbers/FloatTraits.hpp"
#include "../Polyfills/ctype.hpp"
#include "../Polyfills/math.hpp"
#include "convertNumber.hpp"
#include "parseNumber.hpp"
namespace ARDUINOJSON_NAMESPACE {
template <typename T>
inline T parseFloat(const char* s) {
typedef FloatTraits<T> traits;
typedef typename traits::mantissa_type mantissa_t;
typedef typename traits::exponent_type exponent_t;
if (!s) return 0; // NULL
bool negative_result = false;
switch (*s) {
case '-':
negative_result = true;
s++;
break;
case '+':
s++;
break;
}
if (*s == 't') return 1; // true
if (*s == 'n' || *s == 'N') return traits::nan();
if (*s == 'i' || *s == 'I')
return negative_result ? -traits::inf() : traits::inf();
mantissa_t mantissa = 0;
exponent_t exponent_offset = 0;
while (isdigit(*s)) {
if (mantissa < traits::mantissa_max / 10)
mantissa = mantissa * 10 + (*s - '0');
else
exponent_offset++;
s++;
}
if (*s == '.') {
s++;
while (isdigit(*s)) {
if (mantissa < traits::mantissa_max / 10) {
mantissa = mantissa * 10 + (*s - '0');
exponent_offset--;
}
s++;
}
}
int exponent = 0;
if (*s == 'e' || *s == 'E') {
s++;
bool negative_exponent = false;
if (*s == '-') {
negative_exponent = true;
s++;
} else if (*s == '+') {
s++;
}
while (isdigit(*s)) {
exponent = exponent * 10 + (*s - '0');
if (exponent + exponent_offset > traits::exponent_max) {
if (negative_exponent)
return negative_result ? -0.0f : 0.0f;
else
return negative_result ? -traits::inf() : traits::inf();
}
s++;
}
if (negative_exponent) exponent = -exponent;
}
exponent += exponent_offset;
T result = traits::make_float(static_cast<T>(mantissa), exponent);
return negative_result ? -result : result;
// try to reuse the same parameters as JsonDeserializer
typedef typename choose_largest<Float, T>::type TFloat;
return parseNumber<TFloat, UInt>(s).template as<T>();
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -4,34 +4,16 @@
#pragma once
#include "../Configuration.hpp"
#include "../Polyfills/ctype.hpp"
#include "../Polyfills/type_traits.hpp"
#include "convertNumber.hpp"
#include "parseNumber.hpp"
namespace ARDUINOJSON_NAMESPACE {
template <typename T>
T parseInteger(const char *s) {
if (!s) return 0; // NULL
if (*s == 't') return 1; // "true"
T result = 0;
bool negative_result = false;
switch (*s) {
case '-':
negative_result = true;
s++;
break;
case '+':
s++;
break;
}
while (isdigit(*s)) {
result = T(result * 10 + T(*s - '0'));
s++;
}
return negative_result ? T(~result + 1) : result;
// try to reuse the same parameters as JsonDeserializer
typedef typename choose_largest<UInt, typename make_unsigned<T>::type>::type
TUInt;
return parseNumber<Float, TUInt>(s).template as<T>();
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -0,0 +1,156 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2019
// MIT License
#pragma once
#include "../Polyfills/assert.hpp"
#include "../Polyfills/ctype.hpp"
#include "../Polyfills/math.hpp"
#include "../Polyfills/type_traits.hpp"
#include "../Variant/VariantContent.hpp"
#include "FloatTraits.hpp"
#include "convertNumber.hpp"
namespace ARDUINOJSON_NAMESPACE {
template <typename TFloat, typename TUInt>
struct ParsedNumber {
ParsedNumber() : uintValue(0), floatValue(0), _type(VALUE_IS_NULL) {}
ParsedNumber(TUInt value, bool is_negative)
: uintValue(value),
floatValue(TFloat(value)),
_type(uint8_t(is_negative ? VALUE_IS_NEGATIVE_INTEGER
: VALUE_IS_POSITIVE_INTEGER)) {}
ParsedNumber(TFloat value) : floatValue(value), _type(VALUE_IS_FLOAT) {}
template <typename T>
T as() const {
switch (_type) {
case VALUE_IS_NEGATIVE_INTEGER:
return convertNegativeInteger<T>(uintValue);
case VALUE_IS_POSITIVE_INTEGER:
return convertPositiveInteger<T>(uintValue);
case VALUE_IS_FLOAT:
return convertFloat<T>(floatValue);
default:
return 0;
}
}
uint8_t type() const {
return _type;
}
TUInt uintValue;
TFloat floatValue;
uint8_t _type;
};
template <typename A, typename B>
struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> {};
template <typename TFloat, typename TUInt>
inline ParsedNumber<TFloat, TUInt> parseNumber(const char *s) {
typedef FloatTraits<TFloat> traits;
typedef typename choose_largest<typename traits::mantissa_type, TUInt>::type
mantissa_t;
typedef typename traits::exponent_type exponent_t;
typedef ParsedNumber<TFloat, TUInt> return_type;
ARDUINOJSON_ASSERT(s != 0);
bool is_negative = false;
switch (*s) {
case '-':
is_negative = true;
s++;
break;
case '+':
s++;
break;
}
#if ARDUINOJSON_ENABLE_NAN
if (*s == 'n' || *s == 'N') return traits::nan();
#endif
#if ARDUINOJSON_ENABLE_INFINITY
if (*s == 'i' || *s == 'I')
return is_negative ? -traits::inf() : traits::inf();
#endif
if (!isdigit(*s) && *s != '.') return return_type();
mantissa_t mantissa = 0;
exponent_t exponent_offset = 0;
const mantissa_t maxUint = TUInt(-1);
while (isdigit(*s)) {
uint8_t digit = uint8_t(*s - '0');
if (mantissa > maxUint / 10) break;
mantissa *= 10;
if (mantissa > maxUint - digit) break;
mantissa += digit;
s++;
}
if (*s == '\0') return return_type(TUInt(mantissa), is_negative);
// avoid mantissa overflow
while (mantissa > traits::mantissa_max) {
mantissa /= 10;
exponent_offset++;
}
// remaing digits can't fit in the mantissa
while (isdigit(*s)) {
exponent_offset++;
s++;
}
if (*s == '.') {
s++;
while (isdigit(*s)) {
if (mantissa < traits::mantissa_max / 10) {
mantissa = mantissa * 10 + uint8_t(*s - '0');
exponent_offset--;
}
s++;
}
}
int exponent = 0;
if (*s == 'e' || *s == 'E') {
s++;
bool negative_exponent = false;
if (*s == '-') {
negative_exponent = true;
s++;
} else if (*s == '+') {
s++;
}
while (isdigit(*s)) {
exponent = exponent * 10 + (*s - '0');
if (exponent + exponent_offset > traits::exponent_max) {
if (negative_exponent)
return is_negative ? -0.0f : 0.0f;
else
return is_negative ? -traits::inf() : traits::inf();
}
s++;
}
if (negative_exponent) exponent = -exponent;
}
exponent += exponent_offset;
// we should be at the end of the string, otherwise it's an error
if (*s != '\0') return return_type();
TFloat result = traits::make_float(static_cast<TFloat>(mantissa), exponent);
return is_negative ? -result : result;
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -40,9 +40,9 @@ class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >,
return *this;
}
// operator=(char*) const
// operator=(const char*) const
// operator=(const __FlashStringHelper*) const
// operator=(char*)
// operator=(const char*)
// operator=(const __FlashStringHelper*)
template <typename TChar>
FORCE_INLINE this_type &operator=(TChar *src) {
getOrAddUpstreamMember().set(src);

View File

@ -16,11 +16,6 @@ void objectAccept(const CollectionData *obj, Visitor &visitor) {
visitor.visitNull();
}
template <typename TAdaptedString>
inline bool objectContainsKey(const CollectionData *obj, TAdaptedString key) {
return obj && obj->containsKey(key);
}
inline bool objectEquals(const CollectionData *lhs, const CollectionData *rhs) {
if (lhs == rhs) return true;
if (!lhs || !rhs) return false;

View File

@ -35,4 +35,18 @@ inline ObjectRef ObjectShortcuts<TObject>::createNestedObject(
TChar* key) const {
return impl()->getOrAddMember(key).template to<ObjectRef>();
}
template <typename TObject>
template <typename TString>
inline typename enable_if<IsString<TString>::value, bool>::type
ObjectShortcuts<TObject>::containsKey(const TString& key) const {
return !impl()->getMember(key).isUndefined();
}
template <typename TObject>
template <typename TChar>
inline typename enable_if<IsString<TChar*>::value, bool>::type
ObjectShortcuts<TObject>::containsKey(TChar* key) const {
return !impl()->getMember(key).isUndefined();
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -18,7 +18,8 @@ template <typename TData>
class ObjectRefBase {
public:
operator VariantConstRef() const {
return VariantConstRef(reinterpret_cast<const VariantData*>(_data));
const void* data = _data; // prevent warning cast-align
return VariantConstRef(reinterpret_cast<const VariantData*>(data));
}
template <typename Visitor>
@ -26,21 +27,6 @@ class ObjectRefBase {
objectAccept(_data, visitor);
}
// containsKey(const std::string&) const
// containsKey(const String&) const
template <typename TString>
FORCE_INLINE bool containsKey(const TString& key) const {
return objectContainsKey(_data, adaptString(key));
}
// containsKey(char*) const
// containsKey(const char*) const
// containsKey(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE bool containsKey(TChar* key) const {
return objectContainsKey(_data, adaptString(key));
}
FORCE_INLINE bool isNull() const {
return _data == 0;
}
@ -82,6 +68,21 @@ class ObjectConstRef : public ObjectRefBase<const CollectionData>,
return iterator();
}
// containsKey(const std::string&) const
// containsKey(const String&) const
template <typename TString>
FORCE_INLINE bool containsKey(const TString& key) const {
return !getMember(key).isUndefined();
}
// containsKey(char*) const
// containsKey(const char*) const
// containsKey(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE bool containsKey(TChar* key) const {
return !getMember(key).isUndefined();
}
// getMember(const std::string&) const
// getMember(const String&) const
template <typename TString>
@ -140,7 +141,8 @@ class ObjectRef : public ObjectRefBase<CollectionData>,
: base_type(data), _pool(buf) {}
operator VariantRef() const {
return VariantRef(_pool, reinterpret_cast<VariantData*>(_data));
void* data = _data; // prevent warning cast-align
return VariantRef(_pool, reinterpret_cast<VariantData*>(data));
}
operator ObjectConstRef() const {

View File

@ -15,6 +15,19 @@ class MemberProxy;
template <typename TObject>
class ObjectShortcuts {
public:
// containsKey(const std::string&) const
// containsKey(const String&) const
template <typename TString>
FORCE_INLINE typename enable_if<IsString<TString>::value, bool>::type
containsKey(const TString &key) const;
// containsKey(char*) const
// containsKey(const char*) const
// containsKey(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE typename enable_if<IsString<TChar *>::value, bool>::type
containsKey(TChar *key) const;
// operator[](const std::string&) const
// operator[](const String&) const
template <typename TString>

View File

@ -7,154 +7,237 @@
#include "../Variant/VariantRef.hpp"
namespace ARDUINOJSON_NAMESPACE {
template <typename T, typename Enable = void>
struct Comparer;
template <typename T>
struct is_simple_value {
static const bool value = is_integral<T>::value ||
is_floating_point<T>::value ||
is_same<T, bool>::value;
struct Comparer<T, typename enable_if<IsString<T>::value>::type> {
T rhs;
int result;
explicit Comparer(T value) : rhs(value), result(1) {}
void visitArray(const CollectionData &) {}
void visitObject(const CollectionData &) {}
void visitFloat(Float) {}
void visitString(const char *lhs) {
result = -adaptString(rhs).compare(lhs);
}
void visitRawJson(const char *, size_t) {}
void visitNegativeInteger(UInt) {}
void visitPositiveInteger(UInt) {}
void visitBoolean(bool) {}
void visitNull() {
result = adaptString(rhs).compare(NULL);
}
};
template <typename T>
typename enable_if<is_signed<T>::value, int>::type sign(const T &value) {
return value < 0 ? -1 : value > 0 ? 1 : 0;
}
template <typename T>
typename enable_if<is_unsigned<T>::value, int>::type sign(const T &value) {
return value > 0 ? 1 : 0;
}
template <typename T>
struct Comparer<T, typename enable_if<is_integral<T>::value ||
is_floating_point<T>::value>::type> {
T rhs;
int result;
explicit Comparer(T value) : rhs(value), result(1) {}
void visitArray(const CollectionData &) {}
void visitObject(const CollectionData &) {}
void visitFloat(Float lhs) {
result = sign(lhs - static_cast<Float>(rhs));
}
void visitString(const char *) {}
void visitRawJson(const char *, size_t) {}
void visitNegativeInteger(UInt lhs) {
result = -sign(static_cast<T>(lhs) + rhs);
}
void visitPositiveInteger(UInt lhs) {
result = static_cast<T>(lhs) < rhs ? -1 : static_cast<T>(lhs) > rhs ? 1 : 0;
}
void visitBoolean(bool) {}
void visitNull() {}
};
template <>
struct Comparer<bool, void> {
bool rhs;
int result;
explicit Comparer(bool value) : rhs(value), result(1) {}
void visitArray(const CollectionData &) {}
void visitObject(const CollectionData &) {}
void visitFloat(Float) {}
void visitString(const char *) {}
void visitRawJson(const char *, size_t) {}
void visitNegativeInteger(UInt) {}
void visitPositiveInteger(UInt) {}
void visitBoolean(bool lhs) {
result = static_cast<int>(lhs - rhs);
}
void visitNull() {}
};
#if ARDUINOJSON_HAS_NULLPTR
template <>
struct Comparer<decltype(nullptr), void> {
int result;
explicit Comparer(decltype(nullptr)) : result(1) {}
void visitArray(const CollectionData &) {}
void visitObject(const CollectionData &) {}
void visitFloat(Float) {}
void visitString(const char *) {}
void visitRawJson(const char *, size_t) {}
void visitNegativeInteger(UInt) {}
void visitPositiveInteger(UInt) {}
void visitBoolean(bool) {}
void visitNull() {
result = 0;
}
};
#endif
template <typename TVariant>
class VariantComparisons {
private:
template <typename T>
static int compare(TVariant lhs, const T &rhs) {
Comparer<T> comparer(rhs);
lhs.accept(comparer);
return comparer.result;
}
public:
// const char* == TVariant
// value == TVariant
template <typename T>
friend typename enable_if<IsString<T *>::value, bool>::type operator==(
T *lhs, TVariant rhs) {
return adaptString(lhs).equals(rhs.template as<const char *>());
friend bool operator==(T *lhs, TVariant rhs) {
return compare(rhs, lhs) == 0;
}
template <typename T>
friend bool operator==(const T &lhs, TVariant rhs) {
return compare(rhs, lhs) == 0;
}
// std::string == TVariant
// TVariant == value
template <typename T>
friend typename enable_if<IsString<T>::value, bool>::type operator==(
const T &lhs, TVariant rhs) {
return adaptString(lhs).equals(rhs.template as<const char *>());
friend bool operator==(TVariant lhs, T *rhs) {
return compare(lhs, rhs) == 0;
}
template <typename T>
friend bool operator==(TVariant lhs, const T &rhs) {
return compare(lhs, rhs) == 0;
}
// TVariant == const char*
// value != TVariant
template <typename T>
friend typename enable_if<IsString<T *>::value, bool>::type operator==(
TVariant lhs, T *rhs) {
return adaptString(rhs).equals(lhs.template as<const char *>());
friend bool operator!=(T *lhs, TVariant rhs) {
return compare(rhs, lhs) != 0;
}
template <typename T>
friend bool operator!=(const T &lhs, TVariant rhs) {
return compare(rhs, lhs) != 0;
}
// TVariant == std::string
// TVariant != value
template <typename T>
friend typename enable_if<IsString<T>::value, bool>::type operator==(
TVariant lhs, const T &rhs) {
return adaptString(rhs).equals(lhs.template as<const char *>());
friend bool operator!=(TVariant lhs, T *rhs) {
return compare(lhs, rhs) != 0;
}
template <typename T>
friend bool operator!=(TVariant lhs, const T &rhs) {
return compare(lhs, rhs) != 0;
}
// bool/int/float == TVariant
// value < TVariant
template <typename T>
friend typename enable_if<is_simple_value<T>::value, bool>::type operator==(
const T &lhs, TVariant rhs) {
return lhs == rhs.template as<T>();
friend bool operator<(T *lhs, TVariant rhs) {
return compare(rhs, lhs) > 0;
}
template <typename T>
friend bool operator<(const T &lhs, TVariant rhs) {
return compare(rhs, lhs) > 0;
}
// TVariant == bool/int/float
// TVariant < value
template <typename T>
friend typename enable_if<is_simple_value<T>::value, bool>::type operator==(
TVariant lhs, const T &rhs) {
return lhs.template as<T>() == rhs;
friend bool operator<(TVariant lhs, T *rhs) {
return compare(lhs, rhs) < 0;
}
template <typename T>
friend bool operator<(TVariant lhs, const T &rhs) {
return compare(lhs, rhs) < 0;
}
// const char* != TVariant
// value <= TVariant
template <typename T>
friend typename enable_if<IsString<T *>::value, bool>::type operator!=(
T *lhs, TVariant rhs) {
return !adaptString(lhs).equals(rhs.template as<const char *>());
friend bool operator<=(T *lhs, TVariant rhs) {
return compare(rhs, lhs) >= 0;
}
template <typename T>
friend bool operator<=(const T &lhs, TVariant rhs) {
return compare(rhs, lhs) >= 0;
}
// std::string != TVariant
// TVariant <= value
template <typename T>
friend typename enable_if<IsString<T>::value, bool>::type operator!=(
const T &lhs, TVariant rhs) {
return !adaptString(lhs).equals(rhs.template as<const char *>());
friend bool operator<=(TVariant lhs, T *rhs) {
return compare(lhs, rhs) <= 0;
}
template <typename T>
friend bool operator<=(TVariant lhs, const T &rhs) {
return compare(lhs, rhs) <= 0;
}
// TVariant != const char*
// value > TVariant
template <typename T>
friend typename enable_if<IsString<T *>::value, bool>::type operator!=(
TVariant lhs, T *rhs) {
return !adaptString(rhs).equals(lhs.template as<const char *>());
friend bool operator>(T *lhs, TVariant rhs) {
return compare(rhs, lhs) < 0;
}
template <typename T>
friend bool operator>(const T &lhs, TVariant rhs) {
return compare(rhs, lhs) < 0;
}
// TVariant != std::string
// TVariant > value
template <typename T>
friend typename enable_if<IsString<T>::value, bool>::type operator!=(
TVariant lhs, const T &rhs) {
return !adaptString(rhs).equals(lhs.template as<const char *>());
friend bool operator>(TVariant lhs, T *rhs) {
return compare(lhs, rhs) > 0;
}
template <typename T>
friend bool operator>(TVariant lhs, const T &rhs) {
return compare(lhs, rhs) > 0;
}
// bool/int/float != TVariant
// value >= TVariant
template <typename T>
friend typename enable_if<is_simple_value<T>::value, bool>::type operator!=(
const T &lhs, TVariant rhs) {
return lhs != rhs.template as<T>();
friend bool operator>=(T *lhs, TVariant rhs) {
return compare(rhs, lhs) <= 0;
}
template <typename T>
friend bool operator>=(const T &lhs, TVariant rhs) {
return compare(rhs, lhs) <= 0;
}
// TVariant != bool/int/float
// TVariant >= value
template <typename T>
friend typename enable_if<is_simple_value<T>::value, bool>::type operator!=(
TVariant lhs, const T &rhs) {
return lhs.template as<T>() != rhs;
friend bool operator>=(TVariant lhs, T *rhs) {
return compare(lhs, rhs) >= 0;
}
// bool/int/float < TVariant
template <typename T>
friend typename enable_if<is_simple_value<T>::value, bool>::type operator<(
const T &lhs, TVariant rhs) {
return lhs < rhs.template as<T>();
}
// TVariant < bool/int/float
template <typename T>
friend typename enable_if<is_simple_value<T>::value, bool>::type operator<(
TVariant lhs, const T &rhs) {
return lhs.template as<T>() < rhs;
}
// bool/int/float <= TVariant
template <typename T>
friend typename enable_if<is_simple_value<T>::value, bool>::type operator<=(
const T &lhs, TVariant rhs) {
return lhs <= rhs.template as<T>();
}
// TVariant <= bool/int/float
template <typename T>
friend typename enable_if<is_simple_value<T>::value, bool>::type operator<=(
TVariant lhs, const T &rhs) {
return lhs.template as<T>() <= rhs;
}
// bool/int/float > TVariant
template <typename T>
friend typename enable_if<is_simple_value<T>::value, bool>::type operator>(
const T &lhs, TVariant rhs) {
return lhs > rhs.template as<T>();
}
// TVariant > bool/int/float
template <typename T>
friend typename enable_if<is_simple_value<T>::value, bool>::type operator>(
TVariant lhs, const T &rhs) {
return lhs.template as<T>() > rhs;
}
// bool/int/float >= TVariant
template <typename T>
friend typename enable_if<is_simple_value<T>::value, bool>::type operator>=(
const T &lhs, TVariant rhs) {
return lhs >= rhs.template as<T>();
}
// TVariant >= bool/int/float
template <typename T>
friend typename enable_if<is_simple_value<T>::value, bool>::type operator>=(
TVariant lhs, const T &rhs) {
return lhs.template as<T>() >= rhs;
friend bool operator>=(TVariant lhs, const T &rhs) {
return compare(lhs, rhs) >= 0;
}
};

View File

@ -15,8 +15,7 @@ class VariantOr {
public:
// Returns the default value if the VariantRef is undefined of incompatible
template <typename T>
typename enable_if<!is_integral<T>::value, T>::type operator|(
const T &defaultValue) const {
T operator|(const T &defaultValue) const {
if (impl()->template is<T>())
return impl()->template as<T>();
else
@ -30,17 +29,6 @@ class VariantOr {
return value ? value : defaultValue;
}
// Returns the default value if the VariantRef is undefined of incompatible
// Special case for integers: we also accept double
template <typename Integer>
typename enable_if<is_integral<Integer>::value, Integer>::type operator|(
const Integer &defaultValue) const {
if (impl()->template is<double>())
return impl()->template as<Integer>();
else
return defaultValue;
}
private:
const TImpl *impl() const {
return static_cast<const TImpl *>(this);

View File

@ -0,0 +1,28 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2019
// MIT License
#pragma once
#include <stdint.h>
#include <stdlib.h> // for size_t
#include "../Configuration.hpp"
#include "../Polyfills/math.hpp"
namespace ARDUINOJSON_NAMESPACE {
template <typename T, typename F>
struct alias_cast_t {
union {
F raw;
T data;
};
};
template <typename T, typename F>
T alias_cast(F raw_data) {
alias_cast_t<T, F> ac;
ac.raw = raw_data;
return ac.data;
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -33,3 +33,13 @@
#else
#define NOEXCEPT throw()
#endif
#if defined(__has_attribute)
#if __has_attribute(no_sanitize)
#define ARDUINOJSON_NO_SANITIZE(check) __attribute__((no_sanitize(check)))
#else
#define ARDUINOJSON_NO_SANITIZE(check)
#endif
#else
#define ARDUINOJSON_NO_SANITIZE(check)
#endif

View File

@ -0,0 +1,45 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2019
// MIT License
#pragma once
#include "../Polyfills/type_traits.hpp"
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4310)
#endif
namespace ARDUINOJSON_NAMESPACE {
// Differs from standard because we can't use the symbols "min" and "max"
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() {
return 0;
}
static 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() {
return T(T(1) << (sizeof(T) * 8 - 1));
}
static T highest() {
return T(~lowest());
}
};
} // namespace ARDUINOJSON_NAMESPACE
#ifdef _MSC_VER
#pragma warning(pop)
#endif

View File

@ -0,0 +1,22 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2019
// MIT License
#pragma once
namespace ARDUINOJSON_NAMESPACE {
inline int8_t safe_strcmp(const char* a, const char* b) {
if (a == b) return 0;
if (!a) return -1;
if (!b) return 1;
return static_cast<int8_t>(strcmp(a, b));
}
inline int8_t safe_strncmp(const char* a, const char* b, size_t n) {
if (a == b) return 0;
if (!a) return -1;
if (!b) return 1;
return static_cast<int8_t>(strncmp(a, b, n));
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -15,5 +15,6 @@
#include "type_traits/is_same.hpp"
#include "type_traits/is_signed.hpp"
#include "type_traits/is_unsigned.hpp"
#include "type_traits/make_unsigned.hpp"
#include "type_traits/remove_const.hpp"
#include "type_traits/remove_reference.hpp"

View File

@ -0,0 +1,49 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2019
// MIT License
#pragma once
#include "type_identity.hpp"
namespace ARDUINOJSON_NAMESPACE {
template <typename T>
struct make_unsigned;
template <>
struct make_unsigned<char> : type_identity<unsigned char> {};
template <>
struct make_unsigned<signed char> : type_identity<unsigned char> {};
template <>
struct make_unsigned<unsigned char> : type_identity<unsigned char> {};
template <>
struct make_unsigned<signed short> : type_identity<unsigned short> {};
template <>
struct make_unsigned<unsigned short> : type_identity<unsigned short> {};
template <>
struct make_unsigned<signed int> : type_identity<unsigned int> {};
template <>
struct make_unsigned<unsigned int> : type_identity<unsigned int> {};
template <>
struct make_unsigned<signed long> : type_identity<unsigned long> {};
template <>
struct make_unsigned<unsigned long> : type_identity<unsigned long> {};
#if ARDUINOJSON_HAS_LONG_LONG
template <>
struct make_unsigned<signed long long> : type_identity<unsigned long long> {};
template <>
struct make_unsigned<unsigned long long> : type_identity<unsigned long long> {};
#endif
#if ARDUINOJSON_HAS_INT64
template <>
struct make_unsigned<signed __int64> : type_identity<unsigned __int64> {};
template <>
struct make_unsigned<unsigned __int64> : type_identity<unsigned __int64> {};
#endif
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -0,0 +1,15 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2019
// MIT License
#pragma once
#include "integral_constant.hpp"
namespace ARDUINOJSON_NAMESPACE {
template <typename T>
struct type_identity {
typedef T type;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -14,32 +14,38 @@
namespace ARDUINOJSON_NAMESPACE {
template <template <typename> class TSerializer, typename TSource,
typename TPrint>
typename enable_if<!IsWriteableString<TPrint>::value, size_t>::type serialize(
const TSource &source, TPrint &destination) {
TSerializer<TPrint> serializer(destination);
typename TDestination>
size_t doSerialize(const TSource &source, TDestination &destination) {
TSerializer<TDestination> serializer(destination);
source.accept(serializer);
return serializer.bytesWritten();
}
#if ARDUINOJSON_ENABLE_STD_STREAM
template <template <typename> class TSerializer, typename TSource>
size_t serialize(const TSource &source, std::ostream &os) {
StreamWriter writer(os);
return serialize<TSerializer>(source, writer);
size_t serialize(const TSource &source, std::ostream &destination) {
StreamWriter writer(destination);
return doSerialize<TSerializer>(source, writer);
}
#endif
#if ARDUINOJSON_ENABLE_ARDUINO_PRINT
template <template <typename> class TSerializer, typename TSource>
size_t serialize(const TSource &source, Print &destination) {
return doSerialize<TSerializer>(source, destination);
}
#endif
template <template <typename> class TSerializer, typename TSource>
size_t serialize(const TSource &source, char *buffer, size_t bufferSize) {
StaticStringWriter writer(buffer, bufferSize);
return serialize<TSerializer>(source, writer);
return doSerialize<TSerializer>(source, writer);
}
template <template <typename> class TSerializer, typename TSource, size_t N>
size_t serialize(const TSource &source, char (&buffer)[N]) {
StaticStringWriter writer(buffer, N);
return serialize<TSerializer>(source, writer);
return doSerialize<TSerializer>(source, writer);
}
template <template <typename> class TSerializer, typename TSource,
@ -47,7 +53,7 @@ template <template <typename> class TSerializer, typename TSource,
typename enable_if<IsWriteableString<TString>::value, size_t>::type serialize(
const TSource &source, TString &str) {
DynamicStringWriter<TString> writer(str);
return serialize<TSerializer>(source, writer);
return doSerialize<TSerializer>(source, writer);
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -5,6 +5,7 @@
#pragma once
#include <WString.h>
#include "../Polyfills/safe_strcmp.hpp"
namespace ARDUINOJSON_NAMESPACE {
@ -25,11 +26,14 @@ class ArduinoStringAdapter {
return !_str->c_str();
}
bool equals(const char* expected) const {
int8_t compare(const char* other) const {
// Arduino's String::c_str() can return NULL
const char* actual = _str->c_str();
if (!actual || !expected) return actual == expected;
return 0 == strcmp(actual, expected);
const char* me = _str->c_str();
return safe_strcmp(me, other);
}
bool equals(const char* expected) const {
return compare(expected) == 0;
}
const char* data() const {

View File

@ -6,6 +6,7 @@
#include <stddef.h> // size_t
#include <string.h> // strcmp
#include "../Polyfills/safe_strcmp.hpp"
namespace ARDUINOJSON_NAMESPACE {
@ -13,10 +14,12 @@ class ConstRamStringAdapter {
public:
ConstRamStringAdapter(const char* str = 0) : _str(str) {}
int8_t compare(const char* other) const {
return safe_strcmp(_str, other);
}
bool equals(const char* expected) const {
const char* actual = _str;
if (!actual || !expected) return actual == expected;
return strcmp(actual, expected) == 0;
return compare(expected) == 0;
}
bool isNull() const {

View File

@ -10,10 +10,15 @@ class FlashStringAdapter {
public:
FlashStringAdapter(const __FlashStringHelper* str) : _str(str) {}
int8_t compare(const char* other) const {
if (!other && !_str) return 0;
if (!_str) return -1;
if (!other) return 1;
return -strcmp_P(other, reinterpret_cast<const char*>(_str));
}
bool equals(const char* expected) const {
const char* actual = reinterpret_cast<const char*>(_str);
if (!actual || !expected) return actual == expected;
return strcmp_P(expected, actual) == 0;
return compare(expected) == 0;
}
bool isNull() const {

View File

@ -11,10 +11,15 @@ class SizedFlashStringAdapter {
SizedFlashStringAdapter(const __FlashStringHelper* str, size_t sz)
: _str(str), _size(sz) {}
int8_t compare(const char* other) const {
if (!other && !_str) return 0;
if (!_str) return -1;
if (!other) return 1;
return -strncmp_P(other, reinterpret_cast<const char*>(_str), _size);
}
bool equals(const char* expected) const {
const char* actual = reinterpret_cast<const char*>(_str);
if (!actual || !expected) return actual == expected;
return strncmp_P(expected, actual, _size) == 0;
return compare(expected) == 0;
}
bool isNull() const {
@ -24,7 +29,7 @@ class SizedFlashStringAdapter {
char* save(MemoryPool* pool) const {
if (!_str) return NULL;
char* dup = pool->allocFrozenString(_size);
if (!dup) memcpy_P(dup, (const char*)_str, _size);
if (dup) memcpy_P(dup, (const char*)_str, _size);
return dup;
}

View File

@ -12,10 +12,12 @@ class SizedRamStringAdapter {
public:
SizedRamStringAdapter(const char* str, size_t n) : _str(str), _size(n) {}
int8_t compare(const char* other) const {
return safe_strncmp(_str, other, _size) == 0;
}
bool equals(const char* expected) const {
const char* actual = reinterpret_cast<const char*>(_str);
if (!actual || !expected) return actual == expected;
return strcmp(actual, expected) == 0;
return compare(expected) == 0;
}
bool isNull() const {

View File

@ -23,6 +23,11 @@ class StlStringAdapter {
return false;
}
int8_t compare(const char* other) const {
if (!other) return 1;
return static_cast<int8_t>(_str->compare(other));
}
bool equals(const char* expected) const {
if (!expected) return false;
return *_str == expected;

View File

@ -32,4 +32,8 @@ inline size_t slotSize(const VariantSlot* var) {
}
return n;
}
inline VariantData* slotData(VariantSlot* slot) {
return reinterpret_cast<VariantData*>(slot);
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -5,6 +5,7 @@
#pragma once
#include "../Misc/SerializedValue.hpp"
#include "../Numbers/convertNumber.hpp"
#include "../Polyfills/gsl/not_null.hpp"
#include "VariantContent.hpp"
@ -63,9 +64,7 @@ class VariantData {
const char *asString() const;
bool asBoolean() const {
return asIntegral<int>() != 0;
}
bool asBoolean() const;
CollectionData *asArray() {
return isArray() ? &_content.asCollection : 0;
@ -147,9 +146,18 @@ class VariantData {
return (_flags & COLLECTION_MASK) != 0;
}
template <typename T>
bool isInteger() const {
return type() == VALUE_IS_POSITIVE_INTEGER ||
type() == VALUE_IS_NEGATIVE_INTEGER;
switch (type()) {
case VALUE_IS_POSITIVE_INTEGER:
return canStorePositiveInteger<T>(_content.asInteger);
case VALUE_IS_NEGATIVE_INTEGER:
return canStoreNegativeInteger<T>(_content.asInteger);
default:
return false;
}
}
bool isFloat() const {
@ -169,6 +177,10 @@ class VariantData {
return type() == VALUE_IS_NULL;
}
bool isEnclosed() const {
return isCollection() || isString();
}
void remove(size_t index) {
if (isArray()) _content.asCollection.remove(index);
}
@ -225,14 +237,22 @@ class VariantData {
template <typename T>
void setSignedInteger(T value) {
if (value >= 0) {
setType(VALUE_IS_POSITIVE_INTEGER);
_content.asInteger = static_cast<UInt>(value);
setPositiveInteger(static_cast<UInt>(value));
} else {
setType(VALUE_IS_NEGATIVE_INTEGER);
_content.asInteger = ~static_cast<UInt>(value) + 1;
setNegativeInteger(~static_cast<UInt>(value) + 1);
}
}
void setPositiveInteger(UInt value) {
setType(VALUE_IS_POSITIVE_INTEGER);
_content.asInteger = value;
}
void setNegativeInteger(UInt value) {
setType(VALUE_IS_NEGATIVE_INTEGER);
_content.asInteger = value;
}
void setLinkedString(const char *value) {
if (value) {
setType(VALUE_IS_LINKED_STRING);

View File

@ -52,8 +52,9 @@ inline bool variantIsBoolean(const VariantData *var) {
return var && var->isBoolean();
}
template <typename T>
inline bool variantIsInteger(const VariantData *var) {
return var && var->isInteger();
return var && var->isInteger<T>();
}
inline bool variantIsFloat(const VariantData *var) {

View File

@ -5,6 +5,7 @@
#pragma once
#include "../Configuration.hpp"
#include "../Numbers/convertNumber.hpp"
#include "../Numbers/parseFloat.hpp"
#include "../Numbers/parseInteger.hpp"
#include "VariantRef.hpp"
@ -18,19 +19,35 @@ inline T VariantData::asIntegral() const {
switch (type()) {
case VALUE_IS_POSITIVE_INTEGER:
case VALUE_IS_BOOLEAN:
return T(_content.asInteger);
return convertPositiveInteger<T>(_content.asInteger);
case VALUE_IS_NEGATIVE_INTEGER:
return T(~_content.asInteger + 1);
return convertNegativeInteger<T>(_content.asInteger);
case VALUE_IS_LINKED_STRING:
case VALUE_IS_OWNED_STRING:
return parseInteger<T>(_content.asString);
case VALUE_IS_FLOAT:
return T(_content.asFloat);
return convertFloat<T>(_content.asFloat);
default:
return 0;
}
}
inline bool VariantData::asBoolean() const {
switch (type()) {
case VALUE_IS_POSITIVE_INTEGER:
case VALUE_IS_BOOLEAN:
case VALUE_IS_NEGATIVE_INTEGER:
return _content.asInteger != 0;
case VALUE_IS_FLOAT:
return _content.asFloat != 0;
case VALUE_IS_LINKED_STRING:
case VALUE_IS_OWNED_STRING:
return strcmp("true", _content.asString) == 0;
default:
return false;
}
}
// T = float/double
template <typename T>
inline T VariantData::asFloat() const {

View File

@ -9,8 +9,6 @@
#include "../Memory/MemoryPool.hpp"
#include "../Misc/Visitable.hpp"
#include "../Numbers/parseFloat.hpp"
#include "../Numbers/parseInteger.hpp"
#include "../Operators/VariantOperators.hpp"
#include "../Polyfills/type_traits.hpp"
#include "VariantAs.hpp"
@ -45,7 +43,7 @@ class VariantRefBase {
template <typename T>
FORCE_INLINE typename enable_if<is_integral<T>::value, bool>::type is()
const {
return variantIsInteger(_data);
return variantIsInteger<T>(_data);
}
//
// bool is<double>() const;
@ -98,6 +96,10 @@ class VariantRefBase {
return variantIsNull(_data);
}
FORCE_INLINE bool isUndefined() const {
return !_data;
}
FORCE_INLINE size_t memoryUsage() const {
return _data ? _data->memoryUsage() : 0;
}

View File

@ -0,0 +1,23 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2019
// MIT License
//
// clang-format off
#ifdef __GNUC__
#define ARDUINOJSON_PRAGMA(x) _Pragma(#x)
#define ARDUINOJSON_COMPILE_ERROR(msg) ARDUINOJSON_PRAGMA(GCC error msg)
#define ARDUINOJSON_STRINGIFY(S) #S
#define ARDUINOJSON_DEPRECATION_ERROR(X, Y) \
ARDUINOJSON_COMPILE_ERROR(ARDUINOJSON_STRINGIFY(X is a Y from ArduinoJson 5. Please see arduinojson.org/upgrade to learn how to upgrade your program to ArduinoJson version 6))
#define StaticJsonBuffer ARDUINOJSON_DEPRECATION_ERROR(StaticJsonBuffer, class)
#define DynamicJsonBuffer ARDUINOJSON_DEPRECATION_ERROR(DynamicJsonBuffer, class)
#define JsonBuffer ARDUINOJSON_DEPRECATION_ERROR(JsonBuffer, class)
#define RawJson ARDUINOJSON_DEPRECATION_ERROR(RawJson, function)
#endif

View File

@ -4,7 +4,7 @@
#pragma once
#define ARDUINOJSON_VERSION "6.9.0"
#define ARDUINOJSON_VERSION "6.11.1"
#define ARDUINOJSON_VERSION_MAJOR 6
#define ARDUINOJSON_VERSION_MINOR 9
#define ARDUINOJSON_VERSION_REVISION 0
#define ARDUINOJSON_VERSION_MINOR 11
#define ARDUINOJSON_VERSION_REVISION 1

View File

@ -24,7 +24,6 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
-Wshadow
-Wsign-promo
-Wstrict-aliasing
-Wstrict-overflow=5
-Wundef
)

View File

@ -22,7 +22,8 @@ TEST_CASE("JsonArray::operator[]") {
SECTION("long long") {
array[0] = 9223372036854775807;
REQUIRE(9223372036854775807 == array[0].as<int64_t>());
REQUIRE(true == array[0].is<int>());
REQUIRE(true == array[0].is<int64_t>());
REQUIRE(false == array[0].is<int32_t>());
REQUIRE(false == array[0].is<bool>());
}
#endif

View File

@ -3,17 +3,18 @@
# MIT License
add_executable(JsonDeserializerTests
array.cpp
array_static.cpp
DeserializationError.cpp
deserializeJsonArray.cpp
deserializeJsonArrayStatic.cpp
deserializeJsonObject.cpp
deserializeJsonObjectStatic.cpp
deserializeJsonValue.cpp
deserializeJsonString.cpp
input_types.cpp
incomplete_input.cpp
input_types.cpp
number.cpp
invalid_input.cpp
misc.cpp
nestingLimit.cpp
object.cpp
object_static.cpp
string.cpp
)
target_link_libraries(JsonDeserializerTests catch)

View File

@ -7,8 +7,9 @@
#include <catch.hpp>
TEST_CASE("Invalid JSON input") {
const char* testCases[] = {"'\\u'", "'\\u000g'", "'\\u000'",
"'\\u000G'", "'\\u000/'", "\\x1234"};
const char* testCases[] = {"'\\u'", "'\\u000g'", "'\\u000'", "'\\u000G'",
"'\\u000/'", "\\x1234", "6a9", "1,",
"2]", "3}"};
const size_t testCount = sizeof(testCases) / sizeof(testCases[0]);
DynamicJsonDocument doc(4096);

View File

@ -7,11 +7,6 @@
using namespace Catch::Matchers;
namespace my {
using ARDUINOJSON_NAMESPACE::isinf;
using ARDUINOJSON_NAMESPACE::isnan;
} // namespace my
TEST_CASE("deserializeJson(DynamicJsonDocument&)") {
DynamicJsonDocument doc(4096);
@ -48,64 +43,6 @@ TEST_CASE("deserializeJson(DynamicJsonDocument&)") {
}
}
SECTION("Integers") {
SECTION("0") {
DeserializationError err = deserializeJson(doc, "0");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<int>() == true);
REQUIRE(doc.as<int>() == 0);
REQUIRE(doc.as<std::string>() == "0"); // issue #808
}
SECTION("Negative") {
DeserializationError err = deserializeJson(doc, "-42");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<int>());
REQUIRE_FALSE(doc.is<bool>());
REQUIRE(doc.as<int>() == -42);
}
}
SECTION("Floats") {
SECTION("Double") {
DeserializationError err = deserializeJson(doc, "-1.23e+4");
REQUIRE(err == DeserializationError::Ok);
REQUIRE_FALSE(doc.is<int>());
REQUIRE(doc.is<double>());
REQUIRE(doc.as<double>() == Approx(-1.23e+4));
}
SECTION("NaN") {
DeserializationError err = deserializeJson(doc, "NaN");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<float>() == true);
REQUIRE(my::isnan(doc.as<float>()));
}
SECTION("Infinity") {
DeserializationError err = deserializeJson(doc, "Infinity");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<float>() == true);
REQUIRE(my::isinf(doc.as<float>()));
}
SECTION("+Infinity") {
DeserializationError err = deserializeJson(doc, "+Infinity");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<float>() == true);
REQUIRE(my::isinf(doc.as<float>()));
}
SECTION("-Infinity") {
DeserializationError err = deserializeJson(doc, "-Infinity");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<float>() == true);
REQUIRE(my::isinf(doc.as<float>()));
}
}
SECTION("Booleans") {
SECTION("True") {
DeserializationError err = deserializeJson(doc, "true");

View File

@ -0,0 +1,133 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2019
// MIT License
#define ARDUINOJSON_USE_LONG_LONG 0
#define ARDUINOJSON_ENABLE_NAN 1
#define ARDUINOJSON_ENABLE_INFINITY 1
#include <ArduinoJson.h>
#include <limits.h>
#include <catch.hpp>
namespace my {
using ARDUINOJSON_NAMESPACE::isinf;
using ARDUINOJSON_NAMESPACE::isnan;
} // namespace my
TEST_CASE("deserialize an integer") {
DynamicJsonDocument doc(4096);
SECTION("Integer") {
SECTION("0") {
DeserializationError err = deserializeJson(doc, "0");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<int>() == true);
REQUIRE(doc.as<int>() == 0);
REQUIRE(doc.as<std::string>() == "0"); // issue #808
}
SECTION("Negative") {
DeserializationError err = deserializeJson(doc, "-42");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<int>());
REQUIRE_FALSE(doc.is<bool>());
REQUIRE(doc.as<int>() == -42);
}
#if LONG_MAX == 2147483647
SECTION("LONG_MAX") {
DeserializationError err = deserializeJson(doc, "2147483647");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<long>() == true);
REQUIRE(doc.as<long>() == LONG_MAX);
}
SECTION("LONG_MAX + 1") {
DeserializationError err = deserializeJson(doc, "2147483648");
CAPTURE(LONG_MIN);
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<long>() == false);
REQUIRE(doc.is<float>() == true);
}
#endif
#if LONG_MIN == -2147483648
SECTION("LONG_MIN") {
DeserializationError err = deserializeJson(doc, "-2147483648");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<long>() == true);
REQUIRE(doc.as<long>() == LONG_MIN);
}
SECTION("LONG_MIN - 1") {
DeserializationError err = deserializeJson(doc, "-2147483649");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<long>() == false);
REQUIRE(doc.is<float>() == true);
}
#endif
#if ULONG_MAX == 4294967295
SECTION("ULONG_MAX") {
DeserializationError err = deserializeJson(doc, "4294967295");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<unsigned long>() == true);
REQUIRE(doc.as<unsigned long>() == ULONG_MAX);
REQUIRE(doc.is<long>() == false);
}
SECTION("ULONG_MAX + 1") {
DeserializationError err = deserializeJson(doc, "4294967296");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<unsigned long>() == false);
REQUIRE(doc.is<float>() == true);
}
#endif
}
SECTION("Floats") {
SECTION("Double") {
DeserializationError err = deserializeJson(doc, "-1.23e+4");
REQUIRE(err == DeserializationError::Ok);
REQUIRE_FALSE(doc.is<int>());
REQUIRE(doc.is<double>());
REQUIRE(doc.as<double>() == Approx(-1.23e+4));
}
SECTION("NaN") {
DeserializationError err = deserializeJson(doc, "NaN");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<float>() == true);
REQUIRE(my::isnan(doc.as<float>()));
}
SECTION("Infinity") {
DeserializationError err = deserializeJson(doc, "Infinity");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<float>() == true);
REQUIRE(my::isinf(doc.as<float>()));
}
SECTION("+Infinity") {
DeserializationError err = deserializeJson(doc, "+Infinity");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<float>() == true);
REQUIRE(my::isinf(doc.as<float>()));
}
SECTION("-Infinity") {
DeserializationError err = deserializeJson(doc, "-Infinity");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<float>() == true);
REQUIRE(my::isinf(doc.as<float>()));
}
}
}

View File

@ -0,0 +1,49 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2019
// MIT License
#include <ArduinoJson.h>
#include <stdlib.h> // malloc, free
#include <catch.hpp>
#include <sstream>
using ARDUINOJSON_NAMESPACE::addPadding;
class SpyingAllocator {
public:
SpyingAllocator(std::ostream& log) : _log(log) {}
void* allocate(size_t n) {
_log << "A" << n;
return malloc(n);
}
void deallocate(void* p) {
_log << "F";
free(p);
}
private:
SpyingAllocator& operator=(const SpyingAllocator& src);
std::ostream& _log;
};
typedef BasicJsonDocument<SpyingAllocator> MyJsonDocument;
TEST_CASE("BasicJsonDocument") {
std::stringstream log;
SECTION("Construct/Destruct") {
{ MyJsonDocument doc(4096, log); }
REQUIRE(log.str() == "A4096F");
}
SECTION("Copy construct") {
{
MyJsonDocument doc1(4096, log);
doc1.set(std::string("The size of this string is 32!!"));
MyJsonDocument doc2(doc1);
}
REQUIRE(log.str() == "A4096A32FF");
}
}

View File

@ -4,6 +4,8 @@
add_executable(JsonDocumentTests
add.cpp
BasicJsonDocument.cpp
containsKey.cpp
createNested.cpp
DynamicJsonDocument.cpp
isNull.cpp

View File

@ -0,0 +1,44 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2019
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonDocument::containsKey()") {
DynamicJsonDocument doc(4096);
SECTION("returns true on object") {
doc["hello"] = "world";
REQUIRE(doc.containsKey("hello") == true);
}
SECTION("returns true when value is null") {
doc["hello"] = static_cast<const char*>(0);
REQUIRE(doc.containsKey("hello") == true);
}
SECTION("returns true when key is a std::string") {
doc["hello"] = "world";
REQUIRE(doc.containsKey(std::string("hello")) == true);
}
SECTION("returns false on object") {
doc["world"] = "hello";
REQUIRE(doc.containsKey("hello") == false);
}
SECTION("returns false on array") {
doc.add("hello");
REQUIRE(doc.containsKey("hello") == false);
}
SECTION("returns false on null") {
REQUIRE(doc.containsKey("hello") == false);
}
}

View File

@ -161,7 +161,7 @@ TEST_CASE("JsonObject::operator[]") {
obj[null] = 666;
REQUIRE(obj.size() == 1);
REQUIRE(obj[null] == 0);
REQUIRE(obj[null] == null);
}
SECTION("obj[key].to<JsonArray>()") {

View File

@ -7,6 +7,7 @@ add_executable(JsonVariantTests
as.cpp
clear.cpp
compare.cpp
containsKey.cpp
copy.cpp
createNested.cpp
is.cpp
@ -15,6 +16,7 @@ add_executable(JsonVariantTests
misc.cpp
nesting.cpp
or.cpp
overflow.cpp
remove.cpp
set.cpp
subscript.cpp

View File

@ -6,6 +6,10 @@
#include <stdint.h>
#include <catch.hpp>
namespace my {
using ARDUINOJSON_NAMESPACE::isinf;
} // namespace my
static const char* null = 0;
TEST_CASE("JsonVariant::as()") {
@ -94,7 +98,6 @@ TEST_CASE("JsonVariant::as()") {
SECTION("set(\"42\")") {
variant.set("42");
REQUIRE(variant.as<bool>());
REQUIRE(variant.as<long>() == 42L);
}
@ -111,7 +114,6 @@ TEST_CASE("JsonVariant::as()") {
SECTION("set(std::string(\"4.2\"))") {
variant.set(std::string("4.2"));
REQUIRE(variant.as<bool>() == true);
REQUIRE(variant.as<long>() == 4L);
REQUIRE(variant.as<double>() == 4.2);
REQUIRE(variant.as<char*>() == std::string("4.2"));
@ -121,8 +123,31 @@ TEST_CASE("JsonVariant::as()") {
SECTION("set(\"true\")") {
variant.set("true");
REQUIRE(variant.as<bool>());
REQUIRE(variant.as<long>() == 1L);
REQUIRE(variant.as<bool>() == true);
REQUIRE(variant.as<int>() == 0);
}
SECTION("set(-1e300)") {
variant.set(-1e300);
REQUIRE(variant.as<double>() == -1e300);
REQUIRE(variant.as<float>() < 0);
REQUIRE(my::isinf(variant.as<float>()));
}
SECTION("set(1e300)") {
variant.set(1e300);
REQUIRE(variant.as<double>() == 1e300);
REQUIRE(variant.as<float>() > 0);
REQUIRE(my::isinf(variant.as<float>()));
}
SECTION("set(1e300)") {
variant.set(1e-300);
REQUIRE(variant.as<double>() == 1e-300);
REQUIRE(variant.as<float>() == 0);
}
SECTION("to<JsonObject>()") {

View File

@ -229,8 +229,13 @@ TEST_CASE("JsonVariant comparisons") {
}
SECTION("Variants containing linked strings") {
variant1.set("0hello" + 1); // make sure they have
variant2.set("1hello" + 1); // different addresses
// create two identical strings at different addresses
char hello1[] = "hello";
char hello2[] = "hello";
REQUIRE(hello1 != hello2);
variant1.set(hello1);
variant2.set(hello2);
variant3.set("world");
REQUIRE(variant1 == variant2);
@ -253,8 +258,13 @@ TEST_CASE("JsonVariant comparisons") {
}
SECTION("Variants containing linked raws") {
variant1.set(serialized("0hello" + 1)); // make sure they have
variant2.set(serialized("1hello" + 1)); // different addresses
// create two identical strings at different addresses
char hello1[] = "hello";
char hello2[] = "hello";
REQUIRE(hello1 != hello2);
variant1.set(serialized(hello1));
variant2.set(serialized(hello2));
variant3.set(serialized("world"));
REQUIRE(variant1 == variant2);
@ -327,23 +337,117 @@ TEST_CASE("JsonVariant comparisons") {
REQUIRE(variant1 != variant3);
REQUIRE_FALSE(variant1 == variant3);
}
// SECTION("VariantsOfDifferentTypes") {
// DynamicJsonDocument doc1(4096);
// JsonObject obj = doc1.to<JsonObject>();
// DynamicJsonDocument doc2(4096);
// JsonArray arr = doc2.to<JsonArray>();
// JsonVariant variants[] = {
// true, 42, 666.667, "hello", arr, obj,
// };
// size_t n = sizeof(variants) / sizeof(variants[0]);
// for (size_t i = 0; i < n; i++) {
// for (size_t j = i + 1; j < n; j++) {
// REQUIRE(variants[i] != variants[j]);
// REQUIRE_FALSE(variants[i] == variants[j]);
// }
// }
// }
}
class VariantComparisionFixture {
private:
StaticJsonDocument<256> doc;
JsonVariant variant;
public:
VariantComparisionFixture() : variant(doc.to<JsonVariant>()) {}
protected:
template <typename T>
void setValue(const T& value) {
variant.set(value);
}
template <typename T>
void assertEqualsTo(const T& value) {
REQUIRE(variant == value);
REQUIRE(value == variant);
REQUIRE_FALSE(variant != value);
REQUIRE_FALSE(value != variant);
}
template <typename T>
void assertDiffersFrom(const T& value) {
REQUIRE(variant != value);
REQUIRE(value != variant);
REQUIRE_FALSE(variant == value);
REQUIRE_FALSE(value == variant);
}
template <typename T>
void assertGreaterThan(const T& value) {
REQUIRE((variant > value));
REQUIRE((variant >= value));
REQUIRE(value < variant);
REQUIRE(value <= variant);
REQUIRE_FALSE((variant < value));
REQUIRE_FALSE((variant <= value));
REQUIRE_FALSE(value > variant);
REQUIRE_FALSE(value >= variant);
}
template <typename T>
void assertLowerThan(const T& value) {
REQUIRE(variant < value);
REQUIRE(variant <= value);
REQUIRE(value > variant);
REQUIRE(value >= variant);
REQUIRE_FALSE(variant > value);
REQUIRE_FALSE(variant >= value);
REQUIRE_FALSE(value < variant);
REQUIRE_FALSE(value <= variant);
}
};
TEST_CASE_METHOD(VariantComparisionFixture,
"Compare variant with another type") {
SECTION("null") {
assertDiffersFrom(3);
assertDiffersFrom("world");
}
SECTION("string") {
setValue("hello");
assertEqualsTo("hello");
assertDiffersFrom(3);
assertDiffersFrom("world");
assertGreaterThan("helln");
assertLowerThan("hellp");
}
SECTION("positive integer") {
setValue(42);
assertEqualsTo(42);
assertDiffersFrom(43);
assertGreaterThan(41);
assertLowerThan(43);
assertDiffersFrom("world");
}
SECTION("negative integer") {
setValue(-42);
assertEqualsTo(-42);
assertDiffersFrom(42);
assertGreaterThan(-43);
assertLowerThan(-41);
assertDiffersFrom("world");
}
SECTION("double") {
setValue(42.0);
assertEqualsTo(42.0);
assertDiffersFrom(42.1);
assertGreaterThan(41.0);
assertLowerThan(43.0);
assertDiffersFrom("42.0");
}
SECTION("true") {
setValue(true);
assertEqualsTo(true);
assertDiffersFrom(false);
assertDiffersFrom(1);
assertDiffersFrom("true");
assertDiffersFrom(1.0);
assertGreaterThan(false);
}
}

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