Changed integer storage from positive/negative to signed/unsigned

This commit is contained in:
Benoit Blanchon
2021-04-14 11:42:53 +02:00
parent a002393716
commit fc4f5fd05f
16 changed files with 251 additions and 171 deletions

View File

@ -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)") {

View File

@ -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") {

View File

@ -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);

View File

@ -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));
} }

View File

@ -4,6 +4,7 @@
add_executable(TextFormatterTests add_executable(TextFormatterTests
writeFloat.cpp writeFloat.cpp
writeInteger.cpp
writeString.cpp writeString.cpp
) )

View 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");
}

View File

@ -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();
} }

View File

@ -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;

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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);
} }

View File

@ -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 {

View File

@ -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() {

View File

@ -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);

View File

@ -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();
} }