-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathCircularBuffer.swift
93 lines (80 loc) · 2.36 KB
/
CircularBuffer.swift
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
//
// CircularBuffer.swift
//
// Advent of Code tools
//
/// Circular buffer of unlimited size
/// Keeps track of a "current" position which can be moved forwards/clockwise or backwards/counterclockwise
public class CircularBuffer<T> {
private class Node {
let value: T
var next: Node?
var prev: Node?
init(value: T) {
self.value = value
self.next = nil
self.prev = nil
}
}
private var current: Node?
public init() {}
deinit {
var n: Node? = current
while n != nil {
let next = n?.next
n?.prev = nil
n?.next = nil
n = next
}
}
public var isEmpty: Bool { current == nil }
public private(set) var count = 0
/// Add a new value just after the current position,
/// moves the current position to the newly added node
public func insert(value: T) {
let node = Node(value: value)
if current == nil {
current = node
node.next = current
node.prev = current
} else {
node.next = current?.next
node.prev = current
current?.next?.prev = node
current?.next = node
current = node
}
count += 1
}
/// Remove the current node and return its value. It is an error to call this method on an empty CircularBuffer
@discardableResult
public func remove() -> T {
count -= 1
let node = current
// swiftlint:disable:next empty_count
if count == 0 {
current = nil
} else {
current?.prev?.next = current?.next
current?.next?.prev = current?.prev
current = node?.prev
}
node?.prev = nil
node?.next = nil
return node!.value
}
/// move the "current" node forward/clockwise (positive values of `step`) or backwards/counterclockwise (negative values)
public func moveCurrent(by steps: Int) {
for _ in 0..<abs(steps) {
if steps > 0 {
current = current?.next
} else {
current = current?.prev
}
}
}
/// return the value of the "current" node. It is an error to call this method on an empty CircularBuffer
public func value() -> T {
current!.value
}
}