
"Peter Dimov" <pdimov@pdimov.com> writes:
Anthony Williams:
"Peter Dimov" <pdimov@pdimov.com> 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