From f6febbe359f0936c411fac9788985118aa82fdef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= <theo.delrieu@tanker.io> Date: Tue, 24 Jul 2018 13:22:44 +0200 Subject: [PATCH] split meta.hpp, add detected_t (used to define concepts) --- Makefile | 5 +- .../nlohmann/detail/conversions/from_json.hpp | 3 +- .../nlohmann/detail/conversions/to_json.hpp | 3 +- .../nlohmann/detail/iterators/iter_impl.hpp | 2 +- include/nlohmann/detail/meta/cpp_future.hpp | 83 ++++++++++++++++ include/nlohmann/detail/meta/detected.hpp | 56 +++++++++++ .../detail/{meta.hpp => meta/type_traits.hpp} | 76 +-------------- include/nlohmann/detail/meta/void_t.hpp | 10 ++ include/nlohmann/detail/output/serializer.hpp | 2 +- include/nlohmann/json.hpp | 3 +- single_include/nlohmann/json.hpp | 96 +++++++++++-------- test/src/unit-inspection.cpp | 4 +- 12 files changed, 222 insertions(+), 121 deletions(-) create mode 100644 include/nlohmann/detail/meta/cpp_future.hpp create mode 100644 include/nlohmann/detail/meta/detected.hpp rename include/nlohmann/detail/{meta.hpp => meta/type_traits.hpp} (74%) create mode 100644 include/nlohmann/detail/meta/void_t.hpp diff --git a/Makefile b/Makefile index 1e121788..36b01450 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,10 @@ SRCS = include/nlohmann/json.hpp \ include/nlohmann/detail/json_ref.hpp \ include/nlohmann/detail/macro_scope.hpp \ include/nlohmann/detail/macro_unscope.hpp \ - include/nlohmann/detail/meta.hpp \ + include/nlohmann/detail/meta/cpp_future.hpp \ + include/nlohmann/detail/meta/detected.hpp \ + include/nlohmann/detail/meta/type_traits.hpp \ + include/nlohmann/detail/meta/void_t.hpp \ include/nlohmann/detail/output/binary_writer.hpp \ include/nlohmann/detail/output/output_adapters.hpp \ include/nlohmann/detail/output/serializer.hpp \ diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index b092c8cc..5956352f 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -15,7 +15,8 @@ #include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/macro_scope.hpp> -#include <nlohmann/detail/meta.hpp> +#include <nlohmann/detail/meta/cpp_future.hpp> +#include <nlohmann/detail/meta/type_traits.hpp> #include <nlohmann/detail/value_t.hpp> namespace nlohmann diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp index 07946f55..35be5de4 100644 --- a/include/nlohmann/detail/conversions/to_json.hpp +++ b/include/nlohmann/detail/conversions/to_json.hpp @@ -8,7 +8,8 @@ #include <valarray> // valarray #include <vector> // vector -#include <nlohmann/detail/meta.hpp> +#include <nlohmann/detail/meta/cpp_future.hpp> +#include <nlohmann/detail/meta/type_traits.hpp> #include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/iterators/iteration_proxy.hpp> diff --git a/include/nlohmann/detail/iterators/iter_impl.hpp b/include/nlohmann/detail/iterators/iter_impl.hpp index f34f7a55..adcd8a37 100644 --- a/include/nlohmann/detail/iterators/iter_impl.hpp +++ b/include/nlohmann/detail/iterators/iter_impl.hpp @@ -8,7 +8,7 @@ #include <nlohmann/detail/iterators/internal_iterator.hpp> #include <nlohmann/detail/iterators/primitive_iterator.hpp> #include <nlohmann/detail/macro_scope.hpp> -#include <nlohmann/detail/meta.hpp> +#include <nlohmann/detail/meta/cpp_future.hpp> #include <nlohmann/detail/value_t.hpp> namespace nlohmann diff --git a/include/nlohmann/detail/meta/cpp_future.hpp b/include/nlohmann/detail/meta/cpp_future.hpp new file mode 100644 index 00000000..d12d6bdb --- /dev/null +++ b/include/nlohmann/detail/meta/cpp_future.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include <ciso646> // not +#include <cstddef> // size_t +#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type + +namespace nlohmann +{ +namespace detail +{ +// alias templates to reduce boilerplate +template<bool B, typename T = void> +using enable_if_t = typename std::enable_if<B, T>::type; + +template<typename T> +using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template<std::size_t... Ints> +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template<class Sequence1, class Sequence2> +struct merge_and_renumber; + +template<std::size_t... I1, std::size_t... I2> +struct merge_and_renumber<index_sequence<I1...>, index_sequence<I2...>> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template<std::size_t N> +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template<typename... Ts> +using index_sequence_for = make_index_sequence<sizeof...(Ts)>; + +/* +Implementation of two 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 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, not B::value> {}; + +// dispatch utility (taken from ranges-v3) +template<unsigned N> struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template<typename T> +struct static_const +{ + static constexpr T value{}; +}; + +template<typename T> +constexpr T static_const<T>::value; +} +} diff --git a/include/nlohmann/detail/meta/detected.hpp b/include/nlohmann/detail/meta/detected.hpp new file mode 100644 index 00000000..ed1d6ac7 --- /dev/null +++ b/include/nlohmann/detail/meta/detected.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include <type_traits> + +#include <nlohmann/detail/meta/void_t.hpp> + +// http://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + void operator=(nonesuch const&) = delete; +}; + +template <class Default, + class AlwaysVoid, + template <class...> class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template <class Default, template <class...> class Op, class... Args> +struct detector<Default, void_t<Op<Args...>>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op<Args...>; +}; + +template <template <class...> class Op, class... Args> +using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t; + +template <template <class...> class Op, class... Args> +using detected_t = typename detector<nonesuch, void, Op, Args...>::type; + +template <class Default, template <class...> class Op, class... Args> +using detected_or = detector<Default, void, Op, Args...>; + +template <class Default, template <class...> class Op, class... Args> +using detected_or_t = typename detected_or<Default, Op, Args...>::type; + +template <class Expected, template <class...> class Op, class... Args> +using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>; + +template <class To, template <class...> class Op, class... Args> +using is_detected_convertible = + std::is_convertible<detected_t<Op, Args...>, To>; +} +} diff --git a/include/nlohmann/detail/meta.hpp b/include/nlohmann/detail/meta/type_traits.hpp similarity index 74% rename from include/nlohmann/detail/meta.hpp rename to include/nlohmann/detail/meta/type_traits.hpp index 50200304..caf81222 100644 --- a/include/nlohmann/detail/meta.hpp +++ b/include/nlohmann/detail/meta/type_traits.hpp @@ -1,12 +1,12 @@ #pragma once #include <ciso646> // not -#include <cstddef> // size_t #include <limits> // numeric_limits -#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type #include <utility> // declval #include <nlohmann/json_fwd.hpp> +#include <nlohmann/detail/meta/cpp_future.hpp> #include <nlohmann/detail/macro_scope.hpp> namespace nlohmann @@ -30,68 +30,6 @@ template<typename> struct is_basic_json : std::false_type {}; NLOHMANN_BASIC_JSON_TPL_DECLARATION struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {}; -// alias templates to reduce boilerplate -template<bool B, typename T = void> -using enable_if_t = typename std::enable_if<B, T>::type; - -template<typename T> -using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type; - -// implementation of C++14 index_sequence and affiliates -// source: https://stackoverflow.com/a/32223343 -template<std::size_t... Ints> -struct index_sequence -{ - using type = index_sequence; - using value_type = std::size_t; - static constexpr std::size_t size() noexcept - { - return sizeof...(Ints); - } -}; - -template<class Sequence1, class Sequence2> -struct merge_and_renumber; - -template<std::size_t... I1, std::size_t... I2> -struct merge_and_renumber<index_sequence<I1...>, index_sequence<I2...>> - : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; - -template<std::size_t N> -struct make_index_sequence - : merge_and_renumber < typename make_index_sequence < N / 2 >::type, - typename make_index_sequence < N - N / 2 >::type > {}; - -template<> struct make_index_sequence<0> : index_sequence<> {}; -template<> struct make_index_sequence<1> : index_sequence<0> {}; - -template<typename... Ts> -using index_sequence_for = make_index_sequence<sizeof...(Ts)>; - -/* -Implementation of two 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 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, not B::value> {}; - -// dispatch utility (taken from ranges-v3) -template<unsigned N> struct priority_tag : priority_tag < N - 1 > {}; -template<> struct priority_tag<0> {}; - //////////////////////// // has_/is_ functions // //////////////////////// @@ -264,15 +202,5 @@ struct is_compatible_type is_compatible_complete_type<BasicJsonType, CompatibleType>> { }; - -// taken from ranges-v3 -template<typename T> -struct static_const -{ - static constexpr T value{}; -}; - -template<typename T> -constexpr T static_const<T>::value; } } diff --git a/include/nlohmann/detail/meta/void_t.hpp b/include/nlohmann/detail/meta/void_t.hpp new file mode 100644 index 00000000..66c4a359 --- /dev/null +++ b/include/nlohmann/detail/meta/void_t.hpp @@ -0,0 +1,10 @@ +#pragma once + +namespace nlohmann +{ +namespace detail +{ +template <typename...> +using void_t = void; +} +} diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index c0f81776..de3676ac 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -16,7 +16,7 @@ #include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/conversions/to_chars.hpp> #include <nlohmann/detail/macro_scope.hpp> -#include <nlohmann/detail/meta.hpp> +#include <nlohmann/detail/meta/cpp_future.hpp> #include <nlohmann/detail/output/output_adapters.hpp> #include <nlohmann/detail/value_t.hpp> diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 85868f63..9621e2ba 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -48,7 +48,8 @@ SOFTWARE. #include <nlohmann/json_fwd.hpp> #include <nlohmann/detail/macro_scope.hpp> -#include <nlohmann/detail/meta.hpp> +#include <nlohmann/detail/meta/cpp_future.hpp> +#include <nlohmann/detail/meta/type_traits.hpp> #include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/conversions/from_json.hpp> diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index d0c1f02f..9350590c 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -238,41 +238,17 @@ contains a `mapped_type`, whereas `std::vector` fails the test. std::is_integral<decltype(detect(std::declval<T>()))>::value; \ } -// #include <nlohmann/detail/meta.hpp> +// #include <nlohmann/detail/meta/cpp_future.hpp> #include <ciso646> // not #include <cstddef> // size_t -#include <limits> // numeric_limits #include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type -#include <utility> // declval - -// #include <nlohmann/json_fwd.hpp> - -// #include <nlohmann/detail/macro_scope.hpp> - namespace nlohmann { -/*! -@brief detail namespace with internal helper functions - -This namespace collects functions that should not be exposed, -implementations of some @ref basic_json methods, and meta-programming helpers. - -@since version 2.1.0 -*/ namespace detail { -///////////// -// helpers // -///////////// - -template<typename> struct is_basic_json : std::false_type {}; - -NLOHMANN_BASIC_JSON_TPL_DECLARATION -struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {}; - // alias templates to reduce boilerplate template<bool B, typename T = void> using enable_if_t = typename std::enable_if<B, T>::type; @@ -335,6 +311,54 @@ template<class B> struct negation : std::integral_constant<bool, not B::value> { template<unsigned N> struct priority_tag : priority_tag < N - 1 > {}; template<> struct priority_tag<0> {}; +// taken from ranges-v3 +template<typename T> +struct static_const +{ + static constexpr T value{}; +}; + +template<typename T> +constexpr T static_const<T>::value; +} +} + +// #include <nlohmann/detail/meta/type_traits.hpp> + + +#include <ciso646> // not +#include <limits> // numeric_limits +#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type +#include <utility> // declval + +// #include <nlohmann/json_fwd.hpp> + +// #include <nlohmann/detail/meta/cpp_future.hpp> + +// #include <nlohmann/detail/macro_scope.hpp> + + +namespace nlohmann +{ +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ +///////////// +// helpers // +///////////// + +template<typename> struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {}; + //////////////////////// // has_/is_ functions // //////////////////////// @@ -507,16 +531,6 @@ struct is_compatible_type is_compatible_complete_type<BasicJsonType, CompatibleType>> { }; - -// taken from ranges-v3 -template<typename T> -struct static_const -{ - static constexpr T value{}; -}; - -template<typename T> -constexpr T static_const<T>::value; } } @@ -950,7 +964,9 @@ inline bool operator<(const value_t lhs, const value_t rhs) noexcept // #include <nlohmann/detail/macro_scope.hpp> -// #include <nlohmann/detail/meta.hpp> +// #include <nlohmann/detail/meta/cpp_future.hpp> + +// #include <nlohmann/detail/meta/type_traits.hpp> // #include <nlohmann/detail/value_t.hpp> @@ -1335,7 +1351,9 @@ constexpr const auto& from_json = detail::static_const<detail::from_json_fn>::va #include <valarray> // valarray #include <vector> // vector -// #include <nlohmann/detail/meta.hpp> +// #include <nlohmann/detail/meta/cpp_future.hpp> + +// #include <nlohmann/detail/meta/type_traits.hpp> // #include <nlohmann/detail/value_t.hpp> @@ -4873,7 +4891,7 @@ template<typename BasicJsonType> struct internal_iterator // #include <nlohmann/detail/macro_scope.hpp> -// #include <nlohmann/detail/meta.hpp> +// #include <nlohmann/detail/meta/cpp_future.hpp> // #include <nlohmann/detail/value_t.hpp> @@ -9488,7 +9506,7 @@ char* to_chars(char* first, char* last, FloatType value) // #include <nlohmann/detail/macro_scope.hpp> -// #include <nlohmann/detail/meta.hpp> +// #include <nlohmann/detail/meta/cpp_future.hpp> // #include <nlohmann/detail/output/output_adapters.hpp> diff --git a/test/src/unit-inspection.cpp b/test/src/unit-inspection.cpp index 4c03cf96..e50c7338 100644 --- a/test/src/unit-inspection.cpp +++ b/test/src/unit-inspection.cpp @@ -317,8 +317,8 @@ TEST_CASE("object inspection") SECTION("round trips") { for (const auto& s : - {"3.141592653589793", "1000000000000000010E5" - }) + {"3.141592653589793", "1000000000000000010E5" + }) { json j1 = json::parse(s); std::string s1 = j1.dump();