go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/sdk/collections/linked_list.go (about) 1 /* 2 3 Copyright (c) 2023 - Present. Will Charczuk. All rights reserved. 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository. 5 6 */ 7 8 package collections 9 10 // LinkedList is an implementation of a fifo buffer using nodes and poitners. 11 // Remarks; it is not threadsafe. It is constant(ish) time in all ops. 12 type LinkedList[T any] struct { 13 // head is the "first" element in the list 14 head *LinkedListNode[T] 15 // tail is the "last" element in the list 16 tail *LinkedListNode[T] 17 // len is the overall length of the list 18 len int 19 } 20 21 // Len returns the length of the list in constant time. 22 func (l *LinkedList[T]) Len() int { 23 return l.len 24 } 25 26 // PushBack adds a new value to the front of the list. 27 func (l *LinkedList[T]) PushFront(value T) *LinkedListNode[T] { 28 item := &LinkedListNode[T]{Value: value} 29 l.len++ 30 if l.head == nil { 31 l.head = item 32 l.tail = item 33 return item 34 } 35 36 l.head.Previous = item 37 item.Next = l.head 38 item.Previous = nil 39 l.head = item 40 return item 41 } 42 43 // Push appends a node to the end, or tail, of the list. 44 func (l *LinkedList[T]) Push(value T) *LinkedListNode[T] { 45 item := &LinkedListNode[T]{ 46 Value: value, 47 } 48 49 l.len++ 50 if l.head == nil { 51 l.head = item 52 l.tail = item 53 return item 54 } 55 56 l.tail.Next = item 57 item.Previous = l.tail 58 item.Next = nil 59 l.tail = item 60 return item 61 } 62 63 // Pop removes the head element from the list. 64 func (l *LinkedList[T]) Pop() (out T, ok bool) { 65 if l.head == nil { 66 return 67 } 68 69 out = l.head.Value 70 ok = true 71 72 l.len-- 73 if l.head == l.tail { 74 l.head = nil 75 l.tail = nil 76 return 77 } 78 79 next := l.head.Next 80 next.Previous = nil 81 l.head = next 82 return 83 } 84 85 // PopBack removes the last, or tail, element of the list. 86 func (l *LinkedList[T]) PopBack() (out T, ok bool) { 87 if l.tail == nil { 88 return 89 } 90 91 out = l.tail.Value 92 ok = true 93 94 l.len-- 95 if l.tail == l.head { 96 l.head = nil 97 l.tail = nil 98 return 99 } 100 101 previous := l.tail.Previous 102 previous.Next = nil 103 l.tail = previous 104 return 105 } 106 107 // PopAll removes all the elements, returning a slice. 108 func (l *LinkedList[T]) PopAll() (output []T) { 109 ptr := l.head 110 for ptr != nil { 111 output = append(output, ptr.Value) 112 ptr = ptr.Next 113 } 114 l.head = nil 115 l.tail = nil 116 l.len = 0 117 return 118 } 119 120 // Peek returns the first element of the list but does not remove it. 121 func (q *LinkedList[T]) Peek() (out T, ok bool) { 122 if q.head == nil { 123 return 124 } 125 out = q.head.Value 126 ok = true 127 return 128 } 129 130 // PeekBack returns the last element of the list. 131 func (q *LinkedList[T]) PeekBack() (out T, ok bool) { 132 if q.tail == nil { 133 return 134 } 135 out = q.tail.Value 136 ok = true 137 return 138 } 139 140 // Clear clears the linked list. 141 func (l *LinkedList[T]) Clear() { 142 l.tail = nil 143 l.head = nil 144 l.len = 0 145 } 146 147 // Each calls the consumer for each element of the linked list. 148 func (q *LinkedList[T]) Each(consumer func(value T)) { 149 if q.head == nil { 150 return 151 } 152 153 nodePtr := q.head 154 for nodePtr != nil { 155 consumer(nodePtr.Value) 156 nodePtr = nodePtr.Next 157 } 158 } 159 160 func (l *LinkedList[T]) Remove(i *LinkedListNode[T]) { 161 l.len-- 162 163 // three possibilities 164 // - i is both the head and the tail 165 // - nil out both 166 // - i is the head 167 // - set the head to i's next 168 // - i is the tail 169 // - set the tail to i's previous 170 // - i is neither 171 // - if i has a next, set its previous to i's previous 172 // - if i has a previous, set its previous to i's next 173 174 if l.head == i && l.tail == i { 175 l.head = nil 176 l.tail = nil 177 return 178 } 179 if l.head == i { 180 l.head = i.Next 181 return 182 } 183 if l.tail == i { 184 l.tail = i.Previous 185 return 186 } 187 188 next := i.Next 189 if next != nil { 190 next.Previous = i.Previous 191 } 192 previous := i.Previous 193 if previous != nil { 194 previous.Next = i.Next 195 } 196 } 197 198 // LinkedListNode is a linked list node. 199 type LinkedListNode[T any] struct { 200 // Value holds the value of the node. 201 Value T 202 // Next points towards the tail. 203 Next *LinkedListNode[T] 204 // Previous points towards the head. 205 Previous *LinkedListNode[T] 206 }