From: Sven Over Date: Tue, 5 Apr 2016 18:34:21 +0000 (-0700) Subject: folly/futures: replace MoveWrappers with generalised lambda capture X-Git-Tag: 2016.07.26~372 X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=76663af23df01607f74c00c449852f71e5d3f771;p=folly.git folly/futures: replace MoveWrappers with generalised lambda capture Summary:Now that folly::Future uses folly::Function, we can use non-copyable callbacks. That allows us to get rid of folly::MoveWrapper in the implementaion. This diff also enforces perfect forwarding in the implementation of folly::Future, thereby reducing the number of times that a callable that is passed to Future::then et al. gets passed by value. Before folly::Function, Future::then(callback) has invoked the move constructor of the callback type 5 times for small callback objects (fitting into the in-place storage inside folly::detail::Core) and 6 times for large callback objects. This has been reduced to 5 times in all cases with the switch to UniqueFunction. This diff reduces it to 2 times. Reviewed By: yfeldblum Differential Revision: D2976647 fb-gh-sync-id: 9da470d7e9130bd7ad8af762fd238ef9a3ac5892 fbshipit-source-id: 9da470d7e9130bd7ad8af762fd238ef9a3ac5892 --- diff --git a/folly/experimental/fibers/FiberManager-inl.h b/folly/experimental/fibers/FiberManager-inl.h index ff40265e..c7990c44 100644 --- a/folly/experimental/fibers/FiberManager-inl.h +++ b/folly/experimental/fibers/FiberManager-inl.h @@ -19,6 +19,7 @@ #include #include +#include #include #include #include diff --git a/folly/futures/Future-inl.h b/folly/futures/Future-inl.h index 8df0d88c..1f107f91 100644 --- a/folly/futures/Future-inl.h +++ b/folly/futures/Future-inl.h @@ -109,7 +109,7 @@ template template void Future::setCallback_(F&& func) { throwIfInvalid(); - core_->setCallback(std::move(func)); + core_->setCallback(std::forward(func)); } // unwrap @@ -131,19 +131,17 @@ Future::unwrap() { template template typename std::enable_if::type -Future::thenImplementation(F func, detail::argResult) { +Future::thenImplementation(F&& func, detail::argResult) { static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument"); typedef typename R::ReturnsFuture::Inner B; throwIfInvalid(); - // wrap these so we can move them into the lambda - folly::MoveWrapper> p; - p->core_->setInterruptHandlerNoLock(core_->getInterruptHandler()); - folly::MoveWrapper funcm(std::forward(func)); + Promise p; + p.core_->setInterruptHandlerNoLock(core_->getInterruptHandler()); // grab the Future now before we lose our handle on the Promise - auto f = p->getFuture(); + auto f = p.getFuture(); f.core_->setExecutorNoLock(getExecutor()); /* This is a bit tricky. @@ -165,9 +163,6 @@ Future::thenImplementation(F func, detail::argResult) { persist beyond the callback, if it gets moved), and so it is an optimization to just make it shared from the get-go. - We have to move in the Promise and func using the MoveWrapper - hack. (func could be copied but it's a big drag on perf). - Two subtle but important points about this design. detail::Core has no back pointers to Future or Promise, so if Future or Promise get moved (and they will be moved in performant code) we don't have to do @@ -178,16 +173,14 @@ Future::thenImplementation(F func, detail::argResult) { in some circumstances, but I think it should be explicit not implicit in the destruction of the Future used to create it. */ - setCallback_( - [p, funcm](Try&& t) mutable { - if (!isTry && t.hasException()) { - p->setException(std::move(t.exception())); - } else { - p->setWith([&]() { - return (*funcm)(t.template get()...); - }); - } - }); + setCallback_([ funcm = std::forward(func), pm = std::move(p) ]( + Try && t) mutable { + if (!isTry && t.hasException()) { + pm.setException(std::move(t.exception())); + } else { + pm.setWith([&]() { return funcm(t.template get()...); }); + } + }); return f; } @@ -197,39 +190,37 @@ Future::thenImplementation(F func, detail::argResult) { template template typename std::enable_if::type -Future::thenImplementation(F func, detail::argResult) { +Future::thenImplementation(F&& func, detail::argResult) { static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument"); typedef typename R::ReturnsFuture::Inner B; throwIfInvalid(); - // wrap these so we can move them into the lambda - folly::MoveWrapper> p; - p->core_->setInterruptHandlerNoLock(core_->getInterruptHandler()); - folly::MoveWrapper funcm(std::forward(func)); + Promise p; + p.core_->setInterruptHandlerNoLock(core_->getInterruptHandler()); // grab the Future now before we lose our handle on the Promise - auto f = p->getFuture(); + auto f = p.getFuture(); f.core_->setExecutorNoLock(getExecutor()); - setCallback_( - [p, funcm](Try&& t) mutable { - if (!isTry && t.hasException()) { - p->setException(std::move(t.exception())); - } else { - try { - auto f2 = (*funcm)(t.template get()...); - // that didn't throw, now we can steal p - f2.setCallback_([p](Try&& b) mutable { - p->setTry(std::move(b)); - }); - } catch (const std::exception& e) { - p->setException(exception_wrapper(std::current_exception(), e)); - } catch (...) { - p->setException(exception_wrapper(std::current_exception())); - } + setCallback_([ funcm = std::forward(func), pm = std::move(p) ]( + Try && t) mutable { + if (!isTry && t.hasException()) { + pm.setException(std::move(t.exception())); + } else { + try { + auto f2 = funcm(t.template get()...); + // that didn't throw, now we can steal p + f2.setCallback_([p = std::move(pm)](Try && b) mutable { + p.setTry(std::move(b)); + }); + } catch (const std::exception& e) { + pm.setException(exception_wrapper(std::current_exception(), e)); + } catch (...) { + pm.setException(exception_wrapper(std::current_exception())); } - }); + } + }); return f; } @@ -279,15 +270,12 @@ Future::onError(F&& func) { Promise p; p.core_->setInterruptHandlerNoLock(core_->getInterruptHandler()); auto f = p.getFuture(); - auto pm = folly::makeMoveWrapper(std::move(p)); - auto funcm = folly::makeMoveWrapper(std::move(func)); - setCallback_([pm, funcm](Try&& t) mutable { - if (!t.template withException([&] (Exn& e) { - pm->setWith([&]{ - return (*funcm)(e); - }); - })) { - pm->setTry(std::move(t)); + + setCallback_([ funcm = std::forward(func), pm = std::move(p) ]( + Try && t) mutable { + if (!t.template withException( + [&](Exn& e) { pm.setWith([&] { return funcm(e); }); })) { + pm.setTry(std::move(t)); } }); @@ -309,22 +297,22 @@ Future::onError(F&& func) { Promise p; auto f = p.getFuture(); - auto pm = folly::makeMoveWrapper(std::move(p)); - auto funcm = folly::makeMoveWrapper(std::move(func)); - setCallback_([pm, funcm](Try&& t) mutable { - if (!t.template withException([&] (Exn& e) { + + setCallback_([ pm = std::move(p), funcm = std::forward(func) ]( + Try && t) mutable { + if (!t.template withException([&](Exn& e) { try { - auto f2 = (*funcm)(e); - f2.setCallback_([pm](Try&& t2) mutable { - pm->setTry(std::move(t2)); + auto f2 = funcm(e); + f2.setCallback_([pm = std::move(pm)](Try && t2) mutable { + pm.setTry(std::move(t2)); }); } catch (const std::exception& e2) { - pm->setException(exception_wrapper(std::current_exception(), e2)); + pm.setException(exception_wrapper(std::current_exception(), e2)); } catch (...) { - pm->setException(exception_wrapper(std::current_exception())); + pm.setException(exception_wrapper(std::current_exception())); } })) { - pm->setTry(std::move(t)); + pm.setTry(std::move(t)); } }); @@ -333,10 +321,9 @@ Future::onError(F&& func) { template template -Future Future::ensure(F func) { - MoveWrapper funcw(std::move(func)); - return this->then([funcw](Try&& t) mutable { - (*funcw)(); +Future Future::ensure(F&& func) { + return this->then([funcw = std::forward(func)](Try && t) mutable { + funcw(); return makeFuture(std::move(t)); }); } @@ -344,17 +331,15 @@ Future Future::ensure(F func) { template template Future Future::onTimeout(Duration dur, F&& func, Timekeeper* tk) { - auto funcw = folly::makeMoveWrapper(std::forward(func)); - return within(dur, tk) - .onError([funcw](TimedOut const&) { return (*funcw)(); }); + return within(dur, tk).onError([funcw = std::forward(func)]( + TimedOut const&) { return funcw(); }); } template template -typename std::enable_if< - detail::callableWith::value && - detail::Extract::ReturnsFuture::value, - Future>::type +typename std::enable_if::value && + detail::Extract::ReturnsFuture::value, + Future>::type Future::onError(F&& func) { static_assert( std::is_same::Return, Future>::value, @@ -362,24 +347,23 @@ Future::onError(F&& func) { Promise p; auto f = p.getFuture(); - auto pm = folly::makeMoveWrapper(std::move(p)); - auto funcm = folly::makeMoveWrapper(std::move(func)); - setCallback_([pm, funcm](Try t) mutable { - if (t.hasException()) { - try { - auto f2 = (*funcm)(std::move(t.exception())); - f2.setCallback_([pm](Try t2) mutable { - pm->setTry(std::move(t2)); - }); - } catch (const std::exception& e2) { - pm->setException(exception_wrapper(std::current_exception(), e2)); - } catch (...) { - pm->setException(exception_wrapper(std::current_exception())); - } - } else { - pm->setTry(std::move(t)); - } - }); + setCallback_( + [ pm = std::move(p), funcm = std::forward(func) ](Try t) mutable { + if (t.hasException()) { + try { + auto f2 = funcm(std::move(t.exception())); + f2.setCallback_([pm = std::move(pm)](Try t2) mutable { + pm.setTry(std::move(t2)); + }); + } catch (const std::exception& e2) { + pm.setException(exception_wrapper(std::current_exception(), e2)); + } catch (...) { + pm.setException(exception_wrapper(std::current_exception())); + } + } else { + pm.setTry(std::move(t)); + } + }); return f; } @@ -398,17 +382,14 @@ Future::onError(F&& func) { Promise p; auto f = p.getFuture(); - auto pm = folly::makeMoveWrapper(std::move(p)); - auto funcm = folly::makeMoveWrapper(std::move(func)); - setCallback_([pm, funcm](Try t) mutable { - if (t.hasException()) { - pm->setWith([&]{ - return (*funcm)(std::move(t.exception())); + setCallback_( + [ pm = std::move(p), funcm = std::forward(func) ](Try t) mutable { + if (t.hasException()) { + pm.setWith([&] { return funcm(std::move(t.exception())); }); + } else { + pm.setTry(std::move(t)); + } }); - } else { - pm->setTry(std::move(t)); - } - }); return f; } @@ -456,13 +437,12 @@ template inline Future Future::via(Executor* executor, int8_t priority) & { throwIfInvalid(); - MoveWrapper> p; - auto f = p->getFuture(); - then([p](Try&& t) mutable { p->setTry(std::move(t)); }); + Promise p; + auto f = p.getFuture(); + then([p = std::move(p)](Try && t) mutable { p.setTry(std::move(t)); }); return std::move(f).via(executor, priority); } - template auto via(Executor* x, Func func) -> Future::Inner> @@ -762,17 +742,19 @@ Future reduce(It first, It last, T&& initial, F&& func) { } typedef typename std::iterator_traits::value_type::value_type ItT; - typedef typename std::conditional< - detail::callableWith&&>::value, Try, ItT>::type Arg; + typedef + typename std::conditional&&>::value, + Try, + ItT>::type Arg; typedef isTry IsTry; - folly::MoveWrapper minitial(std::move(initial)); auto sfunc = std::make_shared(std::move(func)); - auto f = first->then([minitial, sfunc](Try& head) mutable { - return (*sfunc)(std::move(*minitial), - head.template get()); - }); + auto f = first->then( + [ minitial = std::move(initial), sfunc ](Try & head) mutable { + return (*sfunc)( + std::move(minitial), head.template get()); + }); for (++first; first != last; ++first) { f = collectAll(f, *first).then([sfunc](std::tuple, Try>& t) { @@ -840,12 +822,13 @@ window(Collection input, F func, size_t n) { template template Future Future::reduce(I&& initial, F&& func) { - folly::MoveWrapper minitial(std::move(initial)); - folly::MoveWrapper mfunc(std::move(func)); - return then([minitial, mfunc](T& vals) mutable { - auto ret = std::move(*minitial); + return then([ + minitial = std::forward(initial), + mfunc = std::forward(func) + ](T& vals) mutable { + auto ret = std::move(minitial); for (auto& val : vals) { - ret = (*mfunc)(std::move(ret), std::move(val)); + ret = mfunc(std::move(ret), std::move(val)); } return ret; }); @@ -881,19 +864,19 @@ Future unorderedReduce(It first, It last, T initial, F func) { first, last, [ctx](size_t /* i */, Try&& t) { - folly::MoveWrapper> mt(std::move(t)); // Futures can be completed in any order, simultaneously. // To make this non-blocking, we create a new Future chain in // the order of completion to reduce the values. // The spinlock just protects chaining a new Future, not actually // executing the reduce, which should be really fast. folly::MSLGuard lock(ctx->lock_); - ctx->memo_ = ctx->memo_.then([ctx, mt](T&& v) mutable { - // Either return a ItT&& or a Try&& depending - // on the type of the argument of func. - return ctx->func_(std::move(v), - mt->template get()); - }); + ctx->memo_ = + ctx->memo_.then([ ctx, mt = std::move(t) ](T && v) mutable { + // Either return a ItT&& or a Try&& depending + // on the type of the argument of func. + return ctx->func_(std::move(v), + mt.template get()); + }); if (++ctx->numThens_ == ctx->numFutures_) { // After reducing the value of the last Future, fulfill the Promise ctx->memo_.setCallback_( @@ -980,13 +963,15 @@ void waitImpl(Future& f) { template void waitImpl(Future& f, Duration dur) { // short-circuit if there's nothing to do - if (f.isReady()) return; + if (f.isReady()) { + return; + } - folly::MoveWrapper> promise; - auto ret = promise->getFuture(); + Promise promise; + auto ret = promise.getFuture(); auto baton = std::make_shared(); - f.setCallback_([baton, promise](Try&& t) mutable { - promise->setTry(std::move(t)); + f.setCallback_([ baton, promise = std::move(promise) ](Try && t) mutable { + promise.setTry(std::move(t)); baton->post(); }); f = std::move(ret); @@ -1089,11 +1074,10 @@ Future Future::willEqual(Future& f) { template template -Future Future::filter(F predicate) { - auto p = folly::makeMoveWrapper(std::move(predicate)); - return this->then([p](T val) { +Future Future::filter(F&& predicate) { + return this->then([p = std::forward(predicate)](T val) { T const& valConstRef = val; - if (!(*p)(valConstRef)) { + if (!p(valConstRef)) { throw PredicateDoesNotObtain(); } return val; @@ -1141,28 +1125,31 @@ auto Future::thenMultiWithExecutor(Executor* x, Callback&& fn) } template -inline Future when(bool p, F thunk) { - return p ? thunk().unit() : makeFuture(); +inline Future when(bool p, F&& thunk) { + return p ? std::forward(thunk)().unit() : makeFuture(); } template -Future whileDo(P predicate, F thunk) { +Future whileDo(P&& predicate, F&& thunk) { if (predicate()) { - return thunk().then([=] { - return whileDo(predicate, thunk); + auto future = thunk(); + return future.then([ + predicate = std::forward

