github.com/blend/go-sdk@v1.20240719.1/collections/linked_list.go (about) 1 /* 2 3 Copyright (c) 2024 - Present. Blend Labs, Inc. All rights reserved 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file. 5 6 */ 7 8 package collections 9 10 // NewLinkedList returns a new linked list instance. 11 func NewLinkedList[T any]() *LinkedList[T] { 12 return &LinkedList[T]{} 13 } 14 15 // NewLinkedListFromValues creates a linked list out of a slice. 16 func NewLinkedListFromValues[T any](values []T) *LinkedList[T] { 17 list := new(LinkedList[T]) 18 for _, v := range values { 19 list.Enqueue(v) 20 } 21 return list 22 } 23 24 // LinkedList is an implementation of a fifo buffer using nodes and pointers. 25 // Remarks; it is not thread safe. It is constant(ish) time in all ops. 26 type LinkedList[T any] struct { 27 head *listNode[T] 28 tail *listNode[T] 29 length int 30 } 31 32 // Len returns the length of the queue in constant time. 33 func (q *LinkedList[T]) Len() int { 34 return q.length 35 } 36 37 // Enqueue adds a new value to the queue. 38 func (q *LinkedList[T]) Enqueue(value T) { 39 node := &listNode[T]{Value: value} 40 41 if q.head == nil { // the queue is empty, that is to say head is nil 42 q.head = node 43 q.tail = node 44 } else { // the queue is not empty, we have a (valid) tail pointer 45 q.tail.Previous = node 46 node.Next = q.tail 47 q.tail = node 48 } 49 50 q.length++ 51 } 52 53 // Dequeue removes an item from the front of the queue and returns it. 54 func (q *LinkedList[T]) Dequeue() T { 55 var res T 56 if q.head == nil { 57 return res 58 } 59 60 headValue := q.head.Value 61 62 if q.length == 1 && q.head == q.tail { 63 q.head = nil 64 q.tail = nil 65 } else { 66 q.head = q.head.Previous 67 if q.head != nil { 68 q.head.Next = nil 69 } 70 } 71 72 q.length-- 73 return headValue 74 } 75 76 // DequeueBack pops the _last_ element off the linked list. 77 func (q *LinkedList[T]) DequeueBack() T { 78 var res T 79 if q.tail == nil { 80 return res 81 } 82 tailValue := q.tail.Value 83 84 if q.length == 1 { 85 q.head = nil 86 q.tail = nil 87 } else { 88 q.tail = q.tail.Next 89 if q.tail != nil { 90 q.tail.Previous = nil 91 } 92 } 93 94 q.length-- 95 return tailValue 96 } 97 98 // Peek returns the first element of the queue but does not remove it. 99 func (q *LinkedList[T]) Peek() T { 100 var res T 101 if q.head == nil { 102 return res 103 } 104 return q.head.Value 105 } 106 107 // PeekBack returns the last element of the queue. 108 func (q *LinkedList[T]) PeekBack() T { 109 var res T 110 if q.tail == nil { 111 return res 112 } 113 return q.tail.Value 114 } 115 116 // Clear clears the linked list. 117 func (q *LinkedList[T]) Clear() { 118 q.tail = nil 119 q.head = nil 120 q.length = 0 121 } 122 123 // Drain calls the consumer for each element of the linked list. 124 func (q *LinkedList[T]) Drain() []T { 125 if q.head == nil { 126 return nil 127 } 128 129 contents := make([]T, q.length) 130 nodePtr := q.head 131 index := 0 132 for nodePtr != nil { 133 contents[index] = nodePtr.Value 134 nodePtr = nodePtr.Previous 135 index++ 136 } 137 q.tail = nil 138 q.head = nil 139 q.length = 0 140 return contents 141 } 142 143 // Each calls the consumer for each element of the linked list. 144 func (q *LinkedList[T]) Each(consumer func(value T)) { 145 if q.head == nil { 146 return 147 } 148 149 nodePtr := q.head 150 for nodePtr != nil { 151 consumer(nodePtr.Value) 152 nodePtr = nodePtr.Previous 153 } 154 } 155 156 // Consume calls the consumer for each element of the linked list, removing it. 157 func (q *LinkedList[T]) Consume(consumer func(value T)) { 158 if q.head == nil { 159 return 160 } 161 162 nodePtr := q.head 163 for nodePtr != nil { 164 consumer(nodePtr.Value) 165 nodePtr = nodePtr.Previous 166 } 167 q.tail = nil 168 q.head = nil 169 q.length = 0 170 } 171 172 // EachUntil calls the consumer for each element of the linked list, but can abort. 173 func (q *LinkedList[T]) EachUntil(consumer func(value T) bool) { 174 if q.head == nil { 175 return 176 } 177 178 nodePtr := q.head 179 for nodePtr != nil { 180 if !consumer(nodePtr.Value) { 181 return 182 } 183 nodePtr = nodePtr.Previous 184 } 185 } 186 187 // ReverseEachUntil calls the consumer for each element of the linked list, but can abort. 188 func (q *LinkedList[T]) ReverseEachUntil(consumer func(value T) bool) { 189 if q.head == nil { 190 return 191 } 192 193 nodePtr := q.tail 194 for nodePtr != nil { 195 if !consumer(nodePtr.Value) { 196 return 197 } 198 nodePtr = nodePtr.Next 199 } 200 } 201 202 // Contents returns the full contents of the queue as a slice. 203 func (q *LinkedList[T]) Contents() []T { 204 if q.head == nil { 205 return nil 206 } 207 208 var values []T 209 nodePtr := q.head 210 for nodePtr != nil { 211 values = append(values, nodePtr.Value) 212 nodePtr = nodePtr.Previous 213 } 214 return values 215 } 216 217 type listNode[T any] struct { 218 Next *listNode[T] 219 Previous *listNode[T] 220 Value T 221 }