From 5a81b5dfcaeb70e6271d07d2008b39604b7507da Mon Sep 17 00:00:00 2001 From: Yedidya Feldblum Date: Thu, 20 Jul 2017 01:59:24 -0700 Subject: [PATCH] Move futures helper types into folly::futures::detail Summary: [Folly] Move futures helper types into `folly::futures::detail`. From `folly::detail`, where it would be easier to collide. Especially for names like `Core`. Reviewed By: WillerZ Differential Revision: D5460766 fbshipit-source-id: 3f7bff784bbb89c7c86d2f1824323d71321c7ad6 --- folly/futures/Future-inl.h | 184 +++++++++++++++++------------- folly/futures/Future-pre.h | 4 +- folly/futures/Future.h | 37 +++--- folly/futures/Promise-inl.h | 8 +- folly/futures/Promise.h | 8 +- folly/futures/detail/Core.h | 8 +- folly/futures/detail/FSM.h | 9 +- folly/futures/helpers.h | 34 +++--- folly/futures/test/CoreTest.cpp | 4 +- folly/futures/test/FSMTest.cpp | 2 +- folly/futures/test/FutureTest.cpp | 2 +- 11 files changed, 171 insertions(+), 129 deletions(-) diff --git a/folly/futures/Future-inl.h b/folly/futures/Future-inl.h index df837c54..71ab6fba 100644 --- a/folly/futures/Future-inl.h +++ b/folly/futures/Future-inl.h @@ -39,17 +39,22 @@ namespace folly { class Timekeeper; +namespace futures { namespace detail { #if FOLLY_FUTURE_USING_FIBER typedef folly::fibers::Baton FutureBatonType; #else typedef folly::Baton<> FutureBatonType; #endif -} +} // namespace detail +} // namespace futures namespace detail { std::shared_ptr getTimekeeperSingleton(); +} // namespace detail +namespace futures { +namespace detail { // Guarantees that the stored functor is destructed before the stored promise // may be fulfilled. Assumes the stored functor to be noexcept-destructible. template @@ -123,11 +128,12 @@ inline auto makeCoreCallbackState(Promise&& p, F&& f) noexcept( return CoreCallbackState>>( std::move(p), std::forward(f)); } -} +} // namespace detail +} // namespace futures template Future Future::makeEmpty() { - return Future(detail::EmptyConstruct{}); + return Future(futures::detail::EmptyConstruct{}); } template @@ -178,12 +184,12 @@ Future& Future::operator=(Future&& other) { template template Future::Future(T2&& val) - : core_(new detail::Core(Try(std::forward(val)))) {} + : core_(new futures::detail::Core(Try(std::forward(val)))) {} template template Future::Future(typename std::enable_if::value>::type*) - : core_(new detail::Core(Try(T()))) {} + : core_(new futures::detail::Core(Try(T()))) {} template template < @@ -191,7 +197,9 @@ template < typename std::enable_if::value, int>:: type> Future::Future(in_place_t, Args&&... args) - : core_(new detail::Core(in_place, std::forward(args)...)) {} + : core_( + new futures::detail::Core(in_place, std::forward(args)...)) { +} template Future::~Future() { @@ -238,7 +246,9 @@ Future::unwrap() { template template typename std::enable_if::type -Future::thenImplementation(F&& func, detail::argResult) { +Future::thenImplementation( + F&& func, + futures::detail::argResult) { static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument"); typedef typename R::ReturnsFuture::Inner B; @@ -270,18 +280,18 @@ 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. - 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 + Two subtle but important points about this design. futures::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 anything fancy. And because we store the continuation in the - detail::Core, not in the Future, we can execute the continuation even - after the Future has gone out of scope. This is an intentional design + futures::detail::Core, not in the Future, we can execute the continuation + even after the Future has gone out of scope. This is an intentional design decision. It is likely we will want to be able to cancel a continuation in some circumstances, but I think it should be explicit not implicit in the destruction of the Future used to create it. */ setCallback_( - [state = detail::makeCoreCallbackState( + [state = futures::detail::makeCoreCallbackState( std::move(p), std::forward(func))](Try && t) mutable { if (!isTry && t.hasException()) { state.setException(std::move(t.exception())); @@ -299,7 +309,9 @@ Future::thenImplementation(F&& func, detail::argResult) { template template typename std::enable_if::type -Future::thenImplementation(F&& func, detail::argResult) { +Future::thenImplementation( + F&& func, + futures::detail::argResult) { static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument"); typedef typename R::ReturnsFuture::Inner B; @@ -313,7 +325,7 @@ Future::thenImplementation(F&& func, detail::argResult) { f.core_->setExecutorNoLock(getExecutor()); setCallback_( - [state = detail::makeCoreCallbackState( + [state = futures::detail::makeCoreCallbackState( std::move(p), std::forward(func))](Try && t) mutable { if (!isTry && t.hasException()) { state.setException(std::move(t.exception())); @@ -336,9 +348,9 @@ template template Future::Inner> Future::then(R(Caller::*func)(Args...), Caller *instance) { - typedef typename std::remove_cv< - typename std::remove_reference< - typename detail::ArgType::FirstArg>::type>::type FirstArg; + typedef typename std::remove_cv::FirstArg>::type>::type + FirstArg; return then([instance, func](Try&& t){ return (instance->*func)(t.template get::value, Args>()...); }); @@ -353,13 +365,15 @@ Future Future::then() { template template typename std::enable_if< - !detail::callableWith::value && - !detail::Extract::ReturnsFuture::value, - Future>::type + !futures::detail::callableWith::value && + !futures::detail::Extract::ReturnsFuture::value, + Future>::type Future::onError(F&& func) { - typedef std::remove_reference_t::FirstArg> Exn; + typedef std::remove_reference_t< + typename futures::detail::Extract::FirstArg> + Exn; static_assert( - std::is_same::RawReturn, T>::value, + std::is_same::RawReturn, T>::value, "Return type of onError callback must be T or Future"); Promise p; @@ -367,7 +381,7 @@ Future::onError(F&& func) { auto f = p.getFuture(); setCallback_( - [state = detail::makeCoreCallbackState( + [state = futures::detail::makeCoreCallbackState( std::move(p), std::forward(func))](Try && t) mutable { if (auto e = t.template tryGetExceptionObject()) { state.setTry(makeTryWith([&] { return state.invoke(*e); })); @@ -383,20 +397,23 @@ Future::onError(F&& func) { template template typename std::enable_if< - !detail::callableWith::value && - detail::Extract::ReturnsFuture::value, - Future>::type + !futures::detail::callableWith::value && + futures::detail::Extract::ReturnsFuture::value, + Future>::type Future::onError(F&& func) { static_assert( - std::is_same::Return, Future>::value, + std::is_same::Return, Future>:: + value, "Return type of onError callback must be T or Future"); - typedef std::remove_reference_t::FirstArg> Exn; + typedef std::remove_reference_t< + typename futures::detail::Extract::FirstArg> + Exn; Promise p; auto f = p.getFuture(); setCallback_( - [state = detail::makeCoreCallbackState( + [state = futures::detail::makeCoreCallbackState( std::move(p), std::forward(func))](Try && t) mutable { if (auto e = t.template tryGetExceptionObject()) { auto tf2 = state.tryInvoke(*e); @@ -433,18 +450,20 @@ Future Future::onTimeout(Duration dur, F&& func, Timekeeper* tk) { template template -typename std::enable_if::value && - detail::Extract::ReturnsFuture::value, - Future>::type +typename std::enable_if< + futures::detail::callableWith::value && + futures::detail::Extract::ReturnsFuture::value, + Future>::type Future::onError(F&& func) { static_assert( - std::is_same::Return, Future>::value, + std::is_same::Return, Future>:: + value, "Return type of onError callback must be T or Future"); Promise p; auto f = p.getFuture(); setCallback_( - [state = detail::makeCoreCallbackState( + [state = futures::detail::makeCoreCallbackState( std::move(p), std::forward(func))](Try t) mutable { if (t.hasException()) { auto tf2 = state.tryInvoke(std::move(t.exception())); @@ -467,18 +486,19 @@ Future::onError(F&& func) { template template typename std::enable_if< - detail::callableWith::value && - !detail::Extract::ReturnsFuture::value, - Future>::type + futures::detail::callableWith::value && + !futures::detail::Extract::ReturnsFuture::value, + Future>::type Future::onError(F&& func) { static_assert( - std::is_same::Return, Future>::value, + std::is_same::Return, Future>:: + value, "Return type of onError callback must be T or Future"); Promise p; auto f = p.getFuture(); setCallback_( - [state = detail::makeCoreCallbackState( + [state = futures::detail::makeCoreCallbackState( std::move(p), std::forward(func))](Try && t) mutable { if (t.hasException()) { state.setTry(makeTryWith( @@ -574,8 +594,7 @@ void Future::raise(exception_wrapper exception) { } template -Future::Future(detail::EmptyConstruct) noexcept - : core_(nullptr) {} +Future::Future(futures::detail::EmptyConstruct) noexcept : core_(nullptr) {} // makeFuture @@ -638,7 +657,7 @@ makeFuture(E const& e) { template Future makeFuture(Try&& t) { - return Future(new detail::Core(std::move(t))); + return Future(new futures::detail::Core(std::move(t))); } // via @@ -660,13 +679,13 @@ void mapSetCallback(InputIterator first, InputIterator last, F func) { // collectAll (variadic) template -typename detail::CollectAllVariadicContext< - typename std::decay::type::value_type...>::type +typename futures::detail::CollectAllVariadicContext< + typename std::decay::type::value_type...>::type collectAll(Fs&&... fs) { - auto ctx = std::make_shared::type::value_type...>>(); - detail::collectVariadicHelper( - ctx, std::forward(fs)...); + auto ctx = std::make_shared::type::value_type...>>(); + futures::detail::collectVariadicHelper< + futures::detail::CollectAllVariadicContext>(ctx, std::forward(fs)...); return ctx->p.getFuture(); } @@ -699,6 +718,7 @@ collectAll(InputIterator first, InputIterator last) { // collect (iterator) +namespace futures { namespace detail { template @@ -737,17 +757,18 @@ struct CollectContext { std::atomic threw {false}; }; -} +} // namespace detail +} // namespace futures template -Future::value_type::value_type>::Result> +Future::value_type::value_type>::Result> collect(InputIterator first, InputIterator last) { typedef typename std::iterator_traits::value_type::value_type T; - auto ctx = std::make_shared>( - std::distance(first, last)); + auto ctx = std::make_shared>( + std::distance(first, last)); mapSetCallback(first, last, [ctx](size_t i, Try&& t) { if (t.hasException()) { if (!ctx->threw.exchange(true)) { @@ -763,13 +784,13 @@ collect(InputIterator first, InputIterator last) { // collect (variadic) template -typename detail::CollectVariadicContext< - typename std::decay::type::value_type...>::type +typename futures::detail::CollectVariadicContext< + typename std::decay::type::value_type...>::type collect(Fs&&... fs) { - auto ctx = std::make_shared::type::value_type...>>(); - detail::collectVariadicHelper( - ctx, std::forward(fs)...); + auto ctx = std::make_shared::type::value_type...>>(); + futures::detail::collectVariadicHelper< + futures::detail::CollectVariadicContext>(ctx, std::forward(fs)...); return ctx->p.getFuture(); } @@ -878,10 +899,10 @@ Future reduce(It first, It last, T&& initial, F&& func) { } typedef typename std::iterator_traits::value_type::value_type ItT; - typedef - typename std::conditional&&>::value, - Try, - ItT>::type Arg; + typedef typename std::conditional< + futures::detail::callableWith&&>::value, + Try, + ItT>::type Arg; typedef isTry IsTry; auto sfunc = std::make_shared(std::move(func)); @@ -1083,6 +1104,7 @@ Future Future::delayed(Duration dur, Timekeeper* tk) { }); } +namespace futures { namespace detail { template @@ -1130,41 +1152,42 @@ void waitViaImpl(Future& f, DrivableExecutor* e) { assert(f.isReady()); } -} // detail +} // namespace detail +} // namespace futures template Future& Future::wait() & { - detail::waitImpl(*this); + futures::detail::waitImpl(*this); return *this; } template Future&& Future::wait() && { - detail::waitImpl(*this); + futures::detail::waitImpl(*this); return std::move(*this); } template Future& Future::wait(Duration dur) & { - detail::waitImpl(*this, dur); + futures::detail::waitImpl(*this, dur); return *this; } template Future&& Future::wait(Duration dur) && { - detail::waitImpl(*this, dur); + futures::detail::waitImpl(*this, dur); return std::move(*this); } template Future& Future::waitVia(DrivableExecutor* e) & { - detail::waitViaImpl(*this, e); + futures::detail::waitViaImpl(*this, e); return *this; } template Future&& Future::waitVia(DrivableExecutor* e) && { - detail::waitViaImpl(*this, e); + futures::detail::waitViaImpl(*this, e); return std::move(*this); } @@ -1188,20 +1211,23 @@ T Future::getVia(DrivableExecutor* e) { return std::move(waitVia(e).value()); } +namespace futures { namespace detail { - template - struct TryEquals { - static bool equals(const Try& t1, const Try& t2) { - return t1.value() == t2.value(); - } - }; -} +template +struct TryEquals { + static bool equals(const Try& t1, const Try& t2) { + return t1.value() == t2.value(); + } +}; +} // namespace detail +} // namespace futures template Future Future::willEqual(Future& f) { return collectAll(*this, f).then([](const std::tuple, Try>& t) { if (std::get<0>(t).hasValue() && std::get<1>(t).hasValue()) { - return detail::TryEquals::equals(std::get<0>(t), std::get<1>(t)); + return futures::detail::TryEquals::equals( + std::get<0>(t), std::get<1>(t)); } else { return false; } diff --git a/folly/futures/Future-pre.h b/folly/futures/Future-pre.h index bcae5b08..09fa0667 100644 --- a/folly/futures/Future-pre.h +++ b/folly/futures/Future-pre.h @@ -38,6 +38,7 @@ struct isTry : std::false_type {}; template struct isTry> : std::true_type {}; +namespace futures { namespace detail { template class Core; @@ -154,7 +155,8 @@ struct FunctionReferenceToPointer { using type = R (*)(Args...); }; -} // detail +} // namespace detail +} // namespace futures class Timekeeper; diff --git a/folly/futures/Future.h b/folly/futures/Future.h index f4959ba7..56f24483 100644 --- a/folly/futures/Future.h +++ b/folly/futures/Future.h @@ -210,8 +210,9 @@ class Future { // replaced with F. template < typename F, - typename FF = typename detail::FunctionReferenceToPointer::type, - typename R = detail::callableResult> + typename FF = + typename futures::detail::FunctionReferenceToPointer::type, + typename R = futures::detail::callableResult> typename R::Return then(F&& func) { typedef typename R::Arg Arguments; return thenImplementation(std::forward(func), Arguments()); @@ -271,33 +272,33 @@ class Future { /// }); template typename std::enable_if< - !detail::callableWith::value && - !detail::Extract::ReturnsFuture::value, - Future>::type + !futures::detail::callableWith::value && + !futures::detail::Extract::ReturnsFuture::value, + Future>::type onError(F&& func); /// Overload of onError where the error callback returns a Future template typename std::enable_if< - !detail::callableWith::value && - detail::Extract::ReturnsFuture::value, - Future>::type + !futures::detail::callableWith::value && + futures::detail::Extract::ReturnsFuture::value, + Future>::type onError(F&& func); /// Overload of onError that takes exception_wrapper and returns Future template typename std::enable_if< - detail::callableWith::value && - detail::Extract::ReturnsFuture::value, - Future>::type + futures::detail::callableWith::value && + futures::detail::Extract::ReturnsFuture::value, + Future>::type onError(F&& func); /// Overload of onError that takes exception_wrapper and returns T template typename std::enable_if< - detail::callableWith::value && - !detail::Extract::ReturnsFuture::value, - Future>::type + futures::detail::callableWith::value && + !futures::detail::Extract::ReturnsFuture::value, + Future>::type onError(F&& func); /// func is like std::function and is executed unconditionally, and @@ -482,7 +483,7 @@ class Future { } protected: - typedef detail::Core* corePtr; + typedef futures::detail::Core* corePtr; // shared core state object corePtr core_; @@ -490,7 +491,7 @@ class Future { explicit Future(corePtr obj) : core_(obj) {} - explicit Future(detail::EmptyConstruct) noexcept; + explicit Future(futures::detail::EmptyConstruct) noexcept; void detach(); @@ -529,13 +530,13 @@ class Future { // e.g. f.then([](Try t){ return t.value(); }); template typename std::enable_if::type - thenImplementation(F&& func, detail::argResult); + thenImplementation(F&& func, futures::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, futures::detail::argResult); Executor* getExecutor() { return core_->getExecutor(); } void setExecutor(Executor* x, int8_t priority = Executor::MID_PRI) { diff --git a/folly/futures/Promise-inl.h b/folly/futures/Promise-inl.h index ee5f4d52..580b044d 100644 --- a/folly/futures/Promise-inl.h +++ b/folly/futures/Promise-inl.h @@ -26,12 +26,12 @@ namespace folly { template Promise Promise::makeEmpty() noexcept { - return Promise(detail::EmptyConstruct{}); + return Promise(futures::detail::EmptyConstruct{}); } template -Promise::Promise() : retrieved_(false), core_(new detail::Core()) -{} +Promise::Promise() + : retrieved_(false), core_(new futures::detail::Core()) {} template Promise::Promise(Promise&& other) noexcept @@ -65,7 +65,7 @@ void Promise::throwIfRetrieved() { } template -Promise::Promise(detail::EmptyConstruct) noexcept +Promise::Promise(futures::detail::EmptyConstruct) noexcept : retrieved_(false), core_(nullptr) {} template diff --git a/folly/futures/Promise.h b/folly/futures/Promise.h index 4a3f51c5..42477263 100644 --- a/folly/futures/Promise.h +++ b/folly/futures/Promise.h @@ -25,11 +25,13 @@ namespace folly { // forward declaration template class Future; +namespace futures { namespace detail { struct EmptyConstruct {}; template class CoreCallbackState; -} +} // namespace detail +} // namespace futures template class Promise { @@ -107,7 +109,7 @@ class Promise { typedef typename Future::corePtr corePtr; template friend class Future; template - friend class detail::CoreCallbackState; + friend class futures::detail::CoreCallbackState; // Whether the Future has been retrieved (a one-time operation). bool retrieved_; @@ -115,7 +117,7 @@ class Promise { // shared core state object corePtr core_; - explicit Promise(detail::EmptyConstruct) noexcept; + explicit Promise(futures::detail::EmptyConstruct) noexcept; void throwIfFulfilled(); void throwIfRetrieved(); diff --git a/folly/futures/detail/Core.h b/folly/futures/detail/Core.h index 6cbdebba..f88da8e5 100644 --- a/folly/futures/detail/Core.h +++ b/folly/futures/detail/Core.h @@ -34,7 +34,9 @@ #include -namespace folly { namespace detail { +namespace folly { +namespace futures { +namespace detail { /* OnlyCallback @@ -450,4 +452,6 @@ void collectVariadicHelper(const std::shared_ptr>& ctx, collectVariadicHelper(ctx, std::forward(tail)...); } -}} // folly::detail +} // namespace detail +} // namespace futures +} // namespace folly diff --git a/folly/futures/detail/FSM.h b/folly/futures/detail/FSM.h index a9076adf..9916a918 100644 --- a/folly/futures/detail/FSM.h +++ b/folly/futures/detail/FSM.h @@ -21,7 +21,9 @@ #include -namespace folly { namespace detail { +namespace folly { +namespace futures { +namespace detail { /// Finite State Machine helper base class. /// Inherit from this. @@ -126,5 +128,6 @@ public: #define FSM_BREAK done = true; break; #define FSM_END }}} - -}} // folly::detail +} // namespace detail +} // namespace futures +} // namespace folly diff --git a/folly/futures/helpers.h b/folly/futures/helpers.h index e99a1718..c71fbe02 100644 --- a/folly/futures/helpers.h +++ b/folly/futures/helpers.h @@ -26,6 +26,7 @@ namespace folly { +namespace futures { namespace detail { template struct CollectAllVariadicContext { @@ -65,7 +66,8 @@ struct CollectVariadicContext { std::atomic threw{false}; typedef Future> type; }; -} +} // namespace detail +} // namespace futures /// This namespace is for utility functions that would usually be static /// members of Future, except they don't make sense there because they don't @@ -228,17 +230,16 @@ auto collectAll(Collection&& c) -> decltype(collectAll(c.begin(), c.end())) { /// is a Future, Try, ...>>. /// The Futures are moved in, so your copies are invalid. template -typename detail::CollectAllVariadicContext< - typename std::decay::type::value_type...>::type +typename futures::detail::CollectAllVariadicContext< + typename std::decay::type::value_type...>::type collectAll(Fs&&... fs); /// Like collectAll, but will short circuit on the first exception. Thus, the /// type of the returned Future is std::vector instead of /// std::vector> template -Future::value_type::value_type ->::result_type> +Future::value_type::value_type>::result_type> collect(InputIterator first, InputIterator last); /// Sugar for the most common case @@ -251,8 +252,8 @@ auto collect(Collection&& c) -> decltype(collect(c.begin(), c.end())) { /// type of the returned Future is std::tuple instead of /// std::tuple, Try, ...> template -typename detail::CollectVariadicContext< - typename std::decay::type::value_type...>::type +typename futures::detail::CollectVariadicContext< + typename std::decay::type::value_type...>::type collect(Fs&&... fs); /** The result is a pair of the index of the first Future to complete and @@ -317,16 +318,19 @@ auto collectN(Collection&& c, size_t n) func must return a Future for each value in input */ -template ::value_type, - class Result = typename detail::resultOf::value_type> -std::vector> -window(Collection input, F func, size_t n); +template < + class Collection, + class F, + class ItT = typename std::iterator_traits< + typename Collection::iterator>::value_type, + class Result = typename futures::detail::resultOf::value_type> +std::vector> window(Collection input, F func, size_t n); template using MaybeTryArg = typename std::conditional< - detail::callableWith&&>::value, Try, ItT>::type; + futures::detail::callableWith&&>::value, + Try, + ItT>::type; template using isFutureResult = isFuture::type>; diff --git a/folly/futures/test/CoreTest.cpp b/folly/futures/test/CoreTest.cpp index 3da83b75..8f0b0de3 100644 --- a/folly/futures/test/CoreTest.cpp +++ b/folly/futures/test/CoreTest.cpp @@ -26,7 +26,7 @@ TEST(Core, size) { typename std::aligned_storage::type lambdaBuf_; folly::Optional> result_; std::function&&)> callback_; - detail::FSM fsm_; + futures::detail::FSM fsm_; std::atomic attached_; std::atomic active_; std::atomic interruptHandlerSet_; @@ -40,5 +40,5 @@ TEST(Core, size) { }; // If this number goes down, it's fine! // If it goes up, please seek professional advice ;-) - EXPECT_GE(sizeof(Gold), sizeof(detail::Core)); + EXPECT_GE(sizeof(Gold), sizeof(futures::detail::Core)); } diff --git a/folly/futures/test/FSMTest.cpp b/folly/futures/test/FSMTest.cpp index 630d5e78..1178603f 100644 --- a/folly/futures/test/FSMTest.cpp +++ b/folly/futures/test/FSMTest.cpp @@ -17,7 +17,7 @@ #include #include -using namespace folly::detail; +using namespace folly::futures::detail; enum class State { A, B }; diff --git a/folly/futures/test/FutureTest.cpp b/folly/futures/test/FutureTest.cpp index 6db394d2..a8f3eb8d 100644 --- a/folly/futures/test/FutureTest.cpp +++ b/folly/futures/test/FutureTest.cpp @@ -648,7 +648,7 @@ TEST(Future, finishBigLambda) { // bulk_data, to be captured in the lambda passed to Future::then. // This is meant to force that the lambda can't be stored inside // the Future object. - std::array)> bulk_data = {{0}}; + std::array)> bulk_data = {{0}}; // suppress gcc warning about bulk_data not being used EXPECT_EQ(bulk_data[0], 0); -- 2.34.1