123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- // Copyright (C) 2016-2018 T. Zachary Laine
- //
- // 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)
- //[ future_group
- #include <boost/yap/algorithm.hpp>
- #include <boost/hana/concat.hpp>
- // A custom expression template for future groups. It supports operators ||
- // and &&.
- template <boost::yap::expr_kind Kind, typename Tuple>
- struct future_expr
- {
- static boost::yap::expr_kind const kind = Kind;
- future_expr (Tuple && tuple) :
- elements (std::forward<Tuple &&>(tuple))
- {}
- Tuple elements;
- // Returns the transformed/flattened expression.
- auto get () const;
- };
- BOOST_YAP_USER_BINARY_OPERATOR(logical_or, future_expr, future_expr)
- BOOST_YAP_USER_BINARY_OPERATOR(logical_and, future_expr, future_expr)
- // A special-cased future terminal that matches the semantics from the
- // original Proto example.
- template <typename T>
- struct future :
- future_expr<boost::yap::expr_kind::terminal, boost::hana::tuple<T>>
- {
- future (T const & t = T()) :
- future_expr<boost::yap::expr_kind::terminal, boost::hana::tuple<T>> (boost::hana::tuple<T>{t})
- {}
- T get () const
- { return boost::yap::value(*this); }
- };
- template <typename T>
- using remove_cv_ref_t = std::remove_cv_t<std::remove_reference_t<T>>;
- // A transform that flattens future expressions into a tuple.
- struct future_transform
- {
- // Transform a terminal into its contained tuple.
- template <typename T>
- auto operator() (
- future_expr<
- boost::yap::expr_kind::terminal,
- boost::hana::tuple<T>
- > const & term
- ) {
- return term.elements;
- }
- //[ expr_xform
- // Transform left || right -> transform(left).
- template <typename T, typename U>
- auto operator() (
- future_expr<
- boost::yap::expr_kind::logical_or,
- boost::hana::tuple<T, U>
- > const & or_expr
- ) {
- // Recursively transform the left side, and return the result.
- // Without the recursion, we might return a terminal expression here
- // insead of a tuple.
- return boost::yap::transform(boost::yap::left(or_expr), *this);
- }
- //]
- // Transform left && right -> concat(transform(left), transform(right)).
- template <typename T, typename U>
- auto operator() (
- future_expr<
- boost::yap::expr_kind::logical_and,
- boost::hana::tuple<T, U>
- > const & and_expr
- ) {
- // Recursively transform each side, then combine the resulting tuples
- // into a single tuple result.
- return boost::hana::concat(
- boost::yap::transform(boost::yap::left(and_expr), *this),
- boost::yap::transform(boost::yap::right(and_expr), *this)
- );
- }
- };
- template <boost::yap::expr_kind Kind, typename Tuple>
- auto future_expr<Kind, Tuple>::get () const
- { return boost::yap::transform(*this, future_transform{}); }
- // TEST CASES
- struct A {};
- struct B {};
- struct C {};
- // Called "vector" just so the code in main() will match the original Proto
- // example.
- template <typename ...T>
- using vector = boost::hana::tuple<T...>;
- int main()
- {
- 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;
- }
- //]
|