-
Notifications
You must be signed in to change notification settings - Fork 253
/
Copy pathcircular_buffer.jl
76 lines (66 loc) · 1.92 KB
/
circular_buffer.jl
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
"""
New items are pushed to the back of the list, overwriting values in a circular fashion.
"""
mutable struct CircularBuffer{T} <: AbstractVector{T}
capacity::Int
first::Int
buffer::Vector{T}
CircularBuffer{T}(capacity::Int) where {T} = new{T}(capacity, 1, T[])
end
function Base.empty!(cb::CircularBuffer)
cb.first = 1
empty!(cb.buffer)
end
function _buffer_index(cb::CircularBuffer, i::Int)
n = length(cb)
if i < 1 || i > n
throw(BoundsError("CircularBuffer out of range. cb=$cb i=$i"))
end
idx = cb.first + i - 1
if idx > n
idx - n
else
idx
end
end
function Base.getindex(cb::CircularBuffer, i::Int)
cb.buffer[_buffer_index(cb, i)]
end
function Base.setindex!(cb::CircularBuffer, data, i::Int)
cb.buffer[_buffer_index(cb, i)] = data
cb
end
function Base.push!(cb::CircularBuffer, data)
# if full, increment and overwrite, otherwise push
if length(cb) == cb.capacity
cb.first = (cb.first == cb.capacity ? 1 : cb.first + 1)
cb[length(cb)] = data
else
push!(cb.buffer, data)
end
cb
end
function Base.unshift!(cb::CircularBuffer, data)
# if full, decrement and overwrite, otherwise unshift
if length(cb) == cb.capacity
cb.first = (cb.first == 1 ? cb.capacity : cb.first - 1)
cb[1] = data
else
unshift!(cb.buffer, data)
end
cb
end
function Base.append!(cb::CircularBuffer, datavec::AbstractVector)
# push at most last `capacity` items
n = length(datavec)
for i in max(1, n-capacity(cb)+1):n
push!(cb, datavec[i])
end
cb
end
Base.length(cb::CircularBuffer) = length(cb.buffer)
Base.size(cb::CircularBuffer) = (length(cb),)
Base.convert(::Type{Array}, cb::CircularBuffer{T}) where {T} = T[x for x in cb]
Base.isempty(cb::CircularBuffer) = isempty(cb.buffer)
capacity(cb::CircularBuffer) = cb.capacity
isfull(cb::CircularBuffer) = length(cb) == cb.capacity