
Co-authored-by: wxhwang <wxhwang@126.com> Co-authored-by: godyangfight <godyangfight@gmail.com> Co-authored-by: Tyshawn <tuyunshan@gmail.com>
320 lines
9.8 KiB
C++
320 lines
9.8 KiB
C++
/**
|
|
* Copyright (c) 2021 OceanBase
|
|
* OceanBase CE is licensed under Mulan PubL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
|
* You may obtain a copy of Mulan PubL v2 at:
|
|
* http://license.coscl.org.cn/MulanPubL-2.0
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PubL v2 for more details.
|
|
*/
|
|
|
|
#define UNITTEST_DEBUG
|
|
|
|
#include "lib/function/ob_function.h"
|
|
#include "lib/container/ob_array.h"
|
|
#include <gtest/gtest.h>
|
|
#include <iostream>
|
|
#include <vector>
|
|
|
|
namespace oceanbase {
|
|
namespace unittest {
|
|
|
|
using namespace common;
|
|
using namespace std;
|
|
|
|
function::DebugRecorder &recorder = function::DebugRecorder::get_instance();
|
|
function::DefaultFunctionAllocator &default_allocator = function::DefaultFunctionAllocator::get_default_allocator();
|
|
|
|
class TestObFunction: public ::testing::Test
|
|
{
|
|
public:
|
|
TestObFunction() {};
|
|
virtual ~TestObFunction() {};
|
|
virtual void SetUp() { recorder.reset(); };
|
|
virtual void TearDown() { ASSERT_EQ(default_allocator.total_alive_num, 0); };
|
|
private:
|
|
// disallow copy
|
|
DISALLOW_COPY_AND_ASSIGN(TestObFunction);
|
|
};
|
|
|
|
// 以下为C++中目前(截止到C++20标准)支持的所有可能的调用形式
|
|
// 1,普通函数
|
|
int func1(double arg1, const float &arg2) {
|
|
return (arg1 + arg2);
|
|
}
|
|
|
|
// 2,裸函数指针
|
|
int (*func2)(double, const float &) = func1;
|
|
|
|
// 3, 类成员函数和静态成员函数
|
|
struct Example {
|
|
// 3.1 类成员函数
|
|
int func3(double arg1, const float &arg2) {
|
|
return (arg1 + arg2);
|
|
}
|
|
// 3.2 静态成员函数
|
|
static int func4(double arg1, const float &arg2) {
|
|
return (arg1 + arg2);
|
|
}
|
|
};
|
|
|
|
// 4, 仿函数
|
|
class Func5 {
|
|
public:
|
|
int operator()(double arg1, const float &arg2) {
|
|
return (arg1 + arg2) * ratio;
|
|
}
|
|
private:
|
|
static constexpr int ratio = 1;// 成员状态将影响调用过程
|
|
} func5;
|
|
|
|
// 5, lambda表达式
|
|
auto func6 = [](double arg1, const float &arg2) -> int {
|
|
return (arg1 + arg2);
|
|
};
|
|
|
|
TEST_F(TestObFunction, lvalue_implicit_construction) {
|
|
ObArray<ObFunction<int(double, const float&)>> func_array;
|
|
ASSERT_EQ(OB_SUCCESS, func_array.push_back(func1));
|
|
ASSERT_EQ(OB_SUCCESS, func_array.push_back(func2));
|
|
ASSERT_EQ(OB_SUCCESS, func_array.push_back(&Example::func4));
|
|
ASSERT_EQ(OB_SUCCESS, func_array.push_back(func5));
|
|
ASSERT_EQ(OB_SUCCESS, func_array.push_back(func6));
|
|
|
|
float temp = 1.0f;
|
|
for (int64_t idx = 0; idx < func_array.count(); ++idx) {
|
|
ObFunction<int(double, const float&)> func = func_array.at(idx);
|
|
ASSERT_EQ(3, func(2.0, temp));
|
|
}
|
|
}
|
|
|
|
TEST_F(TestObFunction, rvalue_implicit_construction) {
|
|
ObArray<ObFunction<int(double, const float&)>> func_array;
|
|
ASSERT_EQ(OB_SUCCESS, func_array.push_back([](double a, const float& b) -> int {
|
|
return a + b;
|
|
}));
|
|
|
|
auto create_rvalue_function = []() { return Func5(); };
|
|
ASSERT_EQ(OB_SUCCESS, func_array.push_back(create_rvalue_function()));
|
|
|
|
float temp = 1.0f;
|
|
for (int64_t idx = 0; idx < func_array.count(); ++idx) {
|
|
ObFunction<int(double, const float&)> func = func_array.at(idx);
|
|
ASSERT_EQ(3, func(2.0, temp));
|
|
}
|
|
}
|
|
|
|
TEST_F(TestObFunction, perfect_forwarding) {
|
|
float temp = 1.0f;
|
|
ObFunction<float*(float &)> func = [](float &a) -> float* { return &a; };
|
|
ASSERT_EQ(&temp, func(temp));
|
|
}
|
|
|
|
TEST_F(TestObFunction, construction) {
|
|
ObFunction<int()> f1 = [](){ return 1; };
|
|
ObFunction<int()> f2 = f1;
|
|
ObFunction<int()> f3((ObFunction<int()>(f1)));
|
|
}
|
|
|
|
class TestAllocator1 : public ObIAllocator {
|
|
public:
|
|
void *alloc(int64_t size) override {
|
|
UNUSED(size);
|
|
return nullptr;
|
|
}
|
|
void* alloc(const int64_t size, const ObMemAttr &attr) override {
|
|
UNUSEDx(size, attr);
|
|
return nullptr;
|
|
}
|
|
void free(void *ptr) override {
|
|
UNUSED(ptr);
|
|
}
|
|
} test_allocator1;
|
|
|
|
class TestAllocator2 : public ObIAllocator {
|
|
public:
|
|
void *alloc(int64_t size) override {
|
|
return ob_malloc(size, "");
|
|
}
|
|
void* alloc(const int64_t size, const ObMemAttr &attr) override {
|
|
UNUSED(attr);
|
|
return alloc(size);
|
|
}
|
|
void free(void *ptr) override {
|
|
UNUSED(ptr);
|
|
}
|
|
} test_allocator2;
|
|
|
|
TEST_F(TestObFunction, alloc) {
|
|
float temp = 1.0f;
|
|
// implicit construct then move construct
|
|
ObFunction<float*(float &)> f1 = [](float &a) -> float* { return &a; };
|
|
ASSERT_EQ(true, f1.is_valid());
|
|
ASSERT_EQ(&temp, f1(temp));
|
|
ObFunction<float*(float &)> f2([](float &a) -> float* { return &a; }, test_allocator1);
|
|
ASSERT_EQ(true, f2.is_valid());// alloc invalid, but not used
|
|
ObFunction<float*(float &)> f3(test_allocator2);
|
|
f3 = f1;
|
|
ASSERT_EQ(true, f3.is_valid());
|
|
ObFunction<float*(float &)> f4(test_allocator1);
|
|
f4 = std::move(f1);
|
|
ASSERT_EQ(true, f4.is_valid());
|
|
}
|
|
|
|
TEST_F(TestObFunction, standard_style) {
|
|
ObFunction<void(int)> f = [](int) {};
|
|
if (f.is_valid()) {// 检查构造是否成功
|
|
f(0);
|
|
}
|
|
}
|
|
|
|
TEST_F(TestObFunction, ob_style) {
|
|
ObFunction<void(int)> f;
|
|
if (OB_SUCCESS == f.assign([](int){})) {// 检查赋值是否成功
|
|
f(0);
|
|
}
|
|
}
|
|
|
|
#define JUDGE_RECORDER(v1,v2,v3,v4,v5,v6,v7,v8,v9)\
|
|
ASSERT_EQ(recorder.function_default_construct_time, v1);\
|
|
ASSERT_EQ(recorder.function_copy_construct_time, v2);\
|
|
ASSERT_EQ(recorder.function_move_construct_time, v3);\
|
|
ASSERT_EQ(recorder.function_general_construct_time, v4);\
|
|
ASSERT_EQ(recorder.function_copy_equal_time, v5);\
|
|
ASSERT_EQ(recorder.function_move_equal_time, v6);\
|
|
ASSERT_EQ(recorder.function_general_equal_time, v7);\
|
|
ASSERT_EQ(recorder.derived_construct_time, v8);\
|
|
ASSERT_EQ(recorder.function_base_assign_time, v9);\
|
|
ASSERT_EQ(recorder.function_copy_assign_time, v2 + v5);\
|
|
ASSERT_EQ(recorder.function_move_assign_time, v3 + v6);\
|
|
ASSERT_EQ(recorder.function_general_assign_time, v4 + v7);\
|
|
recorder.reset();
|
|
|
|
TEST_F(TestObFunction, construct_path) {
|
|
// implicit general construction
|
|
ObFunction<int(double, const float&)> f1 = func1;
|
|
JUDGE_RECORDER(0,0,0,1,0,0,0,1,0);
|
|
// default construction and general assign
|
|
ObFunction<int(double, const float&)> f2;
|
|
f2 = func2;
|
|
JUDGE_RECORDER(1,0,0,0,0,0,1,1,0);
|
|
// just general assign
|
|
f2 = Func5();
|
|
JUDGE_RECORDER(0,0,0,0,0,0,1,1,0);
|
|
// copy assign
|
|
f2 = f1;
|
|
JUDGE_RECORDER(0,0,0,0,1,0,0,1,1);
|
|
// move assign
|
|
f2 = std::move(f1);
|
|
JUDGE_RECORDER(0,0,0,0,0,1,0,1,1);
|
|
// copy construction
|
|
ObFunction<int(double, const float&)> f3 = f2;
|
|
JUDGE_RECORDER(0,1,0,0,0,0,0,1,1);
|
|
// move construction
|
|
ObFunction<int(double, const float&)> f4 = std::move(f3);
|
|
JUDGE_RECORDER(0,0,1,0,0,0,0,1,1);
|
|
}
|
|
|
|
struct BigObj {
|
|
unsigned char val[41];
|
|
} ;
|
|
|
|
struct SmallObj {
|
|
unsigned char val[40];
|
|
};
|
|
|
|
// rvalue: small = big
|
|
// big = small
|
|
// small = small
|
|
// big = big
|
|
// lvalue: small = big
|
|
// big = small
|
|
// small = small
|
|
// big = big
|
|
TEST_F(TestObFunction, big_and_small_obj) {
|
|
BigObj big;
|
|
big.val[0] = 0;
|
|
SmallObj small;
|
|
ObFunction<int(void)> f1 = [big](){ return int(big.val[0]); };// big obj
|
|
ObFunction<int(void)> f2 = [big](){ return int(big.val[0]); };// big obj
|
|
ObFunction<int(void)> f3 = [big](){ return int(big.val[0]); };// big obj
|
|
ObFunction<int(void)> f4 = [big](){ return int(big.val[0]); };// big obj
|
|
ObFunction<int(void)> f5 = [big](){ return int(big.val[0]); };// big obj
|
|
ObFunction<int(void)> f6 = [big](){ return int(big.val[0]); };// big obj
|
|
ObFunction<int(void)> f7 = [big](){ return int(big.val[0]); };// big obj
|
|
ObFunction<int(void)> f8 = [big](){ return int(big.val[0]); };// big obj
|
|
ObFunction<int(void)> f9 = [small](){ return int(small.val[0]); };// small obj
|
|
ObFunction<int(void)> f10 = [small](){ return int(small.val[0]); };// small obj
|
|
ObFunction<int(void)> f11 = [small](){ return int(small.val[0]); };// small obj
|
|
ObFunction<int(void)> f12 = [small](){ return int(small.val[0]); };// small obj
|
|
ObFunction<int(void)> f13 = [small](){ return int(small.val[0]); };// small obj
|
|
ObFunction<int(void)> f14 = [small](){ return int(small.val[0]); };// small obj
|
|
ObFunction<int(void)> f15 = [small](){ return int(small.val[0]); };// small obj
|
|
ObFunction<int(void)> f16 = [small](){ return int(small.val[0]); };// small obj
|
|
|
|
recorder.reset();
|
|
// rvalue equal
|
|
f9 = std::move(f1);// small = big
|
|
JUDGE_RECORDER(0,0,0,0,0,1,0,1,1);
|
|
f2 = std::move(f10);// big = small
|
|
JUDGE_RECORDER(0,0,0,0,0,1,0,1,1);
|
|
f3 = std::move(f4);// big = big
|
|
JUDGE_RECORDER(0,0,0,0,0,1,0,0,0);
|
|
f11 = std::move(f12);// small = small
|
|
JUDGE_RECORDER(0,0,0,0,0,1,0,1,1);
|
|
// lvalue equal
|
|
f13 = f5;// small = big
|
|
JUDGE_RECORDER(0,0,0,0,1,0,0,1,1);
|
|
f6 = f14;// big = small
|
|
JUDGE_RECORDER(0,0,0,0,1,0,0,1,1);
|
|
f7 = f8;// big = big
|
|
JUDGE_RECORDER(0,0,0,0,1,0,0,1,1);
|
|
f15 = f16;// small = small
|
|
JUDGE_RECORDER(0,0,0,0,1,0,0,1,1);
|
|
// rvalue construct
|
|
ObFunction<int(void)> f17 = std::move(f9);//construct big
|
|
JUDGE_RECORDER(0,0,1,0,0,0,0,0,0);
|
|
ObFunction<int(void)> f18 = std::move(f2);//construct small
|
|
JUDGE_RECORDER(0,0,1,0,0,0,0,1,1);
|
|
// lvalue construct
|
|
ObFunction<int(void)> f19 = f17;
|
|
JUDGE_RECORDER(0,1,0,0,0,0,0,1,1);
|
|
ObFunction<int(void)> f20 = f18;
|
|
JUDGE_RECORDER(0,1,0,0,0,0,0,1,1);
|
|
|
|
}
|
|
|
|
struct TestContructDestruct
|
|
{
|
|
TestContructDestruct(int64_t &count) : count_(count) { ++count_; }
|
|
TestContructDestruct(const TestContructDestruct &rhs) : count_(rhs.count_) { ++count_; }
|
|
~TestContructDestruct() { --count_; }
|
|
void operator()() {}
|
|
int64_t &count_;
|
|
};
|
|
TEST_F(TestObFunction, test_construct_destruct)
|
|
{
|
|
int64_t count = 0;
|
|
TestContructDestruct test(count);
|
|
ASSERT_EQ(count, 1);
|
|
{
|
|
ObFunction<void()> f = test;
|
|
ASSERT_EQ(count, 2);
|
|
}
|
|
ASSERT_EQ(count, 1);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
system("rm -rf test_ob_function.log");
|
|
oceanbase::common::ObLogger &logger = oceanbase::common::ObLogger::get_logger();
|
|
logger.set_file_name("test_ob_function.log", false);
|
|
logger.set_log_level(OB_LOG_LEVEL_DEBUG);
|
|
testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
} |