diff options
author | Daniel Friesel <daniel.friesel@uos.de> | 2021-05-12 09:12:09 +0200 |
---|---|---|
committer | Daniel Friesel <daniel.friesel@uos.de> | 2021-05-12 09:12:09 +0200 |
commit | 39895a677e5d370824e702cfe90ebc67737b8482 (patch) | |
tree | ff5b4cc9e373d33a795d50d9333e05549bd9f2b8 /include/lib/ArduinoJson/Numbers | |
parent | 42e7fdf01c3a5701bb51e93ad6c650c3dbbc5450 (diff) |
import ArduinoJson 6.18.0
Diffstat (limited to 'include/lib/ArduinoJson/Numbers')
-rw-r--r-- | include/lib/ArduinoJson/Numbers/Float.hpp | 17 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Numbers/FloatParts.hpp | 87 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Numbers/FloatTraits.hpp | 201 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Numbers/Integer.hpp | 32 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Numbers/arithmeticCompare.hpp | 121 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Numbers/convertNumber.hpp | 107 | ||||
-rw-r--r-- | include/lib/ArduinoJson/Numbers/parseNumber.hpp | 153 |
7 files changed, 718 insertions, 0 deletions
diff --git a/include/lib/ArduinoJson/Numbers/Float.hpp b/include/lib/ArduinoJson/Numbers/Float.hpp new file mode 100644 index 0000000..bbaca04 --- /dev/null +++ b/include/lib/ArduinoJson/Numbers/Float.hpp @@ -0,0 +1,17 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Namespace.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +#if ARDUINOJSON_USE_DOUBLE +typedef double Float; +#else +typedef float Float; +#endif +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Numbers/FloatParts.hpp b/include/lib/ArduinoJson/Numbers/FloatParts.hpp new file mode 100644 index 0000000..4e53add --- /dev/null +++ b/include/lib/ArduinoJson/Numbers/FloatParts.hpp @@ -0,0 +1,87 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Numbers/FloatTraits.hpp> +#include <ArduinoJson/Polyfills/math.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename TFloat> +struct FloatParts { + uint32_t integral; + uint32_t decimal; + int16_t exponent; + int8_t decimalPlaces; + + FloatParts(TFloat value) { + uint32_t maxDecimalPart = sizeof(TFloat) >= 8 ? 1000000000 : 1000000; + decimalPlaces = sizeof(TFloat) >= 8 ? 9 : 6; + + exponent = normalize(value); + + integral = uint32_t(value); + // reduce number of decimal places by the number of integral places + for (uint32_t tmp = integral; tmp >= 10; tmp /= 10) { + maxDecimalPart /= 10; + decimalPlaces--; + } + + TFloat remainder = (value - TFloat(integral)) * TFloat(maxDecimalPart); + + decimal = uint32_t(remainder); + remainder = remainder - TFloat(decimal); + + // rounding: + // increment by 1 if remainder >= 0.5 + decimal += uint32_t(remainder * 2); + if (decimal >= maxDecimalPart) { + decimal = 0; + integral++; + if (exponent && integral >= 10) { + exponent++; + integral = 1; + } + } + + // remove trailing zeros + while (decimal % 10 == 0 && decimalPlaces > 0) { + decimal /= 10; + decimalPlaces--; + } + } + + static int16_t normalize(TFloat& value) { + typedef FloatTraits<TFloat> traits; + int16_t powersOf10 = 0; + + int8_t index = sizeof(TFloat) == 8 ? 8 : 5; + int bit = 1 << index; + + if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) { + for (; index >= 0; index--) { + if (value >= traits::positiveBinaryPowerOfTen(index)) { + value *= traits::negativeBinaryPowerOfTen(index); + powersOf10 = int16_t(powersOf10 + bit); + } + bit >>= 1; + } + } + + if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) { + for (; index >= 0; index--) { + if (value < traits::negativeBinaryPowerOfTenPlusOne(index)) { + value *= traits::positiveBinaryPowerOfTen(index); + powersOf10 = int16_t(powersOf10 - bit); + } + bit >>= 1; + } + } + + return powersOf10; + } +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Numbers/FloatTraits.hpp b/include/lib/ArduinoJson/Numbers/FloatTraits.hpp new file mode 100644 index 0000000..60b1dfd --- /dev/null +++ b/include/lib/ArduinoJson/Numbers/FloatTraits.hpp @@ -0,0 +1,201 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <stddef.h> // for size_t +#include <stdint.h> + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Polyfills/alias_cast.hpp> +#include <ArduinoJson/Polyfills/math.hpp> +#include <ArduinoJson/Polyfills/preprocessor.hpp> +#include <ArduinoJson/Polyfills/static_array.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename T, size_t = sizeof(T)> +struct FloatTraits {}; + +template <typename T> +struct FloatTraits<T, 8 /*64bits*/> { + typedef uint64_t mantissa_type; + static const short mantissa_bits = 52; + static const mantissa_type mantissa_max = + (mantissa_type(1) << mantissa_bits) - 1; + + typedef int16_t exponent_type; + static const exponent_type exponent_max = 308; + + template <typename TExponent> + static T make_float(T m, TExponent e) { + if (e > 0) { + for (uint8_t index = 0; e != 0; index++) { + if (e & 1) + m *= positiveBinaryPowerOfTen(index); + e >>= 1; + } + } else { + e = TExponent(-e); + for (uint8_t index = 0; e != 0; index++) { + if (e & 1) + m *= negativeBinaryPowerOfTen(index); + e >>= 1; + } + } + return m; + } + + static T positiveBinaryPowerOfTen(int index) { + ARDUINOJSON_DEFINE_STATIC_ARRAY( // + uint32_t, factors, + ARDUINOJSON_EXPAND18({ + 0x40240000, 0x00000000, // 1e1 + 0x40590000, 0x00000000, // 1e2 + 0x40C38800, 0x00000000, // 1e4 + 0x4197D784, 0x00000000, // 1e8 + 0x4341C379, 0x37E08000, // 1e16 + 0x4693B8B5, 0xB5056E17, // 1e32 + 0x4D384F03, 0xE93FF9F5, // 1e64 + 0x5A827748, 0xF9301D32, // 1e128 + 0x75154FDD, 0x7F73BF3C // 1e256 + })); + return forge( + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); + } + + static T negativeBinaryPowerOfTen(int index) { + ARDUINOJSON_DEFINE_STATIC_ARRAY( // + uint32_t, factors, + ARDUINOJSON_EXPAND18({ + 0x3FB99999, 0x9999999A, // 1e-1 + 0x3F847AE1, 0x47AE147B, // 1e-2 + 0x3F1A36E2, 0xEB1C432D, // 1e-4 + 0x3E45798E, 0xE2308C3A, // 1e-8 + 0x3C9CD2B2, 0x97D889BC, // 1e-16 + 0x3949F623, 0xD5A8A733, // 1e-32 + 0x32A50FFD, 0x44F4A73D, // 1e-64 + 0x255BBA08, 0xCF8C979D, // 1e-128 + 0x0AC80628, 0x64AC6F43 // 1e-256 + })); + return forge( + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); + } + + static T negativeBinaryPowerOfTenPlusOne(int index) { + ARDUINOJSON_DEFINE_STATIC_ARRAY( // + uint32_t, factors, + ARDUINOJSON_EXPAND18({ + 0x3FF00000, 0x00000000, // 1e0 + 0x3FB99999, 0x9999999A, // 1e-1 + 0x3F50624D, 0xD2F1A9FC, // 1e-3 + 0x3E7AD7F2, 0x9ABCAF48, // 1e-7 + 0x3CD203AF, 0x9EE75616, // 1e-15 + 0x398039D6, 0x65896880, // 1e-31 + 0x32DA53FC, 0x9631D10D, // 1e-63 + 0x25915445, 0x81B7DEC2, // 1e-127 + 0x0AFE07B2, 0x7DD78B14 // 1e-255 + })); + return forge( + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index), + ARDUINOJSON_READ_STATIC_ARRAY(uint32_t, factors, 2 * index + 1)); + } + + static T nan() { + return forge(0x7ff80000, 0x00000000); + } + + static T inf() { + return forge(0x7ff00000, 0x00000000); + } + + static T highest() { + return forge(0x7FEFFFFF, 0xFFFFFFFF); + } + + static T lowest() { + return forge(0xFFEFFFFF, 0xFFFFFFFF); + } + + // constructs a double floating point values from its binary representation + // we use this function to workaround platforms with single precision literals + // (for example, when -fsingle-precision-constant is passed to GCC) + static T forge(uint32_t msb, uint32_t lsb) { + return alias_cast<T>((uint64_t(msb) << 32) | lsb); + } +}; + +template <typename T> +struct FloatTraits<T, 4 /*32bits*/> { + typedef uint32_t mantissa_type; + static const short mantissa_bits = 23; + static const mantissa_type mantissa_max = + (mantissa_type(1) << mantissa_bits) - 1; + + typedef int8_t exponent_type; + static const exponent_type exponent_max = 38; + + template <typename TExponent> + static T make_float(T m, TExponent e) { + if (e > 0) { + for (uint8_t index = 0; e != 0; index++) { + if (e & 1) + m *= positiveBinaryPowerOfTen(index); + e >>= 1; + } + } else { + e = -e; + for (uint8_t index = 0; e != 0; index++) { + if (e & 1) + m *= negativeBinaryPowerOfTen(index); + e >>= 1; + } + } + return m; + } + + static T positiveBinaryPowerOfTen(int index) { + ARDUINOJSON_DEFINE_STATIC_ARRAY( + T, factors, + ARDUINOJSON_EXPAND6({1e1f, 1e2f, 1e4f, 1e8f, 1e16f, 1e32f})); + return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); + } + + static T negativeBinaryPowerOfTen(int index) { + ARDUINOJSON_DEFINE_STATIC_ARRAY( + T, factors, + ARDUINOJSON_EXPAND6({1e-1f, 1e-2f, 1e-4f, 1e-8f, 1e-16f, 1e-32f})); + return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); + } + + static T negativeBinaryPowerOfTenPlusOne(int index) { + ARDUINOJSON_DEFINE_STATIC_ARRAY( + T, factors, + ARDUINOJSON_EXPAND6({1e0f, 1e-1f, 1e-3f, 1e-7f, 1e-15f, 1e-31f})); + return ARDUINOJSON_READ_STATIC_ARRAY(T, factors, index); + } + + static T forge(uint32_t bits) { + return alias_cast<T>(bits); + } + + static T nan() { + return forge(0x7fc00000); + } + + static T inf() { + return forge(0x7f800000); + } + + static T highest() { + return forge(0x7f7fffff); + } + + static T lowest() { + return forge(0xFf7fffff); + } +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Numbers/Integer.hpp b/include/lib/ArduinoJson/Numbers/Integer.hpp new file mode 100644 index 0000000..fb656a7 --- /dev/null +++ b/include/lib/ArduinoJson/Numbers/Integer.hpp @@ -0,0 +1,32 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Configuration.hpp> +#include <ArduinoJson/Namespace.hpp> + +#include <stdint.h> // int64_t + +namespace ARDUINOJSON_NAMESPACE { + +#if ARDUINOJSON_USE_LONG_LONG +typedef int64_t Integer; +typedef uint64_t UInt; +#else +typedef long Integer; +typedef unsigned long UInt; +#endif + +} // namespace ARDUINOJSON_NAMESPACE + +#if ARDUINOJSON_HAS_LONG_LONG && !ARDUINOJSON_USE_LONG_LONG +#define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) \ + static_assert(sizeof(T) <= sizeof(ARDUINOJSON_NAMESPACE::Integer), \ + "To use 64-bit integers with ArduinoJson, you must set " \ + "ARDUINOJSON_USE_LONG_LONG to 1. See " \ + "https://arduinojson.org/v6/api/config/use_long_long/"); +#else +#define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) +#endif diff --git a/include/lib/ArduinoJson/Numbers/arithmeticCompare.hpp b/include/lib/ArduinoJson/Numbers/arithmeticCompare.hpp new file mode 100644 index 0000000..bfd41d5 --- /dev/null +++ b/include/lib/ArduinoJson/Numbers/arithmeticCompare.hpp @@ -0,0 +1,121 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Numbers/Integer.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +enum CompareResult { + COMPARE_RESULT_DIFFER = 0, + COMPARE_RESULT_EQUAL = 1, + COMPARE_RESULT_GREATER = 2, + COMPARE_RESULT_LESS = 4, + + COMPARE_RESULT_GREATER_OR_EQUAL = 3, + COMPARE_RESULT_LESS_OR_EQUAL = 5 +}; + +template <typename T> +CompareResult arithmeticCompare(const T &lhs, const T &rhs) { + if (lhs < rhs) + return COMPARE_RESULT_LESS; + else if (lhs > rhs) + return COMPARE_RESULT_GREATER; + else + return COMPARE_RESULT_EQUAL; +} + +template <typename T1, typename T2> +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if<is_integral<T1>::value && is_integral<T2>::value && + sizeof(T1) < sizeof(T2), + int // Using int instead of void to avoid C2572 on + // Visual Studio 2012, 2013, and 2015 + >::type * = 0) { + return arithmeticCompare<T2>(static_cast<T2>(lhs), rhs); +} + +template <typename T1, typename T2> +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if<is_integral<T1>::value && is_integral<T2>::value && + sizeof(T2) < sizeof(T1)>::type * = 0) { + return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs)); +} + +template <typename T1, typename T2> +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if<is_integral<T1>::value && is_integral<T2>::value && + is_signed<T1>::value == is_signed<T2>::value && + sizeof(T2) == sizeof(T1)>::type * = 0) { + return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs)); +} + +template <typename T1, typename T2> +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if<is_integral<T1>::value && is_integral<T2>::value && + is_unsigned<T1>::value && is_signed<T2>::value && + sizeof(T2) == sizeof(T1)>::type * = 0) { + if (rhs < 0) + return COMPARE_RESULT_GREATER; + return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs)); +} + +template <typename T1, typename T2> +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if<is_integral<T1>::value && is_integral<T2>::value && + is_signed<T1>::value && is_unsigned<T2>::value && + sizeof(T2) == sizeof(T1)>::type * = 0) { + if (lhs < 0) + return COMPARE_RESULT_LESS; + return arithmeticCompare<T2>(static_cast<T2>(lhs), rhs); +} + +template <typename T1, typename T2> +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if<is_floating_point<T1>::value || + is_floating_point<T2>::value>::type * = 0) { + return arithmeticCompare<double>(static_cast<double>(lhs), + static_cast<double>(rhs)); +} + +template <typename T2> +CompareResult arithmeticCompareNegateLeft( + UInt, const T2 &, typename enable_if<is_unsigned<T2>::value>::type * = 0) { + return COMPARE_RESULT_LESS; +} + +template <typename T2> +CompareResult arithmeticCompareNegateLeft( + UInt lhs, const T2 &rhs, + typename enable_if<is_signed<T2>::value>::type * = 0) { + if (rhs > 0) + return COMPARE_RESULT_LESS; + return arithmeticCompare(-rhs, static_cast<T2>(lhs)); +} + +template <typename T1> +CompareResult arithmeticCompareNegateRight( + const T1 &, UInt, typename enable_if<is_unsigned<T1>::value>::type * = 0) { + return COMPARE_RESULT_GREATER; +} + +template <typename T1> +CompareResult arithmeticCompareNegateRight( + const T1 &lhs, UInt rhs, + typename enable_if<is_signed<T1>::value>::type * = 0) { + if (lhs > 0) + return COMPARE_RESULT_GREATER; + return arithmeticCompare(static_cast<T1>(rhs), -lhs); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/include/lib/ArduinoJson/Numbers/convertNumber.hpp b/include/lib/ArduinoJson/Numbers/convertNumber.hpp new file mode 100644 index 0000000..02bbefa --- /dev/null +++ b/include/lib/ArduinoJson/Numbers/convertNumber.hpp @@ -0,0 +1,107 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" +#elif defined(__GNUC__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +#pragma GCC diagnostic push +#endif +#pragma GCC diagnostic ignored "-Wconversion" +#endif + +#include <ArduinoJson/Numbers/Float.hpp> +#include <ArduinoJson/Polyfills/limits.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +// uint32 -> int32 +// uint64 -> int32 +template <typename TOut, typename TIn> +typename enable_if<is_integral<TIn>::value && is_unsigned<TIn>::value && + is_integral<TOut>::value && sizeof(TOut) <= sizeof(TIn), + bool>::type +canConvertNumber(TIn value) { + return value <= TIn(numeric_limits<TOut>::highest()); +} + +// uint32 -> int64 +template <typename TOut, typename TIn> +typename enable_if<is_integral<TIn>::value && is_unsigned<TIn>::value && + is_integral<TOut>::value && sizeof(TIn) < sizeof(TOut), + bool>::type +canConvertNumber(TIn) { + return true; +} + +// uint32 -> float +// int32 -> float +template <typename TOut, typename TIn> +typename enable_if<is_integral<TIn>::value && is_floating_point<TOut>::value, + bool>::type +canConvertNumber(TIn) { + return true; +} + +// int64 -> int32 +template <typename TOut, typename TIn> +typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value && + is_integral<TOut>::value && is_signed<TOut>::value && + sizeof(TOut) < sizeof(TIn), + bool>::type +canConvertNumber(TIn value) { + return value >= TIn(numeric_limits<TOut>::lowest()) && + value <= TIn(numeric_limits<TOut>::highest()); +} + +// int32 -> int32 +// int32 -> int64 +template <typename TOut, typename TIn> +typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value && + is_integral<TOut>::value && is_signed<TOut>::value && + sizeof(TIn) <= sizeof(TOut), + bool>::type +canConvertNumber(TIn) { + return true; +} + +// int32 -> uint32 +template <typename TOut, typename TIn> +typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value && + is_integral<TOut>::value && is_unsigned<TOut>::value, + bool>::type +canConvertNumber(TIn value) { + if (value < 0) + return false; + return value <= TIn(numeric_limits<TOut>::highest()); +} + +// float -> int32 +// float -> int64 +template <typename TOut, typename TIn> +typename enable_if<is_floating_point<TIn>::value && + !is_floating_point<TOut>::value, + bool>::type +canConvertNumber(TIn value) { + return value >= numeric_limits<TOut>::lowest() && + value <= numeric_limits<TOut>::highest(); +} + +template <typename TOut, typename TIn> +TOut convertNumber(TIn value) { + return canConvertNumber<TOut>(value) ? TOut(value) : 0; +} +} // namespace ARDUINOJSON_NAMESPACE + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +#pragma GCC diagnostic pop +#endif +#endif diff --git a/include/lib/ArduinoJson/Numbers/parseNumber.hpp b/include/lib/ArduinoJson/Numbers/parseNumber.hpp new file mode 100644 index 0000000..cf050c7 --- /dev/null +++ b/include/lib/ArduinoJson/Numbers/parseNumber.hpp @@ -0,0 +1,153 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include <ArduinoJson/Numbers/FloatTraits.hpp> +#include <ArduinoJson/Numbers/convertNumber.hpp> +#include <ArduinoJson/Polyfills/assert.hpp> +#include <ArduinoJson/Polyfills/ctype.hpp> +#include <ArduinoJson/Polyfills/math.hpp> +#include <ArduinoJson/Polyfills/type_traits.hpp> +#include <ArduinoJson/Variant/Converter.hpp> +#include <ArduinoJson/Variant/VariantData.hpp> + +namespace ARDUINOJSON_NAMESPACE { + +template <typename A, typename B> +struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> {}; + +inline bool parseNumber(const char* s, VariantData& result) { + typedef FloatTraits<Float> traits; + typedef choose_largest<traits::mantissa_type, UInt>::type mantissa_t; + typedef traits::exponent_type exponent_t; + + ARDUINOJSON_ASSERT(s != 0); + + bool is_negative = false; + switch (*s) { + case '-': + is_negative = true; + s++; + break; + case '+': + s++; + break; + } + +#if ARDUINOJSON_ENABLE_NAN + if (*s == 'n' || *s == 'N') { + result.setFloat(traits::nan()); + return true; + } +#endif + +#if ARDUINOJSON_ENABLE_INFINITY + if (*s == 'i' || *s == 'I') { + result.setFloat(is_negative ? -traits::inf() : traits::inf()); + return true; + } +#endif + + if (!isdigit(*s) && *s != '.') + return false; + + mantissa_t mantissa = 0; + exponent_t exponent_offset = 0; + const mantissa_t maxUint = UInt(-1); + + while (isdigit(*s)) { + uint8_t digit = uint8_t(*s - '0'); + if (mantissa > maxUint / 10) + break; + mantissa *= 10; + if (mantissa > maxUint - digit) + break; + mantissa += digit; + s++; + } + + if (*s == '\0') { + if (is_negative) { + const mantissa_t sintMantissaMax = mantissa_t(1) + << (sizeof(Integer) * 8 - 1); + if (mantissa <= sintMantissaMax) { + result.setInteger(Integer(~mantissa + 1)); + return true; + } + } else { + result.setInteger(UInt(mantissa)); + return true; + } + } + + // avoid mantissa overflow + while (mantissa > traits::mantissa_max) { + mantissa /= 10; + exponent_offset++; + } + + // remaing digits can't fit in the mantissa + while (isdigit(*s)) { + exponent_offset++; + s++; + } + + if (*s == '.') { + s++; + while (isdigit(*s)) { + if (mantissa < traits::mantissa_max / 10) { + mantissa = mantissa * 10 + uint8_t(*s - '0'); + exponent_offset--; + } + s++; + } + } + + int exponent = 0; + if (*s == 'e' || *s == 'E') { + s++; + bool negative_exponent = false; + if (*s == '-') { + negative_exponent = true; + s++; + } else if (*s == '+') { + s++; + } + + while (isdigit(*s)) { + exponent = exponent * 10 + (*s - '0'); + if (exponent + exponent_offset > traits::exponent_max) { + if (negative_exponent) + result.setFloat(is_negative ? -0.0f : 0.0f); + else + result.setFloat(is_negative ? -traits::inf() : traits::inf()); + return true; + } + s++; + } + if (negative_exponent) + exponent = -exponent; + } + exponent += exponent_offset; + + // we should be at the end of the string, otherwise it's an error + if (*s != '\0') + return false; + + Float final_result = + traits::make_float(static_cast<Float>(mantissa), exponent); + + result.setFloat(is_negative ? -final_result : final_result); + return true; +} + +template <typename T> +inline T parseNumber(const char* s) { + VariantData value; + value.init(); // VariantData is a POD, so it has no constructor + parseNumber(s, value); + return Converter<T>::fromJson(VariantConstRef(&value)); +} +} // namespace ARDUINOJSON_NAMESPACE |