Remove busy wait
[folly.git] / folly / futures / Try.h
1 /*
2  * Copyright 2015 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 <type_traits>
20 #include <exception>
21 #include <algorithm>
22 #include <folly/ExceptionWrapper.h>
23 #include <folly/Likely.h>
24 #include <folly/Memory.h>
25 #include <folly/Portability.h>
26 #include <folly/futures/FutureException.h>
27 #include <folly/futures/Unit.h>
28
29 namespace folly {
30
31 /*
32  * Try<T> is a wrapper that contains either an instance of T, an exception, or
33  * nothing. Its primary use case is as a representation of a Promise or Future's
34  * result and so it provides a number of methods that are useful in that
35  * context. Exceptions are stored as exception_wrappers so that the user can
36  * minimize rethrows if so desired.
37  *
38  * To represent success or a captured exception, use Try<Unit>
39  */
40 template <class T>
41 class Try {
42   static_assert(!std::is_reference<T>::value,
43                 "Try may not be used with reference types");
44
45   enum class Contains {
46     VALUE,
47     EXCEPTION,
48     NOTHING,
49   };
50
51  public:
52   /*
53    * The value type for the Try
54    */
55   typedef T element_type;
56
57   /*
58    * Construct an empty Try
59    */
60   Try() : contains_(Contains::NOTHING) {}
61
62   /*
63    * Construct a Try with a value by copy
64    *
65    * @param v The value to copy in
66    */
67   explicit Try(const T& v) : contains_(Contains::VALUE), value_(v) {}
68
69   /*
70    * Construct a Try with a value by move
71    *
72    * @param v The value to move in
73    */
74   explicit Try(T&& v) : contains_(Contains::VALUE), value_(std::move(v)) {}
75
76   /// Implicit conversion from Try<void> to Try<Unit>
77   template <class T2 = T>
78   /* implicit */
79   Try(typename std::enable_if<std::is_same<Unit, T2>::value,
80                               Try<void> const&>::type t);
81
82   /*
83    * Construct a Try with an exception_wrapper
84    *
85    * @param e The exception_wrapper
86    */
87   explicit Try(exception_wrapper e)
88     : contains_(Contains::EXCEPTION),
89       e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
90
91   /*
92    * DEPRECATED
93    * Construct a Try with an exception_pointer
94    *
95    * @param ep The exception_pointer. Will be rethrown.
96    */
97   FOLLY_DEPRECATED("use Try(exception_wrapper)")
98   explicit Try(std::exception_ptr ep)
99     : contains_(Contains::EXCEPTION) {
100     try {
101       std::rethrow_exception(ep);
102     } catch (const std::exception& e) {
103       e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
104     } catch (...) {
105       e_ = folly::make_unique<exception_wrapper>(std::current_exception());
106     }
107   }
108
109   // Move constructor
110   Try(Try<T>&& t) noexcept;
111   // Move assigner
112   Try& operator=(Try<T>&& t) noexcept;
113
114   // Copy constructor
115   Try(const Try& t);
116   // Copy assigner
117   Try& operator=(const Try& t);
118
119   ~Try();
120
121   /*
122    * Get a mutable reference to the contained value. If the Try contains an
123    * exception it will be rethrown.
124    *
125    * @returns mutable reference to the contained value
126    */
127   T& value();
128   /*
129    * Get a const reference to the contained value. If the Try contains an
130    * exception it will be rethrown.
131    *
132    * @returns const reference to the contained value
133    */
134   const T& value() const;
135
136   /*
137    * If the Try contains an exception, rethrow it. Otherwise do nothing.
138    */
139   void throwIfFailed() const;
140
141   /*
142    * Const dereference operator. If the Try contains an exception it will be
143    * rethrown.
144    *
145    * @returns const reference to the contained value
146    */
147   const T& operator*() const { return value(); }
148   /*
149    * Dereference operator. If the Try contains an exception it will be rethrown.
150    *
151    * @returns mutable reference to the contained value
152    */
153   T& operator*() { return value(); }
154
155   /*
156    * Const arrow operator. If the Try contains an exception it will be
157    * rethrown.
158    *
159    * @returns const reference to the contained value
160    */
161   const T* operator->() const { return &value(); }
162   /*
163    * Arrow operator. If the Try contains an exception it will be rethrown.
164    *
165    * @returns mutable reference to the contained value
166    */
167   T* operator->() { return &value(); }
168
169   /*
170    * @returns True if the Try contains a value, false otherwise
171    */
172   bool hasValue() const { return contains_ == Contains::VALUE; }
173   /*
174    * @returns True if the Try contains an exception, false otherwise
175    */
176   bool hasException() const { return contains_ == Contains::EXCEPTION; }
177
178   /*
179    * @returns True if the Try contains an exception of type Ex, false otherwise
180    */
181   template <class Ex>
182   bool hasException() const {
183     return hasException() && e_->is_compatible_with<Ex>();
184   }
185
186   exception_wrapper& exception() {
187     if (UNLIKELY(!hasException())) {
188       throw FutureException("exception(): Try does not contain an exception");
189     }
190     return *e_;
191   }
192
193   const exception_wrapper& exception() const {
194     if (UNLIKELY(!hasException())) {
195       throw FutureException("exception(): Try does not contain an exception");
196     }
197     return *e_;
198   }
199
200   /*
201    * If the Try contains an exception and it is of type Ex, execute func(Ex)
202    *
203    * @param func a function that takes a single parameter of type const Ex&
204    *
205    * @returns True if the Try held an Ex and func was executed, false otherwise
206    */
207   template <class Ex, class F>
208   bool withException(F func) const {
209     if (!hasException()) {
210       return false;
211     }
212     return e_->with_exception<Ex>(std::move(func));
213   }
214
215   template <bool isTry, typename R>
216   typename std::enable_if<isTry, R>::type get() {
217     return std::forward<R>(*this);
218   }
219
220   template <bool isTry, typename R>
221   typename std::enable_if<!isTry, R>::type get() {
222     return std::forward<R>(value());
223   }
224
225  private:
226   Contains contains_;
227   union {
228     T value_;
229     std::unique_ptr<exception_wrapper> e_;
230   };
231 };
232
233 /*
234  * Specialization of Try for void value type. Encapsulates either success or an
235  * exception.
236  */
237 template <>
238 class Try<void> {
239  public:
240   // Construct a Try holding a successful and void result
241   Try() : hasValue_(true) {}
242
243   /*
244    * Construct a Try with an exception_wrapper
245    *
246    * @param e The exception_wrapper
247    */
248   explicit Try(exception_wrapper e)
249     : hasValue_(false),
250       e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
251
252   /*
253    * DEPRECATED
254    * Construct a Try with an exception_pointer
255    *
256    * @param ep The exception_pointer. Will be rethrown.
257    */
258   FOLLY_DEPRECATED("use Try(exception_wrapper)")
259   explicit Try(std::exception_ptr ep) : hasValue_(false) {
260     try {
261       std::rethrow_exception(ep);
262     } catch (const std::exception& e) {
263       e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
264     } catch (...) {
265       e_ = folly::make_unique<exception_wrapper>(std::current_exception());
266     }
267   }
268
269   // Copy assigner
270   Try& operator=(const Try<void>& t) {
271     hasValue_ = t.hasValue_;
272     if (t.e_) {
273       e_ = folly::make_unique<exception_wrapper>(*t.e_);
274     }
275     return *this;
276   }
277   // Copy constructor
278   Try(const Try<void>& t) {
279     *this = t;
280   }
281
282   // If the Try contains an exception, throws it
283   void value() const { throwIfFailed(); }
284   // Dereference operator. If the Try contains an exception, throws it
285   void operator*() const { return value(); }
286
287   // If the Try contains an exception, throws it
288   inline void throwIfFailed() const;
289
290   // @returns False if the Try contains an exception, true otherwise
291   bool hasValue() const { return hasValue_; }
292   // @returns True if the Try contains an exception, false otherwise
293   bool hasException() const { return !hasValue_; }
294
295   // @returns True if the Try contains an exception of type Ex, false otherwise
296   template <class Ex>
297   bool hasException() const {
298     return hasException() && e_->is_compatible_with<Ex>();
299   }
300
301   /*
302    * @throws FutureException if the Try doesn't contain an exception
303    *
304    * @returns mutable reference to the exception contained by this Try
305    */
306   exception_wrapper& exception() {
307     if (UNLIKELY(!hasException())) {
308       throw FutureException("exception(): Try does not contain an exception");
309     }
310     return *e_;
311   }
312
313   const exception_wrapper& exception() const {
314     if (UNLIKELY(!hasException())) {
315       throw FutureException("exception(): Try does not contain an exception");
316     }
317     return *e_;
318   }
319
320   /*
321    * If the Try contains an exception and it is of type Ex, execute func(Ex)
322    *
323    * @param func a function that takes a single parameter of type const Ex&
324    *
325    * @returns True if the Try held an Ex and func was executed, false otherwise
326    */
327   template <class Ex, class F>
328   bool withException(F func) const {
329     if (!hasException()) {
330       return false;
331     }
332     return e_->with_exception<Ex>(std::move(func));
333   }
334
335   template <bool, typename R>
336   R get() {
337     return std::forward<R>(*this);
338   }
339
340  private:
341   bool hasValue_;
342   std::unique_ptr<exception_wrapper> e_{nullptr};
343 };
344
345 /*
346  * Extracts value from try and returns it. Throws if try contained an exception.
347  *
348  * @param t Try to extract value from
349  *
350  * @returns value contained in t
351  */
352 template <typename T>
353 T moveFromTry(Try<T>& t);
354
355 /*
356  * Throws if try contained an exception.
357  *
358  * @param t Try to move from
359  */
360 void moveFromTry(Try<void>& t);
361
362 /*
363  * @param f a function to execute and capture the result of (value or exception)
364  *
365  * @returns Try holding the result of f
366  */
367 template <typename F>
368 typename std::enable_if<
369   !std::is_same<typename std::result_of<F()>::type, void>::value,
370   Try<typename std::result_of<F()>::type>>::type
371 makeTryWith(F&& f);
372
373 /*
374  * Specialization of makeTryWith for void return
375  *
376  * @param f a function to execute and capture the result of
377  *
378  * @returns Try<void> holding the result of f
379  */
380 template <typename F>
381 typename std::enable_if<
382   std::is_same<typename std::result_of<F()>::type, void>::value,
383   Try<void>>::type
384 makeTryWith(F&& f);
385
386 } // folly
387
388 #include <folly/futures/Try-inl.h>