summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/histogram/test/axis_variant_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/histogram/test/axis_variant_test.cpp')
-rw-r--r--src/boost/libs/histogram/test/axis_variant_test.cpp250
1 files changed, 250 insertions, 0 deletions
diff --git a/src/boost/libs/histogram/test/axis_variant_test.cpp b/src/boost/libs/histogram/test/axis_variant_test.cpp
new file mode 100644
index 000000000..016b592d8
--- /dev/null
+++ b/src/boost/libs/histogram/test/axis_variant_test.cpp
@@ -0,0 +1,250 @@
+// Copyright 2015-2018 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)
+
+#include <boost/core/lightweight_test.hpp>
+#include <boost/core/lightweight_test_trait.hpp>
+#include <boost/histogram/axis/category.hpp>
+#include <boost/histogram/axis/integer.hpp>
+#include <boost/histogram/axis/ostream.hpp>
+#include <boost/histogram/axis/regular.hpp>
+#include <boost/histogram/axis/variant.hpp>
+#include <boost/histogram/detail/type_name.hpp>
+#include <string>
+#include <type_traits>
+#include <vector>
+#include "throw_exception.hpp"
+#include "utility_allocator.hpp"
+#include "utility_axis.hpp"
+#include "utility_str.hpp"
+
+int main() {
+ using namespace boost::histogram;
+ namespace tr = axis::transform;
+
+ {
+ (void)axis::variant<>{};
+ }
+
+ {
+ using meta_type = std::vector<int>;
+ using variant_type =
+ axis::variant<axis::integer<double>, axis::category<std::string, meta_type>>;
+ auto a = variant_type{axis::integer<double>(0, 2, "foo")};
+ BOOST_TEST_EQ(a.index(-10), -1);
+ BOOST_TEST_EQ(a.index(-1), -1);
+ BOOST_TEST_EQ(a.index(0), 0);
+ BOOST_TEST_EQ(a.index(0.5), 0);
+ BOOST_TEST_EQ(a.index(1), 1);
+ BOOST_TEST_EQ(a.index(2), 2);
+ BOOST_TEST_EQ(a.index(10), 2);
+ BOOST_TEST_EQ(a.bin(-1).lower(), -std::numeric_limits<double>::infinity());
+ BOOST_TEST_EQ(a.bin(a.size()).upper(), std::numeric_limits<double>::infinity());
+ BOOST_TEST_EQ(a.bin(-10).lower(), -std::numeric_limits<double>::infinity());
+ BOOST_TEST_EQ(a.bin(a.size() + 10).upper(), std::numeric_limits<double>::infinity());
+ BOOST_TEST_EQ(a.metadata(), "foo");
+ a.metadata() = "bar";
+ BOOST_TEST_EQ(static_cast<const variant_type&>(a).metadata(), "bar");
+ BOOST_TEST_EQ(a.options(), axis::option::underflow | axis::option::overflow);
+
+ a = axis::category<std::string, meta_type>({"A", "B"}, {1, 2, 3});
+ BOOST_TEST_EQ(a.index("A"), 0);
+ BOOST_TEST_EQ(a.index("B"), 1);
+ BOOST_TEST_THROWS(a.metadata(), std::runtime_error);
+ BOOST_TEST_THROWS(static_cast<const variant_type&>(a).metadata(), std::runtime_error);
+ BOOST_TEST_EQ(a.options(), axis::option::overflow_t::value);
+ }
+
+ // axis::variant with pointers
+ {
+ using A = axis::integer<>;
+ using B = axis::regular<>;
+ auto a = A(1, 5, "foo");
+ auto b = B(3, 1, 5, "bar");
+ axis::variant<A*, B*> r1(&a);
+ BOOST_TEST_EQ(r1, a);
+ BOOST_TEST_NE(r1, A(2, 4));
+ BOOST_TEST_NE(r1, b);
+ BOOST_TEST_EQ(r1.size(), 4);
+ BOOST_TEST_EQ(r1.value(0), 1);
+ BOOST_TEST_EQ(r1.metadata(), a.metadata());
+ BOOST_TEST_EQ(r1.options(), a.options());
+ // change original through r1
+ axis::get<A>(r1).metadata() = "bar";
+ BOOST_TEST_EQ(a.metadata(), "bar");
+ r1 = &b;
+ BOOST_TEST_EQ(r1, b);
+
+ axis::variant<const A*, const B*> r2(static_cast<const B*>(&b));
+ BOOST_TEST_EQ(r2, b);
+ BOOST_TEST_NE(r2, B(4, 1, 5));
+ BOOST_TEST_NE(r2, a);
+ BOOST_TEST_EQ(r2.size(), 3);
+ BOOST_TEST_EQ(r2.value(0), 1);
+ BOOST_TEST_EQ(r2.metadata(), "bar");
+ b.metadata() = "baz";
+ BOOST_TEST_EQ(r2.metadata(), "baz");
+ }
+
+ // axis::variant copyable
+ {
+ axis::variant<axis::regular<>> a1(axis::regular<>(2, -1, 1));
+ axis::variant<axis::regular<>> a2(a1);
+ BOOST_TEST_EQ(a1, a2);
+ axis::variant<axis::regular<>> a3;
+ BOOST_TEST_NE(a3, a1);
+ a3 = a1;
+ BOOST_TEST_EQ(a3, a1);
+ axis::variant<axis::regular<>> a4(axis::regular<>(3, -2, 2));
+ axis::variant<axis::regular<>, axis::integer<>> a5(a4);
+ BOOST_TEST_EQ(a4, a5);
+ axis::variant<axis::regular<>> a6;
+ a6 = a1;
+ BOOST_TEST_EQ(a6, a1);
+ axis::variant<axis::regular<>, axis::integer<>> a7(axis::integer<>(0, 2));
+ BOOST_TEST_THROWS(axis::variant<axis::regular<>> a8(a7), std::runtime_error);
+ BOOST_TEST_THROWS(a4 = a7, std::runtime_error);
+ }
+
+ // axis::variant movable
+ {
+ axis::variant<axis::regular<>> a(axis::regular<>(2, -1, 1));
+ axis::variant<axis::regular<>> r(a);
+ axis::variant<axis::regular<>> b(std::move(a));
+ BOOST_TEST_EQ(b, r);
+ axis::variant<axis::regular<>> c;
+ BOOST_TEST_NE(c, b);
+ c = std::move(b);
+ BOOST_TEST(c == r);
+ }
+
+ // axis::variant streamable
+ {
+ auto test = [](auto&& a, const char* ref) {
+ using T = std::decay_t<decltype(a)>;
+ axis::variant<T> axis(std::move(a));
+ BOOST_TEST_CSTR_EQ(str(axis).c_str(), ref);
+ };
+
+ test(axis::regular<>(2, -1, 1, "regular1"),
+ "regular(2, -1, 1, metadata=\"regular1\", options=underflow | overflow)");
+
+ struct user_defined {};
+ const auto ref = "integer(-1, 1, metadata=" + detail::type_name<user_defined>() +
+ ", options=none)";
+ test(axis::integer<int, user_defined, axis::option::none_t>(-1, 1), ref.c_str());
+ }
+
+ // bin_type operator<<
+ {
+ auto test = [](auto&& a, const char* ref) {
+ using T = std::decay_t<decltype(a)>;
+ axis::variant<T> axis(std::move(a));
+ BOOST_TEST_CSTR_EQ(str(axis.bin(0)).c_str(), ref);
+ };
+
+ test(axis::regular<>(2, 1, 2), "[1, 1.5)");
+ test(axis::category<>({1, 2}), "1");
+ }
+
+ // axis::variant operator==
+ {
+ enum { A, B, C };
+ using variant =
+ axis::variant<axis::regular<>, axis::regular<double, axis::transform::pow>,
+ axis::category<>, axis::integer<>>;
+ std::vector<variant> axes;
+ axes.push_back(axis::regular<>{2, -1, 1});
+ axes.push_back(axis::regular<double, tr::pow>(tr::pow(0.5), 2, 1, 4));
+ axes.push_back(axis::category<>({A, B, C}));
+ axes.push_back(axis::integer<>{-1, 1});
+ for (const auto& a : axes) {
+ BOOST_TEST(!(a == variant()));
+ BOOST_TEST_EQ(a, variant(a));
+ }
+ BOOST_TEST_NOT(axes == std::vector<variant>());
+ BOOST_TEST(axes == std::vector<variant>(axes));
+ }
+
+ // axis::variant with axis that has incompatible bin type
+ {
+ auto a = axis::variant<axis::category<std::string>>(
+ axis::category<std::string>({"A", "B", "C"}));
+ BOOST_TEST_THROWS(a.bin(0), std::runtime_error);
+ auto b = axis::variant<axis::category<int>>(axis::category<int>({2, 1, 3}));
+ BOOST_TEST_EQ(b.bin(0), 2);
+ BOOST_TEST_EQ(b.bin(0).lower(),
+ b.bin(0).upper()); // lower == upper for bin without interval
+ }
+
+ // axis::variant support for user-defined axis types
+ {
+ struct minimal_axis {
+ int index(int x) const { return x % 2; }
+ int size() const { return 2; }
+ };
+
+ axis::variant<minimal_axis, axis::category<std::string>> axis;
+ BOOST_TEST_EQ(axis.index(0), 0);
+ BOOST_TEST_EQ(axis.index(9), 1);
+ BOOST_TEST_EQ(axis.size(), 2);
+ BOOST_TEST_EQ(axis.metadata(), axis::null_type{});
+ BOOST_TEST_CSTR_EQ(str(axis).c_str(), "<unstreamable>");
+ BOOST_TEST_THROWS(axis.value(0), std::runtime_error);
+
+ axis = axis::category<std::string>({"A", "B"}, "category");
+ BOOST_TEST_EQ(axis.index("B"), 1);
+ BOOST_TEST_THROWS(axis.value(0), std::runtime_error);
+ }
+
+ // vector of axes with custom allocators
+ {
+ using M = std::vector<char, tracing_allocator<char>>;
+ using T1 = axis::regular<double, tr::id, M>;
+ using T2 = axis::integer<int, axis::null_type>;
+ using T3 = axis::category<long, axis::null_type, axis::option::overflow_t,
+ tracing_allocator<long>>;
+ using axis_type = axis::variant<T1, T2, T3>; // no heap allocation
+ using axes_type = std::vector<axis_type, tracing_allocator<axis_type>>;
+
+ tracing_allocator_db db;
+ {
+ auto a = tracing_allocator<char>(db);
+ axes_type axes(a);
+ axes.reserve(3);
+ axes.emplace_back(T1(1, 0, 1, M(3, 'c', a)));
+ axes.emplace_back(T2(0, 4));
+ axes.emplace_back(T3({1, 2, 3, 4, 5}, {}, a));
+ }
+ // 3 axis::variant objects
+ BOOST_TEST_EQ(db.at<axis_type>().first, 0);
+ BOOST_TEST_EQ(db.at<axis_type>().second, 3);
+
+ // label of T1
+ BOOST_TEST_EQ(db.at<char>().first, 0);
+ BOOST_TEST_EQ(db.at<char>().second, 3);
+
+ // T3 allocates storage for long array
+ BOOST_TEST_EQ(db.at<long>().first, 0);
+ BOOST_TEST_EQ(db.at<long>().second, 5);
+ }
+
+ // testing pass-through versions of get
+ {
+ axis::regular<> a(10, 0, 1);
+ axis::integer<> b(0, 3);
+ const auto& ta = axis::get<axis::regular<>>(a);
+ BOOST_TEST_EQ(ta, a);
+ const auto* tb = axis::get_if<axis::integer<>>(&b);
+ BOOST_TEST_EQ(tb, &b);
+ const auto* tc = axis::get_if<axis::regular<>>(&b);
+ BOOST_TEST_EQ(tc, nullptr);
+ }
+
+ // iterators
+ test_axis_iterator(axis::variant<axis::regular<>>(axis::regular<>(5, 0, 1)), 0, 5);
+
+ return boost::report_errors();
+}