diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index 79478b8..0149abd 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -48,10 +48,28 @@ const LargestUInt Value::maxLargestUInt = LargestUInt(-1); /// Unknown size marker static const unsigned int unknown = (unsigned)-1; +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) template static inline bool InRange(double d, T min, U max) { - return d >= min && d <= max; + return d >= min && d <= max; } +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +static inline double integerToDouble( Json::UInt64 value ) +{ + return static_cast( UInt(value >> 32) ) * (UInt64(1)<<32) + UInt(value & 0xffffffff); +} + +template +static inline double integerToDouble( T value ) +{ + return static_cast( value ); +} + +template +static inline bool InRange(double d, T min, U max) { + return d >= integerToDouble(min) && d <= integerToDouble(max); +} +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) /** Duplicates the specified string value. @@ -673,9 +691,6 @@ Value::asCString() const std::string Value::asString() const { - // Let the STL sort it out for numeric types. - std::ostringstream oss; - switch ( type_ ) { case nullValue: @@ -685,18 +700,14 @@ Value::asString() const case booleanValue: return value_.bool_ ? "true" : "false"; case intValue: - oss << value_.int_; - break; + return valueToString( value_.int_ ); case uintValue: - oss << value_.uint_; - break; + return valueToString( value_.uint_ ); case realValue: - oss << value_.real_; - break; + return valueToString( value_.real_ ); default: JSON_FAIL_MESSAGE( "Type is not convertible to string" ); } - return oss.str(); } # ifdef JSON_USE_CPPTL @@ -842,7 +853,7 @@ Value::asDouble() const #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) return static_cast( value_.uint_ ); #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return static_cast( Int(value_.uint_/2) ) * 2 + Int(value_.uint_ & 1); + return integerToDouble( value_.uint_ ); #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) case realValue: return value_.real_; diff --git a/src/test_lib_json/jsontest.cpp b/src/test_lib_json/jsontest.cpp index 46f2eea..327d344 100644 --- a/src/test_lib_json/jsontest.cpp +++ b/src/test_lib_json/jsontest.cpp @@ -249,6 +249,23 @@ TestResult::addToLastFailure( const std::string &message ) return *this; } +TestResult & +TestResult::operator << ( Json::Int64 value ) { + return addToLastFailure( Json::valueToString(value) ); +} + + +TestResult & +TestResult::operator << ( Json::UInt64 value ) { + return addToLastFailure( Json::valueToString(value) ); +} + + +TestResult & +TestResult::operator << ( bool value ) { + return addToLastFailure(value ? "true" : "false"); +} + // class TestCase // ////////////////////////////////////////////////////////////////// diff --git a/src/test_lib_json/jsontest.h b/src/test_lib_json/jsontest.h index 28792a9..207692b 100644 --- a/src/test_lib_json/jsontest.h +++ b/src/test_lib_json/jsontest.h @@ -8,6 +8,7 @@ # include # include +# include # include # include # include @@ -90,14 +91,17 @@ namespace JsonTest { template TestResult &operator << ( const T& value ) { std::ostringstream oss; + oss.precision( 16 ); + oss.setf( std::ios_base::floatfield ); oss << value; return addToLastFailure(oss.str()); } // Specialized versions. - TestResult &operator << ( bool value ) { - return addToLastFailure(value ? "true" : "false"); - } + TestResult &operator << ( bool value ); + // std:ostream does not support 64bits integers on all STL implementation + TestResult &operator << ( Json::Int64 value ); + TestResult &operator << ( Json::UInt64 value ); private: TestResult &addToLastFailure( const std::string &message ); @@ -195,6 +199,7 @@ namespace JsonTest { return result; } + TestResult & checkStringEqual( TestResult &result, const std::string &expected, const std::string &actual, diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index a195542..773bf10 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -30,6 +30,17 @@ static const float kfuint32max = float(kuint32max); // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +static inline double uint64ToDouble( Json::UInt64 value ) +{ + return static_cast( value ); +} +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +static inline double uint64ToDouble( Json::UInt64 value ) +{ + return static_cast( Json::UInt(value >> 32) ) * (Json::UInt64(1)<<32) + Json::UInt(value & 0xffffffff); +} +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) struct ValueTest : JsonTest::TestCase { @@ -453,7 +464,7 @@ JSONTEST_FIXTURE( ValueTest, integers ) JSONTEST_ASSERT_EQUAL(0.0, val.asDouble()); JSONTEST_ASSERT_EQUAL(0.0, val.asFloat()); JSONTEST_ASSERT_EQUAL(false, val.asBool()); - JSONTEST_ASSERT_STRING_EQUAL("0", val.asString()); + JSONTEST_ASSERT_STRING_EQUAL("0.0", val.asString()); // Zero (signed constructor arg) val = Json::Value(0); @@ -537,13 +548,12 @@ JSONTEST_FIXTURE( ValueTest, integers ) JSONTEST_ASSERT_EQUAL(0.0, val.asDouble()); JSONTEST_ASSERT_EQUAL(0.0, val.asFloat()); JSONTEST_ASSERT_EQUAL(false, val.asBool()); - JSONTEST_ASSERT_STRING_EQUAL("0", val.asString()); + JSONTEST_ASSERT_STRING_EQUAL("0.0", val.asString()); // 2^20 (signed constructor arg) val = Json::Value(1 << 20); JSONTEST_ASSERT_EQUAL(Json::intValue, val.type()); - checks = IsCheck(); checks.isInt_ = true; checks.isInt64_ = true; @@ -568,7 +578,7 @@ JSONTEST_FIXTURE( ValueTest, integers ) JSONTEST_ASSERT_STRING_EQUAL("1048576", val.asString()); // 2^20 (unsigned constructor arg) - val = Json::Value(1u << 20); + val = Json::Value(Json::UInt(1 << 20)); JSONTEST_ASSERT_EQUAL(Json::uintValue, val.type()); @@ -621,7 +631,7 @@ JSONTEST_FIXTURE( ValueTest, integers ) JSONTEST_ASSERT_EQUAL((1 << 20), val.asDouble()); JSONTEST_ASSERT_EQUAL((1 << 20), val.asFloat()); JSONTEST_ASSERT_EQUAL(true, val.asBool()); - JSONTEST_ASSERT_STRING_EQUAL("1.04858e+6", normalizeFloatingPointStr(val.asString())); + JSONTEST_ASSERT_STRING_EQUAL("1048576.0", normalizeFloatingPointStr(val.asString())); // -2^20 val = Json::Value(-(1 << 20)); @@ -786,7 +796,7 @@ JSONTEST_FIXTURE( ValueTest, integers ) JSONTEST_ASSERT_STRING_EQUAL("1.84467e+19", val.asString()); #else // ifdef JSON_NO_INT64 // 2^40 (signed constructor arg) - val = Json::Value(1LL << 40); + val = Json::Value(Json::Int64(1) << 40); JSONTEST_ASSERT_EQUAL(Json::intValue, val.type()); @@ -802,17 +812,17 @@ JSONTEST_FIXTURE( ValueTest, integers ) JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); - JSONTEST_ASSERT_EQUAL((1LL << 40), val.asInt64()); - JSONTEST_ASSERT_EQUAL((1LL << 40), val.asLargestInt()); - JSONTEST_ASSERT_EQUAL((1LL << 40), val.asUInt64()); - JSONTEST_ASSERT_EQUAL((1LL << 40), val.asLargestUInt()); - JSONTEST_ASSERT_EQUAL((1LL << 40), val.asDouble()); - JSONTEST_ASSERT_EQUAL((1LL << 40), val.asFloat()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asInt64()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asLargestInt()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asUInt64()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asDouble()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asFloat()); JSONTEST_ASSERT_EQUAL(true, val.asBool()); JSONTEST_ASSERT_STRING_EQUAL("1099511627776", val.asString()); // 2^40 (unsigned constructor arg) - val = Json::Value(1ULL << 40); + val = Json::Value(Json::UInt64(1) << 40); JSONTEST_ASSERT_EQUAL(Json::uintValue, val.type()); @@ -828,17 +838,17 @@ JSONTEST_FIXTURE( ValueTest, integers ) JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); - JSONTEST_ASSERT_EQUAL((1LL << 40), val.asInt64()); - JSONTEST_ASSERT_EQUAL((1LL << 40), val.asLargestInt()); - JSONTEST_ASSERT_EQUAL((1LL << 40), val.asUInt64()); - JSONTEST_ASSERT_EQUAL((1LL << 40), val.asLargestUInt()); - JSONTEST_ASSERT_EQUAL((1LL << 40), val.asDouble()); - JSONTEST_ASSERT_EQUAL((1LL << 40), val.asFloat()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asInt64()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asLargestInt()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asUInt64()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asDouble()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asFloat()); JSONTEST_ASSERT_EQUAL(true, val.asBool()); JSONTEST_ASSERT_STRING_EQUAL("1099511627776", val.asString()); // 2^40 (floating-point constructor arg) - val = Json::Value((1LL << 40) / 1.0); + val = Json::Value((Json::Int64(1) << 40) / 1.0); JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); @@ -854,17 +864,17 @@ JSONTEST_FIXTURE( ValueTest, integers ) JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); - JSONTEST_ASSERT_EQUAL((1LL << 40), val.asInt64()); - JSONTEST_ASSERT_EQUAL((1LL << 40), val.asLargestInt()); - JSONTEST_ASSERT_EQUAL((1LL << 40), val.asUInt64()); - JSONTEST_ASSERT_EQUAL((1LL << 40), val.asLargestUInt()); - JSONTEST_ASSERT_EQUAL((1LL << 40), val.asDouble()); - JSONTEST_ASSERT_EQUAL((1LL << 40), val.asFloat()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asInt64()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asLargestInt()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asUInt64()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asDouble()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asFloat()); JSONTEST_ASSERT_EQUAL(true, val.asBool()); - JSONTEST_ASSERT_STRING_EQUAL("1.09951e+12", normalizeFloatingPointStr(val.asString())); + JSONTEST_ASSERT_STRING_EQUAL("1099511627776.0", normalizeFloatingPointStr(val.asString())); // -2^40 - val = Json::Value(-(1LL << 40)); + val = Json::Value(-(Json::Int64(1) << 40)); JSONTEST_ASSERT_EQUAL(Json::intValue, val.type()); @@ -879,10 +889,10 @@ JSONTEST_FIXTURE( ValueTest, integers ) JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); - JSONTEST_ASSERT_EQUAL(-(1LL << 40), val.asInt64()); - JSONTEST_ASSERT_EQUAL(-(1LL << 40), val.asLargestInt()); - JSONTEST_ASSERT_EQUAL(-(1LL << 40), val.asDouble()); - JSONTEST_ASSERT_EQUAL(-(1LL << 40), val.asFloat()); + JSONTEST_ASSERT_EQUAL(-(Json::Int64(1) << 40), val.asInt64()); + JSONTEST_ASSERT_EQUAL(-(Json::Int64(1) << 40), val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(-(Json::Int64(1) << 40), val.asDouble()); + JSONTEST_ASSERT_EQUAL(-(Json::Int64(1) << 40), val.asFloat()); JSONTEST_ASSERT_EQUAL(true, val.asBool()); JSONTEST_ASSERT_STRING_EQUAL("-1099511627776", val.asString()); @@ -929,12 +939,12 @@ JSONTEST_FIXTURE( ValueTest, integers ) JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); - JSONTEST_ASSERT_EQUAL(9223372036854775808ULL, val.asUInt64()); - JSONTEST_ASSERT_EQUAL(9223372036854775808ULL, val.asLargestUInt()); - JSONTEST_ASSERT_EQUAL(9223372036854775808ULL, val.asDouble()); - JSONTEST_ASSERT_EQUAL(9223372036854775808ULL, val.asFloat()); + JSONTEST_ASSERT_EQUAL(Json::UInt64(1) << 63, val.asUInt64()); + JSONTEST_ASSERT_EQUAL(Json::UInt64(1) << 63, val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL(uint64ToDouble(Json::UInt64(1) << 63), val.asDouble()); + JSONTEST_ASSERT_EQUAL(float(uint64ToDouble(Json::UInt64(1) << 63)), val.asFloat()); JSONTEST_ASSERT_EQUAL(true, val.asBool()); - JSONTEST_ASSERT_STRING_EQUAL("9.22337e+18", normalizeFloatingPointStr(val.asString())); + JSONTEST_ASSERT_STRING_EQUAL("9.223372036854776e+18", normalizeFloatingPointStr(val.asString())); // int64 min val = Json::Value(Json::Int64(kint64min)); @@ -981,7 +991,7 @@ JSONTEST_FIXTURE( ValueTest, integers ) JSONTEST_ASSERT_EQUAL(-9223372036854775808.0, val.asDouble()); JSONTEST_ASSERT_EQUAL(-9223372036854775808.0, val.asFloat()); JSONTEST_ASSERT_EQUAL(true, val.asBool()); - JSONTEST_ASSERT_STRING_EQUAL("-9.22337e+18", normalizeFloatingPointStr(val.asString())); + JSONTEST_ASSERT_STRING_EQUAL("-9.223372036854776e+18", normalizeFloatingPointStr(val.asString())); // uint64 max val = Json::Value(Json::UInt64(kuint64max)); @@ -1001,14 +1011,14 @@ JSONTEST_FIXTURE( ValueTest, integers ) JSONTEST_ASSERT_EQUAL(kuint64max, val.asUInt64()); JSONTEST_ASSERT_EQUAL(kuint64max, val.asLargestUInt()); - JSONTEST_ASSERT_EQUAL(double(kuint64max), val.asDouble()); - JSONTEST_ASSERT_EQUAL(float(kuint64max), val.asFloat()); + JSONTEST_ASSERT_EQUAL(uint64ToDouble(kuint64max), val.asDouble()); + JSONTEST_ASSERT_EQUAL(float(uint64ToDouble(kuint64max)), val.asFloat()); JSONTEST_ASSERT_EQUAL(true, val.asBool()); JSONTEST_ASSERT_STRING_EQUAL("18446744073709551615", val.asString()); // uint64 max (floating point constructor). Note that kuint64max is not // exactly representable as a double, and will be rounded up to be higher. - val = Json::Value(double(kuint64max)); + val = Json::Value(uint64ToDouble(kuint64max)); JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); @@ -1024,7 +1034,7 @@ JSONTEST_FIXTURE( ValueTest, integers ) JSONTEST_ASSERT_EQUAL(18446744073709551616.0, val.asDouble()); JSONTEST_ASSERT_EQUAL(18446744073709551616.0, val.asFloat()); JSONTEST_ASSERT_EQUAL(true, val.asBool()); - JSONTEST_ASSERT_STRING_EQUAL("1.84467e+19", normalizeFloatingPointStr(val.asString())); + JSONTEST_ASSERT_STRING_EQUAL("1.844674407370955e+19", normalizeFloatingPointStr(val.asString())); #endif } @@ -1060,7 +1070,7 @@ JSONTEST_FIXTURE( ValueTest, nonIntegers ) JSONTEST_ASSERT_EQUAL(1, val.asUInt()); JSONTEST_ASSERT_EQUAL(1, val.asLargestUInt()); JSONTEST_ASSERT_EQUAL(true, val.asBool()); - JSONTEST_ASSERT_EQUAL("1.5", val.asString()); + JSONTEST_ASSERT_EQUAL("1.50", val.asString()); // Small negative number val = Json::Value(-1.5); @@ -1086,7 +1096,7 @@ JSONTEST_FIXTURE( ValueTest, nonIntegers ) JSONTEST_ASSERT_EQUAL(-1, val.asInt()); JSONTEST_ASSERT_EQUAL(-1, val.asLargestInt()); JSONTEST_ASSERT_EQUAL(true, val.asBool()); - JSONTEST_ASSERT_EQUAL("-1.5", val.asString()); + JSONTEST_ASSERT_EQUAL("-1.50", val.asString()); // A bit over int32 max val = Json::Value(kint32max + 0.5); @@ -1115,7 +1125,7 @@ JSONTEST_FIXTURE( ValueTest, nonIntegers ) JSONTEST_ASSERT_EQUAL(2147483647U, val.asLargestUInt()); #endif JSONTEST_ASSERT_EQUAL(true, val.asBool()); - JSONTEST_ASSERT_EQUAL("2.14748e+9", normalizeFloatingPointStr(val.asString())); + JSONTEST_ASSERT_EQUAL("2147483647.50", normalizeFloatingPointStr(val.asString())); // A bit under int32 min val = Json::Value(kint32min - 0.5); @@ -1139,10 +1149,10 @@ JSONTEST_FIXTURE( ValueTest, nonIntegers ) JSONTEST_ASSERT_EQUAL(-2147483648.5, val.asDouble()); JSONTEST_ASSERT_EQUAL(float(-2147483648.5), val.asFloat()); #ifdef JSON_HAS_INT64 - JSONTEST_ASSERT_EQUAL(-2147483648LL, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(-Json::Int64(1)<< 31, val.asLargestInt()); #endif JSONTEST_ASSERT_EQUAL(true, val.asBool()); - JSONTEST_ASSERT_EQUAL("-2.14748e+9", normalizeFloatingPointStr(val.asString())); + JSONTEST_ASSERT_EQUAL("-2147483648.50", normalizeFloatingPointStr(val.asString())); // A bit over uint32 max val = Json::Value(kuint32max + 0.5); @@ -1166,11 +1176,14 @@ JSONTEST_FIXTURE( ValueTest, nonIntegers ) JSONTEST_ASSERT_EQUAL(4294967295.5, val.asDouble()); JSONTEST_ASSERT_EQUAL(float(4294967295.5), val.asFloat()); #ifdef JSON_HAS_INT64 - JSONTEST_ASSERT_EQUAL(4294967295LL, val.asLargestInt()); - JSONTEST_ASSERT_EQUAL(4294967295ULL, val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 32)-1, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL((Json::UInt64(1) << 32)-Json::UInt64(1), val.asLargestUInt()); #endif JSONTEST_ASSERT_EQUAL(true, val.asBool()); - JSONTEST_ASSERT_EQUAL("4.29497e+9", normalizeFloatingPointStr(val.asString())); + JSONTEST_ASSERT_EQUAL("4294967295.50", normalizeFloatingPointStr(val.asString())); + + val = Json::Value(1.2345678901234); + JSONTEST_ASSERT_STRING_EQUAL( "1.23456789012340", normalizeFloatingPointStr(val.asString())); } @@ -1243,7 +1256,6 @@ ValueTest::checkIs( const Json::Value &value, const IsCheck &check ) #endif } - JSONTEST_FIXTURE( ValueTest, compareNull ) { JSONTEST_ASSERT_PRED( checkIsEqual( Json::Value(), Json::Value() ) ); @@ -1389,7 +1401,6 @@ ValueTest::checkIsEqual( const Json::Value &x, const Json::Value &y ) JSONTEST_ASSERT( y.compare( x ) == 0 ); } - int main( int argc, const char *argv[] ) { JsonTest::Runner runner;