Skip to content
This repository was archived by the owner on Jul 19, 2022. It is now read-only.

Differentiate Integer type from Double type (which was originally named Number) to make it possible to correctly store a 64bit integer on 32bit systems. #41

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 51 additions & 15 deletions jsonxx.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ bool parse_array(std::istream& input, Array& array);
bool parse_bool(std::istream& input, Boolean& value);
bool parse_comment(std::istream &input);
bool parse_null(std::istream& input);
bool parse_number(std::istream& input, Number& value);
bool parse_integer(std::istream& input, Integer& value);
bool parse_double(std::istream& input, Double& value);
bool parse_object(std::istream& input, Object& object);
bool parse_string(std::istream& input, String& value);
bool parse_identifier(std::istream& input, String& value);
Expand Down Expand Up @@ -181,7 +182,21 @@ bool parse_identifier(std::istream& input, String& value) {
}
}

bool parse_number(std::istream& input, Number& value) {
bool parse_integer(std::istream& input, Integer& value) {
input >> std::ws;
std::streampos rollback = input.tellg();
input >> value;
// if the next character is a dot, we consider that the number is a
// floating point number
if (input.fail() || input.peek() == '.') {
input.clear();
input.seekg(rollback);
return false;
}
return true;
}

bool parse_double(std::istream& input, Double& value) {
input >> std::ws;
std::streampos rollback = input.tellg();
input >> value;
Expand Down Expand Up @@ -345,8 +360,14 @@ bool Value::parse(std::istream& input, Value& value) {
value.type_ = STRING_;
return true;
}
if (parse_number(input, value.number_value_)) {
value.type_ = NUMBER_;

if (parse_integer(input, value.integer_value_)) {
value.type_ = INTEGER_;
return true;
}

if (parse_double(input, value.double_value_)) {
value.type_ = DOUBLE_;
return true;
}

Expand Down Expand Up @@ -454,8 +475,10 @@ static std::ostream& stream_string(std::ostream& stream,

std::ostream& operator<<(std::ostream& stream, const jsonxx::Value& v) {
using namespace jsonxx;
if (v.is<Number>()) {
return stream << v.get<Number>();
if (v.is<Integer>()) {
return stream << v.get<Integer>();
} else if (v.is<Double>()) {
return stream << v.get<Double>();
} else if (v.is<String>()) {
return stream_string(stream, v.get<std::string>());
} else if (v.is<Boolean>()) {
Expand Down Expand Up @@ -597,10 +620,14 @@ namespace json {
ss << tag( format, depth+1, it->first, *it->second );
return remove_last_comma( ss.str() ) + tab + "}" ",\n";

case jsonxx::Value::NUMBER_:
case jsonxx::Value::INTEGER_:
ss << t.integer_value_;
return ss.str() + ",\n";

case jsonxx::Value::DOUBLE_:
// max precision
ss << std::setprecision(std::numeric_limits<long double>::digits10 + 1);
ss << t.number_value_;
ss << std::setprecision(std::numeric_limits<Double>::digits10 + 1);
ss << t.double_value_;
return ss.str() + ",\n";
}
}
Expand Down Expand Up @@ -689,7 +716,8 @@ std::string open_tag( unsigned format, char type, const std::string &name, const
case 'a': tagname = "json:array" + tagname; break;
case 's': tagname = "json:string" + tagname; break;
case 'o': tagname = "json:object" + tagname; break;
case 'n': tagname = "json:number" + tagname; break;
case 'i': tagname = "json:integer" + tagname; break;
case 'd': tagname = "json:double" + tagname; break;
}
break;

Expand All @@ -705,7 +733,8 @@ std::string open_tag( unsigned format, char type, const std::string &name, const
case 'a': tagname += " type=\"json:array\""; break;
case 's': tagname += " type=\"json:string\""; break;
case 'o': tagname += " type=\"json:object\""; break;
case 'n': tagname += " type=\"json:number\""; break;
case 'i': tagname += " type=\"json:integer\""; break;
case 'd': tagname += " type=\"json:double\""; break;
}

if( !name.empty() )
Expand Down Expand Up @@ -735,7 +764,8 @@ std::string close_tag( unsigned format, char type, const std::string &name ) {
case 'a': return "</json:array>";
case 'o': return "</json:object>";
case 's': return "</json:string>";
case 'n': return "</json:number>";
case 'i': return "</json:integer>";
case 'd': return "</json:double>";
}
break;

Expand Down Expand Up @@ -785,10 +815,16 @@ std::string tag( unsigned format, unsigned depth, const std::string &name, const
+ ss.str()
+ tab + close_tag( format, 'o', name ) + '\n';

case jsonxx::Value::NUMBER_:
case jsonxx::Value::INTEGER_:
ss << t.integer_value_;
return tab + open_tag( format, 'n', name, std::string(), format == jsonxx::JXMLex ? ss.str() : std::string() )
+ ss.str()
+ close_tag( format, 'n', name ) + '\n';

case jsonxx::Value::DOUBLE_:
// max precision
ss << std::setprecision(std::numeric_limits<long double>::digits10 + 1);
ss << t.number_value_;
ss << std::setprecision(std::numeric_limits<Double>::digits10 + 1);
ss << t.double_value_;
return tab + open_tag( format, 'n', name, std::string(), format == jsonxx::JXMLex ? ss.str() : std::string() )
+ ss.str()
+ close_tag( format, 'n', name ) + '\n';
Expand Down
91 changes: 62 additions & 29 deletions jsonxx.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ enum Format {
};

// Types
typedef long double Number;
typedef long long Integer;
typedef long double Double;
typedef bool Boolean;
typedef std::string String;
struct Null {};
Expand Down Expand Up @@ -179,7 +180,7 @@ class Array {
container values_;
};

// A value could be a number, an array, a string, an object, a
// A value could be an integer, a double, an array, a string, an object, a
// boolean, or null
class Value {
public:
Expand All @@ -200,24 +201,34 @@ class Value {
type_ = BOOL_;
bool_value_ = b;
}
#define $number(TYPE) \

#define $integer(TYPE) \
void import( const TYPE &n ) { \
reset(); \
type_ = INTEGER_; \
integer_value_ = static_cast<Integer>(n); \
}
$integer( char )
$integer( int )
$integer( long )
$integer( long long )
$integer( unsigned char )
$integer( unsigned int )
$integer( unsigned long )
$integer( unsigned long long )
#undef $integer

#define $double(TYPE) \
void import( const TYPE &n ) { \
reset(); \
type_ = NUMBER_; \
number_value_ = static_cast<long double>(n); \
type_ = DOUBLE_; \
double_value_ = static_cast<Double>(n); \
}
$number( char )
$number( int )
$number( long )
$number( long long )
$number( unsigned char )
$number( unsigned int )
$number( unsigned long )
$number( unsigned long long )
$number( float )
$number( double )
$number( long double )
#undef $number
$double( float )
$double( double )
$double( long double )
#undef $double

#if JSONXX_COMPILER_HAS_CXX11 > 0
void import( const std::nullptr_t & ) {
reset();
Expand Down Expand Up @@ -252,8 +263,11 @@ class Value {
case BOOL_:
import( other.bool_value_ );
break;
case NUMBER_:
import( other.number_value_ );
case INTEGER_:
import( other.integer_value_ );
break;
case DOUBLE_:
import( other.double_value_ );
break;
case STRING_:
import( *other.string_value_ );
Expand Down Expand Up @@ -302,7 +316,8 @@ class Value {

public:
enum {
NUMBER_,
INTEGER_,
DOUBLE_,
STRING_,
BOOL_,
NULL_,
Expand All @@ -311,7 +326,8 @@ class Value {
INVALID_
} type_;
union {
Number number_value_;
Integer integer_value_;
Double double_value_;
String* string_value_;
Boolean bool_value_;
Array* array_value_;
Expand Down Expand Up @@ -404,8 +420,13 @@ inline bool Value::is<String>() const {
}

template<>
inline bool Value::is<Number>() const {
return type_ == NUMBER_;
inline bool Value::is<Integer>() const {
return type_ == INTEGER_;
}

template<>
inline bool Value::is<Double>() const {
return type_ == DOUBLE_;
}

template<>
Expand Down Expand Up @@ -441,9 +462,15 @@ inline std::string& Value::get<String>() {
}

template<>
inline Number& Value::get<Number>() {
JSONXX_ASSERT(is<Number>());
return number_value_;
inline Integer& Value::get<Integer>() {
JSONXX_ASSERT(is<Integer>());
return integer_value_;
}

template<>
inline Double& Value::get<Double>() {
JSONXX_ASSERT(is<Double>());
return double_value_;
}

template<>
Expand Down Expand Up @@ -471,9 +498,15 @@ inline const String& Value::get<String>() const {
}

template<>
inline const Number& Value::get<Number>() const {
JSONXX_ASSERT(is<Number>());
return number_value_;
inline const Integer& Value::get<Integer>() const {
JSONXX_ASSERT(is<Integer>());
return integer_value_;
}

template<>
inline const Double& Value::get<Double>() const {
JSONXX_ASSERT(is<Double>());
return double_value_;
}

template<>
Expand Down