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