remove some useless checks, format a bit, added some comments

This commit is contained in:
Théo Delrieu 2016-11-24 13:22:46 +01:00 committed by Théo DELRIEU
parent 907484fb43
commit 74bb11d92c

View file

@ -130,11 +130,17 @@ using conditional_t = typename std::conditional<If, Then, Else>::type;
namespace detail namespace detail
{ {
// implementation of 3 C++17 constructs: conjunction, disjunction, negation. // Implementation of 3 C++17 constructs: conjunction, disjunction, negation.
// This is needed to avoid evaluating all the traits, MSVC cannot compile due // This is needed to avoid evaluating all the traits in a condition
// to std::is_constructible<basic_json_t, void> being instantiated //
// (void -> back_insert_iterator::value_type) // For example: not std::is_same<void, T>::value and has_value_type<T>::value
// this could slow down compilation, since this implementation is taken from the example in cppreference... // 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...> struct conjunction : std::true_type {};
template <class B1> struct conjunction<B1> : B1 {}; template <class B1> struct conjunction<B1> : B1 {};
template <class B1, class... Bn> template <class B1, class... Bn>
@ -192,6 +198,8 @@ struct is_compatible_object_type_impl<true, RealType, CompatibleObjectType>
template<class RealType, class CompatibleObjectType> template<class RealType, class CompatibleObjectType>
struct is_compatible_object_type 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>>, conjunction<negation<std::is_same<void, CompatibleObjectType>>,
has_mapped_type<CompatibleObjectType>, has_mapped_type<CompatibleObjectType>,
@ -223,17 +231,14 @@ struct is_compatible_array_type_impl<true, BasicJson, CompatibleArrayType>
template <class BasicJson, class CompatibleArrayType> template <class BasicJson, class CompatibleArrayType>
struct is_compatible_array_type struct is_compatible_array_type
{ {
static auto constexpr value = disjunction< // the check for CompatibleArrayType = void is done in is_compatible_object_type
std::is_same<BasicJson, CompatibleArrayType>, // but we need the conjunction here as well
is_compatible_array_type_impl< static auto constexpr value = is_compatible_array_type_impl<
conjunction<negation< conjunction<negation<is_compatible_object_type<
// MSVC has troubles without this typename BasicJson::object_t, CompatibleArrayType>>,
std::is_same<void, CompatibleArrayType>>, has_value_type<CompatibleArrayType>,
negation<is_compatible_object_type< has_iterator<CompatibleArrayType>>::value,
typename BasicJson::object_t, CompatibleArrayType>>, BasicJson, CompatibleArrayType>::value;
has_value_type<CompatibleArrayType>,
has_iterator<CompatibleArrayType>>::value,
BasicJson, CompatibleArrayType>>::value;
}; };
template <bool, typename, typename> template <bool, typename, typename>
@ -242,11 +247,14 @@ 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>
{ {
using RealLimits = std::numeric_limits<RealIntegerType>;
using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
static constexpr auto value = static constexpr auto value =
std::is_constructible<RealIntegerType, std::is_constructible<RealIntegerType,
CompatibleNumberIntegerType>::value and CompatibleNumberIntegerType>::value and
std::numeric_limits<CompatibleNumberIntegerType>::is_integer and CompatibleLimits::is_integer and
std::numeric_limits<CompatibleNumberIntegerType>::is_signed; RealLimits::is_signed == CompatibleLimits::is_signed;
}; };
template <typename RealIntegerType, typename CompatibleNumberIntegerType> template <typename RealIntegerType, typename CompatibleNumberIntegerType>
@ -257,27 +265,6 @@ struct is_compatible_integer_type
CompatibleNumberIntegerType>::value; CompatibleNumberIntegerType>::value;
}; };
template <bool, typename, typename>
struct is_compatible_unsigned_integer_type_impl : std::false_type{};
template <typename RealUnsignedType, typename CompatibleNumberUnsignedType>
struct is_compatible_unsigned_integer_type_impl<true, RealUnsignedType, CompatibleNumberUnsignedType>
{
static constexpr auto value =
std::is_constructible<RealUnsignedType,
CompatibleNumberUnsignedType>::value and
std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
not std::numeric_limits<CompatibleNumberUnsignedType>::is_signed;
};
template <typename RealUnsignedType, typename CompatibleNumberUnsignedType>
struct is_compatible_unsigned_integer_type
{
static constexpr auto value = is_compatible_unsigned_integer_type_impl<
std::is_arithmetic<CompatibleNumberUnsignedType>::value, RealUnsignedType,
CompatibleNumberUnsignedType>::value;
};
template <typename RealFloat, typename CompatibleFloat> template <typename RealFloat, typename CompatibleFloat>
struct is_compatible_float_type struct is_compatible_float_type
{ {
@ -298,8 +285,8 @@ struct is_compatible_basic_json_type
is_compatible_float_type<typename BasicJson::number_float_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, is_compatible_integer_type<typename BasicJson::number_integer_t,
T>::value or T>::value or
is_compatible_unsigned_integer_type<typename BasicJson::number_unsigned_t, is_compatible_integer_type<typename BasicJson::number_unsigned_t,
T>::value; T>::value;
}; };
template <template <typename, typename> class JSONSerializer, typename Json, template <template <typename, typename> class JSONSerializer, typename Json,
@ -334,11 +321,14 @@ public:
detect(std::declval<JSONSerializer<T, void>>()))>::value; detect(std::declval<JSONSerializer<T, void>>()))>::value;
}; };
// those declarations are needed to workaround a MSVC bug related to ADL
// (idea taken from MSVC-Ranges implementation
void to_json(); void to_json();
void from_json(); void from_json();
struct to_json_fn struct to_json_fn
{ {
// is it really useful to mark those as constexpr?
template <typename Json, typename T> template <typename Json, typename T>
constexpr auto operator()(Json &&j, T &&val) const constexpr auto operator()(Json &&j, T &&val) const
noexcept(noexcept(to_json(std::forward<Json>(j), std::forward<T>(val)))) noexcept(noexcept(to_json(std::forward<Json>(j), std::forward<T>(val))))
@ -357,7 +347,7 @@ struct from_json_fn
-> decltype(from_json(std::forward<Json>(j), val), void()) -> decltype(from_json(std::forward<Json>(j), val), void())
{ {
return from_json(std::forward<Json>(j), val); return from_json(std::forward<Json>(j), val);
} }
}; };
/*! /*!
@ -384,18 +374,18 @@ struct DecimalSeparator : std::numpunct<char>
// taken from ranges-v3 // taken from ranges-v3
// TODO add doc // TODO add doc
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;
inline namespace inline namespace
{ {
constexpr auto const& to_json = _static_const<detail::to_json_fn>::value; constexpr auto const& to_json = static_const<detail::to_json_fn>::value;
constexpr auto const& from_json = _static_const<detail::from_json_fn>::value; constexpr auto const& from_json = static_const<detail::from_json_fn>::value;
} }
// default JSONSerializer template argument, doesn't care about template argument // default JSONSerializer template argument, doesn't care about template argument
@ -1493,14 +1483,16 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
template<class CompatibleObjectType, enable_if_t<detail::is_compatible_object_type<object_t, CompatibleObjectType>::value, int> = 0> template <class CompatibleObjectType,
basic_json(const CompatibleObjectType& val) enable_if_t<detail::is_compatible_object_type<
: m_type(value_t::object) object_t, CompatibleObjectType>::value,
int> = 0>
basic_json(const CompatibleObjectType &val) : m_type(value_t::object)
{ {
using std::begin; using std::begin;
using std::end; using std::end;
m_value.object = create<object_t>(begin(val), end(val)); m_value.object = create<object_t>(begin(val), end(val));
assert_invariant(); assert_invariant();
} }
/*! /*!
@ -1554,16 +1546,12 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
template < template <class CompatibleArrayType,
class CompatibleArrayType, enable_if_t<detail::is_compatible_array_type<
enable_if_t< basic_json_t, CompatibleArrayType>::value,
detail::disjunction< int> = 0>
// MSVC.. basic_json(const CompatibleArrayType &val) : m_type(value_t::array)
std::is_same<uncvref_t<CompatibleArrayType>, basic_json_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::begin;
using std::end; using std::end;
m_value.array = create<array_t>(begin(val), end(val)); m_value.array = create<array_t>(begin(val), end(val));
@ -1571,19 +1559,18 @@ class basic_json
} }
// constructor chosen when JSONSerializer::to_json exists for type T // constructor chosen when:
// first check avoids being chosen instead of move/copy constructor // - 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 < template <
typename T, typename T,
enable_if_t< enable_if_t<not std::is_base_of<std::istream, uncvref_t<T>>::value and
detail::conjunction< not detail::is_compatible_basic_json_type<
detail::negation<std::is_same<uncvref_t<T>, basic_json_t>>, uncvref_t<T>, basic_json_t>::value and
detail::negation<std::is_base_of<std::istream, uncvref_t<T>>>, detail::has_to_json<JSONSerializer, basic_json,
detail::negation<detail::is_compatible_basic_json_type< uncvref_t<T>>::value,
uncvref_t<T>, basic_json_t>>, int> = 0>
detail::has_to_json<JSONSerializer, basic_json,
uncvref_t<T>>>::value,
int> = 0>
explicit basic_json(T &&val) explicit basic_json(T &&val)
{ {
JSONSerializer<uncvref_t<T>>::to_json(*this, std::forward<T>(val)); JSONSerializer<uncvref_t<T>>::to_json(*this, std::forward<T>(val));
@ -1842,7 +1829,7 @@ class basic_json
*/ */
template < template <
typename CompatibleNumberUnsignedType, typename CompatibleNumberUnsignedType,
enable_if_t<detail::is_compatible_unsigned_integer_type< enable_if_t<detail::is_compatible_integer_type<
number_unsigned_t, CompatibleNumberUnsignedType>::value, number_unsigned_t, CompatibleNumberUnsignedType>::value,
int> = 0> int> = 0>
basic_json(const CompatibleNumberUnsignedType val) noexcept basic_json(const CompatibleNumberUnsignedType val) noexcept
@ -3257,21 +3244,19 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
template <typename ValueType, template <typename ValueType,
enable_if_t< enable_if_t<not std::is_pointer<ValueType>::value, int> = 0>
not std::is_pointer<ValueType>::value,
int> = 0>
auto get() const auto get() const
-> decltype(this->get_impl(static_cast<ValueType *>(nullptr))) { -> decltype(this->get_impl(static_cast<ValueType *>(nullptr)))
{
return get_impl(static_cast<ValueType *>(nullptr)); return get_impl(static_cast<ValueType *>(nullptr));
} }
template < template <
typename T, typename T,
enable_if_t<detail::conjunction< enable_if_t<not detail::is_compatible_basic_json_type<
detail::negation<detail::is_compatible_basic_json_type< uncvref_t<T>, basic_json_t>::value and
uncvref_t<T>, basic_json_t>>,
detail::has_from_json<JSONSerializer, basic_json_t, detail::has_from_json<JSONSerializer, basic_json_t,
uncvref_t<T>>>::value, uncvref_t<T>>::value,
int> = 0> int> = 0>
auto get() const -> uncvref_t<T> auto get() const -> uncvref_t<T>
{ {