| /* |
| * Copyright 2015 Facebook, Inc. |
| * |
| * 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 <atomic> |
| #include <thread> |
| |
| #include <folly/futures/FutureException.h> |
| #include <folly/futures/detail/Core.h> |
| |
| namespace folly { |
| |
| template <class T> |
| Promise<T>::Promise() : retrieved_(false), core_(new detail::Core<T>()) |
| {} |
| |
| template <class T> |
| Promise<T>::Promise(Promise<T>&& other) noexcept |
| : retrieved_(other.retrieved_), core_(other.core_) { |
| other.core_ = nullptr; |
| other.retrieved_ = false; |
| } |
| |
| template <class T> |
| Promise<T>& Promise<T>::operator=(Promise<T>&& other) noexcept { |
| std::swap(core_, other.core_); |
| std::swap(retrieved_, other.retrieved_); |
| return *this; |
| } |
| |
| template <class T> |
| void Promise<T>::throwIfFulfilled() { |
| if (UNLIKELY(!core_)) { |
| throw NoState(); |
| } |
| if (UNLIKELY(core_->ready())) { |
| throw PromiseAlreadySatisfied(); |
| } |
| } |
| |
| template <class T> |
| void Promise<T>::throwIfRetrieved() { |
| if (UNLIKELY(retrieved_)) { |
| throw FutureAlreadyRetrieved(); |
| } |
| } |
| |
| template <class T> |
| Promise<T>::~Promise() { |
| detach(); |
| } |
| |
| template <class T> |
| void Promise<T>::detach() { |
| if (core_) { |
| if (!retrieved_) |
| core_->detachFuture(); |
| core_->detachPromise(); |
| core_ = nullptr; |
| } |
| } |
| |
| template <class T> |
| Future<T> Promise<T>::getFuture() { |
| throwIfRetrieved(); |
| retrieved_ = true; |
| return Future<T>(core_); |
| } |
| |
| template <class T> |
| template <class E> |
| typename std::enable_if<std::is_base_of<std::exception, E>::value>::type |
| Promise<T>::setException(E const& e) { |
| setException(make_exception_wrapper<E>(e)); |
| } |
| |
| template <class T> |
| void Promise<T>::setException(std::exception_ptr const& ep) { |
| try { |
| std::rethrow_exception(ep); |
| } catch (const std::exception& e) { |
| setException(exception_wrapper(std::current_exception(), e)); |
| } catch (...) { |
| setException(exception_wrapper(std::current_exception())); |
| } |
| } |
| |
| template <class T> |
| void Promise<T>::setException(exception_wrapper ew) { |
| throwIfFulfilled(); |
| core_->setResult(Try<T>(std::move(ew))); |
| } |
| |
| template <class T> |
| void Promise<T>::setInterruptHandler( |
| std::function<void(exception_wrapper const&)> fn) { |
| core_->setInterruptHandler(std::move(fn)); |
| } |
| |
| template <class T> |
| void Promise<T>::setTry(Try<T>&& t) { |
| throwIfFulfilled(); |
| core_->setResult(std::move(t)); |
| } |
| |
| template <class T> |
| template <class M> |
| void Promise<T>::setValue(M&& v) { |
| static_assert(!std::is_same<T, void>::value, |
| "Use setValue() instead"); |
| |
| setTry(Try<T>(std::forward<M>(v))); |
| } |
| |
| template <class T> |
| template <class F> |
| void Promise<T>::setWith(F&& func) { |
| throwIfFulfilled(); |
| setTry(makeTryWith(std::forward<F>(func))); |
| } |
| |
| template <class T> |
| bool Promise<T>::isFulfilled() { |
| if (core_) { |
| return core_->hasResult(); |
| } |
| return true; |
| } |
| |
| } |