foxygit / Torlinkc Log in
commits tags

/src/ui/coalescing_notifier.cpp · 1.4 KB

raw
#include "torlinkc/ui/coalescing_notifier.hpp"

namespace torlinkc::ui {

CoalescingNotifier::CoalescingNotifier(std::chrono::milliseconds window, std::function<void()> onFlush)
    : window_(window), onFlush_(std::move(onFlush)) {
  thread_ = std::thread([this] { run(); });
}

CoalescingNotifier::~CoalescingNotifier() {
  {
    std::lock_guard<std::mutex> lock(mutex_);
    stop_ = true;
  }
  cv_.notify_all();
  if (thread_.joinable()) thread_.join();
}

void CoalescingNotifier::markDirty() {
  std::lock_guard<std::mutex> lock(mutex_);
  dirty_ = true;
  cv_.notify_all();
}

void CoalescingNotifier::flushNow() {
  std::lock_guard<std::mutex> lock(mutex_);
  dirty_ = true;
  flushRequested_ = true;
  cv_.notify_all();
}

void CoalescingNotifier::run() {
  std::unique_lock<std::mutex> lock(mutex_);
  while (!stop_) {
    cv_.wait(lock, [this] { return dirty_ || stop_; });
    if (stop_) break;

    // Wait out the coalescing window, unless flushNow() or stop wakes us
    // early -- this is the "further calls before the deadline are absorbed"
    // half of the contract: any markDirty() during this wait just leaves
    // dirty_ (already) true without re-arming a fresh window.
    cv_.wait_for(lock, window_, [this] { return flushRequested_ || stop_; });
    if (stop_) break;

    dirty_ = false;
    flushRequested_ = false;
    lock.unlock();
    onFlush_();
    lock.lock();
  }
}

}  // namespace torlinkc::ui