 9dae112952
			
		
	
	9dae112952
	
	
	
		
			
			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();
 | |
| } |