// 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) #ifndef BOOST_HISTOGRAM_DETAIL_AXES_HPP #define BOOST_HISTOGRAM_DETAIL_AXES_HPP #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace histogram { namespace detail { template decltype(auto) axis_get(std::tuple& axes) { return std::get(axes); } template decltype(auto) axis_get(const std::tuple& axes) { return std::get(axes); } template decltype(auto) axis_get(T& axes) { return axes[N]; } template decltype(auto) axis_get(const T& axes) { return axes[N]; } template decltype(auto) axis_get(std::tuple& axes, unsigned i) { return mp11::mp_with_index( i, [&](auto I) { return axis::variant(std::get(axes)); }); } template decltype(auto) axis_get(const std::tuple& axes, unsigned i) { return mp11::mp_with_index( i, [&](auto I) { return axis::variant(std::get(axes)); }); } template decltype(auto) axis_get(T& axes, unsigned i) { return axes.at(i); } template decltype(auto) axis_get(const T& axes, unsigned i) { return axes.at(i); } template bool axes_equal(const std::tuple& ts, const std::tuple& us) { return static_if, mp11::mp_list>>( [](const auto& ts, const auto& us) { using N = mp11::mp_size>; bool equal = true; mp11::mp_for_each>( [&](auto I) { equal &= relaxed_equal(std::get(ts), std::get(us)); }); return equal; }, [](const auto&, const auto&) { return false; }, ts, us); } template bool axes_equal(const std::tuple& t, const U& u) { if (sizeof...(Ts) != u.size()) return false; bool equal = true; mp11::mp_for_each>( [&](auto I) { equal &= u[I] == std::get(t); }); return equal; } template bool axes_equal(const T& t, const std::tuple& u) { return axes_equal(u, t); } template bool axes_equal(const T& t, const U& u) { if (t.size() != u.size()) return false; return std::equal(t.begin(), t.end(), u.begin()); } template void axes_assign(std::tuple& t, const std::tuple& u) { static_if, mp11::mp_list>>( [](auto& a, const auto& b) { a = b; }, [](auto&, const auto&) { BOOST_THROW_EXCEPTION( std::invalid_argument("cannot assign axes, types do not match")); }, t, u); } template void axes_assign(std::tuple& t, const U& u) { mp11::mp_for_each>([&](auto I) { using T = mp11::mp_at_c, I>; std::get(t) = axis::get(u[I]); }); } template void axes_assign(T& t, const std::tuple& u) { // resize instead of reserve, because t may not be empty and we want exact capacity t.resize(sizeof...(Us)); mp11::mp_for_each>( [&](auto I) { t[I] = std::get(u); }); } template void axes_assign(T& t, const U& u) { t.assign(u.begin(), u.end()); } template void axis_index_is_valid(const T& axes, const unsigned N) { BOOST_ASSERT_MSG(N < get_size(axes), "index out of range"); } template void for_each_axis_impl(std::true_type, const T& axes, F&& f) { for (const auto& x : axes) { axis::visit(std::forward(f), x); } } template void for_each_axis_impl(std::false_type, const T& axes, F&& f) { for (const auto& x : axes) std::forward(f)(x); } template void for_each_axis(const T& axes, F&& f) { using U = mp11::mp_first; for_each_axis_impl(is_axis_variant(), axes, std::forward(f)); } template void for_each_axis(const std::tuple& axes, F&& f) { mp11::tuple_for_each(axes, std::forward(f)); } template std::size_t bincount(const T& axes) { std::size_t n = 1; for_each_axis(axes, [&n](const auto& a) { const auto old = n; const auto s = axis::traits::extent(a); n *= s; if (s > 0 && n < old) BOOST_THROW_EXCEPTION(std::overflow_error("bincount overflow")); }); return n; } } // namespace detail } // namespace histogram } // namespace boost #endif