2 * Copyright 2014-present 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.
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>
26 #include <type_traits>
31 class FOLLY_EXPORT TryException : public std::logic_error {
33 using std::logic_error::logic_error;
36 class FOLLY_EXPORT UsingUninitializedTry : public TryException {
38 UsingUninitializedTry() : TryException("Using uninitialized try") {}
41 namespace try_detail {
42 [[noreturn]] void throwTryDoesNotContainException();
43 [[noreturn]] void throwUsingUninitializedTry();
44 } // namespace try_detail
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.
51 * To represent success or a captured exception, use Try<Unit>.
55 static_assert(!std::is_reference<T>::value,
56 "Try may not be used with reference types");
66 * The value type for the Try
68 typedef T element_type;
71 * Construct an empty Try
73 Try() : contains_(Contains::NOTHING) {}
76 * Construct a Try with a value by copy
78 * @param v The value to copy in
80 explicit Try(const T& v) : contains_(Contains::VALUE), value_(v) {}
83 * Construct a Try with a value by move
85 * @param v The value to move in
87 explicit Try(T&& v) : contains_(Contains::VALUE), value_(std::move(v)) {}
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)...) {}
94 /// Implicit conversion from Try<void> to Try<Unit>
95 template <class T2 = T>
97 Try(typename std::enable_if<std::is_same<Unit, T2>::value,
98 Try<void> const&>::type t);
101 * Construct a Try with an exception_wrapper
103 * @param e The exception_wrapper
105 explicit Try(exception_wrapper e)
106 : contains_(Contains::EXCEPTION), e_(std::move(e)) {}
110 * Construct a Try with an exception_pointer
112 * @param ep The exception_pointer. Will be rethrown.
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)) {}
120 Try(Try<T>&& t) noexcept;
122 Try& operator=(Try<T>&& t) noexcept;
127 Try& operator=(const Try& t);
132 * Get a mutable reference to the contained value. If the Try contains an
133 * exception it will be rethrown.
135 * @returns mutable reference to the contained value
139 * Get a rvalue reference to the contained value. If the Try contains an
140 * exception it will be rethrown.
142 * @returns rvalue reference to the contained value
146 * Get a const reference to the contained value. If the Try contains an
147 * exception it will be rethrown.
149 * @returns const reference to the contained value
151 const T& value() const &;
153 * Get a const rvalue reference to the contained value. If the Try contains an
154 * exception it will be rethrown.
156 * @returns const rvalue reference to the contained value
158 const T&& value() const &&;
161 * If the Try contains an exception, rethrow it. Otherwise do nothing.
163 void throwIfFailed() const;
166 * Const dereference operator. If the Try contains an exception it will be
169 * @returns const reference to the contained value
171 const T& operator*() const & {
175 * Dereference operator. If the Try contains an exception it will be rethrown.
177 * @returns mutable reference to the contained value
183 * Mutable rvalue dereference operator. If the Try contains an exception it
186 * @returns rvalue reference to the contained value
189 return std::move(value());
192 * Const rvalue dereference operator. If the Try contains an exception it
195 * @returns rvalue reference to the contained value
197 const T&& operator*() const && {
198 return std::move(value());
202 * Const arrow operator. If the Try contains an exception it will be
205 * @returns const reference to the contained value
207 const T* operator->() const { return &value(); }
209 * Arrow operator. If the Try contains an exception it will be rethrown.
211 * @returns mutable reference to the contained value
213 T* operator->() { return &value(); }
216 * @returns True if the Try contains a value, false otherwise
218 bool hasValue() const { return contains_ == Contains::VALUE; }
220 * @returns True if the Try contains an exception, false otherwise
222 bool hasException() const { return contains_ == Contains::EXCEPTION; }
225 * @returns True if the Try contains an exception of type Ex, false otherwise
228 bool hasException() const {
229 return hasException() && e_.is_compatible_with<Ex>();
232 exception_wrapper& exception() & {
233 if (!hasException()) {
234 try_detail::throwTryDoesNotContainException();
239 exception_wrapper&& exception() && {
240 if (!hasException()) {
241 try_detail::throwTryDoesNotContainException();
243 return std::move(e_);
246 const exception_wrapper& exception() const & {
247 if (!hasException()) {
248 try_detail::throwTryDoesNotContainException();
253 const exception_wrapper&& exception() const && {
254 if (!hasException()) {
255 try_detail::throwTryDoesNotContainException();
257 return std::move(e_);
261 * @returns a pointer to the `std::exception` held by `*this`, if one is held;
262 * otherwise, returns `nullptr`.
264 std::exception* tryGetExceptionObject() {
265 return hasException() ? e_.get_exception() : nullptr;
267 std::exception const* tryGetExceptionObject() const {
268 return hasException() ? e_.get_exception() : nullptr;
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,
277 E* tryGetExceptionObject() {
278 return hasException() ? e_.get_exception<E>() : nullptr;
281 E const* tryGetExceptionObject() const {
282 return hasException() ? e_.get_exception<E>() : nullptr;
286 * If the Try contains an exception and it is of type Ex, execute func(Ex)
288 * @param func a function that takes a single parameter of type const Ex&
290 * @returns True if the Try held an Ex and func was executed, false otherwise
292 template <class Ex, class F>
293 bool withException(F func) {
294 if (!hasException()) {
297 return e_.with_exception<Ex>(std::move(func));
299 template <class Ex, class F>
300 bool withException(F func) const {
301 if (!hasException()) {
304 return e_.with_exception<Ex>(std::move(func));
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)
311 * @param func a function that takes a single parameter of type const Ex&
313 * @returns True if the Try held an Ex and func was executed, false otherwise
316 bool withException(F func) {
317 if (!hasException()) {
320 return e_.with_exception(std::move(func));
323 bool withException(F func) const {
324 if (!hasException()) {
327 return e_.with_exception(std::move(func));
330 template <bool isTry, typename R>
331 typename std::enable_if<isTry, R>::type get() {
332 return std::forward<R>(*this);
335 template <bool isTry, typename R>
336 typename std::enable_if<!isTry, R>::type get() {
337 return std::forward<R>(value());
344 exception_wrapper e_;
349 * Specialization of Try for void value type. Encapsulates either success or an
356 * The value type for the Try
358 typedef void element_type;
360 // Construct a Try holding a successful and void result
361 Try() : hasValue_(true) {}
364 * Construct a Try with an exception_wrapper
366 * @param e The exception_wrapper
368 explicit Try(exception_wrapper e) : hasValue_(false), e_(std::move(e)) {}
372 * Construct a Try with an exception_pointer
374 * @param ep The exception_pointer. Will be rethrown.
376 FOLLY_DEPRECATED("use Try(exception_wrapper)")
377 explicit Try(std::exception_ptr ep)
378 : hasValue_(false), e_(exception_wrapper::from_exception_ptr(ep)) {}
381 Try& operator=(const Try<void>& t) {
382 hasValue_ = t.hasValue_;
387 Try(const Try<void>& t) {
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(); }
396 // If the Try contains an exception, throws it
397 inline void throwIfFailed() const;
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_; }
404 // @returns True if the Try contains an exception of type Ex, false otherwise
406 bool hasException() const {
407 return hasException() && e_.is_compatible_with<Ex>();
411 * @throws TryException if the Try doesn't contain an exception
413 * @returns mutable reference to the exception contained by this Try
415 exception_wrapper& exception() & {
416 if (!hasException()) {
417 try_detail::throwTryDoesNotContainException();
422 exception_wrapper&& exception() && {
423 if (!hasException()) {
424 try_detail::throwTryDoesNotContainException();
426 return std::move(e_);
429 const exception_wrapper& exception() const & {
430 if (!hasException()) {
431 try_detail::throwTryDoesNotContainException();
436 const exception_wrapper&& exception() const && {
437 if (!hasException()) {
438 try_detail::throwTryDoesNotContainException();
440 return std::move(e_);
444 * @returns a pointer to the `std::exception` held by `*this`, if one is held;
445 * otherwise, returns `nullptr`.
447 std::exception* tryGetExceptionObject() {
448 return hasException() ? e_.get_exception() : nullptr;
450 std::exception const* tryGetExceptionObject() const {
451 return hasException() ? e_.get_exception() : nullptr;
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,
460 E* tryGetExceptionObject() {
461 return hasException() ? e_.get_exception<E>() : nullptr;
464 E const* tryGetExceptionObject() const {
465 return hasException() ? e_.get_exception<E>() : nullptr;
469 * If the Try contains an exception and it is of type Ex, execute func(Ex)
471 * @param func a function that takes a single parameter of type const Ex&
473 * @returns True if the Try held an Ex and func was executed, false otherwise
475 template <class Ex, class F>
476 bool withException(F func) {
477 if (!hasException()) {
480 return e_.with_exception<Ex>(std::move(func));
482 template <class Ex, class F>
483 bool withException(F func) const {
484 if (!hasException()) {
487 return e_.with_exception<Ex>(std::move(func));
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)
494 * @param func a function that takes a single parameter of type const Ex&
496 * @returns True if the Try held an Ex and func was executed, false otherwise
499 bool withException(F func) {
500 if (!hasException()) {
503 return e_.with_exception(std::move(func));
506 bool withException(F func) const {
507 if (!hasException()) {
510 return e_.with_exception(std::move(func));
513 template <bool, typename R>
515 return std::forward<R>(*this);
520 exception_wrapper e_;
524 * @param f a function to execute and capture the result of (value or exception)
526 * @returns Try holding the result of f
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
535 * Specialization of makeTryWith for void return
537 * @param f a function to execute and capture the result of
539 * @returns Try<void> holding the result of f
541 template <typename F>
542 typename std::enable_if<
543 std::is_same<typename std::result_of<F()>::type, void>::value,
548 * Tuple<Try<Type>...> -> std::tuple<Type...>
550 * Unwraps a tuple-like type containing a sequence of Try<Type> instances to
553 template <typename Tuple>
554 auto unwrapTryTuple(Tuple&&);
558 #include <folly/Try-inl.h>