summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/proto/example/futures.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/proto/example/futures.cpp')
-rw-r--r--src/boost/libs/proto/example/futures.cpp134
1 files changed, 134 insertions, 0 deletions
diff --git a/src/boost/libs/proto/example/futures.cpp b/src/boost/libs/proto/example/futures.cpp
new file mode 100644
index 00000000..29e77d6e
--- /dev/null
+++ b/src/boost/libs/proto/example/futures.cpp
@@ -0,0 +1,134 @@
+//[ FutureGroup
+// Copyright 2008 Eric Niebler. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// This is an example of using Proto transforms to implement
+// Howard Hinnant's future group proposal.
+
+#include <boost/fusion/include/vector.hpp>
+#include <boost/fusion/include/as_vector.hpp>
+#include <boost/fusion/include/joint_view.hpp>
+#include <boost/fusion/include/single_view.hpp>
+#include <boost/proto/core.hpp>
+#include <boost/proto/transform.hpp>
+namespace mpl = boost::mpl;
+namespace proto = boost::proto;
+namespace fusion = boost::fusion;
+using proto::_;
+
+template<class L,class R>
+struct pick_left
+{
+ BOOST_MPL_ASSERT((boost::is_same<L, R>));
+ typedef L type;
+};
+
+// Work-arounds for Microsoft Visual C++ 7.1
+#if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
+#define FutureGroup(x) proto::call<FutureGroup(x)>
+#endif
+
+// Define the grammar of future group expression, as well as a
+// transform to turn them into a Fusion sequence of the correct
+// type.
+struct FutureGroup
+ : proto::or_<
+ // terminals become a single-element Fusion sequence
+ proto::when<
+ proto::terminal<_>
+ , fusion::single_view<proto::_value>(proto::_value)
+ >
+ // (a && b) becomes a concatenation of the sequence
+ // from 'a' and the one from 'b':
+ , proto::when<
+ proto::logical_and<FutureGroup, FutureGroup>
+ , fusion::joint_view<
+ boost::add_const<FutureGroup(proto::_left) >
+ , boost::add_const<FutureGroup(proto::_right) >
+ >(FutureGroup(proto::_left), FutureGroup(proto::_right))
+ >
+ // (a || b) becomes the sequence for 'a', so long
+ // as it is the same as the sequence for 'b'.
+ , proto::when<
+ proto::logical_or<FutureGroup, FutureGroup>
+ , pick_left<
+ FutureGroup(proto::_left)
+ , FutureGroup(proto::_right)
+ >(FutureGroup(proto::_left))
+ >
+ >
+{};
+
+#if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
+#undef FutureGroup
+#endif
+
+template<class E>
+struct future_expr;
+
+struct future_dom
+ : proto::domain<proto::generator<future_expr>, FutureGroup>
+{};
+
+// Expressions in the future group domain have a .get()
+// member function that (ostensibly) blocks for the futures
+// to complete and returns the results in an appropriate
+// tuple.
+template<class E>
+struct future_expr
+ : proto::extends<E, future_expr<E>, future_dom>
+{
+ explicit future_expr(E const &e)
+ : future_expr::proto_extends(e)
+ {}
+
+ typename fusion::result_of::as_vector<
+ typename boost::result_of<FutureGroup(E)>::type
+ >::type
+ get() const
+ {
+ return fusion::as_vector(FutureGroup()(*this));
+ }
+};
+
+// The future<> type has an even simpler .get()
+// member function.
+template<class T>
+struct future
+ : future_expr<typename proto::terminal<T>::type>
+{
+ future(T const &t = T())
+ : future::proto_derived_expr(future::proto_base_expr::make(t))
+ {}
+
+ T get() const
+ {
+ return proto::value(*this);
+ }
+};
+
+// TEST CASES
+struct A {};
+struct B {};
+struct C {};
+
+int main()
+{
+ using fusion::vector;
+ future<A> a;
+ future<B> b;
+ future<C> c;
+ future<vector<A,B> > ab;
+
+ // Verify that various future groups have the
+ // correct return types.
+ A t0 = a.get();
+ vector<A, B, C> t1 = (a && b && c).get();
+ vector<A, C> t2 = ((a || a) && c).get();
+ vector<A, B, C> t3 = ((a && b || a && b) && c).get();
+ vector<vector<A, B>, C> t4 = ((ab || ab) && c).get();
+
+ return 0;
+}
+//]