2021-12-26 17:01:36 +03:00
|
|
|
module datatypes
|
2021-12-24 12:19:40 +03:00
|
|
|
|
2022-11-26 19:23:26 +03:00
|
|
|
struct DoublyListNode[T] {
|
2021-12-24 12:19:40 +03:00
|
|
|
mut:
|
|
|
|
data T
|
2022-11-26 19:23:26 +03:00
|
|
|
next &DoublyListNode[T] = unsafe { 0 }
|
|
|
|
prev &DoublyListNode[T] = unsafe { 0 }
|
2021-12-24 12:19:40 +03:00
|
|
|
}
|
|
|
|
|
2022-12-02 10:22:48 +03:00
|
|
|
// DoublyLinkedList[T] represents a generic doubly linked list of elements, each of type T.
|
2022-11-26 19:23:26 +03:00
|
|
|
pub struct DoublyLinkedList[T] {
|
2021-12-24 12:19:40 +03:00
|
|
|
mut:
|
2022-11-26 19:23:26 +03:00
|
|
|
head &DoublyListNode[T] = unsafe { 0 }
|
|
|
|
tail &DoublyListNode[T] = unsafe { 0 }
|
2021-12-24 12:19:40 +03:00
|
|
|
// Internal iter pointer for allowing safe modification
|
|
|
|
// of the list while iterating. TODO: use an option
|
|
|
|
// instead of a pointer to determine it is initialized.
|
2022-11-26 19:23:26 +03:00
|
|
|
iter &DoublyListIter[T] = unsafe { 0 }
|
2021-12-24 12:19:40 +03:00
|
|
|
len int
|
|
|
|
}
|
|
|
|
|
|
|
|
// is_empty checks if the linked list is empty
|
2022-11-26 19:23:26 +03:00
|
|
|
pub fn (list DoublyLinkedList[T]) is_empty() bool {
|
2021-12-24 12:19:40 +03:00
|
|
|
return list.len == 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// len returns the length of the linked list
|
2022-11-26 19:23:26 +03:00
|
|
|
pub fn (list DoublyLinkedList[T]) len() int {
|
2021-12-24 12:19:40 +03:00
|
|
|
return list.len
|
|
|
|
}
|
|
|
|
|
|
|
|
// first returns the first element of the linked list
|
2022-11-28 11:24:47 +03:00
|
|
|
pub fn (list DoublyLinkedList[T]) first() !T {
|
2021-12-24 12:19:40 +03:00
|
|
|
if list.is_empty() {
|
|
|
|
return error('Linked list is empty')
|
|
|
|
}
|
|
|
|
return list.head.data
|
|
|
|
}
|
|
|
|
|
|
|
|
// last returns the last element of the linked list
|
2022-11-28 11:24:47 +03:00
|
|
|
pub fn (list DoublyLinkedList[T]) last() !T {
|
2021-12-24 12:19:40 +03:00
|
|
|
if list.is_empty() {
|
|
|
|
return error('Linked list is empty')
|
|
|
|
}
|
|
|
|
return list.tail.data
|
|
|
|
}
|
|
|
|
|
|
|
|
// push_back adds an element to the end of the linked list
|
2022-11-26 19:23:26 +03:00
|
|
|
pub fn (mut list DoublyLinkedList[T]) push_back(item T) {
|
|
|
|
mut new_node := &DoublyListNode[T]{
|
2021-12-24 12:19:40 +03:00
|
|
|
data: item
|
|
|
|
}
|
|
|
|
if list.is_empty() {
|
|
|
|
// first node case
|
|
|
|
list.head = new_node
|
|
|
|
list.tail = new_node
|
|
|
|
} else {
|
|
|
|
list.tail.next = new_node
|
|
|
|
new_node.prev = list.tail
|
|
|
|
list.tail = new_node
|
|
|
|
}
|
|
|
|
list.len += 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// push_front adds an element to the beginning of the linked list
|
2022-11-26 19:23:26 +03:00
|
|
|
pub fn (mut list DoublyLinkedList[T]) push_front(item T) {
|
|
|
|
mut new_node := &DoublyListNode[T]{
|
2021-12-24 12:19:40 +03:00
|
|
|
data: item
|
|
|
|
}
|
|
|
|
if list.is_empty() {
|
|
|
|
// first node case
|
|
|
|
list.head = new_node
|
|
|
|
list.tail = new_node
|
|
|
|
} else {
|
|
|
|
list.head.prev = new_node
|
|
|
|
new_node.next = list.head
|
|
|
|
list.head = new_node
|
|
|
|
}
|
|
|
|
list.len += 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// pop_back removes the last element of the linked list
|
2022-11-28 11:24:47 +03:00
|
|
|
pub fn (mut list DoublyLinkedList[T]) pop_back() !T {
|
2021-12-24 12:19:40 +03:00
|
|
|
if list.is_empty() {
|
|
|
|
return error('Linked list is empty')
|
|
|
|
}
|
|
|
|
defer {
|
|
|
|
list.len -= 1
|
|
|
|
}
|
|
|
|
if list.len == 1 {
|
|
|
|
// head == tail
|
|
|
|
value := list.tail.data
|
2022-07-21 20:45:57 +03:00
|
|
|
list.head = unsafe { nil }
|
|
|
|
list.tail = unsafe { nil }
|
2021-12-24 12:19:40 +03:00
|
|
|
return value
|
|
|
|
}
|
|
|
|
value := list.tail.data
|
2022-07-21 20:45:57 +03:00
|
|
|
list.tail.prev.next = unsafe { nil } // unlink tail
|
2021-12-24 12:19:40 +03:00
|
|
|
list.tail = list.tail.prev
|
|
|
|
return value
|
|
|
|
}
|
|
|
|
|
|
|
|
// pop_front removes the last element of the linked list
|
2022-11-28 11:24:47 +03:00
|
|
|
pub fn (mut list DoublyLinkedList[T]) pop_front() !T {
|
2021-12-24 12:19:40 +03:00
|
|
|
if list.is_empty() {
|
|
|
|
return error('Linked list is empty')
|
|
|
|
}
|
|
|
|
defer {
|
|
|
|
list.len -= 1
|
|
|
|
}
|
|
|
|
if list.len == 1 {
|
|
|
|
// head == tail
|
|
|
|
value := list.head.data
|
2022-07-21 20:45:57 +03:00
|
|
|
list.head = unsafe { nil }
|
|
|
|
list.tail = unsafe { nil }
|
2021-12-24 12:19:40 +03:00
|
|
|
return value
|
|
|
|
}
|
|
|
|
value := list.head.data
|
2022-07-21 20:45:57 +03:00
|
|
|
list.head.next.prev = unsafe { nil } // unlink head
|
2021-12-24 12:19:40 +03:00
|
|
|
list.head = list.head.next
|
|
|
|
return value
|
|
|
|
}
|
|
|
|
|
|
|
|
// insert adds an element to the linked list at the given index
|
2022-11-28 11:24:47 +03:00
|
|
|
pub fn (mut list DoublyLinkedList[T]) insert(idx int, item T) ! {
|
2021-12-24 12:19:40 +03:00
|
|
|
if idx < 0 || idx > list.len {
|
2022-11-22 14:42:29 +03:00
|
|
|
return error('Index ${idx} out of bounds [0..${list.len}]')
|
2021-12-24 12:19:40 +03:00
|
|
|
} else if idx == 0 {
|
|
|
|
// new head
|
|
|
|
list.push_front(item)
|
|
|
|
} else if idx == list.len {
|
|
|
|
// new tail
|
|
|
|
list.push_back(item)
|
|
|
|
} else if idx <= list.len / 2 {
|
|
|
|
list.insert_front(idx, item)
|
|
|
|
} else {
|
|
|
|
list.insert_back(idx, item)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// insert_back walks from the tail and inserts a new item at index idx
|
|
|
|
// (determined from the forward index). This function should be called
|
|
|
|
// when idx > list.len/2. This helper function assumes idx bounds have
|
|
|
|
// already been checked and idx is not at the edges.
|
2022-11-26 19:23:26 +03:00
|
|
|
fn (mut list DoublyLinkedList[T]) insert_back(idx int, item T) {
|
2021-12-24 12:19:40 +03:00
|
|
|
mut node := list.node(idx + 1)
|
|
|
|
mut prev := node.prev
|
|
|
|
// prev node
|
|
|
|
// ------ ------
|
|
|
|
// |next|---->|next|
|
|
|
|
// |prev|<----|prev|
|
|
|
|
// ------ ------
|
2022-11-26 19:23:26 +03:00
|
|
|
new := &DoublyListNode[T]{
|
2021-12-24 12:19:40 +03:00
|
|
|
data: item
|
|
|
|
next: node
|
|
|
|
prev: prev
|
|
|
|
}
|
|
|
|
// prev new node
|
|
|
|
// ------ ------ ------
|
|
|
|
// |next|---->|next|---->|next|
|
|
|
|
// |prev|<----|prev|<----|prev|
|
|
|
|
// ------ ------ ------
|
|
|
|
node.prev = new
|
|
|
|
prev.next = new
|
|
|
|
list.len += 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// insert_front walks from the head and inserts a new item at index idx
|
|
|
|
// (determined from the forward index). This function should be called
|
|
|
|
// when idx <= list.len/2. This helper function assumes idx bounds have
|
|
|
|
// already been checked and idx is not at the edges.
|
2022-11-26 19:23:26 +03:00
|
|
|
fn (mut list DoublyLinkedList[T]) insert_front(idx int, item T) {
|
2021-12-24 12:19:40 +03:00
|
|
|
mut node := list.node(idx - 1)
|
|
|
|
mut next := node.next
|
|
|
|
// node next
|
|
|
|
// ------ ------
|
|
|
|
// |next|---->|next|
|
|
|
|
// |prev|<----|prev|
|
|
|
|
// ------ ------
|
2022-11-26 19:23:26 +03:00
|
|
|
new := &DoublyListNode[T]{
|
2021-12-24 12:19:40 +03:00
|
|
|
data: item
|
|
|
|
next: next
|
|
|
|
prev: node
|
|
|
|
}
|
|
|
|
// node new next
|
|
|
|
// ------ ------ ------
|
|
|
|
// |next|---->|next|---->|next|
|
|
|
|
// |prev|<----|prev|<----|prev|
|
|
|
|
// ------ ------ ------
|
|
|
|
node.next = new
|
|
|
|
next.prev = new
|
|
|
|
list.len += 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// node walks from the head or tail and finds the node at index idx.
|
|
|
|
// This helper function assumes the list is not empty and idx is in
|
|
|
|
// bounds.
|
2022-11-26 19:23:26 +03:00
|
|
|
fn (list &DoublyLinkedList[T]) node(idx int) &DoublyListNode[T] {
|
2021-12-24 12:19:40 +03:00
|
|
|
if idx <= list.len / 2 {
|
|
|
|
mut node := list.head
|
|
|
|
for h := 0; h < idx; h += 1 {
|
|
|
|
node = node.next
|
|
|
|
}
|
|
|
|
return node
|
|
|
|
}
|
|
|
|
mut node := list.tail
|
|
|
|
for t := list.len - 1; t >= idx; t -= 1 {
|
|
|
|
node = node.prev
|
|
|
|
}
|
|
|
|
return node
|
|
|
|
}
|
|
|
|
|
|
|
|
// index searches the linked list for item and returns the forward index
|
|
|
|
// or none if not found.
|
2022-11-28 11:24:47 +03:00
|
|
|
pub fn (list &DoublyLinkedList[T]) index(item T) !int {
|
2021-12-24 12:19:40 +03:00
|
|
|
mut hn := list.head
|
|
|
|
mut tn := list.tail
|
|
|
|
for h, t := 0, list.len - 1; h <= t; {
|
|
|
|
if hn.data == item {
|
|
|
|
return h
|
|
|
|
} else if tn.data == item {
|
|
|
|
return t
|
|
|
|
}
|
|
|
|
h += 1
|
|
|
|
hn = hn.next
|
|
|
|
t -= 1
|
|
|
|
tn = tn.prev
|
|
|
|
}
|
2022-11-28 11:24:47 +03:00
|
|
|
return error('none')
|
2021-12-24 12:19:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// delete removes index idx from the linked list and is safe to call
|
|
|
|
// for any idx.
|
2022-11-26 19:23:26 +03:00
|
|
|
pub fn (mut list DoublyLinkedList[T]) delete(idx int) {
|
2021-12-24 12:19:40 +03:00
|
|
|
if idx < 0 || idx >= list.len {
|
|
|
|
return
|
|
|
|
} else if idx == 0 {
|
|
|
|
list.pop_front() or {}
|
|
|
|
return
|
|
|
|
} else if idx == list.len - 1 {
|
|
|
|
list.pop_back() or {}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// node should be somewhere in the middle
|
|
|
|
mut node := list.node(idx)
|
|
|
|
node.prev.next = node.next
|
|
|
|
node.next.prev = node.prev
|
|
|
|
list.len -= 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// str returns a string representation of the linked list
|
2022-11-26 19:23:26 +03:00
|
|
|
pub fn (list DoublyLinkedList[T]) str() string {
|
2022-08-25 14:12:39 +03:00
|
|
|
return list.array().str()
|
|
|
|
}
|
|
|
|
|
|
|
|
// array returns a array representation of the linked list
|
2022-11-26 19:23:26 +03:00
|
|
|
pub fn (list DoublyLinkedList[T]) array() []T {
|
2022-09-23 22:29:13 +03:00
|
|
|
mut result_array := []T{cap: list.len}
|
2021-12-24 12:19:40 +03:00
|
|
|
mut node := list.head
|
2022-05-20 18:30:16 +03:00
|
|
|
for unsafe { node != 0 } {
|
2021-12-24 12:19:40 +03:00
|
|
|
result_array << node.data
|
|
|
|
node = node.next
|
|
|
|
}
|
2022-08-25 14:12:39 +03:00
|
|
|
return result_array
|
2021-12-24 12:19:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// next implements the iter interface to use DoublyLinkedList with
|
2022-09-23 22:29:13 +03:00
|
|
|
// V's `for x in list {` loop syntax.
|
2022-11-26 19:23:26 +03:00
|
|
|
pub fn (mut list DoublyLinkedList[T]) next() ?T {
|
2022-07-21 20:45:57 +03:00
|
|
|
if list.iter == unsafe { nil } {
|
2021-12-24 12:19:40 +03:00
|
|
|
// initialize new iter object
|
2022-11-26 19:23:26 +03:00
|
|
|
list.iter = &DoublyListIter[T]{
|
2021-12-24 12:19:40 +03:00
|
|
|
node: list.head
|
|
|
|
}
|
|
|
|
return list.next()
|
|
|
|
}
|
2022-07-21 20:45:57 +03:00
|
|
|
if list.iter.node == unsafe { nil } {
|
|
|
|
list.iter = unsafe { nil }
|
2021-12-24 12:19:40 +03:00
|
|
|
return none
|
|
|
|
}
|
|
|
|
defer {
|
|
|
|
list.iter.node = list.iter.node.next
|
|
|
|
}
|
|
|
|
return list.iter.node.data
|
|
|
|
}
|
|
|
|
|
2022-09-23 22:29:13 +03:00
|
|
|
// iterator returns a new iterator instance for the `list`.
|
2022-11-26 19:23:26 +03:00
|
|
|
pub fn (mut list DoublyLinkedList[T]) iterator() DoublyListIter[T] {
|
|
|
|
return DoublyListIter[T]{
|
2022-09-23 22:29:13 +03:00
|
|
|
node: list.head
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// back_iterator returns a new backwards iterator instance for the `list`.
|
2022-11-26 19:23:26 +03:00
|
|
|
pub fn (mut list DoublyLinkedList[T]) back_iterator() DoublyListIterBack[T] {
|
|
|
|
return DoublyListIterBack[T]{
|
2022-09-23 22:29:13 +03:00
|
|
|
node: list.tail
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-02 10:22:48 +03:00
|
|
|
// DoublyListIter[T] is an iterator for DoublyLinkedList.
|
2022-09-23 22:29:13 +03:00
|
|
|
// It starts from *the start* and moves forwards to *the end* of the list.
|
|
|
|
// It can be used with V's `for x in iter {` construct.
|
|
|
|
// One list can have multiple independent iterators, pointing to different positions/places in the list.
|
|
|
|
// A DoublyListIter iterator instance always traverses the list from *start to finish*.
|
2022-11-26 19:23:26 +03:00
|
|
|
pub struct DoublyListIter[T] {
|
2022-09-23 22:29:13 +03:00
|
|
|
mut:
|
2022-11-26 19:23:26 +03:00
|
|
|
node &DoublyListNode[T] = unsafe { 0 }
|
2022-09-23 22:29:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// next returns *the next* element of the list, or `none` when the end of the list is reached.
|
|
|
|
// It is called by V's `for x in iter{` on each iteration.
|
2022-11-26 19:23:26 +03:00
|
|
|
pub fn (mut iter DoublyListIter[T]) next() ?T {
|
2022-09-23 22:29:13 +03:00
|
|
|
if iter.node == unsafe { nil } {
|
|
|
|
return none
|
|
|
|
}
|
|
|
|
res := iter.node.data
|
|
|
|
iter.node = iter.node.next
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
2022-12-02 10:22:48 +03:00
|
|
|
// DoublyListIterBack[T] is an iterator for DoublyLinkedList.
|
2022-09-23 22:29:13 +03:00
|
|
|
// It starts from *the end* and moves backwards to *the start* of the list.
|
|
|
|
// It can be used with V's `for x in iter {` construct.
|
|
|
|
// One list can have multiple independent iterators, pointing to different positions/places in the list.
|
|
|
|
// A DoublyListIterBack iterator instance always traverses the list from *finish to start*.
|
2022-11-26 19:23:26 +03:00
|
|
|
pub struct DoublyListIterBack[T] {
|
2021-12-24 12:19:40 +03:00
|
|
|
mut:
|
2022-11-26 19:23:26 +03:00
|
|
|
node &DoublyListNode[T] = unsafe { 0 }
|
2021-12-24 12:19:40 +03:00
|
|
|
}
|
2022-09-23 22:29:13 +03:00
|
|
|
|
|
|
|
// next returns *the previous* element of the list, or `none` when the start of the list is reached.
|
|
|
|
// It is called by V's `for x in iter{` on each iteration.
|
2022-11-26 19:23:26 +03:00
|
|
|
pub fn (mut iter DoublyListIterBack[T]) next() ?T {
|
2022-09-23 22:29:13 +03:00
|
|
|
if iter.node == unsafe { nil } {
|
|
|
|
return none
|
|
|
|
}
|
|
|
|
res := iter.node.data
|
|
|
|
iter.node = iter.node.prev
|
|
|
|
return res
|
|
|
|
}
|