Repository: JuliaCollections/DataStructures.jl
Pull request #736 (2021-04-28 15:12:13)

Circ buff new constructor
Adds constructors to Circular Buffer allowing a vector or other iterable to be in the buffer once initialized. Capacity is still required to be provided by the user and errors if the given capacity is less than the length of the given iterable. If no type parameter is given the eltype of the provided iterable is used. If one is provided the provided iterable is converted to that type (if possible, errors otherwise).

Existing constructors have changed slightly via new type restrictions.

Allows:
`CircularBuffer(1:5,10)`
`CircularBuffer{Float64}([1,2],100)`
`CircularBuffer((1,2.0,"hi"),20)`


Patch:
diff --git a/src/circular_buffer.jl b/src/circular_buffer.jl
index 3d991cd..b5fcaad 100644
--- a/src/circular_buffer.jl
+++ b/src/circular_buffer.jl
@@ -1,11 +1,12 @@
 """
-    CircularBuffer{T}(n)
+    CircularBuffer{T}(v,n::Int)
 
 The CircularBuffer type implements a circular buffer of fixed capacity
 where new items are pushed to the back of the list, overwriting values
 in a circular fashion.
 
-Allocate a buffer of elements of type `T` with maximum capacity `n`.
+Allocate a buffer of elements of type `T`  containing items `v` with maximum capacity `n`.
+If no capacity is provided the capacity is the number of elements in `v`
 """
 mutable struct CircularBuffer{T} <: AbstractVector{T}
     capacity::Int
@@ -13,10 +14,30 @@ mutable struct CircularBuffer{T} <: AbstractVector{T}
     length::Int
     buffer::Vector{T}
 
-    CircularBuffer{T}(capacity::Int) where {T} = new{T}(capacity, 1, 0, Vector{T}(undef, capacity))
+    function CircularBuffer{T}(f,len,buf) where {T}
+        f <= length(buf) || throw(ArgumentError("Value of 'first' must be inbounds of buffer"))
+        len <= length(buf) || throw(ArgumentError("Value of 'length' must be <= length of buffer"))
+        return new{T}(length(buf), f, len, buf)
+    end
+end
+
+function CircularBuffer{T}(iter, capacity::Int) where {T}
+    vec = copyto!(Vector{T}(undef,capacity), iter)
+    CircularBuffer{T}(1, length(iter),vec)
+end
+
+CircularBuffer(capacity::Int) = CircularBuffer{Any}(capacity)
+
+CircularBuffer{T}(capacity::Int) where {T} = CircularBuffer{T}(T[],capacity)
+
+CircularBuffer(iter,capacity::Int) =  CircularBuffer{eltype(iter)}(iter,capacity)
+
+function CircularBuffer{T}(iter) where {T}
+  vec = reshape(collect(T,iter),:) 
+  CircularBuffer{T}(1, length(vec), vec)
 end
 
-CircularBuffer(capacity) = CircularBuffer{Any}(capacity)
+CircularBuffer(iter) = CircularBuffer{eltype(iter)}(iter)
 
 """
     empty!(cb::CircularBuffer)


Test patch:
diff --git a/test/test_circular_buffer.jl b/test/test_circular_buffer.jl
index 3064c0d..ee99547 100644
--- a/test/test_circular_buffer.jl
+++ b/test/test_circular_buffer.jl
@@ -50,10 +50,42 @@
         end
     end
 
-    @testset "other constructor" begin
-        cb = CircularBuffer(10)
-        @test length(cb) == 0
-        @test typeof(cb) <: CircularBuffer{Any}
+    @testset "other constructors" begin
+        @testset "internal constructor" begin
+            @test_throws ArgumentError CircularBuffer{Int64}(6,0,Vector{Int64}(undef,5))
+            @test_throws ArgumentError CircularBuffer{Int64}(1,6,Vector{Int64}(undef,5))
+        end
+        @testset "capacity only" begin
+            cb = CircularBuffer(10)
+            @test length(cb) == 0
+            @test typeof(cb) <: CircularBuffer{Any}
+        end
+        @testset "from vec inferred type with capacity" begin
+            cb = CircularBuffer(1:5,10)
+            @test length(cb) == 5
+            @test typeof(cb) == CircularBuffer{Int}
+        end
+        @testset "from vec given type with capacity" begin
+            cb = CircularBuffer{Float64}(1:5,10)
+            @test length(cb) == 5
+            @test typeof(cb) == CircularBuffer{Float64}
+            @test collect(cb) == [1.0,2.0,3.0,4.0,5.0]
+        end
+        @testset "inferred capacity given type" begin
+            cb = CircularBuffer{Float64}(1:5)
+            @test length(cb) == 5
+            @test typeof(cb) == CircularBuffer{Float64}
+            @test collect(cb) == [1.0,2.0,3.0,4.0,5.0]
+            @test capacity(cb) == 5
+        end
+        @testset "inferred capacity inferred type" begin
+            cb = CircularBuffer(1:5)
+            @test length(cb) == 5
+            @test typeof(cb) == CircularBuffer{Int}
+            @test collect(cb) == [1,2,3,4,5]
+            @test capacity(cb) == 5
+        end
+
     end
 
     @testset "pushfirst" begin