Skip to content

Commit

Permalink
Take advantage of updates in ArrayInterface
Browse files Browse the repository at this point in the history
  • Loading branch information
Tokazama committed Oct 13, 2020
1 parent f993af0 commit 6d9c642
Show file tree
Hide file tree
Showing 11 changed files with 155 additions and 119 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "StaticRanges"
uuid = "d8176aec-3168-11e9-3c98-e3954798be3a"
authors = ["zchristensen "]
version = "0.8.1"
version = "0.8.2"

[deps]
ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"
Expand Down
57 changes: 56 additions & 1 deletion src/GapRange/GapRange.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,59 @@

include("type.jl")
include("getindex.jl")

# GapRange
unsafe_index_first(gr::GapRange, i) = @inbounds(getindex(first_range(gr), i))
function unsafe_index_last(gr::GapRange, i)
return @inbounds(getindex(last_range(gr), i .- first_length(gr)))
end

function Base.getindex(gr::GapRange, i::Integer)
@boundscheck checkbounds(gr, i)
return i <= first_length(gr) ? unsafe_index_first(gr, i) : unsafe_index_last(gr, i)
end

@propagate_inbounds function Base.getindex(r::AbstractRange, gr::GapRange)
fr = r[gr.first_range]
lr = r[gr.last_range]
return GapRange{eltype(r),typeof(fr),typeof(lr)}(fr, lr)
end

@propagate_inbounds function Base.getindex(gr::GapRange, v::AbstractRange)
@boundscheck checkbounds(gr, v)
fr = first_range(gr)
lr = last_range(gr)
if checkindexhi(fr, minimum(v))
if checkindexlo(lr, maximum(v))
return unsafe_spanning_getindex(gr, v)
else
# largest value of `v` is not found in last segment so only index first segment
return unsafe_index_first(gr, v)
end
else
# smallest value of `v` is not found in first segment so only index last segment
return unsafe_index_last(gr, v)
end
end

function unsafe_spanning_getindex(gr, v)
ltfli = find_all(<=(first_lastindex(gr)), v)
gtlfi = find_all(>=(last_firstindex(gr)), v)
if is_forward(v)
return _unsafe_gaprange(
unsafe_index_first(gr, @inbounds(v[ltfli])),
unsafe_index_last(gr, @inbounds(v[gtlfi]))
)
else # is_reverse(v)
return _unsafe_gaprange(
unsafe_index_last(gr, @inbounds(v[gtlfi])),
unsafe_index_first(gr, @inbounds(v[ltfli]))
)
end
end

Base.checkbounds(::Type{Bool}, gr::GapRange, i::Integer) = checkindex(Bool, gr, i)

function Base.checkindex(::Type{Bool}, gr::GapRange, i::Integer)
return checkindexlo(gr, i) & checkindexhi(gr, i)
end

71 changes: 0 additions & 71 deletions src/GapRange/getindex.jl

This file was deleted.

7 changes: 7 additions & 0 deletions src/GapRange/type.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

"""
GapRange{T,F,L}
Expand Down Expand Up @@ -173,3 +174,9 @@ Base.lastindex(gr::GapRange) = length(gr)

last_firstindex(gr::GapRange) = lastindex(first_range(gr)) + 1

function Base.AbstractArray{T}(gr::GapRange) where {T}
fr = AbstractRange{T}(gr.first_range)
lr = AbstractRange{T}(gr.last_range)
return GapRange{T,typeof(fr),typeof(lr)}(fr, lr)
end

3 changes: 2 additions & 1 deletion src/StaticRanges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ using Reexport
using ArrayInterface
using ArrayInterface: can_change_size, can_setindex, parent_type
using ArrayInterface: known_first, known_step, known_last, known_length
using ArrayInterface: OptionallyStaticUnitRange
using ArrayInterface: static_first, static_last
using ArrayInterface: OptionallyStaticUnitRange, unsafe_reconstruct, StaticInt, OptionallyStaticRange

using IntervalSets
using Requires
Expand Down
31 changes: 21 additions & 10 deletions src/first.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,12 @@ function set_first!(x::AbstractVector{T}, val) where {T}
return x
end

function set_first!(x::AbstractUnitRange{T}, val) where {T}
can_set_first(x) || throw(MethodError(set_first!, (x, val)))
function set_first!(x::UnitMRange{T}, val) where {T}
setfield!(x, :start, T(val))
return x
end

function set_first!(x::OrdinalRange{T,S}, val) where {T,S}
can_set_first(x) || throw(MethodError(set_first!, (x, val)))
function set_first!(x::StepMRange{T,S}, val) where {T,S}
val2 = T(val)
setfield!(x, :start, val2)
setfield!(x, :stop, Base.steprange_last(val2, step(x), last(x)))
Expand All @@ -67,6 +65,15 @@ function set_first!(x::StepMRangeLen{T,R}, val) where {T,R}
return setfield!(x, :ref, R(val) - (1 - x.offset) * step_hp(x))
end
set_first!(x::LinMRange{T}, val) where {T} = (setfield!(x, :start, T(val)); x)
function set_first!(x::AbstractRange, val)
if parent_type(x) <: typeof(x)
throw(MethodError(set_first!, (x, val)))
else
set_first!(parent(x), val)
return x
end
end


"""
set_first(x, val)
Expand All @@ -90,14 +97,18 @@ function set_first(x::AbstractVector, val)
return vcat(val, @inbounds(x[2:end]))
end
end

