From bb26ba30b6d8e195a6b61d69b60d7543b32859ff Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 17 Oct 2021 22:12:33 +0200 Subject: [PATCH] Add progress reporter type To log/report progress of long duration operations using given time period. --- apps/openmw_test_suite/CMakeLists.txt | 1 + .../misc/progressreporter.cpp | 43 ++++++++++++++++ components/misc/progressreporter.hpp | 50 +++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 apps/openmw_test_suite/misc/progressreporter.cpp create mode 100644 components/misc/progressreporter.hpp diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index 67001a7885..e8a296b563 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -24,6 +24,7 @@ if (GTEST_FOUND AND GMOCK_FOUND) misc/test_stringops.cpp misc/test_endianness.cpp + misc/progressreporter.cpp nifloader/testbulletnifloader.cpp diff --git a/apps/openmw_test_suite/misc/progressreporter.cpp b/apps/openmw_test_suite/misc/progressreporter.cpp new file mode 100644 index 0000000000..cd5449acf7 --- /dev/null +++ b/apps/openmw_test_suite/misc/progressreporter.cpp @@ -0,0 +1,43 @@ +#include + +#include +#include + +#include + +namespace +{ + using namespace testing; + using namespace Misc; + + struct ReportMock + { + MOCK_METHOD(void, call, (std::size_t, std::size_t), ()); + }; + + struct Report + { + StrictMock* mImpl; + + void operator()(std::size_t provided, std::size_t expected) + { + mImpl->call(provided, expected); + } + }; + + TEST(MiscProgressReporterTest, shouldCallReportWhenPassedInterval) + { + StrictMock report; + EXPECT_CALL(report, call(13, 42)).WillOnce(Return()); + ProgressReporter reporter(std::chrono::steady_clock::duration(0), Report {&report}); + reporter(13, 42); + } + + TEST(MiscProgressReporterTest, shouldNotCallReportWhenIntervalIsNotPassed) + { + StrictMock report; + EXPECT_CALL(report, call(13, 42)).Times(0); + ProgressReporter reporter(std::chrono::seconds(1000), Report {&report}); + reporter(13, 42); + } +} diff --git a/components/misc/progressreporter.hpp b/components/misc/progressreporter.hpp new file mode 100644 index 0000000000..733e36191e --- /dev/null +++ b/components/misc/progressreporter.hpp @@ -0,0 +1,50 @@ +#ifndef OPENMW_COMPONENTS_MISC_PROGRESSREPORTER_H +#define OPENMW_COMPONENTS_MISC_PROGRESSREPORTER_H + +#include +#include +#include +#include +#include + +namespace Misc +{ + template + class ProgressReporter + { + public: + explicit ProgressReporter(Report&& report = Report {}) + : mReport(std::forward(report)) + {} + + explicit ProgressReporter(std::chrono::steady_clock::duration interval, Report&& report = Report {}) + : mInterval(interval) + , mReport(std::forward(report)) + {} + + void operator()(std::size_t provided, std::size_t expected) + { + expected = std::max(expected, provided); + const bool shouldReport = [&] + { + const std::lock_guard lock(mMutex); + const auto now = std::chrono::steady_clock::now(); + const auto left = mNextReport - now; + if (left.count() > 0 || provided == expected) + return false; + mNextReport += mInterval + left; + return true; + } (); + if (shouldReport) + mReport(provided, expected); + } + + private: + const std::chrono::steady_clock::duration mInterval = std::chrono::seconds(1); + Report mReport; + std::mutex mMutex; + std::chrono::steady_clock::time_point mNextReport {std::chrono::steady_clock::now() + mInterval}; + }; +} + +#endif