X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2FExceptionWrapper.h;h=9f734c5e8a738e0619becdcd8f334c1ad660f9b5;hp=a6023267a4716f8d4889b814e04b9a689b562646;hb=8a56900338f3fccf82a35f5e4de9e9680abb05ad;hpb=ed8c80a0e0988e4ce687f51ca832a00e4a6b7930 diff --git a/folly/ExceptionWrapper.h b/folly/ExceptionWrapper.h index a6023267..9f734c5e 100644 --- a/folly/ExceptionWrapper.h +++ b/folly/ExceptionWrapper.h @@ -1,5 +1,5 @@ /* - * Copyright 2017 Facebook, Inc. + * Copyright 2017-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,421 +13,660 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +/* + * Author: Eric Niebler + */ #pragma once +#include +#include #include +#include #include -#include -#include +#include #include +#include #include +#include +#include +#include #include #include +#include -namespace folly { +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wpotentially-evaluated-expression" +// GCC gets confused about lambda scopes and issues shadow-local warnings for +// parameters in totally different functions. +#pragma GCC diagnostic ignored "-Wshadow-local" +#pragma GCC diagnostic ignored "-Wshadow-compatible-local" +#endif -/* - * Throwing exceptions can be a convenient way to handle errors. Storing - * exceptions in an exception_ptr makes it easy to handle exceptions in a - * different thread or at a later time. exception_ptr can also be used in a very - * generic result/exception wrapper. - * - * However, there are some issues with throwing exceptions and - * std::exception_ptr. These issues revolve around throw being expensive, - * particularly in a multithreaded environment (see - * ExceptionWrapperBenchmark.cpp). - * - * Imagine we have a library that has an API which returns a result/exception - * wrapper. Let's consider some approaches for implementing this wrapper. - * First, we could store a std::exception. This approach loses the derived - * exception type, which can make exception handling more difficult for users - * that prefer rethrowing the exception. We could use a folly::dynamic for every - * possible type of exception. This is not very flexible - adding new types of - * exceptions requires a change to the result/exception wrapper. We could use an - * exception_ptr. However, constructing an exception_ptr as well as accessing - * the error requires a call to throw. That means that there will be two calls - * to throw in order to process the exception. For performance sensitive - * applications, this may be unacceptable. - * - * exception_wrapper is designed to handle exception management for both - * convenience and high performance use cases. make_exception_wrapper is - * templated on derived type, allowing us to rethrow the exception properly for - * users that prefer convenience. These explicitly named exception types can - * therefore be handled without any peformance penalty. exception_wrapper is - * also flexible enough to accept any type. If a caught exception is not of an - * explicitly named type, then std::exception_ptr is used to preserve the - * exception state. For performance sensitive applications, the accessor methods - * can test or extract a pointer to a specific exception type with very little - * overhead. - * - * \par Example usage: - * \par - * \code - * exception_wrapper globalExceptionWrapper; - * - * // Thread1 - * void doSomethingCrazy() { - * int rc = doSomethingCrazyWithLameReturnCodes(); - * if (rc == NAILED_IT) { - * globalExceptionWrapper = exception_wrapper(); - * } else if (rc == FACE_PLANT) { - * globalExceptionWrapper = make_exception_wrapper(); - * } else if (rc == FAIL_WHALE) { - * globalExceptionWrapper = make_exception_wrapper(); - * } - * } - * - * // Thread2: Exceptions are ok! - * void processResult() { - * try { - * globalExceptionWrapper.throwException(); - * } catch (const FacePlantException& e) { - * LOG(ERROR) << "FACEPLANT!"; - * } catch (const FailWhaleException& e) { - * LOG(ERROR) << "FAILWHALE!"; - * } - * } - * - * // Thread2: Exceptions are bad! - * void processResult() { - * globalExceptionWrapper.with_exception( - * [&](FacePlantException& faceplant) { - * LOG(ERROR) << "FACEPLANT"; - * }) || - * globalExceptionWrapper.with_exception( - * [&](FailWhaleException& failwhale) { - * LOG(ERROR) << "FAILWHALE!"; - * }) || - * LOG(FATAL) << "Unrecognized exception"; - * } - * \endcode - * - */ -class exception_wrapper { - private: - template - struct optimize; +#define FOLLY_EXCEPTION_WRAPPER_H_INCLUDED - public: - exception_wrapper() = default; - - // Implicitly construct an exception_wrapper from a qualifying exception. - // See the optimize struct for details. - template ::type>::value> - ::type> - /* implicit */ exception_wrapper(Ex&& exn) { - typedef typename std::decay::type DEx; - assign_sptr(std::make_shared(std::forward(exn))); - } +namespace folly { - // The following two constructors are meant to emulate the behavior of - // try_and_catch in performance sensitive code as well as to be flexible - // enough to wrap exceptions of unknown type. There is an overload that - // takes an exception reference so that the wrapper can extract and store - // the exception's type and what() when possible. - // - // The canonical use case is to construct an all-catching exception wrapper - // with minimal overhead like so: - // - // try { - // // some throwing code - // } catch (const std::exception& e) { - // // won't lose e's type and what() - // exception_wrapper ew{std::current_exception(), e}; - // } catch (...) { - // // everything else - // exception_wrapper ew{std::current_exception()}; - // } - // - // try_and_catch is cleaner and preferable. Use it unless you're sure you need - // something like this instead. - template - explicit exception_wrapper(std::exception_ptr eptr, Ex& exn) { - assign_eptr(eptr, exn); - } +#define FOLLY_REQUIRES_DEF(...) \ + _t(__VA_ARGS__), long>> - explicit exception_wrapper(std::exception_ptr eptr) { - assign_eptr(eptr); - } +#define FOLLY_REQUIRES(...) FOLLY_REQUIRES_DEF(__VA_ARGS__) = __LINE__ - // If the exception_wrapper does not contain an exception, std::terminate() - // is invoked to assure the [[noreturn]] behaviour. - [[noreturn]] void throwException() const; +namespace exception_wrapper_detail { - explicit operator bool() const { - return item_ || eptr_; - } +template