💄 overworked documentation and indentation

This commit is contained in:
Niels Lohmann 2017-01-24 13:47:33 +01:00
parent 030cf674ef
commit 250e5bf43d
2 changed files with 486 additions and 436 deletions

View file

@ -107,12 +107,15 @@ SOFTWARE.
*/ */
namespace nlohmann namespace nlohmann
{ {
// TODO update this doc
/*! /*!
@brief unnamed namespace with internal helper functions @brief unnamed namespace with internal helper functions
@since version 1.0.0
*/
This namespace collects some functions that could not be defined inside the
@ref basic_json class.
@since version 2.1.0
*/
namespace detail namespace detail
{ {
/////////////////////////// ///////////////////////////
@ -122,22 +125,24 @@ namespace detail
/*! /*!
@brief the JSON type enumeration @brief the JSON type enumeration
This enumeration collects the different JSON types. It is internally used This enumeration collects the different JSON types. It is internally used to
to distinguish the stored values, and the functions @ref basic_json::is_null(), @ref distinguish the stored values, and the functions @ref basic_json::is_null(),
basic_json::is_object(), @ref basic_json::is_array(), @ref basic_json::is_string(), @ref basic_json::is_boolean(), @ref @ref basic_json::is_object(), @ref basic_json::is_array(),
basic_json::is_number() (with @ref basic_json::is_number_integer(), @ref basic_json::is_number_unsigned(), and @ref basic_json::is_string(), @ref basic_json::is_boolean(),
@ref basic_json::is_number_float()), @ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and @ref basic_json::is_number() (with @ref basic_json::is_number_integer(),
@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()),
@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and
@ref basic_json::is_structured() rely on it. @ref basic_json::is_structured() rely on it.
@note There are three enumeration entries (number_integer, @note There are three enumeration entries (number_integer, number_unsigned, and
number_unsigned, and number_float), because the library distinguishes number_float), because the library distinguishes these three types for numbers:
these three types for numbers: @ref basic_json::number_unsigned_t is used for unsigned @ref basic_json::number_unsigned_t is used for unsigned integers,
integers, @ref basic_json::number_integer_t is used for signed integers, and @ref @ref basic_json::number_integer_t is used for signed integers, and
basic_json::number_float_t is used for floating-point numbers or to approximate @ref basic_json::number_float_t is used for floating-point numbers or to
integers which do not fit in the limits of their respective type. approximate integers which do not fit in the limits of their respective type.
@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON value with @sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON
the default value for a given type value with the default value for a given type
@since version 1.0.0 @since version 1.0.0
*/ */
@ -154,12 +159,6 @@ enum class value_t : uint8_t
discarded ///< discarded by the the parser callback function discarded ///< discarded by the the parser callback function
}; };
//////////////////////////////////////////
// lexicographical comparison operators //
//////////////////////////////////////////
/// @name lexicographical comparison operators
/// @{
/*! /*!
@brief comparison operator for JSON types @brief comparison operator for JSON types
@ -193,51 +192,62 @@ inline bool operator<(const value_t lhs, const value_t rhs) noexcept
order[static_cast<std::size_t>(rhs)]; order[static_cast<std::size_t>(rhs)];
} }
/////////////
// helpers //
/////////////
// alias templates to reduce boilerplate // alias templates to reduce boilerplate
template <bool B, typename T = void> template<bool B, typename T = void>
using enable_if_t = typename std::enable_if<B, T>::type; using enable_if_t = typename std::enable_if<B, T>::type;
template <typename T> template<typename T>
using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type; using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
// Taken from http://stackoverflow.com/questions/26936640/how-to-implement-is-enum-class-type-trait // Taken from http://stackoverflow.com/questions/26936640/how-to-implement-is-enum-class-type-trait
template <typename T> template<typename T>
using is_unscoped_enum = using is_unscoped_enum =
std::integral_constant<bool, std::is_convertible<T, int>::value and std::integral_constant<bool, std::is_convertible<T, int>::value and
std::is_enum<T>::value>; std::is_enum<T>::value>;
// Implementation of 2 C++17 constructs: conjunction, negation. /*
// This is needed to avoid evaluating all the traits in a condition Implementation of 2 C++17 constructs: conjunction, 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...>
: std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
template <class B> struct negation : std::integral_constant < bool, !B::value > {}; 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 to (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...> : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
template<class B> struct negation : std::integral_constant < bool, !B::value > {};
// dispatch utility (taken from ranges-v3) // dispatch utility (taken from ranges-v3)
template <unsigned N> struct priority_tag : priority_tag < N - 1 > {}; template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
template<> struct priority_tag<0> {};
template <> struct priority_tag<0> {};
//////////////////
// constructors //
//////////////////
// This is an experiment. I need this to move constructors out of basic_json. // This is an experiment. I need this to move constructors out of basic_json.
// I'm sure there is a better way, but this might need a big basic_json refactoring // I'm sure there is a better way, but this might need a big basic_json
template <value_t> struct external_constructor; // refactoring
template<value_t> struct external_constructor;
template <> template<>
struct external_constructor<value_t::boolean> struct external_constructor<value_t::boolean>
{ {
template <typename BasicJsonType> template<typename BasicJsonType>
static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept
{ {
j.m_type = value_t::boolean; j.m_type = value_t::boolean;
@ -246,10 +256,10 @@ struct external_constructor<value_t::boolean>
} }
}; };
template <> template<>
struct external_constructor<value_t::string> struct external_constructor<value_t::string>
{ {
template <typename BasicJsonType> template<typename BasicJsonType>
static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)
{ {
j.m_type = value_t::string; j.m_type = value_t::string;
@ -258,15 +268,17 @@ struct external_constructor<value_t::string>
} }
}; };
template <> template<>
struct external_constructor<value_t::number_float> struct external_constructor<value_t::number_float>
{ {
template <typename BasicJsonType> template<typename BasicJsonType>
static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept
{ {
// replace infinity and NAN by null // replace infinity and NAN by null
if (not std::isfinite(val)) if (not std::isfinite(val))
{
j = BasicJsonType{}; j = BasicJsonType{};
}
else else
{ {
j.m_type = value_t::number_float; j.m_type = value_t::number_float;
@ -276,10 +288,10 @@ struct external_constructor<value_t::number_float>
} }
}; };
template <> template<>
struct external_constructor<value_t::number_unsigned> struct external_constructor<value_t::number_unsigned>
{ {
template <typename BasicJsonType> template<typename BasicJsonType>
static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept
{ {
j.m_type = value_t::number_unsigned; j.m_type = value_t::number_unsigned;
@ -288,10 +300,10 @@ struct external_constructor<value_t::number_unsigned>
} }
}; };
template <> template<>
struct external_constructor<value_t::number_integer> struct external_constructor<value_t::number_integer>
{ {
template <typename BasicJsonType> template<typename BasicJsonType>
static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept
{ {
j.m_type = value_t::number_integer; j.m_type = value_t::number_integer;
@ -300,10 +312,10 @@ struct external_constructor<value_t::number_integer>
} }
}; };
template <> template<>
struct external_constructor<value_t::array> struct external_constructor<value_t::array>
{ {
template <typename BasicJsonType> template<typename BasicJsonType>
static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
{ {
j.m_type = value_t::array; j.m_type = value_t::array;
@ -311,25 +323,24 @@ struct external_constructor<value_t::array>
j.assert_invariant(); j.assert_invariant();
} }
template <typename BasicJsonType, typename CompatibleArrayType, template<typename BasicJsonType, typename CompatibleArrayType,
enable_if_t<not std::is_same<CompatibleArrayType, enable_if_t<not std::is_same<CompatibleArrayType,
typename BasicJsonType::array_t>::value, typename BasicJsonType::array_t>::value,
int> = 0> int> = 0>
static void construct(BasicJsonType& j, const CompatibleArrayType& arr) static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
{ {
using std::begin; using std::begin;
using std::end; using std::end;
j.m_type = value_t::array; j.m_type = value_t::array;
j.m_value.array = j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
j.assert_invariant(); j.assert_invariant();
} }
}; };
template <> template<>
struct external_constructor<value_t::object> struct external_constructor<value_t::object>
{ {
template <typename BasicJsonType> template<typename BasicJsonType>
static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
{ {
j.m_type = value_t::object; j.m_type = value_t::object;
@ -337,22 +348,26 @@ struct external_constructor<value_t::object>
j.assert_invariant(); j.assert_invariant();
} }
template <typename BasicJsonType, typename CompatibleObjectType, template<typename BasicJsonType, typename CompatibleObjectType,
enable_if_t<not std::is_same<CompatibleObjectType, enable_if_t<not std::is_same<CompatibleObjectType,
typename BasicJsonType::object_t>::value, typename BasicJsonType::object_t>::value,
int> = 0> int> = 0>
static void construct(BasicJsonType& j, const CompatibleObjectType& obj) static void construct(BasicJsonType& j, const CompatibleObjectType& obj)
{ {
using std::begin; using std::begin;
using std::end; using std::end;
j.m_type = value_t::object; j.m_type = value_t::object;
j.m_value.object = j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
j.assert_invariant(); j.assert_invariant();
} }
}; };
////////////////////////
// has_/is_ functions //
////////////////////////
/*! /*!
@brief Helper to determine whether there's a key_type for T. @brief Helper to determine whether there's a key_type for T.
@ -364,9 +379,9 @@ contains a `mapped_type`, whereas `std::vector` fails the test.
@since version 1.0.0, overworked in version 2.0.6 @since version 1.0.0, overworked in version 2.0.6
*/ */
#define NLOHMANN_JSON_HAS_HELPER(type) \ #define NLOHMANN_JSON_HAS_HELPER(type) \
template <typename T> struct has_##type { \ template<typename T> struct has_##type { \
private: \ private: \
template <typename U, typename = typename U::type> \ template<typename U, typename = typename U::type> \
static int detect(U &&); \ static int detect(U &&); \
static void detect(...); \ static void detect(...); \
public: \ public: \
@ -381,10 +396,10 @@ 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>
{ {
static constexpr auto value = static constexpr auto value =
@ -404,7 +419,7 @@ struct is_compatible_object_type
typename BasicJsonType::object_t, CompatibleObjectType >::value; typename BasicJsonType::object_t, CompatibleObjectType >::value;
}; };
template <typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct is_basic_json_nested_type struct is_basic_json_nested_type
{ {
static auto constexpr value = std::is_same<T, typename BasicJsonType::iterator>::value or static auto constexpr value = std::is_same<T, typename BasicJsonType::iterator>::value or
@ -414,11 +429,9 @@ struct is_basic_json_nested_type
std::is_same<T, typename BasicJsonType::json_pointer>::value; std::is_same<T, typename BasicJsonType::json_pointer>::value;
}; };
template <class BasicJsonType, class CompatibleArrayType> template<class BasicJsonType, class CompatibleArrayType>
struct is_compatible_array_type struct is_compatible_array_type
{ {
// TODO concept Container?
// this might not make VS happy
static auto constexpr value = static auto constexpr value =
conjunction<negation<std::is_same<void, CompatibleArrayType>>, conjunction<negation<std::is_same<void, CompatibleArrayType>>,
negation<is_compatible_object_type< negation<is_compatible_object_type<
@ -430,10 +443,10 @@ struct is_compatible_array_type
has_iterator<CompatibleArrayType>>::value; has_iterator<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>
{ {
// is there an assert somewhere on overflows? // is there an assert somewhere on overflows?
@ -447,24 +460,25 @@ struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIn
RealLimits::is_signed == CompatibleLimits::is_signed; RealLimits::is_signed == CompatibleLimits::is_signed;
}; };
template <typename RealIntegerType, typename CompatibleNumberIntegerType> template<typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type struct is_compatible_integer_type
{ {
static constexpr auto static constexpr auto value =
value = is_compatible_integer_type_impl < is_compatible_integer_type_impl <
std::is_integral<CompatibleNumberIntegerType>::value and std::is_integral<CompatibleNumberIntegerType>::value and
not std::is_same<bool, CompatibleNumberIntegerType>::value, not std::is_same<bool, CompatibleNumberIntegerType>::value,
RealIntegerType, CompatibleNumberIntegerType > ::value; RealIntegerType, CompatibleNumberIntegerType > ::value;
}; };
// This trait checks if JSONSerializer<T>::from_json(json const&, udt&) exists // This trait checks if JSONSerializer<T>::from_json(json const&, udt&) exists
template <typename BasicJsonType, typename T> template<typename BasicJsonType, 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<BasicJsonType>(), std::declval<T&>()))>::value>> std::declval<BasicJsonType>(), std::declval<T&>()))>::value>>
static int detect(U&&); static int detect(U&&);
static void detect(...); static void detect(...);
@ -475,7 +489,7 @@ struct has_from_json
// This trait checks if JSONSerializer<T>::from_json(json const&) exists // This trait checks if JSONSerializer<T>::from_json(json const&) exists
// this overload is used for non-default-constructible user-defined-types // this overload is used for non-default-constructible user-defined-types
template <typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct has_non_default_from_json struct has_non_default_from_json
{ {
private: private:
@ -492,12 +506,12 @@ struct has_non_default_from_json
}; };
// This trait checks if BasicJsonType::json_serializer<T>::to_json exists // This trait checks if BasicJsonType::json_serializer<T>::to_json exists
template <typename BasicJsonType, typename T> template<typename BasicJsonType, 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<BasicJsonType&>(), std::declval<T>()))> std::declval<BasicJsonType&>(), std::declval<T>()))>
static int detect(U&&); static int detect(U&&);
static void detect(...); static void detect(...);
@ -506,58 +520,33 @@ struct has_to_json
std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value;
}; };
// overloads for basic_json template parameters
template <typename BasicJsonType, typename ArithmeticType, /////////////
enable_if_t<std::is_arithmetic<ArithmeticType>::value and // to_json //
not std::is_same<ArithmeticType, /////////////
typename BasicJsonType::boolean_t>::value,
int> = 0>
void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
{
switch (static_cast<value_t>(j))
{
case value_t::number_unsigned:
val = static_cast<ArithmeticType>(
*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
break;
case value_t::number_integer:
val = static_cast<ArithmeticType>(
*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
break;
case value_t::number_float:
val = static_cast<ArithmeticType>(
*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
break;
default:
JSON_THROW(
std::domain_error("type must be number, but is " + j.type_name()));
}
}
template <typename BasicJsonType> template<typename BasicJsonType>
void to_json(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept void to_json(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept
{ {
external_constructor<value_t::boolean>::construct(j, b); external_constructor<value_t::boolean>::construct(j, b);
} }
template <typename BasicJsonType, typename CompatibleString, template<typename BasicJsonType, typename CompatibleString,
enable_if_t<std::is_constructible<typename BasicJsonType::string_t, enable_if_t<std::is_constructible<typename BasicJsonType::string_t,
CompatibleString>::value, CompatibleString>::value,
int> = 0> int> = 0>
void to_json(BasicJsonType& j, const CompatibleString& s) void to_json(BasicJsonType& j, const CompatibleString& s)
{ {
external_constructor<value_t::string>::construct(j, s); external_constructor<value_t::string>::construct(j, s);
} }
template <typename BasicJsonType, typename FloatType, template<typename BasicJsonType, typename FloatType,
enable_if_t<std::is_floating_point<FloatType>::value, int> = 0> enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>
void to_json(BasicJsonType& j, FloatType val) noexcept void to_json(BasicJsonType& j, FloatType val) noexcept
{ {
external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val)); external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val));
} }
template < template <
typename BasicJsonType, typename CompatibleNumberUnsignedType, typename BasicJsonType, typename CompatibleNumberUnsignedType,
enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t,
@ -578,8 +567,8 @@ void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept
external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val)); external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));
} }
template <typename BasicJsonType, typename UnscopedEnumType, template<typename BasicJsonType, typename UnscopedEnumType,
enable_if_t<is_unscoped_enum<UnscopedEnumType>::value, int> = 0> enable_if_t<is_unscoped_enum<UnscopedEnumType>::value, int> = 0>
void to_json(BasicJsonType& j, UnscopedEnumType e) noexcept void to_json(BasicJsonType& j, UnscopedEnumType e) noexcept
{ {
external_constructor<value_t::number_integer>::construct(j, e); external_constructor<value_t::number_integer>::construct(j, e);
@ -605,7 +594,48 @@ void to_json(BasicJsonType& j, const CompatibleObjectType& arr)
external_constructor<value_t::object>::construct(j, arr); external_constructor<value_t::object>::construct(j, arr);
} }
template <typename BasicJsonType>
///////////////
// from_json //
///////////////
// overloads for basic_json template parameters
template<typename BasicJsonType, typename ArithmeticType,
enable_if_t<std::is_arithmetic<ArithmeticType>::value and
not std::is_same<ArithmeticType,
typename BasicJsonType::boolean_t>::value,
int> = 0>
void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
{
switch (static_cast<value_t>(j))
{
case value_t::number_unsigned:
{
val = static_cast<ArithmeticType>(
*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
break;
}
case value_t::number_integer:
{
val = static_cast<ArithmeticType>(
*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
break;
}
case value_t::number_float:
{
val = static_cast<ArithmeticType>(
*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
break;
}
default:
{
JSON_THROW(
std::domain_error("type must be number, but is " + j.type_name()));
}
}
}
template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
{ {
if (!j.is_boolean()) if (!j.is_boolean())
@ -615,7 +645,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>(); b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
} }
template <typename BasicJsonType> template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
{ {
if (!j.is_string()) if (!j.is_string())
@ -625,35 +655,35 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
s = *j.template get_ptr<const typename BasicJsonType::string_t*>(); s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
} }
template <typename BasicJsonType> template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)
{ {
get_arithmetic_value(j, val); get_arithmetic_value(j, val);
} }
template <typename BasicJsonType> template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val)
{ {
get_arithmetic_value(j, val); get_arithmetic_value(j, val);
} }
template <typename BasicJsonType> template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)
{ {
get_arithmetic_value(j, val); get_arithmetic_value(j, val);
} }
template <typename BasicJsonType, typename UnscopedEnumType, template<typename BasicJsonType, typename UnscopedEnumType,
enable_if_t<is_unscoped_enum<UnscopedEnumType>::value, int> = 0> enable_if_t<is_unscoped_enum<UnscopedEnumType>::value, int> = 0>
void from_json(const BasicJsonType& j, UnscopedEnumType& e) void from_json(const BasicJsonType& j, UnscopedEnumType& e)
{ {
typename std::underlying_type<UnscopedEnumType>::type val = e; typename std::underlying_type<UnscopedEnumType>::type val = e;
get_arithmetic_value(j, val); get_arithmetic_value(j, val);
e = static_cast<UnscopedEnumType>(val); e = static_cast<UnscopedEnumType>(val);
} }
template <typename BasicJsonType> template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr)
{ {
if (!j.is_array()) if (!j.is_array())
{ {
@ -662,8 +692,9 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr)
arr = *j.template get_ptr<const typename BasicJsonType::array_t*>(); arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
} }
// forward_list doesn't have an insert method, TODO find a way to avoid including forward_list // forward_list doesn't have an insert method
template <typename BasicJsonType, typename T, typename Allocator> // TODO find a way to avoid including forward_list
template<typename BasicJsonType, typename T, typename Allocator>
void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l) void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
{ {
// do not perform the check when user wants to retrieve jsons // do not perform the check when user wants to retrieve jsons
@ -685,23 +716,23 @@ void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
} }
} }
template <typename BasicJsonType, typename CompatibleArrayType> template<typename BasicJsonType, typename CompatibleArrayType>
void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0>) void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0>)
{ {
using std::begin; using std::begin;
using std::end; using std::end;
std::transform( std::transform(j.begin(), j.end(),
j.begin(), j.end(), std::inserter(arr, end(arr)), [](const BasicJsonType & i) std::inserter(arr, end(arr)), [](const BasicJsonType & i)
{ {
// get<BasicJsonType>() returns *this, this won't call a from_json method when // get<BasicJsonType>() returns *this, this won't call a from_json
// value_type is BasicJsonType // method when value_type is BasicJsonType
return i.template get<typename CompatibleArrayType::value_type>(); return i.template get<typename CompatibleArrayType::value_type>();
}); });
} }
template <typename BasicJsonType, typename CompatibleArrayType> template<typename BasicJsonType, typename CompatibleArrayType>
auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1>) auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1>)
-> decltype( -> decltype(
arr.reserve(std::declval<typename CompatibleArrayType::size_type>()), arr.reserve(std::declval<typename CompatibleArrayType::size_type>()),
void()) void())
@ -711,26 +742,24 @@ auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, pri
arr.reserve(j.size()); arr.reserve(j.size());
std::transform( std::transform(
j.begin(), j.end(), std::inserter(arr, end(arr)), [](const BasicJsonType & i) j.begin(), j.end(), std::inserter(arr, end(arr)), [](const BasicJsonType & i)
{ {
// get<BasicJsonType>() returns *this, this won't call a from_json method when // get<BasicJsonType>() returns *this, this won't call a from_json
// value_type is BasicJsonType // method when value_type is BasicJsonType
return i.template get<typename CompatibleArrayType::value_type>(); return i.template get<typename CompatibleArrayType::value_type>();
}); });
} }
template < template<typename BasicJsonType, typename CompatibleArrayType,
typename BasicJsonType, typename CompatibleArrayType, enable_if_t<is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and
enable_if_t<is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and not std::is_same<typename BasicJsonType::array_t, CompatibleArrayType>::value, int> = 0>
not std::is_same<typename BasicJsonType::array_t, void from_json(const BasicJsonType& j, CompatibleArrayType& arr)
CompatibleArrayType>::value,
int> = 0 >
void from_json(const BasicJsonType& j, CompatibleArrayType& arr)
{ {
if (j.is_null()) if (j.is_null())
{ {
JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); JSON_THROW(std::domain_error("type must be array, but is " + j.type_name()));
} }
// when T == BasicJsonType, do not check if value_t is correct // when T == BasicJsonType, do not check if value_t is correct
if (not std::is_same<typename CompatibleArrayType::value_type, BasicJsonType>::value) if (not std::is_same<typename CompatibleArrayType::value_type, BasicJsonType>::value)
{ {
@ -742,12 +771,9 @@ void from_json(const BasicJsonType& j, CompatibleArrayType& arr)
from_json_array_impl(j, arr, priority_tag<1> {}); from_json_array_impl(j, arr, priority_tag<1> {});
} }
template<typename BasicJsonType, typename CompatibleObjectType,
template < enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value, int> = 0>
typename BasicJsonType, typename CompatibleObjectType, void from_json(const BasicJsonType& j, CompatibleObjectType& obj)
enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value,
int> = 0 >
void from_json(const BasicJsonType& j, CompatibleObjectType& obj)
{ {
if (!j.is_object()) if (!j.is_object())
{ {
@ -766,63 +792,52 @@ void from_json(const BasicJsonType& j, CompatibleObjectType& obj)
// //
// note: Is it really necessary to provide explicit overloads for boolean_t etc.. // note: Is it really necessary to provide explicit overloads for boolean_t etc..
// in case of a custom BooleanType which is not an arithmetic type? // in case of a custom BooleanType which is not an arithmetic type?
template < template<typename BasicJsonType, typename ArithmeticType,
typename BasicJsonType, typename ArithmeticType, enable_if_t <
enable_if_t < std::is_arithmetic<ArithmeticType>::value and
std::is_arithmetic<ArithmeticType>::value and not std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value and
not std::is_same<ArithmeticType, not std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value and
typename BasicJsonType::number_unsigned_t>::value and not std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value and
not std::is_same<ArithmeticType, not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
typename BasicJsonType::number_integer_t>::value and int> = 0>
not std::is_same<ArithmeticType,
typename BasicJsonType::number_float_t>::value and
not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
int > = 0 >
void from_json(const BasicJsonType& j, ArithmeticType& val) void from_json(const BasicJsonType& j, ArithmeticType& val)
{ {
switch (static_cast<value_t>(j)) switch (static_cast<value_t>(j))
{ {
case value_t::number_unsigned: case value_t::number_unsigned:
val = static_cast<ArithmeticType>( val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
break; break;
case value_t::number_integer: case value_t::number_integer:
val = static_cast<ArithmeticType>( val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
break; break;
case value_t::number_float: case value_t::number_float:
val = static_cast<ArithmeticType>( val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
break; break;
case value_t::boolean: case value_t::boolean:
val = static_cast<ArithmeticType>( val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());
*j.template get_ptr<const typename BasicJsonType::boolean_t*>());
break; break;
default: default:
JSON_THROW( JSON_THROW(std::domain_error("type must be number, but is " + j.type_name()));
std::domain_error("type must be number, but is " + j.type_name()));
} }
} }
struct to_json_fn struct to_json_fn
{ {
template <typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
auto call(BasicJsonType& j, T&& val, priority_tag<1>) const auto call(BasicJsonType& j, T&& val, priority_tag<1>) const noexcept(noexcept(to_json(j, std::forward<T>(val))))
noexcept(noexcept(to_json(j, std::forward<T>(val)))) -> decltype(to_json(j, std::forward<T>(val)), void())
-> decltype(to_json(j, std::forward<T>(val)),
void())
{ {
return to_json(j, std::forward<T>(val)); return to_json(j, std::forward<T>(val));
} }
template <typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
void call(BasicJsonType&, T&&, priority_tag<0>) const noexcept void call(BasicJsonType&, T&&, priority_tag<0>) const noexcept
{ {
static_assert(sizeof(BasicJsonType) == 0, "to_json method in T's namespace can not be called"); static_assert(sizeof(BasicJsonType) == 0, "to_json method in T's namespace can not be called");
} }
public: public:
template <typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
void operator()(BasicJsonType& j, T&& val) const void operator()(BasicJsonType& j, T&& val) const
noexcept(noexcept(std::declval<to_json_fn>().call(j, std::forward<T>(val), priority_tag<1> {}))) noexcept(noexcept(std::declval<to_json_fn>().call(j, std::forward<T>(val), priority_tag<1> {})))
{ {
@ -833,23 +848,23 @@ struct to_json_fn
struct from_json_fn struct from_json_fn
{ {
private: private:
template <typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
auto call(const BasicJsonType& j, T& val, priority_tag<1>) const auto call(const BasicJsonType& j, T& val, priority_tag<1>) const
noexcept(noexcept(from_json(j, val))) noexcept(noexcept(from_json(j, val)))
-> decltype(from_json(j, val), void()) -> decltype(from_json(j, val), void())
{ {
return from_json(j, val); return from_json(j, val);
} }
template <typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
void call(const BasicJsonType&, T&, priority_tag<0>) const noexcept void call(const BasicJsonType&, T&, priority_tag<0>) const noexcept
{ {
static_assert(sizeof(BasicJsonType) == 0, "from_json method in T's namespace can not be called"); static_assert(sizeof(BasicJsonType) == 0, "from_json method in T's namespace can not be called");
} }
public: public:
template <typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
void operator()(const BasicJsonType& j, T& val) const void operator()(const BasicJsonType& j, T& val) const
noexcept(noexcept(std::declval<from_json_fn>().call(j, val, priority_tag<1> {}))) noexcept(noexcept(std::declval<from_json_fn>().call(j, val, priority_tag<1> {})))
{ {
return call(j, val, priority_tag<1> {}); return call(j, val, priority_tag<1> {});
@ -857,15 +872,16 @@ struct from_json_fn
}; };
// taken from ranges-v3 // taken from ranges-v3
template <typename T> template<typename T>
struct static_const struct static_const
{ {
static constexpr T value{}; static constexpr T value{};
}; };
template <typename T> template<typename T>
constexpr T static_const<T>::value; constexpr T static_const<T>::value;
/*! /*!
@brief helper class to create locales with decimal point @brief helper class to create locales with decimal point
@ -885,7 +901,8 @@ struct DecimalSeparator : std::numpunct<char>
return '.'; return '.';
} }
}; };
} } // namespace detail
namespace namespace
{ {
@ -895,16 +912,16 @@ constexpr const auto& from_json = detail::static_const<detail::from_json_fn>::va
// default JSONSerializer template argument, doesn't care about template argument // default JSONSerializer template argument, doesn't care about template argument
// will use ADL for serialization // will use ADL for serialization
template <typename = void, typename = void> template<typename = void, typename = void>
struct adl_serializer struct adl_serializer
{ {
template <typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
static void from_json(BasicJsonType&& j, T& val) noexcept(noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val))) static void from_json(BasicJsonType&& j, T& val) noexcept(noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val)))
{ {
::nlohmann::from_json(std::forward<BasicJsonType>(j), val); ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
} }
template <typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
static void to_json(BasicJsonType& j, T&& val) noexcept( static void to_json(BasicJsonType& j, T&& val) noexcept(
noexcept(::nlohmann::to_json(j, std::forward<T>(val)))) noexcept(::nlohmann::to_json(j, std::forward<T>(val))))
{ {
@ -912,6 +929,7 @@ struct adl_serializer
} }
}; };
/*! /*!
@brief a class to store JSON values @brief a class to store JSON values
@ -1005,7 +1023,7 @@ template <
class basic_json class basic_json
{ {
private: private:
template <detail::value_t> friend struct detail::external_constructor; template<detail::value_t> friend struct detail::external_constructor;
/// 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,
@ -1017,7 +1035,7 @@ class basic_json
template<typename U> class iter_impl; template<typename U> class iter_impl;
template<typename Base> class json_reverse_iterator; template<typename Base> class json_reverse_iterator;
class json_pointer; class json_pointer;
template <typename T, typename SFINAE> template<typename T, typename SFINAE>
using json_serializer = JSONSerializer<T, SFINAE>; using json_serializer = JSONSerializer<T, SFINAE>;
///////////////////// /////////////////////
@ -1904,13 +1922,13 @@ class basic_json
@since version 2.1.0 @since version 2.1.0
*/ */
template <typename T, typename U = detail::uncvref_t<T>, template<typename T, typename U = detail::uncvref_t<T>,
detail::enable_if_t<not std::is_base_of<std::istream, U>::value and detail::enable_if_t<not std::is_base_of<std::istream, U>::value and
not std::is_same<U, basic_json_t>::value and not std::is_same<U, basic_json_t>::value and
not detail::is_basic_json_nested_type< not detail::is_basic_json_nested_type<
basic_json_t, U>::value and basic_json_t, U>::value and
detail::has_to_json<basic_json, U>::value, detail::has_to_json<basic_json, U>::value,
int> = 0> int> = 0>
basic_json(T && val) noexcept(noexcept(JSONSerializer<U>::to_json( basic_json(T && val) noexcept(noexcept(JSONSerializer<U>::to_json(
std::declval<basic_json_t&>(), std::forward<T>(val)))) std::declval<basic_json_t&>(), std::forward<T>(val))))
{ {
@ -5714,6 +5732,13 @@ class basic_json
/// @} /// @}
public: public:
//////////////////////////////////////////
// lexicographical comparison operators //
//////////////////////////////////////////
/// @name lexicographical comparison operators
/// @{
/*! /*!
@brief comparison: equal @brief comparison: equal
@ -10795,7 +10820,7 @@ basic_json_parser_66:
for (; curptr < m_cursor; curptr++) for (; curptr < m_cursor; curptr++)
{ {
// quickly skip tests if a digit // quickly skip tests if a digit
if (*curptr < '0' || *curptr > '9') if (*curptr < '0' or* curptr > '9')
{ {
if (*curptr == '.') if (*curptr == '.')
{ {

View file

@ -107,12 +107,15 @@ SOFTWARE.
*/ */
namespace nlohmann namespace nlohmann
{ {
// TODO update this doc
/*! /*!
@brief unnamed namespace with internal helper functions @brief unnamed namespace with internal helper functions
@since version 1.0.0
*/
This namespace collects some functions that could not be defined inside the
@ref basic_json class.
@since version 2.1.0
*/
namespace detail namespace detail
{ {
/////////////////////////// ///////////////////////////
@ -122,22 +125,24 @@ namespace detail
/*! /*!
@brief the JSON type enumeration @brief the JSON type enumeration
This enumeration collects the different JSON types. It is internally used This enumeration collects the different JSON types. It is internally used to
to distinguish the stored values, and the functions @ref basic_json::is_null(), @ref distinguish the stored values, and the functions @ref basic_json::is_null(),
basic_json::is_object(), @ref basic_json::is_array(), @ref basic_json::is_string(), @ref basic_json::is_boolean(), @ref @ref basic_json::is_object(), @ref basic_json::is_array(),
basic_json::is_number() (with @ref basic_json::is_number_integer(), @ref basic_json::is_number_unsigned(), and @ref basic_json::is_string(), @ref basic_json::is_boolean(),
@ref basic_json::is_number_float()), @ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and @ref basic_json::is_number() (with @ref basic_json::is_number_integer(),
@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()),
@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and
@ref basic_json::is_structured() rely on it. @ref basic_json::is_structured() rely on it.
@note There are three enumeration entries (number_integer, @note There are three enumeration entries (number_integer, number_unsigned, and
number_unsigned, and number_float), because the library distinguishes number_float), because the library distinguishes these three types for numbers:
these three types for numbers: @ref basic_json::number_unsigned_t is used for unsigned @ref basic_json::number_unsigned_t is used for unsigned integers,
integers, @ref basic_json::number_integer_t is used for signed integers, and @ref @ref basic_json::number_integer_t is used for signed integers, and
basic_json::number_float_t is used for floating-point numbers or to approximate @ref basic_json::number_float_t is used for floating-point numbers or to
integers which do not fit in the limits of their respective type. approximate integers which do not fit in the limits of their respective type.
@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON value with @sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON
the default value for a given type value with the default value for a given type
@since version 1.0.0 @since version 1.0.0
*/ */
@ -154,12 +159,6 @@ enum class value_t : uint8_t
discarded ///< discarded by the the parser callback function discarded ///< discarded by the the parser callback function
}; };
//////////////////////////////////////////
// lexicographical comparison operators //
//////////////////////////////////////////
/// @name lexicographical comparison operators
/// @{
/*! /*!
@brief comparison operator for JSON types @brief comparison operator for JSON types
@ -193,51 +192,62 @@ inline bool operator<(const value_t lhs, const value_t rhs) noexcept
order[static_cast<std::size_t>(rhs)]; order[static_cast<std::size_t>(rhs)];
} }
/////////////
// helpers //
/////////////
// alias templates to reduce boilerplate // alias templates to reduce boilerplate
template <bool B, typename T = void> template<bool B, typename T = void>
using enable_if_t = typename std::enable_if<B, T>::type; using enable_if_t = typename std::enable_if<B, T>::type;
template <typename T> template<typename T>
using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type; using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
// Taken from http://stackoverflow.com/questions/26936640/how-to-implement-is-enum-class-type-trait // Taken from http://stackoverflow.com/questions/26936640/how-to-implement-is-enum-class-type-trait
template <typename T> template<typename T>
using is_unscoped_enum = using is_unscoped_enum =
std::integral_constant<bool, std::is_convertible<T, int>::value and std::integral_constant<bool, std::is_convertible<T, int>::value and
std::is_enum<T>::value>; std::is_enum<T>::value>;
// Implementation of 2 C++17 constructs: conjunction, negation. /*
// This is needed to avoid evaluating all the traits in a condition Implementation of 2 C++17 constructs: conjunction, 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...>
: std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
template <class B> struct negation : std::integral_constant < bool, !B::value > {}; 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 to (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...> : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
template<class B> struct negation : std::integral_constant < bool, !B::value > {};
// dispatch utility (taken from ranges-v3) // dispatch utility (taken from ranges-v3)
template <unsigned N> struct priority_tag : priority_tag < N - 1 > {}; template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
template<> struct priority_tag<0> {};
template <> struct priority_tag<0> {};
//////////////////
// constructors //
//////////////////
// This is an experiment. I need this to move constructors out of basic_json. // This is an experiment. I need this to move constructors out of basic_json.
// I'm sure there is a better way, but this might need a big basic_json refactoring // I'm sure there is a better way, but this might need a big basic_json
template <value_t> struct external_constructor; // refactoring
template<value_t> struct external_constructor;
template <> template<>
struct external_constructor<value_t::boolean> struct external_constructor<value_t::boolean>
{ {
template <typename BasicJsonType> template<typename BasicJsonType>
static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept
{ {
j.m_type = value_t::boolean; j.m_type = value_t::boolean;
@ -246,10 +256,10 @@ struct external_constructor<value_t::boolean>
} }
}; };
template <> template<>
struct external_constructor<value_t::string> struct external_constructor<value_t::string>
{ {
template <typename BasicJsonType> template<typename BasicJsonType>
static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)
{ {
j.m_type = value_t::string; j.m_type = value_t::string;
@ -258,15 +268,17 @@ struct external_constructor<value_t::string>
} }
}; };
template <> template<>
struct external_constructor<value_t::number_float> struct external_constructor<value_t::number_float>
{ {
template <typename BasicJsonType> template<typename BasicJsonType>
static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept
{ {
// replace infinity and NAN by null // replace infinity and NAN by null
if (not std::isfinite(val)) if (not std::isfinite(val))
{
j = BasicJsonType{}; j = BasicJsonType{};
}
else else
{ {
j.m_type = value_t::number_float; j.m_type = value_t::number_float;
@ -276,10 +288,10 @@ struct external_constructor<value_t::number_float>
} }
}; };
template <> template<>
struct external_constructor<value_t::number_unsigned> struct external_constructor<value_t::number_unsigned>
{ {
template <typename BasicJsonType> template<typename BasicJsonType>
static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept
{ {
j.m_type = value_t::number_unsigned; j.m_type = value_t::number_unsigned;
@ -288,10 +300,10 @@ struct external_constructor<value_t::number_unsigned>
} }
}; };
template <> template<>
struct external_constructor<value_t::number_integer> struct external_constructor<value_t::number_integer>
{ {
template <typename BasicJsonType> template<typename BasicJsonType>
static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept
{ {
j.m_type = value_t::number_integer; j.m_type = value_t::number_integer;
@ -300,10 +312,10 @@ struct external_constructor<value_t::number_integer>
} }
}; };
template <> template<>
struct external_constructor<value_t::array> struct external_constructor<value_t::array>
{ {
template <typename BasicJsonType> template<typename BasicJsonType>
static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
{ {
j.m_type = value_t::array; j.m_type = value_t::array;
@ -311,25 +323,24 @@ struct external_constructor<value_t::array>
j.assert_invariant(); j.assert_invariant();
} }
template <typename BasicJsonType, typename CompatibleArrayType, template<typename BasicJsonType, typename CompatibleArrayType,
enable_if_t<not std::is_same<CompatibleArrayType, enable_if_t<not std::is_same<CompatibleArrayType,
typename BasicJsonType::array_t>::value, typename BasicJsonType::array_t>::value,
int> = 0> int> = 0>
static void construct(BasicJsonType& j, const CompatibleArrayType& arr) static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
{ {
using std::begin; using std::begin;
using std::end; using std::end;
j.m_type = value_t::array; j.m_type = value_t::array;
j.m_value.array = j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
j.assert_invariant(); j.assert_invariant();
} }
}; };
template <> template<>
struct external_constructor<value_t::object> struct external_constructor<value_t::object>
{ {
template <typename BasicJsonType> template<typename BasicJsonType>
static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
{ {
j.m_type = value_t::object; j.m_type = value_t::object;
@ -337,22 +348,26 @@ struct external_constructor<value_t::object>
j.assert_invariant(); j.assert_invariant();
} }
template <typename BasicJsonType, typename CompatibleObjectType, template<typename BasicJsonType, typename CompatibleObjectType,
enable_if_t<not std::is_same<CompatibleObjectType, enable_if_t<not std::is_same<CompatibleObjectType,
typename BasicJsonType::object_t>::value, typename BasicJsonType::object_t>::value,
int> = 0> int> = 0>
static void construct(BasicJsonType& j, const CompatibleObjectType& obj) static void construct(BasicJsonType& j, const CompatibleObjectType& obj)
{ {
using std::begin; using std::begin;
using std::end; using std::end;
j.m_type = value_t::object; j.m_type = value_t::object;
j.m_value.object = j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
j.assert_invariant(); j.assert_invariant();
} }
}; };
////////////////////////
// has_/is_ functions //
////////////////////////
/*! /*!
@brief Helper to determine whether there's a key_type for T. @brief Helper to determine whether there's a key_type for T.
@ -364,9 +379,9 @@ contains a `mapped_type`, whereas `std::vector` fails the test.
@since version 1.0.0, overworked in version 2.0.6 @since version 1.0.0, overworked in version 2.0.6
*/ */
#define NLOHMANN_JSON_HAS_HELPER(type) \ #define NLOHMANN_JSON_HAS_HELPER(type) \
template <typename T> struct has_##type { \ template<typename T> struct has_##type { \
private: \ private: \
template <typename U, typename = typename U::type> \ template<typename U, typename = typename U::type> \
static int detect(U &&); \ static int detect(U &&); \
static void detect(...); \ static void detect(...); \
public: \ public: \
@ -381,10 +396,10 @@ 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>
{ {
static constexpr auto value = static constexpr auto value =
@ -404,7 +419,7 @@ struct is_compatible_object_type
typename BasicJsonType::object_t, CompatibleObjectType >::value; typename BasicJsonType::object_t, CompatibleObjectType >::value;
}; };
template <typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct is_basic_json_nested_type struct is_basic_json_nested_type
{ {
static auto constexpr value = std::is_same<T, typename BasicJsonType::iterator>::value or static auto constexpr value = std::is_same<T, typename BasicJsonType::iterator>::value or
@ -414,11 +429,9 @@ struct is_basic_json_nested_type
std::is_same<T, typename BasicJsonType::json_pointer>::value; std::is_same<T, typename BasicJsonType::json_pointer>::value;
}; };
template <class BasicJsonType, class CompatibleArrayType> template<class BasicJsonType, class CompatibleArrayType>
struct is_compatible_array_type struct is_compatible_array_type
{ {
// TODO concept Container?
// this might not make VS happy
static auto constexpr value = static auto constexpr value =
conjunction<negation<std::is_same<void, CompatibleArrayType>>, conjunction<negation<std::is_same<void, CompatibleArrayType>>,
negation<is_compatible_object_type< negation<is_compatible_object_type<
@ -430,10 +443,10 @@ struct is_compatible_array_type
has_iterator<CompatibleArrayType>>::value; has_iterator<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>
{ {
// is there an assert somewhere on overflows? // is there an assert somewhere on overflows?
@ -447,24 +460,25 @@ struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIn
RealLimits::is_signed == CompatibleLimits::is_signed; RealLimits::is_signed == CompatibleLimits::is_signed;
}; };
template <typename RealIntegerType, typename CompatibleNumberIntegerType> template<typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type struct is_compatible_integer_type
{ {
static constexpr auto static constexpr auto value =
value = is_compatible_integer_type_impl < is_compatible_integer_type_impl <
std::is_integral<CompatibleNumberIntegerType>::value and std::is_integral<CompatibleNumberIntegerType>::value and
not std::is_same<bool, CompatibleNumberIntegerType>::value, not std::is_same<bool, CompatibleNumberIntegerType>::value,
RealIntegerType, CompatibleNumberIntegerType > ::value; RealIntegerType, CompatibleNumberIntegerType > ::value;
}; };
// This trait checks if JSONSerializer<T>::from_json(json const&, udt&) exists // This trait checks if JSONSerializer<T>::from_json(json const&, udt&) exists
template <typename BasicJsonType, typename T> template<typename BasicJsonType, 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<BasicJsonType>(), std::declval<T&>()))>::value>> std::declval<BasicJsonType>(), std::declval<T&>()))>::value>>
static int detect(U&&); static int detect(U&&);
static void detect(...); static void detect(...);
@ -475,7 +489,7 @@ struct has_from_json
// This trait checks if JSONSerializer<T>::from_json(json const&) exists // This trait checks if JSONSerializer<T>::from_json(json const&) exists
// this overload is used for non-default-constructible user-defined-types // this overload is used for non-default-constructible user-defined-types
template <typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct has_non_default_from_json struct has_non_default_from_json
{ {
private: private:
@ -492,12 +506,12 @@ struct has_non_default_from_json
}; };
// This trait checks if BasicJsonType::json_serializer<T>::to_json exists // This trait checks if BasicJsonType::json_serializer<T>::to_json exists
template <typename BasicJsonType, typename T> template<typename BasicJsonType, 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<BasicJsonType&>(), std::declval<T>()))> std::declval<BasicJsonType&>(), std::declval<T>()))>
static int detect(U&&); static int detect(U&&);
static void detect(...); static void detect(...);
@ -506,58 +520,33 @@ struct has_to_json
std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value;
}; };
// overloads for basic_json template parameters
template <typename BasicJsonType, typename ArithmeticType, /////////////
enable_if_t<std::is_arithmetic<ArithmeticType>::value and // to_json //
not std::is_same<ArithmeticType, /////////////
typename BasicJsonType::boolean_t>::value,
int> = 0>
void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
{
switch (static_cast<value_t>(j))
{
case value_t::number_unsigned:
val = static_cast<ArithmeticType>(
*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
break;
case value_t::number_integer:
val = static_cast<ArithmeticType>(
*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
break;
case value_t::number_float:
val = static_cast<ArithmeticType>(
*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
break;
default:
JSON_THROW(
std::domain_error("type must be number, but is " + j.type_name()));
}
}
template <typename BasicJsonType> template<typename BasicJsonType>
void to_json(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept void to_json(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept
{ {
external_constructor<value_t::boolean>::construct(j, b); external_constructor<value_t::boolean>::construct(j, b);
} }
template <typename BasicJsonType, typename CompatibleString, template<typename BasicJsonType, typename CompatibleString,
enable_if_t<std::is_constructible<typename BasicJsonType::string_t, enable_if_t<std::is_constructible<typename BasicJsonType::string_t,
CompatibleString>::value, CompatibleString>::value,
int> = 0> int> = 0>
void to_json(BasicJsonType& j, const CompatibleString& s) void to_json(BasicJsonType& j, const CompatibleString& s)
{ {
external_constructor<value_t::string>::construct(j, s); external_constructor<value_t::string>::construct(j, s);
} }
template <typename BasicJsonType, typename FloatType, template<typename BasicJsonType, typename FloatType,
enable_if_t<std::is_floating_point<FloatType>::value, int> = 0> enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>
void to_json(BasicJsonType& j, FloatType val) noexcept void to_json(BasicJsonType& j, FloatType val) noexcept
{ {
external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val)); external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val));
} }
template < template <
typename BasicJsonType, typename CompatibleNumberUnsignedType, typename BasicJsonType, typename CompatibleNumberUnsignedType,
enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t,
@ -578,8 +567,8 @@ void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept
external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val)); external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));
} }
template <typename BasicJsonType, typename UnscopedEnumType, template<typename BasicJsonType, typename UnscopedEnumType,
enable_if_t<is_unscoped_enum<UnscopedEnumType>::value, int> = 0> enable_if_t<is_unscoped_enum<UnscopedEnumType>::value, int> = 0>
void to_json(BasicJsonType& j, UnscopedEnumType e) noexcept void to_json(BasicJsonType& j, UnscopedEnumType e) noexcept
{ {
external_constructor<value_t::number_integer>::construct(j, e); external_constructor<value_t::number_integer>::construct(j, e);
@ -605,7 +594,48 @@ void to_json(BasicJsonType& j, const CompatibleObjectType& arr)
external_constructor<value_t::object>::construct(j, arr); external_constructor<value_t::object>::construct(j, arr);
} }
template <typename BasicJsonType>
///////////////
// from_json //
///////////////
// overloads for basic_json template parameters
template<typename BasicJsonType, typename ArithmeticType,
enable_if_t<std::is_arithmetic<ArithmeticType>::value and
not std::is_same<ArithmeticType,
typename BasicJsonType::boolean_t>::value,
int> = 0>
void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
{
switch (static_cast<value_t>(j))
{
case value_t::number_unsigned:
{
val = static_cast<ArithmeticType>(
*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
break;
}
case value_t::number_integer:
{
val = static_cast<ArithmeticType>(
*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
break;
}
case value_t::number_float:
{
val = static_cast<ArithmeticType>(
*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
break;
}
default:
{
JSON_THROW(
std::domain_error("type must be number, but is " + j.type_name()));
}
}
}
template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
{ {
if (!j.is_boolean()) if (!j.is_boolean())
@ -615,7 +645,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>(); b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
} }
template <typename BasicJsonType> template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
{ {
if (!j.is_string()) if (!j.is_string())
@ -625,35 +655,35 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
s = *j.template get_ptr<const typename BasicJsonType::string_t*>(); s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
} }
template <typename BasicJsonType> template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)
{ {
get_arithmetic_value(j, val); get_arithmetic_value(j, val);
} }
template <typename BasicJsonType> template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val)
{ {
get_arithmetic_value(j, val); get_arithmetic_value(j, val);
} }
template <typename BasicJsonType> template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)
{ {
get_arithmetic_value(j, val); get_arithmetic_value(j, val);
} }
template <typename BasicJsonType, typename UnscopedEnumType, template<typename BasicJsonType, typename UnscopedEnumType,
enable_if_t<is_unscoped_enum<UnscopedEnumType>::value, int> = 0> enable_if_t<is_unscoped_enum<UnscopedEnumType>::value, int> = 0>
void from_json(const BasicJsonType& j, UnscopedEnumType& e) void from_json(const BasicJsonType& j, UnscopedEnumType& e)
{ {
typename std::underlying_type<UnscopedEnumType>::type val = e; typename std::underlying_type<UnscopedEnumType>::type val = e;
get_arithmetic_value(j, val); get_arithmetic_value(j, val);
e = static_cast<UnscopedEnumType>(val); e = static_cast<UnscopedEnumType>(val);
} }
template <typename BasicJsonType> template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr)
{ {
if (!j.is_array()) if (!j.is_array())
{ {
@ -662,8 +692,9 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr)
arr = *j.template get_ptr<const typename BasicJsonType::array_t*>(); arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
} }
// forward_list doesn't have an insert method, TODO find a way to avoid including forward_list // forward_list doesn't have an insert method
template <typename BasicJsonType, typename T, typename Allocator> // TODO find a way to avoid including forward_list
template<typename BasicJsonType, typename T, typename Allocator>
void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l) void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
{ {
// do not perform the check when user wants to retrieve jsons // do not perform the check when user wants to retrieve jsons
@ -685,23 +716,23 @@ void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
} }
} }
template <typename BasicJsonType, typename CompatibleArrayType> template<typename BasicJsonType, typename CompatibleArrayType>
void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0>) void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0>)
{ {
using std::begin; using std::begin;
using std::end; using std::end;
std::transform( std::transform(j.begin(), j.end(),
j.begin(), j.end(), std::inserter(arr, end(arr)), [](const BasicJsonType & i) std::inserter(arr, end(arr)), [](const BasicJsonType & i)
{ {
// get<BasicJsonType>() returns *this, this won't call a from_json method when // get<BasicJsonType>() returns *this, this won't call a from_json
// value_type is BasicJsonType // method when value_type is BasicJsonType
return i.template get<typename CompatibleArrayType::value_type>(); return i.template get<typename CompatibleArrayType::value_type>();
}); });
} }
template <typename BasicJsonType, typename CompatibleArrayType> template<typename BasicJsonType, typename CompatibleArrayType>
auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1>) auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1>)
-> decltype( -> decltype(
arr.reserve(std::declval<typename CompatibleArrayType::size_type>()), arr.reserve(std::declval<typename CompatibleArrayType::size_type>()),
void()) void())
@ -711,26 +742,24 @@ auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, pri
arr.reserve(j.size()); arr.reserve(j.size());
std::transform( std::transform(
j.begin(), j.end(), std::inserter(arr, end(arr)), [](const BasicJsonType & i) j.begin(), j.end(), std::inserter(arr, end(arr)), [](const BasicJsonType & i)
{ {
// get<BasicJsonType>() returns *this, this won't call a from_json method when // get<BasicJsonType>() returns *this, this won't call a from_json
// value_type is BasicJsonType // method when value_type is BasicJsonType
return i.template get<typename CompatibleArrayType::value_type>(); return i.template get<typename CompatibleArrayType::value_type>();
}); });
} }
template < template<typename BasicJsonType, typename CompatibleArrayType,
typename BasicJsonType, typename CompatibleArrayType, enable_if_t<is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and
enable_if_t<is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and not std::is_same<typename BasicJsonType::array_t, CompatibleArrayType>::value, int> = 0>
not std::is_same<typename BasicJsonType::array_t, void from_json(const BasicJsonType& j, CompatibleArrayType& arr)
CompatibleArrayType>::value,
int> = 0 >
void from_json(const BasicJsonType& j, CompatibleArrayType& arr)
{ {
if (j.is_null()) if (j.is_null())
{ {
JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); JSON_THROW(std::domain_error("type must be array, but is " + j.type_name()));
} }
// when T == BasicJsonType, do not check if value_t is correct // when T == BasicJsonType, do not check if value_t is correct
if (not std::is_same<typename CompatibleArrayType::value_type, BasicJsonType>::value) if (not std::is_same<typename CompatibleArrayType::value_type, BasicJsonType>::value)
{ {
@ -742,12 +771,9 @@ void from_json(const BasicJsonType& j, CompatibleArrayType& arr)
from_json_array_impl(j, arr, priority_tag<1> {}); from_json_array_impl(j, arr, priority_tag<1> {});
} }
template<typename BasicJsonType, typename CompatibleObjectType,
template < enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value, int> = 0>
typename BasicJsonType, typename CompatibleObjectType, void from_json(const BasicJsonType& j, CompatibleObjectType& obj)
enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value,
int> = 0 >
void from_json(const BasicJsonType& j, CompatibleObjectType& obj)
{ {
if (!j.is_object()) if (!j.is_object())
{ {
@ -766,63 +792,52 @@ void from_json(const BasicJsonType& j, CompatibleObjectType& obj)
// //
// note: Is it really necessary to provide explicit overloads for boolean_t etc.. // note: Is it really necessary to provide explicit overloads for boolean_t etc..
// in case of a custom BooleanType which is not an arithmetic type? // in case of a custom BooleanType which is not an arithmetic type?
template < template<typename BasicJsonType, typename ArithmeticType,
typename BasicJsonType, typename ArithmeticType, enable_if_t <
enable_if_t < std::is_arithmetic<ArithmeticType>::value and
std::is_arithmetic<ArithmeticType>::value and not std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value and
not std::is_same<ArithmeticType, not std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value and
typename BasicJsonType::number_unsigned_t>::value and not std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value and
not std::is_same<ArithmeticType, not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
typename BasicJsonType::number_integer_t>::value and int> = 0>
not std::is_same<ArithmeticType,
typename BasicJsonType::number_float_t>::value and
not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
int > = 0 >
void from_json(const BasicJsonType& j, ArithmeticType& val) void from_json(const BasicJsonType& j, ArithmeticType& val)
{ {
switch (static_cast<value_t>(j)) switch (static_cast<value_t>(j))
{ {
case value_t::number_unsigned: case value_t::number_unsigned:
val = static_cast<ArithmeticType>( val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
break; break;
case value_t::number_integer: case value_t::number_integer:
val = static_cast<ArithmeticType>( val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
break; break;
case value_t::number_float: case value_t::number_float:
val = static_cast<ArithmeticType>( val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
break; break;
case value_t::boolean: case value_t::boolean:
val = static_cast<ArithmeticType>( val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());
*j.template get_ptr<const typename BasicJsonType::boolean_t*>());
break; break;
default: default:
JSON_THROW( JSON_THROW(std::domain_error("type must be number, but is " + j.type_name()));
std::domain_error("type must be number, but is " + j.type_name()));
} }
} }
struct to_json_fn struct to_json_fn
{ {
template <typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
auto call(BasicJsonType& j, T&& val, priority_tag<1>) const auto call(BasicJsonType& j, T&& val, priority_tag<1>) const noexcept(noexcept(to_json(j, std::forward<T>(val))))
noexcept(noexcept(to_json(j, std::forward<T>(val)))) -> decltype(to_json(j, std::forward<T>(val)), void())
-> decltype(to_json(j, std::forward<T>(val)),
void())
{ {
return to_json(j, std::forward<T>(val)); return to_json(j, std::forward<T>(val));
} }
template <typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
void call(BasicJsonType&, T&&, priority_tag<0>) const noexcept void call(BasicJsonType&, T&&, priority_tag<0>) const noexcept
{ {
static_assert(sizeof(BasicJsonType) == 0, "to_json method in T's namespace can not be called"); static_assert(sizeof(BasicJsonType) == 0, "to_json method in T's namespace can not be called");
} }
public: public:
template <typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
void operator()(BasicJsonType& j, T&& val) const void operator()(BasicJsonType& j, T&& val) const
noexcept(noexcept(std::declval<to_json_fn>().call(j, std::forward<T>(val), priority_tag<1> {}))) noexcept(noexcept(std::declval<to_json_fn>().call(j, std::forward<T>(val), priority_tag<1> {})))
{ {
@ -833,23 +848,23 @@ struct to_json_fn
struct from_json_fn struct from_json_fn
{ {
private: private:
template <typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
auto call(const BasicJsonType& j, T& val, priority_tag<1>) const auto call(const BasicJsonType& j, T& val, priority_tag<1>) const
noexcept(noexcept(from_json(j, val))) noexcept(noexcept(from_json(j, val)))
-> decltype(from_json(j, val), void()) -> decltype(from_json(j, val), void())
{ {
return from_json(j, val); return from_json(j, val);
} }
template <typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
void call(const BasicJsonType&, T&, priority_tag<0>) const noexcept void call(const BasicJsonType&, T&, priority_tag<0>) const noexcept
{ {
static_assert(sizeof(BasicJsonType) == 0, "from_json method in T's namespace can not be called"); static_assert(sizeof(BasicJsonType) == 0, "from_json method in T's namespace can not be called");
} }
public: public:
template <typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
void operator()(const BasicJsonType& j, T& val) const void operator()(const BasicJsonType& j, T& val) const
noexcept(noexcept(std::declval<from_json_fn>().call(j, val, priority_tag<1> {}))) noexcept(noexcept(std::declval<from_json_fn>().call(j, val, priority_tag<1> {})))
{ {
return call(j, val, priority_tag<1> {}); return call(j, val, priority_tag<1> {});
@ -857,15 +872,16 @@ struct from_json_fn
}; };
// taken from ranges-v3 // taken from ranges-v3
template <typename T> template<typename T>
struct static_const struct static_const
{ {
static constexpr T value{}; static constexpr T value{};
}; };
template <typename T> template<typename T>
constexpr T static_const<T>::value; constexpr T static_const<T>::value;
/*! /*!
@brief helper class to create locales with decimal point @brief helper class to create locales with decimal point
@ -885,7 +901,8 @@ struct DecimalSeparator : std::numpunct<char>
return '.'; return '.';
} }
}; };
} } // namespace detail
namespace namespace
{ {
@ -895,16 +912,16 @@ constexpr const auto& from_json = detail::static_const<detail::from_json_fn>::va
// default JSONSerializer template argument, doesn't care about template argument // default JSONSerializer template argument, doesn't care about template argument
// will use ADL for serialization // will use ADL for serialization
template <typename = void, typename = void> template<typename = void, typename = void>
struct adl_serializer struct adl_serializer
{ {
template <typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
static void from_json(BasicJsonType&& j, T& val) noexcept(noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val))) static void from_json(BasicJsonType&& j, T& val) noexcept(noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val)))
{ {
::nlohmann::from_json(std::forward<BasicJsonType>(j), val); ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
} }
template <typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
static void to_json(BasicJsonType& j, T&& val) noexcept( static void to_json(BasicJsonType& j, T&& val) noexcept(
noexcept(::nlohmann::to_json(j, std::forward<T>(val)))) noexcept(::nlohmann::to_json(j, std::forward<T>(val))))
{ {
@ -912,6 +929,7 @@ struct adl_serializer
} }
}; };
/*! /*!
@brief a class to store JSON values @brief a class to store JSON values
@ -1005,7 +1023,7 @@ template <
class basic_json class basic_json
{ {
private: private:
template <detail::value_t> friend struct detail::external_constructor; template<detail::value_t> friend struct detail::external_constructor;
/// 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,
@ -1017,7 +1035,7 @@ class basic_json
template<typename U> class iter_impl; template<typename U> class iter_impl;
template<typename Base> class json_reverse_iterator; template<typename Base> class json_reverse_iterator;
class json_pointer; class json_pointer;
template <typename T, typename SFINAE> template<typename T, typename SFINAE>
using json_serializer = JSONSerializer<T, SFINAE>; using json_serializer = JSONSerializer<T, SFINAE>;
///////////////////// /////////////////////
@ -1904,13 +1922,13 @@ class basic_json
@since version 2.1.0 @since version 2.1.0
*/ */
template <typename T, typename U = detail::uncvref_t<T>, template<typename T, typename U = detail::uncvref_t<T>,
detail::enable_if_t<not std::is_base_of<std::istream, U>::value and detail::enable_if_t<not std::is_base_of<std::istream, U>::value and
not std::is_same<U, basic_json_t>::value and not std::is_same<U, basic_json_t>::value and
not detail::is_basic_json_nested_type< not detail::is_basic_json_nested_type<
basic_json_t, U>::value and basic_json_t, U>::value and
detail::has_to_json<basic_json, U>::value, detail::has_to_json<basic_json, U>::value,
int> = 0> int> = 0>
basic_json(T && val) noexcept(noexcept(JSONSerializer<U>::to_json( basic_json(T && val) noexcept(noexcept(JSONSerializer<U>::to_json(
std::declval<basic_json_t&>(), std::forward<T>(val)))) std::declval<basic_json_t&>(), std::forward<T>(val))))
{ {
@ -5714,6 +5732,13 @@ class basic_json
/// @} /// @}
public: public:
//////////////////////////////////////////
// lexicographical comparison operators //
//////////////////////////////////////////
/// @name lexicographical comparison operators
/// @{
/*! /*!
@brief comparison: equal @brief comparison: equal
@ -9945,7 +9970,7 @@ class basic_json
for (; curptr < m_cursor; curptr++) for (; curptr < m_cursor; curptr++)
{ {
// quickly skip tests if a digit // quickly skip tests if a digit
if (*curptr < '0' || *curptr > '9') if (*curptr < '0' or* curptr > '9')
{ {
if (*curptr == '.') if (*curptr == '.')
{ {