NBEngine/engine/NBCore/ThreadsafeQueue.hpp
2025-12-27 03:49:34 -06:00

123 lines
3.1 KiB
C++

#pragma once
#ifndef _NB_UTIL_THREADSAFE_QUEUE
#define _NB_UTIL_THREADSAFE_QUEUE
#include <condition_variable>
#include <memory>
#include <mutex>
#include <queue>
#include <type_traits>
namespace nb {
template<typename T, bool isPoly>
class ThreadsafeQueue_impl;
// Non-polymorphic
template<typename T>
class ThreadsafeQueue_impl<T, false> {
public:
bool empty() const {
std::lock_guard<std::mutex> lock(_mutex);
return _queue.empty();
}
unsigned int size() const {
std::lock_guard<std::mutex> lock(_mutex);
return _queue.size();
}
template<typename U>
void push(U&& val) {
std::lock_guard<std::mutex> lock(_mutex);
_queue.push(std::forward<U>(val));
_cond.notify_one();
}
bool pop(std::shared_ptr<T>& dest) {
std::lock_guard<std::mutex> lock(_mutex);
if (_queue.empty()) { return false; }
dest = std::make_shared<T>(std::move(_queue.front()));
_queue.pop();
return true;
}
std::shared_ptr<T> popBlock() {
std::unique_lock<std::mutex> lock(_mutex);
_cond.wait(lock, [&]{ return !_queue.empty(); });
auto ret = std::make_shared<T>(std::move(_queue.front()));
_queue.pop();
return ret;
}
protected:
ThreadsafeQueue_impl() {}
std::queue<T> _queue;
std::condition_variable _cond;
mutable std::mutex _mutex;
};
// Polymorphic
template<typename T>
class ThreadsafeQueue_impl<T, true> {
public:
bool empty() const {
std::lock_guard<std::mutex> lock(_mutex);
return _queue.empty();
}
unsigned int size() const {
std::lock_guard<std::mutex> lock(_mutex);
return _queue.size();
}
template<typename U>
void push(U&& val) {
std::lock_guard<std::mutex> lock(_mutex);
std::shared_ptr<T> newval = std::make_shared<T>(std::forward<U>(val));
_queue.push(newval);
_cond.notify_one();
}
bool pop(std::shared_ptr<T>& dest) {
std::lock_guard<std::mutex> lock(_mutex);
if (_queue.empty()) { return false; }
dest = std::move(_queue.front());
_queue.pop();
return true;
}
std::shared_ptr<T> popBlock() {
std::unique_lock<std::mutex> lock(_mutex);
_cond.wait(lock, [&]{ return !_queue.empty(); });
auto ret = std::move(_queue.front());
_queue.pop();
return ret;
}
protected:
ThreadsafeQueue_impl() {}
std::queue<std::shared_ptr<T>> _queue;
std::condition_variable _cond;
mutable std::mutex _mutex;
};
template<typename T>
class ThreadsafeQueue : public ThreadsafeQueue_impl<T, std::is_polymorphic<T>::value> {
public:
using Implementation = ThreadsafeQueue_impl<T, std::is_polymorphic<T>::value>;
ThreadsafeQueue() = default;
~ThreadsafeQueue() = default;
ThreadsafeQueue(ThreadsafeQueue& rhs) = delete;
ThreadsafeQueue& operator=(ThreadsafeQueue& rhs) = delete;
ThreadsafeQueue(ThreadsafeQueue&& rhs) = delete;
ThreadsafeQueue& operator=(ThreadsafeQueue&& rhs) = delete;
operator bool() const { return !Implementation::empty(); }
};
} // namespace nb
#endif // _NB_UTIL_THREADSAFE_QUEUE