Skip to content
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

Reimplement value() access functions #3663

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/mkdocs/docs/api/basic_json/value.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ValueType value(const typename object_t::key_type& key,
ValueType&& default_value) const;

// (2)
template<class KeyType, class ValueType>
template<class ValueType, class KeyType>
ValueType value(KeyType&& key,
ValueType&& default_value) const;

Expand Down Expand Up @@ -155,5 +155,5 @@ changes to any JSON value.
## Version history

1. Added in version 1.0.0. Changed parameter `default_value` type from `const ValueType&` to `ValueType&&` in version 3.11.0.
2. Added in version 3.11.0.
2. Added in version 3.11.0. Made `ValueType` the first template parameter in version 3.11.2.
3. Added in version 2.0.2.
52 changes: 52 additions & 0 deletions include/nlohmann/detail/meta/type_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -684,5 +684,57 @@ inline constexpr bool value_in_range_of(T val)
return value_in_range_of_impl1<OfType, T>::test(val);
}

template<bool Value>
using bool_constant = std::integral_constant<bool, Value>;

///////////////////////////////////////////////////////////////////////////////
// is_c_string
///////////////////////////////////////////////////////////////////////////////

namespace impl
{

template<typename T>
inline constexpr bool is_c_string()
{
using TUnExt = typename std::remove_extent<T>::type;
using TUnCVExt = typename std::remove_cv<TUnExt>::type;
using TUnPtr = typename std::remove_pointer<T>::type;
using TUnCVPtr = typename std::remove_cv<TUnPtr>::type;
return
(std::is_array<T>::value && std::is_same<TUnCVExt, char>::value)
falbrechtskirchinger marked this conversation as resolved.
Show resolved Hide resolved
|| (std::is_pointer<T>::value && std::is_same<TUnCVPtr, char>::value);
}

} // namespace impl

// checks whether T is a [cv] char */[cv] char[] C string
template<typename T>
struct is_c_string : bool_constant<impl::is_c_string<T>()> {};

template<typename T>
using is_c_string_uncvref = is_c_string<uncvref_t<T>>;

///////////////////////////////////////////////////////////////////////////////
// is_transparent
///////////////////////////////////////////////////////////////////////////////

namespace impl
{

template<typename T>
inline constexpr bool is_transparent()
{
return is_detected<detect_is_transparent, T>::value;
}

} // namespace impl

// checks whether T has a member named is_transparent
template<typename T>
struct is_transparent : bool_constant<impl::is_transparent<T>()> {};

///////////////////////////////////////////////////////////////////////////////

} // namespace detail
NLOHMANN_JSON_NAMESPACE_END
157 changes: 104 additions & 53 deletions include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2194,14 +2194,24 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
}

private:
template<typename KeyType>
using is_comparable_with_object_key = detail::is_comparable <
object_comparator_t, const typename object_t::key_type&, KeyType >;

template<typename ValueType>
using value_return_type = std::conditional <
detail::is_c_string_uncvref<ValueType>::value,
string_t, typename std::decay<ValueType>::type >;

public:
/// @brief access specified object element with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
// this is the value(const typename object_t::key_type&) overload
template < class KeyType, class ValueType, detail::enable_if_t <
std::is_same<KeyType, typename object_t::key_type>::value
template < class ValueType, detail::enable_if_t <
!detail::is_transparent<object_comparator_t>::value
&& detail::is_getable<basic_json_t, ValueType>::value
&& !std::is_same<value_t, ValueType>::value, int > = 0 >
typename std::decay<ValueType>::type value(const KeyType& key, ValueType && default_value) const
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const
{
// value only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
Expand All @@ -2210,47 +2220,49 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
const auto it = find(key);
if (it != end())
{
return it->template get<typename std::decay<ValueType>::type>();
return it->template get<ValueType>();
}

return std::forward<ValueType>(default_value);
return default_value;
}

JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
}

/// @brief access specified object element with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
/// overload for a default value of type const char*
string_t value(const typename object_t::key_type& key, const char* default_value) const
template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type,
detail::enable_if_t <
!detail::is_transparent<object_comparator_t>::value
&& detail::is_getable<basic_json_t, ReturnType>::value
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
ReturnType value(const typename object_t::key_type& key, ValueType && default_value) const
{
return value(key, string_t(default_value));
}
// value only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
// if key is found, return value and given default value otherwise
const auto it = find(key);
if (it != end())
{
return it->template get<ReturnType>();
}

