]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/histogram/test/axis_variant_test.cpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / libs / histogram / test / axis_variant_test.cpp
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>
9 #include <boost/histogram/axis.hpp>
10 #include <boost/histogram/axis/ostream.hpp>
11 #include <boost/histogram/detail/type_name.hpp>
12 #include <string>
13 #include <type_traits>
14 #include <vector>
15 #include "std_ostream.hpp"
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
73 r1.metadata() = "bar";
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");
85 r2.metadata() = "baz"; // change original through r2
86 BOOST_TEST_EQ(b.metadata(), "baz");
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
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\")");
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>,
157 axis::category<>, axis::integer<>, axis::boolean<>>;
158 std::vector<variant> axes;
159 axes.push_back(axis::regular<>{2, -1, 1});
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});
162 axes.push_back(axis::integer<>{-1, 1});
163 axes.push_back(axis::boolean<>{});
164 for (const auto& a : axes) {
165 BOOST_TEST_NE(a, variant{});
166 BOOST_TEST_EQ(a, variant(a));
167 }
168 BOOST_TEST_NE(axes, std::vector<variant>{});
169 BOOST_TEST(axes == std::vector<variant>(axes));
170 }
171
172 // axis::variant with axis that has incompatible bin type
173 {
174 auto a = axis::variant<axis::category<std::string>>{
175 axis::category<std::string>{"A", "B", "C"}};
176 BOOST_TEST_THROWS(a.bin(0), std::runtime_error);
177 auto b = axis::variant<axis::category<int>>{axis::category<int>{2, 1, 3}};
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{});
195 BOOST_TEST_EQ(str(axis), detail::type_name<minimal_axis>());
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 }