Boost logo

Boost :

From: Anthony Williams (anthony.ajw_at_[hidden])
Date: 2008-05-30 11:14:09


"Peter Dimov" <pdimov_at_[hidden]> writes:

> Anthony Williams:
>> "Peter Dimov" <pdimov_at_[hidden]> writes:
>>
>>> (Ignoring the problem in which f1 completes with an exception and f2 is
>>> still active.)
>>
>> I think that's a non-problem. If f1 completes with an exception, f1 is
>> ready, so (f1 || f2) is ready and should propagate the exception,
>> regardless of the state of f2.
>
> The "problem" (bad choice of a word on my part) is with choosing between the
> behavior you outlined and the alternative, in which f1 || f2 only propagates
> an exception when both f1 and f2 end with an exception. Both approaches make
> sense (at least at first sight). I've chosen to implement the first in the
> pseudocode because it's easier, but the implementability of the second
> should probably be a concern as well.

OK. Let's call it "first_value()" as it returns the first value rather
than the first ready future, and we don't have to worry about operator
semantics.

Here's an implementation, based on my operator||. Note that if the
first future ready threw an exception, it takes the value or exception
from the second. If the second had a value, that's what you want. If
it didn't, you've got two exceptions, and you can either pick one at
random or throw a new exception.

As before, if you're worried about is_ready(), you can have it spawn a
thread rather than do lazy evaluation.

namespace detail
{
    template<typename R>
    class future_first_value
    {
        boost::shared_ptr<packaged_task<R> > task;
        shared_future<R> lhs;
        shared_future<R> rhs;

    public:
        future_first_value(boost::shared_ptr<packaged_task<R> > const& task_,
                  shared_future<R> const& lhs_,
                  shared_future<R> const& rhs_):
            task(task_),lhs(lhs_),rhs(rhs_)
        {}

        R operator()()
        {
            unsigned const index=wait_for_any(lhs,rhs);

            bool const is_exceptional=
                index?rhs.has_exception():lhs.has_exception();

            if(!is_exceptional)
            {
                return index?rhs.get():lhs.get();
            }
            else
            {
                return index?lhs.get():rhs.get();
            }
        }

        static void run(jss::packaged_task<int>& pt)
        {
            try
            {
                pt();
            }
            catch(task_already_started&)
            {
            }
        }

    };

}

template<typename R>
unique_future<R> first_value(shared_future<R> const& lhs,shared_future<R> const& rhs)
{
    boost::shared_ptr<packaged_task<R> > task(new packaged_task<R>);

    *task=packaged_task<R>(detail::future_first_value<R>(task,lhs,rhs));

    task->set_wait_callback(detail::future_first_value<R>::run);

    return task->get_future();
}

Anthony

-- 
Anthony Williams            | Just Software Solutions Ltd
Custom Software Development | http://www.justsoftwaresolutions.co.uk
Registered in England, Company Number 5478976.
Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk