From 01be289d0da6225a81e8064eacbff5dcc1c90a9f Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Mon, 9 Jan 2017 08:26:02 -0500 Subject: [PATCH] faster push and unshift to Vector for splatted arguments, support offset arrays in append and prepend, and support iterators in prepend --- base/array.jl | 37 ++++++++++++++++++++++++++++++++----- test/arrayops.jl | 32 +++++++++++++++++++++++++------- 2 files changed, 57 insertions(+), 12 deletions(-) diff --git a/base/array.jl b/base/array.jl index f5bc45fe00af5..9d0e73d2c9e8b 100644 --- a/base/array.jl +++ b/base/array.jl @@ -554,15 +554,17 @@ function push!(a::Array{Any,1}, item::ANY) end function append!{T}(a::Array{T,1}, items::AbstractVector) - n = length(items) + itemindices = eachindex(items) + n = length(itemindices) ccall(:jl_array_grow_end, Void, (Any, UInt), a, n) - copy!(a, length(a)-n+1, items, 1, n) + copy!(a, length(a)-n+1, items, first(itemindices), n) return a end append!(a::Vector, iter) = _append!(a, iteratorsize(iter), iter) +push!(a::Vector, iter...) = append!(a, iter) -function _append!(a, ::HasLength, iter) +function _append!(a, ::Union{HasLength,HasShape}, iter) n = length(a) resize!(a, n+length(iter)) @inbounds for (i,item) in zip(n+1:length(a), iter) @@ -591,17 +593,42 @@ julia> prepend!([3],[1,2]) 3 ``` """ +function prepend! end + function prepend!{T}(a::Array{T,1}, items::AbstractVector) - n = length(items) + itemindices = eachindex(items) + n = length(itemindices) ccall(:jl_array_grow_beg, Void, (Any, UInt), a, n) if a === items copy!(a, 1, items, n+1, n) else - copy!(a, 1, items, 1, n) + copy!(a, 1, items, first(itemindices), n) end return a end +prepend!(a::Vector, iter) = _prepend!(a, iteratorsize(iter), iter) +unshift!(a::Vector, iter...) = prepend!(a, iter) + +function _prepend!(a, ::Union{HasLength,HasShape}, iter) + n = length(iter) + ccall(:jl_array_grow_beg, Void, (Any, UInt), a, n) + i = 0 + for item in iter + @inbounds a[i += 1] = item + end + a +end +function _prepend!(a, ::IteratorSize, iter) + n = 0 + for item in iter + n += 1 + unshift!(a, item) + end + reverse!(a, 1, n) + a +end + """ resize!(a::Vector, n::Integer) -> Vector diff --git a/test/arrayops.jl b/test/arrayops.jl index c073f0b21751a..b2cd9fb77b861 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -1122,10 +1122,31 @@ A = [[i i; i i] for i=1:2] @test cumsum(A) == Any[[1 1; 1 1], [3 3; 3 3]] @test cumprod(A) == Any[[1 1; 1 1], [4 4; 4 4]] -# PR #4627 -A = [1,2] -@test append!(A, A) == [1,2,1,2] -@test prepend!(A, A) == [1,2,1,2,1,2,1,2] +isdefined(Main, :TestHelpers) || eval(Main, :(include("TestHelpers.jl"))) +using TestHelpers.OAs + +@testset "prepend/append" begin + # PR #4627 + A = [1,2] + @test append!(A, A) == [1,2,1,2] + @test prepend!(A, A) == [1,2,1,2,1,2,1,2] + + # iterators with length: + @test append!([1,2], (9,8)) == [1,2,9,8] == push!([1,2], (9,8)...) + @test prepend!([1,2], (9,8)) == [9,8,1,2] == unshift!([1,2], (9,8)...) + @test append!([1,2], ()) == [1,2] == prepend!([1,2], ()) + # iterators without length: + g = (i for i = 1:10 if iseven(i)) + @test append!([1,2], g) == [1,2,2,4,6,8,10] == push!([1,2], g...) + @test prepend!([1,2], g) == [2,4,6,8,10,1,2] == unshift!([1,2], g...) + g = (i for i = 1:2:10 if iseven(i)) # isempty(g) == true + @test append!([1,2], g) == [1,2] == push!([1,2], g...) + @test prepend!([1,2], g) == [1,2] == unshift!([1,2], g...) + + # offset array + @test append!([1,2], OffsetArray([9,8], (-3,))) == [1,2,9,8] + @test prepend!([1,2], OffsetArray([9,8], (-3,))) == [9,8,1,2] +end A = [1,2] s = Set([1,2,3]) @@ -1880,9 +1901,6 @@ end end end -isdefined(Main, :TestHelpers) || eval(Main, :(include("TestHelpers.jl"))) -using TestHelpers.OAs - @testset "accumulate, accumulate!" begin @test accumulate(+, [1,2,3]) == [1, 3, 6]