/*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2016 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*/
-#ifndef FOLLY_EXCEPTIONWRAPPER_H
-#define FOLLY_EXCEPTIONWRAPPER_H
+#pragma once
-#include <cassert>
#include <exception>
#include <memory>
-#include <folly/String.h>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include <folly/ExceptionString.h>
+#include <folly/FBString.h>
#include <folly/detail/ExceptionWrapper.h>
namespace folly {
*
* // Thread2: Exceptions are bad!
* void processResult() {
- * auto ep = globalExceptionWrapper.get();
- * if (!ep.with_exception<FacePlantException>([&](
- * FacePlantException& faceplant) {
- * LOG(ERROR) << "FACEPLANT";
- * })) {
- * ep.with_exception<FailWhaleException>([&](
- * FailWhaleException& failwhale) {
+ * globalExceptionWrapper.with_exception(
+ * [&](FacePlantException& faceplant) {
+ * LOG(ERROR) << "FACEPLANT";
+ * }) ||
+ * globalExceptionWrapper.with_exception(
+ * [&](FailWhaleException& failwhale) {
* LOG(ERROR) << "FAILWHALE!";
- * });
- * }
+ * }) ||
+ * LOG(FATAL) << "Unrecognized exception";
* }
*
*/
assign_eptr(eptr);
}
- void throwException() const {
- if (throwfn_) {
- throwfn_(item_.get());
- } else if (eptr_) {
- std::rethrow_exception(eptr_);
- }
- }
+ // If the exception_wrapper does not contain an exception, std::terminate()
+ // is invoked to assure the [[noreturn]] behaviour.
+ [[noreturn]] void throwException() const;
explicit operator bool() const {
return item_ || eptr_;
std::exception* getCopied() { return item_.get(); }
const std::exception* getCopied() const { return item_.get(); }
- fbstring what() const {
- if (item_) {
- return exceptionStr(*item_);
- } else if (eptr_) {
- return estr_;
- } else {
- return fbstring();
- }
- }
-
- fbstring class_name() const {
- if (item_) {
- auto& i = *item_;
- return demangle(typeid(i));
- } else if (eptr_) {
- return ename_;
- } else {
- return fbstring();
- }
- }
+ fbstring what() const;
+ fbstring class_name() const;
template <class Ex>
bool is_compatible_with() const {
} else if (eptr_) {
try {
std::rethrow_exception(eptr_);
- } catch (std::exception& e) {
- return dynamic_cast<const Ex*>(&e);
+ } catch (typename std::decay<Ex>::type&) {
+ return true;
} catch (...) {
// fall through
}
return false;
}
+ template <class F>
+ bool with_exception(F&& f) {
+ using arg_type = typename functor_traits<F>::arg_type_decayed;
+ return with_exception<arg_type>(std::forward<F>(f));
+ }
+
+ template <class F>
+ bool with_exception(F&& f) const {
+ using arg_type = typename functor_traits<F>::arg_type_decayed;
+ return with_exception<const arg_type>(std::forward<F>(f));
+ }
+
// If this exception wrapper wraps an exception of type Ex, with_exception
// will call f with the wrapped exception as an argument and return true, and
// will otherwise return false.
bool>::type
with_exception(F f) const {
try {
- throwException();
+ if (*this) {
+ throwException();
+ }
} catch (typename std::decay<Ex>::type& e) {
f(e);
return true;
}
try {
- throwException();
+ if (*this) {
+ throwException();
+ }
} catch (...) {
return std::current_exception();
}
friend exception_wrapper make_exception_wrapper(Args&&... args);
private:
+ template <typename F>
+ struct functor_traits {
+ template <typename T>
+ struct impl;
+ template <typename C, typename R, typename A>
+ struct impl<R(C::*)(A)> { using arg_type = A; };
+ template <typename C, typename R, typename A>
+ struct impl<R(C::*)(A) const> { using arg_type = A; };
+ using functor_decayed = typename std::decay<F>::type;
+ using functor_op = decltype(&functor_decayed::operator());
+ using arg_type = typename impl<functor_op>::arg_type;
+ using arg_type_decayed = typename std::decay<arg_type>::type;
+ };
+
// What makes this useful is that T can be exception_wrapper* or
// const exception_wrapper*, and the compiler will use the
// instantiation which works with F.
} else if (that->eptr_) {
try {
std::rethrow_exception(that->eptr_);
- } catch (std::exception& e) {
- if (auto ex = dynamic_cast<Ex*>(&e)) {
- f(*ex);
- return true;
- }
+ } catch (Ex& e) {
+ f(e);
+ return true;
} catch (...) {
// fall through
}
}
// For consistency with exceptionStr() functions in String.h
-inline fbstring exceptionStr(const exception_wrapper& ew) {
- return ew.what();
-}
+fbstring exceptionStr(const exception_wrapper& ew);
/*
* try_and_catch is a simple replacement for try {} catch(){} that allows you to
template <typename Ex>
typename std::enable_if<exception_wrapper::optimize<Ex>::value>::type
- assign_exception(Ex& e, std::exception_ptr eptr) {
+ assign_exception(Ex& e, std::exception_ptr /*eptr*/) {
this->item_ = std::make_shared<Ex>(e);
this->throwfn_ = folly::detail::Thrower<Ex>::doThrow;
}
fn();
}
};
-}
-#endif
+
+} // folly