From 80a02cd90df3b3b1f02a69bf3586bc10b3b872e5 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Sun, 19 May 2019 15:48:27 +0200 Subject: [PATCH] Added `ARDUINOJSON_ENABLE_INFINITY` to enable Infinity in JSON --- CHANGELOG.md | 1 + src/ArduinoJson/Configuration.hpp | 5 +++ src/ArduinoJson/Json/TextFormatter.hpp | 9 +++++ src/ArduinoJson/Namespace.hpp | 18 +++++---- src/ArduinoJson/Numbers/parseNumber.hpp | 5 +++ test/MixedConfiguration/CMakeLists.txt | 6 ++- test/MixedConfiguration/enable_infinity_0.cpp | 35 +++++++++++++++++ test/MixedConfiguration/enable_infinity_1.cpp | 38 +++++++++++++++++++ 8 files changed, 107 insertions(+), 10 deletions(-) create mode 100644 test/MixedConfiguration/enable_infinity_0.cpp create mode 100644 test/MixedConfiguration/enable_infinity_1.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e21e643..6aedf8e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ HEAD * Fixed invalid result from `operator|` (issue #981) * Made `deserializeJson()` more picky about trailing characters (issue #980) * Added `ARDUINOJSON_ENABLE_NAN` to enable NaN in JSON (issue #973) +* Added `ARDUINOJSON_ENABLE_INFINITY` to enable Infinity in JSON > ### BREAKING CHANGE > diff --git a/src/ArduinoJson/Configuration.hpp b/src/ArduinoJson/Configuration.hpp index 5fd66d25..e98cabc8 100644 --- a/src/ArduinoJson/Configuration.hpp +++ b/src/ArduinoJson/Configuration.hpp @@ -140,6 +140,11 @@ #define ARDUINOJSON_ENABLE_NAN 1 #endif +// Support Infinity in JSON +#ifndef ARDUINOJSON_ENABLE_INFINITY +#define ARDUINOJSON_ENABLE_INFINITY 1 +#endif + // Control the exponentiation threshold for big numbers // CAUTION: cannot be more that 1e9 !!!! #ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD diff --git a/src/ArduinoJson/Json/TextFormatter.hpp b/src/ArduinoJson/Json/TextFormatter.hpp index 29bc06ad..8f05ac56 100644 --- a/src/ArduinoJson/Json/TextFormatter.hpp +++ b/src/ArduinoJson/Json/TextFormatter.hpp @@ -54,12 +54,21 @@ class TextFormatter { void writeFloat(T value) { if (isnan(value)) return writeRaw(ARDUINOJSON_ENABLE_NAN ? "NaN" : "null"); +#if ARDUINOJSON_ENABLE_INFINITY if (value < 0.0) { writeRaw('-'); value = -value; } if (isinf(value)) return writeRaw("Infinity"); +#else + if (isinf(value)) return writeRaw("null"); + + if (value < 0.0) { + writeRaw('-'); + value = -value; + } +#endif FloatParts parts(value); diff --git a/src/ArduinoJson/Namespace.hpp b/src/ArduinoJson/Namespace.hpp index dee7d36f..76c4dcf9 100644 --- a/src/ArduinoJson/Namespace.hpp +++ b/src/ArduinoJson/Namespace.hpp @@ -10,17 +10,19 @@ #define ARDUINOJSON_DO_CONCAT(A, B) A##B #define ARDUINOJSON_CONCAT2(A, B) ARDUINOJSON_DO_CONCAT(A, B) +#define ARDUINOJSON_CONCAT3(A, B, C) \ + ARDUINOJSON_CONCAT2(A, ARDUINOJSON_CONCAT2(B, C)) #define ARDUINOJSON_CONCAT4(A, B, C, D) \ ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT2(A, B), ARDUINOJSON_CONCAT2(C, D)) #define ARDUINOJSON_CONCAT8(A, B, C, D, E, F, G, H) \ ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT4(A, B, C, D), \ ARDUINOJSON_CONCAT4(E, F, G, H)) -#define ARDUINOJSON_CONCAT9(A, B, C, D, E, F, G, H, I) \ - ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT4(A, B, C, D), \ - ARDUINOJSON_CONCAT4(E, F, G, ARDUINOJSON_CONCAT2(H, I))) +#define ARDUINOJSON_CONCAT10(A, B, C, D, E, F, G, H, I, J) \ + ARDUINOJSON_CONCAT8(A, B, C, D, E, F, G, ARDUINOJSON_CONCAT3(H, I, J)) -#define ARDUINOJSON_NAMESPACE \ - ARDUINOJSON_CONCAT9(ArduinoJson, ARDUINOJSON_VERSION_MAJOR, \ - ARDUINOJSON_VERSION_MINOR, ARDUINOJSON_VERSION_REVISION, \ - _, ARDUINOJSON_USE_LONG_LONG, ARDUINOJSON_USE_DOUBLE, \ - ARDUINOJSON_DECODE_UNICODE, ARDUINOJSON_ENABLE_NAN) +#define ARDUINOJSON_NAMESPACE \ + ARDUINOJSON_CONCAT10( \ + ArduinoJson, ARDUINOJSON_VERSION_MAJOR, ARDUINOJSON_VERSION_MINOR, \ + ARDUINOJSON_VERSION_REVISION, _, ARDUINOJSON_USE_LONG_LONG, \ + ARDUINOJSON_USE_DOUBLE, ARDUINOJSON_DECODE_UNICODE, \ + ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY) diff --git a/src/ArduinoJson/Numbers/parseNumber.hpp b/src/ArduinoJson/Numbers/parseNumber.hpp index a99efb7a..1fee3819 100644 --- a/src/ArduinoJson/Numbers/parseNumber.hpp +++ b/src/ArduinoJson/Numbers/parseNumber.hpp @@ -71,11 +71,16 @@ inline ParsedNumber parseNumber(const char *s) { s++; break; } + #if ARDUINOJSON_ENABLE_NAN if (*s == 'n' || *s == 'N') return traits::nan(); #endif + +#if ARDUINOJSON_ENABLE_INFINITY if (*s == 'i' || *s == 'I') return is_negative ? -traits::inf() : traits::inf(); +#endif + if (!isdigit(*s) && *s != '.') return return_type(); mantissa_t mantissa = 0; diff --git a/test/MixedConfiguration/CMakeLists.txt b/test/MixedConfiguration/CMakeLists.txt index 08a7b2e8..81bd585b 100644 --- a/test/MixedConfiguration/CMakeLists.txt +++ b/test/MixedConfiguration/CMakeLists.txt @@ -8,12 +8,14 @@ set(CMAKE_CXX_STANDARD 11) add_executable(MixedConfigurationTests decode_unicode_0.cpp decode_unicode_1.cpp + enable_nan_0.cpp + enable_nan_1.cpp + enable_infinity_0.cpp + enable_infinity_1.cpp use_double_0.cpp use_double_1.cpp use_long_long_0.cpp use_long_long_1.cpp - enable_nan_0.cpp - enable_nan_1.cpp ) target_link_libraries(MixedConfigurationTests catch) diff --git a/test/MixedConfiguration/enable_infinity_0.cpp b/test/MixedConfiguration/enable_infinity_0.cpp new file mode 100644 index 00000000..66167ed5 --- /dev/null +++ b/test/MixedConfiguration/enable_infinity_0.cpp @@ -0,0 +1,35 @@ +#define ARDUINOJSON_ENABLE_INFINITY 0 +#include + +#include +#include + +static void assertParseFails(const char* json) { + DynamicJsonDocument doc(4096); + auto err = deserializeJson(doc, json); + + REQUIRE(err == DeserializationError::InvalidInput); +} + +static void assertJsonEquals(const JsonDocument& doc, + std::string expectedJson) { + std::string actualJson; + serializeJson(doc, actualJson); + REQUIRE(actualJson == expectedJson); +} + +TEST_CASE("ARDUINOJSON_ENABLE_INFINITY == 0") { + SECTION("serializeJson()") { + DynamicJsonDocument doc(4096); + doc.add(std::numeric_limits::infinity()); + doc.add(-std::numeric_limits::infinity()); + + assertJsonEquals(doc, "[null,null]"); + } + + SECTION("deserializeJson()") { + assertParseFails("{\"X\":Infinity}"); + assertParseFails("{\"X\":-Infinity}"); + assertParseFails("{\"X\":+Infinity}"); + } +} diff --git a/test/MixedConfiguration/enable_infinity_1.cpp b/test/MixedConfiguration/enable_infinity_1.cpp new file mode 100644 index 00000000..56e49fad --- /dev/null +++ b/test/MixedConfiguration/enable_infinity_1.cpp @@ -0,0 +1,38 @@ +#define ARDUINOJSON_ENABLE_INFINITY 1 +#include + +#include +#include + +namespace my { +using ARDUINOJSON_NAMESPACE::isinf; +} // namespace my + +TEST_CASE("ARDUINOJSON_ENABLE_INFINITY == 1") { + DynamicJsonDocument doc(4096); + + SECTION("serializeJson()") { + doc.add(std::numeric_limits::infinity()); + doc.add(-std::numeric_limits::infinity()); + + std::string json; + serializeJson(doc, json); + + REQUIRE(json == "[Infinity,-Infinity]"); + } + + SECTION("deserializeJson()") { + auto err = deserializeJson(doc, "[Infinity,-Infinity,+Infinity]"); + float a = doc[0]; + float b = doc[1]; + float c = doc[2]; + + REQUIRE(err == DeserializationError::Ok); + REQUIRE(my::isinf(a)); + REQUIRE(a > 0); + REQUIRE(my::isinf(b)); + REQUIRE(b < 0); + REQUIRE(my::isinf(c)); + REQUIRE(c > 0); + } +}