lazy.hpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /*!
  2. @file
  3. Defines `boost::hana::lazy`.
  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_LAZY_HPP
  9. #define BOOST_HANA_LAZY_HPP
  10. #include <boost/hana/fwd/lazy.hpp>
  11. #include <boost/hana/basic_tuple.hpp>
  12. #include <boost/hana/config.hpp>
  13. #include <boost/hana/core/make.hpp>
  14. #include <boost/hana/detail/decay.hpp>
  15. #include <boost/hana/detail/operators/adl.hpp>
  16. #include <boost/hana/detail/operators/monad.hpp>
  17. #include <boost/hana/functional/apply.hpp>
  18. #include <boost/hana/functional/compose.hpp>
  19. #include <boost/hana/functional/on.hpp>
  20. #include <boost/hana/fwd/ap.hpp>
  21. #include <boost/hana/fwd/duplicate.hpp>
  22. #include <boost/hana/fwd/eval.hpp>
  23. #include <boost/hana/fwd/extend.hpp>
  24. #include <boost/hana/fwd/extract.hpp>
  25. #include <boost/hana/fwd/flatten.hpp>
  26. #include <boost/hana/fwd/lift.hpp>
  27. #include <boost/hana/fwd/transform.hpp>
  28. #include <cstddef>
  29. #include <type_traits>
  30. #include <utility>
  31. namespace boost { namespace hana {
  32. //////////////////////////////////////////////////////////////////////////
  33. // lazy
  34. //////////////////////////////////////////////////////////////////////////
  35. template <typename Indices, typename F, typename ...Args>
  36. struct lazy_apply_t;
  37. namespace detail { struct lazy_secret { }; }
  38. template <std::size_t ...n, typename F, typename ...Args>
  39. struct lazy_apply_t<std::index_sequence<n...>, F, Args...>
  40. : detail::operators::adl<>
  41. {
  42. template <typename ...T>
  43. constexpr lazy_apply_t(detail::lazy_secret, T&& ...t)
  44. : storage_{static_cast<T&&>(t)...}
  45. { }
  46. basic_tuple<F, Args...> storage_;
  47. using hana_tag = lazy_tag;
  48. };
  49. template <typename X>
  50. struct lazy_value_t : detail::operators::adl<> {
  51. template <typename Y>
  52. constexpr lazy_value_t(detail::lazy_secret, Y&& y)
  53. : storage_{static_cast<Y&&>(y)}
  54. { }
  55. basic_tuple<X> storage_;
  56. using hana_tag = lazy_tag;
  57. // If this is called, we assume that `X` is in fact a function.
  58. template <typename ...Args>
  59. constexpr lazy_apply_t<
  60. std::make_index_sequence<sizeof...(Args)>,
  61. X, typename detail::decay<Args>::type...
  62. > operator()(Args&& ...args) const& {
  63. return {detail::lazy_secret{},
  64. hana::at_c<0>(storage_), static_cast<Args&&>(args)...};
  65. }
  66. template <typename ...Args>
  67. constexpr lazy_apply_t<
  68. std::make_index_sequence<sizeof...(Args)>,
  69. X, typename detail::decay<Args>::type...
  70. > operator()(Args&& ...args) && {
  71. return {detail::lazy_secret{},
  72. static_cast<X&&>(hana::at_c<0>(storage_)),
  73. static_cast<Args&&>(args)...
  74. };
  75. }
  76. };
  77. //////////////////////////////////////////////////////////////////////////
  78. // make<lazy_tag>
  79. //////////////////////////////////////////////////////////////////////////
  80. template <>
  81. struct make_impl<lazy_tag> {
  82. template <typename X>
  83. static constexpr lazy_value_t<typename detail::decay<X>::type> apply(X&& x) {
  84. return {detail::lazy_secret{}, static_cast<X&&>(x)};
  85. }
  86. };
  87. //////////////////////////////////////////////////////////////////////////
  88. // Operators
  89. //////////////////////////////////////////////////////////////////////////
  90. namespace detail {
  91. template <>
  92. struct monad_operators<lazy_tag> { static constexpr bool value = true; };
  93. }
  94. //////////////////////////////////////////////////////////////////////////
  95. // eval for lazy_tag
  96. //////////////////////////////////////////////////////////////////////////
  97. template <>
  98. struct eval_impl<lazy_tag> {
  99. // lazy_apply_t
  100. template <std::size_t ...n, typename F, typename ...Args>
  101. static constexpr decltype(auto)
  102. apply(lazy_apply_t<std::index_sequence<n...>, F, Args...> const& expr) {
  103. return hana::at_c<0>(expr.storage_)(
  104. hana::at_c<n+1>(expr.storage_)...
  105. );
  106. }
  107. template <std::size_t ...n, typename F, typename ...Args>
  108. static constexpr decltype(auto)
  109. apply(lazy_apply_t<std::index_sequence<n...>, F, Args...>& expr) {
  110. return hana::at_c<0>(expr.storage_)(
  111. hana::at_c<n+1>(expr.storage_)...
  112. );
  113. }
  114. template <std::size_t ...n, typename F, typename ...Args>
  115. static constexpr decltype(auto)
  116. apply(lazy_apply_t<std::index_sequence<n...>, F, Args...>&& expr) {
  117. return static_cast<F&&>(hana::at_c<0>(expr.storage_))(
  118. static_cast<Args&&>(hana::at_c<n+1>(expr.storage_))...
  119. );
  120. }
  121. // lazy_value_t
  122. template <typename X>
  123. static constexpr X const& apply(lazy_value_t<X> const& expr)
  124. { return hana::at_c<0>(expr.storage_); }
  125. template <typename X>
  126. static constexpr X& apply(lazy_value_t<X>& expr)
  127. { return hana::at_c<0>(expr.storage_); }
  128. template <typename X>
  129. static constexpr X apply(lazy_value_t<X>&& expr)
  130. { return static_cast<X&&>(hana::at_c<0>(expr.storage_)); }
  131. };
  132. //////////////////////////////////////////////////////////////////////////
  133. // Functor
  134. //////////////////////////////////////////////////////////////////////////
  135. template <>
  136. struct transform_impl<lazy_tag> {
  137. template <typename Expr, typename F>
  138. static constexpr auto apply(Expr&& expr, F&& f) {
  139. return hana::make_lazy(hana::compose(static_cast<F&&>(f), hana::eval))(
  140. static_cast<Expr&&>(expr)
  141. );
  142. }
  143. };
  144. //////////////////////////////////////////////////////////////////////////
  145. // Applicative
  146. //////////////////////////////////////////////////////////////////////////
  147. template <>
  148. struct lift_impl<lazy_tag> {
  149. template <typename X>
  150. static constexpr lazy_value_t<typename detail::decay<X>::type>
  151. apply(X&& x) {
  152. return {detail::lazy_secret{}, static_cast<X&&>(x)};
  153. }
  154. };
  155. template <>
  156. struct ap_impl<lazy_tag> {
  157. template <typename F, typename X>
  158. static constexpr decltype(auto) apply(F&& f, X&& x) {
  159. return hana::make_lazy(hana::on(hana::apply, hana::eval))(
  160. static_cast<F&&>(f), static_cast<X&&>(x)
  161. );
  162. }
  163. };
  164. //////////////////////////////////////////////////////////////////////////
  165. // Monad
  166. //////////////////////////////////////////////////////////////////////////
  167. template <>
  168. struct flatten_impl<lazy_tag> {
  169. template <typename Expr>
  170. static constexpr decltype(auto) apply(Expr&& expr) {
  171. return hana::make_lazy(hana::compose(hana::eval, hana::eval))(
  172. static_cast<Expr&&>(expr)
  173. );
  174. }
  175. };
  176. //////////////////////////////////////////////////////////////////////////
  177. // Comonad
  178. //////////////////////////////////////////////////////////////////////////
  179. template <>
  180. struct extract_impl<lazy_tag> {
  181. template <typename Expr>
  182. static constexpr decltype(auto) apply(Expr&& expr)
  183. { return hana::eval(static_cast<Expr&&>(expr)); }
  184. };
  185. template <>
  186. struct duplicate_impl<lazy_tag> {
  187. template <typename Expr>
  188. static constexpr decltype(auto) apply(Expr&& expr)
  189. { return hana::make_lazy(static_cast<Expr&&>(expr)); }
  190. };
  191. template <>
  192. struct extend_impl<lazy_tag> {
  193. template <typename Expr, typename F>
  194. static constexpr decltype(auto) apply(Expr&& expr, F&& f) {
  195. return hana::make_lazy(static_cast<F&&>(f))(static_cast<Expr&&>(expr));
  196. }
  197. };
  198. }} // end namespace boost::hana
  199. #endif // !BOOST_HANA_LAZY_HPP