Program Listing for File list.hpp¶
↰ Return to documentation for file (lib/list.hpp
)
/* SPDX-License-Identifier: BSD-2-Clause */
#pragma once
#include <lib/error.hpp>
#include <lib/result.hpp>
namespace Gaia {
template <typename T> struct ListNode {
T *prev = nullptr;
T *next = nullptr;
};
template <typename T, ListNode<T> T::*N> class List {
public:
// Iterator code adapted from Frigg
struct Iterator {
explicit Iterator(T *start) : _current(start){};
T *operator*() const { return _current; }
bool operator==(const Iterator &other) const {
return _current == other._current;
}
bool operator!=(const Iterator &other) const {
return _current != other._current;
}
Iterator &operator++() {
_current = node(_current)->next;
return *this;
}
Iterator operator++(int) {
auto copy = *this;
++(*this);
return copy;
}
private:
T *_current;
ListNode<T> *node(T *elem) { return &(elem->*N); }
};
List() : _tail(nullptr), _head(nullptr) {}
[[nodiscard]] T *tail() const { return _tail; }
[[nodiscard]] T *head() const { return _head; }
Result<Void, Error> insert_head(T *elem) {
if (!elem) {
return Err(Error::INVALID_PARAMETERS);
}
ListNode<T> *node = &(elem->*N);
if (node->next || node->prev) {
return Err(Error::INVALID_PARAMETERS);
}
node->prev = nullptr;
node->next = _head;
if (_head) {
ListNode<T> *head_node = &(_head->*N);
head_node->prev = elem;
}
_head = elem;
if (!_tail) {
_tail = _head;
}
_length++;
return Ok({});
}
Result<Void, Error> insert_tail(T *elem) {
if (!_tail || !_head) {
TRY(insert_head(elem));
} else {
ListNode<T> *node = &(elem->*N);
ListNode<T> *tail_node = &(_tail->*N);
if (!elem)
return Err(Error::INVALID_PARAMETERS);
if (node->next || node->prev)
return Err(Error::INVALID_PARAMETERS);
node->prev = _tail;
node->next = nullptr;
tail_node->next = elem;
_tail = elem;
_length++;
}
return Ok({});
}
Result<Void, Error> insert_before(T *elem, T *before) {
ListNode<T> *node = &(elem->*N);
ListNode<T> *before_node = &(before->*N);
if (!before || !elem)
return Err(Error::INVALID_PARAMETERS);
if (!before_node->prev && !before_node->next && _head != before) {
return Err(Error::INVALID_PARAMETERS);
}
node->next = before;
node->prev = before_node->prev;
if (node->prev) {
ListNode<T> *prev_node = &(node->prev->*N);
prev_node->next = elem;
}
before_node->prev = elem;
return Ok({});
}
Result<Void, Error> insert_after(T *elem, T *after) {
ListNode<T> *node = &(elem->*N);
ListNode<T> *after_node = &(after->*N);
if (!after || !elem)
return Err(Error::INVALID_PARAMETERS);
node->prev = after;
node->next = after_node->next;
after_node->next = node;
if (node->next) {
ListNode<T> *next_node = &(node->next->*N);
next_node->prev = elem;
}
return Ok({});
}
Result<T *, Error> remove_tail() { return remove(_tail); }
Result<T *, Error> remove_head() { return remove(_head); }
Result<T *, Error> remove(T *elem) {
if (!elem)
return Err(Error::INVALID_PARAMETERS);
auto node = &(elem->*N);
auto next = node->next;
auto prev = node->prev;
if (elem == _head) {
_head = next;
}
if (elem == _tail) {
_tail = prev;
}
if (prev) {
auto prev_node = &(prev->*N);
prev_node->next = next;
}
if (next) {
auto next_node = &(next->*N);
next_node->prev = prev;
}
node->next = nullptr;
node->prev = nullptr;
_length--;
return Ok(elem);
}
size_t length() { return _length; }
Iterator begin() { return Iterator{_head}; }
Iterator end() { return Iterator{nullptr}; }
void reset() {
_head = nullptr;
_tail = nullptr;
_length = 0;
}
private:
T *_tail = nullptr;
T *_head = nullptr;
size_t _length = 0;
};
} // namespace Gaia