💄 moved changes to re2c file and ran make pretty

This commit is contained in:
Niels Lohmann 2016-12-18 20:32:09 +01:00 committed by Théo DELRIEU
parent aa2679a8ce
commit be1d3de49b
4 changed files with 6100 additions and 5602 deletions

View file

@ -142,7 +142,10 @@ using is_unscoped_enum =
namespace detail namespace detail
{ {
// Very useful construct against boilerplate (more boilerplate needed than in C++17: http://en.cppreference.com/w/cpp/types/void_t) // Very useful construct against boilerplate (more boilerplate needed than in C++17: http://en.cppreference.com/w/cpp/types/void_t)
template <typename...> struct make_void { using type = void; }; template <typename...> struct make_void
{
using type = void;
};
template <typename... Ts> using void_t = typename make_void<Ts...>::type; template <typename... Ts> using void_t = typename make_void<Ts...>::type;
// Implementation of 3 C++17 constructs: conjunction, disjunction, negation. // Implementation of 3 C++17 constructs: conjunction, disjunction, negation.
@ -160,14 +163,14 @@ template <class...> struct conjunction : std::true_type {};
template <class B1> struct conjunction<B1> : B1 {}; template <class B1> struct conjunction<B1> : B1 {};
template <class B1, class... Bn> template <class B1, class... Bn>
struct conjunction<B1, Bn...> struct conjunction<B1, Bn...>
: conditional_t<bool(B1::value), conjunction<Bn...>, B1> {}; : conditional_t<bool(B1::value), conjunction<Bn...>, B1> {};
template <class B> struct negation : std::integral_constant<bool, !B::value> {}; template <class B> struct negation : std::integral_constant < bool, !B::value > {};
template <class...> struct disjunction : std::false_type {}; template <class...> struct disjunction : std::false_type {};
template <class B1> struct disjunction<B1> : B1 {}; template <class B1> struct disjunction<B1> : B1 {};
template <class B1, class... Bn> template <class B1, class... Bn>
struct disjunction<B1, Bn...> struct disjunction<B1, Bn...>
: conditional_t<bool(B1::value), B1, disjunction<Bn...>> {}; : conditional_t<bool(B1::value), B1, disjunction<Bn...>> {};
/*! /*!
@brief Helper to determine whether there's a key_type for T. @brief Helper to determine whether there's a key_type for T.
@ -198,7 +201,7 @@ NLOHMANN_JSON_HAS_HELPER(iterator)
#undef NLOHMANN_JSON_HAS_HELPER #undef NLOHMANN_JSON_HAS_HELPER
template <bool B, class RealType, class CompatibleObjectType> template <bool B, class RealType, class CompatibleObjectType>
struct is_compatible_object_type_impl : std::false_type{}; struct is_compatible_object_type_impl : std::false_type {};
template <class RealType, class CompatibleObjectType> template <class RealType, class CompatibleObjectType>
struct is_compatible_object_type_impl<true, RealType, CompatibleObjectType> struct is_compatible_object_type_impl<true, RealType, CompatibleObjectType>
@ -215,15 +218,15 @@ struct is_compatible_object_type
{ {
// As noted ahead, we need to stop evaluating traits if CompatibleObjectType = void // As noted ahead, we need to stop evaluating traits if CompatibleObjectType = void
// hence the conjunction // hence the conjunction
static auto constexpr value = is_compatible_object_type_impl< static auto constexpr value = is_compatible_object_type_impl <
conjunction<negation<std::is_same<void, CompatibleObjectType>>, conjunction<negation<std::is_same<void, CompatibleObjectType>>,
has_mapped_type<CompatibleObjectType>, has_mapped_type<CompatibleObjectType>,
has_key_type<CompatibleObjectType>>::value, has_key_type<CompatibleObjectType>>::value,
RealType, CompatibleObjectType>::value; RealType, CompatibleObjectType >::value;
}; };
template <bool B, class BasicJson, class CompatibleArrayType> template <bool B, class BasicJson, class CompatibleArrayType>
struct is_compatible_array_type_impl : std::false_type{}; struct is_compatible_array_type_impl : std::false_type {};
template <class BasicJson, class CompatibleArrayType> template <class BasicJson, class CompatibleArrayType>
struct is_compatible_array_type_impl<true, BasicJson, CompatibleArrayType> struct is_compatible_array_type_impl<true, BasicJson, CompatibleArrayType>
@ -248,16 +251,16 @@ struct is_compatible_array_type
{ {
// the check for CompatibleArrayType = void is done in is_compatible_object_type // the check for CompatibleArrayType = void is done in is_compatible_object_type
// but we need the conjunction here as well // but we need the conjunction here as well
static auto constexpr value = is_compatible_array_type_impl< static auto constexpr value = is_compatible_array_type_impl <
conjunction<negation<is_compatible_object_type< conjunction<negation<is_compatible_object_type<
typename BasicJson::object_t, CompatibleArrayType>>, typename BasicJson::object_t, CompatibleArrayType>>,
has_value_type<CompatibleArrayType>, has_value_type<CompatibleArrayType>,
has_iterator<CompatibleArrayType>>::value, has_iterator<CompatibleArrayType>>::value,
BasicJson, CompatibleArrayType>::value; BasicJson, CompatibleArrayType >::value;
}; };
template <bool, typename, typename> template <bool, typename, typename>
struct is_compatible_integer_type_impl : std::false_type{}; struct is_compatible_integer_type_impl : std::false_type {};
template <typename RealIntegerType, typename CompatibleNumberIntegerType> template <typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIntegerType> struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIntegerType>
@ -275,9 +278,9 @@ struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIn
template <typename RealIntegerType, typename CompatibleNumberIntegerType> template <typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type struct is_compatible_integer_type
{ {
static constexpr auto value = is_compatible_integer_type_impl< static constexpr auto value = is_compatible_integer_type_impl <
std::is_arithmetic<CompatibleNumberIntegerType>::value, RealIntegerType, std::is_arithmetic<CompatibleNumberIntegerType>::value, RealIntegerType,
CompatibleNumberIntegerType>::value; CompatibleNumberIntegerType >::value;
}; };
template <typename RealFloat, typename CompatibleFloat> template <typename RealFloat, typename CompatibleFloat>
@ -321,15 +324,15 @@ template <template <typename, typename> class JSONSerializer, typename Json,
typename T> typename T>
struct has_from_json struct has_from_json
{ {
private: private:
// also check the return type of from_json // also check the return type of from_json
template <typename U, typename = enable_if_t<std::is_same<void, decltype(uncvref_t<U>::from_json( template <typename U, typename = enable_if_t<std::is_same<void, decltype(uncvref_t<U>::from_json(
std::declval<Json>(), std::declval<T &>()))>::value>> std::declval<Json>(), std::declval<T&>()))>::value>>
static int detect(U &&); static int detect(U&&);
static void detect(...); static void detect(...);
public: public:
static constexpr bool value = std::is_integral<decltype( static constexpr bool value = std::is_integral<decltype(
detect(std::declval<JSONSerializer<T, void>>()))>::value; detect(std::declval<JSONSerializer<T, void>>()))>::value;
}; };
@ -340,13 +343,13 @@ template <template <typename, typename> class JSONSerializer, typename Json,
typename T> typename T>
struct has_non_default_from_json struct has_non_default_from_json
{ {
private: private:
template <typename U, typename = enable_if_t<std::is_same<T, decltype(uncvref_t<U>::from_json(std::declval<Json>()))>::value>> template <typename U, typename = enable_if_t<std::is_same<T, decltype(uncvref_t<U>::from_json(std::declval<Json>()))>::value>>
static int detect(U &&); static int detect(U&&);
static void detect(...); static void detect(...);
public: public:
static constexpr bool value = std::is_integral<decltype( static constexpr bool value = std::is_integral<decltype(
detect(std::declval<JSONSerializer<T, void>>()))>::value; detect(std::declval<JSONSerializer<T, void>>()))>::value;
}; };
@ -356,14 +359,14 @@ template <template <typename, typename> class JSONSerializer, typename Json,
typename T> typename T>
struct has_to_json struct has_to_json
{ {
private: private:
template <typename U, typename = decltype(uncvref_t<U>::to_json( template <typename U, typename = decltype(uncvref_t<U>::to_json(
std::declval<Json &>(), std::declval<T>()))> std::declval<Json&>(), std::declval<T>()))>
static int detect(U &&); static int detect(U&&);
static void detect(...); static void detect(...);
public: public:
static constexpr bool value = std::is_integral<decltype( static constexpr bool value = std::is_integral<decltype(
detect(std::declval<JSONSerializer<T, void>>()))>::value; detect(std::declval<JSONSerializer<T, void>>()))>::value;
}; };
@ -377,7 +380,7 @@ struct to_json_fn
{ {
// is it really useful to mark those as constexpr? // is it really useful to mark those as constexpr?
template <typename Json, typename T> template <typename Json, typename T>
constexpr auto operator()(Json &&j, T &&val) const constexpr auto operator()(Json&& j, T&& val) const
noexcept(noexcept(to_json(std::forward<Json>(j), std::forward<T>(val)))) noexcept(noexcept(to_json(std::forward<Json>(j), std::forward<T>(val))))
-> decltype(to_json(std::forward<Json>(j), std::forward<T>(val)), -> decltype(to_json(std::forward<Json>(j), std::forward<T>(val)),
void()) void())
@ -389,7 +392,7 @@ struct to_json_fn
struct from_json_fn struct from_json_fn
{ {
template <typename Json, typename T> template <typename Json, typename T>
constexpr auto operator()(Json &&j, T &val) const constexpr auto operator()(Json&& j, T& val) const
noexcept(noexcept(from_json(std::forward<Json>(j), val))) noexcept(noexcept(from_json(std::forward<Json>(j), val)))
-> decltype(from_json(std::forward<Json>(j), val), void()) -> decltype(from_json(std::forward<Json>(j), val), void())
{ {
@ -431,8 +434,8 @@ constexpr T static_const<T>::value;
inline namespace inline namespace
{ {
constexpr auto const& to_json = static_const<detail::to_json_fn>::value; constexpr auto const& to_json = static_const<detail::to_json_fn>::value;
constexpr auto const& from_json = static_const<detail::from_json_fn>::value; constexpr auto const& from_json = static_const<detail::from_json_fn>::value;
} }
// default JSONSerializer template argument, doesn't care about template argument // default JSONSerializer template argument, doesn't care about template argument
@ -1535,7 +1538,7 @@ class basic_json
enable_if_t<detail::is_compatible_object_type< enable_if_t<detail::is_compatible_object_type<
object_t, CompatibleObjectType>::value, object_t, CompatibleObjectType>::value,
int> = 0> int> = 0>
basic_json(const CompatibleObjectType &val) : m_type(value_t::object) basic_json(const CompatibleObjectType& val) : m_type(value_t::object)
{ {
using std::begin; using std::begin;
using std::end; using std::end;
@ -1598,7 +1601,7 @@ class basic_json
enable_if_t<detail::is_compatible_array_type< enable_if_t<detail::is_compatible_array_type<
basic_json_t, CompatibleArrayType>::value, basic_json_t, CompatibleArrayType>::value,
int> = 0> int> = 0>
basic_json(const CompatibleArrayType &val) : m_type(value_t::array) basic_json(const CompatibleArrayType& val) : m_type(value_t::array)
{ {
using std::begin; using std::begin;
using std::end; using std::end;
@ -1622,8 +1625,8 @@ class basic_json
uncvref_t<T>, basic_json_t>>, uncvref_t<T>, basic_json_t>>,
detail::has_to_json<JSONSerializer, basic_json, detail::has_to_json<JSONSerializer, basic_json,
uncvref_t<T>>>::value, uncvref_t<T>>>::value,
int> = 0> int> = 0 >
basic_json(T &&val) basic_json(T && val)
{ {
JSONSerializer<uncvref_t<T>>::to_json(*this, std::forward<T>(val)); JSONSerializer<uncvref_t<T>>::to_json(*this, std::forward<T>(val));
} }
@ -1828,10 +1831,11 @@ class basic_json
typename CompatibleNumberIntegerType, typename CompatibleNumberIntegerType,
enable_if_t<detail::is_compatible_integer_type< enable_if_t<detail::is_compatible_integer_type<
number_integer_t, CompatibleNumberIntegerType>::value, number_integer_t, CompatibleNumberIntegerType>::value,
int> = 0> int> = 0 >
basic_json(const CompatibleNumberIntegerType val) noexcept basic_json(const CompatibleNumberIntegerType val) noexcept
: m_type(value_t::number_integer), : m_type(value_t::number_integer),
m_value(static_cast<number_integer_t>(val)) { m_value(static_cast<number_integer_t>(val))
{
assert_invariant(); assert_invariant();
} }
@ -1885,10 +1889,11 @@ class basic_json
typename CompatibleNumberUnsignedType, typename CompatibleNumberUnsignedType,
enable_if_t<detail::is_compatible_integer_type< enable_if_t<detail::is_compatible_integer_type<
number_unsigned_t, CompatibleNumberUnsignedType>::value, number_unsigned_t, CompatibleNumberUnsignedType>::value,
int> = 0> int> = 0 >
basic_json(const CompatibleNumberUnsignedType val) noexcept basic_json(const CompatibleNumberUnsignedType val) noexcept
: m_type(value_t::number_unsigned), : m_type(value_t::number_unsigned),
m_value(static_cast<number_unsigned_t>(val)) { m_value(static_cast<number_unsigned_t>(val))
{
assert_invariant(); assert_invariant();
} }
@ -2521,7 +2526,7 @@ class basic_json
template <typename T, enable_if_t<not detail::is_compatible_basic_json_type< template <typename T, enable_if_t<not detail::is_compatible_basic_json_type<
uncvref_t<T>, basic_json_t>::value and uncvref_t<T>, basic_json_t>::value and
detail::has_to_json<JSONSerializer, basic_json_t, uncvref_t<T>>::value>> detail::has_to_json<JSONSerializer, basic_json_t, uncvref_t<T>>::value>>
reference &operator=(T &&val) noexcept(std::is_nothrow_constructible<basic_json_t, uncvref_t<T>>::value and reference& operator=(T&& val) noexcept(std::is_nothrow_constructible<basic_json_t, uncvref_t<T>>::value and
std::is_nothrow_move_assignable<uncvref_t<T>>::value) std::is_nothrow_move_assignable<uncvref_t<T>>::value)
{ {
static_assert(sizeof(T) == 0 , ""); static_assert(sizeof(T) == 0 , "");
@ -2544,32 +2549,38 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
~basic_json() { ~basic_json()
{
assert_invariant(); assert_invariant();
switch (m_type) { switch (m_type)
case value_t::object: { {
case value_t::object:
{
AllocatorType<object_t> alloc; AllocatorType<object_t> alloc;
alloc.destroy(m_value.object); alloc.destroy(m_value.object);
alloc.deallocate(m_value.object, 1); alloc.deallocate(m_value.object, 1);
break; break;
} }
case value_t::array: { case value_t::array:
{
AllocatorType<array_t> alloc; AllocatorType<array_t> alloc;
alloc.destroy(m_value.array); alloc.destroy(m_value.array);
alloc.deallocate(m_value.array, 1); alloc.deallocate(m_value.array, 1);
break; break;
} }
case value_t::string: { case value_t::string:
{
AllocatorType<string_t> alloc; AllocatorType<string_t> alloc;
alloc.destroy(m_value.string); alloc.destroy(m_value.string);
alloc.deallocate(m_value.string, 1); alloc.deallocate(m_value.string, 1);
break; break;
} }
default: { default:
{
// all other types need no specific destructor // all other types need no specific destructor
break; break;
} }
@ -3025,15 +3036,15 @@ class basic_json
/// get an array (explicit) /// get an array (explicit)
template < template <
class T, class T,
typename std::enable_if< typename std::enable_if <
std::is_convertible<basic_json_t, typename T::value_type>::value and std::is_convertible<basic_json_t, typename T::value_type>::value and
not std::is_same<basic_json_t, not std::is_same<basic_json_t,
typename T::value_type>::value and typename T::value_type>::value and
not std::is_arithmetic<T>::value and not std::is_arithmetic<T>::value and
not std::is_convertible<std::string, T>::value and not std::is_convertible<std::string, T>::value and
not detail::has_mapped_type<T>::value, not detail::has_mapped_type<T>::value,
int>::type = 0> int >::type = 0 >
T get_impl(T *) const T get_impl(T*) const
{ {
if (is_array()) if (is_array())
{ {
@ -3305,9 +3316,9 @@ class basic_json
template <typename ValueType, template <typename ValueType,
enable_if_t<not std::is_pointer<ValueType>::value, int> = 0> enable_if_t<not std::is_pointer<ValueType>::value, int> = 0>
auto get() const auto get() const
-> decltype(this->get_impl(static_cast<ValueType *>(nullptr))) -> decltype(this->get_impl(static_cast<ValueType*>(nullptr)))
{ {
return get_impl(static_cast<ValueType *>(nullptr)); return get_impl(static_cast<ValueType*>(nullptr));
} }
template < template <
@ -3316,11 +3327,11 @@ class basic_json
uncvref_t<T>, basic_json_t>>, uncvref_t<T>, basic_json_t>>,
detail::has_from_json<JSONSerializer, basic_json_t, detail::has_from_json<JSONSerializer, basic_json_t,
uncvref_t<T>>>::value, uncvref_t<T>>>::value,
int> = 0> int> = 0 >
auto get() const -> uncvref_t<T> auto get() const -> uncvref_t<T>
{ {
using type = uncvref_t<T>; using type = uncvref_t<T>;
static_assert(std::is_default_constructible<type>::value && static_assert(std::is_default_constructible<type>::value&&
std::is_copy_constructible<type>::value, std::is_copy_constructible<type>::value,
"user-defined types must be DefaultConstructible and " "user-defined types must be DefaultConstructible and "
"CopyConstructible when used with get"); "CopyConstructible when used with get");
@ -3336,7 +3347,7 @@ class basic_json
uncvref_t<T>, basic_json_t>>, uncvref_t<T>, basic_json_t>>,
detail::has_non_default_from_json<JSONSerializer, basic_json_t, detail::has_non_default_from_json<JSONSerializer, basic_json_t,
uncvref_t<T>>>::value, uncvref_t<T>>>::value,
short> = 0> short> = 0 >
T get() const T get() const
{ {
return JSONSerializer<T>::from_json(*this); return JSONSerializer<T>::from_json(*this);
@ -12685,25 +12696,25 @@ using json = basic_json<>;
// specialization of std::swap, and std::hash // specialization of std::swap, and std::hash
namespace std namespace std
{ {
/*! /*!
@brief exchanges the values of two JSON objects @brief exchanges the values of two JSON objects
@since version 1.0.0 @since version 1.0.0
*/ */
template<> template<>
inline void swap(nlohmann::json& j1, inline void swap(nlohmann::json& j1,
nlohmann::json& j2) noexcept( nlohmann::json& j2) noexcept(
is_nothrow_move_constructible<nlohmann::json>::value and is_nothrow_move_constructible<nlohmann::json>::value and
is_nothrow_move_assignable<nlohmann::json>::value is_nothrow_move_assignable<nlohmann::json>::value
) )
{ {
j1.swap(j2); j1.swap(j2);
} }
/// hash value for JSON objects /// hash value for JSON objects
template<> template<>
struct hash<nlohmann::json> struct hash<nlohmann::json>
{ {
/*! /*!
@brief return a hash value for a JSON object @brief return a hash value for a JSON object
@ -12715,7 +12726,7 @@ struct hash<nlohmann::json>
const auto& h = hash<nlohmann::json::string_t>(); const auto& h = hash<nlohmann::json::string_t>();
return h(j.dump()); return h(j.dump());
} }
}; };
} // namespace std } // namespace std
/*! /*!

View file

@ -106,38 +106,356 @@ SOFTWARE.
*/ */
namespace nlohmann namespace nlohmann
{ {
// alias templates to reduce boilerplate
template <bool B, typename T = void>
using enable_if_t = typename std::enable_if<B, T>::type;
template <typename T>
using remove_cv_t = typename std::remove_cv<T>::type;
template <typename T>
using remove_reference_t = typename std::remove_reference<T>::type;
template <typename T>
using uncvref_t = remove_cv_t<remove_reference_t<T>>;
template <bool If, typename Then, typename Else>
using conditional_t = typename std::conditional<If, Then, Else>::type;
// Taken from http://stackoverflow.com/questions/26936640/how-to-implement-is-enum-class-type-trait
template <typename T>
using is_scoped_enum =
std::integral_constant<bool, not std::is_convertible<T, int>::value and
std::is_enum<T>::value>;
template <typename T>
using is_unscoped_enum =
std::integral_constant<bool, std::is_convertible<T, int>::value and
std::is_enum<T>::value>;
// TODO update this doc
/*! /*!
@brief unnamed namespace with internal helper functions @brief unnamed namespace with internal helper functions
@since version 1.0.0 @since version 1.0.0
*/ */
namespace
namespace detail
{ {
// Very useful construct against boilerplate (more boilerplate needed than in C++17: http://en.cppreference.com/w/cpp/types/void_t)
template <typename...> struct make_void
{
using type = void;
};
template <typename... Ts> using void_t = typename make_void<Ts...>::type;
// Implementation of 3 C++17 constructs: conjunction, disjunction, negation.
// This is needed to avoid evaluating all the traits in a condition
//
// For example: not std::is_same<void, T>::value and has_value_type<T>::value
// will not compile when T = void (on MSVC at least)
// Whereas conjunction<negation<std::is_same<void, T>>, has_value_type<T>>::value
// will stop evaluating if negation<...>::value == false
//
// Please note that those constructs must be used with caution, since symbols can
// become very long quickly (which can slow down compilation and cause MSVC internal compiler errors)
// Only use it when you have too (see example ahead)
template <class...> struct conjunction : std::true_type {};
template <class B1> struct conjunction<B1> : B1 {};
template <class B1, class... Bn>
struct conjunction<B1, Bn...>
: conditional_t<bool(B1::value), conjunction<Bn...>, B1> {};
template <class B> struct negation : std::integral_constant < bool, !B::value > {};
template <class...> struct disjunction : std::false_type {};
template <class B1> struct disjunction<B1> : B1 {};
template <class B1, class... Bn>
struct disjunction<B1, Bn...>
: conditional_t<bool(B1::value), B1, disjunction<Bn...>> {};
/*! /*!
@brief Helper to determine whether there's a key_type for T. @brief Helper to determine whether there's a key_type for T.
Thus helper is used to tell associative containers apart from other containers Thus helper is used to tell associative containers apart from other containers
such as sequence containers. For instance, `std::map` passes the test as it such as sequence containers. For instance, `std::map` passes the test as it
contains a `mapped_type`, whereas `std::vector` fails the test. contains a `mapped_type`, whereas `std::vector` fails the test.
@sa http://stackoverflow.com/a/7728728/266378 @sa http://stackoverflow.com/a/7728728/266378
@since version 1.0.0, overworked in version 2.0.6 @since version 1.0.0, overworked in version 2.0.6
*/ */
template<typename T> #define NLOHMANN_JSON_HAS_HELPER(type) \
struct has_mapped_type template <typename T> struct has_##type { \
private: \
template <typename U, typename = typename U::type> \
static int detect(U &&); \
\
static void detect(...); \
\
public: \
static constexpr bool value = \
std::is_integral<decltype(detect(std::declval<T>()))>::value; \
};
NLOHMANN_JSON_HAS_HELPER(mapped_type)
NLOHMANN_JSON_HAS_HELPER(key_type)
NLOHMANN_JSON_HAS_HELPER(value_type)
NLOHMANN_JSON_HAS_HELPER(iterator)
#undef NLOHMANN_JSON_HAS_HELPER
template <bool B, class RealType, class CompatibleObjectType>
struct is_compatible_object_type_impl : std::false_type {};
template <class RealType, class CompatibleObjectType>
struct is_compatible_object_type_impl<true, RealType, CompatibleObjectType>
{
static constexpr auto value =
std::is_constructible<typename RealType::key_type,
typename CompatibleObjectType::key_type>::value and
std::is_constructible<typename RealType::mapped_type,
typename CompatibleObjectType::mapped_type>::value;
};
template<class RealType, class CompatibleObjectType>
struct is_compatible_object_type
{
// As noted ahead, we need to stop evaluating traits if CompatibleObjectType = void
// hence the conjunction
static auto constexpr value = is_compatible_object_type_impl <
conjunction<negation<std::is_same<void, CompatibleObjectType>>,
has_mapped_type<CompatibleObjectType>,
has_key_type<CompatibleObjectType>>::value,
RealType, CompatibleObjectType >::value;
};
template <bool B, class BasicJson, class CompatibleArrayType>
struct is_compatible_array_type_impl : std::false_type {};
template <class BasicJson, class CompatibleArrayType>
struct is_compatible_array_type_impl<true, BasicJson, CompatibleArrayType>
{
static constexpr auto value =
not std::is_same<CompatibleArrayType,
typename BasicJson::iterator>::value and
not std::is_same<CompatibleArrayType,
typename BasicJson::const_iterator>::value and
not std::is_same<CompatibleArrayType,
typename BasicJson::reverse_iterator>::value and
not std::is_same<CompatibleArrayType,
typename BasicJson::const_reverse_iterator>::value and
not std::is_same<CompatibleArrayType,
typename BasicJson::array_t::iterator>::value and
not std::is_same<CompatibleArrayType,
typename BasicJson::array_t::const_iterator>::value;
};
template <class BasicJson, class CompatibleArrayType>
struct is_compatible_array_type
{
// the check for CompatibleArrayType = void is done in is_compatible_object_type
// but we need the conjunction here as well
static auto constexpr value = is_compatible_array_type_impl <
conjunction<negation<is_compatible_object_type<
typename BasicJson::object_t, CompatibleArrayType>>,
has_value_type<CompatibleArrayType>,
has_iterator<CompatibleArrayType>>::value,
BasicJson, CompatibleArrayType >::value;
};
template <bool, typename, typename>
struct is_compatible_integer_type_impl : std::false_type {};
template <typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIntegerType>
{
using RealLimits = std::numeric_limits<RealIntegerType>;
using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
static constexpr auto value =
std::is_constructible<RealIntegerType,
CompatibleNumberIntegerType>::value and
CompatibleLimits::is_integer and
RealLimits::is_signed == CompatibleLimits::is_signed;
};
template <typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type
{
static constexpr auto value = is_compatible_integer_type_impl <
std::is_arithmetic<CompatibleNumberIntegerType>::value, RealIntegerType,
CompatibleNumberIntegerType >::value;
};
template <typename RealFloat, typename CompatibleFloat>
struct is_compatible_float_type
{
static constexpr auto value =
std::is_constructible<RealFloat, CompatibleFloat>::value and
std::is_floating_point<CompatibleFloat>::value;
};
template <typename T, typename BasicJson>
struct is_compatible_basic_json_type
{
static auto constexpr value =
is_unscoped_enum<T>::value or
std::is_same<T, BasicJson>::value or
std::is_constructible<typename BasicJson::string_t, T>::value or
std::is_same<typename BasicJson::boolean_t, T>::value or
is_compatible_array_type<BasicJson, T>::value or
is_compatible_object_type<typename BasicJson::object_t, T>::value or
is_compatible_float_type<typename BasicJson::number_float_t, T>::value or
is_compatible_integer_type<typename BasicJson::number_integer_t,
T>::value or
is_compatible_integer_type<typename BasicJson::number_unsigned_t,
T>::value;
};
template <typename T, typename BasicJson, typename PrimitiveIterator>
struct is_basic_json_nested_class
{
static auto constexpr value = std::is_same<T, typename BasicJson::iterator>::value or
std::is_same<T, typename BasicJson::const_iterator>::value or
std::is_same<T, typename BasicJson::reverse_iterator>::value or
std::is_same<T, typename BasicJson::const_reverse_iterator>::value or
std::is_same<T, PrimitiveIterator>::value or
std::is_same<T, typename BasicJson::json_pointer>::value;
};
// This trait checks if JSONSerializer<T>::from_json(json const&, udt&) exists
template <template <typename, typename> class JSONSerializer, typename Json,
typename T>
struct has_from_json
{ {
private: private:
template <typename U, typename = typename U::mapped_type> // also check the return type of from_json
template <typename U, typename = enable_if_t<std::is_same<void, decltype(uncvref_t<U>::from_json(
std::declval<Json>(), std::declval<T&>()))>::value>>
static int detect(U&&); static int detect(U&&);
static void detect(...); static void detect(...);
public: public:
static constexpr bool value = static constexpr bool value = std::is_integral<decltype(
std::is_integral<decltype(detect(std::declval<T>()))>::value; detect(std::declval<JSONSerializer<T, void>>()))>::value;
}; };
} // namespace // This trait checks if JSONSerializer<T>::from_json(json const&) exists
// this overload is used for non-default-constructible user-defined-types
template <template <typename, typename> class JSONSerializer, typename Json,
typename T>
struct has_non_default_from_json
{
private:
template <typename U, typename = enable_if_t<std::is_same<T, decltype(uncvref_t<U>::from_json(std::declval<Json>()))>::value>>
static int detect(U&&);
static void detect(...);
public:
static constexpr bool value = std::is_integral<decltype(
detect(std::declval<JSONSerializer<T, void>>()))>::value;
};
// This trait checks if JSONSerializer<T>::to_json exists
template <template <typename, typename> class JSONSerializer, typename Json,
typename T>
struct has_to_json
{
private:
template <typename U, typename = decltype(uncvref_t<U>::to_json(
std::declval<Json&>(), std::declval<T>()))>
static int detect(U&&);
static void detect(...);
public:
static constexpr bool value = std::is_integral<decltype(
detect(std::declval<JSONSerializer<T, void>>()))>::value;
};
// those declarations are needed to workaround a MSVC bug related to ADL
// (taken from MSVC-Ranges implementation)
void to_json();
void from_json();
struct to_json_fn
{
// is it really useful to mark those as constexpr?
template <typename Json, typename T>
constexpr auto operator()(Json&& j, T&& val) const
noexcept(noexcept(to_json(std::forward<Json>(j), std::forward<T>(val))))
-> decltype(to_json(std::forward<Json>(j), std::forward<T>(val)),
void())
{
return to_json(std::forward<Json>(j), std::forward<T>(val));
}
};
struct from_json_fn
{
template <typename Json, typename T>
constexpr auto operator()(Json&& j, T& val) const
noexcept(noexcept(from_json(std::forward<Json>(j), val)))
-> decltype(from_json(std::forward<Json>(j), val), void())
{
return from_json(std::forward<Json>(j), val);
}
};
/*!
@brief helper class to create locales with decimal point
This struct is used a default locale during the JSON serialization. JSON
requires the decimal point to be `.`, so this function overloads the
`do_decimal_point()` function to return `.`. This function is called by
float-to-string conversions to retrieve the decimal separator between integer
and fractional parts.
@sa https://github.com/nlohmann/json/issues/51#issuecomment-86869315
@since version 2.0.0
*/
struct DecimalSeparator : std::numpunct<char>
{
char do_decimal_point() const
{
return '.';
}
};
}
// taken from ranges-v3
// TODO add doc
template <typename T>
struct static_const
{
static constexpr T value{};
};
template <typename T>
constexpr T static_const<T>::value;
inline namespace
{
constexpr auto const& to_json = static_const<detail::to_json_fn>::value;
constexpr auto const& from_json = static_const<detail::from_json_fn>::value;
}
// default JSONSerializer template argument, doesn't care about template argument
// will use ADL for serialization
template <typename = void, typename = void>
struct adl_serializer
{
template <typename Json, typename T>
static void from_json(Json&& j, T& val)
{
::nlohmann::from_json(std::forward<Json>(j), val);
}
template <typename Json, typename T>
static void to_json(Json& j, T&& val)
{
::nlohmann::to_json(j, std::forward<T>(val));
}
};
/*! /*!
@brief a class to store JSON values @brief a class to store JSON values
@ -226,7 +544,8 @@ template <
class NumberIntegerType = std::int64_t, class NumberIntegerType = std::int64_t,
class NumberUnsignedType = std::uint64_t, class NumberUnsignedType = std::uint64_t,
class NumberFloatType = double, class NumberFloatType = double,
template<typename U> class AllocatorType = std::allocator template<typename U> class AllocatorType = std::allocator,
template<typename T, typename SFINAE = void> class JSONSerializer = adl_serializer
> >
class basic_json class basic_json
{ {
@ -234,7 +553,8 @@ class basic_json
/// workaround type for MSVC /// workaround type for MSVC
using basic_json_t = basic_json<ObjectType, ArrayType, StringType, using basic_json_t = basic_json<ObjectType, ArrayType, StringType,
BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType,
AllocatorType>; AllocatorType, JSONSerializer>;
class primitive_iterator_t;
public: public:
// forward declarations // forward declarations
@ -1215,11 +1535,11 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
template<class CompatibleObjectType, typename std::enable_if< template <class CompatibleObjectType,
std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and enable_if_t<detail::is_compatible_object_type<
std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type = 0> object_t, CompatibleObjectType>::value,
basic_json(const CompatibleObjectType& val) int> = 0>
: m_type(value_t::object) basic_json(const CompatibleObjectType& val) : m_type(value_t::object)
{ {
using std::begin; using std::begin;
using std::end; using std::end;
@ -1278,16 +1598,11 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
template<class CompatibleArrayType, typename std::enable_if< template <class CompatibleArrayType,
not std::is_same<CompatibleArrayType, typename basic_json_t::iterator>::value and enable_if_t<detail::is_compatible_array_type<
not std::is_same<CompatibleArrayType, typename basic_json_t::const_iterator>::value and basic_json_t, CompatibleArrayType>::value,
not std::is_same<CompatibleArrayType, typename basic_json_t::reverse_iterator>::value and int> = 0>
not std::is_same<CompatibleArrayType, typename basic_json_t::const_reverse_iterator>::value and basic_json(const CompatibleArrayType& val) : m_type(value_t::array)
not std::is_same<CompatibleArrayType, typename array_t::iterator>::value and
not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and
std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value, int>::type = 0>
basic_json(const CompatibleArrayType& val)
: m_type(value_t::array)
{ {
using std::begin; using std::begin;
using std::end; using std::end;
@ -1295,6 +1610,28 @@ class basic_json
assert_invariant(); assert_invariant();
} }
// constructor chosen when:
// - JSONSerializer::to_json exists for type T
// - T is not a istream, nor convertible to basic_json (float, vectors, etc)
// is_compatible_basic_json_type == not is_user_defined_type
template <
typename T,
enable_if_t<not std::is_base_of<std::istream, uncvref_t<T>>::value and
not detail::is_basic_json_nested_class<uncvref_t<T>, basic_json_t, primitive_iterator_t>::value and
not std::is_same<uncvref_t<T>, typename basic_json_t::array_t::iterator>::value and
not std::is_same<uncvref_t<T>, typename basic_json_t::object_t::iterator>::value and
detail::conjunction<detail::negation<detail::is_compatible_basic_json_type<
uncvref_t<T>, basic_json_t>>,
detail::has_to_json<JSONSerializer, basic_json,
uncvref_t<T>>>::value,
int> = 0 >
basic_json(T && val)
{
JSONSerializer<uncvref_t<T>>::to_json(*this, std::forward<T>(val));
}
/*! /*!
@brief create a string (explicit) @brief create a string (explicit)
@ -1456,7 +1793,10 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
basic_json(const int val) noexcept
// Constructor for unscoped enums (not enum classes)
template <typename T, enable_if_t<is_unscoped_enum<T>::value, int> = 0>
basic_json(T val) noexcept
: m_type(value_t::number_integer), : m_type(value_t::number_integer),
m_value(static_cast<number_integer_t>(val)) m_value(static_cast<number_integer_t>(val))
{ {
@ -1488,11 +1828,11 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
template<typename CompatibleNumberIntegerType, typename std::enable_if< template <
std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and typename CompatibleNumberIntegerType,
std::numeric_limits<CompatibleNumberIntegerType>::is_integer and enable_if_t<detail::is_compatible_integer_type<
std::numeric_limits<CompatibleNumberIntegerType>::is_signed, number_integer_t, CompatibleNumberIntegerType>::value,
CompatibleNumberIntegerType>::type = 0> int> = 0 >
basic_json(const CompatibleNumberIntegerType val) noexcept basic_json(const CompatibleNumberIntegerType val) noexcept
: m_type(value_t::number_integer), : m_type(value_t::number_integer),
m_value(static_cast<number_integer_t>(val)) m_value(static_cast<number_integer_t>(val))
@ -1546,11 +1886,11 @@ class basic_json
@since version 2.0.0 @since version 2.0.0
*/ */
template<typename CompatibleNumberUnsignedType, typename std::enable_if < template <
std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and typename CompatibleNumberUnsignedType,
std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and enable_if_t<detail::is_compatible_integer_type<
not std::numeric_limits<CompatibleNumberUnsignedType>::is_signed, number_unsigned_t, CompatibleNumberUnsignedType>::value,
CompatibleNumberUnsignedType>::type = 0> int> = 0 >
basic_json(const CompatibleNumberUnsignedType val) noexcept basic_json(const CompatibleNumberUnsignedType val) noexcept
: m_type(value_t::number_unsigned), : m_type(value_t::number_unsigned),
m_value(static_cast<number_unsigned_t>(val)) m_value(static_cast<number_unsigned_t>(val))
@ -1626,9 +1966,10 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
template<typename CompatibleNumberFloatType, typename = typename std::enable_if< template <typename CompatibleNumberFloatType,
std::is_constructible<number_float_t, CompatibleNumberFloatType>::value and enable_if_t<detail::is_compatible_float_type<
std::is_floating_point<CompatibleNumberFloatType>::value>::type> number_float_t, CompatibleNumberFloatType>::value,
int> = 0>
basic_json(const CompatibleNumberFloatType val) noexcept basic_json(const CompatibleNumberFloatType val) noexcept
: basic_json(number_float_t(val)) : basic_json(number_float_t(val))
{ {
@ -2182,6 +2523,18 @@ class basic_json
return *this; return *this;
} }
// this overload is needed, since constructor for udt is explicit
template <typename T, enable_if_t<not detail::is_compatible_basic_json_type<
uncvref_t<T>, basic_json_t>::value and
detail::has_to_json<JSONSerializer, basic_json_t, uncvref_t<T>>::value>>
reference& operator=(T&& val) noexcept(std::is_nothrow_constructible<basic_json_t, uncvref_t<T>>::value and
std::is_nothrow_move_assignable<uncvref_t<T>>::value)
{
static_assert(sizeof(T) == 0 , "");
// I'm not sure this a is good practice...
return *this = basic_json_t{std::forward<T>(val)};
}
/*! /*!
@brief destructor @brief destructor
@ -2655,7 +3008,6 @@ class basic_json
// value access // // value access //
////////////////// //////////////////
/// get an object (explicit)
template<class T, typename std::enable_if< template<class T, typename std::enable_if<
std::is_convertible<typename object_t::key_type, typename T::key_type>::value and std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
std::is_convertible<basic_json_t, typename T::mapped_type>::value, int>::type = 0> std::is_convertible<basic_json_t, typename T::mapped_type>::value, int>::type = 0>
@ -2681,13 +3033,16 @@ class basic_json
} }
/// get an array (explicit) /// get an array (explicit)
template<class T, typename std::enable_if< template <
class T,
typename std::enable_if <
std::is_convertible<basic_json_t, typename T::value_type>::value and std::is_convertible<basic_json_t, typename T::value_type>::value and
not std::is_same<basic_json_t, typename T::value_type>::value and not std::is_same<basic_json_t,
typename T::value_type>::value and
not std::is_arithmetic<T>::value and not std::is_arithmetic<T>::value and
not std::is_convertible<std::string, T>::value and not std::is_convertible<std::string, T>::value and
not has_mapped_type<T>::value, int>::type = 0> not detail::has_mapped_type<T>::value,
T get_impl(T* /*unused*/) const int >::type = 0 >
{ {
if (is_array()) if (is_array())
{ {
@ -2727,7 +3082,7 @@ class basic_json
/// get an array (explicit) /// get an array (explicit)
template<class T, typename std::enable_if< template<class T, typename std::enable_if<
std::is_same<basic_json, typename T::value_type>::value and std::is_same<basic_json, typename T::value_type>::value and
not has_mapped_type<T>::value, int>::type = 0> not detail::has_mapped_type<T>::value, int>::type = 0>
T get_impl(T* /*unused*/) const T get_impl(T* /*unused*/) const
{ {
if (is_array()) if (is_array())
@ -2956,13 +3311,46 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
template<typename ValueType, typename std::enable_if< template <typename ValueType,
not std::is_pointer<ValueType>::value, int>::type = 0> enable_if_t<not std::is_pointer<ValueType>::value, int> = 0>
ValueType get() const auto get() const
-> decltype(this->get_impl(static_cast<ValueType*>(nullptr)))
{ {
return get_impl(static_cast<ValueType*>(nullptr)); return get_impl(static_cast<ValueType*>(nullptr));
} }
template <
typename T,
enable_if_t<detail::conjunction<detail::negation<detail::is_compatible_basic_json_type<
uncvref_t<T>, basic_json_t>>,
detail::has_from_json<JSONSerializer, basic_json_t,
uncvref_t<T>>>::value,
int> = 0 >
auto get() const -> uncvref_t<T>
{
using type = uncvref_t<T>;
static_assert(std::is_default_constructible<type>::value&&
std::is_copy_constructible<type>::value,
"user-defined types must be DefaultConstructible and "
"CopyConstructible when used with get");
type ret;
JSONSerializer<type>::from_json(*this, ret);
return ret;
}
// This overload is chosen for non-default constructible user-defined-types
template <
typename T,
enable_if_t<detail::conjunction<detail::negation<detail::is_compatible_basic_json_type<
uncvref_t<T>, basic_json_t>>,
detail::has_non_default_from_json<JSONSerializer, basic_json_t,
uncvref_t<T>>>::value,
short> = 0 >
T get() const
{
return JSONSerializer<T>::from_json(*this);
}
/*! /*!
@brief get a pointer value (explicit) @brief get a pointer value (explicit)
@ -8155,6 +8543,11 @@ class basic_json
class primitive_iterator_t class primitive_iterator_t
{ {
public: public:
difference_type get_value() const noexcept
{
return m_it;
}
/// set iterator to a defined beginning /// set iterator to a defined beginning
void set_begin() noexcept void set_begin() noexcept
{ {
@ -8179,16 +8572,87 @@ class basic_json
return (m_it == end_value); return (m_it == end_value);
} }
/// return reference to the value to change and compare friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
operator difference_type& () noexcept
{ {
return m_it; return lhs.m_it == rhs.m_it;
} }
/// return value to compare friend constexpr bool operator!=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
constexpr operator difference_type () const noexcept
{ {
return m_it; return !(lhs == rhs);
}
friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
{
return lhs.m_it < rhs.m_it;
}
friend constexpr bool operator<=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
{
return lhs.m_it <= rhs.m_it;
}
friend constexpr bool operator>(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
{
return lhs.m_it > rhs.m_it;
}
friend constexpr bool operator>=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
{
return lhs.m_it >= rhs.m_it;
}
primitive_iterator_t operator+(difference_type i)
{
auto result = *this;
result += i;
return result;
}
friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
{
return lhs.m_it - rhs.m_it;
}
friend std::ostream& operator<<(std::ostream& os, primitive_iterator_t it)
{
return os << it.m_it;
}
primitive_iterator_t& operator++()
{
++m_it;
return *this;
}
primitive_iterator_t& operator++(int)
{
m_it++;
return *this;
}
primitive_iterator_t& operator--()
{
--m_it;
return *this;
}
primitive_iterator_t& operator--(int)
{
m_it--;
return *this;
}
primitive_iterator_t& operator+=(difference_type n)
{
m_it += n;
return *this;
}
primitive_iterator_t& operator-=(difference_type n)
{
m_it -= n;
return *this;
} }
private: private:
@ -8893,7 +9357,7 @@ class basic_json
default: default:
{ {
if (m_it.primitive_iterator == -n) if (m_it.primitive_iterator.get_value() == -n)
{ {
return *m_object; return *m_object;
} }
@ -11380,25 +11844,25 @@ using json = basic_json<>;
// specialization of std::swap, and std::hash // specialization of std::swap, and std::hash
namespace std namespace std
{ {
/*! /*!
@brief exchanges the values of two JSON objects @brief exchanges the values of two JSON objects
@since version 1.0.0 @since version 1.0.0
*/ */
template<> template<>
inline void swap(nlohmann::json& j1, inline void swap(nlohmann::json& j1,
nlohmann::json& j2) noexcept( nlohmann::json& j2) noexcept(
is_nothrow_move_constructible<nlohmann::json>::value and is_nothrow_move_constructible<nlohmann::json>::value and
is_nothrow_move_assignable<nlohmann::json>::value is_nothrow_move_assignable<nlohmann::json>::value
) )
{ {
j1.swap(j2); j1.swap(j2);
} }
/// hash value for JSON objects /// hash value for JSON objects
template<> template<>
struct hash<nlohmann::json> struct hash<nlohmann::json>
{ {
/*! /*!
@brief return a hash value for a JSON object @brief return a hash value for a JSON object
@ -11410,7 +11874,7 @@ struct hash<nlohmann::json>
const auto& h = hash<nlohmann::json::string_t>(); const auto& h = hash<nlohmann::json::string_t>();
return h(j.dump()); return h(j.dump());
} }
}; };
} // namespace std } // namespace std
/*! /*!

View file

@ -38,67 +38,67 @@ using nlohmann::json;
namespace udt namespace udt
{ {
enum class country enum class country
{ {
china, china,
france, france,
russia russia
}; };
struct age struct age
{ {
int m_val; int m_val;
}; };
struct name struct name
{ {
std::string m_val; std::string m_val;
}; };
struct address struct address
{ {
std::string m_val; std::string m_val;
}; };
struct person struct person
{ {
age m_age; age m_age;
name m_name; name m_name;
country m_country; country m_country;
}; };
struct contact struct contact
{ {
person m_person; person m_person;
address m_address; address m_address;
}; };
struct contact_book struct contact_book
{ {
name m_book_name; name m_book_name;
std::vector<contact> m_contacts; std::vector<contact> m_contacts;
}; };
} }
// to_json methods // to_json methods
namespace udt namespace udt
{ {
// templates because of the custom_json tests (see below) // templates because of the custom_json tests (see below)
template <typename Json> template <typename Json>
void to_json(Json& j, age a) void to_json(Json& j, age a)
{ {
j = a.m_val; j = a.m_val;
} }
template <typename Json> template <typename Json>
void to_json(Json& j, name const& n) void to_json(Json& j, name const& n)
{ {
j = n.m_val; j = n.m_val;
} }
template <typename Json> template <typename Json>
void to_json(Json& j, country c) void to_json(Json& j, country c)
{ {
switch (c) switch (c)
{ {
case country::china: case country::china:
@ -111,123 +111,128 @@ namespace udt
j = u8"Российская Федерация"; j = u8"Российская Федерация";
return; return;
} }
} }
template <typename Json> template <typename Json>
void to_json(Json& j, person const& p) void to_json(Json& j, person const& p)
{ {
j = Json{{"age", p.m_age}, {"name", p.m_name}, {"country", p.m_country}}; j = Json{{"age", p.m_age}, {"name", p.m_name}, {"country", p.m_country}};
} }
void to_json(nlohmann::json& j, address const& a) void to_json(nlohmann::json& j, address const& a)
{ {
j = a.m_val; j = a.m_val;
} }
void to_json(nlohmann::json& j, contact const& c) void to_json(nlohmann::json& j, contact const& c)
{ {
j = json{{"person", c.m_person}, {"address", c.m_address}}; j = json{{"person", c.m_person}, {"address", c.m_address}};
} }
void to_json(nlohmann::json& j, contact_book const& cb) void to_json(nlohmann::json& j, contact_book const& cb)
{ {
j = json{{"name", cb.m_book_name}, {"contacts", cb.m_contacts}}; j = json{{"name", cb.m_book_name}, {"contacts", cb.m_contacts}};
} }
// operators // operators
bool operator==(age lhs, age rhs) bool operator==(age lhs, age rhs)
{ {
return lhs.m_val == rhs.m_val; return lhs.m_val == rhs.m_val;
} }
bool operator==(address const &lhs, address const &rhs) bool operator==(address const& lhs, address const& rhs)
{ {
return lhs.m_val == rhs.m_val; return lhs.m_val == rhs.m_val;
} }
bool operator==(name const &lhs, name const &rhs) bool operator==(name const& lhs, name const& rhs)
{ {
return lhs.m_val == rhs.m_val; return lhs.m_val == rhs.m_val;
} }
bool operator==(person const &lhs, person const &rhs) bool operator==(person const& lhs, person const& rhs)
{ {
return std::tie(lhs.m_name, lhs.m_age) == std::tie(rhs.m_name, rhs.m_age); return std::tie(lhs.m_name, lhs.m_age) == std::tie(rhs.m_name, rhs.m_age);
} }
bool operator==(contact const &lhs, contact const &rhs) bool operator==(contact const& lhs, contact const& rhs)
{ {
return std::tie(lhs.m_person, lhs.m_address) == return std::tie(lhs.m_person, lhs.m_address) ==
std::tie(rhs.m_person, rhs.m_address); std::tie(rhs.m_person, rhs.m_address);
} }
bool operator==(contact_book const &lhs, contact_book const &rhs) bool operator==(contact_book const& lhs, contact_book const& rhs)
{ {
return std::tie(lhs.m_book_name, lhs.m_contacts) == return std::tie(lhs.m_book_name, lhs.m_contacts) ==
std::tie(rhs.m_book_name, rhs.m_contacts); std::tie(rhs.m_book_name, rhs.m_contacts);
} }
} }
// from_json methods // from_json methods
namespace udt namespace udt
{ {
template <typename Json> template <typename Json>
void from_json(Json const& j, age &a) void from_json(Json const& j, age& a)
{ {
a.m_val = j.template get<int>(); a.m_val = j.template get<int>();
} }
template <typename Json> template <typename Json>
void from_json(Json const& j, name &n) void from_json(Json const& j, name& n)
{ {
n.m_val = j.template get<std::string>(); n.m_val = j.template get<std::string>();
} }
template <typename Json> template <typename Json>
void from_json(Json const &j, country &c) void from_json(Json const& j, country& c)
{ {
const auto str = j.template get<std::string>(); const auto str = j.template get<std::string>();
static const std::map<std::string, country> m = { static const std::map<std::string, country> m =
{
{u8"中华人民共和国", country::china}, {u8"中华人民共和国", country::china},
{"France", country::france}, {"France", country::france},
{"Российская Федерация", country::russia}}; {"Российская Федерация", country::russia}
};
const auto it = m.find(str); const auto it = m.find(str);
// TODO test exceptions // TODO test exceptions
c = it->second; c = it->second;
} }
template <typename Json> template <typename Json>
void from_json(Json const& j, person &p) void from_json(Json const& j, person& p)
{ {
p.m_age = j["age"].template get<age>(); p.m_age = j["age"].template get<age>();
p.m_name = j["name"].template get<name>(); p.m_name = j["name"].template get<name>();
p.m_country = j["country"].template get<country>(); p.m_country = j["country"].template get<country>();
} }
void from_json(nlohmann::json const &j, address &a) void from_json(nlohmann::json const& j, address& a)
{ {
a.m_val = j.get<std::string>(); a.m_val = j.get<std::string>();
} }
void from_json(nlohmann::json const& j, contact &c) void from_json(nlohmann::json const& j, contact& c)
{ {
c.m_person = j["person"].get<person>(); c.m_person = j["person"].get<person>();
c.m_address = j["address"].get<address>(); c.m_address = j["address"].get<address>();
} }
void from_json(nlohmann::json const&j, contact_book &cb) void from_json(nlohmann::json const& j, contact_book& cb)
{ {
cb.m_book_name = j["name"].get<name>(); cb.m_book_name = j["name"].get<name>();
cb.m_contacts = j["contacts"].get<std::vector<contact>>(); cb.m_contacts = j["contacts"].get<std::vector<contact>>();
} }
} }
TEST_CASE("basic usage", "[udt]") TEST_CASE("basic usage", "[udt]")
{ {
// a bit narcissic maybe :) ? // a bit narcissic maybe :) ?
const udt::age a{23}; const udt::age a
{
23
};
const udt::name n{"theo"}; const udt::name n{"theo"};
const udt::country c{udt::country::france}; const udt::country c{udt::country::france};
const udt::person sfinae_addict{a, n, c}; const udt::person sfinae_addict{a, n, c};
@ -295,18 +300,26 @@ struct adl_serializer<std::shared_ptr<T>>
static void to_json(json& j, std::shared_ptr<T> const& opt) static void to_json(json& j, std::shared_ptr<T> const& opt)
{ {
if (opt) if (opt)
{
j = *opt; j = *opt;
}
else else
{
j = nullptr; j = nullptr;
} }
}
static void from_json(json const &j, std::shared_ptr<T> &opt) static void from_json(json const& j, std::shared_ptr<T>& opt)
{ {
if (j.is_null()) if (j.is_null())
{
opt = nullptr; opt = nullptr;
}
else else
{
opt.reset(new T(j.get<T>())); opt.reset(new T(j.get<T>()));
} }
}
}; };
template <> template <>
@ -387,7 +400,7 @@ struct adl_serializer<std::vector<T>>
{ {
} }
static void from_json(json const &j, std::vector<T> &opt) static void from_json(json const& j, std::vector<T>& opt)
{ {
} }
}; };
@ -396,9 +409,9 @@ struct adl_serializer<std::vector<T>>
TEST_CASE("current supported types are preferred over specializations", "[udt]") TEST_CASE("current supported types are preferred over specializations", "[udt]")
{ {
json j = std::vector<int>{1, 2, 3}; json j = std::vector<int> {1, 2, 3};
auto f = j.get<std::vector<int>>(); auto f = j.get<std::vector<int>>();
CHECK((f == std::vector<int>{1, 2, 3})); CHECK((f == std::vector<int> {1, 2, 3}));
} }
namespace nlohmann namespace nlohmann
@ -409,20 +422,28 @@ struct adl_serializer<std::unique_ptr<T>>
static void to_json(json& j, std::unique_ptr<T> const& opt) static void to_json(json& j, std::unique_ptr<T> const& opt)
{ {
if (opt) if (opt)
{
j = *opt; j = *opt;
}
else else
{
j = nullptr; j = nullptr;
} }
}
// this is the overload needed for non-copyable types, // this is the overload needed for non-copyable types,
// should we add a priority tag in the implementation to prefer this overload if it exists? // should we add a priority tag in the implementation to prefer this overload if it exists?
static std::unique_ptr<T> from_json(json const &j) static std::unique_ptr<T> from_json(json const& j)
{ {
if (j.is_null()) if (j.is_null())
{
return nullptr; return nullptr;
}
else else
{
return std::unique_ptr<T>(new T(j.get<T>())); return std::unique_ptr<T>(new T(j.get<T>()));
} }
}
}; };
} }
@ -477,7 +498,9 @@ struct pod_serializer
auto bytes = static_cast<char const*>(static_cast<void const*>(&t)); auto bytes = static_cast<char const*>(static_cast<void const*>(&t));
std::uint64_t value = bytes[0]; std::uint64_t value = bytes[0];
for (auto i = 1; i < 8; ++i) for (auto i = 1; i < 8; ++i)
{
value |= bytes[i] << 8 * i; value |= bytes[i] << 8 * i;
}
j = value; j = value;
} }
@ -514,7 +537,7 @@ TEST_CASE("custom serializer for pods", "[udt]")
template <typename T, typename> template <typename T, typename>
struct another_adl_serializer; struct another_adl_serializer;
using custom_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, double, std::allocator, another_adl_serializer>; using custom_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, double, std::allocator, another_adl_serializer>;
template <typename T, typename> template <typename T, typename>
struct another_adl_serializer struct another_adl_serializer