mirror of
https://fuchsia.googlesource.com/third_party/pigweed.googlesource.com/pigweed/pigweed
synced 2024-09-20 13:51:05 +00:00
99de52de27
This implements pw::Function, a standard wrapper for callable objects. This CL is currently provided as a proof-of-concept implementation based on fbl::Function, and does not necessarily represent the final design of pw::Function. Change-Id: Ie2f5714b9711a08de878471e8f31fc46b26d36e8 Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/46080 Reviewed-by: Keir Mierle <keir@google.com> Reviewed-by: Wyatt Hepler <hepler@google.com> Commit-Queue: Alexei Frolov <frolv@google.com>
227 lines
5.5 KiB
C++
227 lines
5.5 KiB
C++
// Copyright 2021 The Pigweed Authors
|
|
//
|
|
// 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
|
|
//
|
|
// https://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.
|
|
|
|
#include "pw_function/function.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
namespace pw {
|
|
namespace {
|
|
|
|
int Multiply(int a, int b) { return a * b; }
|
|
|
|
TEST(Function, OperatorCall) {
|
|
Function<int(int, int)> multiply(Multiply);
|
|
EXPECT_EQ(multiply(3, 7), 21);
|
|
}
|
|
|
|
void CallbackAdd(int a, int b, pw::Function<void(int sum)> callback) {
|
|
callback(a + b);
|
|
}
|
|
|
|
int add_result = -1;
|
|
|
|
void free_add_callback(int sum) { add_result = sum; }
|
|
|
|
TEST(Function, ConstructInPlace_FreeFunction) {
|
|
add_result = -1;
|
|
CallbackAdd(25, 17, free_add_callback);
|
|
EXPECT_EQ(add_result, 42);
|
|
}
|
|
|
|
TEST(Function, ConstructInPlace_NonCapturingLambda) {
|
|
add_result = -1;
|
|
CallbackAdd(25, 18, [](int sum) { add_result = sum; });
|
|
EXPECT_EQ(add_result, 43);
|
|
}
|
|
|
|
TEST(Function, ConstructInPlace_CapturingLambda) {
|
|
int result = -1;
|
|
CallbackAdd(25, 19, [&](int sum) { result = sum; });
|
|
EXPECT_EQ(result, 44);
|
|
}
|
|
|
|
class CallableObject {
|
|
public:
|
|
CallableObject(int* result) : result_(result) {}
|
|
|
|
CallableObject(CallableObject&& other) = default;
|
|
CallableObject& operator=(CallableObject&& other) = default;
|
|
|
|
void operator()(int sum) { *result_ = sum; }
|
|
|
|
private:
|
|
int* result_;
|
|
};
|
|
|
|
TEST(Function, ConstructInPlace_CallableObject) {
|
|
int result = -1;
|
|
CallbackAdd(25, 20, CallableObject(&result));
|
|
EXPECT_EQ(result, 45);
|
|
}
|
|
|
|
class MemberFunctionTest : public ::testing::Test {
|
|
protected:
|
|
MemberFunctionTest() : result_(-1) {}
|
|
|
|
void set_result(int result) { result_ = result; }
|
|
|
|
int result_;
|
|
};
|
|
|
|
TEST_F(MemberFunctionTest, ConstructInPlace_Lambda) {
|
|
CallbackAdd(25, 21, [this](int sum) { set_result(sum); });
|
|
EXPECT_EQ(result_, 46);
|
|
}
|
|
|
|
TEST(Function, Null_OperatorBool) {
|
|
Closure implicit_null;
|
|
Closure explicit_null(nullptr);
|
|
Closure assigned_null = nullptr;
|
|
Closure not_null([]() {});
|
|
|
|
EXPECT_FALSE(bool(implicit_null));
|
|
EXPECT_FALSE(bool(explicit_null));
|
|
EXPECT_FALSE(bool(assigned_null));
|
|
EXPECT_TRUE(bool(not_null));
|
|
|
|
EXPECT_TRUE(!implicit_null);
|
|
EXPECT_TRUE(!explicit_null);
|
|
EXPECT_TRUE(!assigned_null);
|
|
EXPECT_FALSE(!not_null);
|
|
}
|
|
|
|
TEST(Function, Null_OperatorEquals) {
|
|
Closure implicit_null;
|
|
Closure explicit_null(nullptr);
|
|
Closure assigned_null = nullptr;
|
|
Closure not_null([]() {});
|
|
|
|
EXPECT_TRUE(implicit_null == nullptr);
|
|
EXPECT_TRUE(explicit_null == nullptr);
|
|
EXPECT_TRUE(assigned_null == nullptr);
|
|
EXPECT_TRUE(not_null != nullptr);
|
|
|
|
EXPECT_FALSE(implicit_null != nullptr);
|
|
EXPECT_FALSE(explicit_null != nullptr);
|
|
EXPECT_FALSE(assigned_null != nullptr);
|
|
EXPECT_FALSE(not_null == nullptr);
|
|
}
|
|
|
|
TEST(Function, Null_Set) {
|
|
Closure function = []() {};
|
|
EXPECT_NE(function, nullptr);
|
|
function = nullptr;
|
|
EXPECT_EQ(function, nullptr);
|
|
}
|
|
|
|
void DoNothing() {}
|
|
|
|
TEST(Function, Null_FunctionPointer) {
|
|
void (*ptr)() = DoNothing;
|
|
Closure not_null(ptr);
|
|
EXPECT_NE(not_null, nullptr);
|
|
ptr = nullptr;
|
|
Closure is_null(ptr);
|
|
EXPECT_EQ(is_null, nullptr);
|
|
}
|
|
|
|
TEST(Function, Move_Null) {
|
|
Closure moved;
|
|
EXPECT_EQ(moved, nullptr);
|
|
Closure function(std::move(moved));
|
|
EXPECT_EQ(function, nullptr);
|
|
|
|
// Ignore use-after-move.
|
|
#ifndef __clang_analyzer__
|
|
EXPECT_EQ(moved, nullptr);
|
|
#endif // __clang_analyzer__
|
|
}
|
|
|
|
TEST(Function, MoveAssign_Null) {
|
|
Closure moved;
|
|
EXPECT_EQ(moved, nullptr);
|
|
Closure function = std::move(moved);
|
|
EXPECT_EQ(function, nullptr);
|
|
|
|
// Ignore use-after-move.
|
|
#ifndef __clang_analyzer__
|
|
EXPECT_EQ(moved, nullptr);
|
|
#endif // __clang_analyzer__
|
|
}
|
|
|
|
TEST(Function, Move_Inline) {
|
|
Function<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);
|
|
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__
|
|
}
|
|
|
|
class MoveTracker {
|
|
public:
|
|
MoveTracker() : move_count_(0) {}
|
|
|
|
MoveTracker(MoveTracker&& other) : move_count_(other.move_count_ + 1) {}
|
|
MoveTracker& operator=(MoveTracker&& other) = default;
|
|
|
|
int operator()() const { return move_count_; }
|
|
|
|
private:
|
|
int move_count_;
|
|
};
|
|
|
|
TEST(Function, Move_CustomObject) {
|
|
Function<int()> moved((MoveTracker()));
|
|
EXPECT_EQ(moved(), 2); // internally moves twice on construction
|
|
Function<int()> tracker(std::move(moved));
|
|
EXPECT_EQ(tracker(), 3);
|
|
|
|
// Ignore use-after-move.
|
|
#ifndef __clang_analyzer__
|
|
EXPECT_EQ(moved, nullptr);
|
|
#endif // __clang_analyzer__
|
|
}
|
|
|
|
TEST(Function, MoveAssign_CustomObject) {
|
|
Function<int()> moved((MoveTracker()));
|
|
EXPECT_EQ(moved(), 2); // internally moves twice on construction
|
|
Function<int()> tracker = std::move(moved);
|
|
EXPECT_EQ(tracker(), 3);
|
|
|
|
// Ignore use-after-move.
|
|
#ifndef __clang_analyzer__
|
|
EXPECT_EQ(moved, nullptr);
|
|
#endif // __clang_analyzer__
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace pw
|