]>
Commit | Line | Data |
---|---|---|
92f5a8d4 TL |
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> | |
20effc67 TL |
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 | |
92f5a8d4 TL |
14 | #include <iterator> |
15 | #include <tuple> | |
16 | #include <type_traits> | |
17 | ||
f67539c2 TL |
18 | // forward declaration |
19 | namespace boost { | |
20 | namespace variant2 { | |
21 | template <class...> | |
22 | class variant; | |
23 | } // namespace variant2 | |
24 | } // namespace boost | |
25 | ||
92f5a8d4 TL |
26 | namespace boost { |
27 | namespace histogram { | |
28 | namespace detail { | |
29 | ||
20effc67 TL |
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 | |
92f5a8d4 TL |
58 | |
59 | // reset has overloads, trying to get pmf in this case always fails | |
20effc67 | 60 | BOOST_HISTOGRAM_DETAIL_DETECT(has_method_reset, t.reset(0)); |
92f5a8d4 | 61 | |
20effc67 | 62 | BOOST_HISTOGRAM_DETAIL_DETECT(is_indexable, t[0]); |
92f5a8d4 TL |
63 | |
64 | BOOST_HISTOGRAM_DETAIL_DETECT_BINARY( | |
65 | is_transform, | |
66 | (std::declval<T&>().inverse(std::declval<T&>().forward(std::declval<U>())))); | |
67 | ||
20effc67 TL |
68 | BOOST_HISTOGRAM_DETAIL_DETECT(is_indexable_container, |
69 | (t[0], t.size(), std::begin(t), std::end(t))); | |
92f5a8d4 TL |
70 | |
71 | BOOST_HISTOGRAM_DETAIL_DETECT(is_vector_like, | |
20effc67 | 72 | (t[0], t.size(), t.resize(0), std::begin(t), std::end(t))); |
92f5a8d4 | 73 | |
20effc67 TL |
74 | BOOST_HISTOGRAM_DETAIL_DETECT(is_array_like, (t[0], t.size(), std::tuple_size<T>::value, |
75 | std::begin(t), std::end(t))); | |
92f5a8d4 | 76 | |
20effc67 TL |
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))); | |
92f5a8d4 TL |
80 | |
81 | // ok: is_axis is false for axis::variant, because T::index is templated | |
20effc67 | 82 | BOOST_HISTOGRAM_DETAIL_DETECT(is_axis, (t.size(), &T::index)); |
92f5a8d4 | 83 | |
20effc67 | 84 | BOOST_HISTOGRAM_DETAIL_DETECT(is_iterable, (std::begin(t), std::end(t))); |
92f5a8d4 TL |
85 | |
86 | BOOST_HISTOGRAM_DETAIL_DETECT(is_iterator, | |
20effc67 | 87 | (typename std::iterator_traits<T>::iterator_category{})); |
92f5a8d4 | 88 | |
20effc67 | 89 | BOOST_HISTOGRAM_DETAIL_DETECT(is_streamable, (std::declval<std::ostream&>() << t)); |
92f5a8d4 | 90 | |
20effc67 | 91 | BOOST_HISTOGRAM_DETAIL_DETECT(has_operator_preincrement, ++t); |
92f5a8d4 TL |
92 | |
93 | BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_equal, (std::declval<const T&>() == | |
20effc67 | 94 | std::declval<const U&>())); |
92f5a8d4 TL |
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( | |
20effc67 | 109 | has_method_eq, (std::declval<const T&>().operator==(std::declval<const U&>()))); |
92f5a8d4 TL |
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> | |
20effc67 | 123 | struct is_tuple_impl : std::false_type {}; |
92f5a8d4 TL |
124 | |
125 | template <class... Ts> | |
20effc67 | 126 | struct is_tuple_impl<std::tuple<Ts...>> : std::true_type {}; |
92f5a8d4 TL |
127 | |
128 | template <class T> | |
129 | using is_tuple = typename is_tuple_impl<T>::type; | |
130 | ||
131 | template <class T> | |
20effc67 | 132 | struct is_variant_impl : std::false_type {}; |
92f5a8d4 TL |
133 | |
134 | template <class... Ts> | |
20effc67 | 135 | struct is_variant_impl<boost::variant2::variant<Ts...>> : std::true_type {}; |
92f5a8d4 TL |
136 | |
137 | template <class T> | |
138 | using is_variant = typename is_variant_impl<T>::type; | |
139 | ||
140 | template <class T> | |
20effc67 | 141 | struct is_axis_variant_impl : std::false_type {}; |
92f5a8d4 TL |
142 | |
143 | template <class... Ts> | |
20effc67 | 144 | struct is_axis_variant_impl<axis::variant<Ts...>> : std::true_type {}; |
92f5a8d4 TL |
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 | ||
92f5a8d4 TL |
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 |