2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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>
26 #include <type_traits>
31 class TryException : public std::logic_error {
33 using std::logic_error::logic_error;
36 class UsingUninitializedTry : public TryException {
38 UsingUninitializedTry() : TryException("Using uninitialized try") {}
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.
46 * To represent success or a captured exception, use Try<Unit>.
50 static_assert(!std::is_reference<T>::value,
51 "Try may not be used with reference types");
61 * The value type for the Try
63 typedef T element_type;
66 * Construct an empty Try
68 Try() : contains_(Contains::NOTHING) {}
71 * Construct a Try with a value by copy
73 * @param v The value to copy in
75 explicit Try(const T& v) : contains_(Contains::VALUE), value_(v) {}
78 * Construct a Try with a value by move
80 * @param v The value to move in
82 explicit Try(T&& v) : contains_(Contains::VALUE), value_(std::move(v)) {}
84 /// Implicit conversion from Try<void> to Try<Unit>
85 template <class T2 = T>
87 Try(typename std::enable_if<std::is_same<Unit, T2>::value,
88 Try<void> const&>::type t);
91 * Construct a Try with an exception_wrapper
93 * @param e The exception_wrapper
95 explicit Try(exception_wrapper e)
96 : contains_(Contains::EXCEPTION), e_(std::move(e)) {}
100 * Construct a Try with an exception_pointer
102 * @param ep The exception_pointer. Will be rethrown.
104 FOLLY_DEPRECATED("use Try(exception_wrapper)")
105 explicit Try(std::exception_ptr ep)
106 : contains_(Contains::EXCEPTION) {
108 std::rethrow_exception(ep);
109 } catch (std::exception& e) {
110 e_ = exception_wrapper(std::current_exception(), e);
112 e_ = exception_wrapper(std::current_exception());
117 Try(Try<T>&& t) noexcept;
119 Try& operator=(Try<T>&& t) noexcept;
124 Try& operator=(const Try& t);
129 * Get a mutable reference to the contained value. If the Try contains an
130 * exception it will be rethrown.
132 * @returns mutable reference to the contained value
136 * Get a rvalue reference to the contained value. If the Try contains an
137 * exception it will be rethrown.
139 * @returns rvalue reference to the contained value
143 * Get a const reference to the contained value. If the Try contains an
144 * exception it will be rethrown.
146 * @returns const reference to the contained value
148 const T& value() const&;
151 * If the Try contains an exception, rethrow it. Otherwise do nothing.
153 void throwIfFailed() const;
156 * Const dereference operator. If the Try contains an exception it will be
159 * @returns const reference to the contained value
161 const T& operator*() const { return value(); }
163 * Dereference operator. If the Try contains an exception it will be rethrown.
165 * @returns mutable reference to the contained value
167 T& operator*() { return value(); }
170 * Const arrow operator. If the Try contains an exception it will be
173 * @returns const reference to the contained value
175 const T* operator->() const { return &value(); }
177 * Arrow operator. If the Try contains an exception it will be rethrown.
179 * @returns mutable reference to the contained value
181 T* operator->() { return &value(); }
184 * @returns True if the Try contains a value, false otherwise
186 bool hasValue() const { return contains_ == Contains::VALUE; }
188 * @returns True if the Try contains an exception, false otherwise
190 bool hasException() const { return contains_ == Contains::EXCEPTION; }
193 * @returns True if the Try contains an exception of type Ex, false otherwise
196 bool hasException() const {
197 return hasException() && e_.is_compatible_with<Ex>();
200 exception_wrapper& exception() {
201 if (UNLIKELY(!hasException())) {
202 throw TryException("exception(): Try does not contain an exception");
207 const exception_wrapper& exception() const {
208 if (UNLIKELY(!hasException())) {
209 throw TryException("exception(): Try does not contain an exception");
215 * @returns a pointer to the `std::exception` held by `*this`, if one is held;
216 * otherwise, returns `nullptr`.
218 std::exception* tryGetExceptionObject() {
219 return hasException() ? e_.get_exception() : nullptr;
221 std::exception const* tryGetExceptionObject() const {
222 return hasException() ? e_.get_exception() : nullptr;
226 * @returns a pointer to the `Ex` held by `*this`, if it holds an object whose
227 * type `From` permits `std::is_convertible<From*, Ex*>`; otherwise,
231 E* tryGetExceptionObject() {
232 return hasException() ? e_.get_exception<E>() : nullptr;
235 E const* tryGetExceptionObject() const {
236 return hasException() ? e_.get_exception<E>() : nullptr;
240 * If the Try contains an exception and it is of type Ex, execute func(Ex)
242 * @param func a function that takes a single parameter of type const Ex&
244 * @returns True if the Try held an Ex and func was executed, false otherwise
246 template <class Ex, class F>
247 bool withException(F func) {
248 if (!hasException()) {
251 return e_.with_exception<Ex>(std::move(func));
253 template <class Ex, class F>
254 bool withException(F func) const {
255 if (!hasException()) {
258 return e_.with_exception<Ex>(std::move(func));
262 * If the Try contains an exception and it is of type compatible with Ex as
263 * deduced from the first parameter of func, execute func(Ex)
265 * @param func a function that takes a single parameter of type const Ex&
267 * @returns True if the Try held an Ex and func was executed, false otherwise
270 bool withException(F func) {
271 if (!hasException()) {
274 return e_.with_exception(std::move(func));
277 bool withException(F func) const {
278 if (!hasException()) {
281 return e_.with_exception(std::move(func));
284 template <bool isTry, typename R>
285 typename std::enable_if<isTry, R>::type get() {
286 return std::forward<R>(*this);
289 template <bool isTry, typename R>
290 typename std::enable_if<!isTry, R>::type get() {
291 return std::forward<R>(value());
298 exception_wrapper e_;
303 * Specialization of Try for void value type. Encapsulates either success or an
310 * The value type for the Try
312 typedef void element_type;
314 // Construct a Try holding a successful and void result
315 Try() : hasValue_(true) {}
318 * Construct a Try with an exception_wrapper
320 * @param e The exception_wrapper
322 explicit Try(exception_wrapper e) : hasValue_(false), e_(std::move(e)) {}
326 * Construct a Try with an exception_pointer
328 * @param ep The exception_pointer. Will be rethrown.
330 FOLLY_DEPRECATED("use Try(exception_wrapper)")
331 explicit Try(std::exception_ptr ep) : hasValue_(false) {
333 std::rethrow_exception(ep);
334 } catch (const std::exception& e) {
335 e_ = exception_wrapper(std::current_exception(), e);
337 e_ = exception_wrapper(std::current_exception());
342 Try& operator=(const Try<void>& t) {
343 hasValue_ = t.hasValue_;
348 Try(const Try<void>& t) {
352 // If the Try contains an exception, throws it
353 void value() const { throwIfFailed(); }
354 // Dereference operator. If the Try contains an exception, throws it
355 void operator*() const { return value(); }
357 // If the Try contains an exception, throws it
358 inline void throwIfFailed() const;
360 // @returns False if the Try contains an exception, true otherwise
361 bool hasValue() const { return hasValue_; }
362 // @returns True if the Try contains an exception, false otherwise
363 bool hasException() const { return !hasValue_; }
365 // @returns True if the Try contains an exception of type Ex, false otherwise
367 bool hasException() const {
368 return hasException() && e_.is_compatible_with<Ex>();
372 * @throws TryException if the Try doesn't contain an exception
374 * @returns mutable reference to the exception contained by this Try
376 exception_wrapper& exception() {
377 if (UNLIKELY(!hasException())) {
378 throw TryException("exception(): Try does not contain an exception");
383 const exception_wrapper& exception() const {
384 if (UNLIKELY(!hasException())) {
385 throw TryException("exception(): Try does not contain an exception");
391 * @returns a pointer to the `std::exception` held by `*this`, if one is held;
392 * otherwise, returns `nullptr`.
394 std::exception* tryGetExceptionObject() {
395 return hasException() ? e_.get_exception() : nullptr;
397 std::exception const* tryGetExceptionObject() const {
398 return hasException() ? e_.get_exception() : nullptr;
402 * @returns a pointer to the `Ex` held by `*this`, if it holds an object whose
403 * type `From` permits `std::is_convertible<From*, Ex*>`; otherwise,
407 E* tryGetExceptionObject() {
408 return hasException() ? e_.get_exception<E>() : nullptr;
411 E const* tryGetExceptionObject() const {
412 return hasException() ? e_.get_exception<E>() : nullptr;
416 * If the Try contains an exception and it is of type Ex, execute func(Ex)
418 * @param func a function that takes a single parameter of type const Ex&
420 * @returns True if the Try held an Ex and func was executed, false otherwise
422 template <class Ex, class F>
423 bool withException(F func) {
424 if (!hasException()) {
427 return e_.with_exception<Ex>(std::move(func));
429 template <class Ex, class F>
430 bool withException(F func) const {
431 if (!hasException()) {
434 return e_.with_exception<Ex>(std::move(func));
438 * If the Try contains an exception and it is of type compatible with Ex as
439 * deduced from the first parameter of func, execute func(Ex)
441 * @param func a function that takes a single parameter of type const Ex&
443 * @returns True if the Try held an Ex and func was executed, false otherwise
446 bool withException(F func) {
447 if (!hasException()) {
450 return e_.with_exception(std::move(func));
453 bool withException(F func) const {
454 if (!hasException()) {
457 return e_.with_exception(std::move(func));
460 template <bool, typename R>
462 return std::forward<R>(*this);
467 exception_wrapper e_;
471 * Extracts value from try and returns it. Throws if try contained an exception.
473 * @param t Try to extract value from
475 * @returns value contained in t
477 template <typename T>
478 T moveFromTry(Try<T>& t);
481 * Throws if try contained an exception.
483 * @param t Try to move from
485 void moveFromTry(Try<void>& t);
488 * @param f a function to execute and capture the result of (value or exception)
490 * @returns Try holding the result of f
492 template <typename F>
493 typename std::enable_if<
494 !std::is_same<typename std::result_of<F()>::type, void>::value,
495 Try<typename std::result_of<F()>::type>>::type
499 * Specialization of makeTryWith for void return
501 * @param f a function to execute and capture the result of
503 * @returns Try<void> holding the result of f
505 template <typename F>
506 typename std::enable_if<
507 std::is_same<typename std::result_of<F()>::type, void>::value,
511 template <typename... Ts>
512 std::tuple<Ts...> unwrapTryTuple(std::tuple<folly::Try<Ts>...>&& ts);
516 #include <folly/Try-inl.h>