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