Fix 9.22337e+18 outside range of representable values of type 'long'

This commit is contained in:
Benoit Blanchon
2022-04-07 20:58:54 +02:00
parent c9fbc5e40a
commit ccfbb5fd1d
6 changed files with 139 additions and 5 deletions

View File

@ -12,6 +12,7 @@
#include <ArduinoJson/Polyfills/math.hpp>
#include <ArduinoJson/Polyfills/preprocessor.hpp>
#include <ArduinoJson/Polyfills/static_array.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp>
namespace ARDUINOJSON_NAMESPACE {
@ -116,6 +117,22 @@ struct FloatTraits<T, 8 /*64bits*/> {
return forge(0x7FEFFFFF, 0xFFFFFFFF);
}
template <typename TOut> // int64_t
static T highest_for(
typename enable_if<is_integral<TOut>::value && is_signed<TOut>::value &&
sizeof(TOut) == 8,
signed>::type* = 0) {
return forge(0x43DFFFFF, 0xFFFFFFFF); // 9.2233720368547748e+18
}
template <typename TOut> // uint64_t
static T highest_for(
typename enable_if<is_integral<TOut>::value && is_unsigned<TOut>::value &&
sizeof(TOut) == 8,
unsigned>::type* = 0) {
return forge(0x43EFFFFF, 0xFFFFFFFF); // 1.8446744073709549568e+19
}
static T lowest() {
return forge(0xFFEFFFFF, 0xFFFFFFFF);
}
@ -212,6 +229,38 @@ struct FloatTraits<T, 4 /*32bits*/> {
return forge(0x7f7fffff);
}
template <typename TOut> // int32_t
static T highest_for(
typename enable_if<is_integral<TOut>::value && is_signed<TOut>::value &&
sizeof(TOut) == 4,
signed>::type* = 0) {
return forge(0x4EFFFFFF); // 2.14748352E9
}
template <typename TOut> // uint32_t
static T highest_for(
typename enable_if<is_integral<TOut>::value && is_unsigned<TOut>::value &&
sizeof(TOut) == 4,
unsigned>::type* = 0) {
return forge(0x4F7FFFFF); // 4.29496704E9
}
template <typename TOut> // int64_t
static T highest_for(
typename enable_if<is_integral<TOut>::value && is_signed<TOut>::value &&
sizeof(TOut) == 8,
signed>::type* = 0) {
return forge(0x5EFFFFFF); // 9.22337148709896192E18
}
template <typename TOut> // uint64_t
static T highest_for(
typename enable_if<is_integral<TOut>::value && is_unsigned<TOut>::value &&
sizeof(TOut) == 8,
unsigned>::type* = 0) {
return forge(0x5F7FFFFF); // 1.844674297419792384E19
}
static T lowest() {
return forge(0xFf7fffff);
}

View File

@ -15,6 +15,7 @@
#endif
#include <ArduinoJson/Numbers/Float.hpp>
#include <ArduinoJson/Numbers/FloatTraits.hpp>
#include <ArduinoJson/Polyfills/limits.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp>
@ -95,17 +96,34 @@ canConvertNumber(TIn value) {
return value <= TIn(numeric_limits<TOut>::highest());
}
// float -> int32
// float -> int64
// float32 -> int16
// float64 -> int32
template <typename TOut, typename TIn>
typename enable_if<is_floating_point<TIn>::value &&
!is_floating_point<TOut>::value,
typename enable_if<is_floating_point<TIn>::value && is_integral<TOut>::value &&
sizeof(TOut) < sizeof(TIn),
bool>::type
canConvertNumber(TIn value) {
return value >= numeric_limits<TOut>::lowest() &&
value <= numeric_limits<TOut>::highest();
}
// float32 -> int32
// float32 -> uint32
// float32 -> int64
// float32 -> uint64
// float64 -> int64
// float64 -> uint64
template <typename TOut, typename TIn>
typename enable_if<is_floating_point<TIn>::value && is_integral<TOut>::value &&
sizeof(TOut) >= sizeof(TIn),
bool>::type
canConvertNumber(TIn value) {
// Avoid error "9.22337e+18 is outside the range of representable values of
// type 'long'"
return value >= numeric_limits<TOut>::lowest() &&
value <= FloatTraits<TIn>::template highest_for<TOut>();
}
template <typename TOut, typename TIn>
TOut convertNumber(TIn value) {
return canConvertNumber<TOut>(value) ? TOut(value) : 0;