1 | /* |
2 | * Copyright 2014-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #pragma once |
18 | |
19 | #include <atomic> |
20 | #include <thread> |
21 | |
22 | #include <folly/executors/InlineExecutor.h> |
23 | #include <folly/futures/detail/Core.h> |
24 | |
25 | namespace folly { |
26 | |
27 | namespace futures { |
28 | namespace detail { |
29 | template <typename T> |
30 | void coreDetachPromiseMaybeWithResult(Core<T>& core) { |
31 | if (!core.hasResult()) { |
32 | core.setResult(Try<T>(exception_wrapper(BrokenPromise(typeid(T).name())))); |
33 | } |
34 | core.detachPromise(); |
35 | } |
36 | } // namespace detail |
37 | } // namespace futures |
38 | |
39 | template <class T> |
40 | Promise<T> Promise<T>::makeEmpty() noexcept { |
41 | return Promise<T>(futures::detail::EmptyConstruct{}); |
42 | } |
43 | |
44 | template <class T> |
45 | Promise<T>::Promise() : retrieved_(false), core_(Core::make()) {} |
46 | |
47 | template <class T> |
48 | Promise<T>::Promise(Promise<T>&& other) noexcept |
49 | : retrieved_(exchange(other.retrieved_, false)), |
50 | core_(exchange(other.core_, nullptr)) {} |
51 | |
52 | template <class T> |
53 | Promise<T>& Promise<T>::operator=(Promise<T>&& other) noexcept { |
54 | detach(); |
55 | retrieved_ = exchange(other.retrieved_, false); |
56 | core_ = exchange(other.core_, nullptr); |
57 | return *this; |
58 | } |
59 | |
60 | template <class T> |
61 | void Promise<T>::throwIfFulfilled() const { |
62 | if (getCore().hasResult()) { |
63 | throw_exception<PromiseAlreadySatisfied>(); |
64 | } |
65 | } |
66 | |
67 | template <class T> |
68 | Promise<T>::Promise(futures::detail::EmptyConstruct) noexcept |
69 | : retrieved_(false), core_(nullptr) {} |
70 | |
71 | template <class T> |
72 | Promise<T>::~Promise() { |
73 | detach(); |
74 | } |
75 | |
76 | template <class T> |
77 | void Promise<T>::detach() { |
78 | if (core_) { |
79 | if (!retrieved_) { |
80 | core_->detachFuture(); |
81 | } |
82 | futures::detail::coreDetachPromiseMaybeWithResult(*core_); |
83 | core_ = nullptr; |
84 | } |
85 | } |
86 | |
87 | template <class T> |
88 | SemiFuture<T> Promise<T>::getSemiFuture() { |
89 | if (retrieved_) { |
90 | throw_exception<FutureAlreadyRetrieved>(); |
91 | } |
92 | retrieved_ = true; |
93 | return SemiFuture<T>(&getCore()); |
94 | } |
95 | |
96 | template <class T> |
97 | Future<T> Promise<T>::getFuture() { |
98 | // An InlineExecutor approximates the old behaviour of continuations |
99 | // running inine on setting the value of the promise. |
100 | return getSemiFuture().via(&InlineExecutor::instance()); |
101 | } |
102 | |
103 | template <class T> |
104 | template <class E> |
105 | typename std::enable_if<std::is_base_of<std::exception, E>::value>::type |
106 | Promise<T>::setException(E const& e) { |
107 | setException(make_exception_wrapper<E>(e)); |
108 | } |
109 | |
110 | template <class T> |
111 | void Promise<T>::setException(exception_wrapper ew) { |
112 | setTry(Try<T>(std::move(ew))); |
113 | } |
114 | |
115 | template <class T> |
116 | template <typename F> |
117 | void Promise<T>::setInterruptHandler(F&& fn) { |
118 | getCore().setInterruptHandler(std::forward<F>(fn)); |
119 | } |
120 | |
121 | template <class T> |
122 | void Promise<T>::setTry(Try<T>&& t) { |
123 | throwIfFulfilled(); |
124 | core_->setResult(std::move(t)); |
125 | } |
126 | |
127 | template <class T> |
128 | template <class M> |
129 | void Promise<T>::setValue(M&& v) { |
130 | static_assert(!std::is_same<T, void>::value, "Use setValue() instead" ); |
131 | |
132 | setTry(Try<T>(std::forward<M>(v))); |
133 | } |
134 | |
135 | template <class T> |
136 | template <class F> |
137 | void Promise<T>::setWith(F&& func) { |
138 | throwIfFulfilled(); |
139 | setTry(makeTryWith(std::forward<F>(func))); |
140 | } |
141 | |
142 | template <class T> |
143 | bool Promise<T>::isFulfilled() const noexcept { |
144 | if (core_) { |
145 | return core_->hasResult(); |
146 | } |
147 | return true; |
148 | } |
149 | |
150 | } // namespace folly |
151 | |