axes.hpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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. #ifndef BOOST_HISTOGRAM_DETAIL_AXES_HPP
  7. #define BOOST_HISTOGRAM_DETAIL_AXES_HPP
  8. #include <boost/assert.hpp>
  9. #include <boost/histogram/axis/traits.hpp>
  10. #include <boost/histogram/axis/variant.hpp>
  11. #include <boost/histogram/detail/meta.hpp>
  12. #include <boost/histogram/fwd.hpp>
  13. #include <boost/mp11/algorithm.hpp>
  14. #include <boost/mp11/list.hpp>
  15. #include <boost/mp11/tuple.hpp>
  16. #include <boost/throw_exception.hpp>
  17. #include <stdexcept>
  18. #include <tuple>
  19. #include <type_traits>
  20. namespace boost {
  21. namespace histogram {
  22. namespace detail {
  23. template <unsigned N, class... Ts>
  24. decltype(auto) axis_get(std::tuple<Ts...>& axes) {
  25. return std::get<N>(axes);
  26. }
  27. template <unsigned N, class... Ts>
  28. decltype(auto) axis_get(const std::tuple<Ts...>& axes) {
  29. return std::get<N>(axes);
  30. }
  31. template <unsigned N, class T>
  32. decltype(auto) axis_get(T& axes) {
  33. return axes[N];
  34. }
  35. template <unsigned N, class T>
  36. decltype(auto) axis_get(const T& axes) {
  37. return axes[N];
  38. }
  39. template <class... Ts>
  40. decltype(auto) axis_get(std::tuple<Ts...>& axes, unsigned i) {
  41. return mp11::mp_with_index<sizeof...(Ts)>(
  42. i, [&](auto I) { return axis::variant<Ts&...>(std::get<I>(axes)); });
  43. }
  44. template <class... Ts>
  45. decltype(auto) axis_get(const std::tuple<Ts...>& axes, unsigned i) {
  46. return mp11::mp_with_index<sizeof...(Ts)>(
  47. i, [&](auto I) { return axis::variant<const Ts&...>(std::get<I>(axes)); });
  48. }
  49. template <class T>
  50. decltype(auto) axis_get(T& axes, unsigned i) {
  51. return axes.at(i);
  52. }
  53. template <class T>
  54. decltype(auto) axis_get(const T& axes, unsigned i) {
  55. return axes.at(i);
  56. }
  57. template <class... Ts, class... Us>
  58. bool axes_equal(const std::tuple<Ts...>& ts, const std::tuple<Us...>& us) {
  59. return static_if<std::is_same<mp11::mp_list<Ts...>, mp11::mp_list<Us...>>>(
  60. [](const auto& ts, const auto& us) {
  61. using N = mp11::mp_size<remove_cvref_t<decltype(ts)>>;
  62. bool equal = true;
  63. mp11::mp_for_each<mp11::mp_iota<N>>(
  64. [&](auto I) { equal &= relaxed_equal(std::get<I>(ts), std::get<I>(us)); });
  65. return equal;
  66. },
  67. [](const auto&, const auto&) { return false; }, ts, us);
  68. }
  69. template <class... Ts, class U>
  70. bool axes_equal(const std::tuple<Ts...>& t, const U& u) {
  71. if (sizeof...(Ts) != u.size()) return false;
  72. bool equal = true;
  73. mp11::mp_for_each<mp11::mp_iota_c<sizeof...(Ts)>>(
  74. [&](auto I) { equal &= u[I] == std::get<I>(t); });
  75. return equal;
  76. }
  77. template <class T, class... Us>
  78. bool axes_equal(const T& t, const std::tuple<Us...>& u) {
  79. return axes_equal(u, t);
  80. }
  81. template <class T, class U>
  82. bool axes_equal(const T& t, const U& u) {
  83. if (t.size() != u.size()) return false;
  84. return std::equal(t.begin(), t.end(), u.begin());
  85. }
  86. template <class... Ts, class... Us>
  87. void axes_assign(std::tuple<Ts...>& t, const std::tuple<Us...>& u) {
  88. static_if<std::is_same<mp11::mp_list<Ts...>, mp11::mp_list<Us...>>>(
  89. [](auto& a, const auto& b) { a = b; },
  90. [](auto&, const auto&) {
  91. BOOST_THROW_EXCEPTION(
  92. std::invalid_argument("cannot assign axes, types do not match"));
  93. },
  94. t, u);
  95. }
  96. template <class... Ts, class U>
  97. void axes_assign(std::tuple<Ts...>& t, const U& u) {
  98. mp11::mp_for_each<mp11::mp_iota_c<sizeof...(Ts)>>([&](auto I) {
  99. using T = mp11::mp_at_c<std::tuple<Ts...>, I>;
  100. std::get<I>(t) = axis::get<T>(u[I]);
  101. });
  102. }
  103. template <class T, class... Us>
  104. void axes_assign(T& t, const std::tuple<Us...>& u) {
  105. // resize instead of reserve, because t may not be empty and we want exact capacity
  106. t.resize(sizeof...(Us));
  107. mp11::mp_for_each<mp11::mp_iota_c<sizeof...(Us)>>(
  108. [&](auto I) { t[I] = std::get<I>(u); });
  109. }
  110. template <typename T, typename U>
  111. void axes_assign(T& t, const U& u) {
  112. t.assign(u.begin(), u.end());
  113. }
  114. template <typename T>
  115. void axis_index_is_valid(const T& axes, const unsigned N) {
  116. BOOST_ASSERT_MSG(N < get_size(axes), "index out of range");
  117. }
  118. template <typename F, typename T>
  119. void for_each_axis_impl(std::true_type, const T& axes, F&& f) {
  120. for (const auto& x : axes) { axis::visit(std::forward<F>(f), x); }
  121. }
  122. template <typename F, typename T>
  123. void for_each_axis_impl(std::false_type, const T& axes, F&& f) {
  124. for (const auto& x : axes) std::forward<F>(f)(x);
  125. }
  126. template <typename F, typename T>
  127. void for_each_axis(const T& axes, F&& f) {
  128. using U = mp11::mp_first<T>;
  129. for_each_axis_impl(is_axis_variant<U>(), axes, std::forward<F>(f));
  130. }
  131. template <typename F, typename... Ts>
  132. void for_each_axis(const std::tuple<Ts...>& axes, F&& f) {
  133. mp11::tuple_for_each(axes, std::forward<F>(f));
  134. }
  135. template <typename T>
  136. std::size_t bincount(const T& axes) {
  137. std::size_t n = 1;
  138. for_each_axis(axes, [&n](const auto& a) {
  139. const auto old = n;
  140. const auto s = axis::traits::extent(a);
  141. n *= s;
  142. if (s > 0 && n < old) BOOST_THROW_EXCEPTION(std::overflow_error("bincount overflow"));
  143. });
  144. return n;
  145. }
  146. } // namespace detail
  147. } // namespace histogram
  148. } // namespace boost
  149. #endif