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). initialization/destruction order issues (bug #2934500).
The DefaultValueAllocator has been inlined in code. The DefaultValueAllocator has been inlined in code.
- Added support for 64 bits integer. Json::Int and Json::UInt are - Added support for 64 bits integer:
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 Types Json::Int64 and Json::UInt64 have been added. They are aliased
also work). 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 Warning: Json::Value::asInt() and Json::Value::asUInt() now returns
long long. This changes break code that was passing the return value long long. This changes break code that was passing the return value
to *printf() function. to *printf() function.
Notes: you can switch back to the 32 bits only behavior by defining the Support for 64 bits integer can be disabled by defining the macro
macro JSON_NO_INT64 (se include/json/config.h). 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 - The type Json::ArrayIndex is used for indexes of a JSON value array. It
is an unsigned int (typically 32 bits). is an unsigned int (typically 32 bits).

View File

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

View File

@ -126,13 +126,36 @@ namespace Json {
typedef ValueConstIterator const_iterator; typedef ValueConstIterator const_iterator;
typedef Json::UInt UInt; typedef Json::UInt UInt;
typedef Json::Int Int; 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; typedef Json::ArrayIndex ArrayIndex;
static const Value null; 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; static const Int maxInt;
/// Maximum unsigned int value that can be stored in a Json::Value.
static const UInt maxUInt; 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: private:
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
# ifndef JSON_VALUE_USE_INTERNAL_MAP # ifndef JSON_VALUE_USE_INTERNAL_MAP
@ -187,12 +210,12 @@ namespace Json {
\endcode \endcode
*/ */
Value( ValueType type = nullValue ); 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( Int value );
Value( UInt 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( double value );
Value( const char *value ); Value( const char *value );
Value( const char *beginValue, const char *endValue ); Value( const char *beginValue, const char *endValue );
@ -240,6 +263,10 @@ namespace Json {
# endif # endif
Int asInt() const; Int asInt() const;
UInt asUInt() const; UInt asUInt() const;
Int64 asInt64() const;
UInt64 asUInt64() const;
LargestInt asLargestInt() const;
LargestUInt asLargestUInt() const;
float asFloat() const; float asFloat() const;
double asDouble() const; double asDouble() const;
bool asBool() const; bool asBool() const;
@ -448,8 +475,8 @@ namespace Json {
union ValueHolder union ValueHolder
{ {
Int int_; LargestInt int_;
UInt uint_; LargestUInt uint_;
double real_; double real_;
bool bool_; bool bool_;
char *string_; char *string_;

View File

@ -162,8 +162,12 @@ namespace Json {
bool addChildValues_; bool addChildValues_;
}; };
# if defined(JSON_HAS_INT64)
std::string JSON_API valueToString( Int value ); std::string JSON_API valueToString( Int value );
std::string JSON_API valueToString( UInt 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( double value );
std::string JSON_API valueToString( bool value ); std::string JSON_API valueToString( bool value );
std::string JSON_API valueToQuotedString( const char *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() ); fprintf( fout, "%s=null\n", path.c_str() );
break; break;
case Json::intValue: 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; break;
case Json::uintValue: 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; break;
case Json::realValue: case Json::realValue:
fprintf( fout, "%s=%.16g\n", path.c_str(), value.asDouble() ); fprintf( fout, "%s=%.16g\n", path.c_str(), value.asDouble() );
@ -224,36 +224,44 @@ int main( int argc, const char *argv[] )
return exitCode; return exitCode;
} }
std::string input = readInputTestFile( path.c_str() ); try
if ( input.empty() )
{ {
printf( "Failed to read input or empty input: %s\n", path.c_str() ); std::string input = readInputTestFile( path.c_str() );
return 3; if ( input.empty() )
}
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; printf( "Failed to read input or empty input: %s\n", path.c_str() );
exitCode = parseAndSaveValueTree( rewrite, rewriteActualPath, return 3;
"rewrite", rewriteRoot, features, parseOnly );
} }
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; return exitCode;

View File

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

View File

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

View File

@ -28,6 +28,13 @@ const Value Value::null;
const Int Value::minInt = Int( ~(UInt(-1)/2) ); const Int Value::minInt = Int( ~(UInt(-1)/2) );
const Int Value::maxInt = Int( UInt(-1)/2 ); const Int Value::maxInt = Int( UInt(-1)/2 );
const UInt Value::maxUInt = UInt(-1); 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 /// Unknown size marker
enum { unknown = (unsigned)-1 }; enum { unknown = (unsigned)-1 };
@ -262,8 +269,8 @@ Value::Value( ValueType type )
} }
#if !defined(JSON_NO_INT64) #if defined(JSON_HAS_INT64)
Value::Value( ArrayIndex value ) Value::Value( UInt value )
: type_( uintValue ) : type_( uintValue )
, comments_( 0 ) , comments_( 0 )
# ifdef JSON_VALUE_USE_INTERNAL_MAP # ifdef JSON_VALUE_USE_INTERNAL_MAP
@ -273,19 +280,6 @@ Value::Value( ArrayIndex value )
value_.uint_ = 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 ) Value::Value( Int value )
: type_( intValue ) : type_( intValue )
, comments_( 0 ) , comments_( 0 )
@ -296,8 +290,21 @@ Value::Value( Int 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 ) : type_( uintValue )
, comments_( 0 ) , comments_( 0 )
# ifdef JSON_VALUE_USE_INTERNAL_MAP # ifdef JSON_VALUE_USE_INTERNAL_MAP
@ -689,6 +696,7 @@ Value::asConstString() const
} }
# endif # endif
Value::Int Value::Int
Value::asInt() const Value::asInt() const
{ {
@ -697,10 +705,11 @@ Value::asInt() const
case nullValue: case nullValue:
return 0; return 0;
case intValue: 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: case uintValue:
JSON_ASSERT_MESSAGE( value_.uint_ < (unsigned)maxInt, "integer out of signed integer range" ); JSON_ASSERT_MESSAGE( value_.uint_ <= UInt(maxInt), "unsigned integer out of signed int range" );
return value_.uint_; return Int(value_.uint_);
case realValue: case realValue:
JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" ); JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" );
return Int( value_.real_ ); return Int( value_.real_ );
@ -716,6 +725,7 @@ Value::asInt() const
return 0; // unreachable; return 0; // unreachable;
} }
Value::UInt Value::UInt
Value::asUInt() const Value::asUInt() const
{ {
@ -725,9 +735,11 @@ Value::asUInt() const
return 0; return 0;
case intValue: case intValue:
JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" ); 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: case uintValue:
return value_.uint_; JSON_ASSERT_MESSAGE( value_.uint_ <= maxUInt, "unsigned integer out of UInt range" );
return UInt(value_.uint_);
case realValue: case realValue:
JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" ); JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" );
return UInt( value_.real_ ); return UInt( value_.real_ );
@ -743,6 +755,88 @@ Value::asUInt() const
return 0; // unreachable; 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 double
Value::asDouble() const Value::asDouble() const
{ {

View File

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