lambda_tuple.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. // Copyright Louis Dionne 2013-2017
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  4. #include <boost/hana/at.hpp>
  5. #include <boost/hana/bool.hpp>
  6. #include <boost/hana/config.hpp>
  7. #include <boost/hana/detail/variadic/at.hpp>
  8. #include <boost/hana/detail/variadic/drop_into.hpp>
  9. #include <boost/hana/detail/variadic/take.hpp>
  10. #include <boost/hana/functional/always.hpp>
  11. #include <boost/hana/functional/id.hpp>
  12. #include <boost/hana/functional/on.hpp>
  13. #include <boost/hana/fwd/append.hpp>
  14. #include <boost/hana/fwd/at.hpp>
  15. #include <boost/hana/fwd/concat.hpp>
  16. #include <boost/hana/fwd/concept/sequence.hpp>
  17. #include <boost/hana/fwd/core/make.hpp>
  18. #include <boost/hana/fwd/drop_front.hpp>
  19. #include <boost/hana/fwd/empty.hpp>
  20. #include <boost/hana/fwd/front.hpp>
  21. #include <boost/hana/fwd/prepend.hpp>
  22. #include <boost/hana/fwd/take_front.hpp>
  23. #include <boost/hana/fwd/transform.hpp>
  24. #include <boost/hana/fwd/unpack.hpp>
  25. #include <boost/hana/fwd/zip_shortest_with.hpp>
  26. #include <boost/hana/integral_constant.hpp>
  27. #include <boost/hana/is_empty.hpp>
  28. #include <boost/hana/length.hpp>
  29. #include <boost/hana/min.hpp>
  30. #include <boost/hana/minimum.hpp>
  31. #include <boost/hana/range.hpp>
  32. #include <boost/hana/unpack.hpp>
  33. #include <utility>
  34. namespace hana = boost::hana;
  35. // An interesting way of implementing tuple using lambda captures.
  36. struct lambda_tuple_tag { };
  37. template <typename Storage>
  38. struct lambda_tuple_t {
  39. explicit constexpr lambda_tuple_t(Storage&& s)
  40. : storage(std::move(s))
  41. { }
  42. using hana_tag = lambda_tuple_tag;
  43. Storage storage;
  44. };
  45. auto lambda_tuple = [](auto ...xs) {
  46. auto storage = [=](auto f) -> decltype(auto) { return f(xs...); };
  47. return lambda_tuple_t<decltype(storage)>{std::move(storage)};
  48. };
  49. namespace boost { namespace hana {
  50. //////////////////////////////////////////////////////////////////////////
  51. // Foldable
  52. //////////////////////////////////////////////////////////////////////////
  53. template <>
  54. struct unpack_impl<lambda_tuple_tag> {
  55. template <typename Xs, typename F>
  56. static constexpr decltype(auto) apply(Xs&& xs, F&& f) {
  57. return static_cast<Xs&&>(xs).storage(static_cast<F&&>(f));
  58. }
  59. };
  60. //////////////////////////////////////////////////////////////////////////
  61. // Functor
  62. //////////////////////////////////////////////////////////////////////////
  63. template <>
  64. struct transform_impl<lambda_tuple_tag> {
  65. template <typename Xs, typename F>
  66. static constexpr decltype(auto) apply(Xs&& xs, F f) {
  67. return static_cast<Xs&&>(xs).storage(
  68. [f(std::move(f))](auto&& ...xs) -> decltype(auto) {
  69. return lambda_tuple(f(static_cast<decltype(xs)&&>(xs))...);
  70. }
  71. );
  72. }
  73. };
  74. //////////////////////////////////////////////////////////////////////////
  75. // Iterable
  76. //////////////////////////////////////////////////////////////////////////
  77. template <>
  78. struct front_impl<lambda_tuple_tag> {
  79. template <typename Xs>
  80. static constexpr decltype(auto) apply(Xs&& xs) {
  81. return static_cast<Xs&&>(xs).storage(
  82. [](auto&& x, auto&& ...) -> decltype(auto) {
  83. return id(static_cast<decltype(x)&&>(x));
  84. }
  85. );
  86. }
  87. };
  88. template <>
  89. struct is_empty_impl<lambda_tuple_tag> {
  90. template <typename Xs>
  91. static constexpr decltype(auto) apply(Xs&& xs) {
  92. return static_cast<Xs&&>(xs).storage(
  93. [](auto const& ...xs) -> decltype(auto) {
  94. return hana::bool_c<sizeof...(xs) == 0>;
  95. }
  96. );
  97. }
  98. };
  99. template <>
  100. struct at_impl<lambda_tuple_tag> {
  101. template <typename Xs, typename Index>
  102. static constexpr decltype(auto) apply(Xs&& xs, Index const&) {
  103. return static_cast<Xs&&>(xs).storage(
  104. detail::variadic::at<Index::value>
  105. );
  106. }
  107. };
  108. template <>
  109. struct drop_front_impl<lambda_tuple_tag> {
  110. template <typename Xs, typename N>
  111. static constexpr decltype(auto) apply(Xs&& xs, N const& n) {
  112. auto m = min(n, length(xs));
  113. return static_cast<Xs&&>(xs).storage(
  114. detail::variadic::drop_into<hana::value(m)>(lambda_tuple)
  115. );
  116. }
  117. };
  118. //////////////////////////////////////////////////////////////////////////
  119. // MonadPlus
  120. //////////////////////////////////////////////////////////////////////////
  121. template <>
  122. struct concat_impl<lambda_tuple_tag> {
  123. template <typename Xs, typename Ys>
  124. static constexpr decltype(auto) apply(Xs&& xs, Ys&& ys) {
  125. return static_cast<Xs&&>(xs).storage(
  126. [ys(static_cast<Ys&&>(ys))](auto&& ...xs) -> decltype(auto) {
  127. return std::move(ys).storage(
  128. // We can't initialize the capture with perfect
  129. // forwarding since that's not supported by the
  130. // language.
  131. [=](auto&& ...ys) -> decltype(auto) {
  132. return lambda_tuple(
  133. std::move(xs)...,
  134. static_cast<decltype(ys)&&>(ys)...
  135. );
  136. }
  137. );
  138. }
  139. );
  140. }
  141. };
  142. template <>
  143. struct prepend_impl<lambda_tuple_tag> {
  144. template <typename Xs, typename X>
  145. static constexpr decltype(auto) apply(Xs&& xs, X&& x) {
  146. return static_cast<Xs&&>(xs).storage(
  147. [x(static_cast<X&&>(x))](auto&& ...xs) -> decltype(auto) {
  148. return lambda_tuple(
  149. std::move(x),
  150. static_cast<decltype(xs)&&>(xs)...
  151. );
  152. }
  153. );
  154. }
  155. };
  156. template <>
  157. struct append_impl<lambda_tuple_tag> {
  158. template <typename Xs, typename X>
  159. static constexpr decltype(auto) apply(Xs&& xs, X&& x) {
  160. return static_cast<Xs&&>(xs).storage(
  161. [x(static_cast<X&&>(x))](auto&& ...xs) -> decltype(auto) {
  162. return lambda_tuple(
  163. static_cast<decltype(xs)&&>(xs)...,
  164. std::move(x)
  165. );
  166. }
  167. );
  168. }
  169. };
  170. template <>
  171. struct empty_impl<lambda_tuple_tag> {
  172. static BOOST_HANA_CONSTEXPR_LAMBDA decltype(auto) apply() {
  173. return lambda_tuple();
  174. }
  175. };
  176. //////////////////////////////////////////////////////////////////////////
  177. // Sequence
  178. //////////////////////////////////////////////////////////////////////////
  179. template <>
  180. struct Sequence<lambda_tuple_tag> {
  181. static constexpr bool value = true;
  182. };
  183. template <>
  184. struct take_front_impl<lambda_tuple_tag> {
  185. template <typename Xs, typename N>
  186. static constexpr decltype(auto) apply(Xs&& xs, N const& n) {
  187. auto m = min(n, length(xs));
  188. return static_cast<Xs&&>(xs).storage(
  189. detail::variadic::take<decltype(m)::value>
  190. )(lambda_tuple);
  191. }
  192. };
  193. template <>
  194. struct zip_shortest_with_impl<lambda_tuple_tag> {
  195. template <typename F, typename ...Xss>
  196. static constexpr auto apply(F f, Xss ...tuples) {
  197. auto go = [=](auto index, auto ...nothing) {
  198. return always(f)(nothing...)(at(tuples, index)...);
  199. };
  200. auto zip_length = minimum(lambda_tuple(length(tuples)...));
  201. return unpack(make_range(size_c<0>, zip_length),
  202. on(lambda_tuple, go)
  203. );
  204. }
  205. };
  206. //////////////////////////////////////////////////////////////////////////
  207. // make
  208. //////////////////////////////////////////////////////////////////////////
  209. template <>
  210. struct make_impl<lambda_tuple_tag> {
  211. template <typename ...Xs>
  212. static constexpr decltype(auto) apply(Xs&& ...xs) {
  213. return lambda_tuple(static_cast<Xs&&>(xs)...);
  214. }
  215. };
  216. }} // end namespace boost::hana
  217. int main() {
  218. auto xs = lambda_tuple(1, '2', 3.3);
  219. static_assert(!decltype(hana::is_empty(xs))::value, "");
  220. }