• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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