- Moved definition of Json::Int and Json::UInt to config.h which compiler detection logic to define them to 64 bits integer if JSON_NO_INT64 is not defined.

- Added Json::ArrayIndex as an unsigned int to forwards.h
- Modified Json::Value to consistently use Json::ArrayIndex.
- Added int/unsigned int constructor overload to Json::Value to avoid ambiguous constructor call.
- Modified jsontestrunner/main.cpp to use Json::valueToString for Value::asInt() conversion to string.
- Modified Json::Reader to only overflow to double when the number is too large (previous code relied on the fact that an int fitted in a double without precision loss).
- Generalized uintToString() helpers and buffer size to automatically adapt to the precision of Json::UInt.
- Added specific conversion logic for UInt to double conversion on Microsoft Visual Studio 6 which only support __int64 to double conversion (unsigned __int64 conversion is not supported)
- Added test for 64 bits parsing/writing. Notes: those will fail when compiled with JSON_NO_INT64 (more dev required to adapt).
This commit is contained in:
Baptiste Lepilleur 2010-04-19 07:37:41 +00:00
parent 377d21e145
commit 201fb2cf0d
15 changed files with 170 additions and 43 deletions

View File

@ -18,4 +18,17 @@
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).
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).
- The type Json::ArrayIndex is used for indexes of a JSON value array. It
is an unsigned int (typically 32 bits).

View File

@ -40,4 +40,32 @@
# define JSON_API
# endif
// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for integer
// Storages.
// #define JSON_NO_INT64 1
#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6
// Microsoft Visual Studio 6 only support conversion from __int64 to double
// (no conversion from unsigned __int64).
#define JSON_USE_INT64_DOUBLE_CONVERSION 1
#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6
namespace Json {
# if defined(JSON_NO_INT64)
typedef int Int;
typedef unsigned int UInt;
# 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;
# else // if defined(_MSC_VER) // Other platforms, use long long
typedef long long int Int;
typedef unsigned long long int UInt;
# endif // if defined(_MSC_VER)
# endif // if defined(JSON_NO_INT64)
} // end namespace Json
#endif // JSON_CONFIG_H_INCLUDED

View File

