libluna: Add a variant of CircularQueue that dynamically allocates its buffer at runtime
This is needed to implement the backlog queue for listening sockets.
This commit is contained in:
parent
97d7a7cc6b
commit
d4fc002d8a
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <luna/Atomic.h>
|
#include <luna/Atomic.h>
|
||||||
|
#include <luna/Heap.h>
|
||||||
|
#include <luna/Result.h>
|
||||||
#include <luna/Types.h>
|
#include <luna/Types.h>
|
||||||
|
|
||||||
template <typename T, usize Size> class CircularQueue
|
template <typename T, usize Size> class CircularQueue
|
||||||
@ -55,3 +57,68 @@ template <typename T, usize Size> class CircularQueue
|
|||||||
Atomic<usize> m_head = 0;
|
Atomic<usize> m_head = 0;
|
||||||
Atomic<usize> m_tail = 0;
|
Atomic<usize> m_tail = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T> class DynamicCircularQueue
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
DynamicCircularQueue()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~DynamicCircularQueue()
|
||||||
|
{
|
||||||
|
if (m_data) free_impl(m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> set_size(usize size)
|
||||||
|
{
|
||||||
|
m_data = (T*)TRY(calloc_impl(size + 1, sizeof(T), false));
|
||||||
|
m_capacity = size + 1;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_push(const T& value)
|
||||||
|
{
|
||||||
|
check(m_capacity);
|
||||||
|
usize current_tail = m_tail.load(MemoryOrder::Relaxed);
|
||||||
|
const usize new_tail = (current_tail + 1) % m_capacity;
|
||||||
|
if (new_tail == m_head.load(MemoryOrder::Acquire))
|
||||||
|
{
|
||||||
|
// Queue is full
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_data[current_tail] = value;
|
||||||
|
if (!m_tail.compare_exchange_strong(current_tail, new_tail, MemoryOrder::Release, MemoryOrder::Relaxed))
|
||||||
|
{
|
||||||
|
// Someone else updated the tail
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_pop(T& value)
|
||||||
|
{
|
||||||
|
check(m_capacity);
|
||||||
|
usize current_head = m_head.load(MemoryOrder::Relaxed);
|
||||||
|
if (current_head == m_tail.load(MemoryOrder::Acquire))
|
||||||
|
{
|
||||||
|
// Queue is empty
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
value = m_data[current_head];
|
||||||
|
const usize new_head = (current_head + 1) % m_capacity;
|
||||||
|
if (!m_head.compare_exchange_strong(current_head, new_head, MemoryOrder::Release, MemoryOrder::Relaxed))
|
||||||
|
{
|
||||||
|
// Someone else updated the head
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T* m_data = nullptr;
|
||||||
|
usize m_capacity = 0;
|
||||||
|
Atomic<usize> m_head = 0;
|
||||||
|
Atomic<usize> m_tail = 0;
|
||||||
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user