rcpp_framework/libs/brynet/base/Timer.hpp

146 lines
3.0 KiB
C++
Raw Normal View History

2020-11-24 15:41:18 +01:00
#pragma once
2021-04-30 16:10:14 +02:00
#include <brynet/base/Noexcept.hpp>
#include <chrono>
2020-11-24 15:41:18 +01:00
#include <functional>
#include <memory>
#include <mutex>
2021-04-30 16:10:14 +02:00
#include <queue>
#include <vector>
2020-11-24 15:41:18 +01:00
2021-05-14 17:16:45 +02:00
namespace brynet {
namespace base {
2020-11-24 15:41:18 +01:00
2021-04-30 16:10:14 +02:00
class TimerMgr;
2021-05-14 17:16:45 +02:00
class Timer final {
2021-04-30 16:10:14 +02:00
public:
2021-05-14 17:16:45 +02:00
using Ptr = std::shared_ptr<Timer>;
using WeakPtr = std::weak_ptr<Timer>;
using Callback = std::function<void(void)>;
Timer(std::chrono::steady_clock::time_point startTime,
std::chrono::nanoseconds lastTime,
Callback &&callback) BRYNET_NOEXCEPT
: mCallback(std::move(callback)),
mStartTime(startTime),
mLastTime(lastTime) {
}
const std::chrono::steady_clock::time_point &getStartTime() const {
return mStartTime;
}
const std::chrono::nanoseconds &getLastTime() const {
return mLastTime;
}
std::chrono::nanoseconds getLeftTime() const {
const auto now = std::chrono::steady_clock::now();
return getLastTime() - (now - getStartTime());
}
void cancel() {
std::call_once(mExecuteOnceFlag, [this]() {
mCallback = nullptr;
});
}
2020-11-24 15:41:18 +01:00
2021-04-30 16:10:14 +02:00
private:
2021-05-14 17:16:45 +02:00
void operator()() {
Callback callback;
std::call_once(mExecuteOnceFlag, [&callback, this]() {
callback = std::move(mCallback);
mCallback = nullptr;
});
if (callback != nullptr) {
callback();
}
}
2020-11-24 15:41:18 +01:00
2021-04-30 16:10:14 +02:00
private:
2021-05-14 17:16:45 +02:00
std::once_flag mExecuteOnceFlag;
Callback mCallback;
const std::chrono::steady_clock::time_point mStartTime;
const std::chrono::nanoseconds mLastTime;
2020-11-24 15:41:18 +01:00
2021-05-14 17:16:45 +02:00
friend class TimerMgr;
2021-04-30 16:10:14 +02:00
};
2020-11-24 15:41:18 +01:00
2021-05-14 17:16:45 +02:00
class TimerMgr final {
2021-04-30 16:10:14 +02:00
public:
2021-05-14 17:16:45 +02:00
using Ptr = std::shared_ptr<TimerMgr>;
template <typename F, typename... TArgs>
Timer::WeakPtr addTimer(
std::chrono::nanoseconds timeout,
F &&callback,
TArgs &&...args) {
auto timer = std::make_shared<Timer>(
std::chrono::steady_clock::now(),
std::chrono::nanoseconds(timeout),
std::bind(std::forward<F>(callback), std::forward<TArgs>(args)...));
mTimers.push(timer);
return timer;
}
void addTimer(const Timer::Ptr &timer) {
mTimers.push(timer);
}
void schedule() {
while (!mTimers.empty()) {
auto tmp = mTimers.top();
if (tmp->getLeftTime() > std::chrono::nanoseconds::zero()) {
break;
}
mTimers.pop();
(*tmp)();
}
}
bool isEmpty() const {
return mTimers.empty();
}
// if timer empty, return zero
std::chrono::nanoseconds nearLeftTime() const {
if (mTimers.empty()) {
return std::chrono::nanoseconds::zero();
}
auto result = mTimers.top()->getLeftTime();
if (result < std::chrono::nanoseconds::zero()) {
return std::chrono::nanoseconds::zero();
}
return result;
}
void clear() {
while (!mTimers.empty()) {
mTimers.pop();
}
}
2020-11-24 15:41:18 +01:00
2021-04-30 16:10:14 +02:00
private:
2021-05-14 17:16:45 +02:00
class CompareTimer {
public:
bool operator()(const Timer::Ptr &left,
const Timer::Ptr &right) const {
const auto startDiff = left->getStartTime() - right->getStartTime();
const auto lastDiff = left->getLastTime() - right->getLastTime();
const auto diff = startDiff.count() + lastDiff.count();
return diff > 0;
}
};
std::priority_queue<Timer::Ptr, std::vector<Timer::Ptr>, CompareTimer> mTimers;
2021-04-30 16:10:14 +02:00
};
2021-05-14 17:16:45 +02:00
} // namespace base
} // namespace brynet