Repository: hyrodium/BasicBSpline.jl (julia)

Issue:
`copy(::KnotVector)` is not defined
```julia
julia> using BasicBSpline

julia> k = KnotVector(rand(5))
KnotVector([0.006113322971981083, 0.04390985165147909, 0.7172036901693241, 0.7285234235639948, 0.769119046562151])

julia> copy(k)
ERROR: MethodError: no method matching copy(::KnotVector{Float64})
Closest candidates are:
  copy(::LinearAlgebra.SymTridiagonal) at ~/julia/julia-1.8.0/share/julia/stdlib/v1.8/LinearAlgebra/src/tridiag.jl:159
  copy(::T) where T<:SHA.SHA1_CTX at ~/julia/julia-1.8.0/share/julia/stdlib/v1.8/SHA/src/types.jl:209
  copy(::Dict) at dict.jl:120
  ...
Stacktrace:
 [1] top-level scope
   @ REPL[18]:1
```

Pull request description:
This PR fixes #258.

Patch:
diff --git a/src/_EmptyKnotVector.jl b/src/_EmptyKnotVector.jl
index 3f7dc3d81..05e7e7503 100644
--- a/src/_EmptyKnotVector.jl
+++ b/src/_EmptyKnotVector.jl
@@ -29,6 +29,8 @@ Base.isempty(::EmptyKnotVector) = true
 
 _vec(::EmptyKnotVector{T}) where T = T[]
 
+Base.copy(k::EmptyKnotVector{T}) where T = k
+
 # + AbstractKnotVector
 Base.:+(k::AbstractKnotVector{T}, ::EmptyKnotVector{T}) where T<:Real = k
 function Base.:+(k::AbstractKnotVector{T1}, ::EmptyKnotVector{T2}) where {T1<:Real, T2<:Real}
diff --git a/src/_KnotVector.jl b/src/_KnotVector.jl
index 174130bee..0ed0520e1 100644
--- a/src/_KnotVector.jl
+++ b/src/_KnotVector.jl
@@ -25,6 +25,8 @@ KnotVector{T}(v::AbstractVector) where T = unsafe_knotvector(T,sort(v))
 KnotVector(v::AbstractVector{T}) where {T<:Real} = unsafe_knotvector(T,sort(v))
 AbstractKnotVector{S}(k::KnotVector{T}) where {S, T} = unsafe_knotvector(promote_type(S,T), _vec(k))
 
+Base.copy(k::KnotVector{T}) where T = unsafe_knotvector(T,copy(_vec(k)))
+
 KnotVector(k::KnotVector) = k
 KnotVector(k::AbstractKnotVector{T}) where T = unsafe_knotvector(T,_vec(k))
 KnotVector{T}(k::KnotVector{T}) where T = k
diff --git a/src/_UniformKnotVector.jl b/src/_UniformKnotVector.jl
index fc7e1c11c..faec21b54 100644
--- a/src/_UniformKnotVector.jl
+++ b/src/_UniformKnotVector.jl
@@ -29,6 +29,8 @@ Base.length(k::UniformKnotVector) = length(k.vector)
 Base.firstindex(k::UniformKnotVector) = 1
 Base.lastindex(k::UniformKnotVector) = length(k)
 
+Base.copy(k::UniformKnotVector{T}) where T = unsafe_uniformknotvector(T,copy(_vec(k)))
+
 function Base.convert(::Type{UniformKnotVector{T,R}},k::UniformKnotVector) where {T,R}
     UniformKnotVector{T,R}(k)
 end


Test patch:
diff --git a/test/test_KnotVector.jl b/test/test_KnotVector.jl
index 771791026..3fd54ffb4 100644
--- a/test/test_KnotVector.jl
+++ b/test/test_KnotVector.jl
@@ -11,6 +11,7 @@
         @test k1 == KnotVector(1.,3,2)::KnotVector{Float64}
         @test k1 == KnotVector{Int}(1,3,2)::KnotVector{Int}
         @test k1 != k2
+        @test k1.vector !== copy(k1).vector
 
         @test KnotVector{Int}([1,2]) isa KnotVector{Int}
         @test KnotVector{Int}(1,2) isa KnotVector{Int}
@@ -34,6 +35,11 @@
         @test BasicBSpline._vec(EmptyKnotVector()) isa Vector{Bool}
     end
 
+    @testset "EmptyKnotVector" begin
+        k = EmptyKnotVector()
+        @test k === copy(k)
+    end
+
     @testset "zeros" begin
         @test KnotVector() == zero(KnotVector)
         @test KnotVector() == 0*k1 == k1*0 == zero(k1)
diff --git a/test/test_UniformKnotVector.jl b/test/test_UniformKnotVector.jl
index 0c9a1090d..d36b3400f 100644
--- a/test/test_UniformKnotVector.jl
+++ b/test/test_UniformKnotVector.jl
@@ -14,6 +14,8 @@
         @test k4 != k2
         @test k2 == KnotVector(1:3)
         @test k2 != 1:3
+        @test k1.vector === copy(k1).vector
+        @test k1 === copy(k1)
     end
 
     @testset "constructor, conversion" begin