detect.hpp
7.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// 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 {
template <class...>
using void_t = void;
struct detect_base {
template <class T>
static T&& val();
template <class T>
static T& ref();
template <class T>
static T const& cref();
};
#define BOOST_HISTOGRAM_DETAIL_DETECT(name, cond) \
template <class U> \
struct name##_impl : detect_base { \
template <class T> \
static mp11::mp_true test(T& t, decltype(cond, 0)); \
template <class T> \
static mp11::mp_false test(T&, float); \
using type = decltype(test<U>(ref<U>(), 0)); \
}; \
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 : detect_base { \
template <class T, class U> \
static mp11::mp_true test(T& t, U& u, decltype(cond, 0)); \
template <class T, class U> \
static mp11::mp_false test(T&, U&, float); \
using type = decltype(test<V, W>(ref<V>(), ref<W>(), 0)); \
}; \
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, (t.inverse(t.forward(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, (cref<T>() == u));
BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_radd, (t += u));
BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rsub, (t -= u));
BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rmul, (t *= u));
BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_rdiv, (t /= u));
BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_method_eq, (cref<T>().operator==(u)));
BOOST_HISTOGRAM_DETAIL_DETECT(has_threading_support, (T::has_threading_support));
// stronger form of std::is_convertible that works with explicit operator T and ctors
BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(is_explicitly_convertible, static_cast<U>(t));
BOOST_HISTOGRAM_DETAIL_DETECT(is_complete, sizeof(T));
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