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