@ -16,8 +16,7 @@ namespace Json {
class Features;
// value.h
typedef int Int;
typedef unsigned int UInt;
typedef unsigned int ArrayIndex;
class StaticString;
class Path;
class PathArgument;

View File

@ -121,7 +121,7 @@ namespace Json {
typedef ValueConstIterator const_iterator;
typedef Json::UInt UInt;
typedef Json::Int Int;
typedef UInt ArrayIndex;
typedef Json::ArrayIndex ArrayIndex;
static const Value null;
static const Int minInt;
@ -140,20 +140,20 @@ namespace Json {
duplicate,
duplicateOnCopy
};
CZString( int index );
CZString( ArrayIndex index );
CZString( const char *cstr, DuplicationPolicy allocate );
CZString( const CZString &other );
~CZString();
CZString &operator =( const CZString &other );
bool operator<( const CZString &other ) const;
bool operator==( const CZString &other ) const;
int index() const;
ArrayIndex index() const;
const char *c_str() const;
bool isStaticString() const;
private:
void swap( CZString &other );
const char *cstr_;
int index_;
ArrayIndex index_;
};
public:
@ -182,6 +182,10 @@ 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 );
Value( double value );
@ -248,7 +252,7 @@ namespace Json {
bool isConvertibleTo( ValueType other ) const;
/// Number of values in array or object
UInt size() const;
ArrayIndex size() const;
/// \brief Return true if empty array, empty object, or null;
/// otherwise, false.
@ -267,24 +271,24 @@ namespace Json {
/// May only be called on nullValue or arrayValue.
/// \pre type() is arrayValue or nullValue
/// \post type() is arrayValue
void resize( UInt size );
void resize( ArrayIndex size );
/// Access an array element (zero based index ).
/// If the array contains less than index element, then null value are inserted
/// in the array so that its size is index+1.
/// (You may need to say 'value[0u]' to get your compiler to distinguish
/// this from the operator[] which takes a string.)
Value &operator[]( UInt index );
Value &operator[]( ArrayIndex index );
/// Access an array element (zero based index )
/// (You may need to say 'value[0u]' to get your compiler to distinguish
/// this from the operator[] which takes a string.)
const Value &operator[]( UInt index ) const;
const Value &operator[]( ArrayIndex index ) const;
/// If the array contains at least index+1 elements, returns the element value,
/// otherwise returns defaultValue.
Value get( UInt index,
Value get( ArrayIndex index,
const Value &defaultValue ) const;
/// Return true if index < size().
bool isValidIndex( UInt index ) const;
bool isValidIndex( ArrayIndex index ) const;
/// \brief Append value to array at the end.
///
/// Equivalent to jsonvalue[jsonvalue.size()] = value;
@ -454,7 +458,7 @@ namespace Json {
friend class Path;
PathArgument();
PathArgument( UInt index );
PathArgument( ArrayIndex index );
PathArgument( const char *key );
PathArgument( const std::string &key );
@ -466,7 +470,7 @@ namespace Json {
kindKey
};
std::string key_;
UInt index_;
ArrayIndex index_;
Kind kind_;
};

View File

@ -35,10 +35,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=%d\n", path.c_str(), value.asInt() );
fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asInt() ).c_str() );
break;
case Json::uintValue:
fprintf( fout, "%s=%u\n", path.c_str(), value.asUInt() );
fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asUInt() ).c_str() );
break;
case Json::realValue:
fprintf( fout, "%s=%.16g\n", path.c_str(), value.asDouble() );
@ -148,6 +148,19 @@ removeSuffix( const std::string &path,
return path.substr( 0, path.length() - extension.length() );
}
static void
printConfig()
{
// Print the configuration used to compile JsonCpp
#if defined(JSON_NO_INT64)
printf( "JSON_NO_INT64=1\n" );
#else
printf( "JSON_NO_INT64=0\n" );
#endif
}
static int
printUsage( const char *argv[] )
{
@ -175,6 +188,12 @@ parseCommandLine( int argc, const char *argv[],
++index;
}
if ( std::string(argv[1]) == "--json-config" )
{
printConfig();
return 3;
}
if ( index == argc || index + 1 < argc )
{
return printUsage( argv );

View File

@ -555,21 +555,36 @@ Reader::decodeNumber( Token &token )
}
if ( isDouble )
return decodeDouble( token );
// Attempts to parse the number as an integer. If the number is
// larger than the maximum supported value of an integer then
// we decode the number as a double.
Location current = token.start_;
bool isNegative = *current == '-';
if ( isNegative )
++current;
Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt)
: Value::maxUInt) / 10;
Value::UInt maxIntegerValue = isNegative ? Value::UInt(-Value::minInt)
: Value::maxUInt;
Value::UInt threshold = maxIntegerValue / 10;
Value::UInt lastDigitThreshold = maxIntegerValue % 10;
assert( lastDigitThreshold >=0 && lastDigitThreshold <= 9 );
Value::UInt value = 0;
while ( current < token.end_ )
{
Char c = *current++;
if ( c < '0' || c > '9' )
return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
Value::UInt digit(c - '0');
if ( value >= threshold )
return decodeDouble( token );
value = value * 10 + Value::UInt(c - '0');
{
// If the current digit is not the last one, or if it is
// greater than the last digit of the maximum integer value,
// the parse the number as a double.
if ( current != token.end_ || digit > lastDigitThreshold )
{
return decodeDouble( token );
}
}
value = value * 10 + digit;
}
if ( isNegative )
currentValue() = -Value::Int( value );

View File

