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>
24 #include <folly/Utility.h>
27 #include <type_traits>
32 class TryException : public std::logic_error {
34 using std::logic_error::logic_error;
37 class UsingUninitializedTry : public TryException {
39 UsingUninitializedTry() : TryException("Using uninitialized try") {}
42 namespace try_detail {
43 [[noreturn]] void throwTryDoesNotContainException();
44 [[noreturn]] void throwUsingUninitializedTry();
45 } // namespace try_detail
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.
52 * To represent success or a captured exception, use Try<Unit>.
56 static_assert(!std::is_reference<T>::value,
57 "Try may not be used with reference types");
67 * The value type for the Try
69 typedef T element_type;
72 * Construct an empty Try
74 Try() : contains_(Contains::NOTHING) {}
77 * Construct a Try with a value by copy
79 * @param v The value to copy in
81 explicit Try(const T& v) : contains_(Contains::VALUE), value_(v) {}
84 * Construct a Try with a value by move
86 * @param v The value to move in
88 explicit Try(T&& v) : contains_(Contains::VALUE), value_(std::move(v)) {}
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)...) {}
95 /// Implicit conversion from Try<void> to Try<Unit>
96 template <class T2 = T>
98 Try(typename std::enable_if<std::is_same<Unit, T2>::value,
99 Try<void> const&>::type t);
102 * Construct a Try with an exception_wrapper
104 * @param e The exception_wrapper
106 explicit Try(exception_wrapper e)
107 : contains_(Contains::EXCEPTION), e_(std::move(e)) {}
111 * Construct a Try with an exception_pointer
113 * @param ep The exception_pointer. Will be rethrown.
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)) {}
121 Try(Try<T>&& t) noexcept;
123 Try& operator=(Try<T>&& t) noexcept;
128 Try& operator=(const Try& t);
133 * Get a mutable reference to the contained value. If the Try contains an
134 * exception it will be rethrown.
136 * @returns mutable reference to the contained value
140 * Get a rvalue reference to the contained value. If the Try contains an
141 * exception it will be rethrown.
143 * @returns rvalue reference to the contained value
147 * Get a const reference to the contained value. If the Try contains an
148 * exception it will be rethrown.
150 * @returns const reference to the contained value
152 const T& value() const &;
154 * Get a const rvalue reference to the contained value. If the Try contains an
155 * exception it will be rethrown.
157 * @returns const rvalue reference to the contained value
159 const T&& value() const &&;
162 * If the Try contains an exception, rethrow it. Otherwise do nothing.
164 void throwIfFailed() const;
167 * Const dereference operator. If the Try contains an exception it will be
170 * @returns const reference to the contained value
172 const T& operator*() const & {
176 * Dereference operator. If the Try contains an exception it will be rethrown.
178 * @returns mutable reference to the contained value
184 * Mutable rvalue dereference operator. If the Try contains an exception it
187 * @returns rvalue reference to the contained value
190 return std::move(value());
193 * Const rvalue dereference operator. If the Try contains an exception it
196 * @returns rvalue reference to the contained value
198 const T&& operator*() const && {
199 return std::move(value());
203 * Const arrow operator. If the Try contains an exception it will be
206 * @returns const reference to the contained value
208 const T* operator->() const { return &value(); }
210 * Arrow operator. If the Try contains an exception it will be rethrown.
212 * @returns mutable reference to the contained value
214 T* operator->() { return &value(); }
217 * @returns True if the Try contains a value, false otherwise
219 bool hasValue() const { return contains_ == Contains::VALUE; }
221 * @returns True if the Try contains an exception, false otherwise
223 bool hasException() const { return contains_ == Contains::EXCEPTION; }
226 * @returns True if the Try contains an exception of type Ex, false otherwise
229 bool hasException() const {
230 return hasException() && e_.is_compatible_with<Ex>();
233 exception_wrapper& exception() & {
234 if (!hasException()) {
235 try_detail::throwTryDoesNotContainException();
240 exception_wrapper&& exception() && {
241 if (!hasException()) {
242 try_detail::throwTryDoesNotContainException();
244 return std::move(e_);
247 const exception_wrapper& exception() const & {
248 if (!hasException()) {
249 try_detail::throwTryDoesNotContainException();
254 const exception_wrapper&& exception() const && {
255 if (!hasException()) {
256 try_detail::throwTryDoesNotContainException();
258 return std::move(e_);
262 * @returns a pointer to the `std::exception` held by `*this`, if one is held;
263 * otherwise, returns `nullptr`.
265 std::exception* tryGetExceptionObject() {
266 return hasException() ? e_.get_exception() : nullptr;
268 std::exception const* tryGetExceptionObject() const {
269 return hasException() ? e_.get_exception() : nullptr;
273 * @returns a pointer to the `Ex` held by `*this`, if it holds an object whose
274 * type `From` permits `std::is_convertible<From*, Ex*>`; otherwise,
278 E* tryGetExceptionObject() {
279 return hasException() ? e_.get_exception<E>() : nullptr;
282 E const* tryGetExceptionObject() const {
283 return hasException() ? e_.get_exception<E>() : nullptr;
287 * If the Try contains an exception and it is of type Ex, execute func(Ex)
289 * @param func a function that takes a single parameter of type const Ex&
291 * @returns True if the Try held an Ex and func was executed, false otherwise
293 template <class Ex, class F>
294 bool withException(F func) {
295 if (!hasException()) {
298 return e_.with_exception<Ex>(std::move(func));
300 template <class Ex, class F>
301 bool withException(F func) const {
302 if (!hasException()) {
305 return e_.with_exception<Ex>(std::move(func));
309 * If the Try contains an exception and it is of type compatible with Ex as
310 * deduced from the first parameter of func, execute func(Ex)
312 * @param func a function that takes a single parameter of type const Ex&
314 * @returns True if the Try held an Ex and func was executed, false otherwise
317 bool withException(F func) {
318 if (!hasException()) {
321 return e_.with_exception(std::move(func));
324 bool withException(F func) const {
325 if (!hasException()) {
328 return e_.with_exception(std::move(func));
331 template <bool isTry, typename R>
332 typename std::enable_if<isTry, R>::type get() {
333 return std::forward<R>(*this);
336 template <bool isTry, typename R>
337 typename std::enable_if<!isTry, R>::type get() {
338 return std::forward<R>(value());
345 exception_wrapper e_;
350 * Specialization of Try for void value type. Encapsulates either success or an
357 * The value type for the Try
359 typedef void element_type;
361 // Construct a Try holding a successful and void result
362 Try() : hasValue_(true) {}
365 * Construct a Try with an exception_wrapper
367 * @param e The exception_wrapper
369 explicit Try(exception_wrapper e) : hasValue_(false), e_(std::move(e)) {}
373 * Construct a Try with an exception_pointer
375 * @param ep The exception_pointer. Will be rethrown.
377 FOLLY_DEPRECATED("use Try(exception_wrapper)")
378 explicit Try(std::exception_ptr ep)
379 : hasValue_(false), e_(exception_wrapper::from_exception_ptr(ep)) {}
382 Try& operator=(const Try<void>& t) {
383 hasValue_ = t.hasValue_;
388 Try(const Try<void>& t) {
392 // If the Try contains an exception, throws it
393 void value() const { throwIfFailed(); }
394 // Dereference operator. If the Try contains an exception, throws it
395 void operator*() const { return value(); }
397 // If the Try contains an exception, throws it
398 inline void throwIfFailed() const;
400 // @returns False if the Try contains an exception, true otherwise
401 bool hasValue() const { return hasValue_; }
402 // @returns True if the Try contains an exception, false otherwise
403 bool hasException() const { return !hasValue_; }
405 // @returns True if the Try contains an exception of type Ex, false otherwise
407 bool hasException() const {
408 return hasException() && e_.is_compatible_with<Ex>();
412 * @throws TryException if the Try doesn't contain an exception
414 * @returns mutable reference to the exception contained by this Try
416 exception_wrapper& exception() & {
417 if (!hasException()) {
418 try_detail::throwTryDoesNotContainException();
423 exception_wrapper&& exception() && {
424 if (!hasException()) {
425 try_detail::throwTryDoesNotContainException();
427 return std::move(e_);
430 const exception_wrapper& exception() const & {
431 if (!hasException()) {
432 try_detail::throwTryDoesNotContainException();
437 const exception_wrapper&& exception() const && {
438 if (!hasException()) {
439 try_detail::throwTryDoesNotContainException();
441 return std::move(e_);
445 * @returns a pointer to the `std::exception` held by `*this`, if one is held;
446 * otherwise, returns `nullptr`.
448 std::exception* tryGetExceptionObject() {
449 return hasException() ? e_.get_exception() : nullptr;
451 std::exception const* tryGetExceptionObject() const {
452 return hasException() ? e_.get_exception() : nullptr;
456 * @returns a pointer to the `Ex` held by `*this`, if it holds an object whose
457 * type `From` permits `std::is_convertible<From*, Ex*>`; otherwise,
461 E* tryGetExceptionObject() {
462 return hasException() ? e_.get_exception<E>() : nullptr;
465 E const* tryGetExceptionObject() const {
466 return hasException() ? e_.get_exception<E>() : nullptr;
470 * If the Try contains an exception and it is of type Ex, execute func(Ex)
472 * @param func a function that takes a single parameter of type const Ex&
474 * @returns True if the Try held an Ex and func was executed, false otherwise
476 template <class Ex, class F>
477 bool withException(F func) {
478 if (!hasException()) {
481 return e_.with_exception<Ex>(std::move(func));
483 template <class Ex, class F>
484 bool withException(F func) const {
485 if (!hasException()) {
488 return e_.with_exception<Ex>(std::move(func));
492 * If the Try contains an exception and it is of type compatible with Ex as
493 * deduced from the first parameter of func, execute func(Ex)
495 * @param func a function that takes a single parameter of type const Ex&
497 * @returns True if the Try held an Ex and func was executed, false otherwise
500 bool withException(F func) {
501 if (!hasException()) {
504 return e_.with_exception(std::move(func));
507 bool withException(F func) const {
508 if (!hasException()) {
511 return e_.with_exception(std::move(func));
514 template <bool, typename R>
516 return std::forward<R>(*this);
521 exception_wrapper e_;
525 * @param f a function to execute and capture the result of (value or exception)
527 * @returns Try holding the result of f
529 template <typename F>
530 typename std::enable_if<
531 !std::is_same<typename std::result_of<F()>::type, void>::value,
532 Try<typename std::result_of<F()>::type>>::type
536 * Specialization of makeTryWith for void return
538 * @param f a function to execute and capture the result of
540 * @returns Try<void> holding the result of f
542 template <typename F>
543 typename std::enable_if<
544 std::is_same<typename std::result_of<F()>::type, void>::value,
549 * Tuple<Try<Type>...> -> std::tuple<Type...>
551 * Unwraps a tuple-like type containing a sequence of Try<Type> instances to
554 template <typename Tuple>
555 auto unwrapTryTuple(Tuple&&);
559 #include <folly/Try-inl.h>