2022-12-06 16:37:43 +00:00
|
|
|
#pragma once
|
|
|
|
#include <luna/Result.h>
|
|
|
|
|
|
|
|
template <typename T> inline Result<T*> nonnull_or_error(T* ptr)
|
|
|
|
{
|
2022-12-06 17:22:45 +00:00
|
|
|
if (ptr == nullptr) return err(ENONE);
|
|
|
|
else
|
|
|
|
return ptr;
|
2022-12-06 16:37:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T> class DoublyLinkedList;
|
|
|
|
|
|
|
|
template <typename T> class DoublyLinkedListNode
|
|
|
|
{
|
|
|
|
|
|
|
|
private:
|
|
|
|
DoublyLinkedListNode<T>* m_next_node;
|
|
|
|
DoublyLinkedListNode<T>* m_last_node;
|
|
|
|
|
|
|
|
void detach_from_list()
|
|
|
|
{
|
|
|
|
m_next_node->m_last_node = m_last_node;
|
|
|
|
m_last_node->m_next_node = m_next_node;
|
|
|
|
}
|
|
|
|
|
|
|
|
void add_to_list(DoublyLinkedListNode<T>* end_node)
|
|
|
|
{
|
|
|
|
end_node->m_next_node = this;
|
|
|
|
this->m_last_node = end_node;
|
|
|
|
}
|
|
|
|
|
|
|
|
friend class DoublyLinkedList<T>;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T> class DoublyLinkedList
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
void append(T* ptr)
|
|
|
|
{
|
|
|
|
DoublyLinkedListNode<T>* node = (DoublyLinkedListNode<T>*)ptr;
|
|
|
|
if (!m_start_node) m_start_node = node;
|
|
|
|
if (m_end_node) node->add_to_list(m_end_node);
|
2022-12-06 17:23:19 +00:00
|
|
|
else
|
|
|
|
node->m_next_node = node->m_last_node = nullptr;
|
2022-12-06 16:37:43 +00:00
|
|
|
m_end_node = node;
|
|
|
|
|
|
|
|
m_count++;
|
|
|
|
}
|
|
|
|
|
2022-12-06 17:25:08 +00:00
|
|
|
void append_after(T* base, T* ptr)
|
|
|
|
{
|
|
|
|
DoublyLinkedListNode<T>* new_node = (DoublyLinkedListNode<T>*)ptr;
|
|
|
|
DoublyLinkedListNode<T>* base_node = (DoublyLinkedListNode<T>*)base;
|
|
|
|
|
|
|
|
if (m_end_node == base_node) m_end_node = new_node;
|
|
|
|
|
|
|
|
new_node->m_next_node = base_node->m_next_node;
|
|
|
|
base_node->m_next_node = new_node;
|
|
|
|
new_node->m_last_node = base_node;
|
|
|
|
|
|
|
|
m_count++;
|
|
|
|
}
|
|
|
|
|
2022-12-06 16:37:43 +00:00
|
|
|
T* remove(T* ptr)
|
|
|
|
{
|
|
|
|
DoublyLinkedListNode<T>* node = (DoublyLinkedListNode<T>*)ptr;
|
|
|
|
|
|
|
|
if (node == m_end_node) m_end_node = node->m_last_node;
|
|
|
|
if (node == m_start_node) m_start_node = node->m_next_node;
|
|
|
|
|
|
|
|
node->detach_from_list();
|
|
|
|
|
|
|
|
m_count--;
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
Result<T*> first()
|
|
|
|
{
|
|
|
|
return nonnull_or_error((T*)m_start_node);
|
|
|
|
}
|
|
|
|
|
|
|
|
Result<T*> last()
|
|
|
|
{
|
|
|
|
return nonnull_or_error((T*)m_end_node);
|
|
|
|
}
|
|
|
|
|
|
|
|
Result<T*> next(T* item)
|
|
|
|
{
|
2022-12-06 17:22:45 +00:00
|
|
|
return nonnull_or_error((T*)((DoublyLinkedListNode<T>*)item)->m_next_node);
|
2022-12-06 16:37:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Result<T*> previous(T* item)
|
|
|
|
{
|
2022-12-06 17:22:45 +00:00
|
|
|
return nonnull_or_error((T*)((DoublyLinkedListNode<T>*)item)->m_last_node);
|
2022-12-06 16:37:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Callback> void for_each(Callback callback)
|
|
|
|
{
|
|
|
|
for (DoublyLinkedListNode<T>* node = m_start_node; node; node = node->m_next_node) { callback((T*)node); }
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Callback> void for_each_reversed(Callback callback)
|
|
|
|
{
|
|
|
|
for (DoublyLinkedListNode<T>* node = m_end_node; node; node = node->m_last_node) { callback((T*)node); }
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Callback> void for_each_after(T* start, Callback callback)
|
|
|
|
{
|
|
|
|
for (DoublyLinkedListNode<T>* node = ((DoublyLinkedListNode<T>*)start)->m_next_node; node;
|
|
|
|
node = node->m_next_node)
|
|
|
|
{
|
|
|
|
callback((T*)node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Callback> void for_each_before(T* end, Callback callback)
|
|
|
|
{
|
|
|
|
for (DoublyLinkedListNode<T>* node = ((DoublyLinkedListNode<T>*)end)->m_last_node; node;
|
|
|
|
node = node->m_last_node)
|
|
|
|
{
|
|
|
|
callback((T*)node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
usize count()
|
|
|
|
{
|
|
|
|
return m_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
DoublyLinkedListNode<T>* m_start_node = nullptr;
|
|
|
|
DoublyLinkedListNode<T>* m_end_node = nullptr;
|
|
|
|
|
|
|
|
usize m_count = 0;
|
|
|
|
};
|