Skip to content

Commit 201fb2c

Browse files
committed
- 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).
1 parent 377d21e commit 201fb2c

15 files changed

+170
-43
lines changed

NEWS.txt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,17 @@
1818
initialization/destruction order issues (bug #2934500).
1919
The DefaultValueAllocator has been inlined in code.
2020

21-
21+
- Added support for 64 bits integer. Json::Int and Json::UInt are
22+
now 64 bits integers on system that support them (more precisely
23+
they are of the size of long long, so if it is 128 bits it will
24+
also work).
25+
26+
Warning: Json::Value::asInt() and Json::Value::asUInt() now returns
27+
long long. This changes break code that was passing the return value
28+
to *printf() function.
29+
30+
Notes: you can switch back to the 32 bits only behavior by defining the
31+
macro JSON_NO_INT64 (se include/json/config.h).
32+
33+
- The type Json::ArrayIndex is used for indexes of a JSON value array. It
34+
is an unsigned int (typically 32 bits).

include/json/config.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,32 @@
4040
# define JSON_API
4141
# endif
4242

43+
// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for integer
44+
// Storages.
45+
// #define JSON_NO_INT64 1
46+
47+
#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6
48+
// Microsoft Visual Studio 6 only support conversion from __int64 to double
49+
// (no conversion from unsigned __int64).
50+
#define JSON_USE_INT64_DOUBLE_CONVERSION 1
51+
#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6
52+
53+
54+
namespace Json {
55+
# if defined(JSON_NO_INT64)
56+
typedef int Int;
57+
typedef unsigned int UInt;
58+
# else // if defined(JSON_NO_INT64)
59+
// For Microsoft Visual use specific types as long long is not supported
60+
# if defined(_MSC_VER) // Microsoft Visual Studio
61+
typedef __int64 Int;
62+
typedef unsigned __int64 UInt;
63+
# else // if defined(_MSC_VER) // Other platforms, use long long
64+
typedef long long int Int;
65+
typedef unsigned long long int UInt;
66+
# endif // if defined(_MSC_VER)
67+
# endif // if defined(JSON_NO_INT64)
68+
} // end namespace Json
69+
70+
4371
#endif // JSON_CONFIG_H_INCLUDED

include/json/forwards.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ namespace Json {
1616
class Features;
1717

1818
// value.h
19-
typedef int Int;
20-
typedef unsigned int UInt;
19+
typedef unsigned int ArrayIndex;
2120
class StaticString;
2221
class Path;
2322
class PathArgument;

include/json/value.h

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ namespace Json {
121121
typedef ValueConstIterator const_iterator;
122122
typedef Json::UInt UInt;
123123
typedef Json::Int Int;
124-
typedef UInt ArrayIndex;
124+
typedef Json::ArrayIndex ArrayIndex;
125125

126126
static const Value null;
127127
static const Int minInt;
@@ -140,20 +140,20 @@ namespace Json {
140140
duplicate,
141141
duplicateOnCopy
142142
};
143-
CZString( int index );
143+
CZString( ArrayIndex index );
144144
CZString( const char *cstr, DuplicationPolicy allocate );
145145
CZString( const CZString &other );
146146
~CZString();
147147
CZString &operator =( const CZString &other );
148148
bool operator<( const CZString &other ) const;
149149
bool operator==( const CZString &other ) const;
150-
int index() const;
150+
ArrayIndex index() const;
151151
const char *c_str() const;
152152
bool isStaticString() const;
153153
private:
154154
void swap( CZString &other );
155155
const char *cstr_;
156-
int index_;
156+
ArrayIndex index_;
157157
};
158158

159159
public:
@@ -182,6 +182,10 @@ namespace Json {
182182
\endcode
183183
*/
184184
Value( ValueType type = nullValue );
185+
#if !defined(JSON_NO_INT64)
186+
Value( int value );
187+
Value( ArrayIndex value );
188+
#endif // if !defined(JSON_NO_INT64)
185189
Value( Int value );
186190
Value( UInt value );
187191
Value( double value );
@@ -248,7 +252,7 @@ namespace Json {
248252
bool isConvertibleTo( ValueType other ) const;
249253

250254
/// Number of values in array or object
251-
UInt size() const;
255+
ArrayIndex size() const;
252256

253257
/// \brief Return true if empty array, empty object, or null;
254258
/// otherwise, false.
@@ -267,24 +271,24 @@ namespace Json {
267271
/// May only be called on nullValue or arrayValue.
268272
/// \pre type() is arrayValue or nullValue
269273
/// \post type() is arrayValue
270-
void resize( UInt size );
274+
void resize( ArrayIndex size );
271275

272276
/// Access an array element (zero based index ).
273277
/// If the array contains less than index element, then null value are inserted
274278
/// in the array so that its size is index+1.
275279
/// (You may need to say 'value[0u]' to get your compiler to distinguish
276280
/// this from the operator[] which takes a string.)
277-
Value &operator[]( UInt index );
281+
Value &operator[]( ArrayIndex index );
278282
/// Access an array element (zero based index )
279283
/// (You may need to say 'value[0u]' to get your compiler to distinguish
280284
/// this from the operator[] which takes a string.)
281-
const Value &operator[]( UInt index ) const;
285+
const Value &operator[]( ArrayIndex index ) const;
282286
/// If the array contains at least index+1 elements, returns the element value,
283287
/// otherwise returns defaultValue.
284-
Value get( UInt index,
288+
Value get( ArrayIndex index,
285289
const Value &defaultValue ) const;
286290
/// Return true if index < size().
287-
bool isValidIndex( UInt index ) const;
291+
bool isValidIndex( ArrayIndex index ) const;
288292
/// \brief Append value to array at the end.
289293
///
290294
/// Equivalent to jsonvalue[jsonvalue.size()] = value;
@@ -454,7 +458,7 @@ namespace Json {
454458
friend class Path;
455459

456460
PathArgument();
457-
PathArgument( UInt index );
461+
PathArgument( ArrayIndex index );
458462
PathArgument( const char *key );
459463
PathArgument( const std::string &key );
460464

@@ -466,7 +470,7 @@ namespace Json {
466470
kindKey
467471
};
468472
std::string key_;
469-
UInt index_;
473+
ArrayIndex index_;
470474
Kind kind_;
471475
};
472476

src/jsontestrunner/main.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ printValueTree( FILE *fout, Json::Value &value, const std::string &path = "." )
3535
fprintf( fout, "%s=null\n", path.c_str() );
3636
break;
3737
case Json::intValue:
38-
fprintf( fout, "%s=%d\n", path.c_str(), value.asInt() );
38+
fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asInt() ).c_str() );
3939
break;
4040
case Json::uintValue:
41-
fprintf( fout, "%s=%u\n", path.c_str(), value.asUInt() );
41+
fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asUInt() ).c_str() );
4242
break;
4343
case Json::realValue:
4444
fprintf( fout, "%s=%.16g\n", path.c_str(), value.asDouble() );
@@ -148,6 +148,19 @@ removeSuffix( const std::string &path,
148148
return path.substr( 0, path.length() - extension.length() );
149149
}
150150

151+
152+
static void
153+
printConfig()
154+
{
155+
// Print the configuration used to compile JsonCpp
156+
#if defined(JSON_NO_INT64)
157+
printf( "JSON_NO_INT64=1\n" );
158+
#else
159+
printf( "JSON_NO_INT64=0\n" );
160+
#endif
161+
}
162+
163+
151164
static int
152165
printUsage( const char *argv[] )
153166
{
@@ -175,6 +188,12 @@ parseCommandLine( int argc, const char *argv[],
175188
++index;
176189
}
177190

191+
if ( std::string(argv[1]) == "--json-config" )
192+
{
193+
printConfig();
194+
return 3;
195+
}
196+
178197
if ( index == argc || index + 1 < argc )
179198
{
180199
return printUsage( argv );

src/lib_json/json_reader.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -555,21 +555,36 @@ Reader::decodeNumber( Token &token )
555555
}
556556
if ( isDouble )
557557
return decodeDouble( token );
558+
// Attempts to parse the number as an integer. If the number is
559+
// larger than the maximum supported value of an integer then
560+
// we decode the number as a double.
558561
Location current = token.start_;
559562
bool isNegative = *current == '-';
560563
if ( isNegative )
561564
++current;
562-
Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt)
563-
: Value::maxUInt) / 10;
565+
Value::UInt maxIntegerValue = isNegative ? Value::UInt(-Value::minInt)
566+
: Value::maxUInt;
567+
Value::UInt threshold = maxIntegerValue / 10;
568+
Value::UInt lastDigitThreshold = maxIntegerValue % 10;
569+
assert( lastDigitThreshold >=0 && lastDigitThreshold <= 9 );
564570
Value::UInt value = 0;
565571
while ( current < token.end_ )
566572
{
567573
Char c = *current++;
568574
if ( c < '0' || c > '9' )
569575
return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
576+
Value::UInt digit(c - '0');
570577
if ( value >= threshold )
571-
return decodeDouble( token );
572-
value = value * 10 + Value::UInt(c - '0');
578+
{
579+
// If the current digit is not the last one, or if it is
580+
// greater than the last digit of the maximum integer value,
581+
// the parse the number as a double.
582+
if ( current != token.end_ || digit > lastDigitThreshold )
583+
{
584+
return decodeDouble( token );
585+
}
586+
}
587+
value = value * 10 + digit;
573588
}
574589
if ( isNegative )
575590
currentValue() = -Value::Int( value );

src/lib_json/json_tool.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,18 +56,28 @@ isControlCharacter(char ch)
5656
}
5757

5858

59+
enum {
60+
/// Constant that specify the size of the buffer that must be passed to uintToString.
61+
uintToStringBufferSize = 3*sizeof(UInt)+1
62+
};
63+
64+
// Defines a char buffer for use with uintToString().
65+
typedef char UIntToStringBuffer[uintToStringBufferSize];
66+
67+
5968
/** Converts an unsigned integer to string.
6069
* @param value Unsigned interger to convert to string
61-
* @param current Input/Output string buffer. Must have at least 10 chars free.
70+
* @param current Input/Output string buffer.
71+
* Must have at least uintToStringBufferSize chars free.
6272
*/
6373
static inline void
64-
uintToString( unsigned int value,
74+
uintToString( UInt value,
6575
char *&current )
6676
{
6777
*--current = 0;
6878
do
6979
{
70-
*--current = (value % 10) + '0';
80+
*--current = char(value % 10) + '0';
7181
value /= 10;
7282
}
7383
while ( value != 0 );

0 commit comments

Comments
 (0)