#pragma once #include "RuntimeEvent.h" #include #include #include #include #include struct RuntimeEventQueueMetrics { std::size_t depth = 0; std::size_t capacity = 0; std::size_t droppedCount = 0; std::size_t coalescedCount = 0; double oldestEventAgeMilliseconds = 0.0; }; class RuntimeEventQueue { public: explicit RuntimeEventQueue(std::size_t capacity = 1024) : mCapacity(capacity) { } bool Push(RuntimeEvent event) { std::lock_guard lock(mMutex); if (mEvents.size() >= mCapacity) { ++mDroppedCount; return false; } mEvents.push_back(std::move(event)); return true; } bool TryPop(RuntimeEvent& event) { std::lock_guard lock(mMutex); if (mEvents.empty()) return false; event = std::move(mEvents.front()); mEvents.pop_front(); return true; } std::vector Drain(std::size_t maxEvents = 0) { std::vector events; std::lock_guard lock(mMutex); const std::size_t count = maxEvents == 0 || maxEvents > mEvents.size() ? mEvents.size() : maxEvents; events.reserve(count); for (std::size_t index = 0; index < count; ++index) { events.push_back(std::move(mEvents.front())); mEvents.pop_front(); } return events; } RuntimeEventQueueMetrics GetMetrics(std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now()) const { std::lock_guard lock(mMutex); RuntimeEventQueueMetrics metrics; metrics.depth = mEvents.size(); metrics.capacity = mCapacity; metrics.droppedCount = mDroppedCount; if (!mEvents.empty()) { const auto age = now - mEvents.front().createdAt; metrics.oldestEventAgeMilliseconds = std::chrono::duration(age).count(); } return metrics; } std::size_t Depth() const { std::lock_guard lock(mMutex); return mEvents.size(); } std::size_t Capacity() const { return mCapacity; } private: mutable std::mutex mMutex; std::deque mEvents; std::size_t mCapacity = 0; std::size_t mDroppedCount = 0; };