Gave a more consistent behavior to the Value::isFoo methods. See
NEWS.txt for more details.
diff --git a/NEWS.txt b/NEWS.txt
index e53b880..ac7c856 100644
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -1,3 +1,23 @@
+ New in SVN:
+ -----------
+
+* Value
+
+ - Updated the Value::isFoo methods to work as follows:
+
+ * isInt, isInt64, isUInt, and isUInt64 return true if and only if the
+ value can be exactly representable as that type. In particular, a value
+ constructed with a double like 17.0 will now return true for all of
+ these methods.
+
+ * isDouble and isFloat now return true for all numeric values, since all
+ numeric values can be converted to a double or float without
+ truncation. Note that the conversion may not be exact -- for example,
+ doubles cannot exactly represent integers above 2^53.
+
+ * isBool, isNull, isString, isArray, and isObject now return true if and
+ only if the value is of that type.
+
New in JsonCpp 0.6.0:
---------------------
diff --git a/include/json/value.h b/include/json/value.h
index e3869e5..b013c9b 100644
--- a/include/json/value.h
+++ b/include/json/value.h
@@ -280,7 +280,9 @@
bool isNull() const;
bool isBool() const;
bool isInt() const;
+ bool isInt64() const;
bool isUInt() const;
+ bool isUInt64() const;
bool isIntegral() const;
bool isDouble() const;
bool isNumeric() const;
diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp
index 0819f3e..35ec41d 100644
--- a/src/lib_json/json_value.cpp
+++ b/src/lib_json/json_value.cpp
@@ -11,6 +11,7 @@
# include "json_batchallocator.h"
# endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <math.h>
#include <iostream>
#include <utility>
#include <stdexcept>
@@ -539,6 +540,7 @@
}
+// TODO(jacobsa): Check this for correctness given the new type-coallescing API.
bool
Value::operator <( const Value &other ) const
{
@@ -601,6 +603,7 @@
return other < *this;
}
+// TODO(jacobsa): Check this for correctness given the new type-coallescing API.
bool
Value::operator ==( const Value &other ) const
{
@@ -694,59 +697,38 @@
Value::Int
Value::asInt() const
{
+ JSON_ASSERT_MESSAGE(isInt(), "Value is not convertible to Int");
switch ( type_ )
{
- case nullValue:
- return 0;
case intValue:
- JSON_ASSERT_MESSAGE( value_.int_ >= minInt && value_.int_ <= maxInt, "unsigned integer out of signed int range" );
return Int(value_.int_);
case uintValue:
- JSON_ASSERT_MESSAGE( value_.uint_ <= UInt(maxInt), "unsigned integer out of signed int range" );
return Int(value_.uint_);
case realValue:
- JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" );
return Int( value_.real_ );
- case booleanValue:
- return value_.bool_ ? 1 : 0;
- case stringValue:
- case arrayValue:
- case objectValue:
- JSON_FAIL_MESSAGE( "Type is not convertible to int" );
default:
- JSON_ASSERT_UNREACHABLE;
+ break;
}
- return 0; // unreachable;
+ JSON_ASSERT_UNREACHABLE;
+ return 0;
}
Value::UInt
Value::asUInt() const
{
+ JSON_ASSERT_MESSAGE(isUInt(), "Value is not convertible to UInt");
switch ( type_ )
{
- case nullValue:
- return 0;
case intValue:
- JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" );
- JSON_ASSERT_MESSAGE( UInt(value_.int_) <= maxUInt, "signed integer out of UInt range" );
return UInt(value_.int_);
case uintValue:
- JSON_ASSERT_MESSAGE( value_.uint_ <= maxUInt, "unsigned integer out of UInt range" );
return UInt(value_.uint_);
case realValue:
- JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" );
return UInt( value_.real_ );
- case booleanValue:
- return value_.bool_ ? 1 : 0;
- case stringValue:
- case arrayValue:
- case objectValue:
- JSON_FAIL_MESSAGE( "Type is not convertible to uint" );
- default:
- JSON_ASSERT_UNREACHABLE;
}
- return 0; // unreachable;
+ JSON_ASSERT_UNREACHABLE;
+ return 0;
}
@@ -755,55 +737,40 @@
Value::Int64
Value::asInt64() const
{
+ JSON_ASSERT_MESSAGE(isInt64(), "Value is not convertible to Int64");
switch ( type_ )
{
- case nullValue:
- return 0;
case intValue:
- return value_.int_;
+ return Int64(value_.int_);
case uintValue:
- JSON_ASSERT_MESSAGE( value_.uint_ <= UInt64(maxInt64), "unsigned integer out of Int64 range" );
- return value_.uint_;
+ return Int64(value_.uint_);
case realValue:
- JSON_ASSERT_MESSAGE( value_.real_ >= minInt64 && value_.real_ <= maxInt64, "Real out of Int64 range" );
return Int64( value_.real_ );
- case booleanValue:
- return value_.bool_ ? 1 : 0;
- case stringValue:
- case arrayValue:
- case objectValue:
- JSON_FAIL_MESSAGE( "Type is not convertible to Int64" );
default:
- JSON_ASSERT_UNREACHABLE;
+ break;
}
- return 0; // unreachable;
+ JSON_ASSERT_UNREACHABLE;
+ return 0;
}
Value::UInt64
Value::asUInt64() const
{
+ JSON_ASSERT_MESSAGE(isUInt64(), "Value is not convertible to UInt64");
switch ( type_ )
{
- case nullValue:
- return 0;
case intValue:
- JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to UInt64" );
- return value_.int_;
+ return UInt64(value_.int_);
case uintValue:
- return value_.uint_;
+ return UInt64(value_.uint_);
case realValue:
- JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt64, "Real out of UInt64 range" );
return UInt64( value_.real_ );
- case booleanValue:
- return value_.bool_ ? 1 : 0;
- case stringValue:
- case arrayValue:
- case objectValue:
- JSON_FAIL_MESSAGE( "Type is not convertible to UInt64" );
default:
- JSON_ASSERT_UNREACHABLE;
+ break;
}
+ JSON_ASSERT_UNREACHABLE;
+ return 0;
return 0; // unreachable;
}
# endif // if defined(JSON_HAS_INT64)
@@ -836,8 +803,6 @@
{
switch ( type_ )
{
- case nullValue:
- return 0.0;
case intValue:
return static_cast<double>( value_.int_ );
case uintValue:
@@ -848,12 +813,12 @@
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
case realValue:
return value_.real_;
+ case nullValue:
case booleanValue:
- return value_.bool_ ? 1.0 : 0.0;
case stringValue:
case arrayValue:
case objectValue:
- JSON_FAIL_MESSAGE( "Type is not convertible to double" );
+ JSON_FAIL_MESSAGE( "Value is not a double" );
default:
JSON_ASSERT_UNREACHABLE;
}
@@ -865,8 +830,6 @@
{
switch ( type_ )
{
- case nullValue:
- return 0.0f;
case intValue:
return static_cast<float>( value_.int_ );
case uintValue:
@@ -877,12 +840,12 @@
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
case realValue:
return static_cast<float>( value_.real_ );
+ case nullValue:
case booleanValue:
- return value_.bool_ ? 1.0f : 0.0f;
case stringValue:
case arrayValue:
case objectValue:
- JSON_FAIL_MESSAGE( "Type is not convertible to float" );
+ JSON_FAIL_MESSAGE( "Value is not a float" );
default:
JSON_ASSERT_UNREACHABLE;
}
@@ -894,20 +857,16 @@
{
switch ( type_ )
{
- case nullValue:
- return false;
- case intValue:
- case uintValue:
- return value_.int_ != 0;
- case realValue:
- return value_.real_ != 0.0;
case booleanValue:
return value_.bool_;
+ case nullValue:
+ case intValue:
+ case uintValue:
+ case realValue:
case stringValue:
- return value_.string_ && value_.string_[0] != 0;
case arrayValue:
case objectValue:
- return value_.map_->size() != 0;
+ JSON_FAIL_MESSAGE( "Value is not a bool" );
default:
JSON_ASSERT_UNREACHABLE;
}
@@ -1366,6 +1325,11 @@
//
//# endif
+static bool IsIntegral(double d) {
+ double integral_part;
+ return modf(d, &integral_part) == 0.0;
+}
+
bool
Value::isNull() const
@@ -1384,30 +1348,106 @@
bool
Value::isInt() const
{
- return type_ == intValue;
+ switch ( type_ )
+ {
+ case intValue:
+ return value_.int_ >= minInt && value_.int_ <= maxInt;
+ case uintValue:
+ return value_.uint_ <= UInt(maxInt);
+ case realValue:
+ return value_.real_ >= minInt &&
+ value_.real_ <= maxInt &&
+ IsIntegral(value_.real_);
+ default:
+ break;
+ }
+ return false;
}
bool
Value::isUInt() const
{
- return type_ == uintValue;
+ switch ( type_ )
+ {
+ case intValue:
+ return value_.int_ >= 0 && value_.int_ <= maxUInt;
+ case uintValue:
+ return value_.uint_ <= maxUInt;
+ case realValue:
+ return value_.real_ >= 0 &&
+ value_.real_ <= maxUInt &&
+ IsIntegral(value_.real_);
+ default:
+ break;
+ }
+ return false;
+}
+
+bool
+Value::isInt64() const
+{
+# if defined(JSON_HAS_INT64)
+ switch ( type_ )
+ {
+ case intValue:
+ return true;
+ case uintValue:
+ return value_.uint_ <= UInt64(maxInt64);
+ case realValue:
+ // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
+ // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
+ // require the value to be strictly less than the limit.
+ return value_.real_ >= double(minInt64) &&
+ value_.real_ < double(maxInt64) &&
+ IsIntegral(value_.real_);
+ default:
+ break;
+ }
+# endif // JSON_HAS_INT64
+ return false;
+}
+
+bool
+Value::isUInt64() const
+{
+# if defined(JSON_HAS_INT64)
+ switch ( type_ )
+ {
+ case intValue:
+ return value_.int_ >= 0;
+ case uintValue:
+ return true;
+ case realValue:
+ // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
+ // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
+ // require the value to be strictly less than the limit.
+ return value_.real_ >= 0 &&
+ value_.real_ < double(maxUInt64) &&
+ IsIntegral(value_.real_);
+ default:
+ break;
+ }
+# endif // JSON_HAS_INT64
+ return false;
}
bool
Value::isIntegral() const
{
- return type_ == intValue
- || type_ == uintValue
- || type_ == booleanValue;
+#if defined(JSON_HAS_INT64)
+ return isInt64() || isUInt64();
+#else
+ return isInt() || isUInt();
+#endif
}
bool
Value::isDouble() const
{
- return type_ == realValue;
+ return type_ == realValue || isIntegral();
}
@@ -1428,14 +1468,14 @@
bool
Value::isArray() const
{
- return type_ == nullValue || type_ == arrayValue;
+ return type_ == arrayValue;
}
bool
Value::isObject() const
{
- return type_ == nullValue || type_ == objectValue;
+ return type_ == objectValue;
}
diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp
index 07b1495..0684c90 100644
--- a/src/test_lib_json/main.cpp
+++ b/src/test_lib_json/main.cpp
@@ -74,13 +74,16 @@
bool isObject_;
bool isArray_;
bool isBool_;
- bool isDouble_;
- bool isInt_;
- bool isUInt_;
- bool isIntegral_;
- bool isNumeric_;
bool isString_;
bool isNull_;
+
+ bool isInt_;
+ bool isInt64_;
+ bool isUInt_;
+ bool isUInt64_;
+ bool isIntegral_;
+ bool isDouble_;
+ bool isNumeric_;
};
void checkConstMemberCount( const Json::Value &value, unsigned int expectedCount );
@@ -120,6 +123,8 @@
JSONTEST_ASSERT_PRED( checkIs( emptyObject_, checks ) );
JSONTEST_ASSERT_PRED( checkIs( object1_, checks ) );
+ JSONTEST_ASSERT_EQUAL( Json::objectValue, emptyObject_.type());
+
// Access through const reference
const Json::Value &constObject = object1_;
@@ -145,6 +150,8 @@
JSONTEST_ASSERT_PRED( checkIs( emptyArray_, checks ) );
JSONTEST_ASSERT_PRED( checkIs( array1_, checks ) );
+ JSONTEST_ASSERT_EQUAL( Json::arrayValue, array1_.type());
+
// Access through const reference
const Json::Value &constArray = array1_;
JSONTEST_ASSERT( Json::Value(1234) == constArray[index0] );
@@ -162,16 +169,18 @@
JSONTEST_FIXTURE( ValueTest, null )
{
+ JSONTEST_ASSERT_EQUAL( Json::nullValue, null_.type());
+
IsCheck checks;
checks.isNull_ = true;
- checks.isObject_ = true;
- checks.isArray_ = true;
JSONTEST_ASSERT_PRED( checkIs( null_, checks ) );
}
JSONTEST_FIXTURE( ValueTest, strings )
{
+ JSONTEST_ASSERT_EQUAL( Json::stringValue, string1_.type());
+
IsCheck checks;
checks.isString_ = true;
JSONTEST_ASSERT_PRED( checkIs( emptyString_, checks ) );
@@ -185,10 +194,10 @@
JSONTEST_FIXTURE( ValueTest, bools )
{
+ JSONTEST_ASSERT_EQUAL( Json::booleanValue, false_.type());
+
IsCheck checks;
checks.isBool_ = true;
- checks.isIntegral_ = true;
- checks.isNumeric_ = true;
JSONTEST_ASSERT_PRED( checkIs( false_, checks ) );
JSONTEST_ASSERT_PRED( checkIs( true_, checks ) );
@@ -209,8 +218,12 @@
checks = IsCheck();
checks.isInt_ = true;
- checks.isNumeric_ = true;
+ checks.isInt64_ = true;
+ checks.isUInt_ = true;
+ checks.isUInt64_ = true;
checks.isIntegral_ = true;
+ checks.isDouble_ = true;
+ checks.isNumeric_ = true;
JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
JSONTEST_ASSERT( 0 == val.asInt());
@@ -226,9 +239,35 @@
JSONTEST_ASSERT_EQUAL(Json::uintValue, val.type());
checks = IsCheck();
+ checks.isInt_ = true;
+ checks.isInt64_ = true;
checks.isUInt_ = true;
- checks.isNumeric_ = true;
+ checks.isUInt64_ = true;
checks.isIntegral_ = true;
+ checks.isDouble_ = true;
+ checks.isNumeric_ = true;
+ JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
+
+ JSONTEST_ASSERT( 0 == val.asInt());
+ JSONTEST_ASSERT( 0 == val.asLargestInt());
+ JSONTEST_ASSERT( 0 == val.asUInt());
+ JSONTEST_ASSERT( 0 == val.asLargestUInt());
+ JSONTEST_ASSERT( 0.0 == val.asDouble());
+ JSONTEST_ASSERT( 0.0 == val.asFloat());
+
+ // Default real
+ val = Json::Value(Json::realValue);
+
+ JSONTEST_ASSERT_EQUAL(Json::realValue, val.type());
+
+ checks = IsCheck();
+ checks.isInt_ = true;
+ checks.isInt64_ = true;
+ checks.isUInt_ = true;
+ checks.isUInt64_ = true;
+ checks.isIntegral_ = true;
+ checks.isDouble_ = true;
+ checks.isNumeric_ = true;
JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
JSONTEST_ASSERT( 0 == val.asInt());
@@ -241,10 +280,16 @@
// Zero (signed constructor arg)
val = Json::Value(0);
+ JSONTEST_ASSERT_EQUAL( Json::intValue, val.type());
+
checks = IsCheck();
checks.isInt_ = true;
- checks.isNumeric_ = true;
+ checks.isInt64_ = true;
+ checks.isUInt_ = true;
+ checks.isUInt64_ = true;
checks.isIntegral_ = true;
+ checks.isDouble_ = true;
+ checks.isNumeric_ = true;
JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
JSONTEST_ASSERT( 0 == val.asInt());
@@ -257,10 +302,16 @@
// Zero (unsigned constructor arg)
val = Json::Value(0u);
+ JSONTEST_ASSERT_EQUAL( Json::uintValue, val.type());
+
checks = IsCheck();
+ checks.isInt_ = true;
+ checks.isInt64_ = true;
checks.isUInt_ = true;
- checks.isNumeric_ = true;
+ checks.isUInt64_ = true;
checks.isIntegral_ = true;
+ checks.isDouble_ = true;
+ checks.isNumeric_ = true;
JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
JSONTEST_ASSERT( 0 == val.asInt());
@@ -273,7 +324,14 @@
// Zero (floating-point constructor arg)
val = Json::Value(0.0);
+ JSONTEST_ASSERT_EQUAL( Json::realValue, val.type());
+
checks = IsCheck();
+ checks.isInt_ = true;
+ checks.isInt64_ = true;
+ checks.isUInt_ = true;
+ checks.isUInt64_ = true;
+ checks.isIntegral_ = true;
checks.isDouble_ = true;
checks.isNumeric_ = true;
JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
@@ -288,10 +346,16 @@
// 2^20 (signed constructor arg)
val = Json::Value(1 << 20);
+ JSONTEST_ASSERT_EQUAL( Json::intValue, val.type());
+
checks = IsCheck();
checks.isInt_ = true;
- checks.isNumeric_ = true;
+ checks.isInt64_ = true;
+ checks.isUInt_ = true;
+ checks.isUInt64_ = true;
checks.isIntegral_ = true;
+ checks.isDouble_ = true;
+ checks.isNumeric_ = true;
JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
JSONTEST_ASSERT( (1 << 20) == val.asInt());
@@ -304,10 +368,16 @@
// 2^20 (unsigned constructor arg)
val = Json::Value(1u << 20);
+ JSONTEST_ASSERT_EQUAL( Json::uintValue, val.type());
+
checks = IsCheck();
+ checks.isInt_ = true;
+ checks.isInt64_ = true;
checks.isUInt_ = true;
- checks.isNumeric_ = true;
+ checks.isUInt64_ = true;
checks.isIntegral_ = true;
+ checks.isDouble_ = true;
+ checks.isNumeric_ = true;
JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
JSONTEST_ASSERT( (1 << 20) == val.asInt());
@@ -320,7 +390,14 @@
// 2^20 (floating-point constructor arg)
val = Json::Value((1 << 20) / 1.0);
+ JSONTEST_ASSERT_EQUAL( Json::realValue, val.type());
+
checks = IsCheck();
+ checks.isInt_ = true;
+ checks.isInt64_ = true;
+ checks.isUInt_ = true;
+ checks.isUInt64_ = true;
+ checks.isIntegral_ = true;
checks.isDouble_ = true;
checks.isNumeric_ = true;
JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
@@ -335,10 +412,14 @@
// -2^20
val = Json::Value(-(1 << 20));
+ JSONTEST_ASSERT_EQUAL( Json::intValue, val.type());
+
checks = IsCheck();
checks.isInt_ = true;
- checks.isNumeric_ = true;
+ checks.isInt64_ = true;
checks.isIntegral_ = true;
+ checks.isDouble_ = true;
+ checks.isNumeric_ = true;
JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
JSONTEST_ASSERT( -(1 << 20) == val.asInt());
@@ -349,10 +430,16 @@
// int32 max
val = Json::Value(kint32max);
+ JSONTEST_ASSERT_EQUAL( Json::intValue, val.type());
+
checks = IsCheck();
checks.isInt_ = true;
- checks.isNumeric_ = true;
+ checks.isInt64_ = true;
+ checks.isUInt_ = true;
+ checks.isUInt64_ = true;
checks.isIntegral_ = true;
+ checks.isDouble_ = true;
+ checks.isNumeric_ = true;
JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
JSONTEST_ASSERT( kint32max == val.asInt());
@@ -365,10 +452,14 @@
// int32 min
val = Json::Value(kint32min);
+ JSONTEST_ASSERT_EQUAL( Json::intValue, val.type());
+
checks = IsCheck();
checks.isInt_ = true;
- checks.isNumeric_ = true;
+ checks.isInt64_ = true;
checks.isIntegral_ = true;
+ checks.isDouble_ = true;
+ checks.isNumeric_ = true;
JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
JSONTEST_ASSERT( kint32min == val.asInt());
@@ -379,10 +470,15 @@
// uint32 max
val = Json::Value(kuint32max);
+ JSONTEST_ASSERT_EQUAL( Json::uintValue, val.type());
+
checks = IsCheck();
+ checks.isInt64_ = true;
checks.isUInt_ = true;
- checks.isNumeric_ = true;
+ checks.isUInt64_ = true;
checks.isIntegral_ = true;
+ checks.isDouble_ = true;
+ checks.isNumeric_ = true;
JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
#ifndef JSON_NO_INT64
@@ -397,6 +493,8 @@
// int64 max
val = Json::Value(double(kint64max));
+ JSONTEST_ASSERT_EQUAL( Json::realValue, val.type());
+
checks = IsCheck();
checks.isDouble_ = true;
checks.isNumeric_ = true;
@@ -408,6 +506,8 @@
// int64 min
val = Json::Value(double(kint64min));
+ JSONTEST_ASSERT_EQUAL( Json::realValue, val.type());
+
checks = IsCheck();
checks.isDouble_ = true;
checks.isNumeric_ = true;
@@ -419,6 +519,8 @@
// uint64 max
val = Json::Value(double(kuint64max));
+ JSONTEST_ASSERT_EQUAL( Json::realValue, val.type());
+
checks = IsCheck();
checks.isDouble_ = true;
checks.isNumeric_ = true;
@@ -430,10 +532,14 @@
// 2^40 (signed constructor arg)
val = Json::Value(1LL << 40);
+ JSONTEST_ASSERT_EQUAL( Json::intValue, val.type());
+
checks = IsCheck();
- checks.isInt_ = true;
- checks.isNumeric_ = true;
+ checks.isInt64_ = true;
+ checks.isUInt64_ = true;
checks.isIntegral_ = true;
+ checks.isDouble_ = true;
+ checks.isNumeric_ = true;
JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
JSONTEST_ASSERT( (1LL << 40) == val.asInt64());
@@ -446,10 +552,14 @@
// 2^40 (unsigned constructor arg)
val = Json::Value(1ULL << 40);
+ JSONTEST_ASSERT_EQUAL( Json::uintValue, val.type());
+
checks = IsCheck();
- checks.isUInt_ = true;
- checks.isNumeric_ = true;
+ checks.isInt64_ = true;
+ checks.isUInt64_ = true;
checks.isIntegral_ = true;
+ checks.isDouble_ = true;
+ checks.isNumeric_ = true;
JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
JSONTEST_ASSERT( (1LL << 40) == val.asInt64());
@@ -462,7 +572,12 @@
// 2^40 (floating-point constructor arg)
val = Json::Value((1LL << 40) / 1.0);
+ JSONTEST_ASSERT_EQUAL( Json::realValue, val.type());
+
checks = IsCheck();
+ checks.isInt64_ = true;
+ checks.isUInt64_ = true;
+ checks.isIntegral_ = true;
checks.isDouble_ = true;
checks.isNumeric_ = true;
JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
@@ -477,10 +592,13 @@
// -2^40
val = Json::Value(-(1LL << 40));
+ JSONTEST_ASSERT_EQUAL( Json::intValue, val.type());
+
checks = IsCheck();
- checks.isInt_ = true;
- checks.isNumeric_ = true;
+ checks.isInt64_ = true;
checks.isIntegral_ = true;
+ checks.isDouble_ = true;
+ checks.isNumeric_ = true;
JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
JSONTEST_ASSERT( -(1LL << 40) == val.asInt64());
@@ -491,10 +609,14 @@
// int64 max
val = Json::Value(Json::Int64(kint64max));
+ JSONTEST_ASSERT_EQUAL( Json::intValue, val.type());
+
checks = IsCheck();
- checks.isInt_ = true;
- checks.isNumeric_ = true;
+ checks.isInt64_ = true;
+ checks.isUInt64_ = true;
checks.isIntegral_ = true;
+ checks.isDouble_ = true;
+ checks.isNumeric_ = true;
JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
JSONTEST_ASSERT( kint64max == val.asInt64());
@@ -504,13 +626,34 @@
JSONTEST_ASSERT( double(kint64max) == val.asDouble());
JSONTEST_ASSERT( float(kint64max) == val.asFloat());
+ // int64 max (floating point constructor). Note that kint64max is not exactly
+ // representable as a double, and will be rounded up to be higher.
+ val = Json::Value(double(kint64max));
+
+ JSONTEST_ASSERT_EQUAL( Json::realValue, val.type());
+
+ checks = IsCheck();
+ checks.isUInt64_ = true;
+ checks.isIntegral_ = true;
+ checks.isDouble_ = true;
+ checks.isNumeric_ = true;
+ JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
+
+ JSONTEST_ASSERT( 9223372036854775808ULL == val.asUInt64());
+ JSONTEST_ASSERT( 9223372036854775808ULL == val.asLargestUInt());
+ JSONTEST_ASSERT( 9223372036854775808ULL == val.asDouble());
+ JSONTEST_ASSERT( 9223372036854775808ULL == val.asFloat());
+
// int64 min
val = Json::Value(Json::Int64(kint64min));
+ JSONTEST_ASSERT_EQUAL( Json::intValue, val.type());
+
checks = IsCheck();
- checks.isInt_ = true;
- checks.isNumeric_ = true;
+ checks.isInt64_ = true;
checks.isIntegral_ = true;
+ checks.isDouble_ = true;
+ checks.isNumeric_ = true;
JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
JSONTEST_ASSERT( kint64min == val.asInt64());
@@ -518,19 +661,54 @@
JSONTEST_ASSERT( double(kint64min) == val.asDouble());
JSONTEST_ASSERT( float(kint64min) == val.asFloat());
+ // int64 min (floating point constructor). Note that kint64min *is* exactly
+ // representable as a double.
+ val = Json::Value(double(kint64min));
+
+ JSONTEST_ASSERT_EQUAL( Json::realValue, val.type());
+
+ checks = IsCheck();
+ checks.isInt64_ = true;
+ checks.isIntegral_ = true;
+ checks.isDouble_ = true;
+ checks.isNumeric_ = true;
+ JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
+
+ JSONTEST_ASSERT( -9223372036854775808LL == val.asInt64());
+ JSONTEST_ASSERT( -9223372036854775808LL == val.asLargestInt());
+ JSONTEST_ASSERT( -9223372036854775808.0 == val.asDouble());
+ JSONTEST_ASSERT( -9223372036854775808.0 == val.asFloat());
+
// uint64 max
val = Json::Value(Json::UInt64(kuint64max));
+ JSONTEST_ASSERT_EQUAL( Json::uintValue, val.type());
+
checks = IsCheck();
- checks.isUInt_ = true;
- checks.isNumeric_ = true;
+ checks.isUInt64_ = true;
checks.isIntegral_ = true;
+ checks.isDouble_ = true;
+ checks.isNumeric_ = true;
JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
JSONTEST_ASSERT( kuint64max == val.asUInt64());
JSONTEST_ASSERT( kuint64max == val.asLargestUInt());
JSONTEST_ASSERT( double(kuint64max) == val.asDouble());
JSONTEST_ASSERT( float(kuint64max) == val.asFloat());
+
+ // 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));
+
+ JSONTEST_ASSERT_EQUAL( Json::realValue, val.type());
+
+ checks = IsCheck();
+ checks.isDouble_ = true;
+ checks.isNumeric_ = true;
+ JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
+
+ JSONTEST_ASSERT( 18446744073709551616.0 == val.asDouble());
+ JSONTEST_ASSERT( 18446744073709551616.0 == val.asFloat());
#endif
}
@@ -540,26 +718,11 @@
IsCheck checks;
Json::Value val;
- // Default real
- val = Json::Value(Json::realValue);
-
- JSONTEST_ASSERT_EQUAL(Json::realValue, val.type());
-
- checks = IsCheck();
- checks.isDouble_ = true;
- checks.isNumeric_ = true;
- JSONTEST_ASSERT_PRED( checkIs( val, checks ) );
-
- JSONTEST_ASSERT( 0 == val.asInt());
- JSONTEST_ASSERT( 0 == val.asLargestInt());
- JSONTEST_ASSERT( 0 == val.asUInt());
- JSONTEST_ASSERT( 0 == val.asLargestUInt());
- JSONTEST_ASSERT( 0.0 == val.asDouble());
- JSONTEST_ASSERT( 0.0 == val.asFloat());
-
// Positive number
val = Json::Value(0.25);
+ JSONTEST_ASSERT_EQUAL( Json::realValue, val.type());
+
checks = IsCheck();
checks.isDouble_ = true;
checks.isNumeric_ = true;
@@ -571,6 +734,8 @@
// Negative number
val = Json::Value(-0.25);
+ JSONTEST_ASSERT_EQUAL( Json::realValue, val.type());
+
checks = IsCheck();
checks.isDouble_ = true;
checks.isNumeric_ = true;
@@ -614,13 +779,15 @@
: isObject_( false )
, isArray_( false )
, isBool_( false )
- , isDouble_( false )
- , isInt_( false )
- , isUInt_( false )
- , isIntegral_( false )
- , isNumeric_( false )
, isString_( false )
, isNull_( false )
+ , isInt_( false )
+ , isInt64_( false )
+ , isUInt_( false )
+ , isUInt64_( false )
+ , isIntegral_( false )
+ , isDouble_( false )
+ , isNumeric_( false )
{
}
@@ -633,7 +800,9 @@
JSONTEST_ASSERT_EQUAL( check.isBool_, value.isBool() );
JSONTEST_ASSERT_EQUAL( check.isDouble_, value.isDouble() );
JSONTEST_ASSERT_EQUAL( check.isInt_, value.isInt() );
+ JSONTEST_ASSERT_EQUAL( check.isInt64_, value.isInt64() );
JSONTEST_ASSERT_EQUAL( check.isUInt_, value.isUInt() );
+ JSONTEST_ASSERT_EQUAL( check.isUInt64_, value.isUInt64() );
JSONTEST_ASSERT_EQUAL( check.isIntegral_, value.isIntegral() );
JSONTEST_ASSERT_EQUAL( check.isNumeric_, value.isNumeric() );
JSONTEST_ASSERT_EQUAL( check.isString_, value.isString() );