diff --git a/base/exports.jl b/base/exports.jl index 8aff751aa0079..4e7a7e4b37c0f 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -82,6 +82,7 @@ export SubDArray, SubOrDArray, SubString, + SubVector, SymTridiagonal, TcpSocket, TmStruct, diff --git a/base/subarray.jl b/base/subarray.jl index fa8e51e081bf1..c7236a79415e9 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -339,3 +339,93 @@ end summary(s::SubArray) = string(dims2string(size(s)), " SubArray of ", summary(s.parent)) + + + +# SubVectors are fast 1d slices +immutable SubVector{T} <: AbstractArray{T,1} + ptr::Ptr{T} + stride::Int + len::Int +end + +SubVector{T}(A::Array{T}, firstindex::Integer, strd::Integer, len::Integer) = SubVector{T}(convert(Ptr{T}, A) + (firstindex - 1)*sizeof(T), int(strd), int(len)) + +function SubVector{T}(A::Array{T}, indexes::RangeIndex...) + n = 0 + for i in indexes + n += !isa(i, Int) + end + if n > 1 + error("Must be 1-dimensional") + end + firstindex = 1 + strd = 0 + len = 1 + pstride = 1 + for j = 1:length(indexes) + i = indexes[j] + if min(i) < 1 || max(i) > size(A, j) + error(BoundsError) + end + if isa(i, Int) + firstindex += (i-1)*pstride + else + strd = pstride * step(i) + len = length(i) + firstindex += (first(i)-1)*pstride + end + pstride *= size(A,j) + end + SubVector(A, firstindex, strd, len) +end + +function SubVector{T}(s::SubVector{T}, index::RangeIndex) + if min(index) < 1 || max(index) > length(s) + error(BoundsError) + end + ptr = s.ptr + (first(index)-1)*s.stride*sizeof(T) + strd = s.stride * step(index) + len = length(index) + SubVector{T}(ptr, strd, len) +end + +ndims(s::SubVector) = 1 +length(s::SubVector) = s.len +size(s::SubVector) = (s.len,) +size(s::SubVector, d::Integer) = (d == 1) ? s.len : 1 +eltype{T}(s::SubVector{T}) = T + +similar{T}(s::SubVector, ::Type{T}, sz::NTuple{1, Int}) = Array(T, sz) +function similar{T}(s::SubVector, ::Type{T}, sz::Dims) + n = 0 + for len in sz + n += (len > 1) + end + if n > 1 + error("Requested type is not a vector") + end + Array(T, sz) +end + +unsafe_load(s::SubVector, i::Integer) = unsafe_load(s.ptr, (i-1)*s.stride + 1) + +function getindex(s::SubVector, i::Integer) + if 1 <= i <= length(s) + return unsafe_load(s, i) + else + error(BoundsError) + end +end + +unsafe_store!{T}(s::SubVector{T}, x, i::Integer) = unsafe_store!(s.ptr, x, (i-1)*s.stride + 1) + +function setindex!{T}(s::SubVector{T}, x, i::Integer) + xT = convert(T, x) + if 1 <= i <= length(s) + unsafe_store!(s, xT, i) + else + error(BoundsError) + end + xT +end diff --git a/test/arrayops.jl b/test/arrayops.jl index 43dad94bd4c92..167dccfbc0123 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -114,6 +114,19 @@ sA[2:5:end] = -1 @test all(sA[2:5:end] .== -1) @test all(A[5:15:120] .== -1) +# SubVector +A = reshape(1:48, 8, 6) +s = SubVector(A, 1:3:8, 2) +@assert s[2] == A[4,2] +@assert s == A[1:3:8, 2] +s = SubVector(A, 2:3:8, 2) +@assert s == A[2:3:8, 2] +s = SubVector(A, 4, 3:6) +@assert s == vec(A[4, 3:6]) +s[1] = 0 +@assert A[4,3] == 0 +ss = SubVector(s, 4:-2:2) +@assert ss == [44,28] # get let