From f587e6a420c467a69b7f977875052077aef2913b Mon Sep 17 00:00:00 2001 From: Baptiste Lepilleur Date: Thu, 26 May 2011 22:55:24 +0000 Subject: [PATCH] Fixed compilation issues with MSVC 6: replace usage of ostringstream with valueToString to support 64 bits integer and high precision floating point conversion to string. Replace usage of ULL and LL literal with UInt64(expr) and Int64(expr). Introduced helper function uint64ToDouble() to work-around missing conversion. Unit tests do not pass yet. --- src/lib_json/json_value.cpp | 35 ++++++---- src/test_lib_json/jsontest.cpp | 17 +++++ src/test_lib_json/jsontest.h | 11 +++- src/test_lib_json/main.cpp | 115 ++++++++++++++++++--------------- 4 files changed, 111 insertions(+), 67 deletions(-) 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;