Skip to content

Commit

Permalink
Revamp find related methods (#20)
Browse files Browse the repository at this point in the history
This creates operation specific find methods internally and implements supporting methods for manipulating ranges. There's also a more thorough testing of inference.
  • Loading branch information
Tokazama authored Apr 3, 2020
1 parent c17807f commit 8017458
Show file tree
Hide file tree
Showing 43 changed files with 1,785 additions and 560 deletions.
8 changes: 6 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
name = "StaticRanges"
uuid = "d8176aec-3168-11e9-3c98-e3954798be3a"
authors = ["zchristensen "]
version = "0.5.12"
version = "0.6.0"

[deps]
ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953"
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"

[compat]
ArrayInterface = "2"
IntervalSets = "0.4"
OffsetArrays = "1"
StaticArrays = "0.12.1"
julia = "1"

[extras]
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953"
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Test", "Dates", "Documenter", "IntervalSets"]
test = ["Test", "Dates", "Documenter", "IntervalSets", "OffsetArrays", "StaticArrays"]
52 changes: 47 additions & 5 deletions src/StaticRanges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,14 @@ using Base: @propagate_inbounds, @pure
using Base.Broadcast: DefaultArrayStyle

using Dates
using StaticArrays, ArrayInterface, IntervalSets
using ArrayInterface: can_setindex
using StaticArrays
using ArrayInterface
using IntervalSets
using OffsetArrays

using StaticArrays: Dynamic
using ArrayInterface: can_setindex
using OffsetArrays: IdOffsetRange

export
# Types
Expand Down Expand Up @@ -67,13 +72,23 @@ export
as_fixed,
mrange,
srange,
# find
find_first,
find_firsteq,
find_firstgt,
find_firstlt,
find_firstgteq,
find_firstlteq,
find_last,
find_lasteq,
find_lastgt,
find_lastlt,
find_lastgteq,
find_lastlteq,
findin,
find_all,
find_max,
find_min,
first_segment,
last_segment,
# Traits
parent_type,
axes_type,
Expand All @@ -85,7 +100,6 @@ export
is_static,
is_within,
merge_sort,
middle_segment,
push,
pushfirst,
set_first!,
Expand Down Expand Up @@ -125,6 +139,18 @@ const LinRangeUnion{T} = Union{LinRange{T},AbstractLinRange{T}}
const StepRangeUnion{T,S} = Union{StepRange{T,S},AbstractStepRange{T,S}}
const UnitRangeUnion{T} = Union{UnitRange{T},UnitSRange{T},UnitMRange{T}}

# Things I have to had to avoid ambiguities with base
RANGE_LIST = (LinSRange, LinMRange, StepSRange, StepMRange, UnitSRange, UnitMRange, OneToSRange, OneToMRange, StepSRangeLen, StepMRangeLen)

for R in RANGE_LIST
@eval begin
function Base.findfirst(f::Union{Base.Fix2{typeof(==),T}, Base.Fix2{typeof(isequal),T}}, r::$R) where T<:Integer
return find_first(f, r)
end
end
end


const SRange{T} = Union{OneToSRange{T},UnitSRange{T},StepSRange{T},LinSRange{T},StepSRangeLen{T}}
const MRange{T} = Union{OneToMRange{T},UnitMRange{T},StepMRange{T},LinMRange{T},StepMRangeLen{T}}
const UnionRange{T} = Union{SRange{T},MRange{T}}
Expand Down Expand Up @@ -235,4 +261,20 @@ include("push.jl")
include("show.jl")
include("vcat.jl")

include("find_firsteq.jl")
include("find_firstgt.jl")
include("find_firstlt.jl")
include("find_firstgteq.jl")
include("find_firstlteq.jl")

include("find_lasteq.jl")
include("find_lastgt.jl")
include("find_lastlt.jl")
include("find_lastgteq.jl")
include("find_lastlteq.jl")

include("resize.jl")

include("offset_range.jl")

end
2 changes: 1 addition & 1 deletion src/abstractlinrange.jl
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ for (F,f) in ((:M,:m), (:S,:s))
convert(T, +(first(r1), first(r2))),
convert(T, +(last(r1), last(r2))),
len
)
)
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions src/abstractsteprange.jl
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,7 @@ for (F,f) in ((:M,:m), (:S,:s))
SR = Symbol(:Step, F, :Range)
frange = Symbol(f, :range)
@eval begin
function Base.getindex(r::$(SR), s::AbstractRange{<:Integer})
Base.@_inline_meta
@inline function Base.getindex(r::$(SR), s::AbstractRange{<:Integer})
@boundscheck checkbounds(r, s)
st = oftype(first(r), first(r) + (first(s)-1)*step(r))
return $(frange)(st, step=step(r)*step(s), length=length(s))
Expand All @@ -97,3 +96,4 @@ end

is_static(::Type{<:StepSRange}) = true
is_fixed(::Type{<:StepMRange}) = false

9 changes: 6 additions & 3 deletions src/chainedfix.jl
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,11 @@ const BitAnd{F1,F2} = ChainedFix{typeof(and),F1,F2}

const BitOr{F1,F2} = ChainedFix{typeof(or),F1,F2}

const F2Lt{T} = Fix2{<:Union{typeof(<),typeof(<=)},T}
const F2Gt{T} = Fix2{<:Union{typeof(>),typeof(>=)},T}
const F2Eq{T} = Fix2{<:Union{typeof(isequal),typeof(==)},T}
const Fix2Lt{T} = Union{Fix2{typeof(<),T},Fix2{typeof(isless),T}}

const Fix2Eq{T} = Union{Fix2{typeof(==),T},Fix2{typeof(isequal),T}}

