Commit 704c7ec4 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook GitHub Bot

Decay char-array and trivial args to throw_exception

Summary:
[Folly] Decay char-array and trivial args to `throw_exception` and `terminate_with`.

The motivation is to ensure smaller call-site code size in the common cases, where the solitary argument is a string literal. Extend to cases where arguments are numbers and the like as well, since that is simple enough and is something that `Function` already does.

Reviewed By: aary

Differential Revision: D23550096

fbshipit-source-id: d3a2066dc28dc4cfac6b65e2b8972613ce55d06c
parent ad37aadb
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <folly/CPortability.h> #include <folly/CPortability.h>
#include <folly/CppAttributes.h> #include <folly/CppAttributes.h>
#include <folly/Portability.h> #include <folly/Portability.h>
#include <folly/Traits.h>
namespace folly { namespace folly {
...@@ -48,52 +49,75 @@ template <typename Ex> ...@@ -48,52 +49,75 @@ template <typename Ex>
throw_exception(static_cast<Ex&&>(ex)); throw_exception(static_cast<Ex&&>(ex));
} }
// clang-format off
namespace detail { namespace detail {
template <typename T>
FOLLY_ERASE T&& to_exception_arg_(T&& t) { struct throw_exception_arg_array_ {
return static_cast<T&&>(t); template <typename R>
} using v = std::remove_extent_t<std::remove_reference_t<R>>;
template <std::size_t N> template <typename R>
FOLLY_ERASE char const* to_exception_arg_( using apply = std::enable_if_t<std::is_same<char const, v<R>>::value, v<R>*>;
char const (&array)[N]) { };
return static_cast<char const*>(array); struct throw_exception_arg_trivial_ {
} template <typename R>
using apply = remove_cvref_t<R>;
};
struct throw_exception_arg_base_ {
template <typename R>
using apply = R;
};
template <typename R>
using throw_exception_arg_ = //
conditional_t<
std::is_array<std::remove_reference_t<R>>::value,
throw_exception_arg_array_,
conditional_t<
is_trivially_copyable_v<remove_cvref_t<R>>,
throw_exception_arg_trivial_,
throw_exception_arg_base_>>;
template <typename R>
using throw_exception_arg_t =
typename throw_exception_arg_<R>::template apply<R>;
template <typename Ex, typename... Args> template <typename Ex, typename... Args>
[[noreturn]] FOLLY_NOINLINE FOLLY_COLD void throw_exception_(Args&&... args) { [[noreturn]] FOLLY_NOINLINE FOLLY_COLD void throw_exception_(Args... args) {
throw_exception(Ex(static_cast<Args&&>(args)...)); throw_exception(Ex(static_cast<Args>(args)...));
} }
template <typename Ex, typename... Args> template <typename Ex, typename... Args>
[[noreturn]] FOLLY_NOINLINE FOLLY_COLD void terminate_with_( [[noreturn]] FOLLY_NOINLINE FOLLY_COLD void terminate_with_(
Args&&... args) noexcept { Args... args) noexcept {
throw_exception(Ex(static_cast<Args&&>(args)...)); throw_exception(Ex(static_cast<Args>(args)...));
} }
} // namespace detail } // namespace detail
// clang-format on
/// throw_exception /// throw_exception
/// ///
/// Construct and throw an exception if exceptions are enabled, or terminate if /// Construct and throw an exception if exceptions are enabled, or terminate if
/// compiled with -fno-exceptions. /// compiled with -fno-exceptions.
/// ///
/// Converts any arguments of type `char const[N]` to `char const*`. /// Does not perfectly forward all its arguments. Instead, in the interest of
/// minimizing common-case inline code size, decays its arguments as follows:
/// * refs to arrays of char const are decayed to char const*
/// * refs to arrays are otherwise invalid
/// * refs to trivial types are decayed to values
///
/// The reason for treating refs to arrays as invalid is to avoid having two
/// behaviors for refs to arrays, one for the general case and one for where the
/// inner type is char const. Having two behaviors can be surprising, so avoid.
template <typename Ex, typename... Args> template <typename Ex, typename... Args>
[[noreturn]] FOLLY_ERASE void throw_exception(Args&&... args) { [[noreturn]] FOLLY_ERASE void throw_exception(Args&&... args) {
detail::throw_exception_<Ex>( detail::throw_exception_<Ex, detail::throw_exception_arg_t<Args&&>...>(
detail::to_exception_arg_(static_cast<Args&&>(args))...); static_cast<Args&&>(args)...);
} }
/// terminate_with /// terminate_with
/// ///
/// Terminates as if by forwarding to throw_exception but in a noexcept context. /// Terminates as if by forwarding to throw_exception within a noexcept context.
// clang-format off
template <typename Ex, typename... Args> template <typename Ex, typename... Args>
[[noreturn]] FOLLY_ERASE void [[noreturn]] FOLLY_ERASE void terminate_with(Args&&... args) {
terminate_with(Args&&... args) noexcept { detail::terminate_with_<Ex, detail::throw_exception_arg_t<Args>...>(
detail::terminate_with_<Ex>( static_cast<Args&&>(args)...);
detail::to_exception_arg_(static_cast<Args&&>(args))...);
} }
// clang-format on
/// invoke_cold /// invoke_cold
/// ///
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment