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/parseNumber.hpp | |
parent | 42e7fdf01c3a5701bb51e93ad6c650c3dbbc5450 (diff) |
import ArduinoJson 6.18.0
Diffstat (limited to 'include/lib/ArduinoJson/Numbers/parseNumber.hpp')
-rw-r--r-- | include/lib/ArduinoJson/Numbers/parseNumber.hpp | 153 |
1 files changed, 153 insertions, 0 deletions
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 |