// these two functions, in conjunction with value(const KeyType &, ValueType &&),
// resolve an ambiguity that would otherwise occur between the json_pointer and
// typename object_t::key_type & overloads
template < class ValueType, detail::enable_if_t <
detail::is_getable<basic_json_t, ValueType>::value
&& !std::is_same<value_t, ValueType>::value, int > = 0 >
typename std::decay<ValueType>::type value(const char* key, ValueType && default_value) const
{
return value(typename object_t::key_type(key), std::forward<ValueType>(default_value));
}
return std::forward<ValueType>(default_value);
}

string_t value(const char* key, const char* default_value) const
{
return value(typename object_t::key_type(key), string_t(default_value));
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
}

/// @brief access specified object element with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
/// using std::is_convertible in a std::enable_if will fail when using explicit conversions
template < class KeyType, class ValueType, detail::enable_if_t <
detail::is_getable<basic_json_t, ValueType>::value
&& !std::is_same<value_t, ValueType>::value
&& detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 >
typename std::decay<ValueType>::type value(KeyType && key, ValueType && default_value) const
template < class ValueType, class KeyType, detail::enable_if_t <
detail::is_transparent<object_comparator_t>::value
&& !detail::is_json_pointer<KeyType>::value
&& is_comparable_with_object_key<KeyType>::value
&& detail::is_getable<basic_json_t, ValueType>::value
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
ValueType value(KeyType && key, const ValueType& default_value) const
{
// value only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
Expand All @@ -2259,29 +2271,47 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
const auto it = find(std::forward<KeyType>(key));
if (it != end())
{
return it->template get<typename std::decay<ValueType>::type>();
return it->template get<ValueType>();
}

return std::forward<ValueType>(default_value);
return default_value;
}

JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
}

/// @brief access specified object element with default value
/// @brief access specified object element via JSON Pointer with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
/// overload for a default value of type const char*
template < class KeyType, detail::enable_if_t <
!detail::is_json_pointer<KeyType>::value, int > = 0 >
string_t value(KeyType && key, const char* default_value) const
template < class ValueType, class KeyType, class ReturnType = typename value_return_type<ValueType>::type,
detail::enable_if_t <
detail::is_transparent<object_comparator_t>::value
&& !detail::is_json_pointer<KeyType>::value
&& is_comparable_with_object_key<KeyType>::value
&& detail::is_getable<basic_json_t, ReturnType>::value
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
ReturnType value(KeyType && key, ValueType && default_value) const
{
return value(std::forward<KeyType>(key), string_t(default_value));
// value only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
// if key is found, return value and given default value otherwise
const auto it = find(std::forward<KeyType>(key));
if (it != end())
{
return it->template get<ReturnType>();
}

return std::forward<ValueType>(default_value);
}

JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
}

/// @brief access specified object element via JSON Pointer with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
template < class ValueType, detail::enable_if_t <
detail::is_getable<basic_json_t, ValueType>::value, int> = 0 >
detail::is_getable<basic_json_t, ValueType>::value
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
ValueType value(const json_pointer& ptr, const ValueType& default_value) const
{
// value only works for objects
Expand All @@ -2301,29 +2331,50 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
}

/// @brief access specified object element via JSON Pointer with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type,
detail::enable_if_t <
detail::is_getable<basic_json_t, ReturnType>::value
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
ReturnType value(const json_pointer& ptr, ValueType && default_value) const
{
// value only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
// if pointer resolves a value, return it or use default value
JSON_TRY
{
return ptr.get_checked(this).template get<ReturnType>();
}
JSON_INTERNAL_CATCH (out_of_range&)
{
return std::forward<ValueType>(default_value);
}
}

JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
}

template < class ValueType, class BasicJsonType, detail::enable_if_t <
detail::is_getable<basic_json_t, ValueType>::value, int> = 0 >
detail::is_basic_json<BasicJsonType>::value
&& detail::is_getable<basic_json_t, ValueType>::value
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const
{
return value(ptr.convert(), default_value);
}

/// @brief access specified object element via JSON Pointer with default value
/// @sa https://json.nlohmann.me/api/basic_json/value/
/// overload for a default value of type const char*
JSON_HEDLEY_NON_NULL(3)
string_t value(const json_pointer& ptr, const char* default_value) const
{
return value(ptr, string_t(default_value));
}

template<typename BasicJsonType>
template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type,
detail::enable_if_t <
detail::is_basic_json<BasicJsonType>::value
&& detail::is_getable<basic_json_t, ReturnType>::value
&& !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
JSON_HEDLEY_NON_NULL(3)
string_t value(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr, const char* default_value) const
ReturnType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, ValueType && default_value) const
{
return value(ptr.convert(), default_value);
return value(ptr.convert(), std::forward<ValueType>(default_value));
}

/// @brief access the first element
Expand Down
Loading