cycle.hpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /*!
  2. @file
  3. Defines `boost::hana::cycle`.
  4. Copyright Louis Dionne 2013-2022
  5. Distributed under the Boost Software License, Version 1.0.
  6. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  7. */
  8. #ifndef BOOST_HANA_CYCLE_HPP
  9. #define BOOST_HANA_CYCLE_HPP
  10. #include <boost/hana/fwd/cycle.hpp>
  11. #include <boost/hana/at.hpp>
  12. #include <boost/hana/concat.hpp>
  13. #include <boost/hana/concept/integral_constant.hpp>
  14. #include <boost/hana/concept/monad_plus.hpp>
  15. #include <boost/hana/concept/sequence.hpp>
  16. #include <boost/hana/config.hpp>
  17. #include <boost/hana/core/dispatch.hpp>
  18. #include <boost/hana/core/make.hpp>
  19. #include <boost/hana/detail/array.hpp>
  20. #include <boost/hana/empty.hpp>
  21. #include <boost/hana/length.hpp>
  22. #include <cstddef>
  23. #include <utility>
  24. namespace boost { namespace hana {
  25. //! @cond
  26. template <typename Xs, typename N>
  27. constexpr auto cycle_t::operator()(Xs&& xs, N const& n) const {
  28. using M = typename hana::tag_of<Xs>::type;
  29. using Cycle = BOOST_HANA_DISPATCH_IF(cycle_impl<M>,
  30. hana::MonadPlus<M>::value
  31. );
  32. #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
  33. static_assert(hana::MonadPlus<M>::value,
  34. "hana::cycle(xs, n) requires 'xs' to be a MonadPlus");
  35. static_assert(hana::IntegralConstant<N>::value,
  36. "hana::cycle(xs, n) requires 'n' to be an IntegralConstant");
  37. #endif
  38. static_assert(N::value >= 0,
  39. "hana::cycle(xs, n) requires 'n' to be non-negative");
  40. return Cycle::apply(static_cast<Xs&&>(xs), n);
  41. }
  42. //! @endcond
  43. namespace detail {
  44. template <typename M, std::size_t n, bool = n % 2 == 0>
  45. struct cycle_helper;
  46. template <typename M>
  47. struct cycle_helper<M, 0, true> {
  48. template <typename Xs>
  49. static constexpr auto apply(Xs const&)
  50. { return hana::empty<M>(); }
  51. };
  52. template <typename M, std::size_t n>
  53. struct cycle_helper<M, n, true> {
  54. template <typename Xs>
  55. static constexpr auto apply(Xs const& xs)
  56. { return cycle_helper<M, n/2>::apply(hana::concat(xs, xs)); }
  57. };
  58. template <typename M, std::size_t n>
  59. struct cycle_helper<M, n, false> {
  60. template <typename Xs>
  61. static constexpr auto apply(Xs const& xs)
  62. { return hana::concat(xs, cycle_helper<M, n-1>::apply(xs)); }
  63. };
  64. }
  65. template <typename M, bool condition>
  66. struct cycle_impl<M, when<condition>> : default_ {
  67. template <typename Xs, typename N>
  68. static constexpr auto apply(Xs const& xs, N const&) {
  69. constexpr std::size_t n = N::value;
  70. return detail::cycle_helper<M, n>::apply(xs);
  71. }
  72. };
  73. namespace detail {
  74. template <std::size_t N, std::size_t Len>
  75. struct cycle_indices {
  76. static constexpr auto compute_value() {
  77. detail::array<std::size_t, N * Len> indices{};
  78. // Avoid (incorrect) Clang warning about remainder by zero
  79. // in the loop below.
  80. std::size_t len = Len;
  81. for (std::size_t i = 0; i < N * Len; ++i)
  82. indices[i] = i % len;
  83. return indices;
  84. }
  85. static constexpr auto value = compute_value();
  86. };
  87. }
  88. template <typename S>
  89. struct cycle_impl<S, when<Sequence<S>::value>> {
  90. template <typename Indices, typename Xs, std::size_t ...i>
  91. static constexpr auto cycle_helper(Xs&& xs, std::index_sequence<i...>) {
  92. constexpr auto indices = Indices::value;
  93. (void)indices; // workaround GCC warning when sizeof...(i) == 0
  94. return hana::make<S>(hana::at_c<indices[i]>(xs)...);
  95. }
  96. template <typename Xs, typename N>
  97. static constexpr auto apply(Xs&& xs, N const&) {
  98. constexpr std::size_t n = N::value;
  99. constexpr std::size_t len = decltype(hana::length(xs))::value;
  100. using Indices = detail::cycle_indices<n, len>;
  101. return cycle_helper<Indices>(static_cast<Xs&&>(xs),
  102. std::make_index_sequence<n * len>{});
  103. }
  104. };
  105. }} // end namespace boost::hana
  106. #endif // !BOOST_HANA_CYCLE_HPP