| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- // 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 <boost/assert.hpp>
- #include <boost/histogram/axis/traits.hpp>
- #include <boost/histogram/axis/variant.hpp>
- #include <boost/histogram/detail/meta.hpp>
- #include <boost/histogram/fwd.hpp>
- #include <boost/mp11/algorithm.hpp>
- #include <boost/mp11/list.hpp>
- #include <boost/mp11/tuple.hpp>
- #include <boost/throw_exception.hpp>
- #include <stdexcept>
- #include <tuple>
- #include <type_traits>
- namespace boost {
- namespace histogram {
- namespace detail {
- template <unsigned N, class... Ts>
- decltype(auto) axis_get(std::tuple<Ts...>& axes) {
- return std::get<N>(axes);
- }
- template <unsigned N, class... Ts>
- decltype(auto) axis_get(const std::tuple<Ts...>& axes) {
- return std::get<N>(axes);
- }
- template <unsigned N, class T>
- decltype(auto) axis_get(T& axes) {
- return axes[N];
- }
- template <unsigned N, class T>
- decltype(auto) axis_get(const T& axes) {
- return axes[N];
- }
- template <class... Ts>
- decltype(auto) axis_get(std::tuple<Ts...>& axes, unsigned i) {
- return mp11::mp_with_index<sizeof...(Ts)>(
- i, [&](auto I) { return axis::variant<Ts&...>(std::get<I>(axes)); });
- }
- template <class... Ts>
- decltype(auto) axis_get(const std::tuple<Ts...>& axes, unsigned i) {
- return mp11::mp_with_index<sizeof...(Ts)>(
- i, [&](auto I) { return axis::variant<const Ts&...>(std::get<I>(axes)); });
- }
- template <class T>
- decltype(auto) axis_get(T& axes, unsigned i) {
- return axes.at(i);
- }
- template <class T>
- decltype(auto) axis_get(const T& axes, unsigned i) {
- return axes.at(i);
- }
- template <class... Ts, class... Us>
- bool axes_equal(const std::tuple<Ts...>& ts, const std::tuple<Us...>& us) {
- return static_if<std::is_same<mp11::mp_list<Ts...>, mp11::mp_list<Us...>>>(
- [](const auto& ts, const auto& us) {
- using N = mp11::mp_size<remove_cvref_t<decltype(ts)>>;
- bool equal = true;
- mp11::mp_for_each<mp11::mp_iota<N>>(
- [&](auto I) { equal &= relaxed_equal(std::get<I>(ts), std::get<I>(us)); });
- return equal;
- },
- [](const auto&, const auto&) { return false; }, ts, us);
- }
- template <class... Ts, class U>
- bool axes_equal(const std::tuple<Ts...>& t, const U& u) {
- if (sizeof...(Ts) != u.size()) return false;
- bool equal = true;
- mp11::mp_for_each<mp11::mp_iota_c<sizeof...(Ts)>>(
- [&](auto I) { equal &= u[I] == std::get<I>(t); });
- return equal;
- }
- template <class T, class... Us>
- bool axes_equal(const T& t, const std::tuple<Us...>& u) {
- return axes_equal(u, t);
- }
- template <class T, class U>
- 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 <class... Ts, class... Us>
- void axes_assign(std::tuple<Ts...>& t, const std::tuple<Us...>& u) {
- static_if<std::is_same<mp11::mp_list<Ts...>, mp11::mp_list<Us...>>>(
- [](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 <class... Ts, class U>
- void axes_assign(std::tuple<Ts...>& t, const U& u) {
- mp11::mp_for_each<mp11::mp_iota_c<sizeof...(Ts)>>([&](auto I) {
- using T = mp11::mp_at_c<std::tuple<Ts...>, I>;
- std::get<I>(t) = axis::get<T>(u[I]);
- });
- }
- template <class T, class... Us>
- void axes_assign(T& t, const std::tuple<Us...>& u) {
- // resize instead of reserve, because t may not be empty and we want exact capacity
- t.resize(sizeof...(Us));
- mp11::mp_for_each<mp11::mp_iota_c<sizeof...(Us)>>(
- [&](auto I) { t[I] = std::get<I>(u); });
- }
- template <typename T, typename U>
- void axes_assign(T& t, const U& u) {
- t.assign(u.begin(), u.end());
- }
- template <typename T>
- void axis_index_is_valid(const T& axes, const unsigned N) {
- BOOST_ASSERT_MSG(N < get_size(axes), "index out of range");
- }
- template <typename F, typename T>
- void for_each_axis_impl(std::true_type, const T& axes, F&& f) {
- for (const auto& x : axes) { axis::visit(std::forward<F>(f), x); }
- }
- template <typename F, typename T>
- void for_each_axis_impl(std::false_type, const T& axes, F&& f) {
- for (const auto& x : axes) std::forward<F>(f)(x);
- }
- template <typename F, typename T>
- void for_each_axis(const T& axes, F&& f) {
- using U = mp11::mp_first<T>;
- for_each_axis_impl(is_axis_variant<U>(), axes, std::forward<F>(f));
- }
- template <typename F, typename... Ts>
- void for_each_axis(const std::tuple<Ts...>& axes, F&& f) {
- mp11::tuple_for_each(axes, std::forward<F>(f));
- }
- template <typename T>
- 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
|