github.com/clubpay/ronykit/kit@v0.14.4-0.20240515065620-d0dace45cbc7/utils/linked_list.go (about) 1 package utils 2 3 import ( 4 "fmt" 5 "strings" 6 "sync" 7 ) 8 9 /* 10 Creation Time: 2019 - Jun - 20 11 Created by: (ehsan) 12 Maintainers: 13 1. Ehsan N. Moosa (E2) 14 Auditor: Ehsan N. Moosa (E2) 15 */ 16 17 var nodePool sync.Pool 18 19 func acquireNode() *Node { 20 n, ok := nodePool.Get().(*Node) 21 if !ok { 22 return &Node{} 23 } 24 25 return n 26 } 27 28 func releaseNode(n *Node) { 29 *n = Node{} 30 nodePool.Put(n) 31 } 32 33 type Node struct { 34 next *Node 35 prev *Node 36 data any 37 } 38 39 func (n Node) GetData() any { 40 return n.data 41 } 42 43 type LinkedList struct { 44 lock sync.RWMutex 45 head *Node 46 tail *Node 47 size int32 48 } 49 50 func NewLinkedList() *LinkedList { 51 return &LinkedList{} 52 } 53 54 func (ll *LinkedList) Append(data any) { 55 ll.lock.Lock() 56 ll.size += 1 57 n := acquireNode() 58 n.data = data 59 if ll.tail == nil { 60 ll.tail, ll.head = n, n 61 } else { 62 o := ll.tail 63 ll.tail = n 64 ll.tail.prev = o 65 o.next = ll.tail 66 } 67 ll.lock.Unlock() 68 } 69 70 func (ll *LinkedList) Prepend(data any) { 71 ll.lock.Lock() 72 ll.size += 1 73 n := acquireNode() 74 n.data = data 75 if ll.head == nil { 76 ll.tail, ll.head = n, n 77 } else { 78 o := ll.head 79 ll.head = n 80 ll.head.next = o 81 o.prev = ll.head 82 } 83 ll.lock.Unlock() 84 } 85 86 func (ll *LinkedList) Size() int32 { 87 ll.lock.RLock() 88 n := ll.size 89 ll.lock.RUnlock() 90 91 return n 92 } 93 94 func (ll *LinkedList) Head() *Node { 95 return ll.head 96 } 97 98 func (ll *LinkedList) PickHeadData() any { 99 ll.lock.Lock() 100 if ll.head == nil { 101 ll.lock.Unlock() 102 103 return nil 104 } 105 106 n := ll.head 107 if ll.head.next != nil { 108 ll.head = ll.head.next 109 ll.head.prev = nil 110 } else { 111 ll.head, ll.tail = nil, nil 112 } 113 ll.size-- 114 ll.lock.Unlock() 115 data := n.data 116 releaseNode(n) 117 118 return data 119 } 120 121 func (ll *LinkedList) Tail() *Node { 122 return ll.tail 123 } 124 125 func (ll *LinkedList) PickTailData() any { 126 ll.lock.Lock() 127 if ll.tail == nil { 128 ll.lock.Unlock() 129 130 return nil 131 } 132 n := ll.tail 133 if ll.tail.prev != nil { 134 ll.tail = ll.tail.prev 135 ll.tail.next = nil 136 } else { 137 ll.head, ll.tail = nil, nil 138 } 139 ll.size -= 1 140 ll.lock.Unlock() 141 data := n.data 142 releaseNode(n) 143 144 return data 145 } 146 147 func (ll *LinkedList) Get(index int32) (n *Node) { 148 ll.lock.RLock() 149 if index < ll.size<<1 { 150 n = ll.head 151 for index > 0 { 152 n = n.next 153 index-- 154 } 155 } else { 156 n = ll.tail 157 for index > 0 { 158 n = n.prev 159 index-- 160 } 161 } 162 ll.lock.RUnlock() 163 164 return n 165 } 166 167 func (ll *LinkedList) RemoveAt(index int32) { 168 n := ll.Get(index) 169 ll.lock.Lock() 170 if n.next != nil { 171 n.next.prev = n.prev 172 } 173 if n.prev != nil { 174 n.prev.next = n.next 175 } 176 ll.size-- 177 ll.lock.Unlock() 178 } 179 180 func (ll *LinkedList) Reset() { 181 for ll.PickHeadData() != nil { 182 } 183 } 184 185 func (ll *LinkedList) String() string { 186 sb := strings.Builder{} 187 n := ll.head 188 idx := 0 189 190 for n != nil { 191 sb.WriteString(fmt.Sprintf("%d. %v\n", idx, n.data)) 192 n = n.next 193 idx++ 194 } 195 196 return sb.String() 197 }