I have implemented a simple circular buffer type similar to this, but with cumulative indexing, so that it has offset
field that grows each time an element is pushed back to the full buffer. (That’s why I did not used immutable OffsetArray
with its offsets
tuple).
mutable struct SlidingBuffer{T} <: AbstractVector{T}
buffer::Vector{T}
len::Int
contentLen::Int
first::Int
last::Int
offset::Int
function SlidingBuffer{T}(len::Int) where T
new{T}(Vector{T}(undef, len), len, 0, 0, 1, 0, 0)
end
end
# custom indexing
@inline Base.axes(A::SlidingBuffer) =
(UnitRange{Int}(A.offset + 1, A.offset + A.contentLen),)
# and other methods from AbstractArray interface ...
It behaves in the following way:
b = SlidingBuffer{Int}(10)
> SlidingBuffer{Int64} with indices 1:0
[push!(b, 123) for _=1:15]
b
> SlidingBuffer{Int64} with indices 6:15:
123
123
123
123
⋮
123
123
123
123
Then, I figured that I miss some similar
methods from Interfaces · The Julia Language
and maybe used UnitRange
instead of AbstractUnitRange
.
And on some operations, like b = b*3
these methods are taken from OffsetArray.jl package, automatically converting my buffer to OffsetArray
, due to this method:
Base.similar(::Type{T}, shape::Tuple{OffsetAxis,Vararg{OffsetAxis}}) where {T<:AbstractArray} =
OffsetArray(T(undef, map(indexlength, shape)), map(indexoffset, shape))
with OffsetAxis
broadly defined as:
const OffsetAxis = Union{Integer, UnitRange, Base.OneTo, IdentityUnitRange}
All these function recalls with different types are somewhat confusing. How should I write those similar
and axes
methods for my simple buffer type to not have any type inference between packages?