From ccca50e0582fdbb6cd867282a8efce499dbb3b59 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sat, 2 Apr 2016 17:07:08 -0500 Subject: [PATCH] Use first/last as endpoints for Range indexing --- base/abstractarray.jl | 4 ++++ base/multidimensional.jl | 8 ++++---- base/operators.jl | 21 +++++++++++++++++++++ 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 68e85512e6df9..b783ecc125765 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -130,6 +130,10 @@ end checkbounds(::Type{Bool}, sz::Integer, i) = throw(ArgumentError("unable to check bounds for indices of type $(typeof(i))")) checkbounds(::Type{Bool}, sz::Integer, i::Real) = 1 <= i <= sz checkbounds(::Type{Bool}, sz::Integer, ::Colon) = true +checkbounds(::Type{Bool}, sz::Integer, i::EndpointRange{typeof(first),typeof(last)}) = true +checkbounds(::Type{Bool}, sz::Integer, i::EndpointRange{typeof(first),Int}) = 1 <= i.stop <= sz +checkbounds(::Type{Bool}, sz::Integer, i::EndpointRange{Int,typeof(last)}) = 1 <= i.start <= sz + function checkbounds(::Type{Bool}, sz::Integer, r::Range) @_propagate_inbounds_meta isempty(r) || (checkbounds(Bool, sz, minimum(r)) && checkbounds(Bool, sz, maximum(r))) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 142e1873b20fc..726b3336e54cb 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -210,15 +210,15 @@ index_shape_dim(A, dim, ::Colon) = (trailingsize(A, dim),) # ambiguities for AbstractArray subtypes. See the note in abstractarray.jl # Note that it's most efficient to call checkbounds first, and then to_index -@inline function _getindex(l::LinearIndexing, A::AbstractArray, I::Union{Real, AbstractArray, Colon}...) +@inline function _getindex(l::LinearIndexing, A::AbstractArray, I::Union{Real, AbstractArray, Colon, EndpointRange}...) @boundscheck checkbounds(A, I...) _unsafe_getindex(l, A, I...) end -@generated function _unsafe_getindex(::LinearIndexing, A::AbstractArray, I::Union{Real, AbstractArray, Colon}...) +@generated function _unsafe_getindex(::LinearIndexing, A::AbstractArray, I::Union{Real, AbstractArray, Colon, EndpointRange}...) N = length(I) quote # This is specifically *not* inlined. - @nexprs $N d->(I_d = to_index(I[d])) + @nexprs $N d->(I_d = to_index(A, d, I[d])) dest = similar(A, @ncall $N index_shape A I) @ncall $N checksize dest I @ncall $N _unsafe_getindex! dest A I @@ -305,7 +305,7 @@ _iterable(v) = repeated(v) _unsafe_setindex!(l, A, x, J...) end @inline function _unsafe_setindex!(::LinearIndexing, A::AbstractArray, x, J::Union{Real,AbstractArray,Colon}...) - _unsafe_batchsetindex!(A, _iterable(x), to_indexes(J...)...) + _unsafe_batchsetindex!(A, _iterable(x), to_array_indexes(A, J...)...) end # 1-d logical indexing: override the above to avoid calling find (in to_index) diff --git a/base/operators.jl b/base/operators.jl index cbe42c6c3339b..43eecde86c1e8 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -414,11 +414,32 @@ to_index(A::AbstractArray) = A to_index{T<:AbstractArray}(A::AbstractArray{T}) = throw(ArgumentError("invalid index: $A")) to_index(A::AbstractArray{Colon}) = throw(ArgumentError("invalid index: $A")) to_index(i) = throw(ArgumentError("invalid index: $i")) +to_index(A::AbstractArray, d, idx) = to_index(idx) + +# EndpointRanges (2:last, first:5, first:last) +typealias EndPoint Union{typeof(first), typeof(last)} + +immutable EndpointRange{F<:Union{Int,EndPoint},L<:Union{Int,EndPoint}} <: Range{Int} + start::F + stop::L +end + +colon(start::EndPoint, stop::EndPoint) = EndpointRange(start, stop) +colon(start::EndPoint, stop::Int) = EndpointRange(start, stop) +colon(start::Int, stop::EndPoint) = EndpointRange(start, stop) + +to_index(A::AbstractArray, d, idx::EndpointRange{typeof(first),typeof(last)}) = 1:size(A,d) +to_index(A::AbstractArray, d, idx::EndpointRange{typeof(first),Int}) = 1:idx.stop +to_index(A::AbstractArray, d, idx::EndpointRange{Int,typeof(last)}) = idx.start:size(A,d) to_indexes() = () to_indexes(i1) = (to_index(i1),) to_indexes(i1, I...) = (to_index(i1), to_indexes(I...)...) +to_array_indexes(A, I...) = _to_array_indexes(A, (), I...) +_to_array_indexes(A, out) = out +_to_array_indexes(A, out, i1, I...) = _to_array_indexes(A, (out..., to_index(A, length(out)+1, i1)), I...) + # Addition/subtraction of ranges for f in (:+, :-) @eval begin