github.com/andy2046/gopie@v0.7.0/pkg/dll/dll.go (about) 1 // Package dll provides a lock-free implementation of doubly linked list. 2 package dll 3 4 type ( 5 // List represents a doubly linked list. 6 List struct { 7 head *Element 8 tail *Element 9 } 10 11 // Element is an element of a linked list. 12 Element struct { 13 // Next and previous pointers in the doubly-linked list of elements. 14 next, prev *atomicMarkableReference 15 16 // The value stored with this element. 17 Value interface{} 18 } 19 ) 20 21 // New returns an initialized list. 22 func New() *List { return new(List).Init() } 23 24 // Init initializes or clears list l. 25 func (l *List) Init() *List { 26 l.head = &Element{ 27 prev: newAtomicMarkableReference(nil, false), 28 next: newAtomicMarkableReference(nil, false), 29 } 30 l.tail = &Element{ 31 prev: newAtomicMarkableReference(nil, false), 32 next: newAtomicMarkableReference(nil, false), 33 } 34 35 l.head.next.compareAndSet(nil, l.tail, false, false) 36 l.tail.prev.compareAndSet(nil, l.head, false, false) 37 38 return l 39 } 40 41 // Empty returns true if list l is empty, false otherwise 42 func (l *List) Empty() bool { 43 t := l.head.next.getReference() 44 h := l.tail.prev.getReference() 45 46 if t == l.tail && h == l.head { 47 return true 48 } 49 50 return false 51 } 52 53 // Remove removes e from l if e is an element of list l. 54 // It returns the element value e.Value if succeed, nil otherwise 55 func (l *List) Remove(e *Element) interface{} { 56 node := e 57 if node == nil { 58 return nil 59 } 60 61 if node == l.tail || node == l.head { 62 return nil 63 } 64 65 for { 66 removed, nodeNext := node.next.get() 67 if removed { 68 return nil 69 } 70 if node.next.compareAndSet(nodeNext, nodeNext, false, true) { 71 for { 72 removed2, nodePrev := node.prev.get() 73 if removed2 || node.prev.compareAndSet(nodePrev, nodePrev, false, true) { 74 break 75 } 76 } 77 78 l.correctPrev(node.prev.getReference(), nodeNext) 79 return node.Value 80 } 81 } 82 } 83 84 func (l *List) correctPrev(prev, node *Element) *Element { 85 var lastLink *Element 86 87 for { 88 removed, link1 := node.prev.get() 89 if removed { 90 break 91 } 92 removed2, prevNext := prev.next.get() 93 if removed2 { 94 if lastLink != nil { 95 setMark(prev.prev) 96 lastLink.next.compareAndSet(prev, prevNext, false, false) 97 prev = lastLink 98 lastLink = nil 99 continue 100 } 101 prevNext = prev.prev.getReference() 102 prev = prevNext 103 continue 104 } 105 106 if prevNext != node { 107 lastLink = prev 108 prev = prevNext 109 continue 110 } 111 112 if node.prev.compareAndSet(link1, prev, removed, false) { 113 if prev.prev.isMarked() { 114 continue 115 } 116 break 117 } 118 } 119 120 return prev 121 } 122 123 func setMark(node *atomicMarkableReference) { 124 for { 125 removed, link := node.get() 126 if removed || node.compareAndSet(link, link, false, true) { 127 break 128 } 129 } 130 } 131 132 // PopLeft returns the first element of list l or nil if the list is empty. 133 func (l *List) PopLeft() interface{} { 134 prev := l.head 135 136 for { 137 node := prev.next.getReference() 138 // deque is empty 139 if node == l.tail { 140 return nil 141 } 142 143 removed, nodeNext := node.next.get() 144 // concurrent pop started to delete this node, help it, then continue 145 if removed { 146 helpDelete(node, "help concurrent") 147 continue 148 } 149 150 // 1 pop step 151 if node.next.compareAndSet(nodeNext, nodeNext, false, true) { 152 // 2, 3 step 153 helpDelete(node, "1st step") 154 next := node.next.getReference() 155 // 4 step 156 helpInsert(prev, next, "popLeft New") 157 158 return node.Value 159 } 160 } 161 } 162 163 // PopRight returns the last element of list l or nil if the list is empty. 164 func (l *List) PopRight() interface{} { 165 next := l.tail 166 node := next.prev.getReference() 167 168 for { 169 if !node.next.compareAndSet(next, next, false, false) { 170 node = helpInsert(node, next, "popRight") 171 continue 172 } 173 174 if node == l.head { 175 return nil 176 } 177 178 if node.next.compareAndSet(next, next, false, true) { 179 helpDelete(node, "") 180 prev := node.prev.getReference() 181 helpInsert(prev, next, "popRight") 182 183 return node.Value 184 } 185 } 186 } 187 188 // PushLeft inserts a new element e with value v at the front of list l and returns e. 189 func (l *List) PushLeft(v interface{}) *Element { 190 node := &Element{Value: v} 191 prev := l.head 192 next := prev.next.getReference() 193 194 for { 195 if !prev.next.compareAndSet(next, next, false, false) { 196 next = prev.next.getReference() 197 continue 198 } 199 200 node.prev = newAtomicMarkableReference(prev, false) 201 node.next = newAtomicMarkableReference(next, false) 202 203 if prev.next.compareAndSet(next, node, false, false) { 204 break 205 } 206 } 207 208 pushCommon(node, next) 209 210 return node 211 } 212 213 // PushRight inserts a new element e with value v at the back of list l and returns e. 214 func (l *List) PushRight(v interface{}) *Element { 215 node := &Element{Value: v} 216 next := l.tail 217 prev := next.prev.getReference() 218 219 for { 220 if !prev.next.compareAndSet(next, next, false, false) { 221 // concurrent push inserted -> get new prev 222 prev = helpInsert(prev, next, "concurrentPushRight") 223 continue 224 } 225 226 // 0 push step 227 node.prev = newAtomicMarkableReference(prev, false) 228 node.next = newAtomicMarkableReference(next, false) 229 // 1 push step 230 if prev.next.compareAndSet(next, node, false, false) { 231 break 232 } 233 } 234 235 // 2 push step 236 pushCommon(node, next) 237 238 return node 239 } 240 241 func pushCommon(node, next *Element) { 242 for { 243 link1 := next.prev 244 if link1.isMarked() || !node.next.compareAndSet(next, next, false, false) { 245 break 246 } 247 248 if next.prev.compareAndSet(link1.getReference(), node, false, false) { 249 if node.prev.isMarked() { 250 helpInsert(node, next, "pushCommon") 251 } 252 break 253 } 254 } 255 } 256 257 // Next returns the next list element or nil. 258 func (l *List) Next(node *Element) *Element { 259 for node != l.tail { 260 if node == nil { 261 break 262 } 263 264 next := node.next.getReference() 265 if next == nil { 266 break 267 } 268 269 removed, nextNext := next.next.get() 270 if removed { 271 // The next pointer of the node behind me has the deleted mark set 272 removed2, nodeNext := node.next.get() 273 if !removed2 || nodeNext != next { 274 setMark(next.prev) 275 node.next.compareAndSet(next, nextNext, false, false) // next removed == false? 276 continue 277 } 278 } 279 280 node = next 281 282 if !removed { 283 return next 284 } 285 } 286 287 return nil 288 } 289 290 // Prev returns the previous list element or nil. 291 func (l *List) Prev(node *Element) *Element { 292 for node != l.head { 293 if node == nil { 294 break 295 } 296 297 prev := node.prev.getReference() 298 if prev == nil { 299 break 300 } 301 302 prevNext := prev.next.getReference() 303 removed := node.next.isMarked() 304 305 if prevNext == node && !removed { 306 return prev 307 } else if removed { 308 node = l.Next(node) 309 } else { 310 prev = l.correctPrev(prev, node) 311 } 312 } 313 314 return nil 315 } 316 317 /** 318 * Correct node.prev to the closest previous node 319 * helpInsert is very weak - does not reset node.prev to the actual prev.next 320 * but just tries to set node.prev to the given suggestion of a prev node 321 * (for 2 push step, 4 pop step) 322 */ 323 func helpInsert(prev *Element, node *Element, method string) *Element { 324 // last = is the last node : last.next == prev and it is not marked as removed 325 var last, nodePrev *Element 326 327 for { 328 removed, prevNext := prev.next.get() 329 330 if removed { 331 if last != nil { 332 markPrev(prev) 333 next2 := prev.next.getReference() 334 last.next.compareAndSet(prev, next2, false, false) 335 prev = last 336 last = nil 337 } else { 338 prevNext = prev.prev.getReference() 339 prev = prevNext 340 } 341 continue 342 } 343 344 removed, nodePrev = node.prev.get() 345 if removed { 346 break 347 } 348 349 // prev is not the previous node of node 350 if prevNext != node { 351 last = prev 352 prev = prevNext 353 continue 354 } 355 356 if nodePrev == prev { 357 break 358 } 359 360 if prev.next.getReference() == node && node.prev.compareAndSet(nodePrev, prev, false, false) { 361 if prev.prev.isMarked() { 362 continue 363 } 364 break 365 } 366 } 367 368 return prev 369 } 370 371 // 2 and 3 pop steps 372 func helpDelete(node *Element, place string) { 373 markPrev(node) 374 375 prev := node.prev.getReference() 376 next := node.next.getReference() 377 var last *Element 378 379 for { 380 if prev == next { 381 break 382 } 383 384 if next.next.isMarked() { 385 markPrev(next) 386 next = next.next.getReference() 387 continue 388 } 389 390 removed, prevNext := prev.next.get() 391 if removed { 392 if last != nil { 393 markPrev(prev) 394 next2 := prev.next.getReference() 395 last.next.compareAndSet(prev, next2, false, false) 396 prev = last 397 last = nil 398 } else { 399 prevNext = prev.prev.getReference() 400 prev = prevNext 401 // assert(prev != nil) 402 } 403 continue 404 } 405 406 if prevNext != node { 407 last = prev 408 prev = prevNext 409 continue 410 } 411 412 if prev.next.compareAndSet(node, next, false, false) { 413 break 414 } 415 } 416 } 417 418 func markPrev(node *Element) { 419 for { 420 link1 := node.prev 421 if link1.isMarked() || 422 node.prev.compareAndSet(link1.getReference(), link1.getReference(), false, true) { 423 break 424 } 425 } 426 }