lazy.hpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /*=============================================================================
  2. Copyright (c) 2014 Paul Fultz II
  3. lazy.h
  4. Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. ==============================================================================*/
  7. #ifndef BOOST_HOF_GUARD_FUNCTION_LAZY_H
  8. #define BOOST_HOF_GUARD_FUNCTION_LAZY_H
  9. /// lazy
  10. /// ====
  11. ///
  12. /// Description
  13. /// -----------
  14. ///
  15. /// The `lazy` function adaptor returns a function object call wrapper for a
  16. /// function. Calling this wrapper is equivalent to invoking the function. It
  17. /// is a simple form of lambda expressions, but is constexpr friendly. By
  18. /// default, `lazy` captures all of its variables by value, just like `bind`.
  19. /// `std::ref` can be used to capture references instead.
  20. ///
  21. /// Ultimately, calling `lazy(f)(x)` is the equivalent to calling
  22. /// `std::bind(f, x)` except the lazy version can be called in a constexpr
  23. /// context, as well. The `lazy` adaptor is compatible with `std::bind`, so
  24. /// most of the time `lazy` and `std::bind` can be used interchangeably.
  25. ///
  26. /// Synopsis
  27. /// --------
  28. ///
  29. /// template<class F>
  30. /// constexpr lazy_adaptor<F> lazy(F f);
  31. ///
  32. /// Semantics
  33. /// ---------
  34. ///
  35. /// assert(lazy(f)(xs...) == std::bind(f, xs...))
  36. /// assert(lazy(f)(xs...)() == f(xs...))
  37. /// assert(lazy(f)(_1)(x) == f(x))
  38. /// assert(lazy(f)(lazy(g)(_1))(x) == f(g(x)))
  39. ///
  40. /// Requirements
  41. /// ------------
  42. ///
  43. /// F must be:
  44. ///
  45. /// * [ConstInvocable](ConstInvocable)
  46. /// * MoveConstructible
  47. ///
  48. /// Example
  49. /// -------
  50. ///
  51. /// #include <boost/hof.hpp>
  52. /// #include <cassert>
  53. /// using namespace boost::hof;
  54. ///
  55. /// int main() {
  56. /// auto add = [](auto x, auto y) { return x+y; };
  57. /// auto increment = lazy(add)(_1, 1);
  58. /// assert(increment(5) == 6);
  59. /// }
  60. ///
  61. /// References
  62. /// ----------
  63. ///
  64. /// * [std::bind](http://en.cppreference.com/w/cpp/utility/functional/bind)
  65. ///
  66. #include <boost/hof/arg.hpp>
  67. #include <boost/hof/first_of.hpp>
  68. #include <boost/hof/always.hpp>
  69. #include <boost/hof/static.hpp>
  70. #include <boost/hof/detail/delegate.hpp>
  71. #include <boost/hof/detail/compressed_pair.hpp>
  72. #include <boost/hof/pack.hpp>
  73. #include <boost/hof/detail/make.hpp>
  74. #include <boost/hof/detail/static_const_var.hpp>
  75. #include <functional>
  76. #include <type_traits>
  77. namespace boost { namespace hof {
  78. namespace detail {
  79. struct placeholder_transformer
  80. {
  81. template<class T, typename std::enable_if<(std::is_placeholder<T>::value > 0), int>::type = 0>
  82. constexpr detail::make_args_f<std::size_t, std::is_placeholder<T>::value> operator()(const T&) const noexcept
  83. {
  84. return {};
  85. }
  86. };
  87. struct bind_transformer
  88. {
  89. template<class T, typename std::enable_if<std::is_bind_expression<T>::value, int>::type = 0>
  90. constexpr const T& operator()(const T& x) const noexcept
  91. {
  92. return x;
  93. }
  94. };
  95. struct ref_transformer
  96. {
  97. template<class T>
  98. constexpr auto operator()(std::reference_wrapper<T> x) const
  99. BOOST_HOF_SFINAE_RETURNS(boost::hof::always_ref(x.get()));
  100. };
  101. struct id_transformer
  102. {
  103. template<class T>
  104. constexpr auto operator()(T&& x) const
  105. BOOST_HOF_SFINAE_RETURNS(always_detail::always_base<T>(BOOST_HOF_FORWARD(T)(x)));
  106. };
  107. BOOST_HOF_DECLARE_STATIC_VAR(pick_transformer, first_of_adaptor<placeholder_transformer, bind_transformer, ref_transformer, id_transformer>);
  108. template<class T, class Pack>
  109. constexpr auto lazy_transform(T&& x, const Pack& p) BOOST_HOF_RETURNS
  110. (
  111. p(boost::hof::detail::pick_transformer(BOOST_HOF_FORWARD(T)(x)))
  112. );
  113. template<class F, class Pack>
  114. struct lazy_unpack
  115. {
  116. const F& f;
  117. const Pack& p;
  118. constexpr lazy_unpack(const F& fp, const Pack& pp) noexcept
  119. : f(fp), p(pp)
  120. {}
  121. template<class... Ts>
  122. constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS
  123. (
  124. f(lazy_transform(BOOST_HOF_FORWARD(Ts)(xs), p)...)
  125. );
  126. };
  127. template<class F, class Pack>
  128. constexpr lazy_unpack<F, Pack> make_lazy_unpack(const F& f, const Pack& p) noexcept
  129. {
  130. return lazy_unpack<F, Pack>(f, p);
  131. }
  132. template<class F, class Pack>
  133. struct lazy_invoker
  134. : detail::compressed_pair<F, Pack>
  135. {
  136. typedef detail::compressed_pair<F, Pack> base_type;
  137. typedef lazy_invoker fit_rewritable1_tag;
  138. #ifdef _MSC_VER
  139. BOOST_HOF_INHERIT_CONSTRUCTOR(lazy_invoker, base_type)
  140. #else
  141. BOOST_HOF_INHERIT_DEFAULT_EMPTY(lazy_invoker, base_type)
  142. template<class X, class Y,
  143. BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(base_type, X&&, Y&&)
  144. >
  145. constexpr lazy_invoker(X&& x, Y&& y)
  146. BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(base_type, X&&, Y&&)
  147. : base_type(BOOST_HOF_FORWARD(X)(x), BOOST_HOF_FORWARD(Y)(y))
  148. {}
  149. #endif
  150. template<class... Ts>
  151. constexpr const F& base_function(Ts&&... xs) const noexcept
  152. {
  153. return this->first(xs...);
  154. }
  155. template<class... Ts>
  156. constexpr const Pack& get_pack(Ts&&... xs) const noexcept
  157. {
  158. return this->second(xs...);
  159. }
  160. BOOST_HOF_RETURNS_CLASS(lazy_invoker);
  161. template<class... Ts>
  162. constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS
  163. (
  164. BOOST_HOF_MANGLE_CAST(const Pack&)(BOOST_HOF_CONST_THIS->get_pack(xs...))(
  165. boost::hof::detail::make_lazy_unpack(
  166. BOOST_HOF_MANGLE_CAST(const F&)(BOOST_HOF_CONST_THIS->base_function(xs...)),
  167. boost::hof::pack_forward(BOOST_HOF_FORWARD(Ts)(xs)...)
  168. )
  169. )
  170. );
  171. };
  172. template<class F, class Pack>
  173. constexpr lazy_invoker<F, Pack> make_lazy_invoker(F f, Pack pack)
  174. BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(lazy_invoker<F, Pack>, F&&, Pack&&)
  175. {
  176. return lazy_invoker<F, Pack>(static_cast<F&&>(f), static_cast<Pack&&>(pack));
  177. }
  178. template<class F>
  179. struct lazy_nullary_invoker : F
  180. {
  181. BOOST_HOF_INHERIT_CONSTRUCTOR(lazy_nullary_invoker, F);
  182. template<class... Ts>
  183. constexpr const F& base_function(Ts&&... xs) const noexcept
  184. {
  185. return boost::hof::always_ref(*this)(xs...);
  186. }
  187. BOOST_HOF_RETURNS_CLASS(lazy_nullary_invoker);
  188. template<class... Ts>
  189. constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS
  190. (
  191. BOOST_HOF_MANGLE_CAST(const F&)(BOOST_HOF_CONST_THIS->base_function(xs...))()
  192. );
  193. };
  194. template<class F>
  195. constexpr lazy_nullary_invoker<F> make_lazy_nullary_invoker(F f)
  196. BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(lazy_nullary_invoker<F>, F&&)
  197. {
  198. return lazy_nullary_invoker<F>(static_cast<F&&>(f));
  199. }
  200. }
  201. template<class F>
  202. struct lazy_adaptor : detail::callable_base<F>
  203. {
  204. BOOST_HOF_INHERIT_CONSTRUCTOR(lazy_adaptor, detail::callable_base<F>);
  205. template<class... Ts>
  206. constexpr const detail::callable_base<F>& base_function(Ts&&... xs) const noexcept
  207. {
  208. return boost::hof::always_ref(*this)(xs...);
  209. }
  210. BOOST_HOF_RETURNS_CLASS(lazy_adaptor);
  211. template<class T, class... Ts>
  212. constexpr auto operator()(T x, Ts... xs) const BOOST_HOF_RETURNS
  213. (
  214. boost::hof::detail::make_lazy_invoker(BOOST_HOF_RETURNS_C_CAST(detail::callable_base<F>&&)(BOOST_HOF_CONST_THIS->base_function(x, xs...)),
  215. boost::hof::pack_basic(BOOST_HOF_RETURNS_STATIC_CAST(T&&)(x), BOOST_HOF_RETURNS_STATIC_CAST(Ts&&)(xs)...))
  216. );
  217. // Workaround for gcc 4.7
  218. template<class Unused=int>
  219. constexpr detail::lazy_nullary_invoker<F> operator()() const
  220. BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(
  221. boost::hof::detail::make_lazy_nullary_invoker(BOOST_HOF_RETURNS_C_CAST(detail::callable_base<F>&&)(
  222. BOOST_HOF_CONST_THIS->base_function(BOOST_HOF_RETURNS_CONSTRUCT(Unused)())
  223. ))
  224. )
  225. {
  226. return boost::hof::detail::make_lazy_nullary_invoker((detail::callable_base<F>&&)(
  227. this->base_function(Unused())
  228. ));
  229. }
  230. // TODO: Overloads to use with ref qualifiers
  231. // template<class... Ts>
  232. // constexpr auto operator()(Ts... xs) const& BOOST_HOF_RETURNS
  233. // (
  234. // boost::hof::detail::make_lazy_invoker(this->base_function(xs...),
  235. // pack(boost::hof::move(xs)...))
  236. // );
  237. // template<class... Ts>
  238. // constexpr auto operator()(Ts... xs) && BOOST_HOF_RETURNS
  239. // (
  240. // boost::hof::detail::make_lazy_invoker((F&&)this->base_function(xs...),
  241. // pack(boost::hof::move(xs)...))
  242. // );
  243. };
  244. BOOST_HOF_DECLARE_STATIC_VAR(lazy, detail::make<lazy_adaptor>);
  245. }} // namespace boost::hof
  246. namespace std {
  247. template<class F, class Pack>
  248. struct is_bind_expression<boost::hof::detail::lazy_invoker<F, Pack>>
  249. : std::true_type
  250. {};
  251. template<class F>
  252. struct is_bind_expression<boost::hof::detail::lazy_nullary_invoker<F>>
  253. : std::true_type
  254. {};
  255. }
  256. #endif