From 824b7a25ca5b6db939b29cd2fcf99296f46d708e Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Sun, 26 Jul 2020 12:23:55 +0200 Subject: [PATCH] Reduced stack usage when compiled with -Og (issue #1210) This saves 96 bytes on ESP8266 --- extras/tests/Numbers/parseNumber.cpp | 10 ++-- src/ArduinoJson/Json/JsonDeserializer.hpp | 3 +- src/ArduinoJson/Numbers/parseFloat.hpp | 4 +- src/ArduinoJson/Numbers/parseInteger.hpp | 4 +- src/ArduinoJson/Numbers/parseNumber.hpp | 62 ++++++++++++++--------- 5 files changed, 51 insertions(+), 32 deletions(-) diff --git a/extras/tests/Numbers/parseNumber.cpp b/extras/tests/Numbers/parseNumber.cpp index 01b53cae..38eafc99 100644 --- a/extras/tests/Numbers/parseNumber.cpp +++ b/extras/tests/Numbers/parseNumber.cpp @@ -8,17 +8,17 @@ using namespace ARDUINOJSON_NAMESPACE; TEST_CASE("Test uint32_t overflow") { - ParsedNumber first = - parseNumber("4294967295"); - ParsedNumber second = - parseNumber("4294967296"); + ParsedNumber first, second; + parseNumber("4294967295", first); + parseNumber("4294967296", second); REQUIRE(first.type() == uint8_t(VALUE_IS_POSITIVE_INTEGER)); REQUIRE(second.type() == uint8_t(VALUE_IS_FLOAT)); } TEST_CASE("Invalid value") { - ParsedNumber result = parseNumber("6a3"); + ParsedNumber result; + parseNumber("6a3", result); REQUIRE(result.type() == uint8_t(VALUE_IS_NULL)); } diff --git a/src/ArduinoJson/Json/JsonDeserializer.hpp b/src/ArduinoJson/Json/JsonDeserializer.hpp index e81f0376..54ba2756 100644 --- a/src/ArduinoJson/Json/JsonDeserializer.hpp +++ b/src/ArduinoJson/Json/JsonDeserializer.hpp @@ -466,7 +466,8 @@ class JsonDeserializer { : DeserializationError::IncompleteInput; } - ParsedNumber num = parseNumber(_buffer); + ParsedNumber num; + parseNumber(_buffer, num); switch (num.type()) { case VALUE_IS_NEGATIVE_INTEGER: diff --git a/src/ArduinoJson/Numbers/parseFloat.hpp b/src/ArduinoJson/Numbers/parseFloat.hpp index bfc303c4..40c65c71 100644 --- a/src/ArduinoJson/Numbers/parseFloat.hpp +++ b/src/ArduinoJson/Numbers/parseFloat.hpp @@ -13,6 +13,8 @@ template inline T parseFloat(const char* s) { // try to reuse the same parameters as JsonDeserializer typedef typename choose_largest::type TFloat; - return parseNumber(s).template as(); + ParsedNumber value; + parseNumber(s, value); + return value.template as(); } } // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Numbers/parseInteger.hpp b/src/ArduinoJson/Numbers/parseInteger.hpp index 8da434e6..d8a54ea4 100644 --- a/src/ArduinoJson/Numbers/parseInteger.hpp +++ b/src/ArduinoJson/Numbers/parseInteger.hpp @@ -14,6 +14,8 @@ T parseInteger(const char *s) { // try to reuse the same parameters as JsonDeserializer typedef typename choose_largest::type>::type TUInt; - return parseNumber(s).template as(); + ParsedNumber value; + parseNumber(s, value); + return value.template as(); } } // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Numbers/parseNumber.hpp b/src/ArduinoJson/Numbers/parseNumber.hpp index ad493a3c..76f28ea4 100644 --- a/src/ArduinoJson/Numbers/parseNumber.hpp +++ b/src/ArduinoJson/Numbers/parseNumber.hpp @@ -16,14 +16,18 @@ namespace ARDUINOJSON_NAMESPACE { template struct ParsedNumber { - ParsedNumber() : uintValue(0), floatValue(0), _type(VALUE_IS_NULL) {} + ParsedNumber() : _type(VALUE_IS_NULL) {} - ParsedNumber(TUInt value, bool is_negative) - : uintValue(value), - floatValue(TFloat(value)), - _type(uint8_t(is_negative ? VALUE_IS_NEGATIVE_INTEGER - : VALUE_IS_POSITIVE_INTEGER)) {} - ParsedNumber(TFloat value) : floatValue(value), _type(VALUE_IS_FLOAT) {} + void setInteger(TUInt value, bool is_negative) { + uintValue = value; + _type = uint8_t(is_negative ? VALUE_IS_NEGATIVE_INTEGER + : VALUE_IS_POSITIVE_INTEGER); + } + + void setFloat(TFloat value) { + floatValue = value; + _type = VALUE_IS_FLOAT; + } template T as() const { @@ -43,21 +47,22 @@ struct ParsedNumber { return _type; } - TUInt uintValue; - TFloat floatValue; + union { + TUInt uintValue; + TFloat floatValue; + }; uint8_t _type; -}; +}; // namespace ARDUINOJSON_NAMESPACE template struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> {}; template -inline ParsedNumber parseNumber(const char *s) { +inline void parseNumber(const char* s, ParsedNumber& result) { typedef FloatTraits traits; typedef typename choose_largest::type mantissa_t; typedef typename traits::exponent_type exponent_t; - typedef ParsedNumber return_type; ARDUINOJSON_ASSERT(s != 0); @@ -73,17 +78,22 @@ inline ParsedNumber parseNumber(const char *s) { } #if ARDUINOJSON_ENABLE_NAN - if (*s == 'n' || *s == 'N') - return traits::nan(); + if (*s == 'n' || *s == 'N') { + result.setFloat(traits::nan()); + return; + } + #endif #if ARDUINOJSON_ENABLE_INFINITY - if (*s == 'i' || *s == 'I') - return is_negative ? -traits::inf() : traits::inf(); + if (*s == 'i' || *s == 'I') { + result.setFloat(is_negative ? -traits::inf() : traits::inf()); + return; + } #endif if (!isdigit(*s) && *s != '.') - return return_type(); + return; mantissa_t mantissa = 0; exponent_t exponent_offset = 0; @@ -100,8 +110,10 @@ inline ParsedNumber parseNumber(const char *s) { s++; } - if (*s == '\0') - return return_type(TUInt(mantissa), is_negative); + if (*s == '\0') { + result.setInteger(TUInt(mantissa), is_negative); + return; + } // avoid mantissa overflow while (mantissa > traits::mantissa_max) { @@ -141,9 +153,10 @@ inline ParsedNumber parseNumber(const char *s) { exponent = exponent * 10 + (*s - '0'); if (exponent + exponent_offset > traits::exponent_max) { if (negative_exponent) - return is_negative ? -0.0f : 0.0f; + result.setFloat(is_negative ? -0.0f : 0.0f); else - return is_negative ? -traits::inf() : traits::inf(); + result.setFloat(is_negative ? -traits::inf() : traits::inf()); + return; } s++; } @@ -154,10 +167,11 @@ inline ParsedNumber parseNumber(const char *s) { // we should be at the end of the string, otherwise it's an error if (*s != '\0') - return return_type(); + return; - TFloat result = traits::make_float(static_cast(mantissa), exponent); + TFloat final_result = + traits::make_float(static_cast(mantissa), exponent); - return is_negative ? -result : result; + result.setFloat(is_negative ? -final_result : final_result); } } // namespace ARDUINOJSON_NAMESPACE