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),
97 e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
101 * Construct a Try with an exception_pointer
103 * @param ep The exception_pointer. Will be rethrown.
105 FOLLY_DEPRECATED("use Try(exception_wrapper)")
106 explicit Try(std::exception_ptr ep)
107 : contains_(Contains::EXCEPTION) {
109 std::rethrow_exception(ep);
110 } catch (const std::exception& e) {
111 e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
113 e_ = folly::make_unique<exception_wrapper>(std::current_exception());
118 Try(Try<T>&& t) noexcept;
120 Try& operator=(Try<T>&& t) noexcept;
125 Try& operator=(const Try& t);
130 * Get a mutable reference to the contained value. If the Try contains an
131 * exception it will be rethrown.
133 * @returns mutable reference to the contained value
137 * Get a rvalue reference to the contained value. If the Try contains an
138 * exception it will be rethrown.
140 * @returns rvalue reference to the contained value
144 * Get a const reference to the contained value. If the Try contains an
145 * exception it will be rethrown.
147 * @returns const reference to the contained value
149 const T& value() const&;
152 * If the Try contains an exception, rethrow it. Otherwise do nothing.
154 void throwIfFailed() const;
157 * Const dereference operator. If the Try contains an exception it will be
160 * @returns const reference to the contained value
162 const T& operator*() const { return value(); }
164 * Dereference operator. If the Try contains an exception it will be rethrown.
166 * @returns mutable reference to the contained value
168 T& operator*() { return value(); }
171 * Const arrow operator. If the Try contains an exception it will be
174 * @returns const reference to the contained value
176 const T* operator->() const { return &value(); }
178 * Arrow operator. If the Try contains an exception it will be rethrown.
180 * @returns mutable reference to the contained value
182 T* operator->() { return &value(); }
185 * @returns True if the Try contains a value, false otherwise
187 bool hasValue() const { return contains_ == Contains::VALUE; }
189 * @returns True if the Try contains an exception, false otherwise
191 bool hasException() const { return contains_ == Contains::EXCEPTION; }
194 * @returns True if the Try contains an exception of type Ex, false otherwise
197 bool hasException() const {
198 return hasException() && e_->is_compatible_with<Ex>();
201 exception_wrapper& exception() {
202 if (UNLIKELY(!hasException())) {
203 throw TryException("exception(): Try does not contain an exception");
208 const exception_wrapper& exception() const {
209 if (UNLIKELY(!hasException())) {
210 throw TryException("exception(): Try does not contain an exception");
216 * If the Try contains an exception and it is of type Ex, execute func(Ex)
218 * @param func a function that takes a single parameter of type const Ex&
220 * @returns True if the Try held an Ex and func was executed, false otherwise
222 template <class Ex, class F>
223 bool withException(F func) const {
224 if (!hasException()) {
227 return e_->with_exception(std::move(func));
230 template <bool isTry, typename R>
231 typename std::enable_if<isTry, R>::type get() {
232 return std::forward<R>(*this);
235 template <bool isTry, typename R>
236 typename std::enable_if<!isTry, R>::type get() {
237 return std::forward<R>(value());
244 std::unique_ptr<exception_wrapper> e_;
249 * Specialization of Try for void value type. Encapsulates either success or an
256 * The value type for the Try
258 typedef void element_type;
260 // Construct a Try holding a successful and void result
261 Try() : hasValue_(true) {}
264 * Construct a Try with an exception_wrapper
266 * @param e The exception_wrapper
268 explicit Try(exception_wrapper e)
270 e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
274 * Construct a Try with an exception_pointer
276 * @param ep The exception_pointer. Will be rethrown.
278 FOLLY_DEPRECATED("use Try(exception_wrapper)")
279 explicit Try(std::exception_ptr ep) : hasValue_(false) {
281 std::rethrow_exception(ep);
282 } catch (const std::exception& e) {
283 e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
285 e_ = folly::make_unique<exception_wrapper>(std::current_exception());
290 Try& operator=(const Try<void>& t) {
291 hasValue_ = t.hasValue_;
293 e_ = folly::make_unique<exception_wrapper>(*t.e_);
298 Try(const Try<void>& t) {
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(); }
307 // If the Try contains an exception, throws it
308 inline void throwIfFailed() const;
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_; }
315 // @returns True if the Try contains an exception of type Ex, false otherwise
317 bool hasException() const {
318 return hasException() && e_->is_compatible_with<Ex>();
322 * @throws TryException if the Try doesn't contain an exception
324 * @returns mutable reference to the exception contained by this Try
326 exception_wrapper& exception() {
327 if (UNLIKELY(!hasException())) {
328 throw TryException("exception(): Try does not contain an exception");
333 const exception_wrapper& exception() const {
334 if (UNLIKELY(!hasException())) {
335 throw TryException("exception(): Try does not contain an exception");
341 * If the Try contains an exception and it is of type Ex, execute func(Ex)
343 * @param func a function that takes a single parameter of type const Ex&
345 * @returns True if the Try held an Ex and func was executed, false otherwise
347 template <class Ex, class F>
348 bool withException(F func) const {
349 if (!hasException()) {
352 return e_->with_exception(std::move(func));
355 template <bool, typename R>
357 return std::forward<R>(*this);
362 std::unique_ptr<exception_wrapper> e_{nullptr};
366 * Extracts value from try and returns it. Throws if try contained an exception.
368 * @param t Try to extract value from
370 * @returns value contained in t
372 template <typename T>
373 T moveFromTry(Try<T>& t);
376 * Throws if try contained an exception.
378 * @param t Try to move from
380 void moveFromTry(Try<void>& t);
383 * @param f a function to execute and capture the result of (value or exception)
385 * @returns Try holding the result of f
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
394 * Specialization of makeTryWith for void return
396 * @param f a function to execute and capture the result of
398 * @returns Try<void> holding the result of f
400 template <typename F>
401 typename std::enable_if<
402 std::is_same<typename std::result_of<F()>::type, void>::value,
406 template <typename... Ts>
407 std::tuple<Ts...> unwrapTryTuple(std::tuple<folly::Try<Ts>...>&& ts);
411 #include <folly/Try-inl.h>