Major rework of 64 integer support: 64 bits integer are only returned when explicitly request via Json::Value::asInt64(), unlike previous implementation where Json::Value::asInt() returned a 64 bits integer.

This eases porting portable code and does not break compatibility with the previous release.

Json::Value::asLargestInt() has also be added to ease writing portable code independent of 64 bits integer support. It is typically used to implement writers.
This commit is contained in:
Baptiste Lepilleur 2010-12-27 17:45:23 +00:00
parent 5c5628aec2
commit 842e9ac54b
9 changed files with 266 additions and 89 deletions

View File

@ -18,17 +18,38 @@
initialization/destruction order issues (bug #2934500).
The DefaultValueAllocator has been inlined in code.
- Added support for 64 bits integer. Json::Int and Json::UInt are
now 64 bits integers on system that support them (more precisely
they are of the size of long long, so if it is 128 bits it will
also work).
- Added support for 64 bits integer:
Types Json::Int64 and Json::UInt64 have been added. They are aliased
to 64 bits integers on system that support them (based on __int64 on
Microsoft Visual Studio platform, and long long on other platforms).
Types Json::LargestInt and Json::LargestUInt have been added. They are
aliased to the largest integer type supported:
either Json::Int/Json::UInt or Json::Int64/Json::UInt64 respectively.
Json::Value::asInt() and Json::Value::asUInt() still returns plain
"int" based types, but asserts if an attempt is made to retrieve
a 64 bits value that can not represented as the return type.
Json::Value::asInt64() and Json::Value::asUInt64() have been added
to obtain the 64 bits integer value.
Json::Value::asLargestInt() and Json::Value::asLargestUInt() returns
the integer as a LargestInt/LargestUInt respectively. Those functions
functions are typically used when implementing writer.
The reader attempts to read number as 64 bits integer, and fall back
to reading a double if the number is not in the range of 64 bits
integer.
Warning: Json::Value::asInt() and Json::Value::asUInt() now returns
long long. This changes break code that was passing the return value
to *printf() function.
Notes: you can switch back to the 32 bits only behavior by defining the
macro JSON_NO_INT64 (se include/json/config.h).
Support for 64 bits integer can be disabled by defining the macro
JSON_NO_INT64 (uncomment it in json/config.h for example), though
it should have no impact on existing usage.
- The type Json::ArrayIndex is used for indexes of a JSON value array. It
is an unsigned int (typically 32 bits).

View File

@ -46,7 +46,7 @@
# endif
// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for integer
// Storages.
// Storages, and 64 bits integer support is disabled.
// #define JSON_NO_INT64 1
#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6
@ -57,18 +57,24 @@
namespace Json {
# if defined(JSON_NO_INT64)
typedef int Int;
typedef unsigned int UInt;
# if defined(JSON_NO_INT64)
typedef int LargestInt;
typedef unsigned int LargestUInt;
# undef JSON_HAS_INT64
# else // if defined(JSON_NO_INT64)
// For Microsoft Visual use specific types as long long is not supported
# if defined(_MSC_VER) // Microsoft Visual Studio
typedef __int64 Int;
typedef unsigned __int64 UInt;
typedef __int64 Int64;
typedef unsigned __int64 UInt64;
# else // if defined(_MSC_VER) // Other platforms, use long long
typedef long long int Int;
typedef unsigned long long int UInt;
typedef long long int Int64;
typedef unsigned long long int UInt64;
# endif // if defined(_MSC_VER)
typedef Int64 LargestInt;
typedef UInt64 LargestUInt;
# define JSON_HAS_INT64
# endif // if defined(JSON_NO_INT64)
} // end namespace Json

View File

@ -126,13 +126,36 @@ namespace Json {
typedef ValueConstIterator const_iterator;
typedef Json::UInt UInt;
typedef Json::Int Int;
# if defined(JSON_HAS_INT64)
typedef Json::UInt64 UInt64;
typedef Json::Int64 Int64;
#endif // defined(JSON_HAS_INT64)
typedef Json::LargestInt LargestInt;
typedef Json::LargestUInt LargestUInt;
typedef Json::ArrayIndex ArrayIndex;
static const Value null;
static const Int minInt;
/// Minimum signed integer value that can be stored in a Json::Value.
static const LargestInt minLargestInt;
/// Maximum signed integer value that can be stored in a Json::Value.
static const LargestInt maxLargestInt;
/// Maximum unsigned integer value that can be stored in a Json::Value.
static const LargestUInt maxLargestUInt;
/// Minimum signed int value that can be stored in a Json::Value.
static const Int minInt;
/// Maximum signed int value that can be stored in a Json::Value.
static const Int maxInt;
/// Maximum unsigned int value that can be stored in a Json::Value.
static const UInt maxUInt;
/// Minimum signed 64 bits int value that can be stored in a Json::Value.
static const Int64 minInt64;
/// Maximum signed 64 bits int value that can be stored in a Json::Value.
static const Int64 maxInt64;
/// Maximum unsigned 64 bits int value that can be stored in a Json::Value.
static const UInt64 maxUInt64;
private:
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
# ifndef JSON_VALUE_USE_INTERNAL_MAP
@ -187,12 +210,12 @@ namespace Json {
\endcode
*/
Value( ValueType type = nullValue );
#if !defined(JSON_NO_INT64)
Value( int value );
Value( ArrayIndex value );
#endif // if !defined(JSON_NO_INT64)
Value( Int value );
Value( UInt value );
#if defined(JSON_HAS_INT64)
Value( Int64 value );
Value( UInt64 value );
#endif // if defined(JSON_HAS_INT64)
Value( double value );
Value( const char *value );
Value( const char *beginValue, const char *endValue );
@ -240,6 +263,10 @@ namespace Json {
# endif
Int asInt() const;
UInt asUInt() const;
Int64 asInt64() const;
UInt64 asUInt64() const;
LargestInt asLargestInt() const;
LargestUInt asLargestUInt() const;
float asFloat() const;
double asDouble() const;
bool asBool() const;
@ -448,8 +475,8 @@ namespace Json {
union ValueHolder
{
Int int_;
UInt uint_;
LargestInt int_;
LargestUInt uint_;
double real_;
bool bool_;
char *string_;

View File

@ -162,8 +162,12 @@ namespace Json {
bool addChildValues_;
};
# if defined(JSON_HAS_INT64)
std::string JSON_API valueToString( Int value );
std::string JSON_API valueToString( UInt value );
# endif // if defined(JSON_HAS_INT64)
std::string JSON_API valueToString( LargestInt value );
std::string JSON_API valueToString( LargestUInt value );
std::string JSON_API valueToString( double value );
std::string JSON_API valueToString( bool value );
std::string JSON_API valueToQuotedString( const char *value );

View File

@ -44,10 +44,10 @@ printValueTree( FILE *fout, Json::Value &value, const std::string &path = "." )
fprintf( fout, "%s=null\n", path.c_str() );
break;
case Json::intValue:
fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asInt() ).c_str() );
fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asLargestInt() ).c_str() );
break;
case Json::uintValue:
fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asUInt() ).c_str() );
fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asLargestUInt() ).c_str() );
break;
case Json::realValue:
fprintf( fout, "%s=%.16g\n", path.c_str(), value.asDouble() );
@ -224,36 +224,44 @@ int main( int argc, const char *argv[] )
return exitCode;
}
std::string input = readInputTestFile( path.c_str() );
if ( input.empty() )
try
{
printf( "Failed to read input or empty input: %s\n", path.c_str() );
return 3;
}
std::string basePath = removeSuffix( argv[1], ".json" );
if ( !parseOnly && basePath.empty() )
{
printf( "Bad input path. Path does not end with '.expected':\n%s\n", path.c_str() );
return 3;
}
std::string actualPath = basePath + ".actual";
std::string rewritePath = basePath + ".rewrite";
std::string rewriteActualPath = basePath + ".actual-rewrite";
Json::Value root;
exitCode = parseAndSaveValueTree( input, actualPath, "input", root, features, parseOnly );
if ( exitCode == 0 && !parseOnly )
{
std::string rewrite;
exitCode = rewriteValueTree( rewritePath, root, rewrite );
if ( exitCode == 0 )
std::string input = readInputTestFile( path.c_str() );
if ( input.empty() )
{
Json::Value rewriteRoot;
exitCode = parseAndSaveValueTree( rewrite, rewriteActualPath,
"rewrite", rewriteRoot, features, parseOnly );
printf( "Failed to read input or empty input: %s\n", path.c_str() );
return 3;
}
std::string basePath = removeSuffix( argv[1], ".json" );
if ( !parseOnly && basePath.empty() )
{
printf( "Bad input path. Path does not end with '.expected':\n%s\n", path.c_str() );
return 3;
}
std::string actualPath = basePath + ".actual";
std::string rewritePath = basePath + ".rewrite";
std::string rewriteActualPath = basePath + ".actual-rewrite";
Json::Value root;
exitCode = parseAndSaveValueTree( input, actualPath, "input", root, features, parseOnly );
if ( exitCode == 0 && !parseOnly )
{
std::string rewrite;
exitCode = rewriteValueTree( rewritePath, root, rewrite );
if ( exitCode == 0 )
{
Json::Value rewriteRoot;
exitCode = parseAndSaveValueTree( rewrite, rewriteActualPath,
"rewrite", rewriteRoot, features, parseOnly );
}
}
}
catch ( const std::exception &e )
{
printf( "Unhandled exception:\n%s\n", e.what() );
exitCode = 1;
}
return exitCode;