set_first(x::OrdinalRange, val) = typeof(x)(val, step(x), last(x))

set_first(x::AbstractUnitRange{T}, val) where {T} = typeof(x)(T(val), last(x))

set_first(x::OptionallyStaticRange, val) = val:ArrayInterface.static_step(x):static_last(x)
function set_first(x::AbstractRange{T}, val) where {T}
if parent_type(x) <: typeof(x)
throw(MethodError(set_first, (x, val)))
else
return ArrayInterface.unsafe_reconstruct(x, set_first(parent(x), val))
end
end
set_first(x::Union{<:StepRange,<:StepSRange,<:StepMRange}, val) = typeof(x)(val, step(x), last(x))
set_first(x::Union{<:UnitRange,<:UnitSRange,<:UnitMRange}, val) = typeof(x)(val, last(x))
set_first(x::AbstractStepRangeLen, val) = typeof(x)(val, step(x), x.len, x.offset)
set_first(x::StepRangeLen, val) = typeof(x)(val, step(x), x.len, x.offset)

set_first(x::LinRange, val) = typeof(x)(val, last(x), x.len)
set_first(x::AbstractLinRange, val) = typeof(x)(val, last(x), x.len)

Expand Down
59 changes: 37 additions & 22 deletions src/last.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,33 +46,37 @@ function set_last!(x::AbstractVector, val)
setindex!(x, val, lastindex(x))
return x
end

function set_last!(x::OrdinalRange{T}, val) where {T}
can_set_last(x) || throw(MethodError(set_last!, (x, val)))
if known_step(x) === oneunit(eltype(x))
if known_first(x) === oneunit(T)
setfield!(x, :stop, max(zero(T), T(val)))
else
setfield!(x, :stop, T(val))
end
else
setfield!(x, :stop, T(Base.steprange_last(first(x), step(x), val)))
end
return x
end

function set_last!(x::StepMRangeLen{T}, val) where {T}
len = unsafe_find_value(val, x) # FIXME should not use unsafe_find_value at this point
len >= 0 || throw(ArgumentError("length cannot be negative, got $len"))
1 <= x.offset <= max(1, len) || throw(ArgumentError("StepSRangeLen: offset must be in [1,$len], got $(x.offset)"))
setfield!(x, :len, len)
return x
end

function set_last!(x::LinMRange{T}, val) where {T}
setfield!(x, :stop, T(val))
return x
end
function set_last!(x::StepMRange{T}, val) where {T}
setfield!(x, :stop, T(Base.steprange_last(first(x), step(x), val)))
return x
end
function set_last!(x::UnitMRange{T}, val) where {T}
setfield!(x, :stop, T(val))
return x
end
function set_last!(x::OneToMRange{T}, val) where {T}
setfield!(x, :stop, max(zero(T), T(val)))
return x
end
function set_last!(x::AbstractRange, val)
if parent_type(x) <: typeof(x)
throw(MethodError(set_last!, (x, val)))
else
set_last!(parent(x), val)
return x
end
end

