-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathlifo.go
55 lines (45 loc) · 1.17 KB
/
lifo.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package cqueue
import (
"sync/atomic"
)
// atomicLIFONode represents a single element in the LIFO.
type atomicLIFONode[T any] struct {
value T
next *atomicLIFONode[T]
}
// AtomicLIFO implements an atomic last-in-first-out linked-list.
type AtomicLIFO[T any] struct {
top atomic.Pointer[atomicLIFONode[T]]
}
// Push atomically adds a value to the top of the LIFO.
func (q *AtomicLIFO[T]) Push(value T) {
newNode := &atomicLIFONode[T]{value: value}
for {
// Read the current top.
oldTop := q.top.Load()
// Set the next of the new atomicLIFONode to the current top.
newNode.next = oldTop
// Try to set the new atomicLIFONode as the new top.
if q.top.CompareAndSwap(oldTop, newNode) {
break
}
}
}
// Pop atomically removes and returns the top value of the LIFO.
// It returns the zero value (nil) if the LIFO is empty.
func (q *AtomicLIFO[T]) Pop() T {
for {
// Read the current top.
oldTop := q.top.Load()
if oldTop == nil {
var empty T
return empty
}
// Read the next atomicLIFONode after the top.
next := oldTop.next
// Try to set the next atomicLIFONode as the new top.
if q.top.CompareAndSwap(oldTop, next) {
return oldTop.value
}
}
}