View File

@ -567,12 +567,12 @@ Reader::decodeNumber( Token &token )
bool isNegative = *current == '-';
if ( isNegative )
++current;
Value::UInt maxIntegerValue = isNegative ? Value::UInt(-Value::minInt)
: Value::maxUInt;
Value::UInt threshold = maxIntegerValue / 10;
Value::UInt lastDigitThreshold = maxIntegerValue % 10;
Value::LargestUInt maxIntegerValue = isNegative ? Value::LargestUInt(-Value::minLargestInt)
: Value::maxLargestUInt;
Value::LargestUInt threshold = maxIntegerValue / 10;
Value::UInt lastDigitThreshold = Value::UInt( maxIntegerValue % 10 );
assert( lastDigitThreshold >=0 && lastDigitThreshold <= 9 );
Value::UInt value = 0;
Value::LargestUInt value = 0;
while ( current < token.end_ )
{
Char c = *current++;
@ -592,9 +592,9 @@ Reader::decodeNumber( Token &token )
value = value * 10 + digit;
}
if ( isNegative )
currentValue() = -Value::Int( value );
else if ( value <= Value::UInt(Value::maxInt) )
currentValue() = Value::Int( value );
currentValue() = -Value::LargestInt( value );
else if ( value <= Value::LargestUInt(Value::maxInt) )
currentValue() = Value::LargestInt( value );
else
currentValue() = value;
return true;

