/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include namespace folly { /* * SharedPromise provides the same interface as Promise, but you can extract * multiple Futures from it, i.e. you can call getFuture() as many times as * you'd like. When the SharedPromise is fulfilled, all of the Futures are * completed. Calls to getFuture() after the SharedPromise is fulfilled return * a completed Future. If you find yourself constructing collections of Promises * and fulfilling them simultaneously with the same value, consider this * utility instead. Likewise, if you find yourself in need of setting multiple * callbacks on the same Future (which is indefinitely unsupported), consider * refactoring to use SharedPromise to "split" the Future. * * The SharedPromise must be kept alive manually. Consider FutureSplitter for * automatic lifetime management. */ template class SharedPromise { public: /** * Return a Future tied to the shared core state. Unlike Promise::getFuture, * this can be called an unlimited number of times per SharedPromise. */ SemiFuture getSemiFuture() const; /** * Return a Future tied to the shared core state. Unlike Promise::getFuture, * this can be called an unlimited number of times per SharedPromise. * NOTE: This function is deprecated. Please use getSemiFuture and pass the * appropriate executor to .via on the returned SemiFuture to get a * valid Future where necessary. */ Future getFuture() const; /** Return the number of Futures associated with this SharedPromise */ size_t size() const; /** Fulfill the SharedPromise with an exception_wrapper */ void setException(exception_wrapper ew); /** Fulfill the SharedPromise with an exception type E, which can be passed to make_exception_wrapper(). Useful for originating exceptions. If you caught an exception the exception_wrapper form is more appropriate. */ template typename std::enable_if::value>::type setException(E const&); /// Set an interrupt handler to handle interrupts. See the documentation for /// Future::raise(). Your handler can do whatever it wants, but if you /// bother to set one then you probably will want to fulfill the SharedPromise /// with an exception (or special value) indicating how the interrupt was /// handled. void setInterruptHandler(std::function); /// Sugar to fulfill this SharedPromise template typename std::enable_if::value, void>::type setValue() { setTry(Try(T())); } /** Set the value (use perfect forwarding for both move and copy) */ template void setValue(M&& value); void setTry(Try&& t); /** Fulfill this SharedPromise with the result of a function that takes no arguments and returns something implicitly convertible to T. Captures exceptions. e.g. p.setWith([] { do something that may throw; return a T; }); */ template void setWith(F&& func); bool isFulfilled() const; private: // this allows SharedPromise move-ctor/move-assign to be defaulted struct Mutex : std::mutex { Mutex() = default; Mutex(Mutex&&) noexcept {} Mutex& operator=(Mutex&&) noexcept { return *this; } }; template struct Defaulted { using Noexcept = StrictConjunction< std::is_nothrow_default_constructible, std::is_nothrow_move_constructible, std::is_nothrow_move_assignable>; V value{V()}; Defaulted() = default; Defaulted(Defaulted&& that) noexcept(Noexcept::value) : value(std::exchange(that.value, V())) {} Defaulted& operator=(Defaulted&& that) noexcept(Noexcept::value) { value = std::exchange(that.value, V()); return *this; } }; bool hasResult() const { return try_.value.hasValue() || try_.value.hasException(); } mutable Mutex mutex_; mutable Defaulted size_; Defaulted> try_; mutable std::vector> promises_; std::function interruptHandler_; }; } // namespace folly #include #include