pack.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /*=============================================================================
  2. Copyright (c) 2014 Paul Fultz II
  3. pack.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_PACK_H
  8. #define BOOST_HOF_GUARD_FUNCTION_PACK_H
  9. /// pack
  10. /// ====
  11. ///
  12. /// Description
  13. /// -----------
  14. ///
  15. /// The `pack` function returns a higher order function object that takes a
  16. /// function that will be passed the initial elements. The function object is
  17. /// a sequence that can be unpacked with `unpack_adaptor` as well. Also,
  18. /// `pack_join` can be used to join multiple packs together.
  19. ///
  20. /// Synopsis
  21. /// --------
  22. ///
  23. /// // Decay everything before capturing
  24. /// template<class... Ts>
  25. /// constexpr auto pack(Ts&&... xs);
  26. ///
  27. /// // Capture lvalues by reference and rvalue reference by reference
  28. /// template<class... Ts>
  29. /// constexpr auto pack_forward(Ts&&... xs);
  30. ///
  31. /// // Capture lvalues by reference and rvalues by value.
  32. /// template<class... Ts>
  33. /// constexpr auto pack_basic(Ts&&... xs);
  34. ///
  35. /// // Join multiple packs together
  36. /// template<class... Ts>
  37. /// constexpr auto pack_join(Ts&&... xs);
  38. ///
  39. /// Semantics
  40. /// ---------
  41. ///
  42. /// assert(pack(xs...)(f) == f(xs...));
  43. /// assert(unpack(f)(pack(xs...)) == f(xs...));
  44. ///
  45. /// assert(pack_join(pack(xs...), pack(ys...)) == pack(xs..., ys...));
  46. ///
  47. ///
  48. /// Example
  49. /// -------
  50. ///
  51. /// #include <boost/hof.hpp>
  52. /// #include <cassert>
  53. /// using namespace boost::hof;
  54. ///
  55. /// struct sum
  56. /// {
  57. /// template<class T, class U>
  58. /// T operator()(T x, U y) const
  59. /// {
  60. /// return x+y;
  61. /// }
  62. /// };
  63. ///
  64. /// int main() {
  65. /// int r = pack(3, 2)(sum());
  66. /// assert(r == 5);
  67. /// }
  68. ///
  69. /// See Also
  70. /// --------
  71. ///
  72. /// * [unpack](unpack)
  73. ///
  74. #include <boost/hof/detail/seq.hpp>
  75. #include <boost/hof/detail/delegate.hpp>
  76. #include <boost/hof/detail/remove_rvalue_reference.hpp>
  77. #include <boost/hof/detail/unwrap.hpp>
  78. #include <boost/hof/detail/static_const_var.hpp>
  79. #include <boost/hof/unpack_sequence.hpp>
  80. #include <boost/hof/returns.hpp>
  81. #include <boost/hof/alias.hpp>
  82. #include <boost/hof/decay.hpp>
  83. namespace boost { namespace hof { namespace detail {
  84. template<class...>
  85. struct pack_tag
  86. {};
  87. template<class T, class Tag>
  88. struct pack_holder
  89. : detail::alias_empty<T, Tag>
  90. {};
  91. template<class Seq, class... Ts>
  92. struct pack_base;
  93. template<class T>
  94. struct is_copyable
  95. : std::integral_constant<bool, (
  96. BOOST_HOF_IS_CONSTRUCTIBLE(T, const T&)
  97. )>
  98. {};
  99. template<class T>
  100. struct is_copyable<T&>
  101. : std::true_type
  102. {};
  103. template<class T>
  104. struct is_copyable<T&&>
  105. : std::true_type
  106. {};
  107. template<class T, class Tag, class X, class... Ts, typename std::enable_if<
  108. is_copyable<T>::value && !std::is_lvalue_reference<T>::value
  109. , int>::type = 0>
  110. constexpr T pack_get(X&& x, Ts&&... xs) noexcept(BOOST_HOF_IS_NOTHROW_COPY_CONSTRUCTIBLE(T))
  111. {
  112. return static_cast<T>(boost::hof::alias_value<Tag, T>(BOOST_HOF_FORWARD(X)(x), xs...));
  113. }
  114. template<class T, class Tag, class X, class... Ts, typename std::enable_if<
  115. std::is_lvalue_reference<T>::value
  116. , int>::type = 0>
  117. constexpr T pack_get(X&& x, Ts&&... xs) noexcept
  118. {
  119. return boost::hof::alias_value<Tag, T>(x, xs...);
  120. }
  121. template<class T, class Tag, class X, class... Ts, typename std::enable_if<
  122. !is_copyable<T>::value
  123. , int>::type = 0>
  124. constexpr auto pack_get(X&& x, Ts&&... xs) BOOST_HOF_RETURNS
  125. (
  126. boost::hof::alias_value<Tag, T>(BOOST_HOF_FORWARD(X)(x), xs...)
  127. );
  128. #if (defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 7) || defined(_MSC_VER)
  129. template<class... Ts>
  130. struct pack_holder_base
  131. : Ts::type...
  132. {
  133. template<class... Xs, class=typename std::enable_if<(sizeof...(Xs) == sizeof...(Ts))>::type>
  134. constexpr pack_holder_base(Xs&&... xs)
  135. BOOST_HOF_NOEXCEPT(BOOST_HOF_AND_UNPACK(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(typename Ts::type, Xs&&)))
  136. : Ts::type(BOOST_HOF_FORWARD(Xs)(xs))...
  137. {}
  138. #ifndef _MSC_VER
  139. // BOOST_HOF_INHERIT_DEFAULT(pack_holder_base, typename std::remove_cv<typename std::remove_reference<typename Ts::type>::type>::type...)
  140. BOOST_HOF_INHERIT_DEFAULT(pack_holder_base, typename Ts::type...)
  141. #endif
  142. };
  143. template<class T>
  144. struct pack_holder_base<T>
  145. : T::type
  146. {
  147. typedef typename T::type base;
  148. BOOST_HOF_INHERIT_CONSTRUCTOR(pack_holder_base, base);
  149. };
  150. template<class... Ts>
  151. struct pack_holder_builder
  152. {
  153. template<class T, std::size_t N>
  154. struct apply
  155. : pack_holder<T, pack_tag<seq<N>, Ts...>>
  156. {};
  157. };
  158. template<std::size_t... Ns, class... Ts>
  159. struct pack_base<seq<Ns...>, Ts...>
  160. : pack_holder_base<typename pack_holder_builder<Ts...>::template apply<Ts, Ns>...>
  161. {
  162. typedef pack_holder_base<typename pack_holder_builder<Ts...>::template apply<Ts, Ns>...> base;
  163. template<class X1, class X2, class... Xs>
  164. constexpr pack_base(X1&& x1, X2&& x2, Xs&&... xs)
  165. BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(base, X1&&, X2&&, Xs&...))
  166. : base(BOOST_HOF_FORWARD(X1)(x1), BOOST_HOF_FORWARD(X2)(x2), BOOST_HOF_FORWARD(Xs)(xs)...)
  167. {}
  168. template<class X1, typename std::enable_if<(BOOST_HOF_IS_CONSTRUCTIBLE(base, X1)), int>::type = 0>
  169. constexpr pack_base(X1&& x1)
  170. BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(base, X1&&))
  171. : base(BOOST_HOF_FORWARD(X1)(x1))
  172. {}
  173. // BOOST_HOF_INHERIT_DEFAULT(pack_base, typename std::remove_cv<typename std::remove_reference<Ts>::type>::type...);
  174. BOOST_HOF_INHERIT_DEFAULT(pack_base, Ts...);
  175. BOOST_HOF_RETURNS_CLASS(pack_base);
  176. template<class F>
  177. constexpr auto operator()(F&& f) const BOOST_HOF_RETURNS
  178. (
  179. f(boost::hof::detail::pack_get<Ts, pack_tag<seq<Ns>, Ts...>>(*BOOST_HOF_CONST_THIS, f)...)
  180. );
  181. typedef std::integral_constant<std::size_t, sizeof...(Ts)> fit_function_param_limit;
  182. template<class F>
  183. struct apply
  184. : F::template apply<Ts...>
  185. {};
  186. };
  187. template<class T>
  188. struct pack_base<seq<0>, T>
  189. : pack_holder_base<pack_holder<T, pack_tag<seq<0>, T>>>
  190. {
  191. typedef pack_holder_base<pack_holder<T, pack_tag<seq<0>, T>>> base;
  192. template<class X1, typename std::enable_if<(BOOST_HOF_IS_CONSTRUCTIBLE(base, X1)), int>::type = 0>
  193. constexpr pack_base(X1&& x1)
  194. BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(base, X1&&))
  195. : base(BOOST_HOF_FORWARD(X1)(x1))
  196. {}
  197. BOOST_HOF_INHERIT_DEFAULT(pack_base, T);
  198. BOOST_HOF_RETURNS_CLASS(pack_base);
  199. template<class F>
  200. constexpr auto operator()(F&& f) const BOOST_HOF_RETURNS
  201. (
  202. f(boost::hof::detail::pack_get<T, pack_tag<seq<0>, T>>(*BOOST_HOF_CONST_THIS, f))
  203. );
  204. typedef std::integral_constant<std::size_t, 1> fit_function_param_limit;
  205. template<class F>
  206. struct apply
  207. : F::template apply<T>
  208. {};
  209. };
  210. #else
  211. template<std::size_t... Ns, class... Ts>
  212. struct pack_base<seq<Ns...>, Ts...>
  213. : pack_holder<Ts, pack_tag<seq<Ns>, Ts...>>::type...
  214. {
  215. // BOOST_HOF_INHERIT_DEFAULT(pack_base, typename std::remove_cv<typename std::remove_reference<Ts>::type>::type...);
  216. BOOST_HOF_INHERIT_DEFAULT(pack_base, Ts...);
  217. template<class... Xs, BOOST_HOF_ENABLE_IF_CONVERTIBLE_UNPACK(Xs&&, typename pack_holder<Ts, pack_tag<seq<Ns>, Ts...>>::type)>
  218. constexpr pack_base(Xs&&... xs)
  219. BOOST_HOF_NOEXCEPT(BOOST_HOF_AND_UNPACK(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(typename pack_holder<Ts, pack_tag<seq<Ns>, Ts...>>::type, Xs&&)))
  220. : pack_holder<Ts, pack_tag<seq<Ns>, Ts...>>::type(BOOST_HOF_FORWARD(Xs)(xs))...
  221. {}
  222. // typedef pack_base<seq<Ns...>, Ts...> self_t;
  223. BOOST_HOF_RETURNS_CLASS(pack_base);
  224. template<class F>
  225. constexpr auto operator()(F&& f) const BOOST_HOF_RETURNS
  226. (
  227. f(boost::hof::detail::pack_get<Ts, pack_tag<seq<Ns>, Ts...>>(*BOOST_HOF_CONST_THIS, f)...)
  228. );
  229. typedef std::integral_constant<std::size_t, sizeof...(Ts)> fit_function_param_limit;
  230. template<class F>
  231. struct apply
  232. : F::template apply<Ts...>
  233. {};
  234. };
  235. #endif
  236. template<>
  237. struct pack_base<seq<> >
  238. {
  239. template<class F>
  240. constexpr auto operator()(F&& f) const BOOST_HOF_RETURNS
  241. (f());
  242. typedef std::integral_constant<std::size_t, 0> fit_function_param_limit;
  243. template<class F>
  244. struct apply
  245. : F::template apply<>
  246. {};
  247. };
  248. #define BOOST_HOF_DETAIL_UNPACK_PACK_BASE(ref, move) \
  249. template<class F, std::size_t... Ns, class... Ts> \
  250. constexpr auto unpack_pack_base(F&& f, pack_base<seq<Ns...>, Ts...> ref x) \
  251. BOOST_HOF_RETURNS(f(boost::hof::alias_value<pack_tag<seq<Ns>, Ts...>, Ts>(move(x), f)...))
  252. BOOST_HOF_UNARY_PERFECT_FOREACH(BOOST_HOF_DETAIL_UNPACK_PACK_BASE)
  253. template<class P1, class P2>
  254. struct pack_join_base;
  255. // TODO: Extend to join more than two packs at a time
  256. template<std::size_t... Ns1, class... Ts1, std::size_t... Ns2, class... Ts2>
  257. struct pack_join_base<pack_base<seq<Ns1...>, Ts1...>, pack_base<seq<Ns2...>, Ts2...>>
  258. {
  259. static constexpr long total_size = sizeof...(Ts1) + sizeof...(Ts2);
  260. typedef pack_base<typename detail::gens<total_size>::type, Ts1..., Ts2...> result_type;
  261. template<class P1, class P2>
  262. static constexpr result_type call(P1&& p1, P2&& p2)
  263. BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(
  264. result_type(
  265. boost::hof::detail::pack_get<Ts1, pack_tag<seq<Ns1>, Ts1...>>(BOOST_HOF_FORWARD(P1)(p1))...,
  266. boost::hof::detail::pack_get<Ts2, pack_tag<seq<Ns2>, Ts2...>>(BOOST_HOF_FORWARD(P2)(p2))...)
  267. )
  268. {
  269. return result_type(
  270. boost::hof::detail::pack_get<Ts1, pack_tag<seq<Ns1>, Ts1...>>(BOOST_HOF_FORWARD(P1)(p1))...,
  271. boost::hof::detail::pack_get<Ts2, pack_tag<seq<Ns2>, Ts2...>>(BOOST_HOF_FORWARD(P2)(p2))...);
  272. }
  273. };
  274. template<class P1, class P2>
  275. struct pack_join_result
  276. : pack_join_base<
  277. typename std::remove_cv<typename std::remove_reference<P1>::type>::type,
  278. typename std::remove_cv<typename std::remove_reference<P2>::type>::type
  279. >
  280. {};
  281. struct pack_basic_f
  282. {
  283. template<class... Ts>
  284. constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS
  285. (
  286. pack_base<typename gens<sizeof...(Ts)>::type, typename remove_rvalue_reference<Ts>::type...>(BOOST_HOF_FORWARD(Ts)(xs)...)
  287. );
  288. };
  289. struct pack_forward_f
  290. {
  291. template<class... Ts>
  292. constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS
  293. (
  294. pack_base<typename gens<sizeof...(Ts)>::type, Ts&&...>(BOOST_HOF_FORWARD(Ts)(xs)...)
  295. );
  296. };
  297. struct pack_f
  298. {
  299. template<class... Ts>
  300. constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS
  301. (
  302. pack_basic_f()(boost::hof::decay(BOOST_HOF_FORWARD(Ts)(xs))...)
  303. );
  304. };
  305. template<class P1, class P2>
  306. constexpr typename pack_join_result<P1, P2>::result_type make_pack_join_dual(P1&& p1, P2&& p2)
  307. BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(pack_join_result<P1, P2>::call(BOOST_HOF_FORWARD(P1)(p1), BOOST_HOF_FORWARD(P2)(p2)))
  308. {
  309. return pack_join_result<P1, P2>::call(BOOST_HOF_FORWARD(P1)(p1), BOOST_HOF_FORWARD(P2)(p2));
  310. }
  311. // Manually compute join return type to make older gcc happy
  312. template<class... Ts>
  313. struct join_type;
  314. template<class T>
  315. struct join_type<T>
  316. {
  317. typedef T type;
  318. };
  319. template<class T, class... Ts>
  320. struct join_type<T, Ts...>
  321. {
  322. typedef typename pack_join_result<T, typename join_type<Ts...>::type>::result_type type;
  323. };
  324. template<class P1>
  325. constexpr P1 make_pack_join(P1&& p1) BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(P1, P1&&)
  326. {
  327. return BOOST_HOF_FORWARD(P1)(p1);
  328. }
  329. template<class P1, class... Ps>
  330. constexpr typename join_type<P1, Ps...>::type make_pack_join(P1&& p1, Ps&&... ps)
  331. BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(make_pack_join_dual(BOOST_HOF_FORWARD(P1)(p1), make_pack_join(BOOST_HOF_FORWARD(Ps)(ps)...)))
  332. {
  333. return make_pack_join_dual(BOOST_HOF_FORWARD(P1)(p1), make_pack_join(BOOST_HOF_FORWARD(Ps)(ps)...));
  334. }
  335. struct pack_join_f
  336. {
  337. template<class... Ps>
  338. constexpr auto operator()(Ps&&... ps) const BOOST_HOF_RETURNS
  339. (
  340. make_pack_join(BOOST_HOF_FORWARD(Ps)(ps)...)
  341. );
  342. };
  343. }
  344. BOOST_HOF_DECLARE_STATIC_VAR(pack_basic, detail::pack_basic_f);
  345. BOOST_HOF_DECLARE_STATIC_VAR(pack_forward, detail::pack_forward_f);
  346. BOOST_HOF_DECLARE_STATIC_VAR(pack, detail::pack_f);
  347. BOOST_HOF_DECLARE_STATIC_VAR(pack_join, detail::pack_join_f);
  348. template<class T, class... Ts>
  349. struct unpack_sequence<detail::pack_base<T, Ts...>>
  350. {
  351. template<class F, class P>
  352. constexpr static auto apply(F&& f, P&& p) BOOST_HOF_RETURNS
  353. (
  354. boost::hof::detail::unpack_pack_base(BOOST_HOF_FORWARD(F)(f), BOOST_HOF_FORWARD(P)(p))
  355. );
  356. };
  357. }} // namespace boost::hof
  358. #endif