"""
set_last(x, val)
Expand All @@ -98,14 +102,25 @@ function set_last(x::AbstractVector, val)
return vcat(@inbounds(x[1:end-1]), val)
end
end

set_last(x::OrdinalRange, val) = typeof(x)(first(x), step(x), val)
set_last(x::AbstractUnitRange, val) = typeof(x)(first(x), val)
set_last(x::OneTo, val) = typeof(x)(val)
set_last(x::OneToSRange, val) = typeof(x)(val)
set_last(x::OneToMRange, val) = typeof(x)(val)
set_last(x::OptionallyStaticRange, val) = static_first(x):ArrayInterface.static_step(x):val
function set_last(x::AbstractRange{T}, val) where {T}
if parent_type(x) <: typeof(x)
throw(MethodError(set_last, (x, val)))
else
return ArrayInterface.unsafe_reconstruct(x, set_last(parent(x), val))
end
end
set_last(x::Union{<:StepRange,<:StepSRange,<:StepMRange}, val) = typeof(x)(first(x), step(x), val)
set_last(x::Union{<:UnitRange,<:UnitSRange,<:UnitMRange}, val) = typeof(x)(first(x), val)
set_last(x::Union{<:LinRange,<:LinMRange,<:LinSRange}, val) = typeof(x)(first(x), val, x.len)
function set_last(x::Union{<:StepRangeLen,<:StepMRangeLen,<:StepSRangeLen}, val)
return typeof(x)(x.ref, x.step, unsafe_find_value(val, x), x.offset)
end
@inline function set_last(x::Union{<:OneTo,<:OneToSRange,<:OneToMRange}, val)
if val isa StaticInt
return One():val
else
typeof(x)(val)
end
end

27 changes: 16 additions & 11 deletions src/length.jl
Original file line number Diff line number Diff line change
Expand Up @@ -124,22 +124,29 @@ function set_length!(x::StepMRangeLen, len)
return x
end

function set_length!(x::OrdinalRange{T}, len) where {T}
function set_length!(x::StepMRange{T}, len) where {T}
can_set_length(x) || throw(MethodError(set_length!, (x, len)))
setfield!(x, :stop, convert(T, first(x) + step(x) * (len - 1)))
return x
end

function set_length!(x::AbstractUnitRange{T}, len) where {T}
can_set_length(x) || throw(MethodError(set_length!, (x, len)))
if known_first(x) === one(T)
set_last!(x, len)
function set_length!(x::OneToMRange{T}, len) where {T}
set_last!(x, T(max(zero(T), len)))
return x
end
function set_length!(x::UnitMRange{T}, len) where {T}
set_last!(x, T(first(x)+len-1))
return x
end
function set_length!(x::AbstractRange, len)
if parent_type(x) <: typeof(x)
error("Cannot use set_length! for instances of typeof $(typeof(x)).")
else
set_last!(x, T(first(x)+len-1))
set_length!(parent(x), len)
return x
end
return x
end


"""
set_length(x, len)
Expand All @@ -157,15 +164,13 @@ set_length(x::AbstractStepRangeLen, len) = typeof(x)(x.ref, x.step, len, x.offse
set_length(x::StepRangeLen, len) = typeof(x)(x.ref, x.step, len, x.offset)
set_length(x::LinRange, len) = typeof(x)(first(x), last(x), len)
set_length(x::AbstractLinRange, len) = typeof(x)(first(x), last(x), len)

function set_length(x::AbstractUnitRange{T}, len) where {T}
if known_first(x) === oneunit(T)
return set_last(x, len)
else
return set_last(x, T(first(x)+len-1))
return set_last(x, static_first(x) + len - one(len))
end
end

function set_length(x::OrdinalRange{T}, len) where {T}
return set_last(x, convert(T, first(x) + step(x) * (len - 1)))
end
Expand Down
3 changes: 3 additions & 0 deletions src/onetorange.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ struct OneToSRange{T<:Integer,E} <: OneToRange{T}

OneToSRange{T,L}(stop) where {T<:Integer,L} = OneToSRange{T,T(stop)}()

OneToSRange{T,L}(r::AbstractRange) where {T<:Integer,L} = OneToSRange{T}(r)


function OneToSRange{T}(r::AbstractRange) where {T<:Integer}
first(r) == 1 || (Base.@_noinline_meta; throw(ArgumentError("first element must be 1, got $(first(r))")))
step(r) == 1 || (Base.@_noinline_meta; throw(ArgumentError("step must be 1, got $(step(r))")))
Expand Down
Loading

2 comments on commit 6d9c642

@Tokazama
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator register

Release notes:

  • Utilize new stuff in ArrayInterface
  • Make resizing methods more generic

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/22909

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.8.2 -m "<description of version>" 6d9c642d11043c28140f416875c571d4148f9d59
git push origin v0.8.2

Please sign in to comment.