- 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

@@ -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 );