forked from bblanchon/ArduinoJson
Added overflow handling in JsonVariant::as<T>() and JsonVariant::is<T>()
This commit is contained in:
@ -6,8 +6,7 @@
|
||||
|
||||
#include "../Deserialization/deserialize.hpp"
|
||||
#include "../Memory/MemoryPool.hpp"
|
||||
#include "../Numbers/isFloat.hpp"
|
||||
#include "../Numbers/isInteger.hpp"
|
||||
#include "../Numbers/parseNumber.hpp"
|
||||
#include "../Polyfills/type_traits.hpp"
|
||||
#include "../Variant/VariantData.hpp"
|
||||
#include "EscapeSequence.hpp"
|
||||
@ -251,14 +250,6 @@ class JsonDeserializer {
|
||||
}
|
||||
buffer[n] = 0;
|
||||
|
||||
if (isInteger(buffer)) {
|
||||
result.setInteger(parseInteger<Integer>(buffer));
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
if (isFloat(buffer)) {
|
||||
result.setFloat(parseFloat<Float>(buffer));
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
c = buffer[0];
|
||||
if (c == 't') { // true
|
||||
result.setBoolean(true);
|
||||
@ -275,6 +266,23 @@ class JsonDeserializer {
|
||||
return n == 4 ? DeserializationError::Ok
|
||||
: DeserializationError::IncompleteInput;
|
||||
}
|
||||
|
||||
ParsedNumber<Float, UInt> num = parseNumber<Float, UInt>(buffer);
|
||||
|
||||
switch (num.type()) {
|
||||
case VALUE_IS_NEGATIVE_INTEGER:
|
||||
result.setNegativeInteger(num.uintValue);
|
||||
return DeserializationError::Ok;
|
||||
|
||||
case VALUE_IS_POSITIVE_INTEGER:
|
||||
result.setPositiveInteger(num.uintValue);
|
||||
return DeserializationError::Ok;
|
||||
|
||||
case VALUE_IS_FLOAT:
|
||||
result.setFloat(num.floatValue);
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
return DeserializationError::InvalidInput;
|
||||
}
|
||||
|
||||
|
@ -79,8 +79,7 @@ class MsgPackDeserializer {
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
return readInteger<uint64_t>(variant);
|
||||
#else
|
||||
readInteger<uint32_t>();
|
||||
return readInteger<uint32_t>(variant);
|
||||
return DeserializationError::NotSupported;
|
||||
#endif
|
||||
|
||||
case 0xd0:
|
||||
@ -96,8 +95,7 @@ class MsgPackDeserializer {
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
return readInteger<int64_t>(variant);
|
||||
#else
|
||||
if (!skip(4)) return DeserializationError::IncompleteInput;
|
||||
return readInteger<int32_t>(variant);
|
||||
return DeserializationError::NotSupported;
|
||||
#endif
|
||||
|
||||
case 0xca:
|
||||
|
@ -24,7 +24,8 @@ class MsgPackSerializer {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<sizeof(T) == 8>::type visitFloat(T value64) {
|
||||
typename enable_if<sizeof(T) == 8>::type visitFloat(T value64)
|
||||
ARDUINOJSON_NO_SANITIZE("float-cast-overflow") {
|
||||
float value32 = float(value64);
|
||||
if (value32 == value64) {
|
||||
writeByte(0xCA);
|
||||
|
@ -17,10 +17,10 @@ struct FloatTraits {};
|
||||
|
||||
template <typename T>
|
||||
struct FloatTraits<T, 8 /*64bits*/> {
|
||||
typedef int64_t mantissa_type;
|
||||
typedef uint64_t mantissa_type;
|
||||
static const short mantissa_bits = 52;
|
||||
static const mantissa_type mantissa_max =
|
||||
(static_cast<mantissa_type>(1) << mantissa_bits) - 1;
|
||||
(mantissa_type(1) << mantissa_bits) - 1;
|
||||
|
||||
typedef int16_t exponent_type;
|
||||
static const exponent_type exponent_max = 308;
|
||||
@ -95,6 +95,14 @@ struct FloatTraits<T, 8 /*64bits*/> {
|
||||
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)
|
||||
@ -105,10 +113,10 @@ struct FloatTraits<T, 8 /*64bits*/> {
|
||||
|
||||
template <typename T>
|
||||
struct FloatTraits<T, 4 /*32bits*/> {
|
||||
typedef int32_t mantissa_type;
|
||||
typedef uint32_t mantissa_type;
|
||||
static const short mantissa_bits = 23;
|
||||
static const mantissa_type mantissa_max =
|
||||
(static_cast<mantissa_type>(1) << mantissa_bits) - 1;
|
||||
(mantissa_type(1) << mantissa_bits) - 1;
|
||||
|
||||
typedef int8_t exponent_type;
|
||||
static const exponent_type exponent_max = 38;
|
||||
@ -156,5 +164,13 @@ struct FloatTraits<T, 4 /*32bits*/> {
|
||||
static T inf() {
|
||||
return forge(0x7f800000);
|
||||
}
|
||||
|
||||
static T highest() {
|
||||
return forge(0x7f7fffff);
|
||||
}
|
||||
|
||||
static T lowest() {
|
||||
return forge(0xFf7fffff);
|
||||
}
|
||||
};
|
||||
} // namespace ARDUINOJSON_NAMESPACE
|
||||
|
105
src/ArduinoJson/Numbers/convertNumber.hpp
Normal file
105
src/ArduinoJson/Numbers/convertNumber.hpp
Normal file
@ -0,0 +1,105 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2019
|
||||
// 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 "../Polyfills/limits.hpp"
|
||||
#include "Float.hpp"
|
||||
#include "FloatTraits.hpp"
|
||||
#include "Integer.hpp"
|
||||
|
||||
namespace ARDUINOJSON_NAMESPACE {
|
||||
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_integral<TOut>::value && sizeof(TOut) <= sizeof(TIn),
|
||||
bool>::type
|
||||
canStorePositiveInteger(TIn value) {
|
||||
return value <= TIn(numeric_limits<TOut>::highest());
|
||||
}
|
||||
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_integral<TOut>::value && sizeof(TIn) < sizeof(TOut),
|
||||
bool>::type
|
||||
canStorePositiveInteger(TIn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_floating_point<TOut>::value, bool>::type
|
||||
canStorePositiveInteger(TIn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_floating_point<TOut>::value, bool>::type
|
||||
canStoreNegativeInteger(TIn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_integral<TOut>::value && is_signed<TOut>::value &&
|
||||
sizeof(TOut) <= sizeof(TIn),
|
||||
bool>::type
|
||||
canStoreNegativeInteger(TIn value) {
|
||||
return value <= TIn(numeric_limits<TOut>::highest()) + 1;
|
||||
}
|
||||
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_integral<TOut>::value && is_signed<TOut>::value &&
|
||||
sizeof(TIn) < sizeof(TOut),
|
||||
bool>::type
|
||||
canStoreNegativeInteger(TIn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_integral<TOut>::value && is_unsigned<TOut>::value,
|
||||
bool>::type
|
||||
canStoreNegativeInteger(TIn) {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename TOut, typename TIn>
|
||||
TOut convertPositiveInteger(TIn value) {
|
||||
return canStorePositiveInteger<TOut>(value) ? TOut(value) : 0;
|
||||
}
|
||||
|
||||
template <typename TOut, typename TIn>
|
||||
TOut convertNegativeInteger(TIn value) {
|
||||
return canStoreNegativeInteger<TOut>(value) ? TOut(~value + 1) : 0;
|
||||
}
|
||||
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<is_floating_point<TOut>::value, TOut>::type convertFloat(
|
||||
TIn value) {
|
||||
return TOut(value);
|
||||
}
|
||||
|
||||
template <typename TOut, typename TIn>
|
||||
typename enable_if<!is_floating_point<TOut>::value, TOut>::type convertFloat(
|
||||
TIn value) {
|
||||
return value >= numeric_limits<TOut>::lowest() &&
|
||||
value <= numeric_limits<TOut>::highest()
|
||||
? 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
|
@ -1,36 +0,0 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2019
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string.h> // for strcmp
|
||||
#include "../Polyfills/ctype.hpp"
|
||||
|
||||
namespace ARDUINOJSON_NAMESPACE {
|
||||
|
||||
inline bool isFloat(const char* s) {
|
||||
if (!s) return false;
|
||||
|
||||
if (!strcmp(s, "NaN")) return true;
|
||||
if (issign(*s)) s++;
|
||||
if (!strcmp(s, "Infinity")) return true;
|
||||
if (*s == '\0') return false;
|
||||
|
||||
while (isdigit(*s)) s++;
|
||||
|
||||
if (*s == '.') {
|
||||
s++;
|
||||
while (isdigit(*s)) s++;
|
||||
}
|
||||
|
||||
if (*s == 'e' || *s == 'E') {
|
||||
s++;
|
||||
if (issign(*s)) s++;
|
||||
if (!isdigit(*s)) return false;
|
||||
while (isdigit(*s)) s++;
|
||||
}
|
||||
|
||||
return *s == '\0';
|
||||
}
|
||||
} // namespace ARDUINOJSON_NAMESPACE
|
@ -1,17 +0,0 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2019
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Polyfills/ctype.hpp"
|
||||
|
||||
namespace ARDUINOJSON_NAMESPACE {
|
||||
|
||||
inline bool isInteger(const char* s) {
|
||||
if (!s || !*s) return false;
|
||||
if (issign(*s)) s++;
|
||||
while (isdigit(*s)) s++;
|
||||
return *s == '\0';
|
||||
}
|
||||
} // namespace ARDUINOJSON_NAMESPACE
|
@ -4,85 +4,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Numbers/FloatTraits.hpp"
|
||||
#include "../Polyfills/ctype.hpp"
|
||||
#include "../Polyfills/math.hpp"
|
||||
#include "convertNumber.hpp"
|
||||
#include "parseNumber.hpp"
|
||||
|
||||
namespace ARDUINOJSON_NAMESPACE {
|
||||
|
||||
template <typename T>
|
||||
inline T parseFloat(const char* s) {
|
||||
typedef FloatTraits<T> traits;
|
||||
typedef typename traits::mantissa_type mantissa_t;
|
||||
typedef typename traits::exponent_type exponent_t;
|
||||
|
||||
if (!s) return 0; // NULL
|
||||
|
||||
bool negative_result = false;
|
||||
switch (*s) {
|
||||
case '-':
|
||||
negative_result = true;
|
||||
s++;
|
||||
break;
|
||||
case '+':
|
||||
s++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*s == 't') return 1; // true
|
||||
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;
|
||||
// try to reuse the same parameters as JsonDeserializer
|
||||
typedef typename choose_largest<Float, T>::type TFloat;
|
||||
return parseNumber<TFloat, UInt>(s).template as<T>();
|
||||
}
|
||||
} // namespace ARDUINOJSON_NAMESPACE
|
||||
|
@ -4,34 +4,16 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Configuration.hpp"
|
||||
#include "../Polyfills/ctype.hpp"
|
||||
#include "../Polyfills/type_traits.hpp"
|
||||
#include "convertNumber.hpp"
|
||||
#include "parseNumber.hpp"
|
||||
|
||||
namespace ARDUINOJSON_NAMESPACE {
|
||||
template <typename T>
|
||||
T parseInteger(const char *s) {
|
||||
if (!s) return 0; // NULL
|
||||
|
||||
if (*s == 't') return 1; // "true"
|
||||
|
||||
T result = 0;
|
||||
bool negative_result = false;
|
||||
|
||||
switch (*s) {
|
||||
case '-':
|
||||
negative_result = true;
|
||||
s++;
|
||||
break;
|
||||
case '+':
|
||||
s++;
|
||||
break;
|
||||
}
|
||||
|
||||
while (isdigit(*s)) {
|
||||
result = T(result * 10 + T(*s - '0'));
|
||||
s++;
|
||||
}
|
||||
|
||||
return negative_result ? T(~result + 1) : result;
|
||||
// try to reuse the same parameters as JsonDeserializer
|
||||
typedef typename choose_largest<UInt, typename make_unsigned<T>::type>::type
|
||||
TUInt;
|
||||
return parseNumber<Float, TUInt>(s).template as<T>();
|
||||
}
|
||||
} // namespace ARDUINOJSON_NAMESPACE
|
||||
|
147
src/ArduinoJson/Numbers/parseNumber.hpp
Normal file
147
src/ArduinoJson/Numbers/parseNumber.hpp
Normal file
@ -0,0 +1,147 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2019
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Polyfills/assert.hpp"
|
||||
#include "../Polyfills/ctype.hpp"
|
||||
#include "../Polyfills/math.hpp"
|
||||
#include "../Polyfills/type_traits.hpp"
|
||||
#include "../Variant/VariantContent.hpp"
|
||||
#include "FloatTraits.hpp"
|
||||
#include "convertNumber.hpp"
|
||||
|
||||
namespace ARDUINOJSON_NAMESPACE {
|
||||
|
||||
template <typename TFloat, typename TUInt>
|
||||
struct ParsedNumber {
|
||||
ParsedNumber() : uintValue(0), floatValue(0), _type(VALUE_IS_NULL) {}
|
||||
|
||||
ParsedNumber(TUInt value, bool is_negative)
|
||||
: uintValue(value),
|
||||
floatValue(TFloat(value)),
|
||||
_type(uint8_t(is_negative ? VALUE_IS_NEGATIVE_INTEGER
|
||||
: VALUE_IS_POSITIVE_INTEGER)) {}
|
||||
ParsedNumber(TFloat value) : floatValue(value), _type(VALUE_IS_FLOAT) {}
|
||||
|
||||
template <typename T>
|
||||
T as() const {
|
||||
switch (_type) {
|
||||
case VALUE_IS_NEGATIVE_INTEGER:
|
||||
return convertNegativeInteger<T>(uintValue);
|
||||
case VALUE_IS_POSITIVE_INTEGER:
|
||||
return convertPositiveInteger<T>(uintValue);
|
||||
case VALUE_IS_FLOAT:
|
||||
return convertFloat<T>(floatValue);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t type() const {
|
||||
return _type;
|
||||
}
|
||||
|
||||
TUInt uintValue;
|
||||
TFloat floatValue;
|
||||
uint8_t _type;
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
struct choose_largest : conditional<(sizeof(A) > sizeof(B)), A, B> {};
|
||||
|
||||
template <typename TFloat, typename TUInt>
|
||||
inline ParsedNumber<TFloat, TUInt> parseNumber(const char *s) {
|
||||
typedef FloatTraits<TFloat> traits;
|
||||
typedef typename choose_largest<typename traits::mantissa_type, TUInt>::type
|
||||
mantissa_t;
|
||||
typedef typename traits::exponent_type exponent_t;
|
||||
typedef ParsedNumber<TFloat, TUInt> return_type;
|
||||
|
||||
ARDUINOJSON_ASSERT(s != 0);
|
||||
|
||||
bool is_negative = false;
|
||||
switch (*s) {
|
||||
case '-':
|
||||
is_negative = true;
|
||||
s++;
|
||||
break;
|
||||
case '+':
|
||||
s++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*s == 'n' || *s == 'N') return traits::nan();
|
||||
if (*s == 'i' || *s == 'I')
|
||||
return is_negative ? -traits::inf() : traits::inf();
|
||||
if (!isdigit(*s) && *s != '.') return return_type();
|
||||
|
||||
mantissa_t mantissa = 0;
|
||||
exponent_t exponent_offset = 0;
|
||||
const mantissa_t maxUint = TUInt(-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') return return_type(TUInt(mantissa), is_negative);
|
||||
|
||||
// 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)
|
||||
return is_negative ? -0.0f : 0.0f;
|
||||
else
|
||||
return is_negative ? -traits::inf() : traits::inf();
|
||||
}
|
||||
s++;
|
||||
}
|
||||
if (negative_exponent) exponent = -exponent;
|
||||
}
|
||||
exponent += exponent_offset;
|
||||
|
||||
TFloat result = traits::make_float(static_cast<TFloat>(mantissa), exponent);
|
||||
|
||||
return is_negative ? -result : result;
|
||||
}
|
||||
} // namespace ARDUINOJSON_NAMESPACE
|
@ -33,3 +33,13 @@
|
||||
#else
|
||||
#define NOEXCEPT throw()
|
||||
#endif
|
||||
|
||||
#if defined(__has_attribute)
|
||||
#if __has_attribute(no_sanitize)
|
||||
#define ARDUINOJSON_NO_SANITIZE(check) __attribute__((no_sanitize(check)))
|
||||
#else
|
||||
#define ARDUINOJSON_NO_SANITIZE(check)
|
||||
#endif
|
||||
#else
|
||||
#define ARDUINOJSON_NO_SANITIZE(check)
|
||||
#endif
|
||||
|
45
src/ArduinoJson/Polyfills/limits.hpp
Normal file
45
src/ArduinoJson/Polyfills/limits.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2019
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Polyfills/type_traits.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4310)
|
||||
#endif
|
||||
|
||||
namespace ARDUINOJSON_NAMESPACE {
|
||||
|
||||
// Differs from standard because we can't use the symbols "min" and "max"
|
||||
template <typename T, typename Enable = void>
|
||||
struct numeric_limits;
|
||||
|
||||
template <typename T>
|
||||
struct numeric_limits<T, typename enable_if<is_unsigned<T>::value>::type> {
|
||||
static T lowest() {
|
||||
return 0;
|
||||
}
|
||||
static T highest() {
|
||||
return T(-1);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct numeric_limits<
|
||||
T, typename enable_if<is_integral<T>::value && is_signed<T>::value>::type> {
|
||||
static T lowest() {
|
||||
return T(T(1) << (sizeof(T) * 8 - 1));
|
||||
}
|
||||
static T highest() {
|
||||
return T(~lowest());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ARDUINOJSON_NAMESPACE
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
@ -15,5 +15,6 @@
|
||||
#include "type_traits/is_same.hpp"
|
||||
#include "type_traits/is_signed.hpp"
|
||||
#include "type_traits/is_unsigned.hpp"
|
||||
#include "type_traits/make_unsigned.hpp"
|
||||
#include "type_traits/remove_const.hpp"
|
||||
#include "type_traits/remove_reference.hpp"
|
||||
|
49
src/ArduinoJson/Polyfills/type_traits/make_unsigned.hpp
Normal file
49
src/ArduinoJson/Polyfills/type_traits/make_unsigned.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2019
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "type_identity.hpp"
|
||||
namespace ARDUINOJSON_NAMESPACE {
|
||||
|
||||
template <typename T>
|
||||
struct make_unsigned;
|
||||
|
||||
template <>
|
||||
struct make_unsigned<char> : type_identity<unsigned char> {};
|
||||
|
||||
template <>
|
||||
struct make_unsigned<signed char> : type_identity<unsigned char> {};
|
||||
template <>
|
||||
struct make_unsigned<unsigned char> : type_identity<unsigned char> {};
|
||||
|
||||
template <>
|
||||
struct make_unsigned<signed short> : type_identity<unsigned short> {};
|
||||
template <>
|
||||
struct make_unsigned<unsigned short> : type_identity<unsigned short> {};
|
||||
|
||||
template <>
|
||||
struct make_unsigned<signed int> : type_identity<unsigned int> {};
|
||||
template <>
|
||||
struct make_unsigned<unsigned int> : type_identity<unsigned int> {};
|
||||
|
||||
template <>
|
||||
struct make_unsigned<signed long> : type_identity<unsigned long> {};
|
||||
template <>
|
||||
struct make_unsigned<unsigned long> : type_identity<unsigned long> {};
|
||||
|
||||
#if ARDUINOJSON_HAS_LONG_LONG
|
||||
template <>
|
||||
struct make_unsigned<signed long long> : type_identity<unsigned long long> {};
|
||||
template <>
|
||||
struct make_unsigned<unsigned long long> : type_identity<unsigned long long> {};
|
||||
#endif
|
||||
|
||||
#if ARDUINOJSON_HAS_INT64
|
||||
template <>
|
||||
struct make_unsigned<signed __int64> : type_identity<unsigned __int64> {};
|
||||
template <>
|
||||
struct make_unsigned<unsigned __int64> : type_identity<unsigned __int64> {};
|
||||
#endif
|
||||
} // namespace ARDUINOJSON_NAMESPACE
|
15
src/ArduinoJson/Polyfills/type_traits/type_identity.hpp
Normal file
15
src/ArduinoJson/Polyfills/type_traits/type_identity.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
// ArduinoJson - arduinojson.org
|
||||
// Copyright Benoit Blanchon 2014-2019
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "integral_constant.hpp"
|
||||
|
||||
namespace ARDUINOJSON_NAMESPACE {
|
||||
|
||||
template <typename T>
|
||||
struct type_identity {
|
||||
typedef T type;
|
||||
};
|
||||
} // namespace ARDUINOJSON_NAMESPACE
|
@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Misc/SerializedValue.hpp"
|
||||
#include "../Numbers/convertNumber.hpp"
|
||||
#include "../Polyfills/gsl/not_null.hpp"
|
||||
#include "VariantContent.hpp"
|
||||
|
||||
@ -63,9 +64,7 @@ class VariantData {
|
||||
|
||||
const char *asString() const;
|
||||
|
||||
bool asBoolean() const {
|
||||
return asIntegral<int>() != 0;
|
||||
}
|
||||
bool asBoolean() const;
|
||||
|
||||
CollectionData *asArray() {
|
||||
return isArray() ? &_content.asCollection : 0;
|
||||
@ -147,9 +146,18 @@ class VariantData {
|
||||
return (_flags & COLLECTION_MASK) != 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool isInteger() const {
|
||||
return type() == VALUE_IS_POSITIVE_INTEGER ||
|
||||
type() == VALUE_IS_NEGATIVE_INTEGER;
|
||||
switch (type()) {
|
||||
case VALUE_IS_POSITIVE_INTEGER:
|
||||
return canStorePositiveInteger<T>(_content.asInteger);
|
||||
|
||||
case VALUE_IS_NEGATIVE_INTEGER:
|
||||
return canStoreNegativeInteger<T>(_content.asInteger);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool isFloat() const {
|
||||
@ -225,14 +233,22 @@ class VariantData {
|
||||
template <typename T>
|
||||
void setSignedInteger(T value) {
|
||||
if (value >= 0) {
|
||||
setType(VALUE_IS_POSITIVE_INTEGER);
|
||||
_content.asInteger = static_cast<UInt>(value);
|
||||
setPositiveInteger(static_cast<UInt>(value));
|
||||
} else {
|
||||
setType(VALUE_IS_NEGATIVE_INTEGER);
|
||||
_content.asInteger = ~static_cast<UInt>(value) + 1;
|
||||
setNegativeInteger(~static_cast<UInt>(value) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void setPositiveInteger(UInt value) {
|
||||
setType(VALUE_IS_POSITIVE_INTEGER);
|
||||
_content.asInteger = value;
|
||||
}
|
||||
|
||||
void setNegativeInteger(UInt value) {
|
||||
setType(VALUE_IS_NEGATIVE_INTEGER);
|
||||
_content.asInteger = value;
|
||||
}
|
||||
|
||||
void setLinkedString(const char *value) {
|
||||
if (value) {
|
||||
setType(VALUE_IS_LINKED_STRING);
|
||||
|
@ -52,8 +52,9 @@ inline bool variantIsBoolean(const VariantData *var) {
|
||||
return var && var->isBoolean();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool variantIsInteger(const VariantData *var) {
|
||||
return var && var->isInteger();
|
||||
return var && var->isInteger<T>();
|
||||
}
|
||||
|
||||
inline bool variantIsFloat(const VariantData *var) {
|
||||
|
@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Configuration.hpp"
|
||||
#include "../Numbers/convertNumber.hpp"
|
||||
#include "../Numbers/parseFloat.hpp"
|
||||
#include "../Numbers/parseInteger.hpp"
|
||||
#include "VariantRef.hpp"
|
||||
@ -18,19 +19,35 @@ inline T VariantData::asIntegral() const {
|
||||
switch (type()) {
|
||||
case VALUE_IS_POSITIVE_INTEGER:
|
||||
case VALUE_IS_BOOLEAN:
|
||||
return T(_content.asInteger);
|
||||
return convertPositiveInteger<T>(_content.asInteger);
|
||||
case VALUE_IS_NEGATIVE_INTEGER:
|
||||
return T(~_content.asInteger + 1);
|
||||
return convertNegativeInteger<T>(_content.asInteger);
|
||||
case VALUE_IS_LINKED_STRING:
|
||||
case VALUE_IS_OWNED_STRING:
|
||||
return parseInteger<T>(_content.asString);
|
||||
case VALUE_IS_FLOAT:
|
||||
return T(_content.asFloat);
|
||||
return convertFloat<T>(_content.asFloat);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool VariantData::asBoolean() const {
|
||||
switch (type()) {
|
||||
case VALUE_IS_POSITIVE_INTEGER:
|
||||
case VALUE_IS_BOOLEAN:
|
||||
case VALUE_IS_NEGATIVE_INTEGER:
|
||||
return _content.asInteger != 0;
|
||||
case VALUE_IS_FLOAT:
|
||||
return _content.asFloat != 0;
|
||||
case VALUE_IS_LINKED_STRING:
|
||||
case VALUE_IS_OWNED_STRING:
|
||||
return strcmp("true", _content.asString) == 0;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// T = float/double
|
||||
template <typename T>
|
||||
inline T VariantData::asFloat() const {
|
||||
|
@ -9,8 +9,6 @@
|
||||
|
||||
#include "../Memory/MemoryPool.hpp"
|
||||
#include "../Misc/Visitable.hpp"
|
||||
#include "../Numbers/parseFloat.hpp"
|
||||
#include "../Numbers/parseInteger.hpp"
|
||||
#include "../Operators/VariantOperators.hpp"
|
||||
#include "../Polyfills/type_traits.hpp"
|
||||
#include "VariantAs.hpp"
|
||||
@ -45,7 +43,7 @@ class VariantRefBase {
|
||||
template <typename T>
|
||||
FORCE_INLINE typename enable_if<is_integral<T>::value, bool>::type is()
|
||||
const {
|
||||
return variantIsInteger(_data);
|
||||
return variantIsInteger<T>(_data);
|
||||
}
|
||||
//
|
||||
// bool is<double>() const;
|
||||
|
Reference in New Issue
Block a user