From 021f7dee9270727a11db8e7b462261d0f125918c Mon Sep 17 00:00:00 2001 From: Billy Donahue Date: Fri, 7 Nov 2014 10:00:58 -0500 Subject: [PATCH 1/6] Json::Value constructor: Accept any arithmetic type. --- include/json/value.h | 52 ++++++++++++++++++++++++++++----- src/lib_json/json_value.cpp | 57 ------------------------------------- src/test_lib_json/main.cpp | 37 ++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 64 deletions(-) diff --git a/include/json/value.h b/include/json/value.h index a60ca8f75..38e277c23 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -9,6 +9,7 @@ #if !defined(JSON_IS_AMALGAMATION) #include "forwards.h" #endif // if !defined(JSON_IS_AMALGAMATION) +#include #include #include @@ -84,6 +85,30 @@ class JSON_API StaticString { const char* str_; }; +// Some helper traits for Json::Value +namespace Detail { + +template +struct IsIntegral { + enum { value = std::numeric_limits::is_specialized && + std::numeric_limits::is_integer }; +}; + +template +struct IsFloatingPoint { + enum { value = std::numeric_limits::is_specialized && + !std::numeric_limits::is_integer }; +}; + +template struct EnableIf { }; +template struct EnableIf { typedef T type; }; + +template +struct EnableIfArithmetic + : EnableIf::value || IsFloatingPoint::value, int> {}; + +} // namespace Detail + /** \brief Represents a JSON value. * * This class is a discriminated union wrapper that can represents a: @@ -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 + Value(T value, typename Detail::EnableIfArithmetic::type = 0) + : allocated_(false), +#ifdef JSON_VALUE_USE_INTERNAL_MAP + itemIsUsed_(0), +#endif + comments_(0), start_(0), limit_(0) { + if (Detail::IsFloatingPoint::value) { + type_ = realValue; + value_.real_ = value; + } else if (std::numeric_limits::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. diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index 2a0b97bbb..60c69f6c0 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -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 diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index 13fc21df5..f2f16a72f 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -6,6 +6,7 @@ #include "jsontest.h" #include #include +#include #include // Make numeric limits more convenient to talk about. @@ -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(0)).type()); + JSONTEST_ASSERT_EQUAL(Json::uintValue, + Json::Value(static_cast(0)).type()); + JSONTEST_ASSERT_EQUAL(Json::intValue, + Json::Value(static_cast(0)).type()); + // signed + JSONTEST_ASSERT_EQUAL(Json::intValue, + Json::Value(static_cast(0)).type()); + JSONTEST_ASSERT_EQUAL(Json::intValue, + Json::Value(static_cast(0)).type()); + JSONTEST_ASSERT_EQUAL(Json::intValue, + Json::Value(static_cast(0)).type()); + JSONTEST_ASSERT_EQUAL(Json::intValue, + Json::Value(static_cast(0)).type()); + // unsigned + JSONTEST_ASSERT_EQUAL(Json::uintValue, + Json::Value(static_cast(0)).type()); + JSONTEST_ASSERT_EQUAL(Json::uintValue, + Json::Value(static_cast(0)).type()); + JSONTEST_ASSERT_EQUAL(Json::uintValue, + Json::Value(static_cast(0)).type()); + JSONTEST_ASSERT_EQUAL(Json::uintValue, + Json::Value(static_cast(0)).type()); + // long long types if available +#ifdef LLONG_MAX + JSONTEST_ASSERT_EQUAL(Json::intValue, + Json::Value(static_cast(0)).type()); +#endif +#ifdef ULLONG_MAX + JSONTEST_ASSERT_EQUAL(Json::uintValue, + Json::Value(static_cast(0)).type()); +#endif + checks = IsCheck(); checks.isInt_ = true; checks.isInt64_ = true; From 7ba2c54e6b27050e00dcd7762600734a9086926f Mon Sep 17 00:00:00 2001 From: Billy Donahue Date: Sat, 8 Nov 2014 10:59:28 -0500 Subject: [PATCH 2/6] Improve comments on arithmetic type constructor and helper traits. --- include/json/value.h | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/include/json/value.h b/include/json/value.h index 38e277c23..f45ab397f 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -85,13 +85,12 @@ class JSON_API StaticString { const char* str_; }; -// Some helper traits for Json::Value +// Some Json::Value helpers in lieu of C++11 . namespace Detail { template struct IsIntegral { - enum { value = std::numeric_limits::is_specialized && - std::numeric_limits::is_integer }; + enum { value = std::numeric_limits::is_integer }; }; template @@ -236,6 +235,21 @@ Json::Value obj_value(Json::objectValue); // {} */ Value(ValueType type = nullValue); + /** \brief Accept any arithmetic 'T'. + * + * Selected by substitution failure (sfinae) on dummy argument. + * Arithmetic means built-in integral or floating point type. + * This is currently determined with std::numeric_traits. + * Example: + * \code + * Json::Value v[] = { + * Json::Value(my_vector.size()), + * Json::Value(array_last - array_first), + * Json::Value('x'), + * Json::Value(3.14) + * }; + * \endcode + */ template Value(T value, typename Detail::EnableIfArithmetic::type = 0) : allocated_(false), From 1787b6d122ee903a64be7f0f7eab902f1875b091 Mon Sep 17 00:00:00 2001 From: David Jones Date: Thu, 6 Nov 2014 21:23:41 -0500 Subject: [PATCH 3/6] Make 64-bit int work with 'long int' and 'int64_t' for 64 bit builds (Issue #64) --- include/json/config.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/json/config.h b/include/json/config.h index afd3a4560..85b53b08b 100644 --- a/include/json/config.h +++ b/include/json/config.h @@ -87,6 +87,7 @@ #define JSONCPP_DEPRECATED(message) #endif // if !defined(JSONCPP_DEPRECATED) +#include namespace Json { typedef int Int; typedef unsigned int UInt; @@ -100,8 +101,8 @@ typedef unsigned int LargestUInt; typedef __int64 Int64; typedef unsigned __int64 UInt64; #else // if defined(_MSC_VER) // Other platforms, use long long -typedef long long int Int64; -typedef unsigned long long int UInt64; +typedef int64_t Int64; +typedef uint64_t UInt64; #endif // if defined(_MSC_VER) typedef Int64 LargestInt; typedef UInt64 LargestUInt; From 7e29d492173fe0fd1cb5e5592e5b9e9852594f6e Mon Sep 17 00:00:00 2001 From: David Jones Date: Sat, 8 Nov 2014 21:02:08 -0500 Subject: [PATCH 4/6] Only use fix-width types for C++11 (Issue #64) --- include/json/config.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/json/config.h b/include/json/config.h index 85b53b08b..8d947b2b2 100644 --- a/include/json/config.h +++ b/include/json/config.h @@ -87,7 +87,7 @@ #define JSONCPP_DEPRECATED(message) #endif // if !defined(JSONCPP_DEPRECATED) -#include +#include namespace Json { typedef int Int; typedef unsigned int UInt; @@ -100,9 +100,12 @@ typedef unsigned int LargestUInt; #if defined(_MSC_VER) // Microsoft Visual Studio typedef __int64 Int64; typedef unsigned __int64 UInt64; -#else // if defined(_MSC_VER) // Other platforms, use long long +#elif __cplusplus >= 201103L // Using C++11 typedef int64_t Int64; typedef uint64_t UInt64; +#else // Other platforms, use long long +typedef long long Int64; +typedef unsigned long long Uint64; #endif // if defined(_MSC_VER) typedef Int64 LargestInt; typedef UInt64 LargestUInt; From 337b0d2836371b91223e9592aa6b93b3d8057881 Mon Sep 17 00:00:00 2001 From: Billy Donahue Date: Fri, 7 Nov 2014 10:00:58 -0500 Subject: [PATCH 5/6] Json::Value constructor: Accept any arithmetic type. --- include/json/config.h | 10 ++----- include/json/value.h | 52 ++++++++++++++++++++++++++++----- src/lib_json/json_value.cpp | 57 ------------------------------------- src/test_lib_json/main.cpp | 37 ++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 71 deletions(-) diff --git a/include/json/config.h b/include/json/config.h index 8d947b2b2..afd3a4560 100644 --- a/include/json/config.h +++ b/include/json/config.h @@ -87,7 +87,6 @@ #define JSONCPP_DEPRECATED(message) #endif // if !defined(JSONCPP_DEPRECATED) -#include namespace Json { typedef int Int; typedef unsigned int UInt; @@ -100,12 +99,9 @@ typedef unsigned int LargestUInt; #if defined(_MSC_VER) // Microsoft Visual Studio typedef __int64 Int64; typedef unsigned __int64 UInt64; -#elif __cplusplus >= 201103L // Using C++11 -typedef int64_t Int64; -typedef uint64_t UInt64; -#else // Other platforms, use long long -typedef long long Int64; -typedef unsigned long long Uint64; +#else // if defined(_MSC_VER) // Other platforms, use long long +typedef long long int Int64; +typedef unsigned long long int UInt64; #endif // if defined(_MSC_VER) typedef Int64 LargestInt; typedef UInt64 LargestUInt; diff --git a/include/json/value.h b/include/json/value.h index a60ca8f75..38e277c23 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -9,6 +9,7 @@ #if !defined(JSON_IS_AMALGAMATION) #include "forwards.h" #endif // if !defined(JSON_IS_AMALGAMATION) +#include #include #include @@ -84,6 +85,30 @@ class JSON_API StaticString { const char* str_; }; +// Some helper traits for Json::Value +namespace Detail { + +template +struct IsIntegral { + enum { value = std::numeric_limits::is_specialized && + std::numeric_limits::is_integer }; +}; + +template +struct IsFloatingPoint { + enum { value = std::numeric_limits::is_specialized && + !std::numeric_limits::is_integer }; +}; + +template struct EnableIf { }; +template struct EnableIf { typedef T type; }; + +template +struct EnableIfArithmetic + : EnableIf::value || IsFloatingPoint::value, int> {}; + +} // namespace Detail + /** \brief Represents a JSON value. * * This class is a discriminated union wrapper that can represents a: @@ -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 + Value(T value, typename Detail::EnableIfArithmetic::type = 0) + : allocated_(false), +#ifdef JSON_VALUE_USE_INTERNAL_MAP + itemIsUsed_(0), +#endif + comments_(0), start_(0), limit_(0) { + if (Detail::IsFloatingPoint::value) { + type_ = realValue; + value_.real_ = value; + } else if (std::numeric_limits::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. diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index 2a0b97bbb..60c69f6c0 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -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 diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index 13fc21df5..f2f16a72f 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -6,6 +6,7 @@ #include "jsontest.h" #include #include +#include #include // Make numeric limits more convenient to talk about. @@ -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(0)).type()); + JSONTEST_ASSERT_EQUAL(Json::uintValue, + Json::Value(static_cast(0)).type()); + JSONTEST_ASSERT_EQUAL(Json::intValue, + Json::Value(static_cast(0)).type()); + // signed + JSONTEST_ASSERT_EQUAL(Json::intValue, + Json::Value(static_cast(0)).type()); + JSONTEST_ASSERT_EQUAL(Json::intValue, + Json::Value(static_cast(0)).type()); + JSONTEST_ASSERT_EQUAL(Json::intValue, + Json::Value(static_cast(0)).type()); + JSONTEST_ASSERT_EQUAL(Json::intValue, + Json::Value(static_cast(0)).type()); + // unsigned + JSONTEST_ASSERT_EQUAL(Json::uintValue, + Json::Value(static_cast(0)).type()); + JSONTEST_ASSERT_EQUAL(Json::uintValue, + Json::Value(static_cast(0)).type()); + JSONTEST_ASSERT_EQUAL(Json::uintValue, + Json::Value(static_cast(0)).type()); + JSONTEST_ASSERT_EQUAL(Json::uintValue, + Json::Value(static_cast(0)).type()); + // long long types if available +#ifdef LLONG_MAX + JSONTEST_ASSERT_EQUAL(Json::intValue, + Json::Value(static_cast(0)).type()); +#endif +#ifdef ULLONG_MAX + JSONTEST_ASSERT_EQUAL(Json::uintValue, + Json::Value(static_cast(0)).type()); +#endif + checks = IsCheck(); checks.isInt_ = true; checks.isInt64_ = true; From e5556660650229c0545f43ba33b39adcaa7c2be7 Mon Sep 17 00:00:00 2001 From: Billy Donahue Date: Sat, 8 Nov 2014 10:59:28 -0500 Subject: [PATCH 6/6] Improve comments on arithmetic type constructor and helper traits. --- include/json/value.h | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/include/json/value.h b/include/json/value.h index 38e277c23..f45ab397f 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -85,13 +85,12 @@ class JSON_API StaticString { const char* str_; }; -// Some helper traits for Json::Value +// Some Json::Value helpers in lieu of C++11 . namespace Detail { template struct IsIntegral { - enum { value = std::numeric_limits::is_specialized && - std::numeric_limits::is_integer }; + enum { value = std::numeric_limits::is_integer }; }; template @@ -236,6 +235,21 @@ Json::Value obj_value(Json::objectValue); // {} */ Value(ValueType type = nullValue); + /** \brief Accept any arithmetic 'T'. + * + * Selected by substitution failure (sfinae) on dummy argument. + * Arithmetic means built-in integral or floating point type. + * This is currently determined with std::numeric_traits. + * Example: + * \code + * Json::Value v[] = { + * Json::Value(my_vector.size()), + * Json::Value(array_last - array_first), + * Json::Value('x'), + * Json::Value(3.14) + * }; + * \endcode + */ template Value(T value, typename Detail::EnableIfArithmetic::type = 0) : allocated_(false),