-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathlinkedlist.go
123 lines (111 loc) · 2.42 KB
/
linkedlist.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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package linkedlist
import "sync"
// LinkedList implements a pointer-linked list with a head and tail.
//
// The empty value is a valid empty linked list.
type LinkedList[T any] struct {
// mtx guards below fields
mtx sync.RWMutex
// head is the current head elem
// least-recently-added
head *linkedListElem[T]
// tail is the current tail item
// most-recently-added
tail *linkedListElem[T]
}
// linkedListElem is an elem in the linked list.
type linkedListElem[T any] struct {
// next is the next element in the list
next *linkedListElem[T]
// val is the value
val T
}
// NewLinkedList constructs a new LinkedList.
func NewLinkedList[T any](elems ...T) *LinkedList[T] {
ll := &LinkedList[T]{}
for _, elem := range elems {
ll.pushElem(elem)
}
return ll
}
// Push pushes a value to the end of the linked list.
func (l *LinkedList[T]) Push(val T) {
l.mtx.Lock()
l.pushElem(val)
l.mtx.Unlock()
}
// PushFront pushes a value to the front of the linked list.
// It will be returned next for Pop or Peek.
func (l *LinkedList[T]) PushFront(val T) {
l.mtx.Lock()
elem := &linkedListElem[T]{val: val}
if l.head != nil {
elem.next = l.head
} else {
l.tail = elem
}
l.head = elem
l.mtx.Unlock()
}
// Peek peeks the head of the linked list.
func (l *LinkedList[T]) Peek() (T, bool) {
l.mtx.Lock()
var val T
exists := l.head != nil
if exists {
val = l.head.val
}
l.mtx.Unlock()
return val, exists
}
// IsEmpty checks if the linked list is empty.
func (l *LinkedList[T]) IsEmpty() bool {
l.mtx.Lock()
empty := l.head == nil
l.mtx.Unlock()
return empty
}
// PeekTail peeks the tail of the linked list.
func (l *LinkedList[T]) PeekTail() (T, bool) {
l.mtx.Lock()
var val T
exists := l.tail != nil
if exists {
val = l.tail.val
}
l.mtx.Unlock()
return val, exists
}
// Pop dequeues the head of the linked list.
func (l *LinkedList[T]) Pop() (T, bool) {
l.mtx.Lock()
var val T
exists := l.head != nil
if exists {
val = l.head.val
if l.head.next != nil {
l.head = l.head.next
} else {
l.head = nil
l.tail = nil
}
}
l.mtx.Unlock()
return val, exists
}
// Reset clears the linked list.
func (l *LinkedList[T]) Reset() {
l.mtx.Lock()
l.head, l.tail = nil, nil
l.mtx.Unlock()
}
// pushElem pushes an element to the list while mtx is locked.
func (l *LinkedList[T]) pushElem(val T) {
elem := &linkedListElem[T]{val: val}
if l.tail == nil {
l.head = elem
} else {
l.tail.next = elem
}
l.tail = elem
}