-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathqueue.go
More file actions
156 lines (143 loc) · 3.12 KB
/
queue.go
File metadata and controls
156 lines (143 loc) · 3.12 KB
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package incr
const (
queueDefaultCapacity = 4
)
// queue implements a fifo buffer datastructure using a ringbuffer.
//
// Typically you would see queue's implemented with a linked list, but in
// garbage collected languages there are advantages to keeping an array of items
// live to prevent excess allocations which makes a ringbuffer faster in practice.
type queue[A any] struct {
array []A
head int
tail int
size int
}
// len returns the number of items in the queue.
func (q *queue[A]) len() int {
return q.size
}
// cap is the full size of the ringbuffer's backing
// array (which is typically more in practice than
// the queue's actual length).
func (q *queue[A]) cap() int {
return len(q.array)
}
// clear empties the queue, but does not reclaim any
// allocated space.
//
// to resize the queue to a smaller size, you can use
// the `setCapacity(...)` function.
func (q *queue[A]) clear() {
clear(q.array)
q.head = 0
q.tail = 0
q.size = 0
}
func (q *queue[A]) push(v A) {
if len(q.array) == 0 {
q.array = make([]A, queueDefaultCapacity)
} else if q.size == len(q.array) {
q.setCapacity(len(q.array) << 1)
}
q.array[q.tail] = v
q.tail = (q.tail + 1) % len(q.array)
q.size++
}
func (q *queue[A]) pop() (output A, ok bool) {
if q.size == 0 {
return
}
var zero A
output = q.array[q.head]
q.array[q.head] = zero
ok = true
q.head = (q.head + 1) % len(q.array)
q.size--
return
}
func (q *queue[A]) popBack() (output A, ok bool) {
if q.size == 0 {
return
}
var zero A
if q.tail == 0 {
output = q.array[len(q.array)-1]
q.array[len(q.array)-1] = zero
q.tail = len(q.array) - 1
} else {
output = q.array[q.tail-1]
q.array[q.tail-1] = zero
q.tail = q.tail - 1
}
ok = true
q.size--
return
}
func (q *queue[A]) peek() (output A, ok bool) {
if q.size == 0 {
return
}
output = q.array[q.head]
ok = true
return
}
func (q *queue[A]) peekBack() (output A, ok bool) {
if q.size == 0 {
return
}
if q.tail == 0 {
output = q.array[len(q.array)-1]
ok = true
return
}
output = q.array[q.tail-1]
ok = true
return
}
func (q *queue[A]) values() (output []A) {
if q.size == 0 {
return
}
output = make([]A, 0, q.size)
if q.head < q.tail {
for cursor := q.head; cursor < q.tail; cursor++ {
output = append(output, q.array[cursor])
}
} else {
for cursor := q.head; cursor < len(q.array); cursor++ {
output = append(output, q.array[cursor])
}
for cursor := 0; cursor < q.tail; cursor++ {
output = append(output, q.array[cursor])
}
}
return
}
// setCapacity copies the queue into a new buffer
// with the given capacity.
//
// the new buffer will reset the head and tail
// indices such that head will be 0, and tail
// will be wherever the size index places it.
func (q *queue[A]) setCapacity(capacity int) {
newArray := make([]A, capacity)
if q.size > 0 {
if q.head < q.tail {
copy(newArray, q.array[q.head:q.head+q.size])
} else {
copy(newArray, q.array[q.head:])
copy(newArray[len(q.array)-q.head:], q.array[:q.tail])
}
}
q.array = newArray
q.head = 0
if capacity < q.size {
q.size = capacity
}
if q.size == capacity {
q.tail = 0
} else {
q.tail = q.size
}
}