future_group.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // Copyright (C) 2016-2018 T. Zachary Laine
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. //[ future_group
  7. #include <boost/yap/algorithm.hpp>
  8. #include <boost/hana/concat.hpp>
  9. // A custom expression template for future groups. It supports operators ||
  10. // and &&.
  11. template <boost::yap::expr_kind Kind, typename Tuple>
  12. struct future_expr
  13. {
  14. static boost::yap::expr_kind const kind = Kind;
  15. future_expr (Tuple && tuple) :
  16. elements (std::forward<Tuple &&>(tuple))
  17. {}
  18. Tuple elements;
  19. // Returns the transformed/flattened expression.
  20. auto get () const;
  21. };
  22. BOOST_YAP_USER_BINARY_OPERATOR(logical_or, future_expr, future_expr)
  23. BOOST_YAP_USER_BINARY_OPERATOR(logical_and, future_expr, future_expr)
  24. // A special-cased future terminal that matches the semantics from the
  25. // original Proto example.
  26. template <typename T>
  27. struct future :
  28. future_expr<boost::yap::expr_kind::terminal, boost::hana::tuple<T>>
  29. {
  30. future (T const & t = T()) :
  31. future_expr<boost::yap::expr_kind::terminal, boost::hana::tuple<T>> (boost::hana::tuple<T>{t})
  32. {}
  33. T get () const
  34. { return boost::yap::value(*this); }
  35. };
  36. template <typename T>
  37. using remove_cv_ref_t = std::remove_cv_t<std::remove_reference_t<T>>;
  38. // A transform that flattens future expressions into a tuple.
  39. struct future_transform
  40. {
  41. // Transform a terminal into its contained tuple.
  42. template <typename T>
  43. auto operator() (
  44. future_expr<
  45. boost::yap::expr_kind::terminal,
  46. boost::hana::tuple<T>
  47. > const & term
  48. ) {
  49. return term.elements;
  50. }
  51. //[ expr_xform
  52. // Transform left || right -> transform(left).
  53. template <typename T, typename U>
  54. auto operator() (
  55. future_expr<
  56. boost::yap::expr_kind::logical_or,
  57. boost::hana::tuple<T, U>
  58. > const & or_expr
  59. ) {
  60. // Recursively transform the left side, and return the result.
  61. // Without the recursion, we might return a terminal expression here
  62. // insead of a tuple.
  63. return boost::yap::transform(boost::yap::left(or_expr), *this);
  64. }
  65. //]
  66. // Transform left && right -> concat(transform(left), transform(right)).
  67. template <typename T, typename U>
  68. auto operator() (
  69. future_expr<
  70. boost::yap::expr_kind::logical_and,
  71. boost::hana::tuple<T, U>
  72. > const & and_expr
  73. ) {
  74. // Recursively transform each side, then combine the resulting tuples
  75. // into a single tuple result.
  76. return boost::hana::concat(
  77. boost::yap::transform(boost::yap::left(and_expr), *this),
  78. boost::yap::transform(boost::yap::right(and_expr), *this)
  79. );
  80. }
  81. };
  82. template <boost::yap::expr_kind Kind, typename Tuple>
  83. auto future_expr<Kind, Tuple>::get () const
  84. { return boost::yap::transform(*this, future_transform{}); }
  85. // TEST CASES
  86. struct A {};
  87. struct B {};
  88. struct C {};
  89. // Called "vector" just so the code in main() will match the original Proto
  90. // example.
  91. template <typename ...T>
  92. using vector = boost::hana::tuple<T...>;
  93. int main()
  94. {
  95. future<A> a;
  96. future<B> b;
  97. future<C> c;
  98. future<vector<A,B> > ab;
  99. // Verify that various future groups have the
  100. // correct return types.
  101. A t0 = a.get();
  102. vector<A, B, C> t1 = (a && b && c).get();
  103. vector<A, C> t2 = ((a || a) && c).get();
  104. vector<A, B, C> t3 = ((a && b || a && b) && c).get();
  105. vector<vector<A, B>, C> t4 = ((ab || ab) && c).get();
  106. return 0;
  107. }
  108. //]