#pragma once #include #include #include #include #include #include namespace VUtils { template struct SafeQueue { explicit SafeQueue(size_t maxSize = -1UL) : m_maxSize(maxSize), m_end(false) {}; void push(const T &t); void push(T &&t); void close(); void clear(); std::optional pop(); std::optional waitAndPop(); bool isClosed(); int size(); private: std::queue m_que; std::mutex m_mtx; std::condition_variable m_cvEmpty, m_cvFull; const size_t m_maxSize; std::atomic m_end; }; template void SafeQueue::push(const T &t) { std::unique_lock lck(m_mtx); while (m_que.size() == m_maxSize && !m_end) { // we dont wait! we return false because queue is full... m_cvFull.wait(lck); } assert(!m_end); m_que.push(std::move(t)); m_cvEmpty.notify_one(); } template void SafeQueue::push(T &&t) { std::unique_lock lck(m_mtx); while (m_que.size() == m_maxSize && !m_end) m_cvFull.wait(lck); assert(!m_end); m_que.push(std::move(t)); m_cvEmpty.notify_one(); } template void SafeQueue::close() { m_end = true; std::lock_guard lck(m_mtx); m_cvEmpty.notify_all(); m_cvFull.notify_all(); } template std::optional SafeQueue::pop() { std::unique_lock lck(m_mtx); if (m_que.empty() || m_end) return {}; T t = std::move(m_que.front()); m_que.pop(); m_cvFull.notify_one(); return t; } template std::optional SafeQueue::waitAndPop() { std::unique_lock lck(m_mtx); while (m_que.empty() && !m_end) m_cvEmpty.wait(lck); if (m_que.empty() || m_end) return {}; T t = std::move(m_que.front()); m_que.pop(); m_cvFull.notify_one(); return t; } template void SafeQueue::clear() { std::unique_lock lck(m_mtx); std::queue empty; std::swap(m_que, empty); m_cvEmpty.notify_all(); m_cvFull.notify_all(); } template bool SafeQueue::isClosed() { return m_end; } template int SafeQueue::size() { return m_que.size(); } }