2 * Copyright 2016 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 <type_traits>
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>
30 class TryException : public std::exception {
32 explicit TryException(std::string message_arg) noexcept
33 : message(std::move(message_arg)) {}
35 const char* what() const noexcept override {
36 return message.c_str();
39 bool operator==(const TryException& other) const noexcept {
40 return other.message == this->message;
43 bool operator!=(const TryException& other) const noexcept {
44 return !(*this == other);
51 class UsingUninitializedTry : public TryException {
53 UsingUninitializedTry() noexcept : TryException("Using unitialized try") {}
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.
61 * To represent success or a captured exception, use Try<Unit>.
65 static_assert(!std::is_reference<T>::value,
66 "Try may not be used with reference types");
76 * The value type for the Try
78 typedef T element_type;
81 * Construct an empty Try
83 Try() : contains_(Contains::NOTHING) {}
86 * Construct a Try with a value by copy
88 * @param v The value to copy in
90 explicit Try(const T& v) : contains_(Contains::VALUE), value_(v) {}
93 * Construct a Try with a value by move
95 * @param v The value to move in
97 explicit Try(T&& v) : contains_(Contains::VALUE), value_(std::move(v)) {}
99 /// Implicit conversion from Try<void> to Try<Unit>
100 template <class T2 = T>
102 Try(typename std::enable_if<std::is_same<Unit, T2>::value,
103 Try<void> const&>::type t);
106 * Construct a Try with an exception_wrapper
108 * @param e The exception_wrapper
110 explicit Try(exception_wrapper e)
111 : contains_(Contains::EXCEPTION),
112 e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
116 * Construct a Try with an exception_pointer
118 * @param ep The exception_pointer. Will be rethrown.
120 FOLLY_DEPRECATED("use Try(exception_wrapper)")
121 explicit Try(std::exception_ptr ep)
122 : contains_(Contains::EXCEPTION) {
124 std::rethrow_exception(ep);
125 } catch (const std::exception& e) {
126 e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
128 e_ = folly::make_unique<exception_wrapper>(std::current_exception());
133 Try(Try<T>&& t) noexcept;
135 Try& operator=(Try<T>&& t) noexcept;
140 Try& operator=(const Try& t);
145 * Get a mutable reference to the contained value. If the Try contains an
146 * exception it will be rethrown.
148 * @returns mutable reference to the contained value
152 * Get a rvalue reference to the contained value. If the Try contains an
153 * exception it will be rethrown.
155 * @returns rvalue reference to the contained value
159 * Get a const reference to the contained value. If the Try contains an
160 * exception it will be rethrown.
162 * @returns const reference to the contained value
164 const T& value() const&;
167 * If the Try contains an exception, rethrow it. Otherwise do nothing.
169 void throwIfFailed() const;
172 * Const dereference operator. If the Try contains an exception it will be
175 * @returns const reference to the contained value
177 const T& operator*() const { return value(); }
179 * Dereference operator. If the Try contains an exception it will be rethrown.
181 * @returns mutable reference to the contained value
183 T& operator*() { return value(); }
186 * Const arrow operator. If the Try contains an exception it will be
189 * @returns const reference to the contained value
191 const T* operator->() const { return &value(); }
193 * Arrow operator. If the Try contains an exception it will be rethrown.
195 * @returns mutable reference to the contained value
197 T* operator->() { return &value(); }
200 * @returns True if the Try contains a value, false otherwise
202 bool hasValue() const { return contains_ == Contains::VALUE; }
204 * @returns True if the Try contains an exception, false otherwise
206 bool hasException() const { return contains_ == Contains::EXCEPTION; }
209 * @returns True if the Try contains an exception of type Ex, false otherwise
212 bool hasException() const {
213 return hasException() && e_->is_compatible_with<Ex>();
216 exception_wrapper& exception() {
217 if (UNLIKELY(!hasException())) {
218 throw TryException("exception(): Try does not contain an exception");
223 const exception_wrapper& exception() const {
224 if (UNLIKELY(!hasException())) {
225 throw TryException("exception(): Try does not contain an exception");
231 * If the Try contains an exception and it is of type Ex, execute func(Ex)
233 * @param func a function that takes a single parameter of type const Ex&
235 * @returns True if the Try held an Ex and func was executed, false otherwise
237 template <class Ex, class F>
238 bool withException(F func) const {
239 if (!hasException()) {
242 return e_->with_exception(std::move(func));
245 template <bool isTry, typename R>
246 typename std::enable_if<isTry, R>::type get() {
247 return std::forward<R>(*this);
250 template <bool isTry, typename R>
251 typename std::enable_if<!isTry, R>::type get() {
252 return std::forward<R>(value());
259 std::unique_ptr<exception_wrapper> e_;
264 * Specialization of Try for void value type. Encapsulates either success or an
271 * The value type for the Try
273 typedef void element_type;
275 // Construct a Try holding a successful and void result
276 Try() : hasValue_(true) {}
279 * Construct a Try with an exception_wrapper
281 * @param e The exception_wrapper
283 explicit Try(exception_wrapper e)
285 e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
289 * Construct a Try with an exception_pointer
291 * @param ep The exception_pointer. Will be rethrown.
293 FOLLY_DEPRECATED("use Try(exception_wrapper)")
294 explicit Try(std::exception_ptr ep) : hasValue_(false) {
296 std::rethrow_exception(ep);
297 } catch (const std::exception& e) {
298 e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
300 e_ = folly::make_unique<exception_wrapper>(std::current_exception());
305 Try& operator=(const Try<void>& t) {
306 hasValue_ = t.hasValue_;
308 e_ = folly::make_unique<exception_wrapper>(*t.e_);
313 Try(const Try<void>& t) {
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(); }
322 // If the Try contains an exception, throws it
323 inline void throwIfFailed() const;
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_; }
330 // @returns True if the Try contains an exception of type Ex, false otherwise
332 bool hasException() const {
333 return hasException() && e_->is_compatible_with<Ex>();
337 * @throws TryException if the Try doesn't contain an exception
339 * @returns mutable reference to the exception contained by this Try
341 exception_wrapper& exception() {
342 if (UNLIKELY(!hasException())) {
343 throw TryException("exception(): Try does not contain an exception");
348 const exception_wrapper& exception() const {
349 if (UNLIKELY(!hasException())) {
350 throw TryException("exception(): Try does not contain an exception");
356 * If the Try contains an exception and it is of type Ex, execute func(Ex)
358 * @param func a function that takes a single parameter of type const Ex&
360 * @returns True if the Try held an Ex and func was executed, false otherwise
362 template <class Ex, class F>
363 bool withException(F func) const {
364 if (!hasException()) {
367 return e_->with_exception(std::move(func));
370 template <bool, typename R>
372 return std::forward<R>(*this);
377 std::unique_ptr<exception_wrapper> e_{nullptr};
381 * Extracts value from try and returns it. Throws if try contained an exception.
383 * @param t Try to extract value from
385 * @returns value contained in t
387 template <typename T>
388 T moveFromTry(Try<T>& t);
391 * Throws if try contained an exception.
393 * @param t Try to move from
395 void moveFromTry(Try<void>& t);
398 * @param f a function to execute and capture the result of (value or exception)
400 * @returns Try holding the result of f
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
409 * Specialization of makeTryWith for void return
411 * @param f a function to execute and capture the result of
413 * @returns Try<void> holding the result of f
415 template <typename F>
416 typename std::enable_if<
417 std::is_same<typename std::result_of<F()>::type, void>::value,
423 #include <folly/Try-inl.h>