Compare commits

...

22 Commits

Author SHA1 Message Date
edfe5c6622 Set version to 5.11.0 2017-06-25 15:11:57 +02:00
2b9492317b Added Charles Haynes to the list of donators 2017-06-22 21:56:41 +02:00
5da41edf6a Removed implementation of JsonBufferAllocated::delete. 2017-06-19 10:05:38 +02:00
476e5aaa86 Added DynamicJsonBuffer::clear() 2017-06-17 16:48:40 +02:00
789fa507b5 Added StaticJsonBuffer::clear() 2017-06-17 15:00:46 +02:00
508f936317 Made JsonBuffer non-copyable (PR #524 by @luisrayas3) 2017-06-17 14:17:01 +02:00
e9d88dda8e Set version to 5.10.1 2017-06-12 21:10:02 +02:00
ecceb71a1e AppVeyor: Added Visual Studio 2017 and restored MinGW 2017-06-07 11:15:22 +02:00
bff77abe6a Fixed reading "true" as a float (issue #516) 2017-06-03 16:22:26 +02:00
98413089f6 Added Google to the list of donators 2017-06-01 20:49:50 +02:00
a2446f6c68 Fixed compilation in IAR Embedded Workbench (issue #515) 2017-06-01 20:47:09 +02:00
c955049207 Fixed IntelliSense errors in Visual Micro (issue #483) 2017-05-28 15:33:03 +02:00
574c00c096 Added links to the ArduinoJson assistant (issue #513) 2017-05-27 15:32:12 +02:00
7415f206ea Reduced code size 2017-05-27 15:08:11 +02:00
f76017a015 Set version to 5.10.0 2017-05-20 09:11:03 +02:00
cda05aec04 Removed configurable number of decimal places (issues #288, #427 and #506) 2017-05-20 09:06:53 +02:00
639286f8b6 Travis: Removed retired images 2017-05-04 22:10:43 +02:00
cc66618e70 Fixed error forming reference to reference (issue #495) 2017-05-04 21:58:28 +02:00
9efc0ec40d Travis: Added GCC 6 2017-05-02 21:32:19 +02:00
34674fc282 Fixed error IsBaseOf is not a member of ArduinoJson::TypeTraits (issue #495) 2017-05-02 21:29:45 +02:00
01c3166043 Moved testimonials to https://bblanchon.github.io/ArduinoJson/ 2017-04-29 17:54:26 +02:00
bf2e3d5669 Updated the list of supported hardware (issue #491) 2017-04-28 10:28:38 +02:00
73 changed files with 919 additions and 751 deletions

View File

@ -1,11 +1,14 @@
<!--
Thanks for using ArduinoJson :-)
Before opening an issue, please make sure you've read these:
Before opening an issue, please read the FAQ:
https://bblanchon.github.io/ArduinoJson/faq/
https://bblanchon.github.io/ArduinoJson/doc/pitfalls/
Next, make sure you provide all the relevant information: platform, code snippet, and error messages.
Please provide all the relevant information:
* good title
* short description of the problem
* target platform
* compiler model and version
* MVCE (https://stackoverflow.com/help/mcve)
* compiler output
Please be concise!
Good questions get fast answers!
-->

View File

@ -44,6 +44,12 @@ matrix:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-5']
env: SCRIPT=cmake GCC=5 SANITIZE=undefined
- compiler: gcc
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-6']
env: SCRIPT=cmake GCC=6
- compiler: clang
env: SCRIPT=cmake
- compiler: clang
@ -76,18 +82,6 @@ matrix:
osx_image: xcode6.4
compiler: clang
env: SCRIPT=cmake
- os: osx
osx_image: xcode7
compiler: clang
env: SCRIPT=cmake
- os: osx
osx_image: xcode7.1
compiler: clang
env: SCRIPT=cmake
- os: osx
osx_image: xcode7.2
compiler: clang
env: SCRIPT=cmake
- os: osx
osx_image: xcode7.3
compiler: clang

View File

@ -1,6 +1,53 @@
ArduinoJson: change log
=======================
v5.11.0
-------
* Made `JsonBuffer` non-copyable (PR #524 by @luisrayas3)
* Added `StaticJsonBuffer::clear()`
* Added `DynamicJsonBuffer::clear()`
v5.10.1
-------
* Fixed IntelliSense errors in Visual Micro (issue #483)
* Fixed compilation in IAR Embedded Workbench (issue #515)
* Fixed reading "true" as a float (issue #516)
* Added `ARDUINOJSON_DOUBLE_IS_64BITS`
* Added `ARDUINOJSON_EMBEDDED_MODE`
v5.10.0
-------
* Removed configurable number of decimal places (issues #288, #427 and #506)
* Changed exponentiation thresholds to `1e7` and `1e-5` (issues #288, #427 and #506)
* `JsonVariant::is<double>()` now returns `true` for integers
* Fixed error `IsBaseOf is not a member of ArduinoJson::TypeTraits` (issue #495)
* Fixed error `forming reference to reference` (issue #495)
### BREAKING CHANGES :warning:
| Old syntax | New syntax |
|---------------------------------|---------------------|
| `double_with_n_digits(3.14, 2)` | `3.14` |
| `float_with_n_digits(3.14, 2)` | `3.14f` |
| `obj.set("key", 3.14, 2)` | `obj["key"] = 3.14` |
| `arr.add(3.14, 2)` | `arr.add(3.14)` |
| Input | Old output | New output |
|-----------|------------|------------|
| `3.14159` | `3.14` | `3.14159` |
| `42.0` | `42.00` | `42` |
| `0.0` | `0.00` | `0` |
| Expression | Old result | New result |
|--------------------------------|------------|------------|
| `JsonVariant(42).is<int>()` | `true` | `true` |
| `JsonVariant(42).is<float>()` | `false` | `true` |
| `JsonVariant(42).is<double>()` | `false` | `true` |
v5.9.0
------
@ -53,7 +100,7 @@ v5.8.0
* Added support for `Stream` (issue #300)
* Reduced memory consumption by not duplicating spaces and comments
**BREAKING CHANGES**:
### BREAKING CHANGES :warning:
`JsonBuffer::parseObject()` and `JsonBuffer::parseArray()` have been pulled down to the derived classes `DynamicJsonBuffer` and `StaticJsonBufferBase`.
@ -71,6 +118,7 @@ void myFunction(StaticJsonBufferBase& jsonBuffer);
template<typename TJsonBuffer> void myFunction(TJsonBuffer& jsonBuffer);
```
v5.7.3
------
@ -102,7 +150,7 @@ v5.7.0
* Added example `StringExample.ino` to show where `String` can be used
* Increased default nesting limit to 50 when compiled for a computer (issue #349)
**BREAKING CHANGES**:
### BREAKING CHANGES :warning:
The non-template functions `JsonObject::get()` and `JsonArray.get()` have been removed. This means that you need to explicitely tell the type you expect in return.
@ -229,7 +277,8 @@ v5.0.7
* Made library easier to use from a CMake project: simply `add_subdirectory(ArduinoJson/src)`
* Changed `String` to be a `typedef` of `std::string` (issues #142 and #161)
**BREAKING CHANGES**:
### BREAKING CHANGES :warning:
- `JsonVariant(true).as<String>()` now returns `"true"` instead of `"1"`
- `JsonVariant(false).as<String>()` now returns `"false"` instead of `"0"`
@ -285,7 +334,8 @@ v5.0.0
* Redesigned `JsonVariant` to leverage converting constructors instead of assignment operators (issue #66)
* Switched to new the library layout (requires Arduino 1.0.6 or above)
**BREAKING CHANGES**:
### BREAKING CHANGES :warning:
- `JsonObject::add()` was renamed to `set()`
- `JsonArray::at()` and `JsonObject::at()` were renamed to `get()`
- Number of digits of floating point value are now set with `double_with_n_digits()`

View File

@ -27,14 +27,16 @@ Features
Works on
--------
* All Arduino boards (Uno, Due, Mini, Micro, Yun...)
* ESP8266
* Arduino boards: Uno, Due, Mini, Micro, Yun...
* ESP8266, ESP32
* Teensy
* Intel Edison and Galileo
* PlatformIO
* Energia
* RedBearLab boards (BLE Nano...)
* Computers (Windows, Linux, OSX...)
* Intel Edison and Galileo
* WeMos boards: D1...
* Computers: Windows, Linux, OSX...
* PlatformIO
* Particle
* Energia
Quick start
-----------
@ -56,6 +58,8 @@ double longitude = root["data"][1];
[See JsonParserExample.ino](examples/JsonParserExample/JsonParserExample.ino)
Use [ArduinoJson Assistant](https://bblanchon.github.io/ArduinoJson/assistant/) to compute the buffer size.
#### Encoding / Generating
```c++
@ -66,8 +70,8 @@ root["sensor"] = "gps";
root["time"] = 1351824120;
JsonArray& data = root.createNestedArray("data");
data.add(48.756080, 6); // 6 is the number of decimals to print
data.add(2.302038, 6); // if not specified, 2 digits are printed
data.add(48.756080);
data.add(2.302038);
root.printTo(Serial);
// This prints:
@ -76,6 +80,8 @@ root.printTo(Serial);
[See JsonGeneratorExample.ino](examples/JsonGeneratorExample/JsonGeneratorExample.ino)
Use [ArduinoJson Assistant](https://bblanchon.github.io/ArduinoJson/assistant/) to compute the buffer size.
Documentation
-------------
@ -85,33 +91,6 @@ The documentation is available online in the [ArduinoJson Website](https://bblan
The [ArduinoJson Assistant](https://bblanchon.github.io/ArduinoJson/assistant/) helps you get started with the library.
Testimonials
------------
From Arduino's Forum user `jflaplante`:
> I tried aJson json-arduino before trying your library. I always ran into memory problem after a while.
> I have no such problem so far with your library. It is working perfectly with my web services.
From StackOverflow user `thegreendroid`:
> It has a really elegant, simple API and it works like a charm on embedded and Windows/Linux platforms. We recently started using this on an embedded project and I can vouch for its quality.
From GitHub user `zacsketches`:
> Thanks for a great library!!!
> I've been watching you consistently develop this library over the past six months, and I used it today for a publish and subscribe architecture designed to help hobbyists move into more advanced robotics. Your library allowed me to implement remote subscription in order to facilitate multi-processor robots.
> ArduinoJson saved me a week's worth of time!!
[From Reddit user `erm_what_`](https://www.reddit.com/r/arduino/comments/3jj6ep/announcing_arduinojson_50/cusjk8c):
> This is a great library and I wouldn't be able to do the project I'm doing without it. I completely recommend it.
[From Reddit user `makerhacks`](https://www.reddit.com/r/arduino/comments/3jj6ep/announcing_arduinojson_50/cusqg7b):
> I am just starting an ESP8266 clock project and now I can output JSON from my server script and interpret it painlessly.
[From Twitter user `@hemalchevli`](https://twitter.com/hemalchevli/status/715788439397011456):
> ArduinoJson library should be used as a benchmark/reference for making libraries. Truly elegant.
[From GitHub user `sticilface`](https://github.com/bblanchon/ArduinoJson/issues/381#issuecomment-260203594):
> its a great lib:) and i use it in everything!
Donators
--------
@ -137,6 +116,9 @@ Special thanks to the following persons and companies who made generous donation
* Christoph Schmidt <img alt='Germany' src='https://cdnjs.cloudflare.com/ajax/libs/emojione/2.1.4/assets/svg/1f1e9-1f1ea.svg' width='18' height='18'>
* OpenEVSE LLC <img alt='USA' src='https://cdnjs.cloudflare.com/ajax/libs/emojione/2.1.4/assets/svg/1f1fa-1f1f8.svg' width='18' height='18'>
* Prokhoryatov Alexey <img alt='Russia' src='https://cdnjs.cloudflare.com/ajax/libs/emojione/2.1.4/assets/svg/1f1f7-1f1fa.svg' width='18' height='18'>
* Google Inc. <img alt='USA' src='https://cdnjs.cloudflare.com/ajax/libs/emojione/2.1.4/assets/svg/1f1fa-1f1f8.svg' width='18' height='18'>
* Charles Haynes <img alt='Australia' src='https://d1j8pt39hxlh3d.cloudfront.net/development/emojione/2.2/989/2546.svg' width='18' height='18'>
---

View File

@ -1,13 +1,15 @@
version: 5.9.0.{build}
version: 5.11.0.{build}
environment:
matrix:
- CMAKE_GENERATOR: Visual Studio 14 2015
- CMAKE_GENERATOR: Visual Studio 12 2013
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
CMAKE_GENERATOR: Visual Studio 15 2017
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
CMAKE_GENERATOR: Visual Studio 14 2015
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
CMAKE_GENERATOR: Visual Studio 12 2013
- CMAKE_GENERATOR: Visual Studio 11 2012
- CMAKE_GENERATOR: Visual Studio 10 2010
# - CMAKE_GENERATOR: MinGW Makefiles
# Note: Disabled because of unexplicated error -1073741511
# This used to work fine with GCC 4.8.2 then failed after they upgraded to GCC 4.9.3
- CMAKE_GENERATOR: MinGW Makefiles
configuration: Debug
before_build:
- set PATH=C:\MinGW\bin;%PATH:C:\Program Files\Git\usr\bin;=% # Workaround for CMake not wanting sh.exe on PATH for MinGW

View File

@ -17,13 +17,13 @@ void setup() {
//
// Inside the brackets, 200 is the size of the pool in bytes.
// If the JSON object is more complex, you need to increase that value.
// See https://bblanchon.github.io/ArduinoJson/assistant/
StaticJsonBuffer<200> jsonBuffer;
// StaticJsonBuffer allocates memory on the stack, it can be
// replaced by DynamicJsonBuffer which allocates in the heap.
// It's simpler but less efficient.
//
// DynamicJsonBuffer jsonBuffer;
// DynamicJsonBuffer jsonBuffer(200);
// Create the root of the object tree.
//
@ -44,8 +44,8 @@ void setup() {
// It's also possible to create the array separately and add it to the
// JsonObject but it's less efficient.
JsonArray& data = root.createNestedArray("data");
data.add(double_with_n_digits(48.756080, 6));
data.add(double_with_n_digits(2.302038, 6));
data.add(48.756080);
data.add(2.302038);
root.printTo(Serial);
// This prints:

View File

@ -135,7 +135,7 @@ bool skipResponseHeaders() {
// }
bool readReponseContent(struct UserData* userData) {
// Compute optimal size of the JSON buffer according to what we need to parse.
// This is only required if you use StaticJsonBuffer.
// See https://bblanchon.github.io/ArduinoJson/assistant/
const size_t BUFFER_SIZE =
JSON_OBJECT_SIZE(8) // the root object has 8 elements
+ JSON_OBJECT_SIZE(5) // the "address" object has 5 elements

View File

@ -17,13 +17,13 @@ void setup() {
//
// Inside the brackets, 200 is the size of the pool in bytes,
// If the JSON object is more complex, you need to increase that value.
// See https://bblanchon.github.io/ArduinoJson/assistant/
StaticJsonBuffer<200> jsonBuffer;
// StaticJsonBuffer allocates memory on the stack, it can be
// replaced by DynamicJsonBuffer which allocates in the heap.
// It's simpler but less efficient.
//
// DynamicJsonBuffer jsonBuffer;
// DynamicJsonBuffer jsonBuffer(200);
// JSON input string.
//

View File

@ -2,9 +2,9 @@
// Created by Benoit Blanchon.
// Heavily inspired by "Web Server" from David A. Mellis and Tom Igoe
#include <SPI.h>
#include <Ethernet.h>
#include <ArduinoJson.h>
#include <Ethernet.h>
#include <SPI.h>
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 0, 177);
@ -64,6 +64,8 @@ void loop() {
if (client) {
bool success = readRequest(client);
if (success) {
// Use https://bblanchon.github.io/ArduinoJson/assistant/ to
// compute the right size for the buffer
StaticJsonBuffer<500> jsonBuffer;
JsonObject& json = prepareResponse(jsonBuffer);
writeResponse(client, json);

View File

@ -49,6 +49,8 @@ void setup() {
void loop() {
delay(1000);
// Use https://bblanchon.github.io/ArduinoJson/assistant/ to
// compute the right size for the buffer
StaticJsonBuffer<300> jsonBuffer;
JsonObject& json = buildJson(jsonBuffer);
sendJson(json);

View File

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

View File

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

View File

@ -40,5 +40,14 @@ process()
cd $(dirname $0)/../
INCLUDED=()
process src/ArduinoJson.h true > ../ArduinoJson-$TAG.h
g++ -x c++ -c -o ../smoketest.o - <<END
#include "../ArduinoJson-$TAG.h"
int main() {}
END
INCLUDED=()
process src/ArduinoJson.hpp true > ../ArduinoJson-$TAG.hpp
process src/ArduinoJson.hpp true > ../ArduinoJson-$TAG.hpp
g++ -x c++ -c -o ../smoketest.o - <<END
#include "../ArduinoJson-$TAG.hpp"
int main() {}
END

View File

@ -7,19 +7,23 @@
#pragma once
// enable deprecated functions by default
#ifndef ARDUINOJSON_ENABLE_DEPRECATED
#define ARDUINOJSON_ENABLE_DEPRECATED 1
// Small or big machine?
#ifndef ARDUINOJSON_EMBEDDED_MODE
#if defined(ARDUINO) || defined(__IAR_SYSTEMS_ICC__)
#define ARDUINOJSON_EMBEDDED_MODE 1
#else
#define ARDUINOJSON_EMBEDDED_MODE 0
#endif
#endif
#ifdef ARDUINO // assume this is an embedded platform
#if ARDUINOJSON_EMBEDDED_MODE
// store using float instead of double to reduce the memory usage (issue #134)
// Store floats by default to reduce the memory usage (issue #134)
#ifndef ARDUINOJSON_USE_DOUBLE
#define ARDUINOJSON_USE_DOUBLE 0
#endif
// store using a long because it usually match the size of a float.
// Store longs by default, because they usually match the size of a float.
#ifndef ARDUINOJSON_USE_LONG_LONG
#define ARDUINOJSON_USE_LONG_LONG 0
#endif
@ -27,57 +31,29 @@
#define ARDUINOJSON_USE_INT64 0
#endif
// Arduino has its own implementation of String to replace std::string
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
#define ARDUINOJSON_ENABLE_ARDUINO_STRING 1
#endif
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1
#endif
// On AVR archiecture, we can use PROGMEM
#ifndef ARDUINOJSON_ENABLE_PROGMEM
#ifdef PROGMEM
#define ARDUINOJSON_ENABLE_PROGMEM 1
#else
#define ARDUINOJSON_ENABLE_PROGMEM 0
#endif
#endif
// Arduino doesn't have std::string
// Embedded systems usually don't have std::string
#ifndef ARDUINOJSON_ENABLE_STD_STRING
#define ARDUINOJSON_ENABLE_STD_STRING 0
#endif
// Arduino doesn't support STL stream
// Embedded systems usually don't have std::stream
#ifndef ARDUINOJSON_ENABLE_STD_STREAM
#define ARDUINOJSON_ENABLE_STD_STREAM 0
#endif
#ifndef ARDUINOJSON_ENABLE_ALIGNMENT
#ifdef ARDUINO_ARCH_AVR
// alignment isn't needed for 8-bit AVR
#define ARDUINOJSON_ENABLE_ALIGNMENT 0
#else
// but must processor needs pointer to be align on word size
#define ARDUINOJSON_ENABLE_ALIGNMENT 1
#endif
#endif
// low value to prevent stack overflow
// Limit nesting as the stack is likely to be small
#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT
#define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10
#endif
#else // assume this is a computer
#else // ARDUINOJSON_EMBEDDED_MODE
// on a computer we have plenty of memory so we can use doubles
// On a computer we have plenty of memory so we can use doubles
#ifndef ARDUINOJSON_USE_DOUBLE
#define ARDUINOJSON_USE_DOUBLE 1
#endif
// use long long when available
// Use long long when available
#ifndef ARDUINOJSON_USE_LONG_LONG
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)
#define ARDUINOJSON_USE_LONG_LONG 1
@ -86,7 +62,7 @@
#endif
#endif
// use _int64 on old versions of Visual Studio
// Use _int64 on old versions of Visual Studio
#ifndef ARDUINOJSON_USE_INT64
#if defined(_MSC_VER) && _MSC_VER <= 1700
#define ARDUINOJSON_USE_INT64 1
@ -95,41 +71,91 @@
#endif
#endif
// on a computer, we can use std::string
// On a computer, we can use std::string
#ifndef ARDUINOJSON_ENABLE_STD_STRING
#define ARDUINOJSON_ENABLE_STD_STRING 1
#endif
// on a computer, there is no reason to beleive Arduino String is available
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
#define ARDUINOJSON_ENABLE_ARDUINO_STRING 0
#endif
// PROGMEM is only available on AVR architecture
#ifndef ARDUINOJSON_ENABLE_PROGMEM
#define ARDUINOJSON_ENABLE_PROGMEM 0
#endif
// on a computer, we can assume that the STL is there
// On a computer, we can assume std::stream
#ifndef ARDUINOJSON_ENABLE_STD_STREAM
#define ARDUINOJSON_ENABLE_STD_STREAM 1
#endif
// on a computer, there is no reason to beleive Arduino Stream is available
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0
#endif
#ifndef ARDUINOJSON_ENABLE_ALIGNMENT
// even if not required, most cpu's are faster with aligned pointers
#define ARDUINOJSON_ENABLE_ALIGNMENT 1
#endif
// on a computer, we should have a lot of space on the stack
// On a computer, the stack is large so we can increase nesting limit
#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT
#define ARDUINOJSON_DEFAULT_NESTING_LIMIT 50
#endif
#endif // ARDUINOJSON_EMBEDDED_MODE
#ifdef ARDUINO
// Enable support for Arduino String
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
#define ARDUINOJSON_ENABLE_ARDUINO_STRING 1
#endif
// Enable support for Arduino Stream
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1
#endif
#else // ARDUINO
// Disable support for Arduino String
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
#define ARDUINOJSON_ENABLE_ARDUINO_STRING 0
#endif
// Disable support for Arduino Stream
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0
#endif
#endif // ARDUINO
#ifndef ARDUINOJSON_ENABLE_PROGMEM
#ifdef PROGMEM
#define ARDUINOJSON_ENABLE_PROGMEM 1
#else
#define ARDUINOJSON_ENABLE_PROGMEM 0
#endif
#endif
#ifndef ARDUINOJSON_ENABLE_ALIGNMENT
#ifdef ARDUINO_ARCH_AVR
// alignment isn't needed for 8-bit AVR
#define ARDUINOJSON_ENABLE_ALIGNMENT 0
#else
// but most processors need pointers to be align on word size
#define ARDUINOJSON_ENABLE_ALIGNMENT 1
#endif
#endif
// Enable deprecated functions by default
#ifndef ARDUINOJSON_ENABLE_DEPRECATED
#define ARDUINOJSON_ENABLE_DEPRECATED 1
#endif
// Control the exponentiation threshold for big numbers
// CAUTION: cannot be more that 1e9 !!!!
#ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD
#define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e7
#endif
// Control the exponentiation threshold for small numbers
#ifndef ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD
#define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5
#endif
// how many bits in a double
#ifndef ARDUINOJSON_DOUBLE_IS_64BITS
#if /*GCC*/ (defined(__SIZEOF_DOUBLE__) && __SIZEOF_DOUBLE__ < 8) || \
/*IAR*/ (defined(__DOUBLE__) && __DOUBLE__ < 64)
#define ARDUINOJSON_DOUBLE_IS_64BITS 0
#else
#define ARDUINOJSON_DOUBLE_IS_64BITS 1 // by default support 64-bit
#endif
#endif
#if ARDUINOJSON_USE_LONG_LONG && ARDUINOJSON_USE_INT64

View File

@ -19,7 +19,7 @@ class JsonBufferAllocated {
return jsonBuffer->alloc(n);
}
void operator delete(void *, JsonBuffer *)throw() {}
void operator delete(void *, JsonBuffer *)throw();
};
}
}

View File

@ -20,20 +20,11 @@ enum JsonVariantType {
JSON_UNPARSED, // JsonVariant contains an unparsed string
JSON_STRING, // JsonVariant stores a const char*
JSON_BOOLEAN, // JsonVariant stores a bool
JSON_POSITIVE_INTEGER, // JsonVariant stores an unsigned long
JSON_NEGATIVE_INTEGER, // JsonVariant stores an unsigned long that must be
// negated
JSON_POSITIVE_INTEGER, // JsonVariant stores an JsonUInt
JSON_NEGATIVE_INTEGER, // JsonVariant stores an JsonUInt that must be negated
JSON_ARRAY, // JsonVariant stores a pointer to a JsonArray
JSON_OBJECT, // JsonVariant stores a pointer to a JsonObject
// The following values are reserved for float values
// Multiple values are used for double, depending on the number of decimal
// digits that must be printed in the JSON output.
// This little trick allow to save one extra member in JsonVariant
JSON_FLOAT_0_DECIMALS
// JSON_FLOAT_1_DECIMAL
// JSON_FLOAT_2_DECIMALS
// ...
JSON_FLOAT // JsonVariant stores a JsonFloat
};
}
}

View File

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

View File

@ -0,0 +1,26 @@
// Copyright Benoit Blanchon 2014-2017
// MIT License
//
// Arduino JSON library
// https://bblanchon.github.io/ArduinoJson/
// If you like this project, please add a star!
#pragma once
namespace ArduinoJson {
namespace Internals {
// A type that cannot be copied
class NonCopyable {
protected:
NonCopyable() {}
private:
// copy constructor is private
NonCopyable(const NonCopyable&);
// copy operator is private
NonCopyable& operator=(const NonCopyable&);
};
}
}

View File

@ -22,16 +22,6 @@ class ReferenceType {
bool operator!=(const ReferenceType& other) const {
return this != &other;
}
protected:
ReferenceType() {}
private:
// copy constructor is private
ReferenceType(const ReferenceType&);
// copy operator is private
ReferenceType& operator=(const ReferenceType&);
};
}
}

View File

@ -15,22 +15,21 @@
namespace ArduinoJson {
namespace Internals {
template <typename TSource, typename Enable = void>
template <typename TSourceRef, typename Enable = void>
struct ValueSetter {
template <typename TDestination>
static bool set(JsonBuffer*, TDestination& destination,
const TSource& source) {
static bool set(JsonBuffer*, TDestination& destination, TSourceRef source) {
destination = source;
return true;
}
};
template <typename TSource>
struct ValueSetter<TSource, typename TypeTraits::EnableIf<StringTraits<
TSource>::should_duplicate>::type> {
template <typename TSourceRef>
struct ValueSetter<TSourceRef, typename TypeTraits::EnableIf<StringTraits<
TSourceRef>::should_duplicate>::type> {
template <typename TDestination>
static bool set(JsonBuffer* buffer, TDestination& destination,
const TSource& source) {
TSourceRef source) {
const char* copy = buffer->strdup(source);
if (!copy) return false;
destination = copy;
@ -38,12 +37,11 @@ struct ValueSetter<TSource, typename TypeTraits::EnableIf<StringTraits<
}
};
template <typename TSource>
struct ValueSetter<TSource, typename TypeTraits::EnableIf<!StringTraits<
TSource>::should_duplicate>::type> {
template <typename TSourceRef>
struct ValueSetter<TSourceRef, typename TypeTraits::EnableIf<!StringTraits<
TSourceRef>::should_duplicate>::type> {
template <typename TDestination>
static bool set(JsonBuffer*, TDestination& destination,
const TSource& source) {
static bool set(JsonBuffer*, TDestination& destination, TSourceRef source) {
// unsigned char* -> char*
destination = reinterpret_cast<const char*>(source);
return true;

View File

@ -20,9 +20,8 @@ inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::eat(
}
template <typename TReader, typename TWriter>
inline bool
ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseAnythingTo(
JsonVariant *destination) {
inline bool ArduinoJson::Internals::JsonParser<
TReader, TWriter>::parseAnythingTo(JsonVariant *destination) {
if (_nestingLimit == 0) return false;
_nestingLimit--;
bool success = parseAnythingToUnsafe(destination);
@ -31,9 +30,8 @@ ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseAnythingTo(
}
template <typename TReader, typename TWriter>
inline bool
ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseAnythingToUnsafe(
JsonVariant *destination) {
inline bool ArduinoJson::Internals::JsonParser<
TReader, TWriter>::parseAnythingToUnsafe(JsonVariant *destination) {
skipSpacesAndComments(_reader);
switch (_reader.current()) {

View File

@ -17,8 +17,8 @@ class StringWriter {
public:
String(TChar** ptr) : _writePtr(ptr), _startPtr(*ptr) {}
void append(TChar c) {
*(*_writePtr)++ = c;
void append(char c) {
*(*_writePtr)++ = TChar(c);
}
const char* c_str() const {

View File

@ -46,30 +46,35 @@ class DynamicJsonBufferBase
};
public:
enum { EmptyBlockSize = sizeof(EmptyBlock) };
DynamicJsonBufferBase(size_t initialSize = 256)
: _head(NULL), _nextBlockCapacity(initialSize) {}
~DynamicJsonBufferBase() {
Block* currentBlock = _head;
while (currentBlock != NULL) {
Block* nextBlock = currentBlock->next;
_allocator.deallocate(currentBlock);
currentBlock = nextBlock;
}
freeAllBlocks();
}
// Gets the number of bytes occupied in the buffer
size_t size() const {
size_t total = 0;
for (const Block* b = _head; b; b = b->next) total += b->size;
return total;
}
// Allocates the specified amount of bytes in the buffer
virtual void* alloc(size_t bytes) {
alignNextAlloc();
return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes);
}
// Resets the buffer.
// USE WITH CAUTION: this invalidates all previously allocated data
void clear() {
freeAllBlocks();
_head = 0;
}
class String {
public:
String(DynamicJsonBufferBase* parent)
@ -98,7 +103,7 @@ class DynamicJsonBufferBase
private:
DynamicJsonBufferBase* _parent;
char* _start;
int _length;
size_t _length;
};
String startString() {
@ -129,7 +134,7 @@ class DynamicJsonBufferBase
}
bool addNewBlock(size_t capacity) {
size_t bytes = sizeof(EmptyBlock) + capacity;
size_t bytes = EmptyBlockSize + capacity;
Block* block = static_cast<Block*>(_allocator.allocate(bytes));
if (block == NULL) return false;
block->capacity = capacity;
@ -139,6 +144,16 @@ class DynamicJsonBufferBase
return true;
}
void freeAllBlocks() {
Block* currentBlock = _head;
while (currentBlock != NULL) {
Block* nextBlock = currentBlock->next;
_allocator.deallocate(currentBlock);
currentBlock = nextBlock;
}
}
TAllocator _allocator;
Block* _head;
size_t _nextBlockCapacity;

View File

@ -39,13 +39,14 @@ class JsonArraySubscript;
// It can also be deserialized from a JSON string via JsonBuffer::parseArray().
class JsonArray : public Internals::JsonPrintable<JsonArray>,
public Internals::ReferenceType,
public Internals::NonCopyable,
public Internals::List<JsonVariant>,
public Internals::JsonBufferAllocated {
public:
// Create an empty JsonArray attached to the specified JsonBuffer.
// You should not call this constructor directly.
// Instead, use JsonBuffer::createArray() or JsonBuffer::parseArray().
explicit JsonArray(JsonBuffer *buffer)
explicit JsonArray(JsonBuffer *buffer) throw()
: Internals::List<JsonVariant>(buffer) {}
// Gets the value at the specified index
@ -76,8 +77,9 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
// bool add(TValue value, uint8_t decimals);
// TValue = float, double
template <typename T>
bool add(T value, uint8_t decimals) {
return add_impl<const JsonVariant &>(JsonVariant(value, decimals));
DEPRECATED("Second argument is not supported anymore")
bool add(T value, uint8_t) {
return add_impl<const JsonVariant &>(JsonVariant(value));
}
// Sets the value at specified index.

View File

@ -81,8 +81,9 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
// bool set(TValue, uint8_t decimals);
// TValue = float, double
template <typename TValue>
FORCE_INLINE bool set(const TValue& value, uint8_t decimals) {
return _array.set(_index, value, decimals);
DEPRECATED("Second argument is not supported anymore")
FORCE_INLINE bool set(const TValue& value, uint8_t) {
return _array.set(_index, value);
}
private:
@ -106,13 +107,13 @@ inline const JsonArraySubscript JsonArray::operator[](size_t index) const {
}
template <typename TImplem>
inline JsonArraySubscript JsonVariantBase<TImplem>::operator[](int index) {
inline JsonArraySubscript JsonVariantBase<TImplem>::operator[](size_t index) {
return as<JsonArray>()[index];
}
template <typename TImplem>
inline const JsonArraySubscript JsonVariantBase<TImplem>::operator[](
int index) const {
size_t index) const {
return as<JsonArray>()[index];
}

View File

@ -11,6 +11,7 @@
#include <stdint.h> // for uint8_t
#include <string.h>
#include "Data/NonCopyable.hpp"
#include "JsonVariant.hpp"
#include "TypeTraits/EnableIf.hpp"
#include "TypeTraits/IsArray.hpp"
@ -34,7 +35,7 @@ class JsonObject;
// Handle the memory management (done in derived classes) and calls the parser.
// This abstract class is implemented by StaticJsonBuffer which implements a
// fixed memory allocation.
class JsonBuffer {
class JsonBuffer : Internals::NonCopyable {
public:
// CAUTION: NO VIRTUAL DESTRUCTOR!
// If we add a virtual constructor the Arduino compiler will add malloc() and

View File

@ -38,13 +38,15 @@ class JsonBuffer;
// It can also be deserialized from a JSON string via JsonBuffer::parseObject().
class JsonObject : public Internals::JsonPrintable<JsonObject>,
public Internals::ReferenceType,
public Internals::NonCopyable,
public Internals::List<JsonPair>,
public Internals::JsonBufferAllocated {
public:
// Create an empty JsonArray attached to the specified JsonBuffer.
// You should not use this constructor directly.
// Instead, use JsonBuffer::createObject() or JsonBuffer.parseObject().
explicit JsonObject(JsonBuffer* buffer) : Internals::List<JsonPair>(buffer) {}
explicit JsonObject(JsonBuffer* buffer) throw()
: Internals::List<JsonPair>(buffer) {}
// Gets or sets the value associated with the specified key.
//
@ -134,23 +136,25 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
// TKey = const std::string&, const String&
// TValue = float, double
template <typename TValue, typename TString>
DEPRECATED("Second argument is not supported anymore")
typename TypeTraits::EnableIf<TypeTraits::IsFloatingPoint<TValue>::value &&
!TypeTraits::IsArray<TString>::value,
bool>::type
set(const TString& key, TValue value, uint8_t decimals) {
return set_impl<const TString&, const JsonVariant&>(
key, JsonVariant(value, decimals));
set(const TString& key, TValue value, uint8_t) {
return set_impl<const TString&, const JsonVariant&>(key,
JsonVariant(value));
}
//
// bool set(TKey, TValue, uint8_t decimals);
// TKey = const char*, const char[N], const FlashStringHelper*
// TValue = float, double
template <typename TValue, typename TString>
DEPRECATED("Second argument is not supported anymore")
typename TypeTraits::EnableIf<TypeTraits::IsFloatingPoint<TValue>::value,
bool>::type
set(const TString* key, TValue value, uint8_t decimals) {
return set_impl<const TString*, const JsonVariant&>(
key, JsonVariant(value, decimals));
set(const TString* key, TValue value, uint8_t) {
return set_impl<const TString*, const JsonVariant&>(key,
JsonVariant(value));
}
// Gets the value associated with the specified key.

View File

@ -93,8 +93,9 @@ class JsonObjectSubscript
// bool set(TValue, uint8_t decimals);
// TValue = float, double
template <typename TValue>
FORCE_INLINE bool set(const TValue& value, uint8_t decimals) {
return _object.set(_key, value, decimals);
DEPRECATED("Second argument is not supported anymore")
FORCE_INLINE bool set(const TValue& value, uint8_t) {
return _object.set(_key, value);
}
private:

View File

@ -52,20 +52,26 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
JsonVariant(bool value) {
using namespace Internals;
_type = JSON_BOOLEAN;
_content.asInteger = static_cast<JsonInteger>(value);
_content.asInteger = static_cast<JsonUInt>(value);
}
// Create a JsonVariant containing a floating point value.
// The second argument specifies the number of decimal digits to write in
// the JSON string.
// JsonVariant(double value, uint8_t decimals);
// JsonVariant(float value, uint8_t decimals);
// JsonVariant(double value);
// JsonVariant(float value);
template <typename T>
JsonVariant(T value, uint8_t decimals = 2,
JsonVariant(T value, typename TypeTraits::EnableIf<
TypeTraits::IsFloatingPoint<T>::value>::type * = 0) {
using namespace Internals;
_type = JSON_FLOAT;
_content.asFloat = static_cast<JsonFloat>(value);
}
template <typename T>
DEPRECATED("Second argument is not supported anymore")
JsonVariant(T value, uint8_t,
typename TypeTraits::EnableIf<
TypeTraits::IsFloatingPoint<T>::value>::type * = 0) {
using namespace Internals;
_type = static_cast<JsonVariantType>(JSON_FLOAT_0_DECIMALS + decimals);
_type = JSON_FLOAT;
_content.asFloat = static_cast<JsonFloat>(value);
}
@ -342,11 +348,13 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
Internals::JsonVariantContent _content;
};
inline JsonVariant float_with_n_digits(float value, uint8_t digits) {
return JsonVariant(value, digits);
DEPRECATED("Decimal places are ignored, use the float value instead")
inline JsonVariant float_with_n_digits(float value, uint8_t) {
return JsonVariant(value);
}
inline JsonVariant double_with_n_digits(double value, uint8_t digits) {
return JsonVariant(value, digits);
DEPRECATED("Decimal places are ignored, use the double value instead")
inline JsonVariant double_with_n_digits(double value, uint8_t) {
return JsonVariant(value);
}
}

View File

@ -78,8 +78,8 @@ class JsonVariantBase : public Internals::JsonPrintable<TImpl> {
// Mimics an array.
// Returns the element at specified index if the variant is an array.
// Returns JsonVariant::invalid() if the variant is not an array.
FORCE_INLINE const JsonArraySubscript operator[](int index) const;
FORCE_INLINE JsonArraySubscript operator[](int index);
FORCE_INLINE const JsonArraySubscript operator[](size_t index) const;
FORCE_INLINE JsonArraySubscript operator[](size_t index);
// Mimics an object.
// Returns the value associated with the specified key if the variant is

View File

@ -56,16 +56,14 @@ inline T JsonVariant::variantAsInteger() const {
return 0;
case JSON_POSITIVE_INTEGER:
case JSON_BOOLEAN:
return static_cast<T>(_content.asInteger);
return T(_content.asInteger);
case JSON_NEGATIVE_INTEGER:
return static_cast<T>(_content.asInteger * -1);
return T(~_content.asInteger + 1);
case JSON_STRING:
case JSON_UNPARSED:
if (!_content.asString) return 0;
if (!strcmp("true", _content.asString)) return 1;
return Polyfills::parseInteger<T>(_content.asString);
default:
return static_cast<T>(_content.asFloat);
return T(_content.asFloat);
}
}
@ -117,7 +115,8 @@ inline bool JsonVariant::variantIsInteger() const {
inline bool JsonVariant::variantIsFloat() const {
using namespace Internals;
return _type >= JSON_FLOAT_0_DECIMALS ||
return _type == JSON_FLOAT || _type == JSON_POSITIVE_INTEGER ||
_type == JSON_NEGATIVE_INTEGER ||
(_type == JSON_UNPARSED && Polyfills::isFloat(_content.asString));
}

View File

@ -7,11 +7,14 @@
#pragma once
#ifdef _MSC_VER
#ifdef _MSC_VER // Visual Studio
#define FORCE_INLINE __forceinline
#define NO_INLINE __declspec(noinline)
#define DEPRECATED(msg) __declspec(deprecated(msg))
#else
#elif defined(__GNUC__) // GCC or Clang
#define FORCE_INLINE __attribute__((always_inline))
#define NO_INLINE __attribute__((noinline))
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
@ -19,4 +22,11 @@
#else
#define DEPRECATED(msg) __attribute__((deprecated))
#endif
#else // Other compilers
#define FORCE_INLINE
#define NO_INLINE
#define DEPRECATED(msg)
#endif

View File

@ -19,24 +19,23 @@ inline bool isFloat(const char* s) {
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++;
bool has_dot = *s == '.';
if (has_dot) {
if (*s == '.') {
s++;
while (isdigit(*s)) s++;
}
bool has_exponent = *s == 'e' || *s == 'E';
if (has_exponent) {
if (*s == 'e' || *s == 'E') {
s++;
if (issign(*s)) s++;
if (!isdigit(*s)) return false;
while (isdigit(*s)) s++;
}
return (has_dot || has_exponent) && *s == '\0';
return *s == '\0';
}
}
}

View File

@ -7,126 +7,16 @@
#pragma once
// If Visual Studo
#if defined(_MSC_VER)
#include <float.h>
#include <limits>
namespace ArduinoJson {
namespace Polyfills {
template <typename T>
bool isNaN(T x) {
return _isnan(x) != 0;
return x != x;
}
template <typename T>
bool isInfinity(T x) {
return !_finite(x);
}
template <typename T>
T nan() {
return std::numeric_limits<T>::quiet_NaN();
}
template <typename T>
T inf() {
return std::numeric_limits<T>::infinity();
return x != 0.0 && x * 2 == x;
}
}
}
#else
#include <math.h>
// GCC warning: "conversion to 'float' from 'double' may alter its value"
#ifdef __GNUC__
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
#pragma GCC diagnostic push
#endif
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)
#pragma GCC diagnostic ignored "-Wfloat-conversion"
#else
#pragma GCC diagnostic ignored "-Wconversion"
#endif
#endif
// Workaround for libs that #undef isnan or isinf
// https://bblanchon.github.io/ArduinoJson//issues/284
#if !defined(isnan) || !defined(isinf)
namespace std {}
#endif
namespace ArduinoJson {
namespace Polyfills {
template <typename T>
bool isNaN(T x) {
// Workaround for libs that #undef isnan
// https://bblanchon.github.io/ArduinoJson//issues/284
#ifndef isnan
using namespace std;
#endif
return isnan(x);
}
#if defined(_GLIBCXX_HAVE_ISNANL) && _GLIBCXX_HAVE_ISNANL
template <>
inline bool isNaN<double>(double x) {
return isnanl(x);
}
#endif
#if defined(_GLIBCXX_HAVE_ISNANF) && _GLIBCXX_HAVE_ISNANF
template <>
inline bool isNaN<float>(float x) {
return isnanf(x);
}
#endif
template <typename T>
bool isInfinity(T x) {
// Workaround for libs that #undef isinf
// https://bblanchon.github.io/ArduinoJson//issues/284
#ifndef isinf
using namespace std;
#endif
return isinf(x);
}
#if defined(_GLIBCXX_HAVE_ISINFL) && _GLIBCXX_HAVE_ISINFL
template <>
inline bool isInfinity<double>(double x) {
return isinfl(x);
}
#endif
#if defined(_GLIBCXX_HAVE_ISINFF) && _GLIBCXX_HAVE_ISINFF
template <>
inline bool isInfinity<float>(float x) {
return isinff(x);
}
#endif
template <typename T>
T nan() {
return static_cast<T>(NAN);
}
template <typename T>
T inf() {
return static_cast<T>(INFINITY);
}
#if defined(__GNUC__)
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
#pragma GCC diagnostic pop
#endif
#endif
}
}
#endif

View File

@ -7,41 +7,97 @@
#pragma once
#include "../Configuration.hpp"
namespace ArduinoJson {
namespace Polyfills {
#ifdef ARDUINO
// on embedded platform, favor code size over speed
template <typename T>
short normalize(T& value) {
short powersOf10 = 0;
while (value && value < 1) {
powersOf10--;
value *= 10;
}
while (value > 10) {
powersOf10++;
value /= 10;
}
return powersOf10;
}
#else
// on non-embedded platform, favor speed over code size
template <typename T>
short normalize(T& value) {
if (value == 0.0) return 0;
short powersOf10 = static_cast<short>(floor(log10(value)));
value /= pow(T(10), powersOf10);
return powersOf10;
}
int16_t normalize(T& value) {
int16_t powersOf10 = 0;
if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) {
#if ARDUINOJSON_DOUBLE_IS_64BITS
if (value >= 1e256) {
value /= 1e256;
powersOf10 = int16_t(powersOf10 + 256);
}
if (value >= 1e128) {
value /= 1e128;
powersOf10 = int16_t(powersOf10 + 128);
}
if (value >= 1e64) {
value /= 1e64;
powersOf10 = int16_t(powersOf10 + 64);
}
#endif
if (value >= 1e32) {
value /= 1e32;
powersOf10 = int16_t(powersOf10 + 32);
}
if (value >= 1e16) {
value /= 1e16;
powersOf10 = int16_t(powersOf10 + 16);
}
if (value >= 1e8) {
value /= 1e8;
powersOf10 = int16_t(powersOf10 + 8);
}
if (value >= 1e4) {
value /= 1e4;
powersOf10 = int16_t(powersOf10 + 4);
}
if (value >= 1e2) {
value /= 1e2;
powersOf10 = int16_t(powersOf10 + 2);
}
if (value >= 1e1) {
value /= 1e1;
powersOf10 = int16_t(powersOf10 + 1);
}
}
if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) {
#if ARDUINOJSON_DOUBLE_IS_64BITS
if (value < 1e-255) {
value *= 1e256;
powersOf10 = int16_t(powersOf10 - 256);
}
if (value < 1e-127) {
value *= 1e128;
powersOf10 = int16_t(powersOf10 - 128);
}
if (value < 1e-63) {
value *= 1e64;
powersOf10 = int16_t(powersOf10 - 64);
}
#endif
if (value < 1e-31) {
value *= 1e32;
powersOf10 = int16_t(powersOf10 - 32);
}
if (value < 1e-15) {
value *= 1e16;
powersOf10 = int16_t(powersOf10 - 16);
}
if (value < 1e-7) {
value *= 1e8;
powersOf10 = int16_t(powersOf10 - 8);
}
if (value < 1e-3) {
value *= 1e4;
powersOf10 = int16_t(powersOf10 - 4);
}
if (value < 1e-1) {
value *= 1e2;
powersOf10 = int16_t(powersOf10 - 2);
}
if (value < 1e0) {
value *= 1e1;
powersOf10 = int16_t(powersOf10 - 1);
}
}
return powersOf10;
}
}
}

View File

@ -20,7 +20,7 @@ inline T parseFloat(const char* s) {
typedef typename traits::mantissa_type mantissa_t;
typedef typename traits::exponent_type exponent_t;
if (!s) return 0;
if (!s) return 0; // NULL
bool negative_result = false;
switch (*s) {
@ -30,6 +30,7 @@ inline T parseFloat(const char* s) {
s++;
}
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();

View File

@ -16,7 +16,9 @@ namespace ArduinoJson {
namespace Polyfills {
template <typename T>
T parseInteger(const char *s) {
if (!s) return 0;
if (!s) return 0; // NULL
if (*s == 't') return 1; // "true"
T result = 0;
bool negative_result = false;
@ -30,11 +32,11 @@ T parseInteger(const char *s) {
}
while (isdigit(*s)) {
result = static_cast<T>(result * 10 + (*s - '0'));
result = T(result * 10 + T(*s - '0'));
s++;
}
return negative_result ? static_cast<T>(result * -1) : result;
return negative_result ? T(~result + 1) : result;
}
}
}

View File

@ -69,7 +69,8 @@ template <typename Writer>
inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
const JsonVariant& variant, Writer& writer) {
switch (variant._type) {
case JSON_UNDEFINED:
case JSON_FLOAT:
writer.writeFloat(variant._content.asFloat);
return;
case JSON_ARRAY:
@ -98,9 +99,7 @@ inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
writer.writeBoolean(variant._content.asInteger != 0);
return;
default:
uint8_t decimals =
static_cast<uint8_t>(variant._type - JSON_FLOAT_0_DECIMALS);
writer.writeFloat(variant._content.asFloat, decimals);
default: // JSON_UNDEFINED
return;
}
}

View File

@ -14,6 +14,7 @@
#include "../Polyfills/attributes.hpp"
#include "../Polyfills/math.hpp"
#include "../Polyfills/normalize.hpp"
#include "../TypeTraits/FloatTraits.hpp"
namespace ArduinoJson {
namespace Internals {
@ -27,6 +28,10 @@ namespace Internals {
// indentation.
template <typename Print>
class JsonWriter {
static const uint8_t maxDecimalPlaces = sizeof(JsonFloat) >= 8 ? 9 : 6;
static const uint32_t maxDecimalPart =
sizeof(JsonFloat) >= 8 ? 1000000000 : 1000000;
public:
explicit JsonWriter(Print &sink) : _sink(sink), _length(0) {}
@ -82,7 +87,7 @@ class JsonWriter {
}
}
void writeFloat(JsonFloat value, uint8_t digits = 2) {
void writeFloat(JsonFloat value) {
if (Polyfills::isNaN(value)) return writeRaw("NaN");
if (value < 0.0) {
@ -92,36 +97,12 @@ class JsonWriter {
if (Polyfills::isInfinity(value)) return writeRaw("Infinity");
short powersOf10;
if (value > 1000 || value < 0.001) {
powersOf10 = Polyfills::normalize(value);
} else {
powersOf10 = 0;
}
uint32_t integralPart, decimalPart;
int16_t powersOf10;
splitFloat(value, integralPart, decimalPart, powersOf10);
// Round up last digit (so that print(1.999, 2) prints as "2.00")
value += getRoundingBias(digits);
// Extract the integer part of the value and print it
JsonUInt int_part = static_cast<JsonUInt>(value);
JsonFloat remainder = value - static_cast<JsonFloat>(int_part);
writeInteger(int_part);
// Print the decimal point, but only if there are digits beyond
if (digits > 0) {
writeRaw('.');
}
// Extract digits from the remainder one at a time
while (digits-- > 0) {
// Extract digit
remainder *= 10.0;
char currentDigit = char(remainder);
remainder -= static_cast<JsonFloat>(currentDigit);
// Print
writeRaw(char('0' + currentDigit));
}
writeInteger(integralPart);
if (decimalPart) writeDecimals(decimalPart, maxDecimalPlaces);
if (powersOf10 < 0) {
writeRaw("e-");
@ -134,19 +115,44 @@ class JsonWriter {
}
}
void writeInteger(JsonUInt value) {
template <typename UInt>
void writeInteger(UInt value) {
char buffer[22];
char *ptr = buffer + sizeof(buffer) - 1;
*ptr = 0;
do {
*--ptr = static_cast<char>(value % 10 + '0');
value /= 10;
*--ptr = char(value % 10 + '0');
value = UInt(value / 10);
} while (value);
writeRaw(ptr);
}
void writeDecimals(uint32_t value, int8_t width) {
// remove trailing zeros
while (value % 10 == 0 && width > 0) {
value /= 10;
width--;
}
// buffer should be big enough for all digits, the dot and the null
// terminator
char buffer[maxDecimalPlaces + 2];
char *ptr = buffer + sizeof(buffer) - 1;
// write the string in reverse order
*ptr = 0;
while (width--) {
*--ptr = char(value % 10 + '0');
value /= 10;
}
*--ptr = '.';
// and dump it in the right order
writeRaw(ptr);
}
void writeRaw(const char *s) {
_length += _sink.print(s);
}
@ -161,24 +167,28 @@ class JsonWriter {
private:
JsonWriter &operator=(const JsonWriter &); // cannot be assigned
static JsonFloat getLastDigit(uint8_t digits) {
// Designed as a compromise between code size and speed
switch (digits) {
case 0:
return 1e-0;
case 1:
return 1e-1;
case 2:
return 1e-2;
case 3:
return 1e-3;
default:
return getLastDigit(uint8_t(digits - 4)) * 1e-4;
}
}
void splitFloat(JsonFloat value, uint32_t &integralPart,
uint32_t &decimalPart, int16_t &powersOf10) {
powersOf10 = Polyfills::normalize(value);
FORCE_INLINE static JsonFloat getRoundingBias(uint8_t digits) {
return 0.5 * getLastDigit(digits);
integralPart = uint32_t(value);
JsonFloat remainder = value - JsonFloat(integralPart);
remainder *= maxDecimalPart;
decimalPart = uint32_t(remainder);
remainder = remainder - JsonFloat(decimalPart);
// rounding:
// increment by 1 if remainder >= 0.5
decimalPart += uint32_t(remainder * 2);
if (decimalPart >= maxDecimalPart) {
decimalPart = 0;
integralPart++;
if (powersOf10 && integralPart >= 10) {
powersOf10++;
integralPart = 1;
}
}
}
};
}

View File

@ -28,7 +28,7 @@ class StaticStringBuilder {
char *begin = p;
while (p < end && *s) *p++ = *s++;
*p = '\0';
return p - begin;
return size_t(p - begin);
}
private:

View File

@ -54,19 +54,29 @@ class StaticJsonBufferBase : public JsonBufferBase<StaticJsonBufferBase> {
StaticJsonBufferBase(char* buffer, size_t capa)
: _buffer(buffer), _capacity(capa), _size(0) {}
// Gets the capacity of the buffer in bytes
size_t capacity() const {
return _capacity;
}
// Gets the current usage of the buffer in bytes
size_t size() const {
return _size;
}
// Allocates the specified amount of bytes in the buffer
virtual void* alloc(size_t bytes) {
alignNextAlloc();
if (!canAlloc(bytes)) return NULL;
return doAlloc(bytes);
}
// Resets the buffer.
// USE WITH CAUTION: this invalidates all previously allocated data
void clear() {
_size = 0;
}
String startString() {
return String(this);
}

View File

@ -11,10 +11,6 @@
#include <Stream.h>
#include "../TypeTraits/EnableIf.hpp"
#include "../TypeTraits/IsBaseOf.hpp"
#include "../TypeTraits/RemoveReference.hpp"
namespace ArduinoJson {
namespace Internals {

View File

@ -7,9 +7,6 @@
#pragma once
#include "../TypeTraits/EnableIf.hpp"
#include "../TypeTraits/IsChar.hpp"
namespace ArduinoJson {
namespace Internals {
@ -26,12 +23,12 @@ struct CharPointerTraits {
++_ptr;
}
TChar current() const {
return _ptr[0];
char current() const {
return char(_ptr[0]);
}
TChar next() const {
return _ptr[1];
char next() const {
return char(_ptr[1]);
}
};

View File

@ -10,9 +10,6 @@
#if ARDUINOJSON_ENABLE_STD_STREAM
#include <istream>
#include "../TypeTraits/EnableIf.hpp"
#include "../TypeTraits/IsBaseOf.hpp"
#include "../TypeTraits/RemoveReference.hpp"
namespace ArduinoJson {
namespace Internals {

View File

@ -7,7 +7,12 @@
#pragma once
#include <string.h>
#include "../Configuration.hpp"
#include "../TypeTraits/EnableIf.hpp"
#include "../TypeTraits/IsBaseOf.hpp"
#include "../TypeTraits/IsChar.hpp"
#include "../TypeTraits/RemoveReference.hpp"
namespace ArduinoJson {
namespace Internals {

View File

@ -9,6 +9,7 @@
#include <stdint.h>
#include <stdlib.h> // for size_t
#include "../Configuration.hpp"
#include "../Polyfills/math.hpp"
namespace ArduinoJson {
@ -17,7 +18,7 @@ namespace TypeTraits {
template <typename T, size_t = sizeof(T)>
struct FloatTraits {};
#if !defined(__SIZEOF_DOUBLE__) || __SIZEOF_DOUBLE__ >= 8
#if ARDUINOJSON_DOUBLE_IS_64BITS
template <typename T>
struct FloatTraits<T, 8 /*64bits*/> {
typedef int64_t mantissa_type;
@ -35,7 +36,7 @@ struct FloatTraits<T, 8 /*64bits*/> {
(e & 8 ? 1e8 : 1) * (e & 16 ? 1e16 : 1) * (e & 32 ? 1e32 : 1) *
(e & 64 ? 1e64 : 1) * (e & 128 ? 1e128 : 1) *
(e & 256 ? 1e256 : 1);
e = -e;
e = TExponent(-e);
return m * (e & 1 ? 1e-1 : 1) * (e & 2 ? 1e-2 : 1) * (e & 4 ? 1e-4 : 1) *
(e & 8 ? 1e-8 : 1) * (e & 16 ? 1e-16 : 1) * (e & 32 ? 1e-32 : 1) *
(e & 64 ? 1e-64 : 1) * (e & 128 ? 1e-128 : 1) *
@ -43,11 +44,13 @@ struct FloatTraits<T, 8 /*64bits*/> {
}
static T nan() {
return Polyfills::nan<T>();
uint64_t x = uint64_t(0x7ff8) << 48;
return *reinterpret_cast<T*>(&x);
}
static T inf() {
return Polyfills::inf<T>();
uint64_t x = uint64_t(0x7ff0) << 48;
return *reinterpret_cast<T*>(&x);
}
};
#endif
@ -73,11 +76,13 @@ struct FloatTraits<T, 4 /*32bits*/> {
}
static T nan() {
return Polyfills::nan<T>();
uint32_t x = 0x7fc00000;
return *reinterpret_cast<T*>(&x);
}
static T inf() {
return Polyfills::inf<T>();
uint32_t x = 0x7f800000;
return *reinterpret_cast<T*>(&x);
}
};
}

View File

@ -29,6 +29,12 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
-Wstrict-overflow=5
-Wundef
)
if(NOT MINGW)
add_compile_options(
-std=c++98
)
endif()
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")

View File

@ -8,10 +8,11 @@
add_executable(DynamicJsonBufferTests
alloc.cpp
createArray.cpp
no_memory.cpp
createObject.cpp
strdup.cpp
no_memory.cpp
size.cpp
startString.cpp
strdup.cpp
)
target_link_libraries(DynamicJsonBufferTests catch)

View File

@ -7,6 +7,7 @@
#include <ArduinoJson.h>
#include <catch.hpp>
#include <sstream>
static bool isAligned(void* ptr) {
const size_t mask = sizeof(void*) - 1;
@ -14,32 +15,64 @@ static bool isAligned(void* ptr) {
return (addr & mask) == 0;
}
std::stringstream allocatorLog;
struct SpyingAllocator : DefaultAllocator {
void* allocate(size_t n) {
allocatorLog << "A" << (n - DynamicJsonBuffer::EmptyBlockSize);
return DefaultAllocator::allocate(n);
}
void deallocate(void* p) {
allocatorLog << "F";
return DefaultAllocator::deallocate(p);
}
};
TEST_CASE("DynamicJsonBuffer::alloc()") {
DynamicJsonBuffer buffer;
SECTION("InitialSizeIsZero") {
REQUIRE(0 == buffer.size());
}
SECTION("SizeIncreasesAfterAlloc") {
buffer.alloc(1);
REQUIRE(1U <= buffer.size());
buffer.alloc(1);
REQUIRE(2U <= buffer.size());
}
SECTION("ReturnDifferentPointer") {
SECTION("Returns different pointers") {
DynamicJsonBuffer buffer;
void* p1 = buffer.alloc(1);
void* p2 = buffer.alloc(2);
REQUIRE(p1 != p2);
}
SECTION("Doubles allocation size when full") {
allocatorLog.str("");
{
DynamicJsonBufferBase<SpyingAllocator> buffer(1);
buffer.alloc(1);
buffer.alloc(1);
}
REQUIRE(allocatorLog.str() == "A1A2FF");
}
SECTION("Keeps increasing allocation size after clear") {
allocatorLog.str("");
{
DynamicJsonBufferBase<SpyingAllocator> buffer(1);
buffer.alloc(1);
buffer.alloc(1);
buffer.clear();
buffer.alloc(1);
}
REQUIRE(allocatorLog.str() == "A1A2FFA4F");
}
SECTION("Makes a big allocation when needed") {
allocatorLog.str("");
{
DynamicJsonBufferBase<SpyingAllocator> buffer(1);
buffer.alloc(42);
}
REQUIRE(allocatorLog.str() == "A42F");
}
SECTION("Alignment") {
// make room for two but not three
buffer = DynamicJsonBuffer(2 * sizeof(void*) + 1);
DynamicJsonBuffer tinyBuf(2 * sizeof(void*) + 1);
REQUIRE(isAligned(buffer.alloc(1))); // this on is aligned by design
REQUIRE(isAligned(buffer.alloc(1))); // this one fits in the first block
REQUIRE(isAligned(buffer.alloc(1))); // this one requires a new block
REQUIRE(isAligned(tinyBuf.alloc(1))); // this on is aligned by design
REQUIRE(isAligned(tinyBuf.alloc(1))); // this one fits in the first block
REQUIRE(isAligned(tinyBuf.alloc(1))); // this one requires a new block
}
}

View File

@ -0,0 +1,30 @@
// Copyright Benoit Blanchon 2014-2017
// MIT License
//
// Arduino JSON library
// https://bblanchon.github.io/ArduinoJson/
// If you like this project, please add a star!
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("DynamicJsonBuffer::size()") {
DynamicJsonBuffer buffer;
SECTION("Initial size is 0") {
REQUIRE(0 == buffer.size());
}
SECTION("Increases after alloc()") {
buffer.alloc(1);
REQUIRE(1U <= buffer.size());
buffer.alloc(1);
REQUIRE(2U <= buffer.size());
}
SECTION("Goes back to 0 after clear()") {
buffer.alloc(1);
buffer.clear();
REQUIRE(0 == buffer.size());
}
}

View File

@ -87,7 +87,7 @@ TEST_CASE("Gbathree") {
REQUIRE(3 == array.size());
for (int i = 0; i < 3; i++) {
for (size_t i = 0; i < 3; i++) {
REQUIRE(50 == array[i]);
}
}
@ -112,11 +112,11 @@ TEST_CASE("Gbathree") {
REQUIRE(array.success());
REQUIRE(4 == array.size());
for (int i = 0; i < 4; i++) {
for (size_t i = 0; i < 4; i++) {
JsonArray& nestedArray = array[i];
REQUIRE(4 == nestedArray.size());
for (int j = 0; j < 4; j++) {
for (size_t j = 0; j < 4; j++) {
REQUIRE(34 == nestedArray[j]);
}
}
@ -130,7 +130,7 @@ TEST_CASE("Gbathree") {
REQUIRE(4 == array.size());
for (int i = 0; i < 4; i++) {
for (size_t i = 0; i < 4; i++) {
REQUIRE(2 == array[i]);
}
}
@ -143,7 +143,7 @@ TEST_CASE("Gbathree") {
REQUIRE(4 == array.size());
for (int i = 0; i < 4; i++) {
for (size_t i = 0; i < 4; i++) {
REQUIRE(2 == array[i]);
}
}
@ -155,12 +155,12 @@ TEST_CASE("Gbathree") {
REQUIRE(array.success());
REQUIRE(4 == array.size());
for (int i = 0; i < 4; i++) {
for (size_t i = 0; i < 4; i++) {
JsonArray& nestedArray = array[i];
REQUIRE(4 == nestedArray.size());
for (int j = 0; j < 4; j++) {
for (size_t j = 0; j < 4; j++) {
REQUIRE(15 == nestedArray[j]);
}
}
@ -173,11 +173,11 @@ TEST_CASE("Gbathree") {
REQUIRE(array.success());
REQUIRE(4 == array.size());
for (int i = 0; i < 4; i++) {
for (size_t i = 0; i < 4; i++) {
JsonArray& nestedArray = array[i];
REQUIRE(4 == nestedArray.size());
for (int j = 0; j < 4; j++) {
for (size_t j = 0; j < 4; j++) {
REQUIRE(15 == nestedArray[j]);
}
}
@ -191,7 +191,7 @@ TEST_CASE("Gbathree") {
REQUIRE(4 == array.size());
for (int i = 0; i < 4; i++) {
for (size_t i = 0; i < 4; i++) {
REQUIRE(2 == array[i]);
}
}
@ -204,7 +204,7 @@ TEST_CASE("Gbathree") {
REQUIRE(4 == array.size());
for (int i = 0; i < 4; i++) {
for (size_t i = 0; i < 4; i++) {
REQUIRE(2 == array[i]);
}
}

View File

@ -17,28 +17,28 @@ TEST_CASE("JsonArray::add()") {
REQUIRE(1U == _array.size());
}
SECTION("StoreInteger") {
SECTION("int") {
_array.add(123);
REQUIRE(123 == _array[0].as<int>());
REQUIRE(_array[0].is<int>());
REQUIRE_FALSE(_array[0].is<double>());
REQUIRE(_array[0].is<double>());
}
SECTION("StoreDouble") {
SECTION("double") {
_array.add(123.45);
REQUIRE(123.45 == _array[0].as<double>());
REQUIRE(_array[0].is<double>());
REQUIRE_FALSE(_array[0].is<int>());
REQUIRE_FALSE(_array[0].is<bool>());
}
SECTION("StoreBoolean") {
SECTION("bool") {
_array.add(true);
REQUIRE(true == _array[0].as<bool>());
REQUIRE(_array[0].is<bool>());
REQUIRE_FALSE(_array[0].is<int>());
}
SECTION("StoreString") {
SECTION("const char*") {
const char* str = "hello";
_array.add(str);
REQUIRE(str == _array[0].as<const char*>());
@ -46,7 +46,7 @@ TEST_CASE("JsonArray::add()") {
REQUIRE_FALSE(_array[0].is<int>());
}
SECTION("StoreNestedArray") {
SECTION("nested array") {
JsonArray& arr = _jsonBuffer.createArray();
_array.add(arr);
@ -56,7 +56,7 @@ TEST_CASE("JsonArray::add()") {
REQUIRE_FALSE(_array[0].is<int>());
}
SECTION("StoreNestedObject") {
SECTION("nested object") {
JsonObject& obj = _jsonBuffer.createObject();
_array.add(obj);
@ -66,7 +66,7 @@ TEST_CASE("JsonArray::add()") {
REQUIRE_FALSE(_array[0].is<int>());
}
SECTION("StoreArraySubscript") {
SECTION("array subscript") {
const char* str = "hello";
JsonArray& arr = _jsonBuffer.createArray();
arr.add(str);
@ -76,7 +76,7 @@ TEST_CASE("JsonArray::add()") {
REQUIRE(str == _array[0]);
}
SECTION("StoreObjectSubscript") {
SECTION("object subscript") {
const char* str = "hello";
JsonObject& obj = _jsonBuffer.createObject();
obj["x"] = str;

View File

@ -52,29 +52,9 @@ TEST_CASE("JsonArray::printTo()") {
check(array, "[\"hello\",\"world\"]");
}
SECTION("OneDoubleDefaultDigits") {
array.add(3.14159265358979323846);
check(array, "[3.14]");
}
SECTION("OneDoubleFourDigits") {
array.add(3.14159265358979323846, 4);
check(array, "[3.1416]");
}
SECTION("OneDoubleFourDigits_AlternativeSyntax") {
array.add(double_with_n_digits(3.14159265358979323846, 4));
check(array, "[3.1416]");
}
SECTION("OneFloatDefaultDigits") {
array.add(3.14159f);
check(array, "[3.14]");
}
SECTION("OneFloatFourDigits") {
array.add(3.14159f, 4);
check(array, "[3.1416]");
SECTION("One double") {
array.add(3.1415927);
check(array, "[3.1415927]");
}
SECTION("OneInteger") {

View File

@ -20,35 +20,35 @@ TEST_CASE("JsonArray::set()") {
REQUIRE(1U == _array.size());
}
SECTION("StoreInteger") {
SECTION("int") {
_array.set(0, 123);
REQUIRE(123 == _array[0].as<int>());
REQUIRE(_array[0].is<int>());
REQUIRE_FALSE(_array[0].is<double>());
REQUIRE_FALSE(_array[0].is<bool>());
}
SECTION("StoreDouble") {
SECTION("double") {
_array.set(0, 123.45);
REQUIRE(123.45 == _array[0].as<double>());
REQUIRE(_array[0].is<double>());
REQUIRE_FALSE(_array[0].is<int>());
}
SECTION("StoreBoolean") {
SECTION("bool") {
_array.set(0, true);
REQUIRE(true == _array[0].as<bool>());
REQUIRE(_array[0].is<bool>());
REQUIRE_FALSE(_array[0].is<int>());
}
SECTION("StoreString") {
SECTION("const char*") {
_array.set(0, "hello");
REQUIRE_THAT(_array[0].as<const char*>(), Equals("hello"));
REQUIRE(_array[0].is<const char*>());
REQUIRE_FALSE(_array[0].is<int>());
}
SECTION("StoreNestedArray") {
SECTION("nested array") {
JsonArray& arr = _jsonBuffer.createArray();
_array.set(0, arr);
@ -58,7 +58,7 @@ TEST_CASE("JsonArray::set()") {
REQUIRE_FALSE(_array[0].is<int>());
}
SECTION("StoreNestedObject") {
SECTION("nested object") {
JsonObject& obj = _jsonBuffer.createObject();
_array.set(0, obj);
@ -68,7 +68,7 @@ TEST_CASE("JsonArray::set()") {
REQUIRE_FALSE(_array[0].is<int>());
}
SECTION("StoreArraySubscript") {
SECTION("array subscript") {
JsonArray& arr = _jsonBuffer.createArray();
arr.add("hello");
@ -77,7 +77,7 @@ TEST_CASE("JsonArray::set()") {
REQUIRE_THAT(_array[0].as<char*>(), Equals("hello"));
}
SECTION("StoreObjectSubscript") {
SECTION("object subscript") {
JsonObject& obj = _jsonBuffer.createObject();
obj["x"] = "hello";

View File

@ -19,44 +19,37 @@ TEST_CASE("JsonArray::operator[]") {
REQUIRE(1U == _array.size());
}
SECTION("StoreInteger") {
SECTION("int") {
_array[0] = 123;
REQUIRE(123 == _array[0].as<int>());
REQUIRE(true == _array[0].is<int>());
REQUIRE(false == _array[0].is<double>());
REQUIRE(false == _array[0].is<bool>());
}
#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
SECTION("StoreLongLong") {
SECTION("long long") {
_array[0] = 9223372036854775807;
REQUIRE(9223372036854775807 == _array[0].as<long long>());
REQUIRE(true == _array[0].is<int>());
REQUIRE(false == _array[0].is<double>());
REQUIRE(false == _array[0].is<bool>());
}
#endif
SECTION("StoreDouble") {
SECTION("double") {
_array[0] = 123.45;
REQUIRE(123.45 == _array[0].as<double>());
REQUIRE(true == _array[0].is<double>());
REQUIRE(false == _array[0].is<int>());
}
SECTION("StoreDoubleWithDecimals") {
_array[0].set(123.45, 2);
REQUIRE(123.45 == _array[0].as<double>());
REQUIRE(true == _array[0].is<double>());
REQUIRE(false == _array[0].is<int>());
}
SECTION("StoreBoolean") {
SECTION("bool") {
_array[0] = true;
REQUIRE(true == _array[0].as<bool>());
REQUIRE(true == _array[0].is<bool>());
REQUIRE(false == _array[0].is<int>());
}
SECTION("StoreString") {
SECTION("const char*") {
const char* str = "hello";
_array[0] = str;
@ -66,7 +59,7 @@ TEST_CASE("JsonArray::operator[]") {
REQUIRE(false == _array[0].is<int>());
}
SECTION("StoreNestedArray") {
SECTION("nested array") {
JsonArray& arr = _jsonBuffer.createArray();
_array[0] = arr;
@ -79,7 +72,7 @@ TEST_CASE("JsonArray::operator[]") {
REQUIRE(false == _array[0].is<int>());
}
SECTION("StoreNestedObject") {
SECTION("nested object") {
JsonObject& obj = _jsonBuffer.createObject();
_array[0] = obj;
@ -92,7 +85,7 @@ TEST_CASE("JsonArray::operator[]") {
REQUIRE(false == _array[0].is<int>());
}
SECTION("StoreArraySubscript") {
SECTION("array subscript") {
JsonArray& arr = _jsonBuffer.createArray();
const char* str = "hello";
@ -103,7 +96,7 @@ TEST_CASE("JsonArray::operator[]") {
REQUIRE(str == _array[0]);
}
SECTION("StoreObjectSubscript") {
SECTION("object subscript") {
JsonObject& obj = _jsonBuffer.createObject();
const char* str = "hello";

View File

@ -29,7 +29,7 @@ TEST_CASE("JsonBuffer::parse()") {
JsonVariant variant = jb.parse("-42");
REQUIRE(variant.success());
REQUIRE(variant.is<int>());
REQUIRE_FALSE(variant.is<double>());
REQUIRE_FALSE(variant.is<bool>());
REQUIRE(variant == -42);
}

View File

@ -76,17 +76,10 @@ TEST_CASE("JsonObject::printTo()") {
check(obj, "{\"a\":[1,2],\"b\":[4,5]}");
}
SECTION("TwoDoublesFourDigits") {
obj["a"] = double_with_n_digits(3.14159265358979323846, 4);
obj.set("b", 2.71828182845904523536, 4);
obj.set("c", double_with_n_digits(3.14159265358979323846, 3));
check(obj, "{\"a\":3.1416,\"b\":2.7183,\"c\":3.142}");
}
SECTION("TwoDoubleDefaultDigits") {
obj["a"] = 3.14159265358979323846;
obj.set("b", 2.71828182845904523536);
check(obj, "{\"a\":3.14,\"b\":2.72}");
SECTION("Two doubles") {
obj["a"] = 12.34;
obj.set("b", 56.78);
check(obj, "{\"a\":12.34,\"b\":56.78}");
}
SECTION("TwoNull") {

View File

@ -24,31 +24,23 @@ TEST_CASE("JsonObject::set()") {
REQUIRE(1 == _object.size());
}
SECTION("StoreInteger") {
SECTION("int") {
_object.set("hello", 123);
REQUIRE(123 == _object["hello"].as<int>());
REQUIRE(_object["hello"].is<int>());
REQUIRE_FALSE(_object["hello"].is<double>());
REQUIRE_FALSE(_object["hello"].is<bool>());
}
SECTION("StoreDouble") {
SECTION("double") {
_object.set("hello", 123.45);
REQUIRE(123.45 == _object["hello"].as<double>());
REQUIRE(_object["hello"].is<double>());
REQUIRE_FALSE(_object["hello"].is<long>());
REQUIRE_FALSE(_object["hello"].is<bool>());
}
SECTION("StoreDoubleWithDigits") {
_object.set("hello", 123.45, 2);
REQUIRE(123.45 == _object["hello"].as<double>());
REQUIRE(_object["hello"].is<double>());
REQUIRE_FALSE(_object["hello"].is<long>());
}
SECTION("StoreBoolean") {
SECTION("bool") {
_object.set("hello", true);
REQUIRE(_object["hello"].as<bool>());
@ -56,7 +48,7 @@ TEST_CASE("JsonObject::set()") {
REQUIRE_FALSE(_object["hello"].is<long>());
}
SECTION("StoreString") {
SECTION("const char*") {
_object.set("hello", "h3110");
REQUIRE(std::string("h3110") == _object["hello"].as<const char*>());
@ -64,7 +56,7 @@ TEST_CASE("JsonObject::set()") {
REQUIRE_FALSE(_object["hello"].is<long>());
}
SECTION("StoreArray") {
SECTION("nested array") {
JsonArray& arr = jb.createArray();
_object.set("hello", arr);
@ -74,7 +66,7 @@ TEST_CASE("JsonObject::set()") {
REQUIRE_FALSE(_object["hello"].is<JsonObject&>());
}
SECTION("StoreObject") {
SECTION("nested object") {
JsonObject& obj = jb.createObject();
_object.set("hello", obj);
@ -84,7 +76,7 @@ TEST_CASE("JsonObject::set()") {
REQUIRE_FALSE(_object["hello"].is<JsonArray&>());
}
SECTION("StoreArraySubscript") {
SECTION("array subscript") {
JsonArray& arr = jb.createArray();
arr.add(42);
@ -93,7 +85,7 @@ TEST_CASE("JsonObject::set()") {
REQUIRE(42 == _object["a"]);
}
SECTION("StoreObjectSubscript") {
SECTION("object subscript") {
JsonObject& obj = jb.createObject();
obj.set("x", 42);

View File

@ -23,24 +23,24 @@ TEST_CASE("JsonObject::operator[]") {
REQUIRE(1 == _object.size());
}
SECTION("StoreInteger") {
SECTION("int") {
_object["hello"] = 123;
REQUIRE(123 == _object["hello"].as<int>());
REQUIRE(true == _object["hello"].is<int>());
REQUIRE(false == _object["hello"].is<double>());
REQUIRE(false == _object["hello"].is<bool>());
}
SECTION("StoreVolatileInteger") { // issue #415
SECTION("volatile int") { // issue #415
volatile int i = 123;
_object["hello"] = i;
REQUIRE(123 == _object["hello"].as<int>());
REQUIRE(true == _object["hello"].is<int>());
REQUIRE(false == _object["hello"].is<double>());
REQUIRE(false == _object["hello"].is<bool>());
}
SECTION("StoreDouble") {
SECTION("double") {
_object["hello"] = 123.45;
REQUIRE(true == _object["hello"].is<double>());
@ -48,15 +48,7 @@ TEST_CASE("JsonObject::operator[]") {
REQUIRE(123.45 == _object["hello"].as<double>());
}
SECTION("StoreDoubleWithDigits") {
_object["hello"].set(123.45, 2);
REQUIRE(true == _object["hello"].is<double>());
REQUIRE(false == _object["hello"].is<long>());
REQUIRE(123.45 == _object["hello"].as<double>());
}
SECTION("StoreBoolean") {
SECTION("bool") {
_object["hello"] = true;
REQUIRE(true == _object["hello"].is<bool>());
@ -64,7 +56,7 @@ TEST_CASE("JsonObject::operator[]") {
REQUIRE(true == _object["hello"].as<bool>());
}
SECTION("StoreString") {
SECTION("const char*") {
_object["hello"] = "h3110";
REQUIRE(true == _object["hello"].is<const char*>());
@ -74,7 +66,7 @@ TEST_CASE("JsonObject::operator[]") {
_object["hello"].as<char*>()); // <- short hand
}
SECTION("StoreArray") {
SECTION("array") {
JsonArray& arr = _jsonBuffer.createArray();
_object["hello"] = arr;
@ -90,7 +82,7 @@ TEST_CASE("JsonObject::operator[]") {
REQUIRE(false == _object["hello"].is<JsonObject&>());
}
SECTION("StoreObject") {
SECTION("object") {
JsonObject& obj = _jsonBuffer.createObject();
_object["hello"] = obj;
@ -106,7 +98,7 @@ TEST_CASE("JsonObject::operator[]") {
REQUIRE(false == _object["hello"].is<JsonArray&>());
}
SECTION("StoreArraySubscript") {
SECTION("array subscript") {
JsonArray& arr = _jsonBuffer.createArray();
arr.add(42);
@ -115,7 +107,7 @@ TEST_CASE("JsonObject::operator[]") {
REQUIRE(42 == _object["a"]);
}
SECTION("StoreObjectSubscript") {
SECTION("object subscript") {
JsonObject& obj = _jsonBuffer.createObject();
obj.set("x", 42);

View File

@ -24,7 +24,7 @@ TEST_CASE("JsonVariant::as()") {
SECTION("DoubleAsString") {
JsonVariant variant = 4.2;
REQUIRE(std::string("4.20") == variant.as<std::string>());
REQUIRE(std::string("4.2") == variant.as<std::string>());
}
SECTION("DoubleAsLong") {

View File

@ -50,10 +50,10 @@ void checkIsFloat(JsonVariant var) {
void checkIsInteger(JsonVariant var) {
REQUIRE(var.is<long>());
REQUIRE(var.is<int>());
REQUIRE(var.is<float>());
REQUIRE(var.is<double>());
REQUIRE_FALSE(var.is<bool>());
REQUIRE_FALSE(var.is<double>());
REQUIRE_FALSE(var.is<float>());
REQUIRE_FALSE(var.is<const char*>());
REQUIRE_FALSE(var.is<JsonArray>());
REQUIRE_FALSE(var.is<JsonObject>());

View File

@ -29,48 +29,8 @@ TEST_CASE("JsonVariant::printTo()") {
check("hello", "\"hello\"");
}
SECTION("DoubleZero") {
check(0.0, "0.00");
}
SECTION("DoubleDefaultDigits") {
check(3.14159265358979323846, "3.14");
}
SECTION("DoubleFourDigits") {
check(JsonVariant(3.14159265358979323846, 4), "3.1416");
}
SECTION("Infinity") {
check(std::numeric_limits<double>::infinity(), "Infinity");
}
SECTION("MinusInfinity") {
check(-std::numeric_limits<double>::infinity(), "-Infinity");
}
SECTION("SignalingNaN") {
check(std::numeric_limits<double>::signaling_NaN(), "NaN");
}
SECTION("QuietNaN") {
check(std::numeric_limits<double>::quiet_NaN(), "NaN");
}
SECTION("VeryBigPositiveDouble") {
check(JsonVariant(3.14159265358979323846e42, 4), "3.1416e42");
}
SECTION("VeryBigNegativeDouble") {
check(JsonVariant(-3.14159265358979323846e42, 4), "-3.1416e42");
}
SECTION("VerySmallPositiveDouble") {
check(JsonVariant(3.14159265358979323846e-42, 4), "3.1416e-42");
}
SECTION("VerySmallNegativeDouble") {
check(JsonVariant(-3.14159265358979323846e-42, 4), "-3.1416e-42");
SECTION("Double") {
check(3.1415927, "3.1415927");
}
SECTION("Integer") {
@ -103,7 +63,7 @@ TEST_CASE("JsonVariant::printTo()") {
}
SECTION("UInt64") {
check(18446744073709551615, "18446744073709551615");
check(18446744073709551615U, "18446744073709551615");
}
#endif
}

View File

@ -23,7 +23,7 @@ TEST_CASE("JsonVariant::operator[]") {
REQUIRE(std::string("element at index 1") == var[1]);
REQUIRE(std::string("element at index 0") ==
var[static_cast<unsigned char>(0)]); // issue #381
REQUIRE_FALSE(var[-1].success());
REQUIRE_FALSE(var[666].success());
REQUIRE_FALSE(var[3].success());
REQUIRE_FALSE(var["0"].success());
}

View File

@ -9,82 +9,97 @@
#include <limits>
#include <string>
#include <ArduinoJson/Serialization/DynamicStringBuilder.hpp>
#include <ArduinoJson/Serialization/JsonWriter.hpp>
#include <ArduinoJson/Serialization/StaticStringBuilder.hpp>
using namespace ArduinoJson::Internals;
void check(const std::string& expected, double input, uint8_t digits = 2) {
char output[1024];
StaticStringBuilder sb(output, sizeof(output));
JsonWriter<StaticStringBuilder> writer(sb);
writer.writeFloat(input, digits);
REQUIRE(output == expected);
REQUIRE(writer.bytesWritten() == expected.size());
void check(double input, const std::string& expected) {
std::string output;
DynamicStringBuilder<std::string> sb(output);
JsonWriter<DynamicStringBuilder<std::string> > writer(sb);
writer.writeFloat(input);
REQUIRE(writer.bytesWritten() == output.size());
CHECK(expected == output);
}
TEST_CASE("JsonWriter::writeFloat()") {
SECTION("NaN") {
check("NaN", std::numeric_limits<double>::signaling_NaN());
SECTION("Pi") {
check(3.14159265359, "3.141592654");
}
SECTION("PositiveInfinity") {
check("Infinity", std::numeric_limits<double>::infinity());
SECTION("Signaling NaN") {
double nan = std::numeric_limits<double>::signaling_NaN();
check(nan, "NaN");
}
SECTION("NegativeInfinity") {
check("-Infinity", -std::numeric_limits<double>::infinity());
SECTION("Quiet NaN") {
double nan = std::numeric_limits<double>::quiet_NaN();
check(nan, "NaN");
}
SECTION("Infinity") {
double inf = std::numeric_limits<double>::infinity();
check(inf, "Infinity");
check(-inf, "-Infinity");
}
SECTION("Zero") {
check("0.00", 0);
check(0.0, "0");
check(-0.0, "0");
}
SECTION("ZeroDigits_Rounding") {
check("10", 9.5, 0);
SECTION("Espilon") {
check(2.2250738585072014E-308, "2.225073859e-308");
check(-2.2250738585072014E-308, "-2.225073859e-308");
}
SECTION("ZeroDigits_NoRounding") {
check("9", 9.4, 0);
SECTION("Max double") {
check(1.7976931348623157E+308, "1.797693135e308");
check(-1.7976931348623157E+308, "-1.797693135e308");
}
SECTION("OneDigit_Rounding") {
check("10.0", 9.95, 1);
SECTION("Big exponent") {
// this test increases coverage of normalize()
check(1e255, "1e255");
check(1e-255, "1e-255");
}
SECTION("OneDigit_NoRounding") {
check("9.9", 9.94, 1);
SECTION("Exponentation when <= 1e-5") {
check(1e-4, "0.0001");
check(1e-5, "1e-5");
check(-1e-4, "-0.0001");
check(-1e-5, "-1e-5");
}
SECTION("TwoDigits_Rounding") {
check("10.00", 9.995, 2);
SECTION("Exponentation when >= 1e7") {
check(9999999.999, "9999999.999");
check(10000000, "1e7");
check(-9999999.999, "-9999999.999");
check(-10000000, "-1e7");
}
SECTION("TwoDigits_NoRounding") {
check("9.99", 9.994, 2);
SECTION("Rounding when too many decimals") {
check(0.000099999999999, "0.0001");
check(0.0000099999999999, "1e-5");
check(0.9999999996, "1");
}
SECTION("ThreeDigits_Rounding") {
check("10.000", 9.9995, 3);
SECTION("9 decimal places") {
check(0.100000001, "0.100000001");
check(0.999999999, "0.999999999");
check(9.000000001, "9.000000001");
check(9.999999999, "9.999999999");
}
SECTION("ThreeDigits_NoRounding") {
check("9.999", 9.9994, 3);
}
SECTION("10 decimal places") {
check(0.1000000001, "0.1");
check(0.9999999999, "1");
SECTION("FourDigits_Rounding") {
check("10.0000", 9.99995, 4);
}
SECTION("FourDigits_NoRounding") {
check("9.9999", 9.99994, 4);
}
SECTION("FiveDigits_Rounding") {
check("10.00000", 9.999995, 5);
}
SECTION("FiveDigits_NoRounding") {
check("9.99999", 9.999994, 5);
check(9.0000000001, "9");
check(9.9999999999, "10");
}
}

View File

@ -19,14 +19,14 @@
#endif
TEST_CASE("Deprecated functions") {
DynamicJsonBuffer jsonBuffer;
SECTION("JsonVariant::asArray()") {
DynamicJsonBuffer jsonBuffer;
JsonVariant variant = jsonBuffer.createArray();
REQUIRE(variant.asArray().success());
}
SECTION("JsonVariant::asObject()") {
DynamicJsonBuffer jsonBuffer;
JsonVariant variant = jsonBuffer.createObject();
REQUIRE(variant.asObject().success());
}
@ -37,8 +37,73 @@ TEST_CASE("Deprecated functions") {
}
SECTION("JsonArray::removeAt()") {
DynamicJsonBuffer jsonBuffer;
JsonArray& arr = jsonBuffer.createArray();
arr.removeAt(0);
}
SECTION("JsonVariant::JsonVariant(float, uint8_t)") {
JsonVariant variant(3.14f, 2);
REQUIRE(variant == 3.14f);
}
SECTION("JsonVariant::JsonVariant(double, uint8_t)") {
JsonVariant variant(3.14, 2);
REQUIRE(variant == 3.14);
}
SECTION("float_with_n_digits()") {
JsonVariant variant = float_with_n_digits(3.14f, 4);
REQUIRE(variant == 3.14f);
}
SECTION("double_with_n_digits()") {
JsonVariant variant = double_with_n_digits(3.14f, 4);
REQUIRE(variant == 3.14f);
}
SECTION("JsonArraySubscript::set(double, uint8_t)") {
JsonArray& arr = jsonBuffer.createArray();
arr.add(666);
arr[0].set(123.45, 2);
REQUIRE(123.45 == arr[0].as<double>());
REQUIRE(true == arr[0].is<double>());
REQUIRE(false == arr[0].is<int>());
}
SECTION("JsonArray::add(double, uint8_t)") {
JsonArray& arr = jsonBuffer.createArray();
arr.add(3.14159265358979323846, 4);
}
SECTION("JsonArray::add(float, uint8_t)") {
JsonArray& arr = jsonBuffer.createArray();
arr.add(3.14159265358979323846f, 4);
}
SECTION("JsonObject::set(unsigned char[], double, uint8_t)") {
unsigned char key[] = "hello";
JsonObject& obj = jsonBuffer.createObject();
obj.set(key, 3.14, 2);
REQUIRE(3.14 == obj["hello"]);
}
SECTION("JsonObject::set(const char*, double, uint8_t)") {
JsonObject& obj = jsonBuffer.createObject();
obj.set("hello", 123.45, 2);
REQUIRE(123.45 == obj["hello"].as<double>());
REQUIRE(obj["hello"].is<double>());
REQUIRE_FALSE(obj["hello"].is<long>());
}
SECTION("JsonObjectSubscript::set(double, uint8_t)") {
JsonObject& obj = jsonBuffer.createObject();
obj["hello"].set(123.45, 2);
REQUIRE(true == obj["hello"].is<double>());
REQUIRE(false == obj["hello"].is<long>());
REQUIRE(123.45 == obj["hello"].as<double>());
}
}

View File

@ -166,16 +166,6 @@ TEST_CASE("unsigned char string") {
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("JsonObject::set() key with decimals") {
unsigned char key[] = "hello";
DynamicJsonBuffer jsonBuffer;
JsonObject& obj = jsonBuffer.createObject();
obj.set(key, 3.14, 2);
REQUIRE(3.14 == obj["hello"]);
}
SECTION("JsonObject::set key&value") {
unsigned char key[] = "world";

View File

@ -214,18 +214,6 @@ TEST_CASE("Variable Length Array") {
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("JsonObject_Set_Key_WithDecimals") {
int i = 16;
char vla[i];
strcpy(vla, "hello");
DynamicJsonBuffer jsonBuffer;
JsonObject& obj = jsonBuffer.createObject();
obj.set(vla, 3.14, 2);
REQUIRE(3.14 == obj["hello"]);
}
SECTION("JsonObject_Set_KeyAndValue") {
int i = 16;
char vla[i];

View File

@ -40,9 +40,9 @@ TEST_CASE("isFloat()") {
}
SECTION("Integer") {
REQUIRE_FALSE(isFloat("14"));
REQUIRE_FALSE(isFloat("-14"));
REQUIRE_FALSE(isFloat("+14"));
REQUIRE(isFloat("14"));
REQUIRE(isFloat("-14"));
REQUIRE(isFloat("+14"));
}
SECTION("ExponentMissing") {

View File

@ -101,6 +101,11 @@ TEST_CASE("parseFloat<float>()") {
checkInf<float>("+inf", false);
checkInf<float>("-inf", true);
}
SECTION("Boolean") {
check<float>("false", 0.0f);
check<float>("true", 1.0f);
}
}
TEST_CASE("parseFloat<double>()") {
@ -167,4 +172,9 @@ TEST_CASE("parseFloat<double>()") {
checkNaN<double>("NaN");
checkNaN<double>("nan");
}
SECTION("Boolean") {
check<double>("false", 0.0);
check<double>("true", 1.0);
}
}

View File

@ -23,11 +23,12 @@ TEST_CASE("parseInteger<int8_t>()") {
check<int8_t>("127", 127);
check<int8_t>("+127", 127);
check<int8_t>("3.14", 3);
// check<int8_t>(" 42", 0);
check<int8_t>("x42", 0);
check<int8_t>("128", -128);
check<int8_t>("-129", 127);
check<int8_t>(NULL, 0);
check<int8_t>("true", 1);
check<int8_t>("false", 0);
}
TEST_CASE("parseInteger<int16_t>()") {
@ -35,11 +36,12 @@ TEST_CASE("parseInteger<int16_t>()") {
check<int16_t>("32767", 32767);
check<int16_t>("+32767", 32767);
check<int16_t>("3.14", 3);
// check<int16_t>(" 42", 0);
check<int16_t>("x42", 0);
check<int16_t>("-32769", 32767);
check<int16_t>("32768", -32768);
check<int16_t>(NULL, 0);
check<int16_t>("true", 1);
check<int16_t>("false", 0);
}
TEST_CASE("parseInteger<int32_t>()") {
@ -47,10 +49,11 @@ TEST_CASE("parseInteger<int32_t>()") {
check<int32_t>("2147483647", 2147483647);
check<int32_t>("+2147483647", 2147483647);
check<int32_t>("3.14", 3);
// check<int32_t>(" 42", 0);
check<int32_t>("x42", 0);
check<int32_t>("-2147483649", 2147483647);
check<int32_t>("2147483648", (-2147483647 - 1));
check<int32_t>("true", 1);
check<int32_t>("false", 0);
}
TEST_CASE("parseInteger<uint8_t>()") {
@ -58,10 +61,11 @@ TEST_CASE("parseInteger<uint8_t>()") {
check<uint8_t>("255", 255);
check<uint8_t>("+255", 255);
check<uint8_t>("3.14", 3);
// check<uint8_t>(" 42", 0);
check<uint8_t>("x42", 0);
check<uint8_t>("-1", 255);
check<uint8_t>("256", 0);
check<uint8_t>("true", 1);
check<uint8_t>("false", 0);
}
TEST_CASE("parseInteger<uint16_t>()") {
@ -73,4 +77,6 @@ TEST_CASE("parseInteger<uint16_t>()") {
check<uint16_t>("x42", 0);
check<uint16_t>("-1", 65535);
check<uint16_t>("65536", 0);
check<uint16_t>("true", 1);
check<uint16_t>("false", 0);
}

View File

@ -11,6 +11,7 @@ add_executable(StaticJsonBufferTests
createObject.cpp
parseArray.cpp
parseObject.cpp
size.cpp
startString.cpp
)

View File

@ -17,52 +17,39 @@ static bool isAligned(void *ptr) {
TEST_CASE("StaticJsonBuffer::alloc()") {
StaticJsonBuffer<64> buffer;
SECTION("CapacityMatchTemplateParameter") {
REQUIRE(64 == buffer.capacity());
SECTION("Returns different addresses") {
void *p1 = buffer.alloc(1);
void *p2 = buffer.alloc(1);
REQUIRE(p1 != p2);
}
SECTION("InitialSizeIsZero") {
REQUIRE(0 == buffer.size());
}
SECTION("GrowsAfterAlloc") {
buffer.alloc(1);
REQUIRE(1U <= buffer.size());
buffer.alloc(1);
REQUIRE(2U <= buffer.size());
}
SECTION("DoesntGrowWhenFull") {
buffer.alloc(64);
buffer.alloc(1);
REQUIRE(64 == buffer.size());
}
SECTION("DoesntGrowWhenTooSmall") {
buffer.alloc(65);
REQUIRE(0 == buffer.size());
}
SECTION("ReturnsNonNull") {
SECTION("Returns non-NULL when using full capacity") {
void *p = buffer.alloc(64);
REQUIRE(0 != p);
}
SECTION("ReturnsNullWhenFull") {
SECTION("Returns NULL when full") {
buffer.alloc(64);
void *p = buffer.alloc(1);
REQUIRE(0 == p);
}
SECTION("ReturnsNullWhenTooSmall") {
SECTION("Returns NULL when buffer is too small") {
void *p = buffer.alloc(65);
REQUIRE(0 == p);
}
SECTION("Alignment") {
SECTION("Returns aligned pointers") {
for (size_t size = 1; size <= sizeof(void *); size++) {
void *p = buffer.alloc(1);
REQUIRE(isAligned(p));
}
}
SECTION("Returns same address after clear()") {
void *p1 = buffer.alloc(1);
buffer.clear();
void *p2 = buffer.alloc(1);
REQUIRE(p1 == p2);
}
}

View File

@ -0,0 +1,45 @@
// Copyright Benoit Blanchon 2014-2017
// MIT License
//
// Arduino JSON library
// https://bblanchon.github.io/ArduinoJson/
// If you like this project, please add a star!
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("StaticJsonBuffer::size()") {
StaticJsonBuffer<64> buffer;
SECTION("Capacity equals template parameter") {
REQUIRE(64 == buffer.capacity());
}
SECTION("Initial size is 0") {
REQUIRE(0 == buffer.size());
}
SECTION("Increases after alloc()") {
buffer.alloc(1);
REQUIRE(1U <= buffer.size());
buffer.alloc(1);
REQUIRE(2U <= buffer.size());
}
SECTION("Doesn't grow when buffer is full") {
buffer.alloc(64);
buffer.alloc(1);
REQUIRE(64 == buffer.size());
}
SECTION("Does't grow when buffer is too small for alloc") {
buffer.alloc(65);
REQUIRE(0 == buffer.size());
}
SECTION("Goes back to zero after clear()") {
buffer.alloc(1);
buffer.clear();
REQUIRE(0 == buffer.size());
}
}