Skip to content

Commit

Permalink
let Function be sometimes constant-initializable
Browse files Browse the repository at this point in the history
Summary: When it is initialized empty or with a capture-free or static lambda.

Reviewed By: ot, luciang

Differential Revision: D47460443

fbshipit-source-id: 4e9dde5cfcf4a051a6adf12509f6ba3cec043d74
  • Loading branch information
yfeldblum authored and facebook-github-bot committed Jul 14, 2023
1 parent 4dfd0a6 commit 81b0048
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 4 deletions.
11 changes: 7 additions & 4 deletions folly/Function.h
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,7 @@ class Function final : private detail::function::FunctionTraits<FunctionType> {
/**
* Default constructor. Constructs an empty Function.
*/
Function() = default;
constexpr Function() = default;

// not copyable
Function(const Function&) = delete;
Expand All @@ -711,7 +711,7 @@ class Function final : private detail::function::FunctionTraits<FunctionType> {
/**
* Constructs an empty `Function`.
*/
/* implicit */ Function(std::nullptr_t) noexcept {}
/* implicit */ constexpr Function(std::nullptr_t) noexcept {}

/**
* Constructs a new `Function` from any callable object that is _not_ a
Expand Down Expand Up @@ -744,7 +744,7 @@ class Function final : private detail::function::FunctionTraits<FunctionType> {
sizeof(Fun) <= sizeof(Data) && //
alignof(Fun) <= alignof(Data) && //
noexcept(Fun(FOLLY_DECLVAL(Fun))))>
/* implicit */ Function(Fun fun) noexcept(IsSmall) {
/* implicit */ constexpr Function(Fun fun) noexcept(IsSmall) {
using Dispatch = conditional_t<
IsSmall && is_trivially_copyable_v<Fun>,
detail::function::DispatchSmallTrivial,
Expand All @@ -758,7 +758,10 @@ class Function final : private detail::function::FunctionTraits<FunctionType> {
}
}
if FOLLY_CXX17_CONSTEXPR (IsSmall) {
::new (&data_.tiny) Fun(static_cast<Fun&&>(fun));
if FOLLY_CXX17_CONSTEXPR (
!std::is_empty<Fun>::value || !is_trivially_copyable_v<Fun>) {
::new (&data_.tiny) Fun(static_cast<Fun&&>(fun));
}
} else {
data_.big = new Fun(static_cast<Fun&&>(fun));
}
Expand Down
44 changes: 44 additions & 0 deletions folly/test/FunctionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1425,3 +1425,47 @@ TEST(Function, TrivialSmallBig) {
EXPECT_EQ(7, s2());
EXPECT_EQ(7, h2());
}

TEST(Function, ConstInitEmpty) {
static FOLLY_CONSTINIT Function<int()> func;
EXPECT_THROW(func(), std::bad_function_call);
}

TEST(Function, ConstInitNullptr) {
static FOLLY_CONSTINIT Function<int()> func{nullptr};
EXPECT_THROW(func(), std::bad_function_call);
}

TEST(Function, ConstInitStaticLambda) {
static FOLLY_CONSTINIT Function<int()> func{[] { return 3; }};
EXPECT_EQ(3, func());
}

namespace {
template <typename T>
union consteval_immortal {
T value;
template <typename... A>
explicit FOLLY_CONSTEVAL consteval_immortal(folly::in_place_t, A&&... a)
: value{static_cast<A&&>(a)...} {}
~consteval_immortal() {}
};
} // namespace

TEST(Function, ConstEvalEmpty) {
static FOLLY_CONSTINIT consteval_immortal<Function<int()>> func{
folly::in_place};
EXPECT_THROW(func.value(), std::bad_function_call);
}

TEST(Function, ConstEvalNullptr) {
static FOLLY_CONSTINIT consteval_immortal<Function<int()>> func{
folly::in_place, nullptr};
EXPECT_THROW(func.value(), std::bad_function_call);
}

TEST(Function, ConstEvalStaticLambda) {
static FOLLY_CONSTINIT consteval_immortal<Function<int()>> func{
folly::in_place, [] { return 3; }};
EXPECT_EQ(3, func.value());
}

0 comments on commit 81b0048

Please sign in to comment.