Skip to content

Json::Value constructor: Accept any arithmetic type. #66

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 8 commits into from
Closed
52 changes: 45 additions & 7 deletions include/json/value.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#if !defined(JSON_IS_AMALGAMATION)
#include "forwards.h"
#endif // if !defined(JSON_IS_AMALGAMATION)
#include <limits>
#include <string>
#include <vector>

Expand Down Expand Up @@ -84,6 +85,30 @@ class JSON_API StaticString {
const char* str_;
};

// Some helper traits for Json::Value
namespace Detail {

template <typename T>
struct IsIntegral {
enum { value = std::numeric_limits<T>::is_specialized &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly out of curiosity: why this is_specialized here? According to cppreference, is_integer is false for non-specialized types. Maybe that's not guaranteed for future versions of the standard?

std::numeric_limits<T>::is_integer };
};

template <typename T>
struct IsFloatingPoint {
enum { value = std::numeric_limits<T>::is_specialized &&
!std::numeric_limits<T>::is_integer };
};

template <bool C, typename T = void> struct EnableIf { };
template <typename T> struct EnableIf<true, T> { typedef T type; };

template <typename T>
struct EnableIfArithmetic
: EnableIf<IsIntegral<T>::value || IsFloatingPoint<T>::value, int> {};

} // namespace Detail

/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
*
* This class is a discriminated union wrapper that can represents a:
Expand Down Expand Up @@ -210,13 +235,26 @@ Json::Value obj_value(Json::objectValue); // {}
\endcode
*/
Value(ValueType type = nullValue);
Value(Int value);
Value(UInt value);
#if defined(JSON_HAS_INT64)
Value(Int64 value);
Value(UInt64 value);
#endif // if defined(JSON_HAS_INT64)
Value(double value);

template <typename T>
Value(T value, typename Detail::EnableIfArithmetic<T>::type = 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment explaining what is going on here, maybe with the key word 'SFINAE' for those unfamiliar.

: allocated_(false),
#ifdef JSON_VALUE_USE_INTERNAL_MAP
itemIsUsed_(0),
#endif
comments_(0), start_(0), limit_(0) {
if (Detail::IsFloatingPoint<T>::value) {
type_ = realValue;
value_.real_ = value;
} else if (std::numeric_limits<T>::is_signed) {
type_ = intValue;
value_.int_ = value;
} else {
type_ = uintValue;
value_.uint_ = value;
}
}

Value(const char* value);
Value(const char* beginValue, const char* endValue);
/** \brief Constructs a value from a static string.
Expand Down
57 changes: 0 additions & 57 deletions src/lib_json/json_value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,63 +267,6 @@ Value::Value(ValueType type)
}
}

Value::Value(UInt value)
: type_(uintValue), allocated_(false)
#ifdef JSON_VALUE_USE_INTERNAL_MAP
,
itemIsUsed_(0)
#endif
,
comments_(0), start_(0), limit_(0) {
value_.uint_ = value;
}

Value::Value(Int value)
: type_(intValue), allocated_(false)
#ifdef JSON_VALUE_USE_INTERNAL_MAP
,
itemIsUsed_(0)
#endif
,
comments_(0), start_(0), limit_(0) {
value_.int_ = value;
}

#if defined(JSON_HAS_INT64)
Value::Value(Int64 value)
: type_(intValue), allocated_(false)
#ifdef JSON_VALUE_USE_INTERNAL_MAP
,
itemIsUsed_(0)
#endif
,
comments_(0), start_(0), limit_(0) {
value_.int_ = value;
}

Value::Value(UInt64 value)
: type_(uintValue), allocated_(false)
#ifdef JSON_VALUE_USE_INTERNAL_MAP
,
itemIsUsed_(0)
#endif
,
comments_(0), start_(0), limit_(0) {
value_.uint_ = value;
}
#endif // defined(JSON_HAS_INT64)

Value::Value(double value)
: type_(realValue), allocated_(false)
#ifdef JSON_VALUE_USE_INTERNAL_MAP
,
itemIsUsed_(0)
#endif
,
comments_(0), start_(0), limit_(0) {
value_.real_ = value;
}

Value::Value(const char* value)
: type_(stringValue), allocated_(true)
#ifdef JSON_VALUE_USE_INTERNAL_MAP
Expand Down
37 changes: 37 additions & 0 deletions src/test_lib_json/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "jsontest.h"
#include <json/config.h>
#include <json/json.h>
#include <climits>
#include <stdexcept>

// Make numeric limits more convenient to talk about.
Expand Down Expand Up @@ -394,6 +395,42 @@ JSONTEST_FIXTURE(ValueTest, integers) {

JSONTEST_ASSERT_EQUAL(Json::uintValue, val.type());

// A few more integral types
// special
JSONTEST_ASSERT_EQUAL(Json::booleanValue,
Json::Value(static_cast<bool>(0)).type());
JSONTEST_ASSERT_EQUAL(Json::uintValue,
Json::Value(static_cast<std::size_t>(0)).type());
JSONTEST_ASSERT_EQUAL(Json::intValue,
Json::Value(static_cast<std::ptrdiff_t>(0)).type());
// signed
JSONTEST_ASSERT_EQUAL(Json::intValue,
Json::Value(static_cast<signed char>(0)).type());
JSONTEST_ASSERT_EQUAL(Json::intValue,
Json::Value(static_cast<short>(0)).type());
JSONTEST_ASSERT_EQUAL(Json::intValue,
Json::Value(static_cast<int>(0)).type());
JSONTEST_ASSERT_EQUAL(Json::intValue,
Json::Value(static_cast<long>(0)).type());
// unsigned
JSONTEST_ASSERT_EQUAL(Json::uintValue,
Json::Value(static_cast<unsigned char>(0)).type());
JSONTEST_ASSERT_EQUAL(Json::uintValue,
Json::Value(static_cast<unsigned short>(0)).type());
JSONTEST_ASSERT_EQUAL(Json::uintValue,
Json::Value(static_cast<unsigned>(0)).type());
JSONTEST_ASSERT_EQUAL(Json::uintValue,
Json::Value(static_cast<unsigned long>(0)).type());
// long long types if available
#ifdef LLONG_MAX
JSONTEST_ASSERT_EQUAL(Json::intValue,
Json::Value(static_cast<long long>(0)).type());
#endif
#ifdef ULLONG_MAX
JSONTEST_ASSERT_EQUAL(Json::uintValue,
Json::Value(static_cast<unsigned long long>(0)).type());
#endif

checks = IsCheck();
checks.isInt_ = true;
checks.isInt64_ = true;
Expand Down