(predicate), + thunk = std::forward(thunk) + ]() mutable { + return whileDo(std::forward

(predicate), std::forward(thunk)); }); } return makeFuture(); } template -Future times(const int n, F thunk) { - auto count = folly::makeMoveWrapper( - std::unique_ptr>(new std::atomic(0)) - ); - return folly::whileDo([=]() mutable { - return (*count)->fetch_add(1) < n; - }, thunk); +Future times(const int n, F&& thunk) { + return folly::whileDo( + [ n, count = folly::make_unique>(0) ]() mutable { + return count->fetch_add(1) < n; + }, + std::forward(thunk)); } namespace futures { @@ -1204,25 +1191,24 @@ retrying(size_t k, Policy&& p, FF&& ff) { using F = typename std::result_of::type; using T = typename F::value_type; auto f = ff(k++); - auto pm = makeMoveWrapper(p); - auto ffm = makeMoveWrapper(ff); - return f.onError([=](exception_wrapper x) mutable { - auto q = (*pm)(k, x); - auto xm = makeMoveWrapper(std::move(x)); - return q.then([=](bool r) mutable { - return r - ? retrying(k, pm.move(), ffm.move()) - : makeFuture(xm.move()); + return f.onError( + [ k, pm = std::forward(p), ffm = std::forward(ff) ]( + exception_wrapper x) mutable { + auto q = pm(k, x); + return q.then( + [ k, xm = std::move(x), pm = std::move(pm), ffm = std::move(ffm) ]( + bool r) mutable { + return r ? retrying(k, std::move(pm), std::move(ffm)) + : makeFuture(std::move(xm)); + }); }); - }); } template typename std::result_of::type retrying(Policy&& p, FF&& ff, retrying_policy_raw_tag) { - auto pm = makeMoveWrapper(std::move(p)); - auto q = [=](size_t k, exception_wrapper x) { - return makeFuture((*pm)(k, x)); + auto q = [pm = std::forward(p)](size_t k, exception_wrapper x) { + return makeFuture(pm(k, x)); }; return retrying(0, std::move(q), std::forward(ff)); } @@ -1255,18 +1241,29 @@ retryingPolicyCappedJitteredExponentialBackoff( Duration backoff_min, Duration backoff_max, double jitter_param, - URNG rng, + URNG&& rng, Policy&& p) { - auto pm = makeMoveWrapper(std::move(p)); - auto rngp = std::make_shared(std::move(rng)); - return [=](size_t n, const exception_wrapper& ex) mutable { - if (n == max_tries) { return makeFuture(false); } - return (*pm)(n, ex).then([=](bool v) { - if (!v) { return makeFuture(false); } - auto backoff = detail::retryingJitteredExponentialBackoffDur( - n, backoff_min, backoff_max, jitter_param, *rngp); - return futures::sleep(backoff).then([] { return true; }); - }); + return [ + pm = std::forward(p), + max_tries, + backoff_min, + backoff_max, + jitter_param, + rngp = std::forward(rng) + ](size_t n, const exception_wrapper& ex) mutable { + if (n == max_tries) { + return makeFuture(false); + } + return pm(n, ex).then( + [ n, backoff_min, backoff_max, jitter_param, rngp = std::move(rngp) ]( + bool v) mutable { + if (!v) { + return makeFuture(false); + } + auto backoff = detail::retryingJitteredExponentialBackoffDur( + n, backoff_min, backoff_max, jitter_param, rngp); + return futures::sleep(backoff).then([] { return true; }); + }); }; } @@ -1277,19 +1274,19 @@ retryingPolicyCappedJitteredExponentialBackoff( Duration backoff_min, Duration backoff_max, double jitter_param, - URNG rng, + URNG&& rng, Policy&& p, retrying_policy_raw_tag) { - auto pm = makeMoveWrapper(std::move(p)); - auto q = [=](size_t n, const exception_wrapper& e) { - return makeFuture((*pm)(n, e)); + auto q = [pm = std::forward(p)]( + size_t n, const exception_wrapper& e) { + return makeFuture(pm(n, e)); }; return retryingPolicyCappedJitteredExponentialBackoff( max_tries, backoff_min, backoff_max, jitter_param, - std::move(rng), + std::forward(rng), std::move(q)); } @@ -1300,7 +1297,7 @@ retryingPolicyCappedJitteredExponentialBackoff( Duration backoff_min, Duration backoff_max, double jitter_param, - URNG rng, + URNG&& rng, Policy&& p, retrying_policy_fut_tag) { return retryingPolicyCappedJitteredExponentialBackoff( @@ -1308,10 +1305,9 @@ retryingPolicyCappedJitteredExponentialBackoff( backoff_min, backoff_max, jitter_param, - std::move(rng), - std::move(p)); + std::forward(rng), + std::forward(p)); } - } template @@ -1335,7 +1331,7 @@ retryingPolicyCappedJitteredExponentialBackoff( Duration backoff_min, Duration backoff_max, double jitter_param, - URNG rng, + URNG&& rng, Policy&& p) { using tag = typename detail::retrying_policy_traits::tag; return detail::retryingPolicyCappedJitteredExponentialBackoff( @@ -1343,8 +1339,8 @@ retryingPolicyCappedJitteredExponentialBackoff( backoff_min, backoff_max, jitter_param, - std::move(rng), - std::move(p), + std::forward(rng), + std::forward(p), tag()); } diff --git a/folly/futures/Future-pre.h b/folly/futures/Future-pre.h index 8beea726..2116ce8d 100644 --- a/folly/futures/Future-pre.h +++ b/folly/futures/Future-pre.h @@ -119,8 +119,26 @@ struct Extract { typedef typename ArgType::FirstArg FirstArg; }; -} // detail +// gcc-4.8 refuses to capture a function reference in a lambda. This can be +// mitigated by casting them to function pointer types first. The following +// helper is used in Future.h to achieve that where necessary. +// When compiling with gcc versions 4.9 and up, as well as clang, we do not +// need to apply FunctionReferenceToPointer (i.e. T can be used instead of +// FunctionReferenceToPointer). +// Applying FunctionReferenceToPointer first, the code works on all tested +// compiler versions: gcc 4.8 and above, cland 3.5 and above. + +template +struct FunctionReferenceToPointer { + using type = T; +}; +template +struct FunctionReferenceToPointer { + using type = R (*)(Args...); +}; + +} // detail class Timekeeper; diff --git a/folly/futures/Future.h b/folly/futures/Future.h index cde04928..49ff679a 100644 --- a/folly/futures/Future.h +++ b/folly/futures/Future.h @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -177,10 +176,19 @@ class Future { value(), which may rethrow if this has captured an exception. If func throws, the exception will be captured in the Future that is returned. */ - template > - typename R::Return then(F func) { + // gcc 4.8 requires that we cast function reference types to function pointer + // types. Fore more details see the comment on FunctionReferenceToPointer + // in Future-pre.h. + // gcc versions 4.9 and above (as well as clang) do not require this hack. + // For those, the FF tenplate parameter can be removed and occurences of FF + // replaced with F. + template < + typename F, + typename FF = typename detail::FunctionReferenceToPointer::type, + typename R = detail::callableResult> + typename R::Return then(F&& func) { typedef typename R::Arg Arguments; - return thenImplementation(std::move(func), Arguments()); + return thenImplementation(std::forward(func), Arguments()); } /// Variant where func is an member function @@ -268,7 +276,7 @@ class Future { /// func shouldn't throw, but if it does it will be captured and propagated, /// and discard any value/exception that this Future has obtained. template - Future ensure(F func); + Future ensure(F&& func); /// Like onError, but for timeouts. example: /// @@ -386,7 +394,7 @@ class Future { /// If the predicate does not obtain with the value, the result /// is a folly::PredicateDoesNotObtain exception template - Future filter(F predicate); + Future filter(F&& predicate); /// Like reduce, but works on a Future>>, for example /// the result of collect or collectAll @@ -458,14 +466,14 @@ class Future { /// /// thunk behaves like std::function(void)> template - friend Future times(const int n, F thunk); + friend Future times(int n, F&& thunk); /// Carry out the computation contained in the given future if /// the predicate holds. /// /// thunk behaves like std::function(void)> template - friend Future when(bool p, F thunk); + friend Future when(bool p, F&& thunk); /// Carry out the computation contained in the given future if /// while the predicate continues to hold. @@ -474,19 +482,19 @@ class Future { /// /// predicate behaves like std::function template - friend Future whileDo(P predicate, F thunk); + friend Future whileDo(P&& predicate, F&& thunk); // Variant: returns a value // e.g. f.then([](Try t){ return t.value(); }); template typename std::enable_if::type - thenImplementation(F func, detail::argResult); + thenImplementation(F&& func, detail::argResult); // Variant: returns a Future // e.g. f.then([](Try t){ return makeFuture(t); }); template typename std::enable_if::type - thenImplementation(F func, detail::argResult); + thenImplementation(F&& func, detail::argResult); Executor* getExecutor() { return core_->getExecutor(); } void setExecutor(Executor* x, int8_t priority = Executor::MID_PRI) { diff --git a/folly/futures/detail/Core.h b/folly/futures/detail/Core.h index 20bb78b1..a4105900 100644 --- a/folly/futures/detail/Core.h +++ b/folly/futures/detail/Core.h @@ -149,11 +149,11 @@ class Core { /// Call only from Future thread. template - void setCallback(F func) { + void setCallback(F&& func) { bool transitionToArmed = false; auto setCallback_ = [&]{ context_ = RequestContext::saveContext(); - callback_ = std::move(func); + callback_ = std::forward(func); }; FSM_START(fsm_) diff --git a/folly/futures/helpers.h b/folly/futures/helpers.h index b393eaac..bcfd8ba3 100644 --- a/folly/futures/helpers.h +++ b/folly/futures/helpers.h @@ -367,7 +367,7 @@ retryingPolicyCappedJitteredExponentialBackoff( Duration backoff_min, Duration backoff_max, double jitter_param, - URNG rng, + URNG&& rng, Policy&& p); inline diff --git a/folly/futures/test/EnsureTest.cpp b/folly/futures/test/EnsureTest.cpp index 2ffb6e1b..62122027 100644 --- a/folly/futures/test/EnsureTest.cpp +++ b/folly/futures/test/EnsureTest.cpp @@ -19,7 +19,6 @@ #include -#include #include using namespace folly;