From ce98a59397a039c19ee813ded5344b74ef95b6e2 Mon Sep 17 00:00:00 2001 From: tqcq <99722391+tqcq@users.noreply.github.com> Date: Fri, 29 Dec 2023 11:04:52 +0800 Subject: [PATCH] feat add defer --- src/ulib/utils/defer.h | 51 +++++++++++++++++++++++ tests/CMakeLists.txt | 1 + tests/ulib/system/timer_unittest.cpp | 28 +++++++------ tests/ulib/utils/defer_unittest.cpp | 60 ++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+), 12 deletions(-) create mode 100644 src/ulib/utils/defer.h create mode 100644 tests/ulib/utils/defer_unittest.cpp diff --git a/src/ulib/utils/defer.h b/src/ulib/utils/defer.h new file mode 100644 index 0000000..5e280b9 --- /dev/null +++ b/src/ulib/utils/defer.h @@ -0,0 +1,51 @@ +#ifndef ULIB_SRC_ULIB_UTILS_DEFER_H_ +#define ULIB_SRC_ULIB_UTILS_DEFER_H_ +#include "ulib/base/noncopyable.h" +#include "ulib/base/stringize_macros.h" +#include +#include +#include +#include + +namespace ulib { +class Defer : NonCopyable { +public: + using DeferFunc = std::function; + + Defer() = default; + + Defer(const DeferFunc &defer_func) { Add(defer_func); } + + Defer(DeferFunc &&defer_func) { Add(std::move(defer_func)); } + + Defer(Defer &&other) noexcept : defer_funcs_(std::move(other.defer_funcs_)) + {} + + ~Defer() + { + std::for_each(defer_funcs_.rbegin(), defer_funcs_.rend(), + [](const DeferFunc &defer_func) { defer_func(); }); + } + + template + void Add(F &&func, Args &&...args) + { + defer_funcs_.push_back( + std::bind(std::forward(func), std::forward(args)...)); + } + + void Clear() { defer_funcs_.clear(); } + +private: + std::vector defer_funcs_; +}; + +#define _ULIB_DEFER_CONCAT(a, b) a##b +#define ULIB_DEFER_CONCAT(a, b) _ULIB_DEFER_CONCAT(a, b) + +#define defer(x) \ + ::ulib::Defer ULIB_DEFER_CONCAT(__ulib_defer__, __LINE__) = \ + ::ulib::Defer(x); + +}// namespace ulib +#endif// ULIB_SRC_ULIB_UTILS_DEFER_H_ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d8e9918..caa4802 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -10,6 +10,7 @@ add_executable(ulib_test ulib/system/thread_unittest.cpp ulib/system/thread_pool_unittest.cpp ulib/system/timer_unittest.cpp + ulib/utils/defer_unittest.cpp ) target_link_libraries(ulib_test PRIVATE ulib diff --git a/tests/ulib/system/timer_unittest.cpp b/tests/ulib/system/timer_unittest.cpp index 9029ca7..ad91e61 100644 --- a/tests/ulib/system/timer_unittest.cpp +++ b/tests/ulib/system/timer_unittest.cpp @@ -7,30 +7,34 @@ class TimerTest : public ::testing::Test { protected: void SetUp() override { latch_ = nullptr; } + void TearDown() override { delete latch_; } protected: ulib::CountDownLatch *latch_; }; -TEST_F(TimerTest, OnceTrigger) { +TEST_F(TimerTest, OnceTrigger) +{ latch_ = new ulib::CountDownLatch(1); - ulib::TimerId timer_id = ulib::TimerManager::AddTimer([&]{ - latch_->CountDown(); - }, 1000); + ulib::TimerId timer_id = + ulib::TimerManager::AddTimer([&] { latch_->CountDown(); }, 1000); latch_->Await(); ulib::TimerManager::CancelTimer(timer_id); } -TEST_F(TimerTest, PeriodTrigger) { +TEST_F(TimerTest, PeriodTrigger) +{ latch_ = new ulib::CountDownLatch(3); std::atomic_int cnt(3); - ulib::TimerId timer_id = ulib::TimerManager::AddTimer([&]{ - if (cnt.fetch_sub(1) > 0) { - ULOG_INFO("timer.unittest", "start count down: {}", cnt); - latch_->CountDown(); - } - }, 1000, 3000); + ulib::TimerId timer_id = ulib::TimerManager::AddTimer( + [&] { + if (cnt.fetch_sub(1) > 0) { + ULOG_INFO("timer.unittest", "start count down: {}", cnt); + latch_->CountDown(); + } + }, + 1000, 1000); latch_->Await(); ulib::TimerManager::CancelTimer(timer_id); -} \ No newline at end of file +} diff --git a/tests/ulib/utils/defer_unittest.cpp b/tests/ulib/utils/defer_unittest.cpp new file mode 100644 index 0000000..fbc5c26 --- /dev/null +++ b/tests/ulib/utils/defer_unittest.cpp @@ -0,0 +1,60 @@ +#include +#include + +TEST(Defer, Defer) +{ + int i = 0; + { + defer([&i]() { i++; }); + EXPECT_EQ(i, 0); + } + EXPECT_EQ(i, 1); +} + +TEST(Defer, DeferFunc) +{ + int i = 0; + { + defer([&i]() { i++; }); + EXPECT_EQ(i, 0); + } + EXPECT_EQ(i, 1); +} + +TEST(Defer, DeferMove) +{ + int i = 0; + { + defer([&i]() { i++; }); + EXPECT_EQ(i, 0); + defer([&i]() { i++; }); + EXPECT_EQ(i, 0); + } + EXPECT_EQ(i, 2); +} + +TEST(Defer, Add) +{ + int i = 0; + { + ulib::Defer defer; + defer.Add([&i]() { i++; }); + EXPECT_EQ(i, 0); + defer.Add([&i]() { i++; }); + EXPECT_EQ(i, 0); + } + EXPECT_EQ(i, 2); +} + +TEST(Defer, Clear) +{ + int i = 0; + { + ulib::Defer defer; + defer.Add([&i]() { i++; }); + EXPECT_EQ(i, 0); + defer.Clear(); + EXPECT_EQ(i, 0); + } + EXPECT_EQ(i, 0); +}