diff options
Diffstat (limited to 'boost/histogram/detail/axes.hpp')
-rw-r--r-- | boost/histogram/detail/axes.hpp | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/boost/histogram/detail/axes.hpp b/boost/histogram/detail/axes.hpp new file mode 100644 index 0000000000..7af45c3e45 --- /dev/null +++ b/boost/histogram/detail/axes.hpp @@ -0,0 +1,176 @@ +// 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 |