Skip to content

Commit

Permalink
pw_function: Add pw::InlineFunction alias
Browse files Browse the repository at this point in the history
In cases when dynamic allocation is enabled for pw::Function, but
compile-time inlining verification is still required alias
pw::InlineFunction can be used.

Change-Id: Idbf7a939254cb41b4a4e2030ce74479df6f49e25
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/109710
Reviewed-by: Wyatt Hepler <[email protected]>
Commit-Queue: Dennis Kormalev <[email protected]>
Pigweed-Auto-Submit: Dennis Kormalev <[email protected]>
  • Loading branch information
dkormalev authored and CQ Bot Account committed Sep 9, 2022
1 parent 026f36d commit 302b1b6
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 0 deletions.
7 changes: 7 additions & 0 deletions pw_function/docs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ inline storage size defaults to the size of two pointers, but is configurable
through the build system. The size of a ``Function`` object is equivalent to its
inline storage size.

The ``pw::InlineFunction`` alias is similar to ``pw::Function``, but is always
inlined. That is, even if dynamic allocation is enabled for ``pw::Function`` -
``pw::InlineFunction`` will fail to compile if the callable is larger than the
inline storage size.

Attempting to construct a function from a callable larger than its inline size
is a compile-time error unless dynamic allocation is enabled.

Expand Down Expand Up @@ -109,6 +114,8 @@ is a compile-time error unless dynamic allocation is enabled.

When ``PW_FUNCTION_ENABLE_DYNAMIC_ALLOCATION`` is enabled, a ``Function``
will use dynamic allocation to store callables that exceed the inline size.
When it is enabled but a compile-time check for the inlining is still required
``pw::InlineFunction`` can be used.

API usage
=========
Expand Down
61 changes: 61 additions & 0 deletions pw_function/function_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ void CallbackAdd(int a, int b, pw::Function<void(int sum)> callback) {
callback(a + b);
}

void InlineCallbackAdd(int a,
int b,
pw::InlineFunction<void(int sum)> callback) {
callback(a + b);
}

int add_result = -1;

void free_add_callback(int sum) { add_result = sum; }
Expand All @@ -81,6 +87,24 @@ TEST(Function, ConstructInPlace_CapturingLambda) {
EXPECT_EQ(result, 44);
}

TEST(InlineFunction, ConstructInPlace_FreeFunction) {
add_result = -1;
InlineCallbackAdd(25, 17, free_add_callback);
EXPECT_EQ(add_result, 42);
}

TEST(InlineFunction, ConstructInPlace_NonCapturingLambda) {
add_result = -1;
InlineCallbackAdd(25, 18, [](int sum) { add_result = sum; });
EXPECT_EQ(add_result, 43);
}

TEST(InlineFunction, ConstructInPlace_CapturingLambda) {
int result = -1;
InlineCallbackAdd(25, 19, [&](int sum) { result = sum; });
EXPECT_EQ(result, 44);
}

class CallableObject {
public:
CallableObject(int* result) : result_(result) {}
Expand All @@ -100,6 +124,12 @@ TEST(Function, ConstructInPlace_CallableObject) {
EXPECT_EQ(result, 45);
}

TEST(InlineFunction, ConstructInPlace_CallableObject) {
int result = -1;
InlineCallbackAdd(25, 20, CallableObject(&result));
EXPECT_EQ(result, 45);
}

class MemberFunctionTest : public ::testing::Test {
protected:
MemberFunctionTest() : result_(-1) {}
Expand Down Expand Up @@ -202,6 +232,18 @@ TEST(Function, Move_Inline) {
#endif // __clang_analyzer__
}

TEST(InlineFunction, Move_InlineFunctionToFunction) {
InlineFunction<int(int, int)> moved(Multiply);
EXPECT_NE(moved, nullptr);
Function<int(int, int)> multiply(std::move(moved));
EXPECT_EQ(multiply(3, 3), 9);

// Ignore use-after-move.
#ifndef __clang_analyzer__
EXPECT_EQ(moved, nullptr);
#endif // __clang_analyzer__
}

TEST(Function, MoveAssign_Inline) {
Function<int(int, int)> moved(Multiply);
EXPECT_NE(moved, nullptr);
Expand All @@ -214,13 +256,32 @@ TEST(Function, MoveAssign_Inline) {
#endif // __clang_analyzer__
}

TEST(InlineFunction, MoveAssign_InlineFunctionToFunction) {
InlineFunction<int(int, int)> moved(Multiply);
EXPECT_NE(moved, nullptr);
Function<int(int, int)> multiply = std::move(moved);
EXPECT_EQ(multiply(3, 3), 9);

// Ignore use-after-move.
#ifndef __clang_analyzer__
EXPECT_EQ(moved, nullptr);
#endif // __clang_analyzer__
}

TEST(Function, MoveAssign_Callable) {
Function<int(int, int)> operation = Multiply;
EXPECT_EQ(operation(3, 3), 9);
operation = [](int a, int b) -> int { return a + b; };
EXPECT_EQ(operation(3, 3), 6);
}

TEST(InlineFunction, MoveAssign_Callable) {
InlineFunction<int(int, int)> operation = Multiply;
EXPECT_EQ(operation(3, 3), 9);
operation = [](int a, int b) -> int { return a + b; };
EXPECT_EQ(operation(3, 3), 6);
}

class MoveTracker {
public:
MoveTracker() : move_count_(0) {}
Expand Down
5 changes: 5 additions & 0 deletions pw_function/public/pw_function/function.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ using Function = fit::function_impl<
/*require_inline=*/!function_internal::config::kEnableDynamicAllocation,
Callable>;

template <typename Callable,
size_t inline_target_size =
function_internal::config::kInlineCallableSize>
using InlineFunction = fit::inline_function<Callable, inline_target_size>;

using Closure = Function<void()>;

} // namespace pw

0 comments on commit 302b1b6

Please sign in to comment.