X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2Ffutures%2FFuture.h;h=5b2dc82f7b44b6c8f9a4a910f1f17fdb0c6c1204;hp=56f244833ecef2f31468a52620f6e1e491083be3;hb=ff18deaf720fbe59551a7ff275b09003a61c4351;hpb=5a81b5dfcaeb70e6271d07d2008b39604b7507da diff --git a/folly/futures/Future.h b/folly/futures/Future.h index 56f24483..5b2dc82f 100644 --- a/folly/futures/Future.h +++ b/folly/futures/Future.h @@ -1,5 +1,5 @@ /* - * Copyright 2017 Facebook, Inc. + * Copyright 2017-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #pragma once #include @@ -25,9 +24,10 @@ #include #include +#include #include #include -#include +#include #include #include #include @@ -42,19 +42,359 @@ namespace folly { template -class Future { +class Future; + +template +class SemiFuture; + +namespace futures { +namespace detail { +template +class FutureBase { public: typedef T value_type; - static Future makeEmpty(); // equivalent to moved-from + /// Construct a Future from a value (perfect forwarding) + template < + class T2 = T, + typename = typename std::enable_if< + !isFuture::type>::value && + !isSemiFuture::type>::value>::type> + /* implicit */ FutureBase(T2&& val); + + template + /* implicit */ FutureBase( + typename std::enable_if::value>::type*); + + template < + class... Args, + typename std::enable_if::value, int>:: + type = 0> + explicit FutureBase(in_place_t, Args&&... args); + + FutureBase(FutureBase const&) = delete; + FutureBase(SemiFuture&&) noexcept; + FutureBase(Future&&) noexcept; // not copyable - Future(Future const&) = delete; - Future& operator=(Future const&) = delete; + FutureBase(Future const&) = delete; + FutureBase(SemiFuture const&) = delete; + + ~FutureBase(); + + /// Returns a reference to the result, with a reference category and const- + /// qualification equivalent to the reference category and const-qualification + /// of the receiver. + /// + /// If moved-from, throws NoState. + /// + /// If !isReady(), throws FutureNotReady. + /// + /// If an exception has been captured, throws that exception. + T& value() &; + T const& value() const&; + T&& value() &&; + T const&& value() const&&; + + /// Returns a reference to the try of the result. Throws as for value if + /// future is not valid. + Try& result() &; + Try const& result() const&; + Try&& result() &&; + Try const&& result() const&&; + + /** True when the result (or exception) is ready. */ + bool isReady() const; + + /// sugar for getTry().hasValue() + bool hasValue(); + + /// sugar for getTry().hasException() + bool hasException(); + + /// If the promise has been fulfilled, return an Optional with the Try. + /// Otherwise return an empty Optional. + /// Note that this moves the Try out. + Optional> poll(); + + /// This is not the method you're looking for. + /// + /// This needs to be public because it's used by make* and when*, and it's + /// not worth listing all those and their fancy template signatures as + /// friends. But it's not for public consumption. + template + void setCallback_(F&& func); + + bool isActive() { + return core_->isActive(); + } + + template + void raise(E&& exception) { + raise(make_exception_wrapper::type>( + std::forward(exception))); + } + /// Raise an interrupt. If the promise holder has an interrupt + /// handler it will be called and potentially stop asynchronous work from + /// being done. This is advisory only - a promise holder may not set an + /// interrupt handler, or may do anything including ignore. But, if you know + /// your future supports this the most likely result is stopping or + /// preventing the asynchronous operation (if in time), and the promise + /// holder setting an exception on the future. (That may happen + /// asynchronously, of course.) + void raise(exception_wrapper interrupt); + + void cancel() { + raise(FutureCancellation()); + } + + protected: + friend class Promise; + template + friend class SemiFuture; + template + friend class Future; + + using corePtr = futures::detail::Core*; + + // shared core state object + corePtr core_; + + explicit FutureBase(corePtr obj) : core_(obj) {} + + explicit FutureBase(futures::detail::EmptyConstruct) noexcept; + + void detach(); + + void throwIfInvalid() const; + + template + void assign(FutureType&) noexcept; + + Executor* getExecutor() { + return core_->getExecutor(); + } + + void setExecutor(Executor* x, int8_t priority = Executor::MID_PRI) { + core_->setExecutor(x, priority); + } + + // Variant: returns a value + // e.g. f.then([](Try t){ return t.value(); }); + template + typename std::enable_if::type + 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, futures::detail::argResult); +}; +} // namespace detail +} // namespace futures + +template +class SemiFuture : private futures::detail::FutureBase { + private: + using Base = futures::detail::FutureBase; + using DeferredExecutor = futures::detail::DeferredExecutor; + + public: + static SemiFuture makeEmpty(); // equivalent to moved-from + + // Export public interface of FutureBase + // FutureBase is inherited privately to avoid subclasses being cast to + // a FutureBase pointer + using typename Base::value_type; + + /// Construct a Future from a value (perfect forwarding) + template < + class T2 = T, + typename = typename std::enable_if< + !isFuture::type>::value && + !isSemiFuture::type>::value>::type> + /* implicit */ SemiFuture(T2&& val) : Base(std::forward(val)) {} + + template + /* implicit */ SemiFuture( + typename std::enable_if::value>::type* p = nullptr) + : Base(p) {} + + template < + class... Args, + typename std::enable_if::value, int>:: + type = 0> + explicit SemiFuture(in_place_t, Args&&... args) + : Base(in_place, std::forward(args)...) {} + + SemiFuture(SemiFuture const&) = delete; // movable - Future(Future&&) noexcept; - Future& operator=(Future&&) noexcept; + SemiFuture(SemiFuture&&) noexcept; + // safe move-constructabilty from Future + /* implicit */ SemiFuture(Future&&) noexcept; + + using Base::cancel; + using Base::hasException; + using Base::hasValue; + using Base::isActive; + using Base::isReady; + using Base::poll; + using Base::raise; + using Base::setCallback_; + using Base::value; + using Base::result; + + SemiFuture& operator=(SemiFuture const&) = delete; + SemiFuture& operator=(SemiFuture&&) noexcept; + SemiFuture& operator=(Future&&) noexcept; + + /// Block until the future is fulfilled. Returns the value (moved out), or + /// throws the exception. The future must not already have a callback. + T get() &&; + + /// Block until the future is fulfilled, or until timed out. Returns the + /// value (moved out), or throws the exception (which might be a TimedOut + /// exception). + T get(Duration dur) &&; + + /// Block until the future is fulfilled, or until timed out. Returns the + /// Try of the value (moved out). + Try getTry() &&; + + /// Block until the future is fulfilled, or until timed out. Returns the + /// Try of the value (moved out) or may throw a TimedOut exception. + Try getTry(Duration dur) &&; + + /// Call e->drive() repeatedly until the future is fulfilled. Examples + /// of DrivableExecutor include EventBase and ManualExecutor. Returns the + /// value (moved out), or throws the exception. + T getVia(DrivableExecutor* e) &&; + + /// Call e->drive() repeatedly until the future is fulfilled. Examples + /// of DrivableExecutor include EventBase and ManualExecutor. Returns the + /// Try of the value (moved out). + Try getTryVia(DrivableExecutor* e) &&; + + /// Block until this Future is complete. Returns a reference to this Future. + SemiFuture& wait() &; + + /// Overload of wait() for rvalue Futures + SemiFuture&& wait() &&; + + /// Block until this Future is complete or until the given Duration passes. + /// Returns a reference to this Future + SemiFuture& wait(Duration) &; + + /// Overload of wait(Duration) for rvalue Futures + SemiFuture&& wait(Duration) &&; + + /// Call e->drive() repeatedly until the future is fulfilled. Examples + /// of DrivableExecutor include EventBase and ManualExecutor. Returns a + /// reference to this SemiFuture so that you can chain calls if desired. + /// value (moved out), or throws the exception. + SemiFuture& waitVia(DrivableExecutor* e) &; + + /// Overload of waitVia() for rvalue Futures + SemiFuture&& waitVia(DrivableExecutor* e) &&; + + /// Returns an inactive Future which will call back on the other side of + /// executor (when it is activated). + /// + /// NB remember that Futures activate when they destruct. This is good, + /// it means that this will work: + /// + /// f.via(e).then(a).then(b); + /// + /// a and b will execute in the same context (the far side of e), because + /// the Future (temporary variable) created by via(e) does not call back + /// until it destructs, which is after then(a) and then(b) have been wired + /// up. + /// + /// But this is still racy: + /// + /// f = f.via(e).then(a); + /// f.then(b); + // The ref-qualifier allows for `this` to be moved out so we + // don't get access-after-free situations in chaining. + // https://akrzemi1.wordpress.com/2014/06/02/ref-qualifiers/ + inline Future via( + Executor* executor, + int8_t priority = Executor::MID_PRI) &&; + + /** + * Defer work to run on the consumer of the future. + * This work will be run eithe ron an executor that the caller sets on the + * SemiFuture, or inline with the call to .get(). + * NB: This is a custom method because boost-blocking executors is a + * special-case for work deferral in folly. With more general boost-blocking + * support all executors would boost block and we would simply use some form + * of driveable executor here. + */ + template + SemiFuture::Return::value_type> + defer(F&& func) &&; + + // Public as for setCallback_ + // Ensure that a boostable executor performs work to chain deferred work + // cleanly + void boost_(); + + private: + friend class Promise; + template + friend class futures::detail::FutureBase; + template + friend class SemiFuture; + + using typename Base::corePtr; + using Base::setExecutor; + using Base::throwIfInvalid; + + template + friend SemiFuture makeSemiFuture(Try&&); + + explicit SemiFuture(corePtr obj) : Base(obj) {} + + explicit SemiFuture(futures::detail::EmptyConstruct) noexcept + : Base(futures::detail::EmptyConstruct{}) {} +}; + +template +class Future : private futures::detail::FutureBase { + private: + using Base = futures::detail::FutureBase; + + public: + // Export public interface of FutureBase + // FutureBase is inherited privately to avoid subclasses being cast to + // a FutureBase pointer + using typename Base::value_type; + + /// Construct a Future from a value (perfect forwarding) + template < + class T2 = T, + typename = typename std::enable_if< + !isFuture::type>::value && + !isSemiFuture::type>::value>::type> + /* implicit */ Future(T2&& val) : Base(std::forward(val)) {} + + template + /* implicit */ Future( + typename std::enable_if::value>::type* p = nullptr) + : Base(p) {} + + template < + class... Args, + typename std::enable_if::value, int>:: + type = 0> + explicit Future(in_place_t, Args&&... args) + : Base(in_place, std::forward(args)...) {} + + Future(Future const&) = delete; + // movable + Future(Future&&) noexcept; // converting move template < @@ -81,32 +421,41 @@ class Future { int>::type = 0> Future& operator=(Future&&); - /// Construct a Future from a value (perfect forwarding) - template ::type>::value>::type> - /* implicit */ Future(T2&& val); + using Base::cancel; + using Base::hasException; + using Base::hasValue; + using Base::isActive; + using Base::isReady; + using Base::poll; + using Base::raise; + using Base::setCallback_; + using Base::value; + using Base::result; - template - /* implicit */ Future( - typename std::enable_if::value>::type* = nullptr); + static Future makeEmpty(); // equivalent to moved-from - template < - class... Args, - typename std::enable_if::value, int>:: - type = 0> - explicit Future(in_place_t, Args&&... args); + // not copyable + Future& operator=(Future const&) = delete; - ~Future(); + // movable + Future& operator=(Future&&) noexcept; - /** Return the reference to result. Should not be called if !isReady(). - Will rethrow the exception if an exception has been - captured. - */ - typename std::add_lvalue_reference::type - value(); - typename std::add_lvalue_reference::type - value() const; + /// Call e->drive() repeatedly until the future is fulfilled. Examples + /// of DrivableExecutor include EventBase and ManualExecutor. Returns the + /// value (moved out), or throws the exception. + T getVia(DrivableExecutor* e); + + /// Call e->drive() repeatedly until the future is fulfilled. Examples + /// of DrivableExecutor include EventBase and ManualExecutor. Returns a + /// reference to the Try of the value. + Try& getTryVia(DrivableExecutor* e); + + /// Unwraps the case of a Future> instance, and returns a simple + /// Future instance. + template + typename std:: + enable_if::value, Future::Inner>>::type + unwrap(); /// Returns an inactive Future which will call back on the other side of /// executor (when it is activated). @@ -139,49 +488,6 @@ class Future { Executor* executor, int8_t priority = Executor::MID_PRI) &; - /** True when the result (or exception) is ready. */ - bool isReady() const; - - /// sugar for getTry().hasValue() - bool hasValue(); - - /// sugar for getTry().hasException() - bool hasException(); - - /** A reference to the Try of the value */ - Try& getTry(); - - /// Call e->drive() repeatedly until the future is fulfilled. Examples - /// of DrivableExecutor include EventBase and ManualExecutor. Returns a - /// reference to the Try of the value. - Try& getTryVia(DrivableExecutor* e); - - /// If the promise has been fulfilled, return an Optional with the Try. - /// Otherwise return an empty Optional. - /// Note that this moves the Try out. - Optional> poll(); - - /// Block until the future is fulfilled. Returns the value (moved out), or - /// throws the exception. The future must not already have a callback. - T get(); - - /// Block until the future is fulfilled, or until timed out. Returns the - /// value (moved out), or throws the exception (which might be a TimedOut - /// exception). - T get(Duration dur); - - /// Call e->drive() repeatedly until the future is fulfilled. Examples - /// of DrivableExecutor include EventBase and ManualExecutor. Returns the - /// value (moved out), or throws the exception. - T getVia(DrivableExecutor* e); - - /// Unwraps the case of a Future> instance, and returns a simple - /// Future instance. - template - typename std::enable_if::value, - Future::Inner>>::type - unwrap(); - /** When this Future has completed, execute func which is a function that takes one of: (const) Try&& @@ -202,20 +508,10 @@ 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. */ - // 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 futures::detail::FunctionReferenceToPointer::type, - typename R = futures::detail::callableResult> + template > typename R::Return then(F&& func) { - typedef typename R::Arg Arguments; - return thenImplementation(std::forward(func), Arguments()); + return this->template thenImplementation( + std::forward(func), typename R::Arg()); } /// Variant where func is an member function @@ -229,8 +525,9 @@ class Future { /// /// f1.then(std::bind(&Worker::doWork, w)); template - Future::Inner> - then(R(Caller::*func)(Args...), Caller *instance); + Future::Inner> then( + R (Caller::*func)(Args...), + Caller* instance); /// Execute the callback via the given Executor. The executor doesn't stick. /// @@ -246,16 +543,24 @@ class Future { /// via x, and c executes via the same executor (if any) that f had. template auto then(Executor* x, Arg&& arg, Args&&... args) { - auto oldX = getExecutor(); - setExecutor(x); + auto oldX = this->getExecutor(); + this->setExecutor(x); return this->then(std::forward(arg), std::forward(args)...) .via(oldX); } /// Convenience method for ignoring the value and creating a Future. /// Exceptions still propagate. + /// This function is identical to .unit(). Future then(); + /// Convenience method for ignoring the value and creating a Future. + /// Exceptions still propagate. + /// This function is identical to parameterless .then(). + Future unit() { + return then(); + } + /// Set an error callback for this Future. The callback should take a single /// argument of the type that you want to catch, and should return a value of /// the same type as this Future, or a Future of that type (see overload @@ -273,6 +578,7 @@ class Future { template typename std::enable_if< !futures::detail::callableWith::value && + !futures::detail::callableWith::value && !futures::detail::Extract::ReturnsFuture::value, Future>::type onError(F&& func); @@ -281,6 +587,7 @@ class Future { template typename std::enable_if< !futures::detail::callableWith::value && + !futures::detail::callableWith::value && futures::detail::Extract::ReturnsFuture::value, Future>::type onError(F&& func); @@ -324,60 +631,28 @@ class Future { template Future onTimeout(Duration, F&& func, Timekeeper* = nullptr); - /// This is not the method you're looking for. - /// - /// This needs to be public because it's used by make* and when*, and it's - /// not worth listing all those and their fancy template signatures as - /// friends. But it's not for public consumption. - template - void setCallback_(F&& func); - /// A Future's callback is executed when all three of these conditions have /// become true: it has a value (set by the Promise), it has a callback (set /// by then), and it is active (active by default). /// /// Inactive Futures will activate upon destruction. FOLLY_DEPRECATED("do not use") Future& activate() & { - core_->activate(); + this->core_->activate(); return *this; } FOLLY_DEPRECATED("do not use") Future& deactivate() & { - core_->deactivate(); + this->core_->deactivate(); return *this; } FOLLY_DEPRECATED("do not use") Future activate() && { - core_->activate(); + this->core_->activate(); return std::move(*this); } FOLLY_DEPRECATED("do not use") Future deactivate() && { - core_->deactivate(); + this->core_->deactivate(); return std::move(*this); } - bool isActive() { - return core_->isActive(); - } - - template - void raise(E&& exception) { - raise(make_exception_wrapper::type>( - std::forward(exception))); - } - - /// Raise an interrupt. If the promise holder has an interrupt - /// handler it will be called and potentially stop asynchronous work from - /// being done. This is advisory only - a promise holder may not set an - /// interrupt handler, or may do anything including ignore. But, if you know - /// your future supports this the most likely result is stopping or - /// preventing the asynchronous operation (if in time), and the promise - /// holder setting an exception on the future. (That may happen - /// asynchronously, of course.) - void raise(exception_wrapper interrupt); - - void cancel() { - raise(FutureCancellation()); - } - /// Throw TimedOut if this Future does not complete within the given /// duration from now. The optional Timeekeeper is as with futures::sleep(). Future within(Duration, Timekeeper* = nullptr); @@ -392,6 +667,18 @@ class Future { /// now. The optional Timekeeper is as with futures::sleep(). Future delayed(Duration, Timekeeper* = nullptr); + /// Block until the future is fulfilled. Returns the value (moved out), or + /// throws the exception. The future must not already have a callback. + T get(); + + /// Block until the future is fulfilled, or until timed out. Returns the + /// value (moved out), or throws the exception (which might be a TimedOut + /// exception). + T get(Duration dur); + + /** A reference to the Try of the value */ + Try& getTry(); + /// Block until this Future is complete. Returns a reference to this Future. Future& wait() &; @@ -464,8 +751,8 @@ class Future { auto thenMultiWithExecutor(Executor* x, Callback&& fn, Callbacks&&... fns) { // thenMultiExecutor with two callbacks is // via(x).then(a).thenMulti(b, ...).via(oldX) - auto oldX = getExecutor(); - setExecutor(x); + auto oldX = this->getExecutor(); + this->setExecutor(x); return then(std::forward(fn)) .thenMulti(std::forward(fns)...) .via(oldX); @@ -477,28 +764,29 @@ class Future { return then(x, std::forward(fn)); } - /// Discard a result, but propagate an exception. - Future unit() { - return then([]{ return Unit{}; }); + // Convert this Future to a SemiFuture to safely export from a library + // without exposing a continuation interface + SemiFuture semi() { + return SemiFuture{std::move(*this)}; } protected: - typedef futures::detail::Core* corePtr; - - // shared core state object - corePtr core_; - - explicit - Future(corePtr obj) : core_(obj) {} - - explicit Future(futures::detail::EmptyConstruct) noexcept; + friend class Promise; + template + friend class futures::detail::FutureBase; + template + friend class Future; + template + friend class SemiFuture; - void detach(); + using Base::setExecutor; + using Base::throwIfInvalid; + using typename Base::corePtr; - void throwIfInvalid() const; + explicit Future(corePtr obj) : Base(obj) {} - friend class Promise; - template friend class Future; + explicit Future(futures::detail::EmptyConstruct) noexcept + : Base(futures::detail::EmptyConstruct{}) {} template friend Future makeFuture(Try&&); @@ -525,25 +813,8 @@ class Future { /// predicate behaves like std::function template 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, 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, futures::detail::argResult); - - Executor* getExecutor() { return core_->getExecutor(); } - void setExecutor(Executor* x, int8_t priority = Executor::MID_PRI) { - core_->setExecutor(x, priority); - } }; -} // folly +} // namespace folly #include