const F2LtAndLtEq{T} = Fix2{<:Union{typeof(<),typeof(<=)},T}
const F2GtAndGtEq{T} = Fix2{<:Union{typeof(>),typeof(>=)},T}
const F2IsLess{T} = Fix2{<:Union{typeof(isless),typeof(<)},T}

1 change: 0 additions & 1 deletion src/checkindex.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ checkindexlo(r, i::AbstractVector) = checkindexlo(r, minimum(i))
checkindexlo(r, i) = firstindex(r) <= i
checkindexlo(r, i::CartesianIndex{1}) = firstindex(r) <= first(i.I)


checkindexhi(r, i::AbstractVector) = checkindexhi(r, maximum(i))
checkindexhi(r, i) = lastindex(r) >= i
checkindexhi(r, i::CartesianIndex{1}) = firstindex(r) <= first(i.I)
Expand Down
15 changes: 15 additions & 0 deletions src/find_firsteq.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

@propagate_inbounds function find_firsteq(x, r::AbstractRange)
@boundscheck if !in(x, r)
return nothing
end
return unsafe_findvalue(x, r)
end

function find_firsteq(x, a)
for (i, a_i) in pairs(a)
x == a_i && return i
end
return nothing
end

91 changes: 91 additions & 0 deletions src/find_firstgt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@

find_firstgt(x, r::OneToUnion) = _find_firstgt_oneto(x, r)

@inline function _find_firstgt_oneto(x::Integer, r)
if x >= last(r)
return nothing
elseif x < 1
return 1
else
return x + 1
end
end

@inline function _find_firstgt_oneto(x, r)
idx = round(Integer, x, RoundUp)
if idx > x
if idx < 1
return nothing
elseif idx >= last(r)
return 1
else
return idx
end
else
return _find_firstgt_oneto(idx, r)
end
end

find_firstgt(x, r::AbstractUnitRange) = _find_firstgt_unit(x, r)

@inline function _find_firstgt_unit(x::Integer, r)
if x >= last(r)
return nothing
elseif x < first(r)
return firstindex(r)
else
# b/c +1 get's to the value isequal and we want greater
return (x - first(r)) + 2
end
end

@inline function _find_firstgt_unit(x, r)
xnew = round(Integer, x, RoundUp)
if xnew > x
if xnew >= lastindex(r)
return nothing
elseif xnew < firstindex(r)
return firstindex(r)
else
return unsafe_findvalue(xnew, r)
end
else
return _find_firstgt_unit(xnew, r)
end
end

@inline function find_firstgt(x, r::AbstractRange{T}) where {T}
if step(r) > zero(T)
idx = unsafe_findvalue(x, r)
if idx < firstindex(r)
return firstindex(r)
elseif idx > lastindex(r)
return nothing
elseif (@inbounds(r[idx]) == x) & (idx != lastindex(r))
return idx + oneunit(idx)
else
return nothing
end
elseif step(r) < zero(T)
idx = unsafe_findvalue(x, r)
if idx > lastindex(r)
return lastindex(r)
elseif idx < firstindex(r)
return nothing
elseif (@inbounds(r[idx]) == x) & (idx != firstindex(r))
return idx - oneunit(idx)
else
return nothing
end
else # isempty(r)
return nothing
end
end

function find_firstgt(x, a)
for (i, a_i) in pairs(a)
a_i > x && return i
end
return nothing
end

52 changes: 52 additions & 0 deletions src/find_firstgteq.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@

find_firstgteq(x, r::AbstractUnitRange) = _find_firstgteq_unit(x, r)
function _find_firstgteq_unit(x::Integer, r)
if x > last(r)
return nothing
elseif x < first(r)
return firstindex(r)
else
return unsafe_findvalue(x, r)
end
end

function _find_firstgteq_unit(x, r)
if last(r) < x
return nothing
elseif first(r) > x
return firstindex(r)
else
return _find_firstgteq_unit(round(Integer, x, RoundUp), r)
end
end

@inline function find_firstgteq(x, r::AbstractRange{T}) where {T}
if step(r) > zero(T)
idx = unsafe_findvalue(x, r)
if lastindex(r) < idx
return nothing
elseif firstindex(r) > idx
return firstindex(r)
elseif @inbounds(r[idx]) == x
return idx
else
return idx + oneunit(idx)
end
elseif step(r) < zero(T)
if first(r) >= x
return firstindex(r)
else
return nothing
end
else # isempty(r)
return nothing
end
end

function find_firstgteq(x, a)
for (i, a_i) in pairs(a)
a_i >= x && return i
end
return nothing
end

39 changes: 39 additions & 0 deletions src/find_firstlt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

@inline function find_firstlt(x, r::AbstractUnitRange)
if first(r) >= x
return nothing
else
return firstindex(r)
end
end

@inline function find_firstlt(x, r::AbstractRange{T}) where {T}
if step(r) > zero(T)
if first(r) >= x
return nothing
else
return firstindex(r)
end
elseif step(r) < zero(T)
idx = unsafe_findvalue(x, r)
if lastindex(r) <= idx
return nothing
elseif firstindex(r) > idx
return firstindex(r)
elseif @inbounds(r[idx]) < x
return idx
else
return idx + oneunit(idx)
end
else
return nothing
end
end

function find_firstlt(x, a)
for (i, a_i) in pairs(a)
a_i < x && return i
end
return nothing
end

Loading

2 comments on commit 8017458

@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
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/12145

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.6.0 -m "<description of version>" 8017458a0fe30c1701c5d1b7bcfd58eceda9dde7
git push origin v0.6.0

Please sign in to comment.