Luna/luna/include/luna/LinkedList.h

169 lines
3.5 KiB
C
Raw Normal View History

2022-12-06 16:37:43 +00:00
#pragma once
#include <luna/Option.h>
2022-12-06 16:37:43 +00:00
template <typename T> inline Option<T*> nonnull_or_error(T* ptr)
2022-12-06 16:37:43 +00:00
{
if (ptr == nullptr) return {};
2022-12-06 17:22:45 +00:00
else
return ptr;
2022-12-06 16:37:43 +00:00
}
template <typename T> class DoublyLinkedList;
template <typename T> class DoublyLinkedListNode
{
2022-12-06 17:41:35 +00:00
using SelfType = DoublyLinkedListNode<T>;
2022-12-06 16:37:43 +00:00
private:
2022-12-06 17:41:35 +00:00
SelfType* m_next_node;
SelfType* m_last_node;
void set_next(SelfType* next)
{
m_next_node = next;
}
void set_last(SelfType* last)
{
m_last_node = last;
}
SelfType* get_next()
{
return m_next_node;
}
SelfType* get_last()
{
return m_last_node;
}
2022-12-06 16:37:43 +00:00
void detach_from_list()
{
m_next_node->m_last_node = m_last_node;
m_last_node->m_next_node = m_next_node;
}
2022-12-06 17:41:35 +00:00
void add_to_list(SelfType* end_node)
2022-12-06 16:37:43 +00:00
{
end_node->m_next_node = this;
this->m_last_node = end_node;
}
friend class DoublyLinkedList<T>;
};
template <typename T> class DoublyLinkedList
{
2022-12-06 17:41:35 +00:00
using Node = DoublyLinkedListNode<T>;
2022-12-06 16:37:43 +00:00
public:
void append(T* ptr)
{
2022-12-06 17:41:35 +00:00
Node* const node = extract_node(ptr);
2022-12-06 16:37:43 +00:00
if (!m_start_node) m_start_node = node;
if (m_end_node) node->add_to_list(m_end_node);
else
2022-12-06 17:41:35 +00:00
{
node->set_next(nullptr);
node->set_last(nullptr);
}
2022-12-06 16:37:43 +00:00
m_end_node = node;
m_count++;
}
void append_after(T* base, T* ptr)
{
2022-12-06 17:41:35 +00:00
Node* const new_node = extract_node(ptr);
Node* const base_node = extract_node(base);
if (m_end_node == base_node) m_end_node = new_node;
2022-12-06 17:41:35 +00:00
new_node->set_next(base_node->get_next());
base_node->set_next(new_node);
new_node->set_last(base_node);
m_count++;
}
2022-12-06 16:37:43 +00:00
T* remove(T* ptr)
{
2022-12-06 17:41:35 +00:00
Node* const node = extract_node(ptr);
2022-12-06 16:37:43 +00:00
2022-12-06 17:41:35 +00:00
if (node == m_end_node) m_end_node = node->get_last();
if (node == m_start_node) m_start_node = node->get_next();
2022-12-06 16:37:43 +00:00
node->detach_from_list();
m_count--;
return ptr;
}
Option<T*> first()
2022-12-06 16:37:43 +00:00
{
return nonnull_or_error((T*)m_start_node);
}
T* expect_first()
{
return first().value();
}
Option<T*> last()
2022-12-06 16:37:43 +00:00
{
return nonnull_or_error((T*)m_end_node);
}
T* expect_last()
{
return last().value();
}
Option<T*> next(T* item)
2022-12-06 16:37:43 +00:00
{
2022-12-06 17:41:35 +00:00
return nonnull_or_error((T*)extract_node(item)->get_next());
2022-12-06 16:37:43 +00:00
}
Option<T*> previous(T* item)
2022-12-06 16:37:43 +00:00
{
2022-12-06 17:41:35 +00:00
return nonnull_or_error((T*)extract_node(item)->get_last());
2022-12-06 16:37:43 +00:00
}
template <typename Callback> void for_each(Callback callback)
{
2022-12-06 17:41:35 +00:00
for (Node* node = m_start_node; node; node = node->get_next()) { callback((T*)node); }
2022-12-06 16:37:43 +00:00
}
template <typename Callback> void for_each_reversed(Callback callback)
{
2022-12-06 17:41:35 +00:00
for (Node* node = m_end_node; node; node = node->get_last()) { callback((T*)node); }
2022-12-06 16:37:43 +00:00
}
template <typename Callback> void for_each_after(T* start, Callback callback)
{
2022-12-06 17:41:35 +00:00
for (Node* node = extract_node(start)->m_next_node; node; node = node->get_next()) { callback((T*)node); }
2022-12-06 16:37:43 +00:00
}
template <typename Callback> void for_each_before(T* end, Callback callback)
{
2022-12-06 17:41:35 +00:00
for (Node* node = extract_node(end)->m_last_node; node; node = node->get_last()) { callback((T*)node); }
2022-12-06 16:37:43 +00:00
}
usize count()
{
return m_count;
}
private:
2022-12-06 17:41:35 +00:00
Node* m_start_node = nullptr;
Node* m_end_node = nullptr;
Node* extract_node(T* item)
{
return (Node*)item;
}
2022-12-06 16:37:43 +00:00
usize m_count = 0;
};