mirror of
https://github.com/SerenityOS/serenity
synced 2024-07-21 18:15:58 +00:00
AK: Avoid allocations for the Queue class
Previously the Queue class used a SinglyLinkedList to manage its queue segments. This changes the Queue class to use the IntrusiveList class instead which saves us one allocation per segment.
This commit is contained in:
parent
859e5741ff
commit
3ff0a3aa4b
31
AK/Queue.h
31
AK/Queue.h
|
@ -6,6 +6,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/IntrusiveList.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/SinglyLinkedList.h>
|
||||
#include <AK/Vector.h>
|
||||
|
@ -16,7 +17,11 @@ template<typename T, int segment_size = 1000>
|
|||
class Queue {
|
||||
public:
|
||||
Queue() = default;
|
||||
~Queue() = default;
|
||||
|
||||
~Queue()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
size_t size() const { return m_size; }
|
||||
bool is_empty() const { return m_size == 0; }
|
||||
|
@ -24,18 +29,20 @@ public:
|
|||
template<typename U = T>
|
||||
void enqueue(U&& value)
|
||||
{
|
||||
if (m_segments.is_empty() || m_segments.last()->size() >= segment_size)
|
||||
m_segments.append(make<Vector<T, segment_size>>());
|
||||
m_segments.last()->append(forward<U>(value));
|
||||
if (m_segments.is_empty() || m_segments.last()->data.size() >= segment_size) {
|
||||
auto segment = new QueueSegment;
|
||||
m_segments.append(*segment);
|
||||
}
|
||||
m_segments.last()->data.append(forward<U>(value));
|
||||
++m_size;
|
||||
}
|
||||
|
||||
T dequeue()
|
||||
{
|
||||
VERIFY(!is_empty());
|
||||
auto value = move((*m_segments.first())[m_index_into_first++]);
|
||||
auto value = move(m_segments.first()->data[m_index_into_first++]);
|
||||
if (m_index_into_first == segment_size) {
|
||||
m_segments.take_first();
|
||||
delete m_segments.take_first();
|
||||
m_index_into_first = 0;
|
||||
}
|
||||
--m_size;
|
||||
|
@ -45,18 +52,24 @@ public:
|
|||
const T& head() const
|
||||
{
|
||||
VERIFY(!is_empty());
|
||||
return (*m_segments.first())[m_index_into_first];
|
||||
return m_segments.first()->data[m_index_into_first];
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_segments.clear();
|
||||
while (auto* segment = m_segments.take_first())
|
||||
delete segment;
|
||||
m_index_into_first = 0;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
SinglyLinkedList<OwnPtr<Vector<T, segment_size>>> m_segments;
|
||||
struct QueueSegment {
|
||||
Vector<T, segment_size> data;
|
||||
IntrusiveListNode<QueueSegment> node;
|
||||
};
|
||||
|
||||
IntrusiveList<QueueSegment, RawPtr<QueueSegment>, &QueueSegment::node> m_segments;
|
||||
size_t m_index_into_first { 0 };
|
||||
size_t m_size { 0 };
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue