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