This commit is contained in:
Erich Keane 2016-01-21 04:10:05 +00:00
commit 8776431855
2 changed files with 66 additions and 22 deletions

View File

@ -106,6 +106,43 @@ static bool approx(const T a, const T b)
{ {
return not (a > b or a < b); return not (a > b or a < b);
} }
/*!
@brief Type Trait to convert a type to a void for SFINAE purposes
*/
template<typename T>
struct void_converter
{
using type = void;
};
// Type to help determine between a map or unordered-map type for the
// object_t type alias. Takes advantage of the fact that an unordered_map
// has a hasher member type
template<template<typename...> class ObjectType, class Key, class Value,
template<typename> class AllocatorType, typename Enable = void>
struct object_t_helper
{
using type = ObjectType<
Key,
Value,
std::less<Key>,
AllocatorType<std::pair<Key,Value>>>;
};
// Specialization that works for the 'unordered_map' type
template<template<typename...> class ObjectType, class Key, class Value,
template<typename> class AllocatorType>
struct object_t_helper<ObjectType, Key, Value, AllocatorType,
typename void_converter<typename ObjectType<char,char>::hasher>::type
>
{
using type = ObjectType<
Key,
Value,
std::hash<Key>,
std::equal_to<Key>,
AllocatorType<std::pair<Key,Value>>>;
};
} }
/*! /*!
@ -334,11 +371,12 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
using object_t = ObjectType<StringType, using object_t = typename object_t_helper<
basic_json, ObjectType,
std::less<StringType>, StringType,
AllocatorType<std::pair<const StringType, basic_json,
basic_json>>>; AllocatorType
>::type;
/*! /*!
@brief a type for an array @brief a type for an array
@ -960,7 +998,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)
@ -2170,7 +2208,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
@ -2807,7 +2845,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())
@ -2855,7 +2893,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())
@ -2988,7 +3026,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())
@ -3036,7 +3074,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())
@ -3199,7 +3237,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())
@ -3225,7 +3263,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));
} }
@ -3539,7 +3577,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())
@ -3613,7 +3651,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();
@ -3630,7 +3668,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();
@ -3661,7 +3699,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
assert(not is_object() or m_value.object != nullptr); assert(not is_object() or m_value.object != nullptr);
@ -4306,7 +4344,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()))
@ -4328,9 +4366,9 @@ 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 std::pair<StringType, basic_json>&)
*/ */
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);
@ -6266,7 +6304,7 @@ class basic_json
} }
/// return the key of an object iterator /// return the key of an object iterator
typename object_t::key_type key() const StringType key() const
{ {
assert(m_object != nullptr); assert(m_object != nullptr);
@ -6525,7 +6563,7 @@ class basic_json
} }
/// return the key of an object iterator /// return the key of an object iterator
typename object_t::key_type key() const StringType key() const
{ {
auto it = --this->base(); auto it = --this->base();
return it.key(); return it.key();

View File

@ -11500,6 +11500,12 @@ TEST_CASE("regression tests")
CHECK(s2 == "value"); CHECK(s2 == "value");
} }
SECTION("issue #164 - std::unordered_map cannot be used as ObjectType")
{
// create JSON class with std::unordered_map instead of a std::map
nlohmann::basic_json<std::unordered_map> 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");