💄 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
{
// 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;
// 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, class... 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 B1> struct disjunction<B1> : B1 {};
template <class B1, class... 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.
@ -198,7 +201,7 @@ 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{};
struct is_compatible_object_type_impl : std::false_type {};
template <class RealType, class 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
// 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>>,
has_mapped_type<CompatibleObjectType>,
has_key_type<CompatibleObjectType>>::value,
RealType, CompatibleObjectType>::value;
RealType, CompatibleObjectType >::value;
};
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>
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
// 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<
typename BasicJson::object_t, CompatibleArrayType>>,
has_value_type<CompatibleArrayType>,
has_iterator<CompatibleArrayType>>::value,
BasicJson, CompatibleArrayType>::value;
BasicJson, CompatibleArrayType >::value;
};
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>
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>
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,
CompatibleNumberIntegerType>::value;
CompatibleNumberIntegerType >::value;
};
template <typename RealFloat, typename CompatibleFloat>
@ -321,15 +324,15 @@ template <template <typename, typename> class JSONSerializer, typename Json,
typename T>
struct has_from_json
{
private:
private:
// 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 &&);
std::declval<Json>(), std::declval<T&>()))>::value>>
static int detect(U&&);
static void detect(...);
public:
public:
static constexpr bool value = std::is_integral<decltype(
detect(std::declval<JSONSerializer<T, void>>()))>::value;
};
@ -340,13 +343,13 @@ template <template <typename, typename> class JSONSerializer, typename Json,
typename T>
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>>
static int detect(U &&);
static int detect(U&&);
static void detect(...);
public:
public:
static constexpr bool value = std::is_integral<decltype(
detect(std::declval<JSONSerializer<T, void>>()))>::value;
};
@ -356,14 +359,14 @@ template <template <typename, typename> class JSONSerializer, typename Json,
typename T>
struct has_to_json
{
private:
private:
template <typename U, typename = decltype(uncvref_t<U>::to_json(
std::declval<Json &>(), std::declval<T>()))>
static int detect(U &&);
std::declval<Json&>(), std::declval<T>()))>
static int detect(U&&);
static void detect(...);
public:
public:
static constexpr bool value = std::is_integral<decltype(
detect(std::declval<JSONSerializer<T, void>>()))>::value;
};
@ -377,7 +380,7 @@ 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
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())
@ -389,7 +392,7 @@ struct to_json_fn
struct from_json_fn
{
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)))
-> decltype(from_json(std::forward<Json>(j), val), void())
{
@ -431,8 +434,8 @@ 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;
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
@ -1535,7 +1538,7 @@ class basic_json
enable_if_t<detail::is_compatible_object_type<
object_t, CompatibleObjectType>::value,
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::end;
@ -1598,7 +1601,7 @@ class basic_json
enable_if_t<detail::is_compatible_array_type<
basic_json_t, CompatibleArrayType>::value,
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::end;
@ -1622,8 +1625,8 @@ class basic_json
uncvref_t<T>, basic_json_t>>,
detail::has_to_json<JSONSerializer, basic_json,
uncvref_t<T>>>::value,
int> = 0>
basic_json(T &&val)
int> = 0 >
basic_json(T && val)
{
JSONSerializer<uncvref_t<T>>::to_json(*this, std::forward<T>(val));
}
@ -1828,10 +1831,11 @@ class basic_json
typename CompatibleNumberIntegerType,
enable_if_t<detail::is_compatible_integer_type<
number_integer_t, CompatibleNumberIntegerType>::value,
int> = 0>
int> = 0 >
basic_json(const CompatibleNumberIntegerType val) noexcept
: m_type(value_t::number_integer),
m_value(static_cast<number_integer_t>(val)) {
m_value(static_cast<number_integer_t>(val))
{
assert_invariant();
}
@ -1885,10 +1889,11 @@ class basic_json
typename CompatibleNumberUnsignedType,
enable_if_t<detail::is_compatible_integer_type<
number_unsigned_t, CompatibleNumberUnsignedType>::value,
int> = 0>
int> = 0 >
basic_json(const CompatibleNumberUnsignedType val) noexcept
: m_type(value_t::number_unsigned),
m_value(static_cast<number_unsigned_t>(val)) {
m_value(static_cast<number_unsigned_t>(val))
{
assert_invariant();
}
@ -2521,7 +2526,7 @@ class basic_json
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
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 , "");
@ -2544,32 +2549,38 @@ class basic_json
@since version 1.0.0
*/
~basic_json() {
~basic_json()
{
assert_invariant();
switch (m_type) {
case value_t::object: {
switch (m_type)
{
case value_t::object:
{
AllocatorType<object_t> alloc;
alloc.destroy(m_value.object);
alloc.deallocate(m_value.object, 1);
break;
}
case value_t::array: {
case value_t::array:
{
AllocatorType<array_t> alloc;
alloc.destroy(m_value.array);
alloc.deallocate(m_value.array, 1);
break;
}
case value_t::string: {
case value_t::string:
{
AllocatorType<string_t> alloc;
alloc.destroy(m_value.string);
alloc.deallocate(m_value.string, 1);
break;
}
default: {
default:
{
// all other types need no specific destructor
break;
}
@ -3025,15 +3036,15 @@ class basic_json
/// get an array (explicit)
template <
class T,
typename std::enable_if<
typename std::enable_if <
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_arithmetic<T>::value and
not std::is_convertible<std::string, T>::value and
not detail::has_mapped_type<T>::value,
int>::type = 0>
T get_impl(T *) const
int >::type = 0 >
T get_impl(T*) const
{
if (is_array())
{
@ -3305,9 +3316,9 @@ class basic_json
template <typename ValueType,
enable_if_t<not std::is_pointer<ValueType>::value, int> = 0>
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 <
@ -3316,11 +3327,11 @@ class basic_json
uncvref_t<T>, basic_json_t>>,
detail::has_from_json<JSONSerializer, basic_json_t,
uncvref_t<T>>>::value,
int> = 0>
int> = 0 >
auto get() const -> 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,
"user-defined types must be DefaultConstructible and "
"CopyConstructible when used with get");
@ -3336,7 +3347,7 @@ class basic_json
uncvref_t<T>, basic_json_t>>,
detail::has_non_default_from_json<JSONSerializer, basic_json_t,
uncvref_t<T>>>::value,
short> = 0>
short> = 0 >
T get() const
{
return JSONSerializer<T>::from_json(*this);
@ -12685,25 +12696,25 @@ using json = basic_json<>;
// specialization of std::swap, and std::hash
namespace std
{
/*!
@brief exchanges the values of two JSON objects
/*!
@brief exchanges the values of two JSON objects
@since version 1.0.0
*/
template<>
inline void swap(nlohmann::json& j1,
@since version 1.0.0
*/
template<>
inline void swap(nlohmann::json& j1,
nlohmann::json& j2) noexcept(
is_nothrow_move_constructible<nlohmann::json>::value and
is_nothrow_move_assignable<nlohmann::json>::value
)
{
{
j1.swap(j2);
}
}
/// hash value for JSON objects
template<>
struct hash<nlohmann::json>
{
/// hash value for JSON objects
template<>
struct hash<nlohmann::json>
{
/*!
@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>();
return h(j.dump());
}
};
};
} // namespace std
/*!

View file

@ -106,38 +106,356 @@ SOFTWARE.
*/
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
@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.
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
contains a `mapped_type`, whereas `std::vector` fails the test.
@sa http://stackoverflow.com/a/7728728/266378
@since version 1.0.0, overworked in version 2.0.6
*/
template<typename T>
struct has_mapped_type
#define NLOHMANN_JSON_HAS_HELPER(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:
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 void detect(...);
public:
static constexpr bool value =
std::is_integral<decltype(detect(std::declval<T>()))>::value;
static constexpr bool value = std::is_integral<decltype(
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
@ -226,7 +544,8 @@ template <
class NumberIntegerType = std::int64_t,
class NumberUnsignedType = std::uint64_t,
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
{
@ -234,7 +553,8 @@ class basic_json
/// workaround type for MSVC
using basic_json_t = basic_json<ObjectType, ArrayType, StringType,
BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType,
AllocatorType>;
AllocatorType, JSONSerializer>;
class primitive_iterator_t;
public:
// forward declarations
@ -1215,11 +1535,11 @@ class basic_json
@since version 1.0.0
*/
template<class CompatibleObjectType, typename std::enable_if<
std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and
std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type = 0>
basic_json(const CompatibleObjectType& val)
: m_type(value_t::object)
template <class CompatibleObjectType,
enable_if_t<detail::is_compatible_object_type<
object_t, CompatibleObjectType>::value,
int> = 0>
basic_json(const CompatibleObjectType& val) : m_type(value_t::object)
{
using std::begin;
using std::end;
@ -1278,16 +1598,11 @@ class basic_json
@since version 1.0.0
*/
template<class CompatibleArrayType, typename std::enable_if<
not std::is_same<CompatibleArrayType, typename basic_json_t::iterator>::value and
not std::is_same<CompatibleArrayType, typename basic_json_t::const_iterator>::value and
not std::is_same<CompatibleArrayType, typename basic_json_t::reverse_iterator>::value and
not std::is_same<CompatibleArrayType, typename basic_json_t::const_reverse_iterator>::value and
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)
template <class CompatibleArrayType,
enable_if_t<detail::is_compatible_array_type<
basic_json_t, CompatibleArrayType>::value,
int> = 0>
basic_json(const CompatibleArrayType& val) : m_type(value_t::array)
{
using std::begin;
using std::end;
@ -1295,6 +1610,28 @@ class basic_json
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)
@ -1456,7 +1793,10 @@ class basic_json
@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_value(static_cast<number_integer_t>(val))
{
@ -1488,11 +1828,11 @@ class basic_json
@since version 1.0.0
*/
template<typename CompatibleNumberIntegerType, typename std::enable_if<
std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and
std::numeric_limits<CompatibleNumberIntegerType>::is_integer and
std::numeric_limits<CompatibleNumberIntegerType>::is_signed,
CompatibleNumberIntegerType>::type = 0>
template <
typename CompatibleNumberIntegerType,
enable_if_t<detail::is_compatible_integer_type<
number_integer_t, CompatibleNumberIntegerType>::value,
int> = 0 >
basic_json(const CompatibleNumberIntegerType val) noexcept
: m_type(value_t::number_integer),
m_value(static_cast<number_integer_t>(val))
@ -1546,11 +1886,11 @@ class basic_json
@since version 2.0.0
*/
template<typename CompatibleNumberUnsignedType, typename std::enable_if <
std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
not std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
CompatibleNumberUnsignedType>::type = 0>
template <
typename CompatibleNumberUnsignedType,
enable_if_t<detail::is_compatible_integer_type<
number_unsigned_t, CompatibleNumberUnsignedType>::value,
int> = 0 >
basic_json(const CompatibleNumberUnsignedType val) noexcept
: m_type(value_t::number_unsigned),
m_value(static_cast<number_unsigned_t>(val))
@ -1626,9 +1966,10 @@ class basic_json
@since version 1.0.0
*/
template<typename CompatibleNumberFloatType, typename = typename std::enable_if<
std::is_constructible<number_float_t, CompatibleNumberFloatType>::value and
std::is_floating_point<CompatibleNumberFloatType>::value>::type>
template <typename CompatibleNumberFloatType,
enable_if_t<detail::is_compatible_float_type<
number_float_t, CompatibleNumberFloatType>::value,
int> = 0>
basic_json(const CompatibleNumberFloatType val) noexcept
: basic_json(number_float_t(val))
{
@ -2182,6 +2523,18 @@ class basic_json
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
@ -2655,7 +3008,6 @@ class basic_json
// value access //
//////////////////
/// get an object (explicit)
template<class T, typename std::enable_if<
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>
@ -2681,13 +3033,16 @@ class basic_json
}
/// 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
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_convertible<std::string, T>::value and
not has_mapped_type<T>::value, int>::type = 0>
T get_impl(T* /*unused*/) const
not detail::has_mapped_type<T>::value,
int >::type = 0 >
{
if (is_array())
{
@ -2727,7 +3082,7 @@ class basic_json
/// get an array (explicit)
template<class T, typename std::enable_if<
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
{
if (is_array())
@ -2956,13 +3311,46 @@ class basic_json
@since version 1.0.0
*/
template<typename ValueType, typename std::enable_if<
not std::is_pointer<ValueType>::value, int>::type = 0>
ValueType get() const
template <typename ValueType,
enable_if_t<not std::is_pointer<ValueType>::value, int> = 0>
auto get() const
-> decltype(this->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)
@ -8155,6 +8543,11 @@ class basic_json
class primitive_iterator_t
{
public:
difference_type get_value() const noexcept
{
return m_it;
}
/// set iterator to a defined beginning
void set_begin() noexcept
{
@ -8179,16 +8572,87 @@ class basic_json
return (m_it == end_value);
}
/// return reference to the value to change and compare
operator difference_type& () noexcept
friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
{
return m_it;
return lhs.m_it == rhs.m_it;
}
/// return value to compare
constexpr operator difference_type () const noexcept
friend constexpr bool operator!=(primitive_iterator_t lhs, primitive_iterator_t rhs) 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:
@ -8893,7 +9357,7 @@ class basic_json
default:
{
if (m_it.primitive_iterator == -n)
if (m_it.primitive_iterator.get_value() == -n)
{
return *m_object;
}
@ -11380,25 +11844,25 @@ using json = basic_json<>;
// specialization of std::swap, and std::hash
namespace std
{
/*!
@brief exchanges the values of two JSON objects
/*!
@brief exchanges the values of two JSON objects
@since version 1.0.0
*/
template<>
inline void swap(nlohmann::json& j1,
@since version 1.0.0
*/
template<>
inline void swap(nlohmann::json& j1,
nlohmann::json& j2) noexcept(
is_nothrow_move_constructible<nlohmann::json>::value and
is_nothrow_move_assignable<nlohmann::json>::value
)
{
{
j1.swap(j2);
}
}
/// hash value for JSON objects
template<>
struct hash<nlohmann::json>
{
/// hash value for JSON objects
template<>
struct hash<nlohmann::json>
{
/*!
@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>();
return h(j.dump());
}
};
};
} // namespace std
/*!

View file

@ -38,67 +38,67 @@ using nlohmann::json;
namespace udt
{
enum class country
{
enum class country
{
china,
france,
russia
};
};
struct age
{
struct age
{
int m_val;
};
};
struct name
{
struct name
{
std::string m_val;
};
};
struct address
{
struct address
{
std::string m_val;
};
};
struct person
{
struct person
{
age m_age;
name m_name;
country m_country;
};
};
struct contact
{
struct contact
{
person m_person;
address m_address;
};
};
struct contact_book
{
struct contact_book
{
name m_book_name;
std::vector<contact> m_contacts;
};
};
}
// to_json methods
namespace udt
{
// templates because of the custom_json tests (see below)
template <typename Json>
void to_json(Json& j, age a)
{
// templates because of the custom_json tests (see below)
template <typename Json>
void to_json(Json& j, age a)
{
j = a.m_val;
}
}
template <typename Json>
void to_json(Json& j, name const& n)
{
template <typename Json>
void to_json(Json& j, name const& n)
{
j = n.m_val;
}
}
template <typename Json>
void to_json(Json& j, country c)
{
template <typename Json>
void to_json(Json& j, country c)
{
switch (c)
{
case country::china:
@ -111,123 +111,128 @@ namespace udt
j = u8"Российская Федерация";
return;
}
}
}
template <typename Json>
void to_json(Json& j, person const& p)
{
template <typename Json>
void to_json(Json& j, person const& p)
{
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;
}
}
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}};
}
}
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}};
}
}
// operators
bool operator==(age lhs, age rhs)
{
// operators
bool operator==(age lhs, age rhs)
{
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;
}
}
bool operator==(name const &lhs, name const &rhs)
{
bool operator==(name const& lhs, name const& rhs)
{
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);
}
}
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) ==
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) ==
std::tie(rhs.m_book_name, rhs.m_contacts);
}
}
}
// from_json methods
namespace udt
{
template <typename Json>
void from_json(Json const& j, age &a)
{
template <typename Json>
void from_json(Json const& j, age& a)
{
a.m_val = j.template get<int>();
}
}
template <typename Json>
void from_json(Json const& j, name &n)
{
template <typename Json>
void from_json(Json const& j, name& n)
{
n.m_val = j.template get<std::string>();
}
}
template <typename Json>
void from_json(Json const &j, country &c)
{
template <typename Json>
void from_json(Json const& j, country& c)
{
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},
{"France", country::france},
{"Российская Федерация", country::russia}};
{"Российская Федерация", country::russia}
};
const auto it = m.find(str);
// TODO test exceptions
c = it->second;
}
}
template <typename Json>
void from_json(Json const& j, person &p)
{
template <typename Json>
void from_json(Json const& j, person& p)
{
p.m_age = j["age"].template get<age>();
p.m_name = j["name"].template get<name>();
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>();
}
}
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_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_contacts = j["contacts"].get<std::vector<contact>>();
}
}
}
TEST_CASE("basic usage", "[udt]")
{
// a bit narcissic maybe :) ?
const udt::age a{23};
const udt::age a
{
23
};
const udt::name n{"theo"};
const udt::country c{udt::country::france};
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)
{
if (opt)
{
j = *opt;
}
else
{
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())
{
opt = nullptr;
}
else
{
opt.reset(new T(j.get<T>()));
}
}
};
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]")
{
json j = std::vector<int>{1, 2, 3};
json j = std::vector<int> {1, 2, 3};
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
@ -409,20 +422,28 @@ struct adl_serializer<std::unique_ptr<T>>
static void to_json(json& j, std::unique_ptr<T> const& opt)
{
if (opt)
{
j = *opt;
}
else
{
j = nullptr;
}
}
// 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?
static std::unique_ptr<T> from_json(json const &j)
static std::unique_ptr<T> from_json(json const& j)
{
if (j.is_null())
{
return nullptr;
}
else
{
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));
std::uint64_t value = bytes[0];
for (auto i = 1; i < 8; ++i)
{
value |= bytes[i] << 8 * i;
}
j = value;
}
@ -514,7 +537,7 @@ TEST_CASE("custom serializer for pods", "[udt]")
template <typename T, typename>
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>
struct another_adl_serializer