/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <cassert> #include <cstdint> #include <exception> #include <iosfwd> #include <memory> #include <new> #include <type_traits> #include <typeinfo> #include <utility> #include <folly/CPortability.h> #include <folly/CppAttributes.h> #include <folly/Demangle.h> #include <folly/ExceptionString.h> #include <folly/FBString.h> #include <folly/Portability.h> #include <folly/Traits.h> #include <folly/Utility.h> #include <folly/functional/traits.h> #include <folly/lang/Assume.h> #include <folly/lang/Exception.h> namespace folly { #define FOLLY_REQUIRES_DEF … #define FOLLY_REQUIRES … //! 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, inspecting exceptions through the `exception_ptr` interface, namely //! through `rethrow_exception`, is expensive. This is a wrapper interface which //! offers faster inspection. //! //! \par Example usage: //! \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<FacePlantException>(); //! } else if (rc == FAIL_WHALE) { //! globalExceptionWrapper = make_exception_wrapper<FailWhaleException>(); //! } //! } //! //! // Thread2: Exceptions are ok! //! void processResult() { //! try { //! globalExceptionWrapper.throw_exception(); //! } catch (const FacePlantException& e) { //! LOG(ERROR) << "FACEPLANT!"; //! } catch (const FailWhaleException& e) { //! LOG(ERROR) << "FAILWHALE!"; //! } //! } //! //! // Thread2: Exceptions are bad! //! void processResult() { //! globalExceptionWrapper.handle( //! [&](FacePlantException& faceplant) { //! LOG(ERROR) << "FACEPLANT"; //! }, //! [&](FailWhaleException& failwhale) { //! LOG(ERROR) << "FAILWHALE!"; //! }, //! [](...) { //! LOG(FATAL) << "Unrecognized exception"; //! }); //! } //! \endcode class exception_wrapper final { … }; /** * \return An `exception_wrapper` that wraps an instance of type `Ex` * that has been constructed with arguments `std::forward<As>(as)...`. */ template <class Ex, typename... As> exception_wrapper make_exception_wrapper(As&&... as) { … } /** * Inserts `ew.what()` into the ostream `sout`. * \return `sout` */ template <class Ch> std::basic_ostream<Ch>& operator<<( std::basic_ostream<Ch>& sout, exception_wrapper const& ew) { … } /** * Swaps the value of `a` with the value of `b`. */ inline void swap(exception_wrapper& a, exception_wrapper& b) noexcept { … } // For consistency with exceptionStr() functions in ExceptionString.h fbstring exceptionStr(exception_wrapper const& ew); //! `try_and_catch` is a convenience for `try {} catch(...) {}`` that returns an //! `exception_wrapper` with the thrown exception, if any. template <typename F> exception_wrapper try_and_catch(F&& fn) noexcept { … } } // namespace folly #include <folly/ExceptionWrapper-inl.h> #undef FOLLY_REQUIRES #undef FOLLY_REQUIRES_DEF