mirror of
https://github.com/open-source-parsers/jsoncpp.git
synced 2025-04-02 17:50:51 +02:00
- 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:
parent
377d21e145
commit
201fb2cf0d
15
NEWS.txt
15
NEWS.txt
@ -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).
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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_;
|
||||
};
|
||||
|
||||
|
@ -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 );
|
||||
|
@ -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 );
|
||||
|
@ -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 *¤t )
|
||||
{
|
||||
*--current = 0;
|
||||
do
|
||||
{
|
||||
*--current = (value % 10) + '0';
|
||||
*--current = char(value % 10) + '0';
|
||||
value /= 10;
|
||||
}
|
||||
while ( value != 0 );
|
||||
|
@ -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++ != ']' )
|
||||
|
@ -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 );
|
||||
|
1
test/data/test_integer_06_64bits.expected
Normal file
1
test/data/test_integer_06_64bits.expected
Normal file
@ -0,0 +1 @@
|
||||
.=9223372036854775808
|
2
test/data/test_integer_06_64bits.json
Normal file
2
test/data/test_integer_06_64bits.json
Normal file
@ -0,0 +1,2 @@
|
||||
9223372036854775808
|
||||
|
1
test/data/test_integer_07_64bits.expected
Normal file
1
test/data/test_integer_07_64bits.expected
Normal file
@ -0,0 +1 @@
|
||||
.=-9223372036854775808
|
2
test/data/test_integer_07_64bits.json
Normal file
2
test/data/test_integer_07_64bits.json
Normal file
@ -0,0 +1,2 @@
|
||||
-9223372036854775808
|
||||
|
1
test/data/test_integer_08_64bits.expected
Normal file
1
test/data/test_integer_08_64bits.expected
Normal file
@ -0,0 +1 @@
|
||||
.=18446744073709551615
|
2
test/data/test_integer_08_64bits.json
Normal file
2
test/data/test_integer_08_64bits.json
Normal file
@ -0,0 +1,2 @@
|
||||
18446744073709551615
|
||||
|
Loading…
x
Reference in New Issue
Block a user