+ set number type to int64_t

+ replaced several functions by template magic
This commit is contained in:
Niels 2015-01-20 20:43:54 +01:00
parent a144800774
commit 54fc97d434
5 changed files with 119 additions and 258 deletions

View file

@ -18,7 +18,7 @@ There are myriads of [JSON](http://json.org) libraries out there, and each may e
Other aspects were not so important to us:
- **Memory efficiency**. Each JSON object has an overhead of one pointer (the maximal size of a union) and one enumeration element (1 byte). We use the following C++ data types: `std::string` for strings, `int` or `double` for numbers, `std::map` for objects, `std::vector` for arrays, and `bool` for Booleans. We know that there are more efficient ways to store the values, but we are happy enough right now.
- **Memory efficiency**. Each JSON object has an overhead of one pointer (the maximal size of a union) and one enumeration element (1 byte). We use the following C++ data types: `std::string` for strings, `int64_t` or `double` for numbers, `std::map` for objects, `std::vector` for arrays, and `bool` for Booleans. We know that there are more efficient ways to store the values, but we are happy enough right now.
- **Speed**. We currently implement the parser as naive [recursive descent parser](http://en.wikipedia.org/wiki/Recursive_descent_parser) with hand coded string handling. It is fast enough, but a [LALR-parser](http://en.wikipedia.org/wiki/LALR_parser) with a decent regular expression processor should be even faster (but would consist of more files which makes the integration harder).

View file

@ -74,7 +74,7 @@ class json
/// a type for a Boolean
using boolean_t = bool;
/// a type for an integer number
using number_t = int;
using number_t = int64_t;
/// a type for a floating point number
using number_float_t = double;
/// a type for list initialization
@ -127,10 +127,6 @@ class json
json(const char*);
/// create a Boolean object
json(const bool) noexcept;
/// create a number object
json(const int) noexcept;
/// create a number object
json(const double) noexcept;
/// create an array
json(const array_t&);
/// create an array (move)
@ -142,6 +138,18 @@ class json
/// create from an initializer list (to an array or object)
json(list_init_t);
/// create a number object (integer)
template<typename T, typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type = 0>
json(const T n) noexcept
: type_(value_type::number), value_(static_cast<number_t>(n))
{}
/// create a number object (float)
template<typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
json(const T n) noexcept
: type_(value_type::number_float), value_(static_cast<number_float_t>(n))
{}
/// copy constructor
json(const json&);
/// move constructor
@ -168,6 +176,7 @@ class json
void replaceChar(std::string& str, char c, const std::string& replacement) const;
/// escapes special characters to safely dump the string
std::string escapeString(const std::string&) const;
public:
/// explicit value conversion
template<typename T>
@ -177,7 +186,8 @@ class json
operator std::string() const;
/// implicit conversion to integer (only for numbers)
operator int() const;
operator long() const;
/// implicit conversion to integer (only for numbers)
operator int64_t() const;
/// implicit conversion to double (only for numbers)
operator double() const;
/// implicit conversion to Boolean (only for Booleans)
@ -216,42 +226,33 @@ class json
/// explicit serialization
std::string dump(int = -1) const noexcept;
/// add constructible objects to an array
template<class T, typename std::enable_if<std::is_constructible<json, T>::value>::type = 0>
json & operator+=(const T& o)
{
push_back(json(o));
return *this;
}
/// add an object/array to an array
json& operator+=(const json&);
/// add a string to an array
json& operator+=(const std::string&);
/// add a null object to an array
json& operator+=(const std::nullptr_t);
/// add a string to an array
json& operator+=(const char*);
/// add a Boolean to an array
json& operator+=(bool);
/// add a number to an array
json& operator+=(int);
/// add a number to an array
json& operator+=(double);
/// add a pair to an object
json& operator+=(const object_t::value_type&);
/// add a list of elements to array or list of pairs to object
json& operator+=(list_init_t);
/// add constructible objects to an array
template<class T, typename std::enable_if<std::is_constructible<json, T>::value>::type = 0>
void push_back(const T& o)
{
push_back(json(o));
}
/// add an object/array to an array
void push_back(const json&);
/// add an object/array to an array (move)
void push_back(json&&);
/// add a string to an array
void push_back(const std::string&);
/// add a null object to an array
void push_back(const std::nullptr_t);
/// add a string to an array
void push_back(const char*);
/// add a Boolean to an array
void push_back(bool);
/// add a number to an array
void push_back(int);
/// add a number to an array
void push_back(double);
/// add a pair to an object
void push_back(const object_t::value_type&);
@ -579,14 +580,6 @@ json::json(const bool b) noexcept
: type_(value_type::boolean), value_(b)
{}
json::json(const int i) noexcept
: type_(value_type::number), value_(i)
{}
json::json(const double f) noexcept
: type_(value_type::number_float), value_(f)
{}
json::json(const array_t& a)
: type_(value_type::array), value_(new array_t(a))
{}
@ -826,6 +819,24 @@ std::string json::get() const
*/
template<>
int json::get() const
{
switch (type_)
{
case (value_type::number):
return value_.number;
case (value_type::number_float):
return static_cast<int>(value_.number_float);
default:
throw std::logic_error("cannot cast " + type_name() + " to JSON number");
}
}
/*!
@exception std::logic_error if the function is called for JSON objects whose
type is not number (int or float)
*/
template<>
int64_t json::get() const
{
switch (type_)
{
@ -920,6 +931,11 @@ json::operator int() const
return get<int>();
}
json::operator int64_t() const
{
return get<int64_t>();
}
json::operator double() const
{
return get<double>();
@ -1136,54 +1152,6 @@ json& json::operator+=(const json& o)
return *this;
}
json& json::operator+=(const std::string& s)
{
push_back(json(s));
return *this;
}
json& json::operator+=(const char* s)
{
push_back(json(s));
return *this;
}
json& json::operator+=(std::nullptr_t)
{
push_back(json());
return *this;
}
json& json::operator+=(bool b)
{
push_back(json(b));
return *this;
}
/*!
Adds a number (int) to the current object. This is done by wrapping the number
into a JSON and call push_back for this.
@param i A number (int) to add to the array.
*/
json& json::operator+=(int i)
{
push_back(json(i));
return *this;
}
/*!
Adds a number (float) to the current object. This is done by wrapping the
number into a JSON and call push_back for this.
@param f A number (float) to add to the array.
*/
json& json::operator+=(double f)
{
push_back(json(f));
return *this;
}
/*!
@todo comment me
*/
@ -1271,48 +1239,6 @@ void json::push_back(json&& o)
o.type_ = value_type::null;
}
void json::push_back(const std::string& s)
{
push_back(json(s));
}
void json::push_back(const char* s)
{
push_back(json(s));
}
void json::push_back(std::nullptr_t)
{
push_back(json());
}
void json::push_back(bool b)
{
push_back(json(b));
}
/*!
Adds a number (int) to the current object. This is done by wrapping the number
into a JSON and call push_back for this.
@param i A number (int) to add to the array.
*/
void json::push_back(int i)
{
push_back(json(i));
}
/*!
Adds a number (float) to the current object. This is done by wrapping the
number into a JSON and call push_back for this.
@param f A number (float) to add to the array.
*/
void json::push_back(double f)
{
push_back(json(f));
}
/*!
@todo comment me
*/
@ -2540,7 +2466,7 @@ json json::parser::parse()
try
{
const auto float_val = std::stod(buffer_.substr(_firstpos_, pos_ - _firstpos_));
const auto int_val = static_cast<int>(float_val);
const auto int_val = static_cast<number_t>(float_val);
// check if conversion loses precision
if (float_val == int_val)

View file

@ -111,14 +111,6 @@ json::json(const bool b) noexcept
: type_(value_type::boolean), value_(b)
{}
json::json(const int i) noexcept
: type_(value_type::number), value_(i)
{}
json::json(const double f) noexcept
: type_(value_type::number_float), value_(f)
{}
json::json(const array_t& a)
: type_(value_type::array), value_(new array_t(a))
{}
@ -358,6 +350,24 @@ std::string json::get() const
*/
template<>
int json::get() const
{
switch (type_)
{
case (value_type::number):
return value_.number;
case (value_type::number_float):
return static_cast<int>(value_.number_float);
default:
throw std::logic_error("cannot cast " + type_name() + " to JSON number");
}
}
/*!
@exception std::logic_error if the function is called for JSON objects whose
type is not number (int or float)
*/
template<>
int64_t json::get() const
{
switch (type_)
{
@ -452,6 +462,11 @@ json::operator int() const
return get<int>();
}
json::operator int64_t() const
{
return get<int64_t>();
}
json::operator double() const
{
return get<double>();
@ -668,54 +683,6 @@ json& json::operator+=(const json& o)
return *this;
}
json& json::operator+=(const std::string& s)
{
push_back(json(s));
return *this;
}
json& json::operator+=(const char* s)
{
push_back(json(s));
return *this;
}
json& json::operator+=(std::nullptr_t)
{
push_back(json());
return *this;
}
json& json::operator+=(bool b)
{
push_back(json(b));
return *this;
}
/*!
Adds a number (int) to the current object. This is done by wrapping the number
into a JSON and call push_back for this.
@param i A number (int) to add to the array.
*/
json& json::operator+=(int i)
{
push_back(json(i));
return *this;
}
/*!
Adds a number (float) to the current object. This is done by wrapping the
number into a JSON and call push_back for this.
@param f A number (float) to add to the array.
*/
json& json::operator+=(double f)
{
push_back(json(f));
return *this;
}
/*!
@todo comment me
*/
@ -803,48 +770,6 @@ void json::push_back(json&& o)
o.type_ = value_type::null;
}
void json::push_back(const std::string& s)
{
push_back(json(s));
}
void json::push_back(const char* s)
{
push_back(json(s));
}
void json::push_back(std::nullptr_t)
{
push_back(json());
}
void json::push_back(bool b)
{
push_back(json(b));
}
/*!
Adds a number (int) to the current object. This is done by wrapping the number
into a JSON and call push_back for this.
@param i A number (int) to add to the array.
*/
void json::push_back(int i)
{
push_back(json(i));
}
/*!
Adds a number (float) to the current object. This is done by wrapping the
number into a JSON and call push_back for this.
@param f A number (float) to add to the array.
*/
void json::push_back(double f)
{
push_back(json(f));
}
/*!
@todo comment me
*/
@ -2072,7 +1997,7 @@ json json::parser::parse()
try
{
const auto float_val = std::stod(buffer_.substr(_firstpos_, pos_ - _firstpos_));
const auto int_val = static_cast<int>(float_val);
const auto int_val = static_cast<number_t>(float_val);
// check if conversion loses precision
if (float_val == int_val)

View file

@ -74,7 +74,7 @@ class json
/// a type for a Boolean
using boolean_t = bool;
/// a type for an integer number
using number_t = int;
using number_t = int64_t;
/// a type for a floating point number
using number_float_t = double;
/// a type for list initialization
@ -127,10 +127,6 @@ class json
json(const char*);
/// create a Boolean object
json(const bool) noexcept;
/// create a number object
json(const int) noexcept;
/// create a number object
json(const double) noexcept;
/// create an array
json(const array_t&);
/// create an array (move)
@ -142,6 +138,18 @@ class json
/// create from an initializer list (to an array or object)
json(list_init_t);
/// create a number object (integer)
template<typename T, typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type = 0>
json(const T n) noexcept
: type_(value_type::number), value_(static_cast<number_t>(n))
{}
/// create a number object (float)
template<typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
json(const T n) noexcept
: type_(value_type::number_float), value_(static_cast<number_float_t>(n))
{}
/// copy constructor
json(const json&);
/// move constructor
@ -168,6 +176,7 @@ class json
void replaceChar(std::string& str, char c, const std::string& replacement) const;
/// escapes special characters to safely dump the string
std::string escapeString(const std::string&) const;
public:
/// explicit value conversion
template<typename T>
@ -177,6 +186,8 @@ class json
operator std::string() const;
/// implicit conversion to integer (only for numbers)
operator int() const;
/// implicit conversion to integer (only for numbers)
operator int64_t() const;
/// implicit conversion to double (only for numbers)
operator double() const;
/// implicit conversion to Boolean (only for Booleans)
@ -215,42 +226,33 @@ class json
/// explicit serialization
std::string dump(int = -1) const noexcept;
/// add constructible objects to an array
template<class T, typename std::enable_if<std::is_constructible<json, T>::value>::type = 0>
json & operator+=(const T& o)
{
push_back(json(o));
return *this;
}
/// add an object/array to an array
json& operator+=(const json&);
/// add a string to an array
json& operator+=(const std::string&);
/// add a null object to an array
json& operator+=(const std::nullptr_t);
/// add a string to an array
json& operator+=(const char*);
/// add a Boolean to an array
json& operator+=(bool);
/// add a number to an array
json& operator+=(int);
/// add a number to an array
json& operator+=(double);
/// add a pair to an object
json& operator+=(const object_t::value_type&);
/// add a list of elements to array or list of pairs to object
json& operator+=(list_init_t);
/// add constructible objects to an array
template<class T, typename std::enable_if<std::is_constructible<json, T>::value>::type = 0>
void push_back(const T& o)
{
push_back(json(o));
}
/// add an object/array to an array
void push_back(const json&);
/// add an object/array to an array (move)
void push_back(json&&);
/// add a string to an array
void push_back(const std::string&);
/// add a null object to an array
void push_back(const std::nullptr_t);
/// add a string to an array
void push_back(const char*);
/// add a Boolean to an array
void push_back(bool);
/// add a number to an array
void push_back(int);
/// add a number to an array
void push_back(double);
/// add a pair to an object
void push_back(const object_t::value_type&);

View file

@ -1094,6 +1094,14 @@ TEST_CASE("number (int)")
json j2 = 42;
int v2 = j2;
CHECK(j2.get<int>() == v2);
json j3 = 2147483647;
int v3 = j3;
CHECK(j3.get<int>() == v3);
json j4 = 9223372036854775807;
int64_t v4 = j4;
CHECK(j4.get<int64_t>() == v4);
}
SECTION("Operators")