summaryrefslogtreecommitdiff
path: root/include/lib/ArduinoJson/Numbers
diff options
context:
space:
mode:
Diffstat (limited to 'include/lib/ArduinoJson/Numbers')
-rw-r--r--include/lib/ArduinoJson/Numbers/Float.hpp17
-rw-r--r--include/lib/ArduinoJson/Numbers/FloatParts.hpp87
-rw-r--r--include/lib/ArduinoJson/Numbers/FloatTraits.hpp201
-rw-r--r--include/lib/ArduinoJson/Numbers/Integer.hpp32
-rw-r--r--include/lib/ArduinoJson/Numbers/arithmeticCompare.hpp121
-rw-r--r--include/lib/ArduinoJson/Numbers/convertNumber.hpp107
-rw-r--r--include/lib/ArduinoJson/Numbers/parseNumber.hpp153
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