range.hpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. /*!
  2. @file
  3. Defines `boost::hana::range`.
  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_RANGE_HPP
  9. #define BOOST_HANA_RANGE_HPP
  10. #include <boost/hana/fwd/range.hpp>
  11. #include <boost/hana/bool.hpp>
  12. #include <boost/hana/concept/integral_constant.hpp>
  13. #include <boost/hana/config.hpp>
  14. #include <boost/hana/core/common.hpp>
  15. #include <boost/hana/core/to.hpp>
  16. #include <boost/hana/core/tag_of.hpp>
  17. #include <boost/hana/detail/operators/adl.hpp>
  18. #include <boost/hana/detail/operators/comparable.hpp>
  19. #include <boost/hana/detail/operators/iterable.hpp>
  20. #include <boost/hana/fwd/at.hpp>
  21. #include <boost/hana/fwd/back.hpp>
  22. #include <boost/hana/fwd/contains.hpp>
  23. #include <boost/hana/fwd/drop_front.hpp>
  24. #include <boost/hana/fwd/drop_front_exactly.hpp>
  25. #include <boost/hana/fwd/equal.hpp>
  26. #include <boost/hana/fwd/find.hpp>
  27. #include <boost/hana/fwd/front.hpp>
  28. #include <boost/hana/fwd/is_empty.hpp>
  29. #include <boost/hana/fwd/length.hpp>
  30. #include <boost/hana/fwd/maximum.hpp>
  31. #include <boost/hana/fwd/minimum.hpp>
  32. #include <boost/hana/fwd/product.hpp>
  33. #include <boost/hana/fwd/sum.hpp>
  34. #include <boost/hana/fwd/unpack.hpp>
  35. #include <boost/hana/integral_constant.hpp> // required by fwd decl and below
  36. #include <boost/hana/optional.hpp>
  37. #include <boost/hana/value.hpp>
  38. #include <cstddef>
  39. #include <utility>
  40. namespace boost { namespace hana {
  41. //////////////////////////////////////////////////////////////////////////
  42. // range<>
  43. //////////////////////////////////////////////////////////////////////////
  44. //! @cond
  45. template <typename T, T From, T To>
  46. struct range
  47. : detail::operators::adl<range<T, From, To>>
  48. , detail::iterable_operators<range<T, From, To>>
  49. {
  50. static_assert(From <= To,
  51. "hana::make_range(from, to) requires 'from <= to'");
  52. using value_type = T;
  53. static constexpr value_type from = From;
  54. static constexpr value_type to = To;
  55. };
  56. //! @endcond
  57. template <typename T, T From, T To>
  58. struct tag_of<range<T, From, To>> {
  59. using type = range_tag;
  60. };
  61. //////////////////////////////////////////////////////////////////////////
  62. // make<range_tag>
  63. //////////////////////////////////////////////////////////////////////////
  64. template <>
  65. struct make_impl<range_tag> {
  66. template <typename From, typename To>
  67. static constexpr auto apply(From const&, To const&) {
  68. #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
  69. static_assert(hana::IntegralConstant<From>::value,
  70. "hana::make_range(from, to) requires 'from' to be an IntegralConstant");
  71. static_assert(hana::IntegralConstant<To>::value,
  72. "hana::make_range(from, to) requires 'to' to be an IntegralConstant");
  73. #endif
  74. using T = typename common<
  75. typename hana::tag_of<From>::type::value_type,
  76. typename hana::tag_of<To>::type::value_type
  77. >::type;
  78. constexpr T from = hana::to<T>(From::value);
  79. constexpr T to = hana::to<T>(To::value);
  80. return range<T, from, to>{};
  81. }
  82. };
  83. //////////////////////////////////////////////////////////////////////////
  84. // Operators
  85. //////////////////////////////////////////////////////////////////////////
  86. namespace detail {
  87. template <>
  88. struct comparable_operators<range_tag> {
  89. static constexpr bool value = true;
  90. };
  91. }
  92. //////////////////////////////////////////////////////////////////////////
  93. // Comparable
  94. //////////////////////////////////////////////////////////////////////////
  95. template <>
  96. struct equal_impl<range_tag, range_tag> {
  97. template <typename R1, typename R2>
  98. static constexpr auto apply(R1 const&, R2 const&) {
  99. return hana::bool_c<
  100. (R1::from == R1::to && R2::from == R2::to) ||
  101. (R1::from == R2::from && R1::to == R2::to)
  102. >;
  103. }
  104. };
  105. //////////////////////////////////////////////////////////////////////////
  106. // Foldable
  107. //////////////////////////////////////////////////////////////////////////
  108. template <>
  109. struct unpack_impl<range_tag> {
  110. template <typename T, T from, typename F, T ...v>
  111. static constexpr decltype(auto)
  112. unpack_helper(F&& f, std::integer_sequence<T, v...>) {
  113. return static_cast<F&&>(f)(integral_constant<T, from + v>{}...);
  114. }
  115. template <typename T, T from, T to, typename F>
  116. static constexpr decltype(auto) apply(range<T, from, to> const&, F&& f) {
  117. return unpack_helper<T, from>(static_cast<F&&>(f),
  118. std::make_integer_sequence<T, to - from>{});
  119. }
  120. };
  121. template <>
  122. struct length_impl<range_tag> {
  123. template <typename T, T from, T to>
  124. static constexpr auto apply(range<T, from, to> const&)
  125. { return hana::size_c<static_cast<std::size_t>(to - from)>; }
  126. };
  127. template <>
  128. struct minimum_impl<range_tag> {
  129. template <typename T, T from, T to>
  130. static constexpr auto apply(range<T, from, to> const&)
  131. { return integral_c<T, from>; }
  132. };
  133. template <>
  134. struct maximum_impl<range_tag> {
  135. template <typename T, T from, T to>
  136. static constexpr auto apply(range<T, from, to> const&)
  137. { return integral_c<T, to-1>; }
  138. };
  139. template <>
  140. struct sum_impl<range_tag> {
  141. // Returns the sum of `[m, n]`, where `m <= n` always hold.
  142. template <typename I>
  143. static constexpr I sum_helper(I m, I n) {
  144. if (m == n)
  145. return m;
  146. // 0 == m < n
  147. else if (0 == m)
  148. return n * (n+1) / 2;
  149. // 0 < m < n
  150. else if (0 < m)
  151. return sum_helper(0, n) - sum_helper(0, m-1);
  152. // m < 0 <= n
  153. else if (0 <= n)
  154. return sum_helper(0, n) - sum_helper(0, -m);
  155. // m < n < 0
  156. else
  157. return -sum_helper(-n, -m);
  158. }
  159. template <typename, typename T, T from, T to>
  160. static constexpr auto apply(range<T, from, to> const&) {
  161. return integral_c<T, from == to ? 0 : sum_helper(from, to-1)>;
  162. }
  163. };
  164. template <>
  165. struct product_impl<range_tag> {
  166. // Returns the product of `[m, n)`, where `m <= n` always hold.
  167. template <typename I>
  168. static constexpr I product_helper(I m, I n) {
  169. if (m <= 0 && 0 < n)
  170. return 0;
  171. else {
  172. I p = 1;
  173. for (; m != n; ++m)
  174. p *= m;
  175. return p;
  176. }
  177. }
  178. template <typename, typename T, T from, T to>
  179. static constexpr auto apply(range<T, from, to> const&)
  180. { return integral_c<T, product_helper(from, to)>; }
  181. };
  182. //////////////////////////////////////////////////////////////////////////
  183. // Searchable
  184. //////////////////////////////////////////////////////////////////////////
  185. template <>
  186. struct find_impl<range_tag> {
  187. template <typename T, T from, typename N>
  188. static constexpr auto find_helper(hana::true_) {
  189. constexpr T n = N::value;
  190. return hana::just(hana::integral_c<T, n>);
  191. }
  192. template <typename T, T from, typename N>
  193. static constexpr auto find_helper(hana::false_)
  194. { return hana::nothing; }
  195. template <typename T, T from, T to, typename N>
  196. static constexpr auto apply(range<T, from, to> const&, N const&) {
  197. constexpr auto n = N::value;
  198. return find_helper<T, from, N>(hana::bool_c<(n >= from && n < to)>);
  199. }
  200. };
  201. template <>
  202. struct contains_impl<range_tag> {
  203. template <typename T, T from, T to, typename N>
  204. static constexpr auto apply(range<T, from, to> const&, N const&) {
  205. constexpr auto n = N::value;
  206. return bool_c<(n >= from && n < to)>;
  207. }
  208. };
  209. //////////////////////////////////////////////////////////////////////////
  210. // Iterable
  211. //////////////////////////////////////////////////////////////////////////
  212. template <>
  213. struct front_impl<range_tag> {
  214. template <typename T, T from, T to>
  215. static constexpr auto apply(range<T, from, to> const&)
  216. { return integral_c<T, from>; }
  217. };
  218. template <>
  219. struct is_empty_impl<range_tag> {
  220. template <typename T, T from, T to>
  221. static constexpr auto apply(range<T, from, to> const&)
  222. { return bool_c<from == to>; }
  223. };
  224. template <>
  225. struct at_impl<range_tag> {
  226. template <typename T, T from, T to, typename N>
  227. static constexpr auto apply(range<T, from, to> const&, N const&) {
  228. constexpr auto n = N::value;
  229. return integral_c<T, from + n>;
  230. }
  231. };
  232. template <>
  233. struct back_impl<range_tag> {
  234. template <typename T, T from, T to>
  235. static constexpr auto apply(range<T, from, to> const&)
  236. { return integral_c<T, to - 1>; }
  237. };
  238. template <>
  239. struct drop_front_impl<range_tag> {
  240. template <typename T, T from, T to, typename N>
  241. static constexpr auto apply(range<T, from, to> const&, N const&) {
  242. constexpr auto n = N::value;
  243. return range<T, (to < from + n ? to : from + n), to>{};
  244. }
  245. };
  246. template <>
  247. struct drop_front_exactly_impl<range_tag> {
  248. template <typename T, T from, T to, typename N>
  249. static constexpr auto apply(range<T, from, to> const&, N const&) {
  250. constexpr auto n = N::value;
  251. return range<T, from + n, to>{};
  252. }
  253. };
  254. }} // end namespace boost::hana
  255. #endif // !BOOST_HANA_RANGE_HPP