1 // Copyright 2018 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 #include <boost/core/lightweight_test.hpp>
8 #include <boost/core/lightweight_test_trait.hpp>
9 #include <boost/histogram/axis.hpp>
10 #include <boost/histogram/axis/traits.hpp>
11 #include "std_ostream.hpp"
12 #include "throw_exception.hpp"
13 #include "utility_axis.hpp"
14
15 using namespace boost::histogram::axis;
16 using namespace std::literals;
17
18 struct ValueTypeOverride {
19 index_type index(int);
20 };
21
22 namespace boost {
23 namespace histogram {
24 namespace detail {
25 template <>
26 struct value_type_deducer<ValueTypeOverride> {
27 using type = char;
28 };
29 } // namespace detail
30 } // namespace histogram
31 } // namespace boost
32
main()33 int main() {
34 // value_type
35 {
36 struct Foo {
37 void index(const long&);
38 };
39
40 BOOST_TEST_TRAIT_SAME(traits::value_type<Foo>, long);
41 BOOST_TEST_TRAIT_SAME(traits::value_type<ValueTypeOverride>, char);
42 BOOST_TEST_TRAIT_SAME(traits::value_type<integer<int>>, int);
43 BOOST_TEST_TRAIT_SAME(traits::value_type<category<int>>, int);
44 BOOST_TEST_TRAIT_SAME(traits::value_type<regular<double>>, double);
45 }
46
47 // is_continuous
48 {
49 BOOST_TEST_TRAIT_TRUE((traits::is_continuous<regular<>>));
50 BOOST_TEST_TRAIT_FALSE((traits::is_continuous<integer<int>>));
51 BOOST_TEST_TRAIT_FALSE((traits::is_continuous<category<int>>));
52 BOOST_TEST_TRAIT_TRUE((traits::is_continuous<integer<double>>));
53 }
54
55 // is_reducible
56 {
57 struct not_reducible {};
58 struct reducible {
59 reducible(const reducible&, index_type, index_type, unsigned);
60 };
61
62 BOOST_TEST_TRAIT_TRUE((traits::is_reducible<reducible>));
63 BOOST_TEST_TRAIT_FALSE((traits::is_reducible<not_reducible>));
64
65 BOOST_TEST_TRAIT_TRUE((traits::is_reducible<regular<>>));
66 BOOST_TEST_TRAIT_TRUE((traits::is_reducible<variable<>>));
67 BOOST_TEST_TRAIT_TRUE((traits::is_reducible<circular<>>));
68 BOOST_TEST_TRAIT_TRUE((traits::is_reducible<integer<>>));
69 BOOST_TEST_TRAIT_TRUE((traits::is_reducible<category<>>));
70 }
71
72 // get_options, options()
73 {
74 using A = integer<>;
75 BOOST_TEST_EQ(traits::get_options<A>::test(option::growth), false);
76 auto expected = option::underflow | option::overflow;
77 auto a = A{};
78 BOOST_TEST_EQ(traits::options(a), expected);
79 BOOST_TEST_EQ(traits::options(static_cast<A&>(a)), expected);
80 BOOST_TEST_EQ(traits::options(static_cast<const A&>(a)), expected);
81 BOOST_TEST_EQ(traits::options(std::move(a)), expected);
82
83 using B = integer<int, null_type, option::growth_t>;
84 BOOST_TEST_EQ(traits::get_options<B>::test(option::growth), true);
85 BOOST_TEST_EQ(traits::options(B{}), option::growth);
86
87 struct growing {
88 auto update(double) { return std::make_pair(0, 0); }
89 };
90 using C = growing;
91 BOOST_TEST_EQ(traits::get_options<C>::test(option::growth), true);
92 auto c = C{};
93 BOOST_TEST_EQ(traits::options(c), option::growth);
94 BOOST_TEST_EQ(traits::options(static_cast<C&>(c)), option::growth);
95 BOOST_TEST_EQ(traits::options(static_cast<const C&>(c)), option::growth);
96 BOOST_TEST_EQ(traits::options(std::move(c)), option::growth);
97
98 struct notgrowing {
99 auto index(double) { return 0; }
100 };
101 using D = notgrowing;
102 BOOST_TEST_EQ(traits::get_options<D>::test(option::growth), false);
103 auto d = D{};
104 BOOST_TEST_EQ(traits::options(d), option::none);
105 BOOST_TEST_EQ(traits::options(static_cast<D&>(d)), option::none);
106 BOOST_TEST_EQ(traits::options(static_cast<const D&>(d)), option::none);
107 BOOST_TEST_EQ(traits::options(std::move(d)), option::none);
108 }
109
110 // is_inclusive, inclusive()
111 {
112 struct empty {};
113 struct with_opts_not_inclusive {
114 static constexpr unsigned options() { return option::underflow | option::overflow; }
115 static constexpr bool inclusive() { return false; }
116 };
117
118 BOOST_TEST_EQ(traits::inclusive(empty{}), false);
119 BOOST_TEST_EQ(traits::inclusive(regular<>{}), true);
120
121 BOOST_TEST_TRAIT_FALSE((traits::is_inclusive<empty>));
122 BOOST_TEST_TRAIT_FALSE((traits::is_inclusive<with_opts_not_inclusive>));
123
124 BOOST_TEST_TRAIT_TRUE((traits::is_inclusive<regular<>>));
125 BOOST_TEST_TRAIT_FALSE(
126 (traits::is_inclusive<
127 regular<double, boost::use_default, boost::use_default, option::growth_t>>));
128 BOOST_TEST_TRAIT_FALSE(
129 (traits::is_inclusive<regular<double, boost::use_default, boost::use_default,
130 option::circular_t>>));
131
132 BOOST_TEST_TRAIT_TRUE((traits::is_inclusive<variable<>>));
133 BOOST_TEST_TRAIT_FALSE(
134 (traits::is_inclusive<variable<double, boost::use_default, option::growth_t>>));
135 BOOST_TEST_TRAIT_FALSE(
136 (traits::is_inclusive<variable<double, boost::use_default, option::circular_t>>));
137
138 BOOST_TEST_TRAIT_TRUE((traits::is_inclusive<integer<int>>));
139 BOOST_TEST_TRAIT_TRUE(
140 (traits::is_inclusive<integer<int, boost::use_default, option::growth_t>>));
141 BOOST_TEST_TRAIT_TRUE(
142 (traits::is_inclusive<integer<int, boost::use_default, option::circular_t>>));
143
144 BOOST_TEST_TRAIT_TRUE((traits::is_inclusive<integer<double>>));
145 BOOST_TEST_TRAIT_FALSE(
146 (traits::is_inclusive<integer<double, boost::use_default, option::growth_t>>));
147 BOOST_TEST_TRAIT_FALSE(
148 (traits::is_inclusive<integer<double, boost::use_default, option::circular_t>>));
149
150 BOOST_TEST_TRAIT_TRUE((traits::is_inclusive<category<int>>));
151 BOOST_TEST_TRAIT_TRUE(
152 (traits::is_inclusive<category<int, boost::use_default, option::growth_t>>));
153 BOOST_TEST_TRAIT_FALSE(
154 (traits::is_inclusive<category<int, boost::use_default, option::none_t>>));
155 }
156
157 // is_ordered, ordered()
158 {
159 struct ordered_1 {
160 constexpr static bool ordered() { return true; }
161 index_type index(ordered_1) { return true; }
162 };
163 struct ordered_2 {
164 index_type index(int);
165 };
166 struct not_ordered_1 {
167 constexpr static bool ordered() { return false; }
168 index_type index(int);
169 };
170 struct not_ordered_2 {
171 index_type index(not_ordered_2);
172 };
173
174 BOOST_TEST_TRAIT_TRUE((traits::is_ordered<ordered_1>));
175 BOOST_TEST_TRAIT_TRUE((traits::is_ordered<ordered_2>));
176 BOOST_TEST_TRAIT_FALSE((traits::is_ordered<not_ordered_1>));
177 BOOST_TEST_TRAIT_FALSE((traits::is_ordered<not_ordered_2>));
178
179 BOOST_TEST(traits::ordered(integer<>{}));
180 BOOST_TEST_NOT(traits::ordered(category<int>{}));
181 }
182
183 // index, rank, value, width
184 {
185 auto a = integer<>(1, 3);
186 BOOST_TEST_EQ(traits::index(a, 1), 0);
187 BOOST_TEST_EQ(traits::rank(a), 1);
188 BOOST_TEST_EQ(traits::value(a, 0), 1);
189 BOOST_TEST_EQ(traits::width(a, 0), 0);
190 BOOST_TEST_EQ(traits::width(a, 0), 0);
191
192 auto b = integer<double>(1, 3);
193 BOOST_TEST_EQ(traits::index(b, 1), 0);
194 BOOST_TEST_EQ(traits::rank(b), 1);
195 BOOST_TEST_EQ(traits::value(b, 0), 1);
196 BOOST_TEST_EQ(traits::width(b, 0), 1);
197 BOOST_TEST(traits::get_options<decltype(b)>::test(option::underflow));
198
199 auto c = category<std::string>{"red", "blue"};
200 BOOST_TEST_EQ(traits::index(c, "blue"), 1);
201 BOOST_TEST_EQ(traits::rank(c), 1);
202 BOOST_TEST_EQ(traits::value(c, 0), "red"s);
203 BOOST_TEST_EQ(traits::width(c, 0), 0);
204
205 struct D {
206 index_type index(const std::tuple<int, double>& args) const {
207 return static_cast<index_type>(std::get<0>(args) + std::get<1>(args));
208 }
209 index_type size() const { return 5; }
210 } d;
211 BOOST_TEST_EQ(traits::index(d, std::make_tuple(1, 2.0)), 3.0);
212 BOOST_TEST_EQ(traits::rank(d), 2u);
213
214 variant<D, integer<>> v;
215 v = a;
216 BOOST_TEST_EQ(traits::rank(v), 1u);
217 v = d;
218 BOOST_TEST_EQ(traits::rank(v), 2u);
219
220 struct E : integer<> {
221 using integer::integer; // inherit ctors of base
222 // customization point: convert argument and call base class
223 auto index(const char* s) const { return integer::index(std::atoi(s)); }
224 };
225
226 BOOST_TEST_EQ(traits::index(E{0, 3}, "2"), 2);
227 }
228
229 // update
230 {
231 auto a = integer<int, null_type, option::growth_t>();
232 BOOST_TEST_EQ(traits::update(a, 0), (std::pair<index_type, index_type>(0, -1)));
233 BOOST_TEST_THROWS(traits::update(a, "foo"), std::invalid_argument);
234
235 variant<integer<int, null_type, option::growth_t>, integer<>> v(a);
236 BOOST_TEST_EQ(traits::update(v, 0), (std::pair<index_type, index_type>(0, 0)));
237 }
238
239 // metadata
240 {
241 struct None {};
242
243 struct Const {
244 const int& metadata() const { return m; };
245 int m = 0;
246 };
247
248 struct Both {
249 const int& metadata() const { return m; };
250 int& metadata() { return m; };
251 int m = 0;
252 };
253
254 None none;
255 BOOST_TEST_TRAIT_SAME(decltype(traits::metadata(none)), null_type&);
256 BOOST_TEST_TRAIT_SAME(decltype(traits::metadata(static_cast<None&>(none))),
257 null_type&);
258 BOOST_TEST_TRAIT_SAME(decltype(traits::metadata(static_cast<const None&>(none))),
259 null_type&);
260
261 Const c;
262 BOOST_TEST_EQ(traits::metadata(c), 0);
263 BOOST_TEST_EQ(traits::metadata(static_cast<Const&>(c)), 0);
264 BOOST_TEST_EQ(traits::metadata(static_cast<const Const&>(c)), 0);
265
266 Both b;
267 BOOST_TEST_EQ(traits::metadata(b), 0);
268 BOOST_TEST_EQ(traits::metadata(static_cast<Both&>(b)), 0);
269 BOOST_TEST_EQ(traits::metadata(static_cast<const Both&>(b)), 0);
270 }
271
272 return boost::report_errors();
273 }
274