Abstract object/array type out so that arbitrary types can be used

As suggested by @palacaze in #161, this allows using an unordered_map
as well as anything that obeys the template<K,V> type for the object
type or template<V> for the array type.
This commit is contained in:
Erich Keane 2016-01-01 13:35:21 -08:00
parent 9b07504e23
commit 03ccb5917e
2 changed files with 39 additions and 23 deletions

View File

@ -107,6 +107,12 @@ static bool approx(const T a, const T b)
} }
} }
template<typename K, typename V>
using default_object_type = std::map<K,V>;
template<typename V>
using default_array_type = std::vector<V>;
/*! /*!
@brief a class to store JSON values @brief a class to store JSON values
@ -176,8 +182,8 @@ default)
@nosubgrouping @nosubgrouping
*/ */
template < template <
template<typename U, typename V, typename... Args> class ObjectType = std::map, template<typename K, typename V> class ObjectType = default_object_type,
template<typename U, typename... Args> class ArrayType = std::vector, template<typename V> class ArrayType = default_array_type,
class StringType = std::string, class StringType = std::string,
class BooleanType = bool, class BooleanType = bool,
class NumberIntegerType = int64_t, class NumberIntegerType = int64_t,
@ -333,11 +339,7 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
using object_t = ObjectType<StringType, using object_t = ObjectType<StringType, basic_json>;
basic_json,
std::less<StringType>,
AllocatorType<std::pair<const StringType,
basic_json>>>;
/*! /*!
@brief a type for an array @brief a type for an array
@ -383,7 +385,7 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
using array_t = ArrayType<basic_json, AllocatorType<basic_json>>; using array_t = ArrayType<basic_json>;
/*! /*!
@brief a type for a string @brief a type for a string
@ -959,7 +961,7 @@ class basic_json
*/ */
template <class CompatibleObjectType, typename template <class CompatibleObjectType, typename
std::enable_if< std::enable_if<
std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and std::is_constructible<StringType, typename CompatibleObjectType::key_type>::value and
std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type
= 0> = 0>
basic_json(const CompatibleObjectType& val) basic_json(const CompatibleObjectType& val)
@ -2159,7 +2161,7 @@ class basic_json
/// get an object (explicit) /// get an object (explicit)
template <class T, typename template <class T, typename
std::enable_if< std::enable_if<
std::is_convertible<typename object_t::key_type, typename T::key_type>::value and std::is_convertible<StringType, typename T::key_type>::value and
std::is_convertible<basic_json_t, typename T::mapped_type>::value std::is_convertible<basic_json_t, typename T::mapped_type>::value
, int>::type = 0> , int>::type = 0>
T get_impl(T*) const T get_impl(T*) const
@ -2707,7 +2709,7 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
reference at(const typename object_t::key_type& key) reference at(const StringType& key)
{ {
// at only works for objects // at only works for objects
if (is_object()) if (is_object())
@ -2754,7 +2756,7 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
const_reference at(const typename object_t::key_type& key) const const_reference at(const StringType& key) const
{ {
// at only works for objects // at only works for objects
if (is_object()) if (is_object())
@ -2884,7 +2886,7 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
reference operator[](const typename object_t::key_type& key) reference operator[](const StringType& key)
{ {
// implicitly convert null to object // implicitly convert null to object
if (is_null()) if (is_null())
@ -2931,7 +2933,7 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
const_reference operator[](const typename object_t::key_type& key) const const_reference operator[](const StringType& key) const
{ {
// [] only works for objects // [] only works for objects
if (is_object()) if (is_object())
@ -3089,7 +3091,7 @@ class basic_json
std::enable_if< std::enable_if<
std::is_convertible<basic_json_t, ValueType>::value std::is_convertible<basic_json_t, ValueType>::value
, int>::type = 0> , int>::type = 0>
ValueType value(const typename object_t::key_type& key, ValueType default_value) const ValueType value(const StringType& key, ValueType default_value) const
{ {
// at only works for objects // at only works for objects
if (is_object()) if (is_object())
@ -3115,7 +3117,7 @@ class basic_json
@brief overload for a default value of type const char* @brief overload for a default value of type const char*
@copydoc basic_json::value() @copydoc basic_json::value()
*/ */
string_t value(const typename object_t::key_type& key, const char* default_value) const string_t value(const StringType& key, const char* default_value) const
{ {
return value(key, string_t(default_value)); return value(key, string_t(default_value));
} }
@ -3425,7 +3427,7 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
size_type erase(const typename object_t::key_type& key) size_type erase(const StringType& key)
{ {
// this erase only works for objects // this erase only works for objects
if (is_object()) if (is_object())
@ -3497,7 +3499,7 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
iterator find(typename object_t::key_type key) iterator find(StringType key)
{ {
auto result = end(); auto result = end();
@ -3513,7 +3515,7 @@ class basic_json
@brief find an element in a JSON object @brief find an element in a JSON object
@copydoc find(typename object_t::key_type) @copydoc find(typename object_t::key_type)
*/ */
const_iterator find(typename object_t::key_type key) const const_iterator find(StringType key) const
{ {
auto result = cend(); auto result = cend();
@ -3543,7 +3545,7 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
size_type count(typename object_t::key_type key) const size_type count(StringType key) const
{ {
// return 0 for all nonobject types // return 0 for all nonobject types
return is_object() ? m_value.object->count(key) : 0; return is_object() ? m_value.object->count(key) : 0;
@ -4176,7 +4178,7 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
void push_back(const typename object_t::value_type& val) void push_back(const std::pair<StringType, basic_json>& val)
{ {
// push_back only works for null objects or objects // push_back only works for null objects or objects
if (not(is_null() or is_object())) if (not(is_null() or is_object()))
@ -4199,7 +4201,7 @@ class basic_json
@brief add an object to an object @brief add an object to an object
@copydoc push_back(const typename object_t::value_type&) @copydoc push_back(const typename object_t::value_type&)
*/ */
reference operator+=(const typename object_t::value_type& val) reference operator+=(const std::pair<StringType, basic_json>& val)
{ {
push_back(val); push_back(val);
return operator[](val.first); return operator[](val.first);

View File

@ -11043,6 +11043,9 @@ TEST_CASE("RFC 7159 examples")
} }
} }
template<typename K, typename V>
using unordered_map_type = std::unordered_map<K,V>;
TEST_CASE("Unicode", "[hide]") TEST_CASE("Unicode", "[hide]")
{ {
SECTION("full enumeration of Unicode codepoints") SECTION("full enumeration of Unicode codepoints")
@ -11216,7 +11219,13 @@ TEST_CASE("regression tests")
SECTION("issue #89 - nonstandard integer type") SECTION("issue #89 - nonstandard integer type")
{ {
// create JSON class with nonstandard integer number type // create JSON class with nonstandard integer number type
nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, float> j; nlohmann::basic_json<
nlohmann::default_object_type,
nlohmann::default_array_type,
std::string,
bool,
int32_t,
float> j;
j["int_1"] = 1; j["int_1"] = 1;
// we need to cast to int to compile with Catch - the value is int32_t // we need to cast to int to compile with Catch - the value is int32_t
CHECK(static_cast<int>(j["int_1"]) == 1); CHECK(static_cast<int>(j["int_1"]) == 1);
@ -11314,6 +11323,11 @@ TEST_CASE("regression tests")
CHECK(s2 == "value"); CHECK(s2 == "value");
} }
SECTION("issue #164 - std::unordered_map cannot be used as Object Type")
{
nlohmann::basic_json<unordered_map_type> unordered_json;
}
SECTION("character following a surrogate pair is skipped") SECTION("character following a surrogate pair is skipped")
{ {
CHECK(json::parse("\"\\ud80c\\udc60abc\"").get<json::string_t>() == u8"\U00013060abc"); CHECK(json::parse("\"\\ud80c\\udc60abc\"").get<json::string_t>() == u8"\U00013060abc");