2022-12-06 16:37:43 +00:00
|
|
|
#pragma once
|
2022-12-08 15:09:04 +00:00
|
|
|
#include <luna/Option.h>
|
2022-12-17 12:49:47 +00:00
|
|
|
#include <luna/TypeTraits.h>
|
2022-12-06 16:37:43 +00:00
|
|
|
|
2022-12-19 11:43:23 +00:00
|
|
|
template <typename T> class LinkedList;
|
2022-12-06 16:37:43 +00:00
|
|
|
|
2022-12-19 11:43:23 +00:00
|
|
|
template <typename T> class LinkedListNode
|
2022-12-06 16:37:43 +00:00
|
|
|
{
|
2022-12-19 11:43:23 +00:00
|
|
|
using SelfType = LinkedListNode<T>;
|
2022-12-06 16:37:43 +00:00
|
|
|
|
2024-03-03 13:52:23 +00:00
|
|
|
protected:
|
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()
|
|
|
|
{
|
2022-12-26 11:45:49 +00:00
|
|
|
if (m_next_node) m_next_node->m_last_node = m_last_node;
|
|
|
|
if (m_last_node) m_last_node->m_next_node = m_next_node;
|
2022-12-06 16:37:43 +00:00
|
|
|
}
|
|
|
|
|
2022-12-17 14:27:16 +00:00
|
|
|
void append_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;
|
2022-12-26 14:54:29 +00:00
|
|
|
this->m_next_node = nullptr;
|
2022-12-06 16:37:43 +00:00
|
|
|
}
|
|
|
|
|
2022-12-17 14:27:16 +00:00
|
|
|
void prepend_to_list(SelfType* start_node)
|
|
|
|
{
|
|
|
|
start_node->m_last_node = this;
|
|
|
|
this->m_next_node = start_node;
|
2022-12-26 14:54:29 +00:00
|
|
|
this->m_last_node = nullptr;
|
2022-12-17 14:27:16 +00:00
|
|
|
}
|
|
|
|
|
2022-12-19 11:43:23 +00:00
|
|
|
friend class LinkedList<T>;
|
2022-12-06 16:37:43 +00:00
|
|
|
};
|
|
|
|
|
2022-12-19 11:43:23 +00:00
|
|
|
template <typename T> class LinkedList
|
2022-12-06 16:37:43 +00:00
|
|
|
{
|
2022-12-19 11:43:23 +00:00
|
|
|
using Node = LinkedListNode<T>;
|
2022-12-06 17:41:35 +00:00
|
|
|
|
2022-12-19 11:43:23 +00:00
|
|
|
static_assert(IsBaseOf<LinkedListNode<T>, T>);
|
2022-12-17 12:49:47 +00:00
|
|
|
|
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;
|
2022-12-17 14:27:16 +00:00
|
|
|
if (m_end_node) node->append_to_list(m_end_node);
|
2022-12-06 17:23:19 +00:00
|
|
|
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++;
|
|
|
|
}
|
|
|
|
|
2022-12-17 14:27:16 +00:00
|
|
|
void prepend(T* ptr)
|
|
|
|
{
|
|
|
|
Node* const node = extract_node(ptr);
|
2022-12-17 14:28:18 +00:00
|
|
|
if (!m_end_node) m_end_node = node;
|
2022-12-17 14:27:16 +00:00
|
|
|
if (m_start_node) node->prepend_to_list(m_start_node);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
node->set_next(nullptr);
|
|
|
|
node->set_last(nullptr);
|
|
|
|
}
|
|
|
|
m_start_node = node;
|
|
|
|
|
|
|
|
m_count++;
|
|
|
|
}
|
|
|
|
|
2022-12-17 14:27:00 +00:00
|
|
|
void add_after(T* base, T* ptr)
|
2022-12-06 17:25:08 +00:00
|
|
|
{
|
2022-12-06 17:41:35 +00:00
|
|
|
Node* const new_node = extract_node(ptr);
|
|
|
|
Node* const base_node = extract_node(base);
|
2022-12-06 17:25:08 +00:00
|
|
|
|
|
|
|
if (m_end_node == base_node) m_end_node = new_node;
|
|
|
|
|
2022-12-26 14:54:29 +00:00
|
|
|
if (base_node->get_next()) base_node->get_next()->set_last(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);
|
2022-12-06 17:25:08 +00:00
|
|
|
|
|
|
|
m_count++;
|
|
|
|
}
|
|
|
|
|
2023-11-03 18:52:36 +00:00
|
|
|
void add_before(T* base, T* ptr)
|
|
|
|
{
|
|
|
|
Node* const new_node = extract_node(ptr);
|
|
|
|
Node* const base_node = extract_node(base);
|
|
|
|
|
|
|
|
if (m_start_node == base_node) m_start_node = new_node;
|
|
|
|
|
|
|
|
if (base_node->get_last()) base_node->get_last()->set_next(new_node);
|
|
|
|
|
|
|
|
new_node->set_last(base_node->get_last());
|
|
|
|
base_node->set_last(new_node);
|
|
|
|
new_node->set_next(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;
|
|
|
|
}
|
|
|
|
|
2022-12-08 15:09:04 +00:00
|
|
|
Option<T*> first()
|
2022-12-06 16:37:43 +00:00
|
|
|
{
|
2022-12-30 17:44:37 +00:00
|
|
|
return nonnull_or_empty_option((T*)m_start_node);
|
2022-12-06 16:37:43 +00:00
|
|
|
}
|
|
|
|
|
2022-12-07 14:21:50 +00:00
|
|
|
T* expect_first()
|
|
|
|
{
|
2022-12-30 17:43:39 +00:00
|
|
|
check(m_start_node);
|
2022-12-30 18:02:25 +00:00
|
|
|
return (T*)m_start_node;
|
2022-12-07 14:21:50 +00:00
|
|
|
}
|
|
|
|
|
2022-12-08 15:09:04 +00:00
|
|
|
Option<T*> last()
|
2022-12-06 16:37:43 +00:00
|
|
|
{
|
2022-12-30 17:44:37 +00:00
|
|
|
return nonnull_or_empty_option((T*)m_end_node);
|
2022-12-06 16:37:43 +00:00
|
|
|
}
|
|
|
|
|
2022-12-07 14:21:50 +00:00
|
|
|
T* expect_last()
|
|
|
|
{
|
2022-12-30 17:43:39 +00:00
|
|
|
check(m_end_node);
|
2022-12-30 18:02:25 +00:00
|
|
|
return (T*)m_end_node;
|
2022-12-07 14:21:50 +00:00
|
|
|
}
|
|
|
|
|
2022-12-08 15:09:04 +00:00
|
|
|
Option<T*> next(T* item)
|
2022-12-06 16:37:43 +00:00
|
|
|
{
|
2022-12-30 17:44:37 +00:00
|
|
|
return nonnull_or_empty_option((T*)extract_node(item)->get_next());
|
2022-12-06 16:37:43 +00:00
|
|
|
}
|
|
|
|
|
2022-12-08 15:09:04 +00:00
|
|
|
Option<T*> previous(T* item)
|
2022-12-06 16:37:43 +00:00
|
|
|
{
|
2022-12-30 17:44:37 +00:00
|
|
|
return nonnull_or_empty_option((T*)extract_node(item)->get_last());
|
2022-12-06 16:37:43 +00:00
|
|
|
}
|
|
|
|
|
2022-12-19 11:43:23 +00:00
|
|
|
// Iterates over the elements of the LinkedList from start to end, calling callback for every element.
|
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
|
|
|
}
|
|
|
|
|
2022-12-19 11:43:23 +00:00
|
|
|
// Iterates over the elements of the LinkedList from start to end, calling callback for every element. This
|
2022-12-19 11:41:25 +00:00
|
|
|
// for_each is implemented in such a way that elements can be removed while iterating over it.
|
|
|
|
template <typename Callback> void delayed_for_each(Callback callback)
|
|
|
|
{
|
|
|
|
for (Node* node = m_start_node; node;)
|
|
|
|
{
|
|
|
|
T* current = (T*)node;
|
|
|
|
node = node->get_next();
|
|
|
|
callback(current);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-19 11:43:23 +00:00
|
|
|
// Iterates over the elements of the LinkedList from end to start, calling callback for every element.
|
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
|
|
|
}
|
|
|
|
|
2022-12-19 11:43:23 +00:00
|
|
|
// Iterates over the elements of the LinkedList from the element after 'start' to end, calling callback for
|
2022-12-19 11:35:08 +00:00
|
|
|
// every element.
|
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
|
|
|
}
|
|
|
|
|
2022-12-19 11:43:23 +00:00
|
|
|
// Iterates over the elements of the LinkedList from the element before 'end' to start, calling callback for
|
2022-12-19 11:35:08 +00:00
|
|
|
// every element.
|
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
|
|
|
}
|
|
|
|
|
2022-12-19 11:43:23 +00:00
|
|
|
// Iterates over the elements of the LinkedList from start to end, removing each element before passing it to
|
2022-12-19 11:35:08 +00:00
|
|
|
// the callback.
|
|
|
|
template <typename Callback> void consume(Callback callback)
|
|
|
|
{
|
|
|
|
for (Node* node = m_start_node; node;)
|
|
|
|
{
|
|
|
|
T* current = (T*)node;
|
|
|
|
node = node->get_next();
|
|
|
|
remove(current);
|
|
|
|
callback(current);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-06 16:37:43 +00:00
|
|
|
usize count()
|
|
|
|
{
|
|
|
|
return m_count;
|
|
|
|
}
|
|
|
|
|
2023-04-28 13:12:21 +00:00
|
|
|
struct LinkedListIterator
|
|
|
|
{
|
|
|
|
typedef T* PtrT;
|
|
|
|
|
|
|
|
private:
|
|
|
|
LinkedListIterator(PtrT ptr, LinkedList<T>& list) : m_ptr(ptr), m_list(list)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
PtrT m_ptr;
|
|
|
|
LinkedList<T>& m_list;
|
|
|
|
|
|
|
|
public:
|
|
|
|
PtrT& operator*()
|
|
|
|
{
|
|
|
|
return m_ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator++()
|
|
|
|
{
|
|
|
|
m_ptr = m_list.next(m_ptr).value_or(nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(LinkedListIterator& other)
|
|
|
|
{
|
|
|
|
return m_ptr != other.m_ptr || &m_list != &other.m_list;
|
|
|
|
}
|
|
|
|
|
|
|
|
friend class LinkedList<T>;
|
|
|
|
};
|
|
|
|
|
|
|
|
LinkedListIterator begin()
|
|
|
|
{
|
|
|
|
return { (T*)m_start_node, *this };
|
|
|
|
}
|
|
|
|
|
|
|
|
LinkedListIterator end()
|
|
|
|
{
|
|
|
|
return { nullptr, *this };
|
|
|
|
}
|
|
|
|
|
2023-07-09 18:43:03 +00:00
|
|
|
void reset()
|
|
|
|
{
|
|
|
|
m_start_node = m_end_node = nullptr;
|
|
|
|
m_count = 0;
|
|
|
|
}
|
|
|
|
|
2022-12-06 16:37:43 +00:00
|
|
|
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;
|
2023-01-02 12:07:29 +00:00
|
|
|
};
|
2024-03-03 13:52:23 +00:00
|
|
|
|
|
|
|
struct Tag : public LinkedListNode<Tag>
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Tag(void* ptr) : m_ptr(ptr)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
~Tag()
|
|
|
|
{
|
|
|
|
detach_from_list();
|
|
|
|
}
|
|
|
|
|
|
|
|
void* ptr()
|
|
|
|
{
|
|
|
|
return m_ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T> T& as()
|
|
|
|
{
|
|
|
|
return *static_cast<T*>(m_ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
void* m_ptr;
|
|
|
|
};
|