Use exception_wrapper::from_exception_ptr in Try and Promise
[folly.git] / folly / Try.h
1 /*
2  * Copyright 2017 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 <folly/ExceptionWrapper.h>
20 #include <folly/Likely.h>
21 #include <folly/Memory.h>
22 #include <folly/Portability.h>
23 #include <folly/Unit.h>
24 #include <folly/Utility.h>
25 #include <exception>
26 #include <stdexcept>
27 #include <type_traits>
28 #include <utility>
29
30 namespace folly {
31
32 class TryException : public std::logic_error {
33  public:
34   using std::logic_error::logic_error;
35 };
36
37 class UsingUninitializedTry : public TryException {
38  public:
39   UsingUninitializedTry() : TryException("Using uninitialized try") {}
40 };
41
42 namespace try_detail {
43 [[noreturn]] void throwTryDoesNotContainException();
44 [[noreturn]] void throwUsingUninitializedTry();
45 } // namespace try_detail
46
47 /*
48  * Try<T> is a wrapper that contains either an instance of T, an exception, or
49  * nothing. Exceptions are stored as exception_wrappers so that the user can
50  * minimize rethrows if so desired.
51  *
52  * To represent success or a captured exception, use Try<Unit>.
53  */
54 template <class T>
55 class Try {
56   static_assert(!std::is_reference<T>::value,
57                 "Try may not be used with reference types");
58
59   enum class Contains {
60     VALUE,
61     EXCEPTION,
62     NOTHING,
63   };
64
65  public:
66   /*
67    * The value type for the Try
68    */
69   typedef T element_type;
70
71   /*
72    * Construct an empty Try
73    */
74   Try() : contains_(Contains::NOTHING) {}
75
76   /*
77    * Construct a Try with a value by copy
78    *
79    * @param v The value to copy in
80    */
81   explicit Try(const T& v) : contains_(Contains::VALUE), value_(v) {}
82
83   /*
84    * Construct a Try with a value by move
85    *
86    * @param v The value to move in
87    */
88   explicit Try(T&& v) : contains_(Contains::VALUE), value_(std::move(v)) {}
89
90   template <typename... Args>
91   explicit Try(in_place_t, Args&&... args) noexcept(
92       noexcept(::new (nullptr) T(std::declval<Args&&>()...)))
93       : contains_(Contains::VALUE), value_(std::forward<Args>(args)...) {}
94
95   /// Implicit conversion from Try<void> to Try<Unit>
96   template <class T2 = T>
97   /* implicit */
98   Try(typename std::enable_if<std::is_same<Unit, T2>::value,
99                               Try<void> const&>::type t);
100
101   /*
102    * Construct a Try with an exception_wrapper
103    *
104    * @param e The exception_wrapper
105    */
106   explicit Try(exception_wrapper e)
107       : contains_(Contains::EXCEPTION), e_(std::move(e)) {}
108
109   /*
110    * DEPRECATED
111    * Construct a Try with an exception_pointer
112    *
113    * @param ep The exception_pointer. Will be rethrown.
114    */
115   FOLLY_DEPRECATED("use Try(exception_wrapper)")
116   explicit Try(std::exception_ptr ep)
117       : contains_(Contains::EXCEPTION),
118         e_(exception_wrapper::from_exception_ptr(ep)) {}
119
120   // Move constructor
121   Try(Try<T>&& t) noexcept;
122   // Move assigner
123   Try& operator=(Try<T>&& t) noexcept;
124
125   // Copy constructor
126   Try(const Try& t);
127   // Copy assigner
128   Try& operator=(const Try& t);
129
130   ~Try();
131
132   /*
133    * Get a mutable reference to the contained value. If the Try contains an
134    * exception it will be rethrown.
135    *
136    * @returns mutable reference to the contained value
137    */
138   T& value()&;
139   /*
140    * Get a rvalue reference to the contained value. If the Try contains an
141    * exception it will be rethrown.
142    *
143    * @returns rvalue reference to the contained value
144    */
145   T&& value()&&;
146   /*
147    * Get a const reference to the contained value. If the Try contains an
148    * exception it will be rethrown.
149    *
150    * @returns const reference to the contained value
151    */
152   const T& value() const&;
153
154   /*
155    * If the Try contains an exception, rethrow it. Otherwise do nothing.
156    */
157   void throwIfFailed() const;
158
159   /*
160    * Const dereference operator. If the Try contains an exception it will be
161    * rethrown.
162    *
163    * @returns const reference to the contained value
164    */
165   const T& operator*() const { return value(); }
166   /*
167    * Dereference operator. If the Try contains an exception it will be rethrown.
168    *
169    * @returns mutable reference to the contained value
170    */
171   T& operator*() { return value(); }
172
173   /*
174    * Const arrow operator. If the Try contains an exception it will be
175    * rethrown.
176    *
177    * @returns const reference to the contained value
178    */
179   const T* operator->() const { return &value(); }
180   /*
181    * Arrow operator. If the Try contains an exception it will be rethrown.
182    *
183    * @returns mutable reference to the contained value
184    */
185   T* operator->() { return &value(); }
186
187   /*
188    * @returns True if the Try contains a value, false otherwise
189    */
190   bool hasValue() const { return contains_ == Contains::VALUE; }
191   /*
192    * @returns True if the Try contains an exception, false otherwise
193    */
194   bool hasException() const { return contains_ == Contains::EXCEPTION; }
195
196   /*
197    * @returns True if the Try contains an exception of type Ex, false otherwise
198    */
199   template <class Ex>
200   bool hasException() const {
201     return hasException() && e_.is_compatible_with<Ex>();
202   }
203
204   exception_wrapper& exception() {
205     if (!hasException()) {
206       try_detail::throwTryDoesNotContainException();
207     }
208     return e_;
209   }
210
211   const exception_wrapper& exception() const {
212     if (!hasException()) {
213       try_detail::throwTryDoesNotContainException();
214     }
215     return e_;
216   }
217
218   /*
219    * @returns a pointer to the `std::exception` held by `*this`, if one is held;
220    *          otherwise, returns `nullptr`.
221    */
222   std::exception* tryGetExceptionObject() {
223     return hasException() ? e_.get_exception() : nullptr;
224   }
225   std::exception const* tryGetExceptionObject() const {
226     return hasException() ? e_.get_exception() : nullptr;
227   }
228
229   /*
230    * @returns a pointer to the `Ex` held by `*this`, if it holds an object whose
231    *          type `From` permits `std::is_convertible<From*, Ex*>`; otherwise,
232    *          returns `nullptr`.
233    */
234   template <class E>
235   E* tryGetExceptionObject() {
236     return hasException() ? e_.get_exception<E>() : nullptr;
237   }
238   template <class E>
239   E const* tryGetExceptionObject() const {
240     return hasException() ? e_.get_exception<E>() : nullptr;
241   }
242
243   /*
244    * If the Try contains an exception and it is of type Ex, execute func(Ex)
245    *
246    * @param func a function that takes a single parameter of type const Ex&
247    *
248    * @returns True if the Try held an Ex and func was executed, false otherwise
249    */
250   template <class Ex, class F>
251   bool withException(F func) {
252     if (!hasException()) {
253       return false;
254     }
255     return e_.with_exception<Ex>(std::move(func));
256   }
257   template <class Ex, class F>
258   bool withException(F func) const {
259     if (!hasException()) {
260       return false;
261     }
262     return e_.with_exception<Ex>(std::move(func));
263   }
264
265   /*
266    * If the Try contains an exception and it is of type compatible with Ex as
267    * deduced from the first parameter of func, execute func(Ex)
268    *
269    * @param func a function that takes a single parameter of type const Ex&
270    *
271    * @returns True if the Try held an Ex and func was executed, false otherwise
272    */
273   template <class F>
274   bool withException(F func) {
275     if (!hasException()) {
276       return false;
277     }
278     return e_.with_exception(std::move(func));
279   }
280   template <class F>
281   bool withException(F func) const {
282     if (!hasException()) {
283       return false;
284     }
285     return e_.with_exception(std::move(func));
286   }
287
288   template <bool isTry, typename R>
289   typename std::enable_if<isTry, R>::type get() {
290     return std::forward<R>(*this);
291   }
292
293   template <bool isTry, typename R>
294   typename std::enable_if<!isTry, R>::type get() {
295     return std::forward<R>(value());
296   }
297
298  private:
299   Contains contains_;
300   union {
301     T value_;
302     exception_wrapper e_;
303   };
304 };
305
306 /*
307  * Specialization of Try for void value type. Encapsulates either success or an
308  * exception.
309  */
310 template <>
311 class Try<void> {
312  public:
313   /*
314    * The value type for the Try
315    */
316   typedef void element_type;
317
318   // Construct a Try holding a successful and void result
319   Try() : hasValue_(true) {}
320
321   /*
322    * Construct a Try with an exception_wrapper
323    *
324    * @param e The exception_wrapper
325    */
326   explicit Try(exception_wrapper e) : hasValue_(false), e_(std::move(e)) {}
327
328   /*
329    * DEPRECATED
330    * Construct a Try with an exception_pointer
331    *
332    * @param ep The exception_pointer. Will be rethrown.
333    */
334   FOLLY_DEPRECATED("use Try(exception_wrapper)")
335   explicit Try(std::exception_ptr ep)
336       : hasValue_(false), e_(exception_wrapper::from_exception_ptr(ep)) {}
337
338   // Copy assigner
339   Try& operator=(const Try<void>& t) {
340     hasValue_ = t.hasValue_;
341     e_ = t.e_;
342     return *this;
343   }
344   // Copy constructor
345   Try(const Try<void>& t) {
346     *this = t;
347   }
348
349   // If the Try contains an exception, throws it
350   void value() const { throwIfFailed(); }
351   // Dereference operator. If the Try contains an exception, throws it
352   void operator*() const { return value(); }
353
354   // If the Try contains an exception, throws it
355   inline void throwIfFailed() const;
356
357   // @returns False if the Try contains an exception, true otherwise
358   bool hasValue() const { return hasValue_; }
359   // @returns True if the Try contains an exception, false otherwise
360   bool hasException() const { return !hasValue_; }
361
362   // @returns True if the Try contains an exception of type Ex, false otherwise
363   template <class Ex>
364   bool hasException() const {
365     return hasException() && e_.is_compatible_with<Ex>();
366   }
367
368   /*
369    * @throws TryException if the Try doesn't contain an exception
370    *
371    * @returns mutable reference to the exception contained by this Try
372    */
373   exception_wrapper& exception() {
374     if (!hasException()) {
375       try_detail::throwTryDoesNotContainException();
376     }
377     return e_;
378   }
379
380   const exception_wrapper& exception() const {
381     if (!hasException()) {
382       try_detail::throwTryDoesNotContainException();
383     }
384     return e_;
385   }
386
387   /*
388    * @returns a pointer to the `std::exception` held by `*this`, if one is held;
389    *          otherwise, returns `nullptr`.
390    */
391   std::exception* tryGetExceptionObject() {
392     return hasException() ? e_.get_exception() : nullptr;
393   }
394   std::exception const* tryGetExceptionObject() const {
395     return hasException() ? e_.get_exception() : nullptr;
396   }
397
398   /*
399    * @returns a pointer to the `Ex` held by `*this`, if it holds an object whose
400    *          type `From` permits `std::is_convertible<From*, Ex*>`; otherwise,
401    *          returns `nullptr`.
402    */
403   template <class E>
404   E* tryGetExceptionObject() {
405     return hasException() ? e_.get_exception<E>() : nullptr;
406   }
407   template <class E>
408   E const* tryGetExceptionObject() const {
409     return hasException() ? e_.get_exception<E>() : nullptr;
410   }
411
412   /*
413    * If the Try contains an exception and it is of type Ex, execute func(Ex)
414    *
415    * @param func a function that takes a single parameter of type const Ex&
416    *
417    * @returns True if the Try held an Ex and func was executed, false otherwise
418    */
419   template <class Ex, class F>
420   bool withException(F func) {
421     if (!hasException()) {
422       return false;
423     }
424     return e_.with_exception<Ex>(std::move(func));
425   }
426   template <class Ex, class F>
427   bool withException(F func) const {
428     if (!hasException()) {
429       return false;
430     }
431     return e_.with_exception<Ex>(std::move(func));
432   }
433
434   /*
435    * If the Try contains an exception and it is of type compatible with Ex as
436    * deduced from the first parameter of func, execute func(Ex)
437    *
438    * @param func a function that takes a single parameter of type const Ex&
439    *
440    * @returns True if the Try held an Ex and func was executed, false otherwise
441    */
442   template <class F>
443   bool withException(F func) {
444     if (!hasException()) {
445       return false;
446     }
447     return e_.with_exception(std::move(func));
448   }
449   template <class F>
450   bool withException(F func) const {
451     if (!hasException()) {
452       return false;
453     }
454     return e_.with_exception(std::move(func));
455   }
456
457   template <bool, typename R>
458   R get() {
459     return std::forward<R>(*this);
460   }
461
462  private:
463   bool hasValue_;
464   exception_wrapper e_;
465 };
466
467 /*
468  * @param f a function to execute and capture the result of (value or exception)
469  *
470  * @returns Try holding the result of f
471  */
472 template <typename F>
473 typename std::enable_if<
474   !std::is_same<typename std::result_of<F()>::type, void>::value,
475   Try<typename std::result_of<F()>::type>>::type
476 makeTryWith(F&& f);
477
478 /*
479  * Specialization of makeTryWith for void return
480  *
481  * @param f a function to execute and capture the result of
482  *
483  * @returns Try<void> holding the result of f
484  */
485 template <typename F>
486 typename std::enable_if<
487   std::is_same<typename std::result_of<F()>::type, void>::value,
488   Try<void>>::type
489 makeTryWith(F&& f);
490
491 template <typename... Ts>
492 std::tuple<Ts...> unwrapTryTuple(std::tuple<folly::Try<Ts>...>&& ts);
493
494 } // namespace folly
495
496 #include <folly/Try-inl.h>