mirror of
https://github.com/eledio-devices/thirdparty-ArduinoJson.git
synced 2025-11-02 00:38:26 +01:00
Added custom implementation of strtod() (issue #453)
This commit is contained in:
@@ -1,66 +0,0 @@
|
||||
// Copyright Benoit Blanchon 2014-2017
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
template <typename TFloat>
|
||||
TFloat parse(const char *);
|
||||
|
||||
template <>
|
||||
inline float parse<float>(const char *s) {
|
||||
return static_cast<float>(strtod(s, NULL));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline double parse<double>(const char *s) {
|
||||
return strtod(s, NULL);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline long parse<long>(const char *s) {
|
||||
return strtol(s, NULL, 10);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned long parse<unsigned long>(const char *s) {
|
||||
return strtoul(s, NULL, 10);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline int parse<int>(const char *s) {
|
||||
return atoi(s);
|
||||
}
|
||||
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
template <>
|
||||
inline long long parse<long long>(const char *s) {
|
||||
return strtoll(s, NULL, 10);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned long long parse<unsigned long long>(const char *s) {
|
||||
return strtoull(s, NULL, 10);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ARDUINOJSON_USE_INT64
|
||||
template <>
|
||||
inline __int64 parse<__int64>(const char *s) {
|
||||
return _strtoi64(s, NULL, 10);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned __int64 parse<unsigned __int64>(const char *s) {
|
||||
return _strtoui64(s, NULL, 10);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "Configuration.hpp"
|
||||
#include "Data/Parse.hpp"
|
||||
#include "JsonArray.hpp"
|
||||
#include "JsonObject.hpp"
|
||||
#include "JsonVariant.hpp"
|
||||
#include "Polyfills/isFloat.hpp"
|
||||
#include "Polyfills/parseFloat.hpp"
|
||||
#include "Polyfills/parseInteger.hpp"
|
||||
|
||||
#include <errno.h> // for errno
|
||||
#include <stdlib.h> // for strtol, strtod
|
||||
@@ -56,14 +58,14 @@ inline Internals::JsonInteger JsonVariant::variantAsInteger() const {
|
||||
case JSON_BOOLEAN:
|
||||
return _content.asInteger;
|
||||
case JSON_NEGATIVE_INTEGER:
|
||||
return -static_cast<Internals::JsonInteger>(_content.asInteger);
|
||||
return -static_cast<JsonInteger>(_content.asInteger);
|
||||
case JSON_STRING:
|
||||
case JSON_UNPARSED:
|
||||
if (!_content.asString) return 0;
|
||||
if (!strcmp("true", _content.asString)) return 1;
|
||||
return parse<Internals::JsonInteger>(_content.asString);
|
||||
return Polyfills::parseInteger<JsonInteger>(_content.asString);
|
||||
default:
|
||||
return static_cast<Internals::JsonInteger>(_content.asFloat);
|
||||
return static_cast<JsonInteger>(_content.asFloat);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,9 +82,9 @@ inline Internals::JsonUInt JsonVariant::asUnsignedInteger() const {
|
||||
case JSON_UNPARSED:
|
||||
if (!_content.asString) return 0;
|
||||
if (!strcmp("true", _content.asString)) return 1;
|
||||
return parse<Internals::JsonUInt>(_content.asString);
|
||||
return Polyfills::parseInteger<JsonUInt>(_content.asString);
|
||||
default:
|
||||
return static_cast<Internals::JsonUInt>(_content.asFloat);
|
||||
return static_cast<JsonUInt>(_content.asFloat);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +109,9 @@ inline Internals::JsonFloat JsonVariant::variantAsFloat() const {
|
||||
return -static_cast<JsonFloat>(_content.asInteger);
|
||||
case JSON_STRING:
|
||||
case JSON_UNPARSED:
|
||||
return _content.asString ? parse<JsonFloat>(_content.asString) : 0;
|
||||
return _content.asString
|
||||
? Polyfills::parseFloat<JsonFloat>(_content.asString)
|
||||
: 0;
|
||||
default:
|
||||
return _content.asFloat;
|
||||
}
|
||||
@@ -143,11 +147,7 @@ inline bool JsonVariant::isFloat() const {
|
||||
|
||||
if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
|
||||
|
||||
char *end;
|
||||
errno = 0;
|
||||
strtod(_content.asString, &end);
|
||||
|
||||
return *end == '\0' && errno == 0 && !is<long>();
|
||||
return Polyfills::isFloat(_content.asString);
|
||||
}
|
||||
|
||||
#if ARDUINOJSON_ENABLE_STD_STREAM
|
||||
|
||||
21
include/ArduinoJson/Polyfills/ctype.hpp
Normal file
21
include/ArduinoJson/Polyfills/ctype.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright Benoit Blanchon 2014-2017
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Polyfills {
|
||||
|
||||
inline bool isdigit(char c) {
|
||||
return '0' <= c && c <= '9';
|
||||
}
|
||||
|
||||
inline bool issign(char c) {
|
||||
return '-' == c || c == '+';
|
||||
}
|
||||
}
|
||||
}
|
||||
40
include/ArduinoJson/Polyfills/isFloat.hpp
Normal file
40
include/ArduinoJson/Polyfills/isFloat.hpp
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright Benoit Blanchon 2014-2017
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "./ctype.hpp"
|
||||
#include "./math.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Polyfills {
|
||||
|
||||
inline bool isFloat(const char* s) {
|
||||
if (!strcmp(s, "NaN")) return true;
|
||||
if (issign(*s)) s++;
|
||||
if (!strcmp(s, "Infinity")) return true;
|
||||
|
||||
while (isdigit(*s)) s++;
|
||||
|
||||
bool has_dot = *s == '.';
|
||||
if (has_dot) {
|
||||
s++;
|
||||
while (isdigit(*s)) s++;
|
||||
}
|
||||
|
||||
bool has_exponent = *s == 'e' || *s == 'E';
|
||||
if (has_exponent) {
|
||||
s++;
|
||||
if (issign(*s)) s++;
|
||||
if (!isdigit(*s)) return false;
|
||||
while (isdigit(*s)) s++;
|
||||
}
|
||||
|
||||
return (has_dot || has_exponent) && *s == '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// If Visual Studo <= 2012
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1700
|
||||
// If Visual Studo
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
#include <float.h>
|
||||
#include <limits>
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Polyfills {
|
||||
@@ -23,6 +24,16 @@ template <typename T>
|
||||
bool isInfinity(T x) {
|
||||
return !_finite(x);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T nan() {
|
||||
return std::numeric_limits<T>::quiet_NaN();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T inf() {
|
||||
return std::numeric_limits<T>::infinity();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,6 +112,16 @@ inline bool isInfinity<float>(float x) {
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
T nan() {
|
||||
return static_cast<T>(NAN);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T inf() {
|
||||
return static_cast<T>(INFINITY);
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
87
include/ArduinoJson/Polyfills/parseFloat.hpp
Normal file
87
include/ArduinoJson/Polyfills/parseFloat.hpp
Normal file
@@ -0,0 +1,87 @@
|
||||
// Copyright Benoit Blanchon 2014-2017
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../TypeTraits/FloatTraits.hpp"
|
||||
#include "./ctype.hpp"
|
||||
#include "./math.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Polyfills {
|
||||
|
||||
template <typename T>
|
||||
inline T parseFloat(const char* s) {
|
||||
typedef TypeTraits::FloatTraits<T> traits;
|
||||
typedef typename traits::mantissa_type mantissa_t;
|
||||
typedef typename traits::exponent_type exponent_t;
|
||||
|
||||
bool negative_result = false;
|
||||
switch (*s) {
|
||||
case '-':
|
||||
negative_result = true;
|
||||
case '+':
|
||||
s++;
|
||||
}
|
||||
|
||||
if (*s == 'n' || *s == 'N') return traits::nan();
|
||||
if (*s == 'i' || *s == 'I')
|
||||
return negative_result ? -traits::inf() : traits::inf();
|
||||
|
||||
mantissa_t mantissa = 0;
|
||||
exponent_t exponent_offset = 0;
|
||||
|
||||
while (isdigit(*s)) {
|
||||
if (mantissa < traits::mantissa_max / 10)
|
||||
mantissa = mantissa * 10 + (*s - '0');
|
||||
else
|
||||
exponent_offset++;
|
||||
s++;
|
||||
}
|
||||
|
||||
if (*s == '.') {
|
||||
s++;
|
||||
while (isdigit(*s)) {
|
||||
if (mantissa < traits::mantissa_max / 10) {
|
||||
mantissa = mantissa * 10 + (*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)
|
||||
return negative_result ? -0.0f : 0.0f;
|
||||
else
|
||||
return negative_result ? -traits::inf() : traits::inf();
|
||||
}
|
||||
s++;
|
||||
}
|
||||
if (negative_exponent) exponent = -exponent;
|
||||
}
|
||||
exponent += exponent_offset;
|
||||
|
||||
T result = traits::make_float(static_cast<T>(mantissa), exponent);
|
||||
|
||||
return negative_result ? -result : result;
|
||||
}
|
||||
}
|
||||
}
|
||||
56
include/ArduinoJson/Polyfills/parseInteger.hpp
Normal file
56
include/ArduinoJson/Polyfills/parseInteger.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright Benoit Blanchon 2014-2017
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Polyfills {
|
||||
template <typename T>
|
||||
T parseInteger(const char *s);
|
||||
|
||||
template <>
|
||||
inline long parseInteger<long>(const char *s) {
|
||||
return ::strtol(s, NULL, 10);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned long parseInteger<unsigned long>(const char *s) {
|
||||
return ::strtoul(s, NULL, 10);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline int parseInteger<int>(const char *s) {
|
||||
return ::atoi(s);
|
||||
}
|
||||
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
template <>
|
||||
inline long long parseInteger<long long>(const char *s) {
|
||||
return ::strtoll(s, NULL, 10);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned long long parseInteger<unsigned long long>(const char *s) {
|
||||
return ::strtoull(s, NULL, 10);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ARDUINOJSON_USE_INT64
|
||||
template <>
|
||||
inline __int64 parseInteger<__int64>(const char *s) {
|
||||
return ::_strtoi64(s, NULL, 10);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned __int64 parseInteger<unsigned __int64>(const char *s) {
|
||||
return ::_strtoui64(s, NULL, 10);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
83
include/ArduinoJson/TypeTraits/FloatTraits.hpp
Normal file
83
include/ArduinoJson/TypeTraits/FloatTraits.hpp
Normal file
@@ -0,0 +1,83 @@
|
||||
// Copyright Benoit Blanchon 2014-2017
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "../Polyfills/math.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace TypeTraits {
|
||||
|
||||
template <typename T, size_t = sizeof(T)>
|
||||
struct FloatTraits {};
|
||||
|
||||
#ifndef ARDUINO_ARCH_AVR // double is 32 bits, so 1e64 gives a warning
|
||||
template <typename T>
|
||||
struct FloatTraits<T, 8 /*64bits*/> {
|
||||
typedef int64_t mantissa_type;
|
||||
static const short mantissa_bits = 52;
|
||||
static const mantissa_type mantissa_max =
|
||||
(static_cast<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)
|
||||
return m * (e & 1 ? 1e1 : 1) * (e & 2 ? 1e2 : 1) * (e & 4 ? 1e4 : 1) *
|
||||
(e & 8 ? 1e8 : 1) * (e & 16 ? 1e16 : 1) * (e & 32 ? 1e32 : 1) *
|
||||
(e & 64 ? 1e64 : 1) * (e & 128 ? 1e128 : 1) *
|
||||
(e & 256 ? 1e256 : 1);
|
||||
e = -e;
|
||||
return m * (e & 1 ? 1e-1 : 1) * (e & 2 ? 1e-2 : 1) * (e & 4 ? 1e-4 : 1) *
|
||||
(e & 8 ? 1e-8 : 1) * (e & 16 ? 1e-16 : 1) * (e & 32 ? 1e-32 : 1) *
|
||||
(e & 64 ? 1e-64 : 1) * (e & 128 ? 1e-128 : 1) *
|
||||
(e & 256 ? 1e-256 : 1);
|
||||
}
|
||||
|
||||
static T nan() {
|
||||
return Polyfills::nan<T>();
|
||||
}
|
||||
|
||||
static T inf() {
|
||||
return Polyfills::inf<T>();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
struct FloatTraits<T, 4 /*32bits*/> {
|
||||
typedef int32_t mantissa_type;
|
||||
static const short mantissa_bits = 23;
|
||||
static const mantissa_type mantissa_max =
|
||||
(static_cast<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)
|
||||
return m * (e & 1 ? 1e1f : 1) * (e & 2 ? 1e2f : 1) * (e & 4 ? 1e4f : 1) *
|
||||
(e & 8 ? 1e8f : 1) * (e & 16 ? 1e16f : 1) * (e & 32 ? 1e32f : 1);
|
||||
e = -e;
|
||||
return m * (e & 1 ? 1e-1f : 1) * (e & 2 ? 1e-2f : 1) * (e & 4 ? 1e-4f : 1) *
|
||||
(e & 8 ? 1e-8f : 1) * (e & 16 ? 1e-16f : 1) * (e & 32 ? 1e-32f : 1);
|
||||
}
|
||||
|
||||
static T nan() {
|
||||
return Polyfills::nan<T>();
|
||||
}
|
||||
|
||||
static T inf() {
|
||||
return Polyfills::inf<T>();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user