From 39895a677e5d370824e702cfe90ebc67737b8482 Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Wed, 12 May 2021 09:12:09 +0200 Subject: import ArduinoJson 6.18.0 --- include/lib/ArduinoJson/Numbers/Float.hpp | 17 ++ include/lib/ArduinoJson/Numbers/FloatParts.hpp | 87 +++++++++ include/lib/ArduinoJson/Numbers/FloatTraits.hpp | 201 +++++++++++++++++++++ include/lib/ArduinoJson/Numbers/Integer.hpp | 32 ++++ .../lib/ArduinoJson/Numbers/arithmeticCompare.hpp | 121 +++++++++++++ include/lib/ArduinoJson/Numbers/convertNumber.hpp | 107 +++++++++++ include/lib/ArduinoJson/Numbers/parseNumber.hpp | 153 ++++++++++++++++ 7 files changed, 718 insertions(+) create mode 100644 include/lib/ArduinoJson/Numbers/Float.hpp create mode 100644 include/lib/ArduinoJson/Numbers/FloatParts.hpp create mode 100644 include/lib/ArduinoJson/Numbers/FloatTraits.hpp create mode 100644 include/lib/ArduinoJson/Numbers/Integer.hpp create mode 100644 include/lib/ArduinoJson/Numbers/arithmeticCompare.hpp create mode 100644 include/lib/ArduinoJson/Numbers/convertNumber.hpp create mode 100644 include/lib/ArduinoJson/Numbers/parseNumber.hpp (limited to 'include/lib/ArduinoJson/Numbers') 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 +#include + +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 +#include +#include + +namespace ARDUINOJSON_NAMESPACE { + +template +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 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 // for size_t +#include + +#include +#include +#include +#include +#include + +namespace ARDUINOJSON_NAMESPACE { + +template +struct FloatTraits {}; + +template +struct FloatTraits { + 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 + 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((uint64_t(msb) << 32) | lsb); + } +}; + +template +struct FloatTraits { + 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 + 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(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 +#include + +#include // 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 +#include + +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 +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 +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if::value && is_integral::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(static_cast(lhs), rhs); +} + +template +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if::value && is_integral::value && + sizeof(T2) < sizeof(T1)>::type * = 0) { + return arithmeticCompare(lhs, static_cast(rhs)); +} + +template +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if::value && is_integral::value && + is_signed::value == is_signed::value && + sizeof(T2) == sizeof(T1)>::type * = 0) { + return arithmeticCompare(lhs, static_cast(rhs)); +} + +template +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if::value && is_integral::value && + is_unsigned::value && is_signed::value && + sizeof(T2) == sizeof(T1)>::type * = 0) { + if (rhs < 0) + return COMPARE_RESULT_GREATER; + return arithmeticCompare(lhs, static_cast(rhs)); +} + +template +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if::value && is_integral::value && + is_signed::value && is_unsigned::value && + sizeof(T2) == sizeof(T1)>::type * = 0) { + if (lhs < 0) + return COMPARE_RESULT_LESS; + return arithmeticCompare(static_cast(lhs), rhs); +} + +template +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if::value || + is_floating_point::value>::type * = 0) { + return arithmeticCompare(static_cast(lhs), + static_cast(rhs)); +} + +template +CompareResult arithmeticCompareNegateLeft( + UInt, const T2 &, typename enable_if::value>::type * = 0) { + return COMPARE_RESULT_LESS; +} + +template +CompareResult arithmeticCompareNegateLeft( + UInt lhs, const T2 &rhs, + typename enable_if::value>::type * = 0) { + if (rhs > 0) + return COMPARE_RESULT_LESS; + return arithmeticCompare(-rhs, static_cast(lhs)); +} + +template +CompareResult arithmeticCompareNegateRight( + const T1 &, UInt, typename enable_if::value>::type * = 0) { + return COMPARE_RESULT_GREATER; +} + +template +CompareResult arithmeticCompareNegateRight( + const T1 &lhs, UInt rhs, + typename enable_if::value>::type * = 0) { + if (lhs > 0) + return COMPARE_RESULT_GREATER; + return arithmeticCompare(static_cast(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 +#include +#include + +namespace ARDUINOJSON_NAMESPACE { + +// uint32 -> int32 +// uint64 -> int32 +template +typename enable_if::value && is_unsigned::value && + is_integral::value && sizeof(TOut) <= sizeof(TIn), + bool>::type +canConvertNumber(TIn value) { + return value <= TIn(numeric_limits::highest()); +} + +// uint32 -> int64 +template +typename enable_if::value && is_unsigned::value && + is_integral::value && sizeof(TIn) < sizeof(TOut), + bool>::type +canConvertNumber(TIn) { + return true; +} + +// uint32 -> float +// int32 -> float +template +typename enable_if::value && is_floating_point::value, + bool>::type +canConvertNumber(TIn) { + return true; +} + +// int64 -> int32 +template +typename enable_if::value && is_signed::value && + is_integral::value && is_signed::value && + sizeof(TOut) < sizeof(TIn), + bool>::type +canConvertNumber(TIn value) { + return value >= TIn(numeric_limits::lowest()) && + value <= TIn(numeric_limits::highest()); +} + +// int32 -> int32 +// int32 -> int64 +template +typename enable_if::value && is_signed::value && + is_integral::value && is_signed::value && + sizeof(TIn) <= sizeof(TOut), + bool>::type +canConvertNumber(TIn) { + return true; +} + +// int32 -> uint32 +template +typename enable_if::value && is_signed::value && + is_integral::value && is_unsigned::value, + bool>::type +canConvertNumber(TIn value) { + if (value < 0) + return false; + return value <= TIn(numeric_limits::highest()); +} + +// float -> int32 +// float -> int64 +template +typename enable_if::value && + !is_floating_point::value, + bool>::type +canConvertNumber(TIn value) { + return value >= numeric_limits::lowest() && + value <= numeric_limits::highest(); +} + +template +TOut convertNumber(TIn value) { + return canConvertNumber(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 +#include +#include +#include +#include +#include +#include +#include + +namespace ARDUINOJSON_NAMESPACE { + +template +struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> {}; + +inline bool parseNumber(const char* s, VariantData& result) { + typedef FloatTraits traits; + typedef choose_largest::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(mantissa), exponent); + + result.setFloat(is_negative ? -final_result : final_result); + return true; +} + +template +inline T parseNumber(const char* s) { + VariantData value; + value.init(); // VariantData is a POD, so it has no constructor + parseNumber(s, value); + return Converter::fromJson(VariantConstRef(&value)); +} +} // namespace ARDUINOJSON_NAMESPACE -- cgit v1.2.3