Compare commits

..

8 Commits

33 changed files with 266 additions and 286 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

@ -1,11 +1,20 @@
ArduinoJson: change log
=======================
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 exponentation thresholds to `1e7` and `1e-5` (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)

View File

@ -58,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++
@ -78,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
-------------
@ -112,6 +116,7 @@ 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'>
---

View File

@ -1,13 +1,15 @@
version: 5.10.0.{build}
version: 5.10.1.{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.
//

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.10.0",
"version": "5.10.1",
"authors": {
"name": "Benoit Blanchon",
"url": "https://blog.benoitblanchon.fr"

View File

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

View File

@ -7,30 +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
// 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
#if ARDUINOJSON_EMBEDDED_MODE
// control the exponentiation threshold for small numbers
#ifndef ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD
#define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5
#endif
#ifdef ARDUINO // assume this is an embedded platform
// 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
@ -38,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
@ -97,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
@ -106,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

@ -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

@ -98,7 +98,7 @@ class DynamicJsonBufferBase
private:
DynamicJsonBufferBase* _parent;
char* _start;
int _length;
size_t _length;
};
String startString() {

View File

@ -107,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

@ -52,7 +52,7 @@ 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.

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 || _type == JSON_POSITIVE_INTEGER || _type == JSON_NEGATIVE_INTEGER ||
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

@ -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

@ -16,7 +16,7 @@ int16_t normalize(T& value) {
int16_t powersOf10 = 0;
if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) {
#if !defined(__SIZEOF_DOUBLE__) || __SIZEOF_DOUBLE__ >= 8
#if ARDUINOJSON_DOUBLE_IS_64BITS
if (value >= 1e256) {
value /= 1e256;
powersOf10 = int16_t(powersOf10 + 256);
@ -57,7 +57,7 @@ int16_t normalize(T& value) {
}
if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) {
#if !defined(__SIZEOF_DOUBLE__) || __SIZEOF_DOUBLE__ >= 8
#if ARDUINOJSON_DOUBLE_IS_64BITS
if (value < 1e-255) {
value *= 1e256;
powersOf10 = int16_t(powersOf10 - 256);

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

@ -38,18 +38,34 @@ class JsonWriter {
// Returns the number of bytes sent to the Print implementation.
// This is very handy for implementations of printTo() that must return the
// number of bytes written.
size_t bytesWritten() const { return _length; }
size_t bytesWritten() const {
return _length;
}
void beginArray() { writeRaw('['); }
void endArray() { writeRaw(']'); }
void beginArray() {
writeRaw('[');
}
void endArray() {
writeRaw(']');
}
void beginObject() { writeRaw('{'); }
void endObject() { writeRaw('}'); }
void beginObject() {
writeRaw('{');
}
void endObject() {
writeRaw('}');
}
void writeColon() { writeRaw(':'); }
void writeComma() { writeRaw(','); }
void writeColon() {
writeRaw(':');
}
void writeComma() {
writeRaw(',');
}
void writeBoolean(bool value) { writeRaw(value ? "true" : "false"); }
void writeBoolean(bool value) {
writeRaw(value ? "true" : "false");
}
void writeString(const char *value) {
if (!value) {
@ -106,7 +122,7 @@ class JsonWriter {
*ptr = 0;
do {
*--ptr = static_cast<char>(value % 10 + '0');
*--ptr = char(value % 10 + '0');
value = UInt(value / 10);
} while (value);
@ -137,8 +153,12 @@ class JsonWriter {
writeRaw(ptr);
}
void writeRaw(const char *s) { _length += _sink.print(s); }
void writeRaw(char c) { _length += _sink.print(c); }
void writeRaw(const char *s) {
_length += _sink.print(s);
}
void writeRaw(char c) {
_length += _sink.print(c);
}
protected:
Print &_sink;
@ -154,19 +174,19 @@ class JsonWriter {
integralPart = uint32_t(value);
JsonFloat remainder = value - JsonFloat(integralPart);
decimalPart = uint32_t(remainder * maxDecimalPart);
remainder = remainder * maxDecimalPart - JsonFloat(decimalPart);
remainder *= maxDecimalPart;
decimalPart = uint32_t(remainder);
remainder = remainder - JsonFloat(decimalPart);
// rounding
if (remainder > 0.5) {
decimalPart++;
if (decimalPart >= maxDecimalPart) {
decimalPart -= maxDecimalPart;
integralPart++;
if (powersOf10 && integralPart >= 10) {
powersOf10++;
integralPart /= 10;
}
// 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

@ -23,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

@ -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;
@ -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

@ -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

@ -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

@ -84,6 +84,7 @@ TEST_CASE("JsonWriter::writeFloat()") {
SECTION("Rounding when too many decimals") {
check(0.000099999999999, "0.0001");
check(0.0000099999999999, "1e-5");
check(0.9999999996, "1");
}
SECTION("9 decimal places") {

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);
}