futures.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. //[ FutureGroup
  2. // Copyright 2008 Eric Niebler. Distributed under the Boost
  3. // Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. //
  6. // This is an example of using Proto transforms to implement
  7. // Howard Hinnant's future group proposal.
  8. #include <boost/fusion/include/vector.hpp>
  9. #include <boost/fusion/include/as_vector.hpp>
  10. #include <boost/fusion/include/joint_view.hpp>
  11. #include <boost/fusion/include/single_view.hpp>
  12. #include <boost/proto/core.hpp>
  13. #include <boost/proto/transform.hpp>
  14. namespace mpl = boost::mpl;
  15. namespace proto = boost::proto;
  16. namespace fusion = boost::fusion;
  17. using proto::_;
  18. template<class L,class R>
  19. struct pick_left
  20. {
  21. BOOST_MPL_ASSERT((boost::is_same<L, R>));
  22. typedef L type;
  23. };
  24. // Work-arounds for Microsoft Visual C++ 7.1
  25. #if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
  26. #define FutureGroup(x) proto::call<FutureGroup(x)>
  27. #endif
  28. // Define the grammar of future group expression, as well as a
  29. // transform to turn them into a Fusion sequence of the correct
  30. // type.
  31. struct FutureGroup
  32. : proto::or_<
  33. // terminals become a single-element Fusion sequence
  34. proto::when<
  35. proto::terminal<_>
  36. , fusion::single_view<proto::_value>(proto::_value)
  37. >
  38. // (a && b) becomes a concatenation of the sequence
  39. // from 'a' and the one from 'b':
  40. , proto::when<
  41. proto::logical_and<FutureGroup, FutureGroup>
  42. , fusion::joint_view<
  43. boost::add_const<FutureGroup(proto::_left) >
  44. , boost::add_const<FutureGroup(proto::_right) >
  45. >(FutureGroup(proto::_left), FutureGroup(proto::_right))
  46. >
  47. // (a || b) becomes the sequence for 'a', so long
  48. // as it is the same as the sequence for 'b'.
  49. , proto::when<
  50. proto::logical_or<FutureGroup, FutureGroup>
  51. , pick_left<
  52. FutureGroup(proto::_left)
  53. , FutureGroup(proto::_right)
  54. >(FutureGroup(proto::_left))
  55. >
  56. >
  57. {};
  58. #if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
  59. #undef FutureGroup
  60. #endif
  61. template<class E>
  62. struct future_expr;
  63. struct future_dom
  64. : proto::domain<proto::generator<future_expr>, FutureGroup>
  65. {};
  66. // Expressions in the future group domain have a .get()
  67. // member function that (ostensibly) blocks for the futures
  68. // to complete and returns the results in an appropriate
  69. // tuple.
  70. template<class E>
  71. struct future_expr
  72. : proto::extends<E, future_expr<E>, future_dom>
  73. {
  74. explicit future_expr(E const &e)
  75. : future_expr::proto_extends(e)
  76. {}
  77. typename fusion::result_of::as_vector<
  78. typename boost::result_of<FutureGroup(E)>::type
  79. >::type
  80. get() const
  81. {
  82. return fusion::as_vector(FutureGroup()(*this));
  83. }
  84. };
  85. // The future<> type has an even simpler .get()
  86. // member function.
  87. template<class T>
  88. struct future
  89. : future_expr<typename proto::terminal<T>::type>
  90. {
  91. future(T const &t = T())
  92. : future::proto_derived_expr(future::proto_base_expr::make(t))
  93. {}
  94. T get() const
  95. {
  96. return proto::value(*this);
  97. }
  98. };
  99. // TEST CASES
  100. struct A {};
  101. struct B {};
  102. struct C {};
  103. int main()
  104. {
  105. using fusion::vector;
  106. future<A> a;
  107. future<B> b;
  108. future<C> c;
  109. future<vector<A,B> > ab;
  110. // Verify that various future groups have the
  111. // correct return types.
  112. A t0 = a.get();
  113. vector<A, B, C> t1 = (a && b && c).get();
  114. vector<A, C> t2 = ((a || a) && c).get();
  115. vector<A, B, C> t3 = ((a && b || a && b) && c).get();
  116. vector<vector<A, B>, C> t4 = ((ab || ab) && c).get();
  117. return 0;
  118. }
  119. //]