From 12df824cf4b5cbd7130abdfa9bc86c1d540cafa7 Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Thu, 18 Apr 2019 16:01:48 -0700 Subject: [PATCH] ircd::ctx: Allow lambda transformation of the iterable for when_any()/when_all(). --- include/ircd/ctx/when.h | 82 +++++++++++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 19 deletions(-) diff --git a/include/ircd/ctx/when.h b/include/ircd/ctx/when.h index eb6511286..988b654d8 100644 --- a/include/ircd/ctx/when.h +++ b/include/ircd/ctx/when.h @@ -13,7 +13,10 @@ namespace ircd::ctx { + template future when_all(it first, const it &last, F&& closure); template future when_all(it first, const it &last); + + template future when_any(it first, const it &last, F&& closure); template future when_any(it first, const it &last); } @@ -22,9 +25,9 @@ namespace ircd::ctx::when { template auto &state(const future &); void all_then(promise &p); - template void any_then(promise &p, it &f); - template void set_all_then(promise &p, it &f); - template void set_any_then(promise &p, it &f); + template void any_then(promise &, it &, F&&); + template void set_all_then(promise &, it &, F&&); + template void set_any_then(promise &, it &, F&&); } /// Returns a future which becomes ready when any of the futures in the @@ -41,20 +44,39 @@ template ircd::ctx::future ircd::ctx::when_any(it first, const it &last) +{ + return when_any(first, last, [] + (auto &iterator) -> decltype(*iterator) & + { + return *iterator; + }); +} + +/// Implementation of when_any(); this requires a closure from the user which +/// knows how to use the iterable being passed. The closure must return a +/// a reference to the future. This allows for complex iterables which may +/// have pointers to pointers, etc. The default non-closure when_any() overload +/// supplies a closure that simply dereferences the argument (i.e `return *it;`) +template +ircd::ctx::future +ircd::ctx::when_any(it first, + const it &last, + F&& closure) { promise p; future ret(p); for(auto f(first); f != last; ++f) - if(is(state(*f), future_state::READY)) + if(is(state(closure(f)), future_state::READY)) { - set(when::state(*f), future_state::OBSERVED); + set(when::state(closure(f)), future_state::OBSERVED); p.set_value(f); return ret; } for(; first != last; ++first) - if(is(state(*first), future_state::PENDING)) - when::set_any_then(p, first); + if(is(state(closure(first)), future_state::PENDING)) + when::set_any_then(p, first, closure); if(refcount(p.state()) <= 1) p.set_value(first); @@ -69,12 +91,28 @@ template ircd::ctx::future ircd::ctx::when_all(it first, const it &last) +{ + return when_all(first, last, [] + (auto &iterator) -> decltype(*iterator) & + { + return *iterator; + }); +} + +/// Implementation of when_all(); this requires a closure from the user which +/// knows how to use the iterable being passed. See related when_any() docs. +template +ircd::ctx::future +ircd::ctx::when_all(it first, + const it &last, + F&& closure) { promise p; future ret(p); for(; first != last; ++first) - if(is(state(*first), future_state::PENDING)) - when::set_all_then(p, first); + if(is(state(closure(first)), future_state::PENDING)) + when::set_all_then(p, first, closure); if(refcount(p.state()) <= 1) p.set_value(); @@ -82,25 +120,29 @@ ircd::ctx::when_all(it first, return ret; } -template +template void ircd::ctx::when::set_any_then(promise &p, - it &f) + it &f, + F&& closure) { - when::state(*f).then = [p, f] // TODO: quash this alloc + when::state(closure(f)).then = [p, f, closure] // TODO: quash this alloc (shared_state_base &sb) mutable { if(sb.then) - any_then(p, f); + any_then(p, f, closure); }; } -template +template void ircd::ctx::when::set_all_then(promise &p, - it &f) + it &f, + F&& closure) { - when::state(*f).then = [p] // TODO: quash this alloc + when::state(closure(f)).then = [p] // TODO: quash this alloc (shared_state_base &sb) mutable { if(sb.then) @@ -108,15 +150,17 @@ ircd::ctx::when::set_all_then(promise &p, }; } -template +template void ircd::ctx::when::any_then(promise &p, - it &f) + it &f, + F&& closure) { if(!p.valid()) return; - set(when::state(*f), future_state::OBSERVED); + set(when::state(closure(f)), future_state::OBSERVED); p.set_value(f); }