/* * 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 <exception> #include <stdexcept> #include <type_traits> #include <utility> #include <folly/ExceptionWrapper.h> #include <folly/Likely.h> #include <folly/Memory.h> #include <folly/Portability.h> #include <folly/Unit.h> #include <folly/Utility.h> #include <folly/functional/Invoke.h> #include <folly/lang/Exception.h> namespace folly { class FOLLY_EXPORT TryException : public std::logic_error { … }; class FOLLY_EXPORT UsingUninitializedTry : public TryException { … }; template <class T> class Try; namespace detail { template <class T> class TryBase { … }; } // namespace detail /* * Try<T> is a wrapper that contains either an instance of T, an exception, or * nothing. Exceptions are stored as exception_wrappers so that the user can * minimize rethrows if so desired. * * To represent success or a captured exception, use Try<Unit>. */ template <class T> class Try : detail::TryBase<T>, moveonly_::EnableCopyMove< std::is_copy_constructible<T>::value, std::is_move_constructible<T>::value> { … }; /* * Specialization of Try for void value type. Encapsulates either success or an * exception. */ template <> class Try<void> { … }; template <typename T> struct isTry : std::false_type { … }; isTry<Try<T>>; /* * @param f a function to execute and capture the result of (value or exception) * * @returns Try holding the result of f */ template <typename F> typename std::enable_if< !std::is_same<invoke_result_t<F>, void>::value, Try<invoke_result_t<F>>>::type makeTryWithNoUnwrap(F&& f); /* * Specialization of makeTryWith for void return * * @param f a function to execute and capture the result of * * @returns Try<void> holding the result of f */ template <typename F> typename std:: enable_if<std::is_same<invoke_result_t<F>, void>::value, Try<void>>::type makeTryWithNoUnwrap(F&& f); /* * @param f a function to execute and capture the result of (value or exception) * * @returns Try holding the result of f */ template <typename F> typename std:: enable_if<!isTry<invoke_result_t<F>>::value, Try<invoke_result_t<F>>>::type makeTryWith(F&& f); /* * Specialization of makeTryWith for functions that return Try<T> * Causes makeTryWith to not double-wrap the try. * * @param f a function to execute and capture the result of * * @returns result of f if f did not throw. Otherwise Try<T> containing * exception */ template <typename F> typename std::enable_if<isTry<invoke_result_t<F>>::value, invoke_result_t<F>>:: type makeTryWith(F&& f); /* * Try to in-place construct a new value from the specified arguments. * * If T's constructor throws an exception then this is caught and the Try<T> * object is initialised to hold that exception. * * @param args Are passed to T's constructor. */ template <typename T, typename... Args> T* tryEmplace(Try<T>& t, Args&&... args) noexcept; /* * Overload of tryEmplace() for Try<void>. */ inline void tryEmplace(Try<void>& t) noexcept; /* * Try to in-place construct a new value from the result of a function. * * If the function completes successfully then attempts to in-place construct * a value of type, T, passing the result of the function as the only parameter. * * If either the call to the function completes with an exception or the * constructor completes with an exception then the exception is caught and * stored in the Try object. * * @returns A pointer to the newly constructed object if it completed * successfully, otherwise returns nullptr if the operation completed with * an exception. */ template <typename T, typename Func> T* tryEmplaceWith(Try<T>& t, Func&& func) noexcept; /* * Specialization of tryEmplaceWith() for Try<void>. * * Calls func() and if it doesn't throw an exception then calls t.emplace(). * If func() throws then captures the exception in t using t.emplaceException(). * * Func must be callable with zero parameters and must return void. * * @returns true if func() completed without an exception, false if func() * threw an exception. */ template <typename Func> bool tryEmplaceWith(Try<void>& t, Func&& func) noexcept; /** * Tuple<Try<Type>...> -> std::tuple<Type...> * * Unwraps a tuple-like type containing a sequence of Try<Type> instances to * std::tuple<Type> */ template <typename Tuple> auto unwrapTryTuple(Tuple&&); /* * Try to move the value/exception from another Try object. * * If T's constructor throws an exception then this is caught and the Try<T> * object is initialised to hold that exception. */ template <typename T> void tryAssign(Try<T>& t, Try<T>&& other) noexcept; template <typename T> Try(T&&) -> Try<std::decay_t<T>>; } // namespace folly #include <folly/Try-inl.h>