From 5ae7ae537540c82a59943eb20da20d55bd20ba12 Mon Sep 17 00:00:00 2001 From: neevek Date: Sat, 8 Nov 2014 16:12:51 +0800 Subject: [PATCH] Differentiate Integer type from Double type (which was originally named Number), make it possible to correctly store a 64bit integer on 32bit systems. Note: this commit will stop programs that use the original **jsonxx** lib from compiling. it is required to change the enum *Number* to either *Integer* or *Double* accordingly. --- jsonxx.cc | 66 +++++++++++++++++++++++++++++++--------- jsonxx.h | 91 +++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 113 insertions(+), 44 deletions(-) diff --git a/jsonxx.cc b/jsonxx.cc index 577c999..9f67cb6 100644 --- a/jsonxx.cc +++ b/jsonxx.cc @@ -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); @@ -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; @@ -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; } @@ -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()) { - return stream << v.get(); + if (v.is()) { + return stream << v.get(); + } else if (v.is()) { + return stream << v.get(); } else if (v.is()) { return stream_string(stream, v.get()); } else if (v.is()) { @@ -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::digits10 + 1); - ss << t.number_value_; + ss << std::setprecision(std::numeric_limits::digits10 + 1); + ss << t.double_value_; return ss.str() + ",\n"; } } @@ -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; @@ -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() ) @@ -735,7 +764,8 @@ std::string close_tag( unsigned format, char type, const std::string &name ) { case 'a': return ""; case 'o': return ""; case 's': return ""; - case 'n': return ""; + case 'i': return ""; + case 'd': return ""; } break; @@ -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::digits10 + 1); - ss << t.number_value_; + ss << std::setprecision(std::numeric_limits::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'; diff --git a/jsonxx.h b/jsonxx.h index e336bba..527ab2d 100644 --- a/jsonxx.h +++ b/jsonxx.h @@ -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 {}; @@ -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: @@ -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(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(n); \ + type_ = DOUBLE_; \ + double_value_ = static_cast(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(); @@ -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_ ); @@ -302,7 +316,8 @@ class Value { public: enum { - NUMBER_, + INTEGER_, + DOUBLE_, STRING_, BOOL_, NULL_, @@ -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_; @@ -404,8 +420,13 @@ inline bool Value::is() const { } template<> -inline bool Value::is() const { - return type_ == NUMBER_; +inline bool Value::is() const { + return type_ == INTEGER_; +} + +template<> +inline bool Value::is() const { + return type_ == DOUBLE_; } template<> @@ -441,9 +462,15 @@ inline std::string& Value::get() { } template<> -inline Number& Value::get() { - JSONXX_ASSERT(is()); - return number_value_; +inline Integer& Value::get() { + JSONXX_ASSERT(is()); + return integer_value_; +} + +template<> +inline Double& Value::get() { + JSONXX_ASSERT(is()); + return double_value_; } template<> @@ -471,9 +498,15 @@ inline const String& Value::get() const { } template<> -inline const Number& Value::get() const { - JSONXX_ASSERT(is()); - return number_value_; +inline const Integer& Value::get() const { + JSONXX_ASSERT(is()); + return integer_value_; +} + +template<> +inline const Double& Value::get() const { + JSONXX_ASSERT(is()); + return double_value_; } template<>