mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01: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