mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 00:50:22 +00:00
53262cd08b
And use it in the scheduler. IntrusiveList is similar to InlineLinkedList, except that rather than making assertions about the type (and requiring inheritance), it provides an IntrusiveListNode type that can be used to put an instance into many different lists at once. As a proof of concept, port the scheduler over to use it. The only downside here is that the "list" global needs to know the position of the IntrusiveListNode member, so we have to position things a little awkwardly to make that happen. We also move the runnable lists to Thread, to avoid having to publicize the node.
258 lines
6.2 KiB
C++
258 lines
6.2 KiB
C++
#pragma once
|
|
|
|
namespace AK {
|
|
|
|
class IntrusiveListNode;
|
|
class IntrusiveListStorage {
|
|
private:
|
|
friend class IntrusiveListNode;
|
|
template<class T, IntrusiveListNode T::*member>
|
|
friend class IntrusiveList;
|
|
IntrusiveListNode* m_first { nullptr };
|
|
IntrusiveListNode* m_last { nullptr };
|
|
};
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
class IntrusiveList {
|
|
public:
|
|
IntrusiveList();
|
|
~IntrusiveList();
|
|
|
|
void clear();
|
|
bool is_empty() const;
|
|
void append(T& n);
|
|
void prepend(T& n);
|
|
void remove(T& n);
|
|
bool contains(const T&) const;
|
|
T* first() const;
|
|
T* last() const;
|
|
|
|
class Iterator {
|
|
public:
|
|
Iterator();
|
|
Iterator(T* value);
|
|
|
|
T* operator*() const;
|
|
T* operator->() const;
|
|
bool operator==(const Iterator& other) const;
|
|
bool operator!=(const Iterator& other) const { return !(*this == other); }
|
|
Iterator& operator++();
|
|
Iterator& erase();
|
|
|
|
private:
|
|
T* m_value { nullptr };
|
|
};
|
|
|
|
Iterator begin();
|
|
Iterator end();
|
|
|
|
private:
|
|
static T* next(T* current);
|
|
static T* node_to_value(IntrusiveListNode& node);
|
|
IntrusiveListStorage m_storage;
|
|
};
|
|
|
|
class IntrusiveListNode {
|
|
public:
|
|
~IntrusiveListNode();
|
|
void remove();
|
|
bool is_in_list() const;
|
|
|
|
private:
|
|
template<class T, IntrusiveListNode T::*member>
|
|
friend class IntrusiveList;
|
|
IntrusiveListStorage* m_storage = nullptr;
|
|
IntrusiveListNode* m_next = nullptr;
|
|
IntrusiveListNode* m_prev = nullptr;
|
|
};
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
inline IntrusiveList<T, member>::Iterator::Iterator()
|
|
{
|
|
}
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
inline IntrusiveList<T, member>::Iterator::Iterator(T* value)
|
|
: m_value(value)
|
|
{
|
|
}
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
inline T* IntrusiveList<T, member>::Iterator::operator*() const
|
|
{
|
|
return m_value;
|
|
}
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
inline T* IntrusiveList<T, member>::Iterator::operator->() const
|
|
{
|
|
return m_value;
|
|
}
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
inline bool IntrusiveList<T, member>::Iterator::operator==(const Iterator& other) const
|
|
{
|
|
return other.m_value == m_value;
|
|
}
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
inline typename IntrusiveList<T, member>::Iterator& IntrusiveList<T, member>::Iterator::operator++()
|
|
{
|
|
m_value = IntrusiveList<T, member>::next(m_value);
|
|
return *this;
|
|
}
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
inline typename IntrusiveList<T, member>::Iterator& IntrusiveList<T, member>::Iterator::erase()
|
|
{
|
|
T* old = m_value;
|
|
m_value = IntrusiveList<T, member>::next(m_value);
|
|
(old->*member).remove();
|
|
return *this;
|
|
}
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
inline IntrusiveList<T, member>::IntrusiveList()
|
|
|
|
{
|
|
}
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
inline IntrusiveList<T, member>::~IntrusiveList()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
inline void IntrusiveList<T, member>::clear()
|
|
{
|
|
while (m_storage.m_first)
|
|
m_storage.m_first->remove();
|
|
}
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
inline bool IntrusiveList<T, member>::is_empty() const
|
|
{
|
|
return m_storage.m_first == nullptr;
|
|
}
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
inline void IntrusiveList<T, member>::append(T& n)
|
|
{
|
|
auto& nnode = n.*member;
|
|
if (nnode.m_storage)
|
|
nnode.remove();
|
|
|
|
nnode.m_storage = &m_storage;
|
|
nnode.m_prev = m_storage.m_last;
|
|
nnode.m_next = nullptr;
|
|
|
|
if (m_storage.m_last)
|
|
m_storage.m_last->m_next = &nnode;
|
|
m_storage.m_last = &nnode;
|
|
if (!m_storage.m_first)
|
|
m_storage.m_first = &nnode;
|
|
}
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
inline void IntrusiveList<T, member>::prepend(T& n)
|
|
{
|
|
auto& nnode = n.*member;
|
|
if (nnode.m_storage)
|
|
nnode.remove();
|
|
|
|
nnode.m_storage = &m_storage;
|
|
nnode.m_prev = nullptr;
|
|
nnode.m_next = m_storage.m_first;
|
|
|
|
if (m_storage.m_first)
|
|
m_storage.m_first->m_prev = &nnode;
|
|
m_storage.m_first = &nnode;
|
|
if (!m_storage.m_last)
|
|
m_storage.m_last = &nnode;
|
|
}
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
inline void IntrusiveList<T, member>::remove(T& n)
|
|
{
|
|
auto& nnode = n.*member;
|
|
if (nnode.m_storage)
|
|
nnode.remove();
|
|
}
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
inline bool IntrusiveList<T, member>::contains(const T& n) const
|
|
{
|
|
auto& nnode = n.*member;
|
|
return nnode.m_storage == &m_storage;
|
|
}
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
inline T* IntrusiveList<T, member>::first() const
|
|
{
|
|
return m_storage.m_first ? node_to_value(*m_storage.m_first) : nullptr;
|
|
}
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
inline T* IntrusiveList<T, member>::last() const
|
|
{
|
|
return m_storage.m_last ? node_to_value(*m_storage.m_last) : nullptr;
|
|
}
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
inline T* IntrusiveList<T, member>::next(T* current)
|
|
{
|
|
auto& nextnode = (current->*member).m_next;
|
|
T* nextstruct = nextnode ? node_to_value(*nextnode) : nullptr;
|
|
return nextstruct;
|
|
}
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
inline typename IntrusiveList<T, member>::Iterator IntrusiveList<T, member>::begin()
|
|
{
|
|
return m_storage.m_first ? Iterator(node_to_value(*m_storage.m_first)) : Iterator();
|
|
}
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
inline typename IntrusiveList<T, member>::Iterator IntrusiveList<T, member>::end()
|
|
{
|
|
return Iterator();
|
|
}
|
|
|
|
template<class T, IntrusiveListNode T::*member>
|
|
inline T* IntrusiveList<T, member>::node_to_value(IntrusiveListNode& node)
|
|
{
|
|
return (T*)((char*)&node - ((char*)&(((T*)nullptr)->*member) - (char*)nullptr));
|
|
}
|
|
|
|
inline IntrusiveListNode::~IntrusiveListNode()
|
|
{
|
|
if (m_storage)
|
|
remove();
|
|
}
|
|
|
|
inline void IntrusiveListNode::remove()
|
|
{
|
|
ASSERT(m_storage);
|
|
if (m_storage->m_first == this)
|
|
m_storage->m_first = m_next;
|
|
if (m_storage->m_last == this)
|
|
m_storage->m_last = m_prev;
|
|
if (m_prev)
|
|
m_prev->m_next = m_next;
|
|
if (m_next)
|
|
m_next->m_prev = m_prev;
|
|
m_prev = nullptr;
|
|
m_next = nullptr;
|
|
m_storage = nullptr;
|
|
}
|
|
|
|
inline bool IntrusiveListNode::is_in_list() const
|
|
{
|
|
return m_storage != nullptr;
|
|
}
|
|
|
|
}
|
|
|
|
using AK::IntrusiveList;
|
|
using AK::IntrusiveListNode;
|