View File

@ -63,7 +63,7 @@ isControlCharacter(char ch)
enum {
/// Constant that specify the size of the buffer that must be passed to uintToString.
uintToStringBufferSize = 3*sizeof(UInt)+1
uintToStringBufferSize = 3*sizeof(LargestUInt)+1
};
// Defines a char buffer for use with uintToString().
@ -76,7 +76,7 @@ typedef char UIntToStringBuffer[uintToStringBufferSize];
* Must have at least uintToStringBufferSize chars free.
*/
static inline void
uintToString( UInt value,
uintToString( LargestUInt value,
char *&current )
{
*--current = 0;

View File

@ -28,6 +28,13 @@ const Value Value::null;
const Int Value::minInt = Int( ~(UInt(-1)/2) );
const Int Value::maxInt = Int( UInt(-1)/2 );
const UInt Value::maxUInt = UInt(-1);
const Int64 Value::minInt64 = Int64( ~(UInt64(-1)/2) );
const Int64 Value::maxInt64 = Int64( UInt64(-1)/2 );
const UInt64 Value::maxUInt64 = UInt64(-1);
const LargestInt Value::minLargestInt = LargestInt( ~(LargestUInt(-1)/2) );
const LargestInt Value::maxLargestInt = LargestInt( LargestUInt(-1)/2 );
const LargestUInt Value::maxLargestUInt = LargestUInt(-1);
/// Unknown size marker
enum { unknown = (unsigned)-1 };
@ -262,8 +269,8 @@ Value::Value( ValueType type )
}
#if !defined(JSON_NO_INT64)
Value::Value( ArrayIndex value )
#if defined(JSON_HAS_INT64)
Value::Value( UInt value )
: type_( uintValue )
, comments_( 0 )
# ifdef JSON_VALUE_USE_INTERNAL_MAP
@ -273,19 +280,6 @@ Value::Value( ArrayIndex value )
value_.uint_ = value;
}
Value::Value( int value )
: type_( intValue )
, comments_( 0 )
# ifdef JSON_VALUE_USE_INTERNAL_MAP
, itemIsUsed_( 0 )
#endif
{
value_.int_ = value;
}
#endif // if !defined(JSON_NO_INT64)
Value::Value( Int value )
: type_( intValue )
, comments_( 0 )
@ -296,8 +290,21 @@ Value::Value( Int value )
value_.int_ = value;
}
#endif // if defined(JSON_HAS_INT64)
Value::Value( UInt value )
Value::Value( Int64 value )
: type_( intValue )
, comments_( 0 )
# ifdef JSON_VALUE_USE_INTERNAL_MAP
, itemIsUsed_( 0 )
#endif
{
value_.int_ = value;
}
Value::Value( UInt64 value )
: type_( uintValue )
, comments_( 0 )
# ifdef JSON_VALUE_USE_INTERNAL_MAP
@ -689,6 +696,7 @@ Value::asConstString() const
}
# endif
Value::Int
Value::asInt() const
{
@ -697,10 +705,11 @@ Value::asInt() const
case nullValue:
return 0;
case intValue:
return value_.int_;
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_ < (unsigned)maxInt, "integer out of signed integer range" );
return value_.uint_;
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_ );
@ -716,6 +725,7 @@ Value::asInt() const
return 0; // unreachable;
}
Value::UInt
Value::asUInt() const
{
@ -725,9 +735,11 @@ Value::asUInt() const
return 0;
case intValue:
JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" );
return value_.int_;
JSON_ASSERT_MESSAGE( value_.int_ <= maxUInt, "signed integer out of UInt range" );
return UInt(value_.int_);
case uintValue:
return value_.uint_;
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_ );
@ -743,6 +755,88 @@ Value::asUInt() const
return 0; // unreachable;
}
# if defined(JSON_HAS_INT64)
Value::Int64
Value::asInt64() const
{
switch ( type_ )
{
case nullValue:
return 0;
case intValue:
return value_.int_;
case uintValue:
JSON_ASSERT_MESSAGE( value_.uint_ <= UInt64(maxInt64), "unsigned integer out of Int64 range" );
return value_.uint_;
case realValue:
JSON_ASSERT_MESSAGE( value_.real_ >= minInt64 && value_.real_ <= maxInt64, "Real out of Int64 range" );
return Int( value_.real_ );
case booleanValue:
return value_.bool_ ? 1 : 0;
case stringValue:
case arrayValue:
case objectValue:
JSON_ASSERT_MESSAGE( false, "Type is not convertible to Int64" );
default:
JSON_ASSERT_UNREACHABLE;
}
return 0; // unreachable;
}
Value::UInt64
Value::asUInt64() const
{
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_;
case uintValue:
return value_.uint_;
case realValue:
JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt64, "Real out of UInt64 range" );
return UInt( value_.real_ );
case booleanValue:
return value_.bool_ ? 1 : 0;
case stringValue:
case arrayValue:
case objectValue:
JSON_ASSERT_MESSAGE( false, "Type is not convertible to UInt64" );
default:
JSON_ASSERT_UNREACHABLE;
}
return 0; // unreachable;
}
# endif // if defined(JSON_HAS_INT64)
LargestInt
Value::asLargestInt() const
{
#if defined(JSON_NO_INT64)
return asInt();
#else
return asInt64();
#endif
}
LargestUInt
Value::asLargestUInt() const
{
#if defined(JSON_NO_INT64)
return asUInt();
#else
return asUInt64();
#endif
}
double
Value::asDouble() const
{

View File

@ -29,14 +29,15 @@ static bool containsControlCharacter( const char* str )
return false;
}
std::string valueToString( Int value )
std::string valueToString( LargestInt value )
{
UIntToStringBuffer buffer;
char *current = buffer + sizeof(buffer);
bool isNegative = value < 0;
if ( isNegative )
value = -value;
uintToString( UInt(value), current );
uintToString( LargestUInt(value), current );
if ( isNegative )
*--current = '-';
assert( current >= buffer );
@ -44,7 +45,7 @@ std::string valueToString( Int value )
}
std::string valueToString( UInt value )
std::string valueToString( LargestUInt value )
{
UIntToStringBuffer buffer;
char *current = buffer + sizeof(buffer);
@ -53,6 +54,22 @@ std::string valueToString( UInt value )
return current;
}
#if defined(JSON_HAS_INT64)
std::string valueToString( Int value )
{
return valueToString( LargestInt(value) );
}
std::string valueToString( UInt value )
{
return valueToString( LargestUInt(value) );
}
#endif // # if defined(JSON_HAS_INT64)
std::string valueToString( double value )
{
char buffer[32];
@ -203,10 +220,10 @@ FastWriter::writeValue( const Value &value )
document_ += "null";
break;
case intValue:
document_ += valueToString( value.asInt() );
document_ += valueToString( value.asLargestInt() );
break;
case uintValue:
document_ += valueToString( value.asUInt() );
document_ += valueToString( value.asLargestUInt() );
break;
case realValue:
document_ += valueToString( value.asDouble() );
@ -286,10 +303,10 @@ StyledWriter::writeValue( const Value &value )
pushValue( "null" );
break;
case intValue:
pushValue( valueToString( value.asInt() ) );
pushValue( valueToString( value.asLargestInt() ) );
break;
case uintValue:
pushValue( valueToString( value.asUInt() ) );
pushValue( valueToString( value.asLargestUInt() ) );
break;
case realValue:
pushValue( valueToString( value.asDouble() ) );
@ -562,10 +579,10 @@ StyledStreamWriter::writeValue( const Value &value )
pushValue( "null" );
break;
case intValue:
pushValue( valueToString( value.asInt() ) );
pushValue( valueToString( value.asLargestInt() ) );
break;
case uintValue:
pushValue( valueToString( value.asUInt() ) );
pushValue( valueToString( value.asLargestUInt() ) );
break;
case realValue:
pushValue( valueToString( value.asDouble() ) );