mirror of
https://github.com/bblanchon/ArduinoJson.git
synced 2025-07-16 20:12:16 +02:00
Changed integer storage from positive/negative to signed/unsigned
This commit is contained in:
@ -76,11 +76,28 @@ TEST_CASE("JsonVariant::as()") {
|
|||||||
REQUIRE(variant.as<std::string>() == "-42");
|
REQUIRE(variant.as<std::string>() == "-42");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("set(42UL)") {
|
||||||
|
variant.set(42UL);
|
||||||
|
|
||||||
|
REQUIRE(variant.as<bool>() == true);
|
||||||
|
REQUIRE(variant.as<double>() == 42.0);
|
||||||
|
REQUIRE(variant.as<std::string>() == "42");
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("set(0L)") {
|
SECTION("set(0L)") {
|
||||||
variant.set(0L);
|
variant.set(0L);
|
||||||
|
|
||||||
REQUIRE(variant.as<bool>() == false);
|
REQUIRE(variant.as<bool>() == false);
|
||||||
REQUIRE(variant.as<double>() == 0.0);
|
REQUIRE(variant.as<double>() == 0.0);
|
||||||
|
REQUIRE(variant.as<std::string>() == "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("set(0UL)") {
|
||||||
|
variant.set(0UL);
|
||||||
|
|
||||||
|
REQUIRE(variant.as<bool>() == false);
|
||||||
|
REQUIRE(variant.as<double>() == 0.0);
|
||||||
|
REQUIRE(variant.as<std::string>() == "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("set(null)") {
|
SECTION("set(null)") {
|
||||||
|
@ -46,8 +46,14 @@ TEST_CASE("serialize MsgPack value") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SECTION("positive fixint") {
|
SECTION("positive fixint") {
|
||||||
checkVariant(0, "\x00");
|
SECTION("signed") {
|
||||||
checkVariant(127, "\x7F");
|
checkVariant(0, "\x00");
|
||||||
|
checkVariant(127, "\x7F");
|
||||||
|
}
|
||||||
|
SECTION("unsigned") {
|
||||||
|
checkVariant(0U, "\x00");
|
||||||
|
checkVariant(127U, "\x7F");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("uint 8") {
|
SECTION("uint 8") {
|
||||||
|
@ -47,6 +47,7 @@ TEST_CASE("parseNumber<int32_t>()") {
|
|||||||
|
|
||||||
TEST_CASE("parseNumber<uint8_t>()") {
|
TEST_CASE("parseNumber<uint8_t>()") {
|
||||||
checkInteger<uint8_t>("0", 0);
|
checkInteger<uint8_t>("0", 0);
|
||||||
|
checkInteger<uint8_t>("-0", 0);
|
||||||
checkInteger<uint8_t>("255", 255);
|
checkInteger<uint8_t>("255", 255);
|
||||||
checkInteger<uint8_t>("+255", 255);
|
checkInteger<uint8_t>("+255", 255);
|
||||||
checkInteger<uint8_t>("3.14", 3);
|
checkInteger<uint8_t>("3.14", 3);
|
||||||
|
@ -23,7 +23,27 @@ TEST_CASE("Test unsigned integer overflow") {
|
|||||||
parseNumber("4294967296", second);
|
parseNumber("4294967296", second);
|
||||||
}
|
}
|
||||||
|
|
||||||
REQUIRE(first.type() == uint8_t(VALUE_IS_POSITIVE_INTEGER));
|
REQUIRE(first.type() == uint8_t(VALUE_IS_UNSIGNED_INTEGER));
|
||||||
|
REQUIRE(second.type() == uint8_t(VALUE_IS_FLOAT));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test signed integer overflow") {
|
||||||
|
VariantData first, second;
|
||||||
|
first.init();
|
||||||
|
second.init();
|
||||||
|
|
||||||
|
// Avoids MSVC warning C4127 (conditional expression is constant)
|
||||||
|
size_t integerSize = sizeof(Integer);
|
||||||
|
|
||||||
|
if (integerSize == 8) {
|
||||||
|
parseNumber("-9223372036854775808", first);
|
||||||
|
parseNumber("-9223372036854775809", second);
|
||||||
|
} else {
|
||||||
|
parseNumber("-2147483648", first);
|
||||||
|
parseNumber("-2147483649", second);
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(first.type() == uint8_t(VALUE_IS_SIGNED_INTEGER));
|
||||||
REQUIRE(second.type() == uint8_t(VALUE_IS_FLOAT));
|
REQUIRE(second.type() == uint8_t(VALUE_IS_FLOAT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
add_executable(TextFormatterTests
|
add_executable(TextFormatterTests
|
||||||
writeFloat.cpp
|
writeFloat.cpp
|
||||||
|
writeInteger.cpp
|
||||||
writeString.cpp
|
writeString.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
55
extras/tests/TextFormatter/writeInteger.cpp
Normal file
55
extras/tests/TextFormatter/writeInteger.cpp
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// ArduinoJson - https://arduinojson.org
|
||||||
|
// Copyright Benoit Blanchon 2014-2021
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#include <catch.hpp>
|
||||||
|
#include <limits>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <ArduinoJson/Json/TextFormatter.hpp>
|
||||||
|
#include <ArduinoJson/Serialization/Writer.hpp>
|
||||||
|
|
||||||
|
using namespace ARDUINOJSON_NAMESPACE;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void checkWriteInteger(T value, std::string expected) {
|
||||||
|
char output[1024];
|
||||||
|
StaticStringWriter sb(output, sizeof(output));
|
||||||
|
TextFormatter<StaticStringWriter> writer(sb);
|
||||||
|
writer.writeInteger<T>(value);
|
||||||
|
REQUIRE(expected == output);
|
||||||
|
REQUIRE(writer.bytesWritten() == expected.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("int8_t") {
|
||||||
|
checkWriteInteger<int8_t>(0, "0");
|
||||||
|
checkWriteInteger<int8_t>(-128, "-128");
|
||||||
|
checkWriteInteger<int8_t>(127, "127");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("uint8_t") {
|
||||||
|
checkWriteInteger<uint8_t>(0, "0");
|
||||||
|
checkWriteInteger<uint8_t>(255, "255");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("int16_t") {
|
||||||
|
checkWriteInteger<int16_t>(0, "0");
|
||||||
|
checkWriteInteger<int16_t>(-32768, "-32768");
|
||||||
|
checkWriteInteger<int16_t>(32767, "32767");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("uint16_t") {
|
||||||
|
checkWriteInteger<uint16_t>(0, "0");
|
||||||
|
checkWriteInteger<uint16_t>(65535, "65535");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("int32_t") {
|
||||||
|
checkWriteInteger<int32_t>(0, "0");
|
||||||
|
checkWriteInteger<int32_t>(-2147483647 - 1, "-2147483648");
|
||||||
|
checkWriteInteger<int32_t>(2147483647, "2147483647");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("uint32_t") {
|
||||||
|
checkWriteInteger<uint32_t>(0, "0");
|
||||||
|
checkWriteInteger<uint32_t>(4294967295U, "4294967295");
|
||||||
|
}
|
@ -71,13 +71,13 @@ class JsonSerializer : public Visitor<size_t> {
|
|||||||
return bytesWritten();
|
return bytesWritten();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t visitNegativeInteger(UInt value) {
|
size_t visitSignedInteger(Integer value) {
|
||||||
_formatter.writeNegativeInteger(value);
|
_formatter.writeInteger(value);
|
||||||
return bytesWritten();
|
return bytesWritten();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t visitPositiveInteger(UInt value) {
|
size_t visitUnsignedInteger(UInt value) {
|
||||||
_formatter.writePositiveInteger(value);
|
_formatter.writeInteger(value);
|
||||||
return bytesWritten();
|
return bytesWritten();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <ArduinoJson/Numbers/Integer.hpp>
|
#include <ArduinoJson/Numbers/Integer.hpp>
|
||||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||||
#include <ArduinoJson/Polyfills/attributes.hpp>
|
#include <ArduinoJson/Polyfills/attributes.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||||
#include <ArduinoJson/Serialization/CountingDecorator.hpp>
|
#include <ArduinoJson/Serialization/CountingDecorator.hpp>
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
@ -75,28 +76,31 @@ class TextFormatter {
|
|||||||
|
|
||||||
FloatParts<T> parts(value);
|
FloatParts<T> parts(value);
|
||||||
|
|
||||||
writePositiveInteger(parts.integral);
|
writeInteger(parts.integral);
|
||||||
if (parts.decimalPlaces)
|
if (parts.decimalPlaces)
|
||||||
writeDecimals(parts.decimal, parts.decimalPlaces);
|
writeDecimals(parts.decimal, parts.decimalPlaces);
|
||||||
|
|
||||||
if (parts.exponent < 0) {
|
if (parts.exponent) {
|
||||||
writeRaw("e-");
|
|
||||||
writePositiveInteger(-parts.exponent);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parts.exponent > 0) {
|
|
||||||
writeRaw('e');
|
writeRaw('e');
|
||||||
writePositiveInteger(parts.exponent);
|
writeInteger(parts.exponent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeNegativeInteger(UInt value) {
|
|
||||||
writeRaw('-');
|
|
||||||
writePositiveInteger(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void writePositiveInteger(T value) {
|
typename enable_if<is_signed<T>::value>::type writeInteger(T value) {
|
||||||
|
typedef typename make_unsigned<T>::type unsigned_type;
|
||||||
|
unsigned_type unsigned_value;
|
||||||
|
if (value < 0) {
|
||||||
|
writeRaw('-');
|
||||||
|
unsigned_value = static_cast<unsigned_type>(-value);
|
||||||
|
} else {
|
||||||
|
unsigned_value = static_cast<unsigned_type>(value);
|
||||||
|
}
|
||||||
|
writeInteger(unsigned_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
typename enable_if<is_unsigned<T>::value>::type writeInteger(T value) {
|
||||||
char buffer[22];
|
char buffer[22];
|
||||||
char *end = buffer + sizeof(buffer);
|
char *end = buffer + sizeof(buffer);
|
||||||
char *begin = end;
|
char *begin = end;
|
||||||
|
@ -101,30 +101,37 @@ class MsgPackSerializer : public Visitor<size_t> {
|
|||||||
return bytesWritten();
|
return bytesWritten();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t visitNegativeInteger(UInt value) {
|
size_t visitSignedInteger(Integer value) {
|
||||||
UInt negated = UInt(~value + 1);
|
if (value > 0) {
|
||||||
if (value <= 0x20) {
|
visitUnsignedInteger(static_cast<UInt>(value));
|
||||||
writeInteger(int8_t(negated));
|
} else if (value >= -0x20) {
|
||||||
} else if (value <= 0x80) {
|
writeInteger(int8_t(value));
|
||||||
|
} else if (value >= -0x80) {
|
||||||
writeByte(0xD0);
|
writeByte(0xD0);
|
||||||
writeInteger(int8_t(negated));
|
writeInteger(int8_t(value));
|
||||||
} else if (value <= 0x8000) {
|
} else if (value >= -0x8000) {
|
||||||
writeByte(0xD1);
|
writeByte(0xD1);
|
||||||
writeInteger(int16_t(negated));
|
writeInteger(int16_t(value));
|
||||||
} else if (value <= 0x80000000) {
|
}
|
||||||
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
|
else if (value >= -0x80000000LL)
|
||||||
|
#else
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
writeByte(0xD2);
|
writeByte(0xD2);
|
||||||
writeInteger(int32_t(negated));
|
writeInteger(int32_t(value));
|
||||||
}
|
}
|
||||||
#if ARDUINOJSON_USE_LONG_LONG
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
else {
|
else {
|
||||||
writeByte(0xD3);
|
writeByte(0xD3);
|
||||||
writeInteger(int64_t(negated));
|
writeInteger(int64_t(value));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return bytesWritten();
|
return bytesWritten();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t visitPositiveInteger(UInt value) {
|
size_t visitUnsignedInteger(UInt value) {
|
||||||
if (value <= 0x7F) {
|
if (value <= 0x7F) {
|
||||||
writeInteger(uint8_t(value));
|
writeInteger(uint8_t(value));
|
||||||
} else if (value <= 0xFF) {
|
} else if (value <= 0xFF) {
|
||||||
|
@ -15,84 +15,86 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <ArduinoJson/Numbers/Float.hpp>
|
#include <ArduinoJson/Numbers/Float.hpp>
|
||||||
#include <ArduinoJson/Numbers/FloatTraits.hpp>
|
|
||||||
#include <ArduinoJson/Numbers/Integer.hpp>
|
|
||||||
#include <ArduinoJson/Polyfills/limits.hpp>
|
#include <ArduinoJson/Polyfills/limits.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
|
// uint32 -> int32
|
||||||
|
// uint64 -> int32
|
||||||
template <typename TOut, typename TIn>
|
template <typename TOut, typename TIn>
|
||||||
typename enable_if<is_integral<TOut>::value && sizeof(TOut) <= sizeof(TIn),
|
typename enable_if<is_integral<TIn>::value && is_unsigned<TIn>::value &&
|
||||||
|
is_integral<TOut>::value && sizeof(TOut) <= sizeof(TIn),
|
||||||
bool>::type
|
bool>::type
|
||||||
canStorePositiveInteger(TIn value) {
|
canConvertNumber(TIn value) {
|
||||||
return value <= TIn(numeric_limits<TOut>::highest());
|
return value <= TIn(numeric_limits<TOut>::highest());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// uint32 -> int64
|
||||||
template <typename TOut, typename TIn>
|
template <typename TOut, typename TIn>
|
||||||
typename enable_if<is_integral<TOut>::value && sizeof(TIn) < sizeof(TOut),
|
typename enable_if<is_integral<TIn>::value && is_unsigned<TIn>::value &&
|
||||||
|
is_integral<TOut>::value && sizeof(TIn) < sizeof(TOut),
|
||||||
bool>::type
|
bool>::type
|
||||||
canStorePositiveInteger(TIn) {
|
canConvertNumber(TIn) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// uint32 -> float
|
||||||
|
// int32 -> float
|
||||||
template <typename TOut, typename TIn>
|
template <typename TOut, typename TIn>
|
||||||
typename enable_if<is_floating_point<TOut>::value, bool>::type
|
typename enable_if<is_integral<TIn>::value && is_floating_point<TOut>::value,
|
||||||
canStorePositiveInteger(TIn) {
|
bool>::type
|
||||||
|
canConvertNumber(TIn) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// int64 -> int32
|
||||||
template <typename TOut, typename TIn>
|
template <typename TOut, typename TIn>
|
||||||
typename enable_if<is_floating_point<TOut>::value, bool>::type
|
typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value &&
|
||||||
canStoreNegativeInteger(TIn) {
|
is_integral<TOut>::value && is_signed<TOut>::value &&
|
||||||
|
sizeof(TOut) < sizeof(TIn),
|
||||||
|
bool>::type
|
||||||
|
canConvertNumber(TIn value) {
|
||||||
|
return value >= TIn(numeric_limits<TOut>::lowest()) &&
|
||||||
|
value <= TIn(numeric_limits<TOut>::highest());
|
||||||
|
}
|
||||||
|
|
||||||
|
// int32 -> int32
|
||||||
|
// int32 -> int64
|
||||||
|
template <typename TOut, typename TIn>
|
||||||
|
typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value &&
|
||||||
|
is_integral<TOut>::value && is_signed<TOut>::value &&
|
||||||
|
sizeof(TIn) <= sizeof(TOut),
|
||||||
|
bool>::type
|
||||||
|
canConvertNumber(TIn) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// int32 -> uint32
|
||||||
template <typename TOut, typename TIn>
|
template <typename TOut, typename TIn>
|
||||||
typename enable_if<is_integral<TOut>::value && is_signed<TOut>::value &&
|
typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value &&
|
||||||
sizeof(TOut) <= sizeof(TIn),
|
is_integral<TOut>::value && is_unsigned<TOut>::value,
|
||||||
bool>::type
|
bool>::type
|
||||||
canStoreNegativeInteger(TIn value) {
|
canConvertNumber(TIn value) {
|
||||||
return value <= TIn(numeric_limits<TOut>::highest()) + 1;
|
if (value < 0)
|
||||||
|
return false;
|
||||||
|
return value <= TIn(numeric_limits<TOut>::highest());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// float -> int32
|
||||||
|
// float -> int64
|
||||||
template <typename TOut, typename TIn>
|
template <typename TOut, typename TIn>
|
||||||
typename enable_if<is_integral<TOut>::value && is_signed<TOut>::value &&
|
typename enable_if<is_floating_point<TIn>::value &&
|
||||||
sizeof(TIn) < sizeof(TOut),
|
!is_floating_point<TOut>::value,
|
||||||
bool>::type
|
bool>::type
|
||||||
canStoreNegativeInteger(TIn) {
|
canConvertNumber(TIn value) {
|
||||||
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() &&
|
return value >= numeric_limits<TOut>::lowest() &&
|
||||||
value <= numeric_limits<TOut>::highest()
|
value <= numeric_limits<TOut>::highest();
|
||||||
? TOut(value)
|
}
|
||||||
: 0;
|
|
||||||
|
template <typename TOut, typename TIn>
|
||||||
|
TOut convertNumber(TIn value) {
|
||||||
|
return canConvertNumber<TOut>(value) ? TOut(value) : 0;
|
||||||
}
|
}
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
|
||||||
|
@ -69,11 +69,17 @@ inline bool parseNumber(const char* s, VariantData& result) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (*s == '\0') {
|
if (*s == '\0') {
|
||||||
if (is_negative)
|
if (is_negative) {
|
||||||
result.setNegativeInteger(UInt(mantissa));
|
const mantissa_t sintMantissaMax = mantissa_t(1)
|
||||||
else
|
<< (sizeof(Integer) * 8 - 1);
|
||||||
result.setPositiveInteger(UInt(mantissa));
|
if (mantissa <= sintMantissaMax) {
|
||||||
return true;
|
result.setInteger(Integer(~mantissa + 1));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.setInteger(UInt(mantissa));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// avoid mantissa overflow
|
// avoid mantissa overflow
|
||||||
|
@ -57,16 +57,16 @@ struct Comparer<T, typename enable_if<is_integral<T>::value ||
|
|||||||
return arithmeticCompare(lhs, rhs);
|
return arithmeticCompare(lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompareResult visitNegativeInteger(UInt lhs) {
|
CompareResult visitSignedInteger(Integer lhs) {
|
||||||
return arithmeticCompareNegateLeft(lhs, rhs);
|
return arithmeticCompare(lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompareResult visitPositiveInteger(UInt lhs) {
|
CompareResult visitUnsignedInteger(UInt lhs) {
|
||||||
return arithmeticCompare(lhs, rhs);
|
return arithmeticCompare(lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompareResult visitBoolean(bool lhs) {
|
CompareResult visitBoolean(bool lhs) {
|
||||||
return visitPositiveInteger(static_cast<UInt>(lhs));
|
return visitUnsignedInteger(static_cast<UInt>(lhs));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -96,28 +96,6 @@ struct ArrayComparer : ComparerBase {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NegativeIntegerComparer : ComparerBase {
|
|
||||||
UInt _rhs;
|
|
||||||
|
|
||||||
explicit NegativeIntegerComparer(UInt rhs) : _rhs(rhs) {}
|
|
||||||
|
|
||||||
CompareResult visitFloat(Float lhs) {
|
|
||||||
return arithmeticCompareNegateRight(lhs, _rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
CompareResult visitNegativeInteger(UInt lhs) {
|
|
||||||
return arithmeticCompare(_rhs, lhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
CompareResult visitPositiveInteger(UInt) {
|
|
||||||
return COMPARE_RESULT_GREATER;
|
|
||||||
}
|
|
||||||
|
|
||||||
CompareResult visitBoolean(bool) {
|
|
||||||
return COMPARE_RESULT_GREATER;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ObjectComparer : ComparerBase {
|
struct ObjectComparer : ComparerBase {
|
||||||
const CollectionData *_rhs;
|
const CollectionData *_rhs;
|
||||||
|
|
||||||
@ -182,12 +160,12 @@ struct Comparer<T, typename enable_if<IsVisitable<T>::value>::type>
|
|||||||
return accept(comparer);
|
return accept(comparer);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompareResult visitNegativeInteger(UInt lhs) {
|
CompareResult visitSignedInteger(Integer lhs) {
|
||||||
NegativeIntegerComparer comparer(lhs);
|
Comparer<Integer> comparer(lhs);
|
||||||
return accept(comparer);
|
return accept(comparer);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompareResult visitPositiveInteger(UInt lhs) {
|
CompareResult visitUnsignedInteger(UInt lhs) {
|
||||||
Comparer<UInt> comparer(lhs);
|
Comparer<UInt> comparer(lhs);
|
||||||
return accept(comparer);
|
return accept(comparer);
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,8 @@ enum {
|
|||||||
|
|
||||||
// CAUTION: no VALUE_IS_OWNED below
|
// CAUTION: no VALUE_IS_OWNED below
|
||||||
VALUE_IS_BOOLEAN = 0x06,
|
VALUE_IS_BOOLEAN = 0x06,
|
||||||
VALUE_IS_POSITIVE_INTEGER = 0x08,
|
VALUE_IS_UNSIGNED_INTEGER = 0x08,
|
||||||
VALUE_IS_NEGATIVE_INTEGER = 0x0A,
|
VALUE_IS_SIGNED_INTEGER = 0x0A,
|
||||||
VALUE_IS_FLOAT = 0x0C,
|
VALUE_IS_FLOAT = 0x0C,
|
||||||
|
|
||||||
COLLECTION_MASK = 0x60,
|
COLLECTION_MASK = 0x60,
|
||||||
@ -43,7 +43,9 @@ struct RawData {
|
|||||||
|
|
||||||
union VariantContent {
|
union VariantContent {
|
||||||
Float asFloat;
|
Float asFloat;
|
||||||
UInt asInteger;
|
bool asBoolean;
|
||||||
|
UInt asUnsignedInteger;
|
||||||
|
Integer asSignedInteger;
|
||||||
CollectionData asCollection;
|
CollectionData asCollection;
|
||||||
const char *asString;
|
const char *asString;
|
||||||
struct {
|
struct {
|
||||||
|
@ -56,14 +56,14 @@ class VariantData {
|
|||||||
case VALUE_IS_LINKED_RAW:
|
case VALUE_IS_LINKED_RAW:
|
||||||
return visitor.visitRawJson(_content.asRaw.data, _content.asRaw.size);
|
return visitor.visitRawJson(_content.asRaw.data, _content.asRaw.size);
|
||||||
|
|
||||||
case VALUE_IS_NEGATIVE_INTEGER:
|
case VALUE_IS_SIGNED_INTEGER:
|
||||||
return visitor.visitNegativeInteger(_content.asInteger);
|
return visitor.visitSignedInteger(_content.asSignedInteger);
|
||||||
|
|
||||||
case VALUE_IS_POSITIVE_INTEGER:
|
case VALUE_IS_UNSIGNED_INTEGER:
|
||||||
return visitor.visitPositiveInteger(_content.asInteger);
|
return visitor.visitUnsignedInteger(_content.asUnsignedInteger);
|
||||||
|
|
||||||
case VALUE_IS_BOOLEAN:
|
case VALUE_IS_BOOLEAN:
|
||||||
return visitor.visitBoolean(_content.asInteger != 0);
|
return visitor.visitBoolean(_content.asBoolean != 0);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return visitor.visitNull();
|
return visitor.visitNull();
|
||||||
@ -129,11 +129,11 @@ class VariantData {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
bool isInteger() const {
|
bool isInteger() const {
|
||||||
switch (type()) {
|
switch (type()) {
|
||||||
case VALUE_IS_POSITIVE_INTEGER:
|
case VALUE_IS_UNSIGNED_INTEGER:
|
||||||
return canStorePositiveInteger<T>(_content.asInteger);
|
return canConvertNumber<T>(_content.asUnsignedInteger);
|
||||||
|
|
||||||
case VALUE_IS_NEGATIVE_INTEGER:
|
case VALUE_IS_SIGNED_INTEGER:
|
||||||
return canStoreNegativeInteger<T>(_content.asInteger);
|
return canConvertNumber<T>(_content.asSignedInteger);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@ -141,8 +141,8 @@ class VariantData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isFloat() const {
|
bool isFloat() const {
|
||||||
return type() == VALUE_IS_FLOAT || type() == VALUE_IS_POSITIVE_INTEGER ||
|
return type() == VALUE_IS_FLOAT || type() == VALUE_IS_UNSIGNED_INTEGER ||
|
||||||
type() == VALUE_IS_NEGATIVE_INTEGER;
|
type() == VALUE_IS_SIGNED_INTEGER;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isString() const {
|
bool isString() const {
|
||||||
@ -174,7 +174,7 @@ class VariantData {
|
|||||||
|
|
||||||
void setBoolean(bool value) {
|
void setBoolean(bool value) {
|
||||||
setType(VALUE_IS_BOOLEAN);
|
setType(VALUE_IS_BOOLEAN);
|
||||||
_content.asInteger = static_cast<UInt>(value);
|
_content.asBoolean = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setFloat(Float value) {
|
void setFloat(Float value) {
|
||||||
@ -208,36 +208,14 @@ class VariantData {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename enable_if<is_unsigned<T>::value>::type setInteger(T value) {
|
typename enable_if<is_unsigned<T>::value>::type setInteger(T value) {
|
||||||
setUnsignedInteger(value);
|
setType(VALUE_IS_UNSIGNED_INTEGER);
|
||||||
|
_content.asUnsignedInteger = static_cast<UInt>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename enable_if<is_signed<T>::value>::type setInteger(T value) {
|
typename enable_if<is_signed<T>::value>::type setInteger(T value) {
|
||||||
setSignedInteger(value);
|
setType(VALUE_IS_SIGNED_INTEGER);
|
||||||
}
|
_content.asSignedInteger = value;
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void setSignedInteger(T value) {
|
|
||||||
if (value >= 0) {
|
|
||||||
setPositiveInteger(static_cast<UInt>(value));
|
|
||||||
} else {
|
|
||||||
setNegativeInteger(~static_cast<UInt>(value) + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setUnsignedInteger(UInt value) {
|
|
||||||
setType(VALUE_IS_POSITIVE_INTEGER);
|
|
||||||
_content.asInteger = static_cast<UInt>(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 setNull() {
|
void setNull() {
|
||||||
|
@ -18,16 +18,17 @@ namespace ARDUINOJSON_NAMESPACE {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
inline T VariantData::asIntegral() const {
|
inline T VariantData::asIntegral() const {
|
||||||
switch (type()) {
|
switch (type()) {
|
||||||
case VALUE_IS_POSITIVE_INTEGER:
|
|
||||||
case VALUE_IS_BOOLEAN:
|
case VALUE_IS_BOOLEAN:
|
||||||
return convertPositiveInteger<T>(_content.asInteger);
|
return _content.asBoolean;
|
||||||
case VALUE_IS_NEGATIVE_INTEGER:
|
case VALUE_IS_UNSIGNED_INTEGER:
|
||||||
return convertNegativeInteger<T>(_content.asInteger);
|
return convertNumber<T>(_content.asUnsignedInteger);
|
||||||
|
case VALUE_IS_SIGNED_INTEGER:
|
||||||
|
return convertNumber<T>(_content.asSignedInteger);
|
||||||
case VALUE_IS_LINKED_STRING:
|
case VALUE_IS_LINKED_STRING:
|
||||||
case VALUE_IS_OWNED_STRING:
|
case VALUE_IS_OWNED_STRING:
|
||||||
return parseNumber<T>(_content.asString);
|
return parseNumber<T>(_content.asString);
|
||||||
case VALUE_IS_FLOAT:
|
case VALUE_IS_FLOAT:
|
||||||
return convertFloat<T>(_content.asFloat);
|
return convertNumber<T>(_content.asFloat);
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -35,10 +36,11 @@ inline T VariantData::asIntegral() const {
|
|||||||
|
|
||||||
inline bool VariantData::asBoolean() const {
|
inline bool VariantData::asBoolean() const {
|
||||||
switch (type()) {
|
switch (type()) {
|
||||||
case VALUE_IS_POSITIVE_INTEGER:
|
|
||||||
case VALUE_IS_BOOLEAN:
|
case VALUE_IS_BOOLEAN:
|
||||||
case VALUE_IS_NEGATIVE_INTEGER:
|
return _content.asBoolean;
|
||||||
return _content.asInteger != 0;
|
case VALUE_IS_SIGNED_INTEGER:
|
||||||
|
case VALUE_IS_UNSIGNED_INTEGER:
|
||||||
|
return _content.asUnsignedInteger != 0;
|
||||||
case VALUE_IS_FLOAT:
|
case VALUE_IS_FLOAT:
|
||||||
return _content.asFloat != 0;
|
return _content.asFloat != 0;
|
||||||
case VALUE_IS_NULL:
|
case VALUE_IS_NULL:
|
||||||
@ -52,11 +54,12 @@ inline bool VariantData::asBoolean() const {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
inline T VariantData::asFloat() const {
|
inline T VariantData::asFloat() const {
|
||||||
switch (type()) {
|
switch (type()) {
|
||||||
case VALUE_IS_POSITIVE_INTEGER:
|
|
||||||
case VALUE_IS_BOOLEAN:
|
case VALUE_IS_BOOLEAN:
|
||||||
return static_cast<T>(_content.asInteger);
|
return static_cast<T>(_content.asBoolean);
|
||||||
case VALUE_IS_NEGATIVE_INTEGER:
|
case VALUE_IS_UNSIGNED_INTEGER:
|
||||||
return -static_cast<T>(_content.asInteger);
|
return static_cast<T>(_content.asUnsignedInteger);
|
||||||
|
case VALUE_IS_SIGNED_INTEGER:
|
||||||
|
return static_cast<T>(_content.asSignedInteger);
|
||||||
case VALUE_IS_LINKED_STRING:
|
case VALUE_IS_LINKED_STRING:
|
||||||
case VALUE_IS_OWNED_STRING:
|
case VALUE_IS_OWNED_STRING:
|
||||||
return parseNumber<T>(_content.asString);
|
return parseNumber<T>(_content.asString);
|
||||||
|
@ -26,7 +26,7 @@ struct Visitor {
|
|||||||
return TResult();
|
return TResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
TResult visitNegativeInteger(UInt) {
|
TResult visitSignedInteger(Integer) {
|
||||||
return TResult();
|
return TResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ struct Visitor {
|
|||||||
return TResult();
|
return TResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
TResult visitPositiveInteger(UInt) {
|
TResult visitUnsignedInteger(UInt) {
|
||||||
return TResult();
|
return TResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user