File indexing completed on 2025-01-18 09:38:11
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_HISTOGRAM_DETAIL_DETECT_HPP
0008 #define BOOST_HISTOGRAM_DETAIL_DETECT_HPP
0009
0010 #include <boost/histogram/fwd.hpp>
0011 #include <boost/mp11/function.hpp> // mp_and, mp_or
0012 #include <boost/mp11/integral.hpp> // mp_not
0013 #include <boost/mp11/list.hpp> // mp_first
0014 #include <iterator>
0015 #include <tuple>
0016 #include <type_traits>
0017
0018
0019 namespace boost {
0020 namespace variant2 {
0021 template <class...>
0022 class variant;
0023 }
0024 }
0025
0026 namespace boost {
0027 namespace histogram {
0028 namespace detail {
0029
0030 template <class...>
0031 using void_t = void;
0032
0033 struct detect_base {
0034 template <class T>
0035 static T&& val();
0036 template <class T>
0037 static T& ref();
0038 template <class T>
0039 static T const& cref();
0040 };
0041
0042 #define BOOST_HISTOGRAM_DETAIL_DETECT(name, cond) \
0043 template <class U> \
0044 struct name##_impl : detect_base { \
0045 template <class T> \
0046 static mp11::mp_true test(T& t, decltype(cond, 0)); \
0047 template <class T> \
0048 static mp11::mp_false test(T&, float); \
0049 using type = decltype(test<U>(ref<U>(), 0)); \
0050 }; \
0051 template <class T> \
0052 using name = typename name##_impl<T>::type
0053
0054 #define BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(name, cond) \
0055 template <class V, class W> \
0056 struct name##_impl : detect_base { \
0057 template <class T, class U> \
0058 static mp11::mp_true test(T& t, U& u, decltype(cond, 0)); \
0059 template <class T, class U> \
0060 static mp11::mp_false test(T&, U&, float); \
0061 using type = decltype(test<V, W>(ref<V>(), ref<W>(), 0)); \
0062 }; \
0063 template <class T, class U = T> \
0064 using name = typename name##_impl<T, U>::type
0065
0066
0067 BOOST_HISTOGRAM_DETAIL_DETECT(has_method_reset, t.reset(0));
0068
0069 BOOST_HISTOGRAM_DETAIL_DETECT(is_indexable, t[0]);
0070
0071 BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(is_transform, (t.inverse(t.forward(u))));
0072
0073 BOOST_HISTOGRAM_DETAIL_DETECT(is_indexable_container,
0074 (t[0], t.size(), std::begin(t), std::end(t)));
0075
0076 BOOST_HISTOGRAM_DETAIL_DETECT(is_vector_like,
0077 (t[0], t.size(), t.resize(0), std::begin(t), std::end(t)));
0078
0079 BOOST_HISTOGRAM_DETAIL_DETECT(is_array_like, (t[0], t.size(), std::tuple_size<T>::value,
0080 std::begin(t), std::end(t)));
0081
0082 BOOST_HISTOGRAM_DETAIL_DETECT(is_map_like, ((typename T::key_type*)nullptr,
0083 (typename T::mapped_type*)nullptr,
0084 std::begin(t), std::end(t)));
0085
0086
0087 BOOST_HISTOGRAM_DETAIL_DETECT(is_axis, (t.size(), &T::index));
0088
0089 BOOST_HISTOGRAM_DETAIL_DETECT(is_iterable, (std::begin(t), std::end(t)));
0090
0091 BOOST_HISTOGRAM_DETAIL_DETECT(is_iterator,
0092 (typename std::iterator_traits<T>::iterator_category{}));
0093
0094 BOOST_HISTOGRAM_DETAIL_DETECT(is_streamable, (std::declval<std::ostream&>() << t));
0095
0096 BOOST_HISTOGRAM_DETAIL_DETECT(is_allocator, (&T::allocate, &T::deallocate));
0097
0098 BOOST_HISTOGRAM_DETAIL_DETECT(has_operator_preincrement, ++t);
0099
0100 BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_equal, (cref<T>() == u));
0101
0102 BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_radd, (t += u));
0103
0104 BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rsub, (t -= u));
0105
0106 BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rmul, (t *= u));
0107
0108 BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rdiv, (t /= u));
0109
0110 BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_method_eq, (cref<T>().operator==(u)));
0111
0112 BOOST_HISTOGRAM_DETAIL_DETECT(has_threading_support, (T::has_threading_support));
0113
0114
0115 BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(is_explicitly_convertible, static_cast<U>(t));
0116
0117 BOOST_HISTOGRAM_DETAIL_DETECT(is_complete, sizeof(T));
0118
0119 template <class T>
0120 using is_storage = mp11::mp_and<is_indexable_container<T>, has_method_reset<T>,
0121 has_threading_support<T>>;
0122
0123 template <class T>
0124 using is_adaptible =
0125 mp11::mp_and<mp11::mp_not<is_storage<T>>,
0126 mp11::mp_or<is_vector_like<T>, is_array_like<T>, is_map_like<T>>>;
0127
0128 template <class T>
0129 struct is_tuple_impl : std::false_type {};
0130
0131 template <class... Ts>
0132 struct is_tuple_impl<std::tuple<Ts...>> : std::true_type {};
0133
0134 template <class T>
0135 using is_tuple = typename is_tuple_impl<T>::type;
0136
0137 template <class T>
0138 struct is_variant_impl : std::false_type {};
0139
0140 template <class... Ts>
0141 struct is_variant_impl<boost::variant2::variant<Ts...>> : std::true_type {};
0142
0143 template <class T>
0144 using is_variant = typename is_variant_impl<T>::type;
0145
0146 template <class T>
0147 struct is_axis_variant_impl : std::false_type {};
0148
0149 template <class... Ts>
0150 struct is_axis_variant_impl<axis::variant<Ts...>> : std::true_type {};
0151
0152 template <class T>
0153 using is_axis_variant = typename is_axis_variant_impl<T>::type;
0154
0155 template <class T>
0156 using is_any_axis = mp11::mp_or<is_axis<T>, is_axis_variant<T>>;
0157
0158 template <class T>
0159 using is_sequence_of_axis = mp11::mp_and<is_iterable<T>, is_axis<mp11::mp_first<T>>>;
0160
0161 template <class T>
0162 using is_sequence_of_axis_variant =
0163 mp11::mp_and<is_iterable<T>, is_axis_variant<mp11::mp_first<T>>>;
0164
0165 template <class T>
0166 using is_sequence_of_any_axis =
0167 mp11::mp_and<is_iterable<T>, is_any_axis<mp11::mp_first<T>>>;
0168
0169
0170
0171 template <class T, class = std::enable_if_t<is_storage<std::decay_t<T>>::value>>
0172 struct requires_storage {};
0173
0174 template <class T, class _ = std::decay_t<T>,
0175 class = std::enable_if_t<(is_storage<_>::value || is_adaptible<_>::value)>>
0176 struct requires_storage_or_adaptible {};
0177
0178 template <class T, class = std::enable_if_t<is_iterator<std::decay_t<T>>::value>>
0179 struct requires_iterator {};
0180
0181 template <class T, class = std::enable_if_t<
0182 is_iterable<std::remove_cv_t<std::remove_reference_t<T>>>::value>>
0183 struct requires_iterable {};
0184
0185 template <class T, class = std::enable_if_t<is_axis<std::decay_t<T>>::value>>
0186 struct requires_axis {};
0187
0188 template <class T, class = std::enable_if_t<is_any_axis<std::decay_t<T>>::value>>
0189 struct requires_any_axis {};
0190
0191 template <class T, class = std::enable_if_t<is_sequence_of_axis<std::decay_t<T>>::value>>
0192 struct requires_sequence_of_axis {};
0193
0194 template <class T,
0195 class = std::enable_if_t<is_sequence_of_axis_variant<std::decay_t<T>>::value>>
0196 struct requires_sequence_of_axis_variant {};
0197
0198 template <class T,
0199 class = std::enable_if_t<is_sequence_of_any_axis<std::decay_t<T>>::value>>
0200 struct requires_sequence_of_any_axis {};
0201
0202 template <class T,
0203 class = std::enable_if_t<is_any_axis<mp11::mp_first<std::decay_t<T>>>::value>>
0204 struct requires_axes {};
0205
0206 template <class T, class U,
0207 class = std::enable_if_t<is_transform<std::decay_t<T>, U>::value>>
0208 struct requires_transform {};
0209
0210 template <class T, class = std::enable_if_t<is_allocator<std::decay_t<T>>::value>>
0211 struct requires_allocator {};
0212
0213 }
0214 }
0215 }
0216
0217 #endif