Reduced stack usage when compiled with -Og (issue #1210)

This saves 96 bytes on ESP8266
This commit is contained in:
Benoit Blanchon
2020-07-26 12:23:55 +02:00
parent 2223d40640
commit 824b7a25ca
5 changed files with 51 additions and 32 deletions

View File

@ -8,17 +8,17 @@
using namespace ARDUINOJSON_NAMESPACE; using namespace ARDUINOJSON_NAMESPACE;
TEST_CASE("Test uint32_t overflow") { TEST_CASE("Test uint32_t overflow") {
ParsedNumber<float, uint32_t> first = ParsedNumber<float, uint32_t> first, second;
parseNumber<float, uint32_t>("4294967295"); parseNumber("4294967295", first);
ParsedNumber<float, uint32_t> second = parseNumber("4294967296", second);
parseNumber<float, uint32_t>("4294967296");
REQUIRE(first.type() == uint8_t(VALUE_IS_POSITIVE_INTEGER)); REQUIRE(first.type() == uint8_t(VALUE_IS_POSITIVE_INTEGER));
REQUIRE(second.type() == uint8_t(VALUE_IS_FLOAT)); REQUIRE(second.type() == uint8_t(VALUE_IS_FLOAT));
} }
TEST_CASE("Invalid value") { TEST_CASE("Invalid value") {
ParsedNumber<float, uint32_t> result = parseNumber<float, uint32_t>("6a3"); ParsedNumber<float, uint32_t> result;
parseNumber("6a3", result);
REQUIRE(result.type() == uint8_t(VALUE_IS_NULL)); REQUIRE(result.type() == uint8_t(VALUE_IS_NULL));
} }

View File

@ -466,7 +466,8 @@ class JsonDeserializer {
: DeserializationError::IncompleteInput; : DeserializationError::IncompleteInput;
} }
ParsedNumber<Float, UInt> num = parseNumber<Float, UInt>(_buffer); ParsedNumber<Float, UInt> num;
parseNumber<Float, UInt>(_buffer, num);
switch (num.type()) { switch (num.type()) {
case VALUE_IS_NEGATIVE_INTEGER: case VALUE_IS_NEGATIVE_INTEGER:

View File

@ -13,6 +13,8 @@ template <typename T>
inline T parseFloat(const char* s) { inline T parseFloat(const char* s) {
// try to reuse the same parameters as JsonDeserializer // try to reuse the same parameters as JsonDeserializer
typedef typename choose_largest<Float, T>::type TFloat; typedef typename choose_largest<Float, T>::type TFloat;
return parseNumber<TFloat, UInt>(s).template as<T>(); ParsedNumber<TFloat, UInt> value;
parseNumber(s, value);
return value.template as<T>();
} }
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@ -14,6 +14,8 @@ T parseInteger(const char *s) {
// try to reuse the same parameters as JsonDeserializer // try to reuse the same parameters as JsonDeserializer
typedef typename choose_largest<UInt, typename make_unsigned<T>::type>::type typedef typename choose_largest<UInt, typename make_unsigned<T>::type>::type
TUInt; TUInt;
return parseNumber<Float, TUInt>(s).template as<T>(); ParsedNumber<Float, TUInt> value;
parseNumber(s, value);
return value.template as<T>();
} }
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@ -16,14 +16,18 @@ namespace ARDUINOJSON_NAMESPACE {
template <typename TFloat, typename TUInt> template <typename TFloat, typename TUInt>
struct ParsedNumber { struct ParsedNumber {
ParsedNumber() : uintValue(0), floatValue(0), _type(VALUE_IS_NULL) {} ParsedNumber() : _type(VALUE_IS_NULL) {}
ParsedNumber(TUInt value, bool is_negative) void setInteger(TUInt value, bool is_negative) {
: uintValue(value), uintValue = value;
floatValue(TFloat(value)), _type = uint8_t(is_negative ? VALUE_IS_NEGATIVE_INTEGER
_type(uint8_t(is_negative ? VALUE_IS_NEGATIVE_INTEGER : VALUE_IS_POSITIVE_INTEGER);
: VALUE_IS_POSITIVE_INTEGER)) {} }
ParsedNumber(TFloat value) : floatValue(value), _type(VALUE_IS_FLOAT) {}
void setFloat(TFloat value) {
floatValue = value;
_type = VALUE_IS_FLOAT;
}
template <typename T> template <typename T>
T as() const { T as() const {
@ -43,21 +47,22 @@ struct ParsedNumber {
return _type; return _type;
} }
TUInt uintValue; union {
TFloat floatValue; TUInt uintValue;
TFloat floatValue;
};
uint8_t _type; uint8_t _type;
}; }; // namespace ARDUINOJSON_NAMESPACE
template <typename A, typename B> template <typename A, typename B>
struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> {}; struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> {};
template <typename TFloat, typename TUInt> template <typename TFloat, typename TUInt>
inline ParsedNumber<TFloat, TUInt> parseNumber(const char *s) { inline void parseNumber(const char* s, ParsedNumber<TFloat, TUInt>& result) {
typedef FloatTraits<TFloat> traits; typedef FloatTraits<TFloat> traits;
typedef typename choose_largest<typename traits::mantissa_type, TUInt>::type typedef typename choose_largest<typename traits::mantissa_type, TUInt>::type
mantissa_t; mantissa_t;
typedef typename traits::exponent_type exponent_t; typedef typename traits::exponent_type exponent_t;
typedef ParsedNumber<TFloat, TUInt> return_type;
ARDUINOJSON_ASSERT(s != 0); ARDUINOJSON_ASSERT(s != 0);
@ -73,17 +78,22 @@ inline ParsedNumber<TFloat, TUInt> parseNumber(const char *s) {
} }
#if ARDUINOJSON_ENABLE_NAN #if ARDUINOJSON_ENABLE_NAN
if (*s == 'n' || *s == 'N') if (*s == 'n' || *s == 'N') {
return traits::nan(); result.setFloat(traits::nan());
return;
}
#endif #endif
#if ARDUINOJSON_ENABLE_INFINITY #if ARDUINOJSON_ENABLE_INFINITY
if (*s == 'i' || *s == 'I') if (*s == 'i' || *s == 'I') {
return is_negative ? -traits::inf() : traits::inf(); result.setFloat(is_negative ? -traits::inf() : traits::inf());
return;
}
#endif #endif
if (!isdigit(*s) && *s != '.') if (!isdigit(*s) && *s != '.')
return return_type(); return;
mantissa_t mantissa = 0; mantissa_t mantissa = 0;
exponent_t exponent_offset = 0; exponent_t exponent_offset = 0;
@ -100,8 +110,10 @@ inline ParsedNumber<TFloat, TUInt> parseNumber(const char *s) {
s++; s++;
} }
if (*s == '\0') if (*s == '\0') {
return return_type(TUInt(mantissa), is_negative); result.setInteger(TUInt(mantissa), is_negative);
return;
}
// avoid mantissa overflow // avoid mantissa overflow
while (mantissa > traits::mantissa_max) { while (mantissa > traits::mantissa_max) {
@ -141,9 +153,10 @@ inline ParsedNumber<TFloat, TUInt> parseNumber(const char *s) {
exponent = exponent * 10 + (*s - '0'); exponent = exponent * 10 + (*s - '0');
if (exponent + exponent_offset > traits::exponent_max) { if (exponent + exponent_offset > traits::exponent_max) {
if (negative_exponent) if (negative_exponent)
return is_negative ? -0.0f : 0.0f; result.setFloat(is_negative ? -0.0f : 0.0f);
else else
return is_negative ? -traits::inf() : traits::inf(); result.setFloat(is_negative ? -traits::inf() : traits::inf());
return;
} }
s++; s++;
} }
@ -154,10 +167,11 @@ inline ParsedNumber<TFloat, TUInt> parseNumber(const char *s) {
// we should be at the end of the string, otherwise it's an error // we should be at the end of the string, otherwise it's an error
if (*s != '\0') if (*s != '\0')
return return_type(); return;
TFloat result = traits::make_float(static_cast<TFloat>(mantissa), exponent); TFloat final_result =
traits::make_float(static_cast<TFloat>(mantissa), exponent);
return is_negative ? -result : result; result.setFloat(is_negative ? -final_result : final_result);
} }
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE