2025-04-12 21:58:53 +08:00
|
|
|
#ifndef ASSISTANT_H
|
|
|
|
#define ASSISTANT_H
|
|
|
|
|
|
|
|
#include <fstream>
|
2025-04-13 13:22:35 +08:00
|
|
|
#include <functional>
|
2025-04-12 21:58:53 +08:00
|
|
|
#include <random>
|
2025-04-12 22:51:06 +08:00
|
|
|
#include <string>
|
2025-04-29 12:49:47 +08:00
|
|
|
#include <thread>
|
2025-04-12 21:58:53 +08:00
|
|
|
|
|
|
|
#ifdef USE_BOOST
|
|
|
|
#include <boost/filesystem.hpp>
|
|
|
|
namespace fs = boost::filesystem;
|
|
|
|
#else
|
|
|
|
#include <filesystem>
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
#endif
|
|
|
|
|
2025-04-13 13:22:35 +08:00
|
|
|
/**
|
|
|
|
* @brief 比较两个文件的内容是否完全相同
|
|
|
|
*
|
|
|
|
* @param filea 第一个文件路径
|
|
|
|
* @param fileb 第二个文件路径
|
|
|
|
* @return true 如果文件内容完全相同
|
|
|
|
* @return false 如果文件内容不同或无法读取文件
|
|
|
|
*/
|
|
|
|
bool is_equal_filecontent(const std::string& filea, const std::string& fileb);
|
2025-04-12 21:58:53 +08:00
|
|
|
bool random_file(const std::string& file, size_t size);
|
|
|
|
|
2025-04-12 22:51:06 +08:00
|
|
|
/**
|
|
|
|
* @brief 等待变量的值达到预期值
|
|
|
|
*
|
|
|
|
* @tparam T 变量类型
|
|
|
|
* @tparam Compare 比较器类型
|
|
|
|
* @param value 变量的引用
|
|
|
|
* @param expected 预期值
|
|
|
|
* @param comparator 比较函数 (默认为 std::equal_to)
|
|
|
|
* @param timeout_ms 超时时间(毫秒),0表示无限等待
|
|
|
|
* @param interval_ms 检查间隔(毫秒)
|
|
|
|
* @return true 变量值符合预期
|
|
|
|
* @return false 超时或条件不满足
|
|
|
|
*/
|
|
|
|
template <typename T, typename Compare = std::equal_to<T>>
|
2025-04-13 00:08:50 +08:00
|
|
|
bool value_wait(const std::function<T()>& value_ref, const T& expected, Compare comparator = Compare(),
|
2025-04-12 22:51:06 +08:00
|
|
|
unsigned long timeout_ms = 0, unsigned long interval_ms = 100)
|
|
|
|
{
|
|
|
|
auto start = std::chrono::steady_clock::now();
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
2025-04-13 00:08:50 +08:00
|
|
|
T value = value_ref();
|
2025-04-12 22:51:06 +08:00
|
|
|
if (comparator(value, expected)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (timeout_ms > 0) {
|
|
|
|
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
|
|
std::chrono::steady_clock::now() - start)
|
|
|
|
.count();
|
|
|
|
|
|
|
|
if (elapsed >= timeout_ms) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(interval_ms));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-04-13 13:22:35 +08:00
|
|
|
class ScopeExit
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
ScopeExit() = default;
|
|
|
|
template <typename F> ScopeExit(F&& f) : func_(std::forward<F>(f))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
ScopeExit(const ScopeExit&) = delete;
|
|
|
|
ScopeExit& operator=(const ScopeExit&) = delete;
|
|
|
|
ScopeExit(ScopeExit&& other) noexcept : func_(std::move(other.func_))
|
|
|
|
{
|
|
|
|
other.func_ = nullptr;
|
|
|
|
}
|
|
|
|
ScopeExit& operator=(ScopeExit&& other) noexcept
|
|
|
|
{
|
|
|
|
if (this != &other) {
|
|
|
|
if (func_)
|
|
|
|
func_();
|
|
|
|
func_ = std::move(other.func_);
|
|
|
|
other.func_ = nullptr;
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
~ScopeExit()
|
|
|
|
{
|
|
|
|
if (func_)
|
|
|
|
func_();
|
|
|
|
}
|
|
|
|
void dismiss() noexcept
|
|
|
|
{
|
|
|
|
func_ = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::function<void()> func_;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define _SCOPE_EXIT_CONCAT(a, b) a##b
|
|
|
|
#define _MAKE_ON_SCOPE_EXIT(line) ScopeExit _SCOPE_EXIT_CONCAT(exit_defer_, line) = [&]()
|
|
|
|
#define ON_SCOPE_EXIT _MAKE_ON_SCOPE_EXIT(__LINE__)
|
|
|
|
|
2025-04-12 22:51:06 +08:00
|
|
|
#endif // ASSISTANT_H
|