From 4c2ae7e6e477a092b82ff84f8109aec996425b52 Mon Sep 17 00:00:00 2001 From: Tokazama Date: Mon, 18 Mar 2019 02:53:35 -0400 Subject: [PATCH] Modularize types and beginning of slidingwindow Getting clearer plan of type hierarchy so that easy adoption and customization can be done. Mulidimensional API aspect is still extremely variable though. SlidingWindow type is primitive (at best) but initial benchmarks for multidimensional indexers has been extremely promising. A lot of work has gone into benchmarking every API component. These are messy but likely useful to publish in the future, if I can get the time to put them together. Next update should have working multidimensional indexing and hopefully benchmarks to boot. --- src/SlidingWindow.jl | 168 +++++++++++++++++++ src/StaticAxes.jl | 352 ++++++++++++++++++++++------------------ src/StaticRange.jl | 152 +++++++++++++++++ src/StaticRanges.jl | 48 ------ src/abstractrange.jl | 84 ---------- src/checkbounds.jl | 38 ----- src/indexing.jl | 226 ++++++++------------------ src/multidimensional.jl | 178 -------------------- src/types.jl | 269 ------------------------------ src/utils.jl | 296 ++++++++++++++++++++++++++++----- 10 files changed, 840 insertions(+), 971 deletions(-) create mode 100644 src/SlidingWindow.jl create mode 100644 src/StaticRange.jl delete mode 100644 src/StaticRanges.jl delete mode 100644 src/abstractrange.jl delete mode 100644 src/checkbounds.jl delete mode 100644 src/multidimensional.jl delete mode 100644 src/types.jl 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