mergerfs/libfuse/lib/bounded_queue.hpp
Antonio SJ Musumeci 5ab0fbcaee Add manual GC triggering + configurable process queue depth
Yes, these are unrelated changes but somehow ended up being
prototyped together and I'm too lazy to separate them.
2023-06-26 22:44:23 -05:00

167 lines
2.8 KiB
C++

#pragma once
#include <condition_variable>
#include <mutex>
#include <queue>
#include <utility>
template<typename T>
class BoundedQueue
{
public:
explicit
BoundedQueue(std::size_t max_size_,
bool block_ = true)
: _block(block_),
_max_size(max_size_ ? max_size_ : 1)
{
}
BoundedQueue(const BoundedQueue&) = delete;
BoundedQueue(BoundedQueue&&) = default;
bool
push(const T& item_)
{
{
std::unique_lock<std::mutex> guard(_queue_lock);
_condition_push.wait(guard, [&]() { return _queue.size() < _max_size || !_block; });
if(_queue.size() == _max_size)
return false;
_queue.push(item_);
}
_condition_pop.notify_one();
return true;
}
bool
push(T&& item_)
{
{
std::unique_lock<std::mutex> guard(_queue_lock);
_condition_push.wait(guard, [&]() { return _queue.size() < _max_size || !_block; });
if(_queue.size() == _max_size)
return false;
_queue.push(std::move(item_));
}
_condition_pop.notify_one();
return true;
}
template<typename... Args>
bool
emplace(Args&&... args_)
{
{
std::lock_guard<std::mutex> guard(_queue_lock);
_condition_push.wait(guard, [&]() { return _queue.size() < _max_size || !_block; });
if(_queue.size() == _max_size)
return false;
_queue.emplace(std::forward<Args>(args_)...);
}
_condition_pop.notify_one();
return true;
}
bool
pop(T& item_)
{
{
std::unique_lock<std::mutex> guard(_queue_lock);
_condition_pop.wait(guard, [&]() { return !_queue.empty() || !_block; });
if(_queue.empty())
return false;
item_ = std::move(_queue.front());
_queue.pop();
}
_condition_push.notify_one();
return true;
}
std::size_t
size() const
{
std::lock_guard<std::mutex> guard(_queue_lock);
return _queue.size();
}
std::size_t
capacity() const
{
return _max_size;
}
bool
empty() const
{
std::lock_guard<std::mutex> guard(_queue_lock);
return _queue.empty();
}
bool
full() const
{
std::lock_guard<std::mutex> lock(_queue_lock);
return (_queue.size() == capacity());
}
void
block()
{
std::lock_guard<std::mutex> guard(_queue_lock);
_block = true;
}
void
unblock()
{
{
std::lock_guard<std::mutex> guard(_queue_lock);
_block = false;
}
_condition_push.notify_all();
_condition_pop.notify_all();
}
bool
blocking() const
{
std::lock_guard<std::mutex> guard(_queue_lock);
return _block;
}
private:
mutable std::mutex _queue_lock;
private:
bool _block;
std::queue<T> _queue;
const std::size_t _max_size;
std::condition_variable _condition_push;
std::condition_variable _condition_pop;
};