1 // Copyright 2015-2019 Hans Dembinski 2 // 3 // Distributed under the Boost Software License, Version 1.0. 4 // (See accompanying file LICENSE_1_0.txt 5 // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 7 #ifndef BOOST_HISTOGRAM_DETAIL_DETECT_HPP 8 #define BOOST_HISTOGRAM_DETAIL_DETECT_HPP 9 10 #include <boost/histogram/fwd.hpp> 11 #include <boost/mp11/function.hpp> // mp_and, mp_or 12 #include <boost/mp11/integral.hpp> // mp_not 13 #include <boost/mp11/list.hpp> // mp_first 14 #include <iterator> 15 #include <tuple> 16 #include <type_traits> 17 18 // forward declaration 19 namespace boost { 20 namespace variant2 { 21 template <class...> 22 class variant; 23 } // namespace variant2 24 } // namespace boost 25 26 namespace boost { 27 namespace histogram { 28 namespace detail { 29 30 #define BOOST_HISTOGRAM_DETAIL_DETECT(name, cond) \ 31 template <class U> \ 32 struct name##_impl { \ 33 typedef char yes[1]; \ 34 typedef char no[2]; \ 35 template <class T> \ 36 static yes& test(T& t, decltype(cond, 0)); \ 37 template <class T> \ 38 static no& test(T&, float); \ 39 using type = \ 40 std::integral_constant<bool, (sizeof(test(std::declval<U&>(), 0)) == 1)>; \ 41 }; \ 42 template <class T> \ 43 using name = typename name##_impl<T>::type 44 45 #define BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(name, cond) \ 46 template <class V, class W> \ 47 struct name##_impl { \ 48 typedef char yes[1]; \ 49 typedef char no[2]; \ 50 template <class T, class U> \ 51 static yes& test(decltype(cond, 0)); \ 52 template <class, class> \ 53 static no& test(float); \ 54 using type = std::integral_constant<bool, (sizeof(test<V, W>(0)) == 1)>; \ 55 }; \ 56 template <class T, class U = T> \ 57 using name = typename name##_impl<T, U>::type 58 59 // reset has overloads, trying to get pmf in this case always fails 60 BOOST_HISTOGRAM_DETAIL_DETECT(has_method_reset, t.reset(0)); 61 62 BOOST_HISTOGRAM_DETAIL_DETECT(is_indexable, t[0]); 63 64 BOOST_HISTOGRAM_DETAIL_DETECT_BINARY( 65 is_transform, 66 (std::declval<T&>().inverse(std::declval<T&>().forward(std::declval<U>())))); 67 68 BOOST_HISTOGRAM_DETAIL_DETECT(is_indexable_container, 69 (t[0], t.size(), std::begin(t), std::end(t))); 70 71 BOOST_HISTOGRAM_DETAIL_DETECT(is_vector_like, 72 (t[0], t.size(), t.resize(0), std::begin(t), std::end(t))); 73 74 BOOST_HISTOGRAM_DETAIL_DETECT(is_array_like, (t[0], t.size(), std::tuple_size<T>::value, 75 std::begin(t), std::end(t))); 76 77 BOOST_HISTOGRAM_DETAIL_DETECT(is_map_like, ((typename T::key_type*)nullptr, 78 (typename T::mapped_type*)nullptr, 79 std::begin(t), std::end(t))); 80 81 // ok: is_axis is false for axis::variant, because T::index is templated 82 BOOST_HISTOGRAM_DETAIL_DETECT(is_axis, (t.size(), &T::index)); 83 84 BOOST_HISTOGRAM_DETAIL_DETECT(is_iterable, (std::begin(t), std::end(t))); 85 86 BOOST_HISTOGRAM_DETAIL_DETECT(is_iterator, 87 (typename std::iterator_traits<T>::iterator_category{})); 88 89 BOOST_HISTOGRAM_DETAIL_DETECT(is_streamable, (std::declval<std::ostream&>() << t)); 90 91 BOOST_HISTOGRAM_DETAIL_DETECT(has_operator_preincrement, ++t); 92 93 BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_equal, (std::declval<const T&>() == 94 std::declval<const U>())); 95 96 BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_radd, 97 (std::declval<T&>() += std::declval<U>())); 98 99 BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rsub, 100 (std::declval<T&>() -= std::declval<U>())); 101 102 BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rmul, 103 (std::declval<T&>() *= std::declval<U>())); 104 105 BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rdiv, 106 (std::declval<T&>() /= std::declval<U>())); 107 108 BOOST_HISTOGRAM_DETAIL_DETECT_BINARY( 109 has_method_eq, (std::declval<const T>().operator==(std::declval<const U>()))); 110 111 BOOST_HISTOGRAM_DETAIL_DETECT(has_threading_support, (T::has_threading_support)); 112 113 template <class T> 114 using is_storage = mp11::mp_and<is_indexable_container<T>, has_method_reset<T>, 115 has_threading_support<T>>; 116 117 template <class T> 118 using is_adaptible = 119 mp11::mp_and<mp11::mp_not<is_storage<T>>, 120 mp11::mp_or<is_vector_like<T>, is_array_like<T>, is_map_like<T>>>; 121 122 template <class T> 123 struct is_tuple_impl : std::false_type {}; 124 125 template <class... Ts> 126 struct is_tuple_impl<std::tuple<Ts...>> : std::true_type {}; 127 128 template <class T> 129 using is_tuple = typename is_tuple_impl<T>::type; 130 131 template <class T> 132 struct is_variant_impl : std::false_type {}; 133 134 template <class... Ts> 135 struct is_variant_impl<boost::variant2::variant<Ts...>> : std::true_type {}; 136 137 template <class T> 138 using is_variant = typename is_variant_impl<T>::type; 139 140 template <class T> 141 struct is_axis_variant_impl : std::false_type {}; 142 143 template <class... Ts> 144 struct is_axis_variant_impl<axis::variant<Ts...>> : std::true_type {}; 145 146 template <class T> 147 using is_axis_variant = typename is_axis_variant_impl<T>::type; 148 149 template <class T> 150 using is_any_axis = mp11::mp_or<is_axis<T>, is_axis_variant<T>>; 151 152 template <class T> 153 using is_sequence_of_axis = mp11::mp_and<is_iterable<T>, is_axis<mp11::mp_first<T>>>; 154 155 template <class T> 156 using is_sequence_of_axis_variant = 157 mp11::mp_and<is_iterable<T>, is_axis_variant<mp11::mp_first<T>>>; 158 159 template <class T> 160 using is_sequence_of_any_axis = 161 mp11::mp_and<is_iterable<T>, is_any_axis<mp11::mp_first<T>>>; 162 163 // poor-mans concept checks 164 template <class T, class = std::enable_if_t<is_storage<std::decay_t<T>>::value>> 165 struct requires_storage {}; 166 167 template <class T, class _ = std::decay_t<T>, 168 class = std::enable_if_t<(is_storage<_>::value || is_adaptible<_>::value)>> 169 struct requires_storage_or_adaptible {}; 170 171 template <class T, class = std::enable_if_t<is_iterator<std::decay_t<T>>::value>> 172 struct requires_iterator {}; 173 174 template <class T, class = std::enable_if_t< 175 is_iterable<std::remove_cv_t<std::remove_reference_t<T>>>::value>> 176 struct requires_iterable {}; 177 178 template <class T, class = std::enable_if_t<is_axis<std::decay_t<T>>::value>> 179 struct requires_axis {}; 180 181 template <class T, class = std::enable_if_t<is_any_axis<std::decay_t<T>>::value>> 182 struct requires_any_axis {}; 183 184 template <class T, class = std::enable_if_t<is_sequence_of_axis<std::decay_t<T>>::value>> 185 struct requires_sequence_of_axis {}; 186 187 template <class T, 188 class = std::enable_if_t<is_sequence_of_axis_variant<std::decay_t<T>>::value>> 189 struct requires_sequence_of_axis_variant {}; 190 191 template <class T, 192 class = std::enable_if_t<is_sequence_of_any_axis<std::decay_t<T>>::value>> 193 struct requires_sequence_of_any_axis {}; 194 195 template <class T, 196 class = std::enable_if_t<is_any_axis<mp11::mp_first<std::decay_t<T>>>::value>> 197 struct requires_axes {}; 198 199 template <class T, class U, 200 class = std::enable_if_t<is_transform<std::decay_t<T>, U>::value>> 201 struct requires_transform {}; 202 203 } // namespace detail 204 } // namespace histogram 205 } // namespace boost 206 207 #endif 208