]>
Commit | Line | Data |
---|---|---|
92f5a8d4 TL |
1 | // Copyright 2015-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> | |
20effc67 | 9 | #include <boost/histogram/axis.hpp> |
92f5a8d4 | 10 | #include <boost/histogram/axis/ostream.hpp> |
92f5a8d4 TL |
11 | #include <boost/histogram/detail/type_name.hpp> |
12 | #include <string> | |
13 | #include <type_traits> | |
14 | #include <vector> | |
20effc67 | 15 | #include "std_ostream.hpp" |
92f5a8d4 TL |
16 | #include "throw_exception.hpp" |
17 | #include "utility_allocator.hpp" | |
18 | #include "utility_axis.hpp" | |
19 | #include "utility_str.hpp" | |
20 | ||
21 | int main() { | |
22 | using namespace boost::histogram; | |
23 | namespace tr = axis::transform; | |
24 | ||
25 | { | |
26 | (void)axis::variant<>{}; | |
27 | } | |
28 | ||
29 | { | |
30 | using meta_type = std::vector<int>; | |
31 | using variant_type = | |
32 | axis::variant<axis::integer<double>, axis::category<std::string, meta_type>>; | |
33 | auto a = variant_type{axis::integer<double>(0, 2, "foo")}; | |
34 | BOOST_TEST_EQ(a.index(-10), -1); | |
35 | BOOST_TEST_EQ(a.index(-1), -1); | |
36 | BOOST_TEST_EQ(a.index(0), 0); | |
37 | BOOST_TEST_EQ(a.index(0.5), 0); | |
38 | BOOST_TEST_EQ(a.index(1), 1); | |
39 | BOOST_TEST_EQ(a.index(2), 2); | |
40 | BOOST_TEST_EQ(a.index(10), 2); | |
41 | BOOST_TEST_EQ(a.bin(-1).lower(), -std::numeric_limits<double>::infinity()); | |
42 | BOOST_TEST_EQ(a.bin(a.size()).upper(), std::numeric_limits<double>::infinity()); | |
43 | BOOST_TEST_EQ(a.bin(-10).lower(), -std::numeric_limits<double>::infinity()); | |
44 | BOOST_TEST_EQ(a.bin(a.size() + 10).upper(), std::numeric_limits<double>::infinity()); | |
45 | BOOST_TEST_EQ(a.metadata(), "foo"); | |
46 | a.metadata() = "bar"; | |
47 | BOOST_TEST_EQ(static_cast<const variant_type&>(a).metadata(), "bar"); | |
48 | BOOST_TEST_EQ(a.options(), axis::option::underflow | axis::option::overflow); | |
49 | ||
50 | a = axis::category<std::string, meta_type>({"A", "B"}, {1, 2, 3}); | |
51 | BOOST_TEST_EQ(a.index("A"), 0); | |
52 | BOOST_TEST_EQ(a.index("B"), 1); | |
53 | BOOST_TEST_THROWS(a.metadata(), std::runtime_error); | |
54 | BOOST_TEST_THROWS(static_cast<const variant_type&>(a).metadata(), std::runtime_error); | |
55 | BOOST_TEST_EQ(a.options(), axis::option::overflow_t::value); | |
56 | } | |
57 | ||
58 | // axis::variant with pointers | |
59 | { | |
60 | using A = axis::integer<>; | |
61 | using B = axis::regular<>; | |
62 | auto a = A(1, 5, "foo"); | |
63 | auto b = B(3, 1, 5, "bar"); | |
64 | axis::variant<A*, B*> r1(&a); | |
65 | BOOST_TEST_EQ(r1, a); | |
66 | BOOST_TEST_NE(r1, A(2, 4)); | |
67 | BOOST_TEST_NE(r1, b); | |
68 | BOOST_TEST_EQ(r1.size(), 4); | |
69 | BOOST_TEST_EQ(r1.value(0), 1); | |
70 | BOOST_TEST_EQ(r1.metadata(), a.metadata()); | |
71 | BOOST_TEST_EQ(r1.options(), a.options()); | |
72 | // change original through r1 | |
20effc67 | 73 | r1.metadata() = "bar"; |
92f5a8d4 TL |
74 | BOOST_TEST_EQ(a.metadata(), "bar"); |
75 | r1 = &b; | |
76 | BOOST_TEST_EQ(r1, b); | |
77 | ||
78 | axis::variant<const A*, const B*> r2(static_cast<const B*>(&b)); | |
79 | BOOST_TEST_EQ(r2, b); | |
80 | BOOST_TEST_NE(r2, B(4, 1, 5)); | |
81 | BOOST_TEST_NE(r2, a); | |
82 | BOOST_TEST_EQ(r2.size(), 3); | |
83 | BOOST_TEST_EQ(r2.value(0), 1); | |
84 | BOOST_TEST_EQ(r2.metadata(), "bar"); | |
20effc67 TL |
85 | r2.metadata() = "baz"; // change original through r2 |
86 | BOOST_TEST_EQ(b.metadata(), "baz"); | |
92f5a8d4 TL |
87 | } |
88 | ||
89 | // axis::variant copyable | |
90 | { | |
91 | axis::variant<axis::regular<>> a1(axis::regular<>(2, -1, 1)); | |
92 | axis::variant<axis::regular<>> a2(a1); | |
93 | BOOST_TEST_EQ(a1, a2); | |
94 | axis::variant<axis::regular<>> a3; | |
95 | BOOST_TEST_NE(a3, a1); | |
96 | a3 = a1; | |
97 | BOOST_TEST_EQ(a3, a1); | |
98 | axis::variant<axis::regular<>> a4(axis::regular<>(3, -2, 2)); | |
99 | axis::variant<axis::regular<>, axis::integer<>> a5(a4); | |
100 | BOOST_TEST_EQ(a4, a5); | |
101 | axis::variant<axis::regular<>> a6; | |
102 | a6 = a1; | |
103 | BOOST_TEST_EQ(a6, a1); | |
104 | axis::variant<axis::regular<>, axis::integer<>> a7(axis::integer<>(0, 2)); | |
105 | BOOST_TEST_THROWS(axis::variant<axis::regular<>> a8(a7), std::runtime_error); | |
106 | BOOST_TEST_THROWS(a4 = a7, std::runtime_error); | |
107 | } | |
108 | ||
109 | // axis::variant movable | |
110 | { | |
111 | axis::variant<axis::regular<>> a(axis::regular<>(2, -1, 1)); | |
112 | axis::variant<axis::regular<>> r(a); | |
113 | axis::variant<axis::regular<>> b(std::move(a)); | |
114 | BOOST_TEST_EQ(b, r); | |
115 | axis::variant<axis::regular<>> c; | |
116 | BOOST_TEST_NE(c, b); | |
117 | c = std::move(b); | |
118 | BOOST_TEST(c == r); | |
119 | } | |
120 | ||
121 | // axis::variant streamable | |
122 | { | |
123 | auto test = [](auto&& a, const char* ref) { | |
124 | using T = std::decay_t<decltype(a)>; | |
125 | axis::variant<T> axis(std::move(a)); | |
126 | BOOST_TEST_CSTR_EQ(str(axis).c_str(), ref); | |
127 | }; | |
128 | ||
20effc67 TL |
129 | test(axis::regular<>{2, -1, 1, "foo"}, |
130 | "regular(2, -1, 1, metadata=\"foo\", options=underflow | overflow)"); | |
131 | ||
132 | test(axis::boolean<>{"bar"}, "boolean(metadata=\"bar\")"); | |
92f5a8d4 TL |
133 | |
134 | struct user_defined {}; | |
135 | const auto ref = "integer(-1, 1, metadata=" + detail::type_name<user_defined>() + | |
136 | ", options=none)"; | |
137 | test(axis::integer<int, user_defined, axis::option::none_t>(-1, 1), ref.c_str()); | |
138 | } | |
139 | ||
140 | // bin_type operator<< | |
141 | { | |
142 | auto test = [](auto&& a, const char* ref) { | |
143 | using T = std::decay_t<decltype(a)>; | |
144 | axis::variant<T> axis(std::move(a)); | |
145 | BOOST_TEST_CSTR_EQ(str(axis.bin(0)).c_str(), ref); | |
146 | }; | |
147 | ||
148 | test(axis::regular<>(2, 1, 2), "[1, 1.5)"); | |
149 | test(axis::category<>({1, 2}), "1"); | |
150 | } | |
151 | ||
152 | // axis::variant operator== | |
153 | { | |
154 | enum { A, B, C }; | |
155 | using variant = | |
156 | axis::variant<axis::regular<>, axis::regular<double, axis::transform::pow>, | |
20effc67 | 157 | axis::category<>, axis::integer<>, axis::boolean<>>; |
92f5a8d4 TL |
158 | std::vector<variant> axes; |
159 | axes.push_back(axis::regular<>{2, -1, 1}); | |
20effc67 TL |
160 | axes.push_back(axis::regular<double, tr::pow>{tr::pow{0.5}, 2, 1, 4}); |
161 | axes.push_back(axis::category<>{A, B, C}); | |
92f5a8d4 | 162 | axes.push_back(axis::integer<>{-1, 1}); |
20effc67 | 163 | axes.push_back(axis::boolean<>{}); |
92f5a8d4 | 164 | for (const auto& a : axes) { |
20effc67 | 165 | BOOST_TEST_NE(a, variant{}); |
92f5a8d4 TL |
166 | BOOST_TEST_EQ(a, variant(a)); |
167 | } | |
20effc67 | 168 | BOOST_TEST_NE(axes, std::vector<variant>{}); |
92f5a8d4 TL |
169 | BOOST_TEST(axes == std::vector<variant>(axes)); |
170 | } | |
171 | ||
172 | // axis::variant with axis that has incompatible bin type | |
173 | { | |
20effc67 TL |
174 | auto a = axis::variant<axis::category<std::string>>{ |
175 | axis::category<std::string>{"A", "B", "C"}}; | |
92f5a8d4 | 176 | BOOST_TEST_THROWS(a.bin(0), std::runtime_error); |
20effc67 | 177 | auto b = axis::variant<axis::category<int>>{axis::category<int>{2, 1, 3}}; |
92f5a8d4 TL |
178 | BOOST_TEST_EQ(b.bin(0), 2); |
179 | BOOST_TEST_EQ(b.bin(0).lower(), | |
180 | b.bin(0).upper()); // lower == upper for bin without interval | |
181 | } | |
182 | ||
183 | // axis::variant support for user-defined axis types | |
184 | { | |
185 | struct minimal_axis { | |
186 | int index(int x) const { return x % 2; } | |
187 | int size() const { return 2; } | |
188 | }; | |
189 | ||
190 | axis::variant<minimal_axis, axis::category<std::string>> axis; | |
191 | BOOST_TEST_EQ(axis.index(0), 0); | |
192 | BOOST_TEST_EQ(axis.index(9), 1); | |
193 | BOOST_TEST_EQ(axis.size(), 2); | |
194 | BOOST_TEST_EQ(axis.metadata(), axis::null_type{}); | |
20effc67 | 195 | BOOST_TEST_EQ(str(axis), detail::type_name<minimal_axis>()); |
92f5a8d4 TL |
196 | BOOST_TEST_THROWS(axis.value(0), std::runtime_error); |
197 | ||
198 | axis = axis::category<std::string>({"A", "B"}, "category"); | |
199 | BOOST_TEST_EQ(axis.index("B"), 1); | |
200 | BOOST_TEST_THROWS(axis.value(0), std::runtime_error); | |
201 | } | |
202 | ||
203 | // vector of axes with custom allocators | |
204 | { | |
205 | using M = std::vector<char, tracing_allocator<char>>; | |
206 | using T1 = axis::regular<double, tr::id, M>; | |
207 | using T2 = axis::integer<int, axis::null_type>; | |
208 | using T3 = axis::category<long, axis::null_type, axis::option::overflow_t, | |
209 | tracing_allocator<long>>; | |
210 | using axis_type = axis::variant<T1, T2, T3>; // no heap allocation | |
211 | using axes_type = std::vector<axis_type, tracing_allocator<axis_type>>; | |
212 | ||
213 | tracing_allocator_db db; | |
214 | { | |
215 | auto a = tracing_allocator<char>(db); | |
216 | axes_type axes(a); | |
217 | axes.reserve(3); | |
218 | axes.emplace_back(T1(1, 0, 1, M(3, 'c', a))); | |
219 | axes.emplace_back(T2(0, 4)); | |
220 | axes.emplace_back(T3({1, 2, 3, 4, 5}, {}, a)); | |
221 | } | |
222 | // 3 axis::variant objects | |
223 | BOOST_TEST_EQ(db.at<axis_type>().first, 0); | |
224 | BOOST_TEST_EQ(db.at<axis_type>().second, 3); | |
225 | ||
226 | // label of T1 | |
227 | BOOST_TEST_EQ(db.at<char>().first, 0); | |
228 | BOOST_TEST_EQ(db.at<char>().second, 3); | |
229 | ||
230 | // T3 allocates storage for long array | |
231 | BOOST_TEST_EQ(db.at<long>().first, 0); | |
232 | BOOST_TEST_EQ(db.at<long>().second, 5); | |
233 | } | |
234 | ||
235 | // testing pass-through versions of get | |
236 | { | |
237 | axis::regular<> a(10, 0, 1); | |
238 | axis::integer<> b(0, 3); | |
239 | const auto& ta = axis::get<axis::regular<>>(a); | |
240 | BOOST_TEST_EQ(ta, a); | |
241 | const auto* tb = axis::get_if<axis::integer<>>(&b); | |
242 | BOOST_TEST_EQ(tb, &b); | |
243 | const auto* tc = axis::get_if<axis::regular<>>(&b); | |
244 | BOOST_TEST_EQ(tc, nullptr); | |
245 | } | |
246 | ||
247 | // iterators | |
248 | test_axis_iterator(axis::variant<axis::regular<>>(axis::regular<>(5, 0, 1)), 0, 5); | |
249 | ||
250 | return boost::report_errors(); | |
251 | } |