// Copyright (c) 2021-2024 Christoffer Lerno. All rights reserved. // Use of self source code is governed by the MIT license // a copy of which can be found in the LICENSE_STDLIB file. module std::collections::linkedlist{Type}; const ELEMENT_IS_EQUATABLE = types::is_equatable_type(Type); struct Node @private { Node *next; Node *prev; Type value; } struct LinkedList { Allocator allocator; usz size; Node *_first; Node *_last; } <* @param [&inout] allocator : "The allocator to use, defaults to the heap allocator" @return "the initialized list" *> fn LinkedList* LinkedList.init(&self, Allocator allocator) { *self = { .allocator = allocator }; return self; } fn LinkedList* LinkedList.tinit(&self) { return self.init(tmem) @inline; } fn bool LinkedList.is_initialized(&self) @inline => self.allocator != null; <* @require self.is_initialized() *> macro void LinkedList.free_node(&self, Node* node) @private { allocator::free(self.allocator, node); } macro Node* LinkedList.alloc_node(&self) @private { if (!self.allocator) self.allocator = tmem; return allocator::alloc(self.allocator, Node); } fn void LinkedList.push_front(&self, Type value) { Node *first = self._first; Node *new_node = self.alloc_node(); *new_node = { .next = first, .value = value }; self._first = new_node; if (!first) { self._last = new_node; } else { first.prev = new_node; } self.size++; } fn void LinkedList.push(&self, Type value) { Node *last = self._last; Node *new_node = self.alloc_node(); *new_node = { .prev = last, .value = value }; self._last = new_node; if (!last) { self._first = new_node; } else { last.next = new_node; } self.size++; } fn Type? LinkedList.peek(&self) => self.first() @inline; fn Type? LinkedList.peek_last(&self) => self.last() @inline; fn Type? LinkedList.first(&self) { if (!self._first) return NO_MORE_ELEMENT?; return self._first.value; } fn Type? LinkedList.last(&self) { if (!self._last) return NO_MORE_ELEMENT?; return self._last.value; } fn void LinkedList.free(&self) => self.clear() @inline; fn void LinkedList.clear(&self) { for (Node* node = self._first; node != null;) { Node* next = node.next; self.free_node(node); node = next; } self._first = null; self._last = null; self.size = 0; } fn usz LinkedList.len(&self) @inline => self.size; <* @require index < self.size *> macro Node* LinkedList.node_at_index(&self, usz index) { if (index * 2 >= self.size) { Node* node = self._last; index = self.size - index - 1; while (index--) node = node.prev; return node; } Node* node = self._first; while (index--) node = node.next; return node; } <* @require index < self.size *> fn Type LinkedList.get(&self, usz index) { return self.node_at_index(index).value; } <* @require index < self.size *> fn void LinkedList.set(&self, usz index, Type element) { self.node_at_index(index).value = element; } <* @require index < self.size *> fn void LinkedList.remove_at(&self, usz index) { self.unlink(self.node_at_index(index)); } <* @require index <= self.size *> fn void LinkedList.insert_at(&self, usz index, Type element) { switch (index) { case 0: self.push_front(element); case self.size: self.push(element); default: self.link_before(self.node_at_index(index), element); } } <* @require succ != null *> fn void LinkedList.link_before(&self, Node *succ, Type value) @private { Node* pred = succ.prev; Node* new_node = self.alloc_node(); *new_node = { .prev = pred, .next = succ, .value = value }; succ.prev = new_node; if (!pred) { self._first = new_node; } else { pred.next = new_node; } self.size++; } <* @require self._first != null *> fn void LinkedList.unlink_first(&self) @private { Node* f = self._first; Node* next = f.next; self.free_node(f); self._first = next; if (!next) { self._last = null; } else { next.prev = null; } self.size--; } fn usz LinkedList.remove(&self, Type t) @if(ELEMENT_IS_EQUATABLE) { usz start = self.size; Node* node = self._first; while (node) { switch { case equals(node.value, t): Node* next = node.next; self.unlink(node); node = next; default: node = node.next; } } return start - self.size; } fn Type? LinkedList.pop(&self) { if (!self._last) return NO_MORE_ELEMENT?; defer self.unlink_last(); return self._last.value; } fn bool LinkedList.is_empty(&self) { return !self._first; } fn Type? LinkedList.pop_front(&self) { if (!self._first) return NO_MORE_ELEMENT?; defer self.unlink_first(); return self._first.value; } fn void? LinkedList.remove_last(&self) @maydiscard { if (!self._first) return NO_MORE_ELEMENT?; self.unlink_last(); } fn void? LinkedList.remove_first(&self) @maydiscard { if (!self._first) return NO_MORE_ELEMENT?; self.unlink_first(); } fn bool LinkedList.remove_first_match(&self, Type t) @if(ELEMENT_IS_EQUATABLE) { for (Node* node = self._first; node != null; node = node.next) { if (node.value == t) { self.unlink(node); return true; } } return false; } fn bool LinkedList.remove_last_match(&self, Type t) @if(ELEMENT_IS_EQUATABLE) { for (Node* node = self._last; node != null; node = node.prev) { if (node.value == t) { self.unlink(node); return true; } } return false; } <* @require self._last != null *> fn void LinkedList.unlink_last(&self) @inline @private { Node* l = self._last; Node* prev = l.prev; self._last = prev; self.free_node(l); if (!prev) { self._first = null; } else { prev.next = null; } self.size--; } <* @require x != null *> fn void LinkedList.unlink(&self, Node* x) @private { Node* next = x.next; Node* prev = x.prev; if (!prev) { self._first = next; } else { prev.next = next; } if (!next) { self._last = prev; } else { next.prev = prev; } self.free_node(x); self.size--; }