mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 05:07:45 +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
1 changed files with 22 additions and 9 deletions
31
AK/Queue.h
31
AK/Queue.h
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/IntrusiveList.h>
|
||||||
#include <AK/OwnPtr.h>
|
#include <AK/OwnPtr.h>
|
||||||
#include <AK/SinglyLinkedList.h>
|
#include <AK/SinglyLinkedList.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
|
@ -16,7 +17,11 @@ template<typename T, int segment_size = 1000>
|
||||||
class Queue {
|
class Queue {
|
||||||
public:
|
public:
|
||||||
Queue() = default;
|
Queue() = default;
|
||||||
~Queue() = default;
|
|
||||||
|
~Queue()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
size_t size() const { return m_size; }
|
size_t size() const { return m_size; }
|
||||||
bool is_empty() const { return m_size == 0; }
|
bool is_empty() const { return m_size == 0; }
|
||||||
|
@ -24,18 +29,20 @@ public:
|
||||||
template<typename U = T>
|
template<typename U = T>
|
||||||
void enqueue(U&& value)
|
void enqueue(U&& value)
|
||||||
{
|
{
|
||||||
if (m_segments.is_empty() || m_segments.last()->size() >= segment_size)
|
if (m_segments.is_empty() || m_segments.last()->data.size() >= segment_size) {
|
||||||
m_segments.append(make<Vector<T, segment_size>>());
|
auto segment = new QueueSegment;
|
||||||
m_segments.last()->append(forward<U>(value));
|
m_segments.append(*segment);
|
||||||
|
}
|
||||||
|
m_segments.last()->data.append(forward<U>(value));
|
||||||
++m_size;
|
++m_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
T dequeue()
|
T dequeue()
|
||||||
{
|
{
|
||||||
VERIFY(!is_empty());
|
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) {
|
if (m_index_into_first == segment_size) {
|
||||||
m_segments.take_first();
|
delete m_segments.take_first();
|
||||||
m_index_into_first = 0;
|
m_index_into_first = 0;
|
||||||
}
|
}
|
||||||
--m_size;
|
--m_size;
|
||||||
|
@ -45,18 +52,24 @@ public:
|
||||||
const T& head() const
|
const T& head() const
|
||||||
{
|
{
|
||||||
VERIFY(!is_empty());
|
VERIFY(!is_empty());
|
||||||
return (*m_segments.first())[m_index_into_first];
|
return m_segments.first()->data[m_index_into_first];
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
m_segments.clear();
|
while (auto* segment = m_segments.take_first())
|
||||||
|
delete segment;
|
||||||
m_index_into_first = 0;
|
m_index_into_first = 0;
|
||||||
m_size = 0;
|
m_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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_index_into_first { 0 };
|
||||||
size_t m_size { 0 };
|
size_t m_size { 0 };
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue