diff --git a/src/SlidingWindow.jl b/src/SlidingWindow.jl new file mode 100644 index 0000000..24fcd5e --- /dev/null +++ b/src/SlidingWindow.jl @@ -0,0 +1,168 @@ +# TODO: +# Make tests +# - winds +abstract type SlidingWindow{W<:Tuple,S<:Tuple,P<:Tuple,T,N,L} <: AbstractArray{T,N} end + +const SlidingWindowUnion{W,S,P,T,N,L} = Union{SlidingWindow{W,S,P,T,N,L},Type{<:SlidingWindow{W,S,P,T,N,L}}} + + +for (M1,M2) in ((:wfirst, :_first), (:wlast, :_last), (:wstep, :_step), + (:wsize, :_size), (:woffset, :_offset), (:weltype, :_eltype)) + @eval begin + @pure $M1(::SlidingWindowUnion{W,S,P,T,N,0}, i::Int) where {W,S,P,T,N} = 0 + @pure $M1(::SlidingWindowUnion{W,S,P,T,N,L}, i::Int) where {W,S,P,T,N,L} = i <= N ? $M2(W, i) : 1 + @pure $M1(::SlidingWindowUnion{W,S,P,T,N,L}) where {W,S,P,T,N,L} = $M2(W) + end +end +@pure wlength(::SlidingWindowUnion{W,S,P,T,N,L}) where {W,S,P,T,N,L} = prod(_size(W)) + + +for (M1,M2) in ((:sfirst, :_first), (:slast, :_last), (:sstep, :_step), + (:ssize, :_size), (:soffset, :_offset), (:seltype, :_eltype)) + @eval begin + @pure $M1(::SlidingWindowUnion{W,S,P,T,N,0}, i::Int) where {W,S,P,T,N} = 0 + @pure $M1(::SlidingWindowUnion{W,S,P,T,N,L}, i::Int) where {W,S,P,T,N,L} = i <= N ? $M2(S, i) : 1 + @pure $M1(::SlidingWindowUnion{W,S,P,T,N,L}) where {W,S,P,T,N,L} = $M2(S) + end +end +@pure slength(::SlidingWindowUnion{W,S,P,T,N,L}) where {W,S,P,T,N,L} = prod(_size(S)) + +@pure length(::SlidingWindowUnion{W,S,P,T,N,L}) where {W,S,P,T,N,L} = L::Int +@pure size(::SlidingWindowUnion{W,S,P,T,N,L}, i::Int) where {W,S,P,T,N,L} = + (_size(W, i) * _size(S, i))::Int +@pure size(::SlidingWindowUnion{W,S,P,T,N,L}) where {W,S,P,T,N,L} = + ntuple(i->_size(W, i) * _size(S, i), Val(N))::NTuple{N,Int} +@pure eltype(::SlidingWindowUnion{W,S,P,T,N,L}) where {W,S,P,T,N,L} = T +@pure Base.ndims(::SlidingWindowUnion{W,S,P,T,N,L}) where {W,S,P,T,N,L} = N::Int + +@pure psize(::SlidingWindowUnion{W,S,P,T,N,L}, i::Int) where {W,S,P,T,N,L} = fieldtype(P, i)::Int +@pure psize(::SlidingWindowUnion{W,S,P,T,N,L}) where {W,S,P,T,N,L} = (P.parameters...,)::NTuple{N,Int} + +@pure @inline function to_inds(sw::SlidingWindowUnion{W,S,P,T,N,L}, i::Int, s::Int) where {W,S,P,T,N,L} + @_propagate_inbounds_meta + @boundscheck if i < 1 || i > wlength(sw) || s < 1 || s > slength(sw) + throw(BoundsError(sw, (i,s))) + end + out = 0 + sz = 1 + ind = i - 1 + indnext = 0 + + stride_ind = s - 1 + stride_indnext = 0 + for D in 1:N + indnext = div(ind, wsize(sw, D)) + sindnext = div(stride_ind, ssize(sw, D)) + if D == 1 + out += ((wfirst(sw, D) + ( ind - wsize(sw, D) * indnext + 1 - woffset(sw, D)) * wstep(sw, D)) + + (sfirst(sw, D) + (stride_ind - ssize(sw, D) * sindnext + 1 - soffset(sw, D)) * sstep(sw, D))) + else + out += sz * + (((wfirst(sw, D) + ( ind - wsize(sw, D) * indnext + 1 - woffset(sw, D)) * wstep(sw, D)) + + (sfirst(sw, D) + (stride_ind - ssize(sw, D) * sindnext + 1 - soffset(sw, D)) * sstep(sw, D))) - 1) + #((wfirst(sw, D) + (wfirst(sw, D) + ( ind - wsize(sw, D) * indnext + wfirst(sw, D) - woffset(sw, D)) - woffset(sw, D)) * wstep(sw, D)) * + # (sfirst(sw, D) + ((stride_ind - ssize(sw, D) * sindnext + 1) - soffset(sw, D)) * sstep(sw, D)) - 1) + #(sfirst(sw, D) + (sfirst(sw, D) + (sind - ssize(sw, D) * sindnext + sfirst(sw, D) - soffset(sw, D)) - soffset(sw, D)) * sstep(sw, D)) - 1) + end + sz *= psize(sw, D) + ind = indnext + stride_ind + end + out +end + +function Base.checkbounds(sw::SlidingWindowUnion{W,S,P,T,N,L}, i::Int, s::Int) where {W,S,P,T,N,L} + if 1 > i || i > wlength(sw) + throw(BoundsError(sw, i)) + elseif 1 > s || s > slength(sw) + throw(BoundsError(sw, s)) + end +end + +# TODO: SlidingWindow error messages +function check_slidingwindow_params(W,S,P,N,L) + for i in OneToSRange{N} + if _size(W, i) * _last(S, i) > P.parameters[i] + error("") + elseif _first(W, i) * _first(S, i) < 1 + error("") + end + end +end + + + +struct SWIterator{W,S,P,N,L} <: SlidingWindow{W,S,P,Int,N,L} + function SWIterator{W,S,P,N,L}() where {W,S,P,N,L} + check_slidingwindow_params(W,S,P,N,L) + new{W,S,P,N,L}() + end +end + +SWIterator(p::NTuple{N,Int}, window::W, stride::S) where {N,W<:Tuple{Vararg{<:StaticRange,N}},S<:Tuple{Vararg{<:StaticRange,N}}} = + SWIterator{W,S,Tuple{p...}}() +SWIterator{W,S,P}() where {W,S,P} = SWIterator{W,S,P,length(P.parameters)}() +SWIterator{W,S,P,N}() where {W,S,P,N} = SWIterator{W,S,P,N,prod(_size(W))*prod(_size(S))}() + +SWIterator(p::AbstractArray, window::Tuple{Vararg{<:StaticRange,N}}, stride::Tuple{Vararg{<:StaticRange,N}}=map(_->1,1:N)) where N = + SWIterator(size(p), window, stride) +SWIterator(p::StaticArray{S,T,N}, window::Tuple{Vararg{<:StaticRange,N}}, stride::Tuple{Vararg{<:StaticRange,N}}=map(_->1,1:N)) where {S,T,N} = + SWIterator{typeof(window),typeof(stride),S}() + +SWIterator(psize::NTuple{N,Int}, wsize::NTuple{N,Int}, stride::NTuple{N,Int}, dilation::NTuple{N,Int}) where N = + SWIterator{ Tuple{map(i->StaticRange{Int,1,wsize[i],dilation[i],1,div(wsize[i]-1,dilation[i])+1}, 1:N)...}}(psize, stride) +SWIterator{W}(psize::NTuple{N,Int}, stride::NTuple{N,Int}) where {W,N} = + SWIterator{W,Tuple{map(i->StaticRange{Int,1,stride[i],1,1,1}, 1:N)...},Tuple{psize...}}() + +""" + +srange(Ew, P, step=S) + getindex(w, i, s) + +```jldoctest +using TiledIteration + +A = reshape([1:10000...], (100,100)); +titrs = TileIterator(axes(A), (10,10)); +tile1, itr = iterate(titrs) + + +li = LinearIndices((100, 100)); + +w = (srange(1,20,step=2),srange(1,20,step=2)) +s = (srange(0,40,step=10),srange(0,40,step=10)) +sw = SWIterator(li, w,s); + +li[w...][1] == sw[1, 1] +li[w...][6] == sw[6, 1] +li[w...][11] == sw[11, 1] + + + + +for tileaxs in TileIterator(axes(A), (10,10)) + @show tileaxs +end + +``` +""" +# index linear into which strides +# stride sub indices into window indices --> linear index +@inline function getindex(sw::SlidingWindow{W,S,P,T,N,L}, i::Int, s::Int) where {W,S,P,T,N,L} + @_propagate_inbounds_meta + @boundscheck checkbounds(sw, i, s) + #= + ind = s - 1 + indnext = 0 + stride = 1 + s2i = 0 + for D in 1:N + indnext = div(ind, ssize(sw, D)) + s2i += (wfirst(sw, D) + (ind - ssize(sw, 1) * indnext + sfirst(sw, 1))) + + (i + woffset(sw, D)) * wstep(sw, D) + stride *= psize(sw, D) + ind = indnext + end + =# + return to_inds(sw, i, s) +end diff --git a/src/StaticAxes.jl b/src/StaticAxes.jl index 261f1e9..e566122 100644 --- a/src/StaticAxes.jl +++ b/src/StaticAxes.jl @@ -1,33 +1,44 @@ -struct StaticAxes{N,Ax<:Tuple} end -const StaticAxesUnion{Ax} = Union{StaticAxes{Ax},Type{<:StaticAxes{Ax}}} +""" + StaticAxes -for (F, Trait) in ((:first, :B), (:last, :E), (:step, :S), (:size, :L), (:offset, :F)) +Provides formal axis type for AbsractArrays. + +```jldoctest +julia> inds = (srange(2:3), srange(2:3), srange(1:3), srange(1:2), srange(1:2)) + +``` +""" + +for (F, Trait) in ((:_first, :B), (:_last, :E), (:_step, :S), (:_size, :L), (:_offset, :F), (:_eltype, :T)) @eval begin - @pure function $F(inds::StaticAxesUnion{1,Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}}}, i::Int) where {T1,B1,E1,S1,F1,L1} + @pure function $F( + ::Type{Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}}}, + i::Int) where {T1,B1,E1,S1,F1,L1} if i == 1 return $(Symbol(Trait, 1)) - else - throw(BoundsError(inds, i)) end end - @pure $F(inds::StaticAxesUnion{1,Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}}}) where {T1,B1,E1,S1,F1,L1} = ($(Symbol(Trait, 1)),) + @pure function $F( + ::Type{Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}}} + ) where {T1,B1,E1,S1,F1,L1} + ($(Symbol(Trait, 1)),) + end @pure function $F( - inds::StaticAxesUnion{2,Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1},<:StaticRange{T2,B2,E2,S2,F2,L2}}}, + ::Type{Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, + <:StaticRange{T2,B2,E2,S2,F2,L2}}}, i::Int) where {T1,B1,E1,S1,L1,F1, T2,B2,E2,S2,L2,F2} if i == 1 return $(Symbol(Trait, 1)) - elseif i == 2 + else i == 2 return $(Symbol(Trait, 2)) - else - throw(BoundsError(inds, i)) end end @pure function $F( - inds::StaticAxesUnion{2,Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, - <:StaticRange{T2,B2,E2,S2,F2,L2}}} + ::Type{Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, + <:StaticRange{T2,B2,E2,S2,F2,L2}}} ) where {T1,B1,E1,S1,L1,F1, T2,B2,E2,S2,L2,F2} ($(Symbol(Trait, 1)),$(Symbol(Trait, 2))) @@ -35,26 +46,26 @@ for (F, Trait) in ((:first, :B), (:last, :E), (:step, :S), (:size, :L), (:offset @pure function $F( - inds::StaticAxesUnion{3,Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, - <:StaticRange{T2,B2,E2,S2,F2,L2}, - <:StaticRange{T3,B3,E3,S3,F3,L3}}}, + ::Type{Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, + <:StaticRange{T2,B2,E2,S2,F2,L2}, + <:StaticRange{T3,B3,E3,S3,F3,L3}}}, i::Int) where {T1,B1,E1,S1,F1,L1, T2,B2,E2,S2,F2,L2, T3,B3,E3,S3,F3,L3} - if i == 1 - return $(Symbol(Trait, 1)) - elseif i == 2 - return $(Symbol(Trait, 2)) - elseif i == 3 + if i < 3 + if i == 1 + return $(Symbol(Trait, 1)) + else + return $(Symbol(Trait, 2)) + end + else i == 3 return $(Symbol(Trait, 3)) - else - throw(BoundsError(inds, i)) end end @pure function $F( - inds::StaticAxesUnion{3,Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, - <:StaticRange{T2,B2,E2,S2,F2,L2}, - <:StaticRange{T3,B3,E3,S3,F3,L3}}}, + ::Type{Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, + <:StaticRange{T2,B2,E2,S2,F2,L2}, + <:StaticRange{T3,B3,E3,S3,F3,L3}}}, ) where {T1,B1,E1,S1,F1,L1, T2,B2,E2,S2,F2,L2, T3,B3,E3,S3,F3,L3} @@ -62,32 +73,34 @@ for (F, Trait) in ((:first, :B), (:last, :E), (:step, :S), (:size, :L), (:offset end @pure function $F( - inds::StaticAxesUnion{4,Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, - <:StaticRange{T2,B2,E2,S2,F2,L2}, - <:StaticRange{T3,B3,E3,S3,F3,L3}, - <:StaticRange{T4,B4,E4,S4,F4,L4}}}, + ::Type{Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, + <:StaticRange{T2,B2,E2,S2,F2,L2}, + <:StaticRange{T3,B3,E3,S3,F3,L3}, + <:StaticRange{T4,B4,E4,S4,F4,L4}}}, i::Int) where {T1,B1,E1,S1,F1,L1, T2,B2,E2,S2,F2,L2, T3,B3,E3,S3,F3,L3, T4,B4,E4,S4,F4,L4} - if i == 1 - return $(Symbol(Trait, 1)) - elseif i == 2 - return $(Symbol(Trait, 2)) - elseif i == 3 - return $(Symbol(Trait, 3)) - elseif i == 4 - return $(Symbol(Trait, 4)) + if i < 3 + if i == 1 + return $(Symbol(Trait, 1)) + else + return $(Symbol(Trait, 2)) + end else - throw(BoundsError(inds, i)) + if i == 3 + return $(Symbol(Trait, 3)) + else + return $(Symbol(Trait, 4)) + end end end @pure function $F( - inds::StaticAxesUnion{4,Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, - <:StaticRange{T2,B2,E2,S2,F2,L2}, - <:StaticRange{T3,B3,E3,S3,F3,L3}, - <:StaticRange{T4,B4,E4,S4,F4,L4}}}, + ::Type{Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, + <:StaticRange{T2,B2,E2,S2,F2,L2}, + <:StaticRange{T3,B3,E3,S3,F3,L3}, + <:StaticRange{T4,B4,E4,S4,F4,L4}}}, ) where {T1,B1,E1,S1,F1,L1, T2,B2,E2,S2,F2,L2, T3,B3,E3,S3,F3,L3, @@ -97,37 +110,39 @@ for (F, Trait) in ((:first, :B), (:last, :E), (:step, :S), (:size, :L), (:offset end @pure function $F( - inds::StaticAxesUnion{5,Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, - <:StaticRange{T2,B2,E2,S2,F2,L2}, - <:StaticRange{T3,B3,E3,S3,F3,L3}, - <:StaticRange{T4,B4,E4,S4,F4,L4}, - <:StaticRange{T5,B5,E5,S5,F5,L5}}}, + ::Type{Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, + <:StaticRange{T2,B2,E2,S2,F2,L2}, + <:StaticRange{T3,B3,E3,S3,F3,L3}, + <:StaticRange{T4,B4,E4,S4,F4,L4}, + <:StaticRange{T5,B5,E5,S5,F5,L5}}}, i::Int) where {T1,B1,E1,S1,F1,L1, T2,B2,E2,S2,F2,L2, T3,B3,E3,S3,F3,L3, T4,B4,E4,S4,F4,L4, T5,B5,E5,S5,F5,L5} - if i == 1 - return $(Symbol(Trait, 1)) - elseif i == 2 - return $(Symbol(Trait, 2)) - elseif i == 3 - return $(Symbol(Trait, 3)) - elseif i == 4 - return $(Symbol(Trait, 4)) - elseif i == 5 - return $(Symbol(Trait, 5)) + if i < 3 + if i == 1 + return $(Symbol(Trait, 1)) + else + return $(Symbol(Trait, 2)) + end + elseif i < 5 + if i == 3 + return $(Symbol(Trait, 3)) + else + return $(Symbol(Trait, 4)) + end else - throw(BoundsError(inds, i)) + return $(Symbol(Trait, 5)) end end @pure function $F( - inds::StaticAxesUnion{5,Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, - <:StaticRange{T2,B2,E2,S2,F2,L2}, - <:StaticRange{T3,B3,E3,S3,F3,L3}, - <:StaticRange{T4,B4,E4,S4,F4,L4}, - <:StaticRange{T5,B5,E5,S5,F5,L5}}}, + ::Type{Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, + <:StaticRange{T2,B2,E2,S2,F2,L2}, + <:StaticRange{T3,B3,E3,S3,F3,L3}, + <:StaticRange{T4,B4,E4,S4,F4,L4}, + <:StaticRange{T5,B5,E5,S5,F5,L5}}}, ) where {T1,B1,E1,S1,F1,L1, T2,B2,E2,S2,F2,L2, T3,B3,E3,S3,F3,L3, @@ -138,61 +153,65 @@ for (F, Trait) in ((:first, :B), (:last, :E), (:step, :S), (:size, :L), (:offset end @pure function $F( - ::StaticAxesUnion{6,Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, - <:StaticRange{T2,B2,E2,S2,F2,L2}, - <:StaticRange{T3,B3,E3,S3,F3,L3}, - <:StaticRange{T4,B4,E4,S4,F4,L4}, - <:StaticRange{T5,B5,E5,S5,F5,L5}, - <:StaticRange{T5,B5,E5,S5,F5,L5}}}, + ::Type{Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, + <:StaticRange{T2,B2,E2,S2,F2,L2}, + <:StaticRange{T3,B3,E3,S3,F3,L3}, + <:StaticRange{T4,B4,E4,S4,F4,L4}, + <:StaticRange{T5,B5,E5,S5,F5,L5}, + <:StaticRange{T5,B5,E5,S5,F5,L5}}}, i::Int) where {T1,B1,E1,S1,F1,L1, T2,B2,E2,S2,F2,L2, T3,B3,E3,S3,F3,L3, T4,B4,E4,S4,F4,L4, T5,B5,E5,S5,F5,L5, T6,B6,E6,S6,F6,L6} - if i == 1 - return $(Symbol(Trait, 1)) - elseif i == 2 - return $(Symbol(Trait, 2)) - elseif i == 3 - return $(Symbol(Trait, 3)) - elseif i == 4 - return $(Symbol(Trait, 4)) - elseif i == 5 - return $(Symbol(Trait, 5)) - elseif i == 6 - return $(Symbol(Trait, 6)) + if i < 3 + if i == 1 + return $(Symbol(Trait, 1)) + else + return $(Symbol(Trait, 2)) + end + elseif i < 5 + if i == 3 + return $(Symbol(Trait, 3)) + else + return $(Symbol(Trait, 4)) + end else - throw(BoundsError(inds, i)) + if i == 5 + return $(Symbol(Trait, 5)) + else + return $(Symbol(Trait, 6)) + end end end @pure function $F( - ::StaticAxesUnion{6,Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, - <:StaticRange{T2,B2,E2,S2,F2,L2}, - <:StaticRange{T3,B3,E3,S3,F3,L3}, - <:StaticRange{T4,B4,E4,S4,F4,L4}, - <:StaticRange{T5,B5,E5,S5,F5,L5}, - <:StaticRange{T5,B5,E5,S5,F5,L5}}}, - where {T1,B1,E1,S1,F1,L1, - T2,B2,E2,S2,F2,L2, - T3,B3,E3,S3,F3,L3, - T4,B4,E4,S4,F4,L4, - T5,B5,E5,S5,F5,L5, - T6,B6,E6,S6,F6,L6} + ::Type{Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, + <:StaticRange{T2,B2,E2,S2,F2,L2}, + <:StaticRange{T3,B3,E3,S3,F3,L3}, + <:StaticRange{T4,B4,E4,S4,F4,L4}, + <:StaticRange{T5,B5,E5,S5,F5,L5}, + <:StaticRange{T5,B5,E5,S5,F5,L5}}} + ) where {T1,B1,E1,S1,F1,L1, + T2,B2,E2,S2,F2,L2, + T3,B3,E3,S3,F3,L3, + T4,B4,E4,S4,F4,L4, + T5,B5,E5,S5,F5,L5, + T6,B6,E6,S6,F6,L6} ($(Symbol(Trait, 1)),$(Symbol(Trait, 2)),$(Symbol(Trait, 3)),$(Symbol(Trait, 4)), $(Symbol(Trait, 5)),$(Symbol(Trait, 6))) end @pure function $F( - inds::StaticAxesUnion{7,Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, - <:StaticRange{T2,B2,E2,S2,F2,L2}, - <:StaticRange{T3,B3,E3,S3,F3,L3}, - <:StaticRange{T4,B4,E4,S4,F4,L4}, - <:StaticRange{T5,B5,E5,S5,F5,L5}, - <:StaticRange{T6,B6,E6,S6,F6,L6}, - <:StaticRange{T7,B7,E7,S7,F7,L7}}}, + ::Type{Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, + <:StaticRange{T2,B2,E2,S2,F2,L2}, + <:StaticRange{T3,B3,E3,S3,F3,L3}, + <:StaticRange{T4,B4,E4,S4,F4,L4}, + <:StaticRange{T5,B5,E5,S5,F5,L5}, + <:StaticRange{T6,B6,E6,S6,F6,L6}, + <:StaticRange{T7,B7,E7,S7,F7,L7}}}, i::Int) where {T1,B1,E1,S1,F1,L1, T2,B2,E2,S2,F2,L2, T3,B3,E3,S3,F3,L3, @@ -200,32 +219,40 @@ for (F, Trait) in ((:first, :B), (:last, :E), (:step, :S), (:size, :L), (:offset T5,B5,E5,S5,F5,L5, T6,B6,E6,S6,F6,L6, T7,B7,E7,S7,F7,L7} - if i == 1 - return $(Symbol(Trait, 1)) - elseif i == 2 - return $(Symbol(Trait, 2)) - elseif i == 3 - return $(Symbol(Trait, 3)) - elseif i == 4 - return $(Symbol(Trait, 4)) - elseif i == 5 - return $(Symbol(Trait, 5)) - elseif i == 6 - return $(Symbol(Trait, 6)) - elseif i == 7 - return $(Symbol(Trait, 7)) + if i < 5 + if i < 3 + if i == 1 + return $(Symbol(Trait, 1)) + else + return $(Symbol(Trait, 2)) + end + else + if i == 3 + return $(Symbol(Trait, 3)) + else + return $(Symbol(Trait, 4)) + end + end else - throw(BoundsError(inds, i)) + if i < 7 + if i == 5 + return $(Symbol(Trait, 5)) + else + return $(Symbol(Trait, 6)) + end + else + return $(Symbol(Trait, 7)) + end end end @pure function $F( - inds::StaticAxesUnion{7,Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, - <:StaticRange{T2,B2,E2,S2,F2,L2}, - <:StaticRange{T3,B3,E3,S3,F3,L3}, - <:StaticRange{T4,B4,E4,S4,F4,L4}, - <:StaticRange{T5,B5,E5,S5,F5,L5}, - <:StaticRange{T6,B6,E6,S6,F6,L6}, - <:StaticRange{T7,B7,E7,S7,F7,L7}}}, + ::Type{Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, + <:StaticRange{T2,B2,E2,S2,F2,L2}, + <:StaticRange{T3,B3,E3,S3,F3,L3}, + <:StaticRange{T4,B4,E4,S4,F4,L4}, + <:StaticRange{T5,B5,E5,S5,F5,L5}, + <:StaticRange{T6,B6,E6,S6,F6,L6}, + <:StaticRange{T7,B7,E7,S7,F7,L7}}} ) where {T1,B1,E1,S1,F1,L1, T2,B2,E2,S2,F2,L2, T3,B3,E3,S3,F3,L3, @@ -239,14 +266,14 @@ for (F, Trait) in ((:first, :B), (:last, :E), (:step, :S), (:size, :L), (:offset @pure function $F( - inds::StaticAxesUnion{8,Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, - <:StaticRange{T2,B2,E2,S2,F2,L2}, - <:StaticRange{T3,B3,E3,S3,F3,L3}, - <:StaticRange{T4,B4,E4,S4,F4,L4}, - <:StaticRange{T5,B5,E5,S5,F5,L5}, - <:StaticRange{T6,B6,E6,S6,F6,L6}, - <:StaticRange{T7,B7,E7,S7,F7,L7}, - <:StaticRange{T8,B8,E8,S8,F8,L8}}}, + ::Type{Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, + <:StaticRange{T2,B2,E2,S2,F2,L2}, + <:StaticRange{T3,B3,E3,S3,F3,L3}, + <:StaticRange{T4,B4,E4,S4,F4,L4}, + <:StaticRange{T5,B5,E5,S5,F5,L5}, + <:StaticRange{T6,B6,E6,S6,F6,L6}, + <:StaticRange{T7,B7,E7,S7,F7,L7}, + <:StaticRange{T8,B8,E8,S8,F8,L8}}}, i::Int) where {T1,B1,E1,S1,F1,L1, T2,B2,E2,S2,F2,L2, T3,B3,E3,S3,F3,L3, @@ -255,35 +282,46 @@ for (F, Trait) in ((:first, :B), (:last, :E), (:step, :S), (:size, :L), (:offset T6,B6,E6,S6,F6,L6, T7,B7,E7,S7,F7,L7, T8,B8,E8,S8,F8,L8} - if i == 1 - return $(Symbol(Trait, 1)) - elseif i == 2 - return $(Symbol(Trait, 2)) - elseif i == 3 - return $(Symbol(Trait, 3)) - elseif i == 4 - return $(Symbol(Trait, 4)) - elseif i == 5 - return $(Symbol(Trait, 5)) - elseif i == 6 - return $(Symbol(Trait, 6)) - elseif i == 7 - return $(Symbol(Trait, 7)) - elseif i == 8 - return $(Symbol(Trait, 8)) + if i < 5 + if i < 3 + if i == 1 + return $(Symbol(Trait, 1)) + else + return $(Symbol(Trait, 2)) + end + else + if i == 3 + return $(Symbol(Trait, 3)) + else + return $(Symbol(Trait, 4)) + end + end else - throw(BoundsError(inds, i)) + if i < 7 + if i == 5 + return $(Symbol(Trait, 5)) + else + return $(Symbol(Trait, 6)) + end + else + if i == 7 + return $(Symbol(Trait, 7)) + else + return $(Symbol(Trait, 8)) + end + end end + end @pure function $F( - inds::StaticAxesUnion{8,Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, - <:StaticRange{T2,B2,E2,S2,F2,L2}, - <:StaticRange{T3,B3,E3,S3,F3,L3}, - <:StaticRange{T4,B4,E4,S4,F4,L4}, - <:StaticRange{T5,B5,E5,S5,F5,L5}, - <:StaticRange{T6,B6,E6,S6,F6,L6}, - <:StaticRange{T7,B7,E7,S7,F7,L7}, - <:StaticRange{T8,B8,E8,S8,F8,L8}}}, + ::Type{Tuple{<:StaticRange{T1,B1,E1,S1,F1,L1}, + <:StaticRange{T2,B2,E2,S2,F2,L2}, + <:StaticRange{T3,B3,E3,S3,F3,L3}, + <:StaticRange{T4,B4,E4,S4,F4,L4}, + <:StaticRange{T5,B5,E5,S5,F5,L5}, + <:StaticRange{T6,B6,E6,S6,F6,L6}, + <:StaticRange{T7,B7,E7,S7,F7,L7}, + <:StaticRange{T8,B8,E8,S8,F8,L8}}} ) where {T1,B1,E1,S1,F1,L1, T2,B2,E2,S2,F2,L2, T3,B3,E3,S3,F3,L3, diff --git a/src/StaticRange.jl b/src/StaticRange.jl new file mode 100644 index 0000000..9e42b92 --- /dev/null +++ b/src/StaticRange.jl @@ -0,0 +1,152 @@ +abstract type AbstractStaticRange{T,L} <: AbstractRange{T} end + +const AbstractStaticRangeUnion{T,L} = Union{AbstractStaticRange{T,L},Type{<:AbstractStaticRange{T,L}}} + +@pure length(::AbstractStaticRangeUnion{T,L}) where {T,L} = L::Int +@pure lastindex(::AbstractStaticRangeUnion{T,L}) where {T,L} = L::Int +@pure size(::AbstractStaticRangeUnion{T,L}) where {T,L} = (L,)::NTuple{1,Int} + +@pure Base.isempty(::AbstractStaticRangeUnion{T,0}) where {T,B,E,S} = true +@pure Base.isempty(::AbstractStaticRangeUnion{T,L}) where {T,L} = false +@pure offset(::AbstractStaticRange) = oftype(L, 1) + + +""" + OneToSRange{T,N} + +""" +struct OneToSRange{T,N} <: AbstractStaticRange{T,N} end + +OneToSRange(N::Int) = OneToSRange{T,N}() + +OneToSRangeUnion{T,N} = Union{OneToSRange{T,N},Type{<:OneToSRange{T,N}}} + +@pure last(::OneToSRangeUnion{T,N}) where {T,N} = N::T +@pure step(::OneToSRangeUnion{T,N}) where {T,N} = T(1) +@pure firstindex(::OneToSRangeUnion{T,N}) where {T,N} = 1::Int +@pure lastindex(::OneToSRangeUnion{T,N}) where {T,N} = N::Int + +""" + OrdinalSRange{T,B,E,L} <: AbstractStaticRange{T,L} +""" +abstract type OrdinalSRange{T,B,E,L} <: AbstractStaticRange{T,L} end + +OrdinalSRangeUnion{T,B,E,L} = Union{OrdinalSRange{T,B,E,L},Type{<:OrdinalSRange{T,B,E,L}}} + +@pure first(::OrdinalSRangeUnion{T,B,E,L}) where {T,B,E,L} = B::T +@pure last(::OrdinalSRangeUnion{T,B,E,L}) where {T,B,E,L} = E::T +@pure firstindex(::OrdinalSRangeUnion{T,B,E,L}) where {T,B,E,L} = 1::Int +@pure lastindex(::OrdinalSRangeUnion{T,B,E,L}) where {T,B,E,L} = L::Int +@pure step(::OrdinalSRangeUnion{T,B,E,L}) where {T,B,E,L} = T(1) + +@pure Base.minimum(::OrdinalSRangeUnion{T,B}) where {T,B} = B::T +@pure Base.maximum(::OrdinalSRangeUnion{T,B,E}) where {T,B,E} = E::T +@pure Base.extrema(::OrdinalSRangeUnion{T,B,E}) where {T,B,E} = (B, E)::Tuple{T,T} + + + + +# len lendiv start stop +#struct LinSRange{T,B,E,L} <: AbstractStaticRange{T,L} end +# const LinSRangeUnion{T,B,E,L} = Union{LinSRange{T,B,E,L},Type{<:LinSRange{T,B,E,L}}} + + +""" + UnitSRange{T,B,E,L} + +`OrdinalSRange` that assumes that step is T(1). +""" +struct UnitSRange{T,B,E,L} <: OrdinalSRange{T,B,E,L} end + +""" + AbstractStepSRange +Supertype for ordinal static ranges with elements of type `T` and spacing(s) of type `T` +(note: differs from `OrdinalRange` which allows spacing to have unique type from elements). +""" +abstract type AbstractStepSRange{T,B,E,S,L} <: OrdinalSRange{T,B,E,L} end + +@pure step(::AbstractStepSRange{T,B,E,S,L}) where {T,B,E,S,L} = S::T +@pure step(::Type{<:AbstractStepSRange{T,B,E,S,L}}) where {T,B,E,S,L} = S::T + + +abstract type OffsetSRange{T,B,E,S,F,L} <: AbstractStepSRange{T,B,E,S,L} end + +@pure firstindex(::OffsetSRange{T,B,E,S,F,L}) where {T,B,E,S,F,L} = F::Int +@pure firstindex(::Type{<:OffsetSRange{T,B,E,S,F,L}}) where {T,B,E,S,F,L} = F::Int + +@pure lastindex(::OffsetSRange{T,B,E,S,F,L}) where {T,B,E,S,F,L} = (L + F)::Int +@pure lastindex(::Type{<:OffsetSRange{T,B,E,S,F,L}}) where {T,B,E,S,F,L} = (L + F)::Int + + +""" + StaticRange + +A StaticRange is fully statically typed in all of its traits. +* eltype +* first +* last +* step +* offset: affects indexing into range (doesn't affect actual range values, see examples) +* length +""" +struct StaticRange{T,B,E,S,F,L} <: OffsetSRange{T,B,E,S,F,L} + function StaticRange{T,B,E,S,F,L}() where {T,B,E,S,F,L} + (B*S) > E && error("StaticRange: the last index of a StaticRange cannot be less than the first index unless reverse indexing, got first = $B, and last = $E, step = $S.") + new{T,B,E,S,F,L}() + end +end +StaticRange{T,B,E,S,F}() where {T,B,E,S,F} = StaticRange{T,B,E,S,F,floor(Int, (E-B)/S)+1}() + +const StaticRangeUnion{T,B,E,S,F,L} = Union{StaticRange{T,B,E,S,F,L},Type{<:StaticRange{T,B,E,S,F,L}}} + + +@pure ==(::StaticRangeUnion{T1,B1,E1,S1,F1,L1}, ::StaticRangeUnion{T2,B2,E2,S2,F2,L2}) where {T1,B1,E1,S1,F1,L1,T2,B2,E2,S2,F2,L2} = false +@pure ==(::StaticRangeUnion{T,B,E,S,F,L}, ::StaticRangeUnion{T,B,E,S,F,L}) where {T,B,E,S,F,L} = true + +@pure (+)(::StaticRangeUnion{T,B,E,S,F,L}, i::T) where {T,B,E,S,F,L} = StaticRangeUnion{T,B+i,E+i,S,F,L}() +@pure (-)(::StaticRangeUnion{T,B,E,S,F,L}, i::T) where {T,B,E,S,F,L} = StaticRangeUnion{T,B-i,E-i,S,F,L}() + +# Qs +# - Should offset be reset to one? +# - Should offset be required to be same in both ranges? +@pure (+)(::StaticRangeUnion{T,B1,E1,S,F,L}, ::StaticRangeUnion{T,B2,E2,S,F,L}) where {T,B1,B2,E1,E2,F,S,L} = StaticRange{T,B+i,E+i,S,1,L}() +@pure (-)(::StaticRangeUnion{T,B1,E1,S,F,L}, ::StaticRangeUnion{T,B2,E2,S,F,L}) where {T,B1,B2,E1,E2,F,S,L} = StaticRange{T,B-i,E-i,S,1,L}() + +@pure Base.reverse(::StaticRangeUnion{T,B,E,S,F,L}) where {T,B,E,S,F,L} = StaticRange{T,E,B,-S,F,L}() +Base.similar(::StaticRangeUnion{T,B,E,S,F,L}, type=T, start=B, stop=E, step=S, offset=F, length=L) where {T,B,E,S,F,L,} = + StaticRange{type,start,stop,step,offset,length}() + +# enable base range like interactions +@inline function Base.getproperty(r::StaticRange{T,B,E,S,F,L}, sym::Symbol) where {T,B,E,S,F,L} + if sym === :step + return S::T + elseif sym === :start + return B::T + elseif sym === :stop + return E::T + elseif sym === :len + return L::Int + elseif sym === :lendiv + return (E - B) / S + elseif sym === :ref # for now this is just treated the same as start + return B::T + elseif sym === :offset + return F::Int + else + error("type $(typeof(r)) has no field $sym") + end +end + +Base.show(io::IO, r::StaticRange) = showrange(io, r) +Base.show(io::IO, ::MIME"text/plain", r::StaticRange) = showrange(io, r) + +function showrange(io::IO, r::StaticRange) + print(io, "StaticRange(") + show_mimic_range(io, r) + print(io, ")") +end + +#$(StaticRange)($(B):$(S):$(E))") +show_mimic_range(io::IO, ::StaticRange{T,B,E,S}) where {T,B,E,S} = print(io, "$(B):$(S):$(E)") +#show_mimic_range(io::IO, ::UnitSRange{T,B,E,S}) where {T,B,E,S} = print(io, "$(B):$(E)") +show_mimic_range(io::IO, ::OneToSRange{N}) where {N} = print(io, "OneTo($(N))") diff --git a/src/StaticRanges.jl b/src/StaticRanges.jl deleted file mode 100644 index 0637b39..0000000 --- a/src/StaticRanges.jl +++ /dev/null @@ -1,48 +0,0 @@ -# TODO: -# - ensure axes works on all appropriate types -# - distributed StridedWindow (for each window) indexing creates more objects but is parallel -# - non-distributed can be optimized within one function -# - implement offset - -module StaticRanges - -using StaticArrays, Base.Cartesian - -import StaticArrays: tuple_length, tuple_prod, tuple_minimum - -import Base: # indexing - unsafe_getindex, getindex, checkbounds, to_index, axes, size, - @_inline_meta, @pure, @_propagate_inbounds_meta, @propagate_inbounds, - ==, +, -, - # range - step, OneTo, first, last, firstindex, lastindex, tail, eltype, length -# promote_op, , zero, trunc, floor, round, ceil, -# mod, rem, atan, hypot - -export StaticRange, SRange, OneToSRange, SubRange, srange -export StaticIndices, SubIndices, - CartesianSIndices, SubCartesianIndices, - LinearSIndices, SubLinearIndices, parentsize - -# this is the default number of dimensions supported by default. Users can compile methods -# to support more dimensions by calling `create_nd_support(N)` where N is the max number of -# supported dimensions. -const NDSupport = 3::Int - -# Notes on project organization -# - Abstract types and documentation are kept in this module file -# - Each subtype has it's own file -include("types.jl") -include("traits.jl") -include("checkbounds.jl") -include("indexing.jl") -include("multidimensional.jl") -include("utils.jl") - -#include("SubIndices.jl") - -#include("SlidingWindow.jl") - - - -end diff --git a/src/abstractrange.jl b/src/abstractrange.jl deleted file mode 100644 index faf895d..0000000 --- a/src/abstractrange.jl +++ /dev/null @@ -1,84 +0,0 @@ -abstract type AbstractStaticRange{T,L} <: AbstractRange{T} end - -const AbstractStaticRangeUnion{T,L} = Union{AbstractStaticRange{T,L},Type{<:AbstractStaticRange{T,L}}} - -@pure length(::AbstractStaticRangeUnion{T,L}) where {T,L} = L::Int -@pure lastindex(::AbstractStaticRangeUnion{T,L}) where {T,L} = L::Int -@pure size(::AbstractStaticRangeUnion{T,L}) where {T,L} = (L,)::NTuple{1,Int} -@pure firstindex(::AbstractStaticRangeUnion{T,L}) where {T,L} = 1::Int - -@pure Base.isempty(::AbstractStaticRangeUnion{T,0}) where {T,B,E,S} = true -@pure Base.isempty(::AbstractStaticRangeUnion{T,L}) where {T,L} = false - -# len lendiv start stop -#struct LinSRange{T,B,E,L} <: AbstractStaticRange{T,L} end -# const LinSRangeUnion{T,B,E,L} = Union{LinSRange{T,B,E,L},Type{<:LinSRange{T,B,E,L}}} - -# TODO: handle UnitSRange with multiple non-int types before implementing this -struct UnitSRange{T,B,E,L} <: AbstractStaticRange{T,L} end - -@pure first(::UnitSRange{T,B,E,S,L}) where {T,B,E,S,L} = B::T -@pure first(::Type{<:UnitSRange{T,B,E,S,L}}) where {T,B,E,S,L} = B::T - -@pure last(::UnitSRange{T,B,E,S,L}) where {T,B,E,S,L} = E::T -@pure last(::Type{<:UnitSRange{T,B,E,S,L}}) where {T,B,E,S,L} = E::T - -@pure step(::UnitSRange{T,B,E,S,L}) where {T,B,E,S,L} = T(1) -@pure step(::Type{<:UnitSRange{T,B,E,S,L}}) where {T,B,E,S,L} = T(1) - - - -abstract type OrdinalSRange{T,B,E,S,L} <: AbstractStaticRange{T,L} end - -@pure first(::OrdinalSRange{T,B,E,S,L}) where {T,B,E,S,L} = B::T -@pure first(::Type{<:OrdinalSRange{T,B,E,S,L}}) where {T,B,E,S,L} = B::T - -@pure last(::OrdinalSRange{T,B,E,S,L}) where {T,B,E,S,L} = E::T -@pure last(::Type{<:OrdinalSRange{T,B,E,S,L}}) where {T,B,E,S,L} = E::T - -@pure step(::OrdinalSRange{T,B,E,S,L}) where {T,B,E,S,L} = S::T -@pure step(::Type{<:OrdinalSRange{T,B,E,S,L}}) where {T,B,E,S,L} = S::T - -# TODO: StepSRange needs own non pure getindex -mutable struct StepSRange{T,B,E,S,L} <: OrdinalSRange{T,B,E,S,L} - offset::Int -end - -offset(r::StepSRange{T}) where T = r.offset::Int - - - -""" - StaticRange - -A StaticRange is fully statically typed in all of its traits. -* eltype -* first -* last -* step -* offset -* length - -""" -struct StaticRange{T,B,E,S,F,L} <: OrdinalSRange{T,B,E,S,F,L} - function StaticRange{T,B,E,S,F,L}() where {T,B,E,S,F,L} - (B*S) > E && error("StaticRange: the last index of a StaticRange cannot be less than the first index unless reverse indexing, got first = $B, and last = $E, step = $S.") - new{T,B,E,S,F,L}() - end -end - -const StaticRangeUnion{T,B,E,S,F,L} = Union{StaticRange{T,B,E,S,F,L},Type{<:StaticRange{T,B,E,S,F,L}}} - -offset(::StaticRangeUnion{T,B,E,S,F,L}) where {T,B,E,S,F,L} = F::Int -firstindex(::StaticRangeUnion{T,B,E,S,F,L}) where {T,B,E,S,F,L} = F::Int -lastindex(::StaticRangeUnion{T,B,E,S,F,L}) where {T,B,E,S,F,L} = (L + F)::Int - - -const OneToSRange{N} = StaticRange{Int,1,N,1,1,N} -OneToSRange(N::Int) = OneToSRange{N}() - -StaticRange{B,E,S,F}() where {B,E,S,F} = StaticRange{B,E,S,F,floor(Int, (E-B)/S)+1}() -StaticRange{B,E,S,F,L}() where {B,E,S,F,L} = StaticRange{B,E,S,F,L,typeof(B+0*S)}() - -srange(r::AbstractRange{T}) where T = StaticRange{T,first(r),last(r),step(r),T(1),length(r)}() - diff --git a/src/checkbounds.jl b/src/checkbounds.jl deleted file mode 100644 index 2fde8f4..0000000 --- a/src/checkbounds.jl +++ /dev/null @@ -1,38 +0,0 @@ -# checkbounds -@inline function checkbounds(r::AbstractRange, i::StaticRangeUnion{T,B,E,S,L}) where {T,B,E,S,L} - (B < firstindex(r) || L > lastindex(r)) && throw(BoundsError(r, i)) -end - -@inline function checkbounds(r::StaticRangeUnion{T,B,E,S,L}, i::AbstractRange) where {T,B,E,S,L} - (first(i) < 1 || last(i) > L) && throw(BoundsError(r, i)) -end - - -@pure function checkbounds(r::SOneTo{N}, i::StaticRangeUnion{T,B,E,S,L}) where {T,B,E,S,L,N} - (B < 1 || L > N) && throw(BoundsError(r, i)) -end - -@pure function checkbounds(r::StaticRangeUnion{T,B,E,S,L}, i::SOneTo{N}) where {T,B,E,S,L,N} - N > L && throw(BoundsError(r, i)) -end - - -function Base.checkbounds(::StaticIndices{S,T,N,L}, i::Int) where {S,T,N,L} - if i < 1 || i > L - throw(BoundsError(inds, i)) - end -end - -@inline function Base.checkbounds(::StaticIndices{S,T,N,L}, r::AbstractRange) where {S,T,N,L} - if first(r) < 1 || last(r) > L - throw(BoundsError(inds, r)) - end -end - -@pure function Base.checkbounds(::StaticIndices{S,T,N,L}, r::StaticRangeUnion{<:Integer,B,E}) where {S,T,N,L,B,E} - if B < 1 || E > L - throw(BoundsError(inds, r)) - end -end - - diff --git a/src/indexing.jl b/src/indexing.jl index 2f0269d..97ce393 100644 --- a/src/indexing.jl +++ b/src/indexing.jl @@ -1,17 +1,29 @@ -@pure Base.iterate(::StaticRangeUnion{T,B,E,S,0}) where {T,B,E,S} = nothing -@pure Base.iterate(::StaticRangeUnion{T,B,E,S,L}) where {T,B,E,S,L} = (B, 1)::Tuple{T,Int} -@pure function Base.iterate(::StaticRangeUnion{T,B,E,S,L}, i::Int) where {T,B,E,S,L} - Base.@_inline_meta - i == L && return nothing - (T(B + i * S), i + 1)::Tuple{T,Int} -end +# checkbounds +@inline checkbounds(r::AbstractRange, i::StaticRangeUnion{T,B,E,S,F,L}) where {T,B,E,S,F,L} = + (B < firstindex(r) || L > lastindex(r)) && throw(BoundsError(r, i)) -@pure @propagate_inbounds function getindex(r::StaticRange{T,B,E,S,L}, i::Int) where {T,B,E,S,L} - @boundscheck if i < 1 || i > L - throw(BoundsError(r, i)) - end - return T(B + (i - 1) * S) -end +@inline checkbounds(r::StaticRangeUnion{T,B,E,S,F,L}, i::AbstractRange) where {T,B,E,S,F,L} = + (first(i) < F || last(i) > L + F) && throw(BoundsError(r, i)) + +@pure checkbounds(r::SOneTo{N}, i::StaticRangeUnion{T,B,E,S,L}) where {T,B,E,S,L,N} = + (B < 1 || L > N) && throw(BoundsError(r, i)) + +@pure checkbounds(r::StaticRangeUnion{T,B,E,S,L}, i::SOneTo{N}) where {T,B,E,S,L,N} = + N > L && throw(BoundsError(r, i)) + +#= +@pure Base.checkbounds(::StaticAxes{Ax,S,T,N,L}, i::Int) where {Ax,S,T,N,L} = + i < 1 || i > L && throw(BoundsError(inds, i)) + +@inline Base.checkbounds(::StaticAxes{Ax,S,T,N,L}, r::AbstractRange) where {Ax,S,T,N,L} = + first(r) < 1 || last(r) > L && throw(BoundsError(inds, r)) + +@pure Base.checkbounds(::StaticAxes{Ax,S,T,N,L}, r::StaticRangeUnion{<:Integer,B,E}) where {Ax,S,T,N,L,B,E} = + B < 1 || E > L && throw(BoundsError(inds, r)) + +@pure Base.checkbounds(inds::StaticAxes, i::NTuple{N,Int}) where N = + first(inds) > i || i > last(inds) && throw(BoundsError(inds, i)) +=# #function getindex(A::AbstractArray, I...) # @_propagate_inbounds_meta @@ -19,128 +31,60 @@ end # _getindex(IndexStyle(A), A, to_indices(A, I)...) #end - # Always index with the exactly indices provided. -""" - getindex(A, StaticRange) - -# Examples - -```jldoctest -using StaticRanges - -julia> A = reshape([1:400...], (20, 20)); - -julia> A[srange(1, 8, step=1), srange(1, 8, step=1)] -8×8 SArray{Tuple{8,8},Int64,2,64}: - 1 21 41 61 81 101 121 141 - 2 22 42 62 82 102 122 142 - 3 23 43 63 83 103 123 143 - 4 24 44 64 84 104 124 144 - 5 25 45 65 85 105 125 145 - 6 26 46 66 86 106 126 146 - 7 27 47 67 87 107 127 147 - 8 28 48 68 88 108 128 148 - -julia> A[srange(1, 8, step=2), srange(1, 8, step=2)] -4×4 SArray{Tuple{4,4},Int64,2,16}: - 1 41 81 121 - 3 43 83 123 - 5 45 85 125 - 7 47 87 127 -``` -""" -# ## Index StaticRange - -""" -Index with integer -```jldoctest -julia> srange(1,10,step=1)[4] -4 -``` -""" -# StaticRange[i] -""" -Index `SOneTo` with `StaticRange` -```jldoctest -julia> SOneTo(10)[srange(1,3,step=1)] -SOneTo(3) -``` -""" -@pure @propagate_inbounds function getindex(r::SOneTo{N}, i::StaticRange{T,B,E,S,L}) where {T,B,E,S,L,N} +@pure Base.iterate(::StaticRangeUnion{T,B,E,S,F,0}) where {T,B,E,S,F} = nothing +@pure Base.iterate(::StaticRangeUnion{T,B,E,S,F,L}) where {T,B,E,S,F,L} = (B, 1)::Tuple{T,Int} +@pure function Base.iterate(::StaticRangeUnion{T,B,E,S,F,L}, i::Int) where {T,B,E,S,F,L} + Base.@_inline_meta + i == L && return nothing + (T(B + i * S), i + 1)::Tuple{T,Int} +end + +@pure @propagate_inbounds function getindex(r::StaticRange{T,B,E,S,F,L}, i::Int) where {T,B,E,S,F,L} + @boundscheck if i < F || i > L + throw(BoundsError(r, i)) + end + return T(B + (i - F) * S) +end + +@pure @propagate_inbounds function getindex(r::SOneTo{N}, i::StaticRangeUnion{T,B,E,S,F,L}) where {T,B,E,S,F,L,N} @boundscheck checkbounds(r, i) return i end -""" -Index with `Base.OneTo` -```jldoctest -julia> srange(1,10,step=1)[Base.OneTo(5)] -StaticRange(1:1:5) -``` -""" -# StaticRange[OneTo] -@inline function getindex(r::StaticRangeUnion{T,B,E,S,L}, i::OneTo) where {T,B,E,S,L} +@inline function getindex(r::StaticRangeUnion{T,B,E,S,F,L}, i::OneTo) where {T,B,E,S,F,L} @boundscheck checkbounds(r, i) StaticRange{T,B,B+(length(i)-1)*S,S,1,length(i)}() end - -""" -Index with `UnitRange` -```jldoctest -julia> srange(1,10,step=1)[3:10] -StaticRange(3:1:10) -``` -""" -# StaticRange[UnitRange] -@inline function getindex(r::StaticRangeUnion{T,B,E,S,L}, i::AbstractUnitRange{<:Integer}) where {T,B,E,S,L} - @boundscheck checkbounds(r, i) - StaticRange{T,T(B + (first(i)-1) * S),T(B + (last(i) -1) * S),S,length(i)}() -end - -""" -Index with `StepRange` -```jldoctest -julia> srange(1,10,step=1)[3:2:10] -StaticRange(3:2:9) -``` -""" -# StaticRange[StepRange] -@inline function getindex(r::StaticRangeUnion{T,B,E,S,L}, i::StepRange{<:Integer}) where {T,B,E,S,L} +# TODO: What's the most user friendly way to index offsets? +# e.g. new offset starts from where index was? or just start at 1 again? +@inline function getindex(r::StaticRangeUnion{T,B,E,S,F,L}, i::AbstractUnitRange{<:Integer}) where {T,B,E,S,F,L} @boundscheck checkbounds(r, i) - StaticRange{T,T(B + (first(i)-1) * S),T(B + (first(i)-1) * S) + (length(i)-1)*(S*step(i)),S*step(i),length(i)}() + StaticRange{T,T(B + (first(i) - F) * S),T(B + (last(i) - F) * S),S,1,length(i)}() end -# ## Index Other Ranges +@inline function getindex(r::StaticRangeUnion{T,B,E,S,F,L}, i::StepRange{<:Integer}) where {T,B,E,S,F,L} + @boundscheck checkbounds(r, i) + StaticRange{T,T(B + (first(i) - F) * S),T(B + (first(i) - F) * S) + (length(i)-1)*(S*step(i)),S*step(i),1,length(i)}() +end -""" -Index `UnitRange` with `StepRange` -```jldoctest -julia> (1:2:10)[srange(1,5,step=1)] -1:2:9 -``` -""" -# ### AbstractUnitRange[srange] -@inline function getindex(r::AbstractUnitRange, i::StaticRange{T,B,E,S,L}) where {T,B,E,S,L} +@inline function getindex(r::AbstractUnitRange, i::StaticRange{T,B,E,S,F,L}) where {T,B,E,S,F,L} @boundscheck checkbounds(r, i) range(oftype(r.start, r.start + B*S), step=S, length=L) end -# OneTo[UnitSRange] -@inline function getindex(r::OneTo{T}, i::StaticRange{T,B,E,S,L}) where {T,B,E,S,L} +@inline function getindex(r::OneTo{T}, i::StaticRange{T,B,E,S,F,L}) where {T,B,E,S,F,L} @boundscheck checkbounds(r, i) range(T(B), T(E), step=S) end -# LinRange[UnitSRange] @inline function getindex(r::LinRange, i::UnitSRange{T,B,E,L}) where {T,B,E,L} @boundscheck checkbounds(r, i) return LinRange(B, E, L) end -# LinRange{srange] -@inline function getindex(r::LinRange, i::StaticRange{T,B,E,S,L}) where {T,B,E,S,L} +@inline function getindex(r::LinRange, i::StaticRange{T,B,E,S,F,L}) where {T,B,E,S,F,L} @boundscheck checkbounds(r, i) return range(B, step=S, length=L) end @@ -148,53 +92,24 @@ end # ## Index <:AbstractArray -""" -```jldoctest -julia> [1:10...][srange(2,10,step=2)] -10-element Array{Int64,1}: - 2 - 4 - 6 - 8 - 10 -``` -""" # Array[srange] -@inline function getindex(a::Array{T}, I::StaticRange{Tr,B,E,S,L}) where {Tr,B,E,S,L,T} +@inline function getindex(a::Array{T}, I::StaticRange{Int,B,E,S,F,L}) where {B,E,S,F,L,T} @boundscheck checkbounds(a, I) out = Vector{T}(undef, L) unsafe_copyto!(pointer(out), OneToSRange{L}(), pointer(a), I) return out end - -""" -```jldoctest -julia> SVector(1:10...)[srange(2,10,step=2)] -5-element SArray{Tuple{5},Int64,1,5}: - 2 - 4 - 6 - 8 - 10 - ``` - """ -_unsafe_pointer(a::SArray{S,T}) where {S,T} = convert(Ptr{T}, Base.unsafe_convert(Ptr{Nothing}, Ref(a.data))) -_unsafe_pointer(a::MArray{S,T}) where {S,T} = Base.unsafe_convert(Ptr{T}, pointer_from_objref(a)) -_unsafe_pointer(a::Array{T}) where T = pointer(a) -_unsafe_pointer(a::SizedArray{S,T}) where {S,T} = pointer(a.data)::Ptr{T} - - # StaticArray[srange] @inline function getindex( a::StaticArray{S,T,N}, I::StaticRange{<:Integer,<:Integer,<:Integer,<:Integer,L}) where {S,T,N,L} @boundscheck checkbounds(a, I) ref = Ref{NTuple{L,T}}() - unsafe_copyto!(convert(Ptr{T},Base.unsafe_convert(Ptr{Nothing}, ref)), _unsafe_pointer(a), I) + unsafe_copyto!(convert(Ptr{T},Base.unsafe_convert(Ptr{Nothing}, ref)), dig4pointer(a), I) return similar_type(a, Size(L))(ref[]) end -@pure @propagate_inbounds function getindex(r::StaticRangeUnion{T,B,E,S,L}, i::Int) where {T,B,E,S,L} +@pure @propagate_inbounds function getindex(r::StaticRangeUnion{T,B,E,S,F,L}, i::Int) where {T,B,E,S,F,L} @boundscheck if i < 1 || i > L throw(BoundsError(r, i)) end @@ -204,22 +119,25 @@ end # TODO: ensure that r2 with offset actual gives right result @pure @propagate_inbounds function getindex( - r1::StaticRangeUnion{T1,B1,E1,S1,L1}, r2::StaticRange{T2,B2,E2,S2,L2}) where {T1,B1,E1,S1,L1,T2,B2,E2,S2,L2} - @boundscheck if B2 < 1 || E2 > L1 + r1::StaticRangeUnion{T1,B1,E1,S1,F1,L1}, r2::StaticRange{T2,B2,E2,S2,F2,L2}) where {T1,B1,E1,S1,F1,L1,T2,B2,E2,S2,F2,L2} + @boundscheck if B2 < F1 || E2 > L1 + F1 - 1 throw(BoundsError(r1, r2)) end - StaticRange{T1,T1(B1 + (B2-1) * S1),T1(B1 + (B2-1) * S1) + (L2-1)*(S1*S2),S1*S2,L2}() + StaticRange{T1,T1(B1 + (B2-1) * S1),T1(B1 + (B2-1) * S1) + (L2-1)*(S1*S2),S1*S2,1,L2}() end -@inline function Base.unsafe_copyto!( - dest::Ptr{T}, ::StaticRange{Int,B1,E1,S1,L}, - src::Ptr{T}, ::StaticRange{Int,B2,E2,S2,L}) where {B1,E1,S1,B2,E2,S2,L,T} - i = 1 - while i < L - unsafe_store!(dest, unsafe_load(src, B2 + (i-1) * S2)::T, B1 + (i-1) * S1) - i += 1 - end +@inline function getindex(a::Array{T}, inds::SubIndices) where T + @_propagate_inbounds_meta + @boundscheck checkbounds(a, inds) + out = Array{T}(undef, size(inds)) + unsafe_copyto!(pointer(out), OneToSRange{L}(), pointer(a), inds) + return out end - - +@inline function getindex( + a::StaticArray{S,T,N}, inds::SubIndices) where {S,T,N} + @boundscheck checkbounds(a, I) + ref = Ref{NTuple{length(inds),T}}() + unsafe_copyto!(convert(Ptr{T},Base.unsafe_convert(Ptr{Nothing}, ref)), OneToSRange{L}(), _unsafe_pointer(a), inds) + return similar_type(a, Size(L))(ref[]) +end diff --git a/src/multidimensional.jl b/src/multidimensional.jl deleted file mode 100644 index 424fd55..0000000 --- a/src/multidimensional.jl +++ /dev/null @@ -1,178 +0,0 @@ - -#Base.to_indices(A, I::Tuple{Vararg{Union{<:StaticRange,Integer,Colon},N}}) where N = SubIndices(A, I) - -function getindex(inds::LinearSIndices{S,N,L}, i::Int) where {S,N,L} - @_propagate_inbounds_meta - @boundscheck checkbounds(inds, i) - return i -end - -@pure function getindex(inds::LinearSIndices{S,N,L}, i::Int, ii::Int...) where {S,N,L} - @_propagate_inbounds_meta - @boundscheck checkbounds(inds, i, ii...) - stride = 1 - s2i = i - for D ∈ 2:N - stride *= fieldtype(S, D-1) - s2i += (stride * (ii[D-1] - 1)) - end - return s2i -end - -# tmpfunc(x) = @inbounds x[1,1] -@generated function getindex(inds::CartesianSIndices{S,N,L}, i::Int) where {S,N,L} - i2s = Vector{Expr}(undef, N) - ind = :(i - 1) - indnext = :() - for D in 1:N - indnext = :(div($ind, fieldtype(S, $D))) - i2s[D] = :($ind - fieldtype(S, $D) * $indnext + 1) - ind = indnext - end - return quote - @_propagate_inbounds_meta - @boundscheck checkbounds(inds, i) - CartesianIndex($(i2s...)) - end -end - -function getindex(inds::CartesianSIndices{S,N,L}, i::Int, ii::Int...) where {S,N,L} - @_propagate_inbounds_meta - @boundscheck checkbounds(inds, (i, ii...)) - return CartesianIndex(i, ii...) -end - - -@pure function getindex(si::SubLinearIndices{I,P,S,1,L}, i::Int) where {I,P,S,L} - @_propagate_inbounds_meta - @boundscheck checkbounds(si, i) - stride = 1 - ind = i - 1 - indnext = div(ind, fieldtype(S, 1)) - return ind - fieldtype(S, 1) * indnext + first(fieldtype(I, 1)) -end - -@generated function getindex(si::SubLinearIndices{I,P,S,N,L}, i::Int) where {I,P,S,N,L} - indnext = 0 - ind = :(i - 1) - indnext = :(div($ind, fieldtype(S, 1))) - i2i = :($ind - fieldtype(S, 1) * $indnext + first(fieldtype(I, 1))) - stride = :(fieldtype(P, 1)) - for D ∈ 2:N - ind = indnext - indnext = :(div($ind, fieldtype(S, $D))) - i2i = :($i2i + $stride * (($ind - fieldtype(S, $D) * $indnext + first(fieldtype(I, $D))) - 1)) - stride = :($stride * fieldtype(P, $D)) - end - return quote - @_propagate_inbounds_meta - @boundscheck checkbounds(si, i) - $i2i - end -end - - -# Multi-Dimensional - -@inline function getindex(a::Array{T}, inds::SubIndices) where T - @_propagate_inbounds_meta - @boundscheck checkbounds(a, inds) - out = Array{T}(undef, size(inds)) - unsafe_copyto!(pointer(out), OneToSRange{L}(), pointer(a), inds) - return out -end - -@inline function getindex( - a::StaticArray{S,T,N}, inds::SubIndices) where {S,T,N} - @boundscheck checkbounds(a, I) - ref = Ref{NTuple{length(inds),T}}() - unsafe_copyto!(convert(Ptr{T},Base.unsafe_convert(Ptr{Nothing}, ref)), OneToSRange{L}(), _unsafe_pointer(a), inds) - return similar_type(a, Size(L))(ref[]) -end - - - -############## -# unsafe_ops # -############## -# unsafe_copyto! -@inline function Base.unsafe_copyto!( - dest::Ptr{T}, si1::OneToSRange{L}, - src::Ptr{T}, si2::SubIndices{I,P,S,N,L}) where {T,I,P,S,N,L} - @inbounds for i in si1 - unsafe_coptyo!(dest, unsafe_load(src, si2[i]::Int)::T, i) - end -end - -@inline function Base.unsafe_copyto!( - dest::Ptr{T}, si1::SubIndices{I,P,S,N,L}, - src::Ptr{T}, si2::OneToSRange{L}) where {T,I,P,S,N,L} - @inbounds for i in OneToSRange{L}() - unsafe_coptyo!(dest, unsafe_load(src, i)::T, si1[i]::Int) - end -end - -@inline function Base.unsafe_copyto!( - dest::Ptr{T}, si1::SubIndices{I1,P1,S1,N1,L}, - src::AbstractArray{T}, si2::SubIndices{I2,P2,S2,N2,L}) where {T,I1,P1,S1,N1,I2,P2,S2,N2,L} - @_propagate_inbounds_meta - for i in OneToSRange{L}() - unsafe_coptyo!(dest, src[si2[i]]::T, si1[i]::Int) - end -end - -@inline function _unsafe_copyto!( - dest::AbstractArray{T}, si1::SubIndices{I1,P1,S1,N1,L}, - src::AbstractArray{T}, si2::SubIndices{I2,P2,S2,N2,L}) where {T,I1,P1,S1,N1,I2,P2,S2,N2,L} - @_propagate_inbounds_meta - for i in OneToSRange{L}() - dest[si1[i]] = src[si2[i]]::T - end -end - -@inline function Base.unsafe_copyto!( - dest::AbstractArray{T}, si1::SubIndices{I1,P1,S1,N1,L}, - src::Ptr{T}, si2::SubIndices{I2,P2,S2,N2,L}) where {T,I1,P1,S1,N1,I2,P2,S2,N2,L} - @_propagate_inbounds_meta - for i in OneToSRange{L}() - dest[si1[i]] = unsafe_load(src, si2[i])::T - end -end - -@inline function Base.unsafe_copyto!( - dest::Ptr{T}, si1::SubIndices{I1,P1,S1,N1,L}, - src::Ptr{T}, si2::SubIndices{I2,P2,S2,N2,L}) where {T,I1,P1,S1,N1,I2,P2,S2,N2,L} - @_propagate_inbounds_meta - for i in OneToSRange{L}() - unsafe_coptyo!(dest, unsafe_load(src, si2[i]::Int)::T, si1[i]::Int) - end -end - -# I/O -@inline function Base.unsafe_read(io::IO, ptr::Ptr{T}, r::StaticRange{Tr,B,E,S,L}) where {Tr,B,E,S,L,T} - for i in r - unsafe_store!(ptr, read(io, UInt8)::UInt8, i) - end -end - -@inline function Base.unsafe_read(io::IO, ptr::Ptr{T}, si::SubIndices{I,P,S,N,L}) where {T,I,P,S,N,L} - for i in si - unsafe_store!(ptr, read(io, UInt8)::UInt8, i) - end -end - -@inline function Base.unsafe_write(io::IO, ptr::Ptr{T}, r::StaticRange{Tr,B,E,S,L}) where {Tr,B,E,S,L,T} - written::Int = 0 - for i in si - written += write(io, unsafe_load(ptr, i)::T) - end - return written -end - -@inline function Base.unsafe_write(io::IO, ptr::Ptr{T}, si::SubIndices{I,P,S,N,L}) where {T,I,P,S,N,L} - written::Int = 0 - for i in si - written += write(io, unsafe_load(ptr, i)::T) - end - return written -end diff --git a/src/types.jl b/src/types.jl deleted file mode 100644 index cdc4739..0000000 --- a/src/types.jl +++ /dev/null @@ -1,269 +0,0 @@ -struct StaticRange{T,B,E,S,L} <: AbstractRange{T} - function StaticRange{T,B,E,S,L}() where {T,B,E,S,L} - (B*S) > E && error("StaticRange: the last index of a StaticRange cannot be less than the first index unless reverse indexing, got first = $B, and last = $E, step = $S.") - new{T,B,E,S,L}() - end -end - -const StaticRangeUnion{T,B,E,S,L} = Union{StaticRange{T,B,E,S,L},Type{<:StaticRange{T,B,E,S,L}}} - -const UnitSRange{T,B,E,L} = StaticRange{ T,B,E,1,L} -const OneToSRange{N} = StaticRange{Int,1,N,1,N} -OneToSRange(N::Int) = OneToSRange{N}() - -function StaticRange(start::Real, step::Real, stop::Real, length::Int) - B, E = promote(start, stop) - StaticRange{typeof(B),B,E,step,length}() -end - -StaticRange{B,E,S}() where {B,E,S,F} = StaticRange{B,E,S,F,floor(Int, (E-B)/S)+1}() -StaticRange{B,E,S,L}() where {B,E,S,F,L} = StaticRange{B,E,S,F,L,typeof(B+0*S)}() - -StaticRangeUnion{T,B,E,S,L} = Union{StaticRange{T,B,E,S,L},Type{<:StaticRange{T,B,E,S,L}}} - -srange(r::AbstractRange{T}) where T = StaticRange{T,first(r),last(r),step(r),length(r)}() - -""" - srange(start[, stop]; lengtyh, stop, step=1) - - -(see [`range`](@ref)) - -# Examples - -```jldoctest -julia> allequal(r1, r2) = all(ntuple(i->r1[i] == r2[i], length(r1))) - - -# UnitRange with length keyword -julia> base_range = range(1, length=100); - -julia> static_range = srange(1, length=100) -StaticRange: 1:1:100 - -julia> allequal(base_range, static_range) -true - - -# UnitRange with stop keyword -julia> base_range = range(1, stop=100); - -julia> static_range = srange(1, stop=100) -StaticRange: 1:1:100 - -julia> allequal(base_range, static_range) -true - - -# StepRange with step keyword -julia> base_range = range(1, 100, step=5) - -julia> static_range = srange(1, 100, step=5) -StaticRange: 1:5:96 - -julia> allequal(base_range, static_range) -true - - -# StepRange{Int64,Int64} with step keyword -julia> base_range = range(1, 100, step=5); - -julia> static_range = srange(1, 100, step=5) -StaticRange: 1:5:96 - -julia> allequal(base_range, static_range) -true - - -# StepRange{Int64,Int64} with step and length keywords -julia> base_range = range(1, step=5, length=100); - -julia> static_range = srange(1, step=5, length=100) -StaticRange: 1:5:496 - -julia> allequal(base_range, static_range) - -julia> base_range = StepRangeLen(1, 2, 20, 4) --5:2:33 - -``` - -Many of the same methods available to interface with ranges also applies to a -`StaticRange`. -```jldoctest -eltype(base_range) == eltype(static_range) -length(base_range) == length(static_range) -size(base_range) == size(static_range) -step(base_range) == step(static_range) - -first(base_range) == first(static_range) -last(base_range) == last(static_range) - -firstindex(base_range) == firstindex(static_range) -lastindex(base_range) == lastindex(static_range) - -``` - -""" - -srange(start::Real; length::Union{Integer,Nothing}=nothing, stop::Union{Real,Nothing}=nothing, step::Union{Real,Nothing}=nothing) = - _srange(start, step, stop, length) -# Blatantly copy range from base but adapt to StaticRange -srange(start::Real, stop::Real; length::Union{Integer,Nothing}=nothing, step::Union{Real,Nothing}=nothing) = - _srange2(start, step, stop, length) - -_srange2(start, ::Nothing, stop, ::Nothing) = - throw(ArgumentError("At least one of `length` or `step` must be specified")) - -_srange2(start, step, stop, length) = _srange(start, step, stop, length) - -# Range from start to stop: range(a, [step=s,] stop=b), no length -_srange(start, ::Nothing, stop, ::Nothing) = _staticrange(start, oftype(start, 1), stop, offset) -_srange(start::T, step, ::Nothing, len) where T = _staticrange(start, step, convert(T, start+step*(len-1)), offset) -#StaticRange(::Int64, ::Int64, ::Nothing, ::Int64) - - -# start, step, stop, length -_srange(a::AbstractFloat, ::Nothing, ::Nothing, len::Integer) = _srange(a, oftype(a, 1), nothing, len) -_srange(a::AbstractFloat, st::AbstractFloat, ::Nothing, len::Integer) = _srange(promote(a, st)..., nothing, len) -_srange( a::Real, st::AbstractFloat, ::Nothing, len::Integer) = _srange(float(a), st, nothing, len) -_srange(a::AbstractFloat, st::Real, ::Nothing, len::Integer) = _srange(a, float(st), nothing, len) -#_srange( a, ::Nothing, ::Nothing, len::Integer) = _srange(a, oftype(a-a, 1), nothing, len) -_srange( a::T, ::Nothing, ::Nothing, len::Integer) where T = StaticRange{T,a,T(a+len-1),T(1),len}() -_srange( a::T, ::Nothing, e::T, len::Integer) where T = StaticRange{T,a,e,T((e-a)/len),len}() -_srange( a, st, e, ::Nothing) = StaticRange(a, st, e, floor(Int, (e-a)/st)+1) - - -# TODO -#_range(start::T, ::Nothing, stop::T, len::Integer) where {T<:Real} = LinRange{T}(start, stop, len) - -## for Float16, Float32, and Float64 we hit twiceprecision.jl to lift to higher precision StepRangeLen -# for all other types we fall back to a plain old LinRange -#_linspace(::Type{T}, start::Integer, stop::Integer, len::Integer) where T = LinRange{T}(start, stop, len) - -#(last(r)-first(r))/r.lendiv -#StepRangeLen(start, step, floor(Int, (stop-start)/step)+1) -# Malformed calls -_srange(start, step, ::Nothing, ::Nothing) = # range(a, step=s) - throw(ArgumentError("At least one of `length` or `stop` must be specified")) -_srange(start, ::Nothing, ::Nothing, ::Nothing) = # range(a) - throw(ArgumentError("At least one of `length` or `stop` must be specified")) -_srange(::Nothing, ::Nothing, ::Nothing, ::Nothing) = # range(nothing) - throw(ArgumentError("At least one of `length` or `stop` must be specified")) -_srange(start::Real, step::Real, stop::Real, length::Integer) = # range(a, step=s, stop=b, length=l) - throw(ArgumentError("Too many arguments specified; try passing only one of `stop` or `length`")) -_srange(::Nothing, ::Nothing, ::Nothing, ::Integer) = # range(nothing, length=l) - throw(ArgumentError("Can't start a range at `nothing`")) - -""" -""" -abstract type StaticIndices{S<:Tuple,T,N,L} <: StaticArray{S,T,N} end - -""" - LinearSIndices - -```jldoctest -julia> A = reshape([1:30...], (5,6)); - -julia> li = LinearIndices((5,4,3,2,2)); - -julia> sli = LinearSIndices((5,4,3,2,2)); - -julia> inds = (srange(2:3), srange(2:3), srange(1:3), srange(1:2), srange(1:2)) - -julia> subli = SubLinearIndices(sli, inds) - -julia> subli[1] == sli[inds...][1] == li[inds...][1] - -julia> subli[2] == sli[inds...][2] == li[inds...][2] - -julia> subli[3] == sli[inds...][3] == li[inds...][3] - -``` -""" -struct LinearSIndices{S,N,L} <: StaticIndices{S,Int,N,L} - LinearSIndices{S}() where S = new{S,tuple_length(S),tuple_prod(S)}() -end - -LinearSIndices(ind::NTuple{N,Int}) where N = LinearSIndices{Tuple{ind...}}() -LinearSIndices(inds::Tuple{Vararg{<:StaticRange{Int},N}}) where N = LinearSIndices(ntuple(i->length(inds[i]), Val(N))) -LinearSIndices(inds::Vararg{<:StaticRange,N}) where N = LinearSIndices(ntuple(i->length(inds[i]), Val(N))) -LinearSIndices(A::AbstractArray) = LinearSIndices(size(A)) -LinearSIndices(A::StaticArray{S}) where S = LinearSIndices{S}() - -""" - CartesianSIndices -""" -struct CartesianSIndices{S,N,L} <: StaticIndices{S,CartesianIndex{N},N,L} - CartesianSIndices{S}() where S = new{S,tuple_length(S),tuple_prod(S)}() -end - -CartesianSIndices(ind::NTuple{N,Int}) where N = CartesianSIndices{Tuple{ind...}}() -CartesianSIndices(inds::Tuple{Vararg{<:StaticRange{Int},N}}) where N = CartesianSIndices(ntuple(i->length(inds[i]), Val(N))) -CartesianSIndices(inds::Vararg{<:StaticRange,N}) where N = CartesianSIndices(ntuple(i->length(inds[i]), Val(N))) -CartesianSIndices(A::AbstractArray) = CartesianSIndices(size(A)) -CartesianSIndices(A::StaticArray{S}) where S = CartesianSIndices{S}() - -""" - SubIndices -""" -abstract type SubIndices{I,P,S,T,N,L} <: StaticIndices{S,T,N,L} end - -@inline SubIndices(A::AbstractArray, I) = SubIndices(IndexStyle(A), A, I) -@inline SubIndices(::IndexLinear, A, I) = SubLinearIndices(A, I) -@inline SubIndices(::IndexCartesian, A, I) = SubCartesianIndices(A, I) - -""" - SubLinearIndices -""" -struct SubLinearIndices{I,P,S,N,L} <: SubIndices{I,P,S,Int,N,L} end - -SubLinearIndices{I,P}() where {I,P} = SubLinearIndices{I,P,Tuple{map(length, I.parameters)...}}() -SubLinearIndices{I,P,S}() where {I,P,S} = SubLinearIndices{I,P,S,tuple_length(S),tuple_prod(S)}() - -function SubLinearIndices(si::StaticIndices{S,T,N,L}, inds::Tuple{Vararg{<:StaticRange,N}}) where {S,T,N,L} - @_propagate_inbounds_meta - @boundscheck checkbounds(si, inds...) - SubLinearIndices{typeof(inds),S}() -end - -function SubLinearIndices(si::StaticIndices{S,T,N,L}, inds::Vararg{<:StaticRange,N}) where {S,T,N,L} - @_propagate_inbounds_meta - @boundscheck checkbounds(si, inds...) - SubLinearIndices{typeof(tuple(inds...)),S}() -end - -function SubLinearIndices(sz::NTuple{N,Int}, inds::Vararg{<:StaticRange,N}) where {S,T,N,L} - # TODO boundschecks - SubLinearIndices{typeof(tuple(inds...)),Tuple{sz...}}() -end -function SubLinearIndices(sz::NTuple{N,Int}, inds::Tuple{Vararg{<:StaticRange,N}}) where {S,T,N,L} - # TODO boundschecks - SubLinearIndices{typeof(tuple(inds...)),Tuple{sz...}}() -end - -""" - SubCartesianIndices -""" -struct SubCartesianIndices{I,P,S,N,L} <: SubIndices{I,P,S,CartesianIndex{N},N,L} end - -SubCartesianIndices{I,P}() where {I,P} = SubCartesianIndices{I,P,Tuple{map(length, inds)...}}() -SubCartesianIndices{I,P,S}() where {I,P,S} = SubCartesianIndices{I,P,S,tuple_length(S),tuple_prod(S)}() - -function SubCartesianIndices(si::StaticIndices{S,T,N,L}, inds::Tuple{Vararg{<:StaticRange,N}}) where {S,T,N,L} - @_propagate_inbounds_meta - @boundscheck checkbounds(si, inds...) - SubLinearIndices{typeof(inds),S}() -end - -function SubCartesianIndices(si::StaticIndices{S,T,N,L}, inds::Vararg{<:StaticRange,N}) where {S,T,N,L} - @_propagate_inbounds_meta - @boundscheck checkbounds(si, inds...) - SubLinearIndices{typeof(tuple(inds...)),S}() -end - - - - -# Indexing interface - diff --git a/src/utils.jl b/src/utils.jl index 05aabc6..cd7af6a 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -1,17 +1,3 @@ -Base.show(io::IO, r::StaticRange) = showrange(io, r) -Base.show(io::IO, ::MIME"text/plain", r::StaticRange) = showrange(io, r) - -function showrange(io::IO, r::StaticRange) - print(io, "StaticRange(") - show_mimic_range(io, r) - print(io, ")") -end - -#$(StaticRange)($(B):$(S):$(E))") -show_mimic_range(io::IO, ::StaticRange{T,B,E,S}) where {T,B,E,S} = print(io, "$(B):$(S):$(E)") -show_mimic_range(io::IO, ::UnitSRange{T,B,E,S}) where {T,B,E,S} = print(io, "$(B):$(E)") -show_mimic_range(io::IO, ::OneToSRange{N}) where {N} = print(io, "OneTo($(N))") - # ensure that sub range is integer (indexing) rane #function show_mimic_range(io::IO, ::SubRange{Bi,Ei,Si,Li,Bp,Ep,Sp,Lp,T}) where {Bi,Ei,Si,Li,Bp,Ep,Sp,Lp,T} # showmimicrange(io, SRange{Bp,Ep,Sp,Lp,T}()) @@ -36,48 +22,272 @@ show_mimic_range(io::IO, ::OneToSRange{N}) where {N} = print(io, "OneTo($(N))") #Base.show(io::IO, r::WindowRange) = showrange(io, r) #Base.show(io::IO, ::MIME"text/plain", r::WindowRange) = showrange(io, r) +# +# +#function showsindices(io::IO, inds::StaticAxes{Ax,S,T,N,L}) where {Ax,S,T,N,L} +# print(io, "$(join(size(inds), "x")) $(typeof(inds).name){$N}") +# showaxes(io, inds) +#end +# +#function showaxes(io::IO, inds::SubIndices{I,P,S,T,N,L}) where {I,P,S,T,N,L} +# for i in OneToSRange(N) +# print(io, "\n ", fieldtype(I, i)()) +# end +#end +# +#function showaxes(io::IO, inds::StaticAxes{Ax,S,T,N,L}) where {Ax,S,T,N,L} +# for i in OneToSRange(N) +# print(io, "\n ", axes(inds, i)) +# end +#end +# +# +#Base.show(io::IO, inds::StaticAxes) = showsindices(io, inds) +#Base.show(io::IO, ::MIME"text/plain", inds::StaticAxes) = showsindices(io, inds) -function showsindices(io::IO, inds::StaticIndices{S,T,N,L}) where {S,T,N,L} - print(io, "$(typeof(inds).name)") - showaxes(io, inds) +@pure function _fieldtype(t::Type{Tuple{T1}}, i::Int) where {T1} + if i == 1 + return T1 + else + throw(BoundsError(t, i)) + end end -function showaxes(io::IO, inds::SubIndices{I,P,S,T,N,L}) where {I,P,S,T,N,L} - for i in OneToSRange(N) - print(io, "\n ", fieldtype(I, i)()) +@inline @pure function _fieldtype(t::Type{Tuple{T1,T2}}, i::Int) where {T1,T2} + if i == 1 + return T1 + elseif i == 2 + return T2 + else + throw(BoundsError(t, i)) end end -function showaxes(io::IO, inds::StaticIndices{S,T,N,L}) where {S,T,N,L} - for i in OneToSRange(N) - print(io, "\n ", OneToSRange(fieldtype(S,i))) +@inline @pure function _fieldtype(t::Type{Tuple{T1,T2,T3}}, i::Int) where {T1,T2,T3} + if i < 3 + if i == 1 + return T1 + elseif i == 2 + return T2 + else + throw(BoundsError(t, i)) + end + else + if i == 3 + return T3 + else + throw(BoundsError(t, i)) + end end end +@inline @pure function _fieldtype(t::Type{Tuple{T1,T2,T3,T4}}, i::Int) where {T1,T2,T3,T4} + if i < 3 + if i == 1 + return T1 + else i == 2 + return T2 + end + else i < 5 + if i == 3 + return T3 + else + return T4 + end + end +end -#Base.show(io::IO, inds::StaticIndices) = showsindices(io, inds) -#Base.show(io::IO, ::MIME"text/plain", inds::StaticIndices) = showsindices(io, inds) +@pure function _fieldtype(t::Type{Tuple{T1,T2,T3,T4,T5}}, i::Int) where {T1,T2,T3,T4,T5} + if i < 5 + if i < 3 + if i == 1 + return T1 + elseif i == 2 + return T2 + end + else + if i == 3 + return T3 + else + return T4 + end + end + else + return T5 + end +end + +@pure function _fieldtype(t::Type{Tuple{T1,T2,T3,T4,T5,T6}}, i::Int) where {T1,T2,T3,T4,T5,T6} + if i < 5 + if i < 3 + if i == 1 + return T1 + else i == 2 + return T2 + end + else + if i == 3 + return T3 + else + return T4 + end + end + else + if i == 5 + return T5 + else + return T6 + end + end +end + +@pure function _fieldtype(t::Type{Tuple{T1,T2,T3,T4,T5,T6,T7}}, i::Int) where {T1,T2,T3,T4,T5,T6,T7} + if i < 5 + if i < 3 + if i == 1 + return T1 + else i == 2 + return T2 + end + else + if i == 3 + return T3 + else + return T4 + end + end + else + if i < 7 + if i == 5 + return T5 + else + return T6 + end + else + return T7 + end + end +end -# enable base range like interactions -@inline function Base.getproperty(r::StaticRange{T,B,E,S,L}, sym::Symbol) where {T,B,E,S,L} - if sym === :step - return step(r)::T - elseif sym === :start - return first(r)::T - elseif sym === :stop - return last(r)::T - elseif sym === :len - return length(r)::Int - elseif sym === :lendiv - return (E - B) / S - elseif sym === :ref # for now this is just treated the same as start - return B - elseif sym === :offset - return 1 # TODO: should probably go back and actually implement this +@pure function _fieldtype(t::Type{Tuple{T1,T2,T3,T4,T5,T6,T7,T8}}, i::Int) where {T1,T2,T3,T4,T5,T6,T7,T8} + if i < 5 + if i < 3 + if i == 1 + return T1 + else i == 2 + return T2 + end + else + if i == 3 + return T3 + else + return T4 + end + end else - error("type $(typeof(r)) has no field $sym") + if i < 7 + if i == 5 + return T5 + else + return T6 + end + else + if i == 7 + return T7 + else i == 8 + return T8 + end + end end end -#include("MDTraits/MDTraits.jl") +@pure function _fieldtype(t::Type{Tuple{T1,T2,T3,T4,T5,T6,T7,T8,T9}}, i::Int) where {T1,T2,T3,T4,T5,T6,T7,T8,T9} + if i < 9 + if i < 5 + if i < 3 + if i == 1 + return T1 + elseif i == 2 + return T2 + else + throw(BoundsError(t, i)) + end + else + if i == 3 + return T3 + else + return T4 + end + end + else + if i < 7 + if i == 5 + return T5 + else + return T6 + end + else + if i == 7 + return T7 + elseif i == 8 + return T8 + end + end + end + else + if i == 9 + return T9 + else + throw(BoundsError(t, i)) + end + end +end + +@pure function _fieldtype( + t::Type{Tuple{T1,T2,T3,T4,T5,T6,T7,T8,T9,T10}}, + i::Int) where {T1,T2,T3,T4,T5,T6,T7,T8,T9,T10} + if i < 9 + if i < 5 + if i < 3 + if i == 1 + return T1 + elseif i == 2 + return T2 + else + throw(BoundsError(t, i)) + end + else + if i == 3 + return T3 + else + return T4 + end + end + else + if i < 7 + if i == 5 + return T5 + else + return T6 + end + else + if i == 7 + return T7 + elseif i == 8 + return T8 + end + end + end + else + if i < 11 + if i == 9 + return T9 + else + return T10 + end + else + throw(BoundsError(t, i)) + end + end +end