This repository has been archived by the owner on Jun 18, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 14
/
queue.go
executable file
·98 lines (86 loc) · 2.75 KB
/
queue.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
// CookieJar - A contestant's algorithm toolbox
// Copyright (c) 2013 Peter Szilagyi. All rights reserved.
//
// CookieJar is dual licensed: use of this source code is governed by a BSD
// license that can be found in the LICENSE file. Alternatively, the CookieJar
// toolbox may be used in accordance with the terms and conditions contained
// in a signed written agreement between you and the author(s).
// Package queue implements a FIFO (first in first out) data structure supporting
// arbitrary types (even a mixture).
//
// Internally it uses a dynamically growing circular slice of blocks, resulting
// in faster resizes than a simple dynamic array/slice would allow.
package queue
// The size of a block of data
const blockSize = 4096
// First in, first out data structure.
type Queue struct {
tailIdx int
headIdx int
tailOff int
headOff int
blocks [][]interface{}
head []interface{}
tail []interface{}
}
// Creates a new, empty queue.
func New() *Queue {
result := new(Queue)
result.blocks = [][]interface{}{make([]interface{}, blockSize)}
result.head = result.blocks[0]
result.tail = result.blocks[0]
return result
}
// Pushes a new element into the queue, expanding it if necessary.
func (q *Queue) Push(data interface{}) {
q.tail[q.tailOff] = data
q.tailOff++
if q.tailOff == blockSize {
q.tailOff = 0
q.tailIdx = (q.tailIdx + 1) % len(q.blocks)
// If we wrapped over to the end, insert a new block and update indices
if q.tailIdx == q.headIdx {
buffer := make([][]interface{}, len(q.blocks)+1)
copy(buffer[:q.tailIdx], q.blocks[:q.tailIdx])
buffer[q.tailIdx] = make([]interface{}, blockSize)
copy(buffer[q.tailIdx+1:], q.blocks[q.tailIdx:])
q.blocks = buffer
q.headIdx++
q.head = q.blocks[q.headIdx]
}
q.tail = q.blocks[q.tailIdx]
}
}
// Pops out an element from the queue. Note, no bounds checking are done.
func (q *Queue) Pop() (res interface{}) {
res, q.head[q.headOff] = q.head[q.headOff], nil
q.headOff++
if q.headOff == blockSize {
q.headOff = 0
q.headIdx = (q.headIdx + 1) % len(q.blocks)
q.head = q.blocks[q.headIdx]
}
return
}
// Returns the first element in the queue. Note, no bounds checking are done.
func (q *Queue) Front() interface{} {
return q.head[q.headOff]
}
// Checks whether the queue is empty.
func (q *Queue) Empty() bool {
return q.headIdx == q.tailIdx && q.headOff == q.tailOff
}
// Returns the number of elements in the queue.
func (q *Queue) Size() int {
if q.tailIdx > q.headIdx {
return (q.tailIdx-q.headIdx)*blockSize - q.headOff + q.tailOff
} else if q.tailIdx < q.headIdx {
return (len(q.blocks)-q.headIdx+q.tailIdx)*blockSize - q.headOff + q.tailOff
} else {
return q.tailOff - q.headOff
}
}
// Clears out the contents of the queue.
func (q *Queue) Reset() {
*q = *New()
}