123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- // Copyright 2015-2019 Hans Dembinski
- //
- // Distributed under the Boost Software License, Version 1.0.
- // (See accompanying file LICENSE_1_0.txt
- // or copy at http://www.boost.org/LICENSE_1_0.txt)
- #ifndef BOOST_HISTOGRAM_DETAIL_DETECT_HPP
- #define BOOST_HISTOGRAM_DETAIL_DETECT_HPP
- #include <boost/histogram/fwd.hpp>
- #include <boost/mp11/function.hpp> // mp_and, mp_or
- #include <boost/mp11/integral.hpp> // mp_not
- #include <boost/mp11/list.hpp> // mp_first
- #include <iterator>
- #include <tuple>
- #include <type_traits>
- // forward declaration
- namespace boost {
- namespace variant2 {
- template <class...>
- class variant;
- } // namespace variant2
- } // namespace boost
- namespace boost {
- namespace histogram {
- namespace detail {
- #define BOOST_HISTOGRAM_DETAIL_DETECT(name, cond) \
- template <class U> \
- struct name##_impl { \
- typedef char yes[1]; \
- typedef char no[2]; \
- template <class T> \
- static yes& test(T& t, decltype(cond, 0)); \
- template <class T> \
- static no& test(T&, float); \
- using type = \
- std::integral_constant<bool, (sizeof(test(std::declval<U&>(), 0)) == 1)>; \
- }; \
- template <class T> \
- using name = typename name##_impl<T>::type
- #define BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(name, cond) \
- template <class V, class W> \
- struct name##_impl { \
- typedef char yes[1]; \
- typedef char no[2]; \
- template <class T, class U> \
- static yes& test(decltype(cond, 0)); \
- template <class, class> \
- static no& test(float); \
- using type = std::integral_constant<bool, (sizeof(test<V, W>(0)) == 1)>; \
- }; \
- template <class T, class U = T> \
- using name = typename name##_impl<T, U>::type
- // reset has overloads, trying to get pmf in this case always fails
- BOOST_HISTOGRAM_DETAIL_DETECT(has_method_reset, t.reset(0));
- BOOST_HISTOGRAM_DETAIL_DETECT(is_indexable, t[0]);
- BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(
- is_transform,
- (std::declval<T&>().inverse(std::declval<T&>().forward(std::declval<U>()))));
- BOOST_HISTOGRAM_DETAIL_DETECT(is_indexable_container,
- (t[0], t.size(), std::begin(t), std::end(t)));
- BOOST_HISTOGRAM_DETAIL_DETECT(is_vector_like,
- (t[0], t.size(), t.resize(0), std::begin(t), std::end(t)));
- BOOST_HISTOGRAM_DETAIL_DETECT(is_array_like, (t[0], t.size(), std::tuple_size<T>::value,
- std::begin(t), std::end(t)));
- BOOST_HISTOGRAM_DETAIL_DETECT(is_map_like, ((typename T::key_type*)nullptr,
- (typename T::mapped_type*)nullptr,
- std::begin(t), std::end(t)));
- // ok: is_axis is false for axis::variant, because T::index is templated
- BOOST_HISTOGRAM_DETAIL_DETECT(is_axis, (t.size(), &T::index));
- BOOST_HISTOGRAM_DETAIL_DETECT(is_iterable, (std::begin(t), std::end(t)));
- BOOST_HISTOGRAM_DETAIL_DETECT(is_iterator,
- (typename std::iterator_traits<T>::iterator_category{}));
- BOOST_HISTOGRAM_DETAIL_DETECT(is_streamable, (std::declval<std::ostream&>() << t));
- BOOST_HISTOGRAM_DETAIL_DETECT(has_operator_preincrement, ++t);
- BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_equal, (std::declval<const T&>() ==
- std::declval<const U&>()));
- BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_radd,
- (std::declval<T&>() += std::declval<U>()));
- BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rsub,
- (std::declval<T&>() -= std::declval<U>()));
- BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rmul,
- (std::declval<T&>() *= std::declval<U>()));
- BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rdiv,
- (std::declval<T&>() /= std::declval<U>()));
- BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(
- has_method_eq, (std::declval<const T&>().operator==(std::declval<const U&>())));
- BOOST_HISTOGRAM_DETAIL_DETECT(has_threading_support, (T::has_threading_support));
- template <class T>
- using is_storage = mp11::mp_and<is_indexable_container<T>, has_method_reset<T>,
- has_threading_support<T>>;
- template <class T>
- using is_adaptible =
- mp11::mp_and<mp11::mp_not<is_storage<T>>,
- mp11::mp_or<is_vector_like<T>, is_array_like<T>, is_map_like<T>>>;
- template <class T>
- struct is_tuple_impl : std::false_type {};
- template <class... Ts>
- struct is_tuple_impl<std::tuple<Ts...>> : std::true_type {};
- template <class T>
- using is_tuple = typename is_tuple_impl<T>::type;
- template <class T>
- struct is_variant_impl : std::false_type {};
- template <class... Ts>
- struct is_variant_impl<boost::variant2::variant<Ts...>> : std::true_type {};
- template <class T>
- using is_variant = typename is_variant_impl<T>::type;
- template <class T>
- struct is_axis_variant_impl : std::false_type {};
- template <class... Ts>
- struct is_axis_variant_impl<axis::variant<Ts...>> : std::true_type {};
- template <class T>
- using is_axis_variant = typename is_axis_variant_impl<T>::type;
- template <class T>
- using is_any_axis = mp11::mp_or<is_axis<T>, is_axis_variant<T>>;
- template <class T>
- using is_sequence_of_axis = mp11::mp_and<is_iterable<T>, is_axis<mp11::mp_first<T>>>;
- template <class T>
- using is_sequence_of_axis_variant =
- mp11::mp_and<is_iterable<T>, is_axis_variant<mp11::mp_first<T>>>;
- template <class T>
- using is_sequence_of_any_axis =
- mp11::mp_and<is_iterable<T>, is_any_axis<mp11::mp_first<T>>>;
- // poor-mans concept checks
- template <class T, class = std::enable_if_t<is_storage<std::decay_t<T>>::value>>
- struct requires_storage {};
- template <class T, class _ = std::decay_t<T>,
- class = std::enable_if_t<(is_storage<_>::value || is_adaptible<_>::value)>>
- struct requires_storage_or_adaptible {};
- template <class T, class = std::enable_if_t<is_iterator<std::decay_t<T>>::value>>
- struct requires_iterator {};
- template <class T, class = std::enable_if_t<
- is_iterable<std::remove_cv_t<std::remove_reference_t<T>>>::value>>
- struct requires_iterable {};
- template <class T, class = std::enable_if_t<is_axis<std::decay_t<T>>::value>>
- struct requires_axis {};
- template <class T, class = std::enable_if_t<is_any_axis<std::decay_t<T>>::value>>
- struct requires_any_axis {};
- template <class T, class = std::enable_if_t<is_sequence_of_axis<std::decay_t<T>>::value>>
- struct requires_sequence_of_axis {};
- template <class T,
- class = std::enable_if_t<is_sequence_of_axis_variant<std::decay_t<T>>::value>>
- struct requires_sequence_of_axis_variant {};
- template <class T,
- class = std::enable_if_t<is_sequence_of_any_axis<std::decay_t<T>>::value>>
- struct requires_sequence_of_any_axis {};
- template <class T,
- class = std::enable_if_t<is_any_axis<mp11::mp_first<std::decay_t<T>>>::value>>
- struct requires_axes {};
- template <class T, class U,
- class = std::enable_if_t<is_transform<std::decay_t<T>, U>::value>>
- struct requires_transform {};
- } // namespace detail
- } // namespace histogram
- } // namespace boost
- #endif
|