@ -56,18 +56,28 @@ isControlCharacter(char ch)
}
enum {
/// Constant that specify the size of the buffer that must be passed to uintToString.
uintToStringBufferSize = 3*sizeof(UInt)+1
};
// Defines a char buffer for use with uintToString().
typedef char UIntToStringBuffer[uintToStringBufferSize];
/** Converts an unsigned integer to string.
* @param value Unsigned interger to convert to string
* @param current Input/Output string buffer. Must have at least 10 chars free.
* @param current Input/Output string buffer.
* Must have at least uintToStringBufferSize chars free.
*/
static inline void
uintToString( unsigned int value,
uintToString( UInt value,
char *&current )
{
*--current = 0;
do
{
*--current = (value % 10) + '0';
*--current = char(value % 10) + '0';
value /= 10;
}
while ( value != 0 );

View File

@ -119,7 +119,7 @@ Value::CommentInfo::setComment( const char *text )
// Notes: index_ indicates if the string was allocated when
// a string is stored.
Value::CZString::CZString( int index )
Value::CZString::CZString( ArrayIndex index )
: cstr_( 0 )
, index_( index )
{
@ -179,7 +179,7 @@ Value::CZString::operator==( const CZString &other ) const
}
int
ArrayIndex
Value::CZString::index() const
{
return index_;
@ -257,6 +257,30 @@ Value::Value( ValueType type )
}
#if !defined(JSON_NO_INT64)
Value::Value( ArrayIndex value )
: type_( uintValue )
, comments_( 0 )
# ifdef JSON_VALUE_USE_INTERNAL_MAP
, itemIsUsed_( 0 )
#endif
{
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 )
@ -310,7 +334,7 @@ Value::Value( const char *beginValue,
#endif
{
value_.string_ = duplicateStringValue( beginValue,
UInt(endValue - beginValue) );
(unsigned int)(endValue - beginValue) );
}
@ -722,9 +746,13 @@ Value::asDouble() const
case nullValue:
return 0.0;
case intValue:
return value_.int_;
return static_cast<double>( value_.int_ );
case uintValue:
return value_.uint_;
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
return static_cast<double>( value_.uint_ );
#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
return static_cast<double>( Int(value_.uint_/2) ) * 2 + Int(value_.uint_ & 1);
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
case realValue:
return value_.real_;
case booleanValue:
@ -817,7 +845,7 @@ Value::isConvertibleTo( ValueType other ) const
/// Number of values in array or object
Value::UInt
ArrayIndex
Value::size() const
{
switch ( type_ )
@ -839,7 +867,7 @@ Value::size() const
}
return 0;
case objectValue:
return Int( value_.map_->size() );
return ArrayIndex( value_.map_->size() );
#else
case arrayValue:
return Int( value_.array_->size() );
@ -896,21 +924,23 @@ Value::clear()
}
void
Value::resize( UInt newSize )
Value::resize( ArrayIndex newSize )
{
JSON_ASSERT( type_ == nullValue || type_ == arrayValue );
if ( type_ == nullValue )
*this = Value( arrayValue );
#ifndef JSON_VALUE_USE_INTERNAL_MAP
UInt oldSize = size();
ArrayIndex oldSize = size();
if ( newSize == 0 )
clear();
else if ( newSize > oldSize )
(*this)[ newSize - 1 ];
else
{
for ( UInt index = newSize; index < oldSize; ++index )
for ( ArrayIndex index = newSize; index < oldSize; ++index )
{
value_.map_->erase( index );
}
assert( size() == newSize );
}
#else
@ -920,7 +950,7 @@ Value::resize( UInt newSize )
Value &
Value::operator[]( UInt index )
Value::operator[]( ArrayIndex index )
{
JSON_ASSERT( type_ == nullValue || type_ == arrayValue );
if ( type_ == nullValue )
@ -941,7 +971,7 @@ Value::operator[]( UInt index )
const Value &
Value::operator[]( UInt index ) const
Value::operator[]( ArrayIndex index ) const
{
JSON_ASSERT( type_ == nullValue || type_ == arrayValue );
if ( type_ == nullValue )
@ -991,7 +1021,7 @@ Value::resolveReference( const char *key,
Value
Value::get( UInt index,
Value::get( ArrayIndex index,
const Value &defaultValue ) const
{
const Value *value = &((*this)[index]);
@ -1000,7 +1030,7 @@ Value::get( UInt index,
bool
Value::isValidIndex( UInt index ) const
Value::isValidIndex( ArrayIndex index ) const
{
return index < size();
}
@ -1463,7 +1493,7 @@ PathArgument::PathArgument()
}
PathArgument::PathArgument( Value::UInt index )
PathArgument::PathArgument( ArrayIndex index )
: index_( index )
, kind_( kindIndex )
{
@ -1519,9 +1549,9 @@ Path::makePath( const std::string &path,
addPathInArg( path, in, itInArg, PathArgument::kindIndex );
else
{
Value::UInt index = 0;
ArrayIndex index = 0;
for ( ; current != end && *current >= '0' && *current <= '9'; ++current )
index = index * 10 + Value::UInt(*current - '0');
index = index * 10 + ArrayIndex(*current - '0');
args_.push_back( index );
}
if ( current == end || *current++ != ']' )

View File

@ -26,7 +26,7 @@ static bool containsControlCharacter( const char* str )
std::string valueToString( Int value )
{
char buffer[32];
UIntToStringBuffer buffer;
char *current = buffer + sizeof(buffer);
bool isNegative = value < 0;
if ( isNegative )
@ -41,7 +41,7 @@ std::string valueToString( Int value )
std::string valueToString( UInt value )
{
char buffer[32];
UIntToStringBuffer buffer;
char *current = buffer + sizeof(buffer);
uintToString( value, current );
assert( current >= buffer );

View File

@ -0,0 +1 @@
.=9223372036854775808

View File

@ -0,0 +1,2 @@
9223372036854775808

View File

@ -0,0 +1 @@
.=-9223372036854775808

View File

@ -0,0 +1,2 @@
-9223372036854775808

View File

@ -0,0 +1 @@
.=18446744073709551615

View File

@ -0,0 +1,2 @@
18446744073709551615