From fa1f52d1bc08e04fe852f7360021b4153ed40253 Mon Sep 17 00:00:00 2001 From: Rafael Schouten Date: Tue, 12 Nov 2024 15:42:41 +0100 Subject: [PATCH] Simplify `selectindices` (#856) * simplify selectindices dispatch * reorgaise selectindices * simplify --- src/Lookups/selector.jl | 115 ++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 69 deletions(-) diff --git a/src/Lookups/selector.jl b/src/Lookups/selector.jl index 0f8cbf901..e421c64a1 100644 --- a/src/Lookups/selector.jl +++ b/src/Lookups/selector.jl @@ -79,16 +79,6 @@ const SelectorOrInterval = Union{Selector,Interval,Not} const SelTuple = Tuple{SelectorOrInterval,Vararg{SelectorOrInterval}} -# `Not` form InvertedIndices.jl -@inline function selectindices(l::Lookup, sel::Not; kw...) - indices = selectindices(l, sel.skip; kw...) - return first(to_indices(l, (Not(indices),))) -end -@inline function selectindices(l::Lookup, sel; kw...) - selstr = sprint(show, sel) - throw(ArgumentError("Invalid index `$selstr`. Did you mean `At($selstr)`? Use stardard indices, `Selector`s, or `Val` for compile-time `At`.")) -end - """ At <: IntSelector @@ -136,24 +126,6 @@ Base.show(io::IO, x::At) = print(io, "At(", val(x), ", ", atol(x), ", ", rtol(x) struct _True end struct _False end -@inline selectindices(l::Lookup, sel::At; kw...) = at(l, sel; kw...) -@inline selectindices(l::Lookup, sel::At{<:AbstractVector}; kw...) = - _selectvec(l, sel; kw...) -@inline selectindices(l::Lookup, sel::At{<:Tuple{<:Any,<:Any}}; kw...) = - _selecttuple(l, sel; kw...) -# Handle lookups of Tuple -@inline selectindices(l::Lookup{<:Tuple}, sel::At{<:Tuple}; kw...) = at(l, sel; kw...) -@inline selectindices(l::Lookup{<:Tuple}, sel::At{<:Tuple{<:Any,<:Any}}; kw...) = - at(l, sel; kw...) -@inline selectindices(l::Lookup{<:Tuple}, sel::At{<:Tuple{<:Tuple,<:Tuple}}; kw...) = - _selecttuple(l, sel; kw...) - -@inline _selectvec(l, sel; kw...) = [selectindices(l, rebuild(sel, v); kw...) for v in val(sel)] -@inline function _selecttuple(l, sel; kw...) - v1, v2 = _maybeflipbounds(l, val(sel)) - selectindices(l, rebuild(sel, v1); kw...):selectindices(l, rebuild(sel, v2); kw...) -end - function at(lookup::AbstractCyclic{Cycling}, sel::At; kw...) cycled_sel = rebuild(sel, cycle_val(lookup, val(sel))) return at(no_cycling(lookup), cycled_sel; kw...) @@ -288,13 +260,6 @@ end Near() = Near(nothing) Near(a, b) = Near((a, b)) -@inline selectindices(l::Lookup, sel::Near; kw...) = near(l, sel; kw...) -@inline selectindices(l::Lookup, sel::Near{<:AbstractVector}; kw...) = _selectvec(l, sel; kw...) -@inline selectindices(l::Lookup, sel::Near{<:Tuple}; kw...) = _selecttuple(l, sel; kw...) -# Handle lookups of Tuple -@inline selectindices(l::Lookup{<:Tuple}, sel::Near{<:Tuple}; kw...) = near(l, sel; kw...) -@inline selectindices(l::Lookup{<:Tuple}, sel::Near{<:Tuple{<:Tuple,<:Tuple}}; kw...) = _selecttuple(l, sel; kw...) - Base.show(io::IO, x::Near) = print(io, "Near(", val(x), ")") function near(lookup::AbstractCyclic{Cycling}, sel::Near; kw...) @@ -392,14 +357,11 @@ struct Contains{T} <: IntSelector{T} end Contains() = Contains(nothing) Contains(a, b) = Contains((a, b)) - -# Filter based on sampling and selector ----------------- -@inline selectindices(l::Lookup, sel::Contains; kw...) = contains(l, sel; kw...) -@inline selectindices(l::Lookup, sel::Contains{<:AbstractVector}; kw...) = _selectvec(l, sel; kw...) -@inline selectindices(l::Lookup, sel::Contains{<:Tuple}; kw...) = _selecttuple(l, sel; kw...) -# Handle lookups of Tuple -@inline selectindices(l::Lookup{<:Tuple}, sel::Contains{<:Tuple}; kw...) = contains(l, sel; kw...) -@inline selectindices(l::Lookup{<:Tuple}, sel::Contains{<:Tuple{<:Tuple,<:Tuple}}; kw...) = _selecttuple(l, sel; kw...) +@inline _selectvec(l, sel; kw...) = [selectindices(l, rebuild(sel, v); kw...) for v in val(sel)] +@inline function _selecttuple(l, sel; kw...) + v1, v2 = _maybeflipbounds(l, val(sel)) + selectindices(l, rebuild(sel, v1); kw...):selectindices(l, rebuild(sel, v2); kw...) +end Base.show(io::IO, x::Contains) = print(io, "Contains(", val(x), ")") @@ -612,14 +574,6 @@ abstract type _Side end struct _Upper <: _Side end struct _Lower <: _Side end -@inline selectindices(l::Lookup, sel::Union{Between{<:Tuple},Interval}) = between(l, sel) -@inline function selectindices(lookup::Lookup, sel::Between{<:AbstractVector}) - inds = Int[] - for v in val(sel) - append!(inds, selectindices(lookup, rebuild(sel, v))) - end -end - # between # returns a UnitRange from an Interval function between(l::Lookup, sel::Between) @@ -871,14 +825,6 @@ Touches(a, b) = Touches((a, b)) Base.first(sel::Touches) = first(val(sel)) Base.last(sel::Touches) = last(val(sel)) -@inline selectindices(l::Lookup, sel::Touches) = touches(l, sel) -@inline function selectindices(lookup::Lookup, sel::Touches{<:AbstractVector}) - inds = Int[] - for v in val(sel) - append!(inds, selectindices(lookup, rebuild(sel, v))) - end -end - # touches for tuple intervals # returns a UnitRange like Touches/Interval but for cells contained # NoIndex behaves like `Sampled` `ForwardOrdered` `Points` of 1:N Int @@ -1048,7 +994,7 @@ val(sel::Where) = sel.f Base.show(io::IO, x::Where) = print(io, "Where(", repr(val(x)), ")") # Yes this is everything. `Where` doesn't need lookup specialisation -@inline function selectindices(lookup::Lookup, sel::Where) +@inline function _selectindices(lookup::Lookup, sel::Where) [i for (i, v) in enumerate(parent(lookup)) if sel.f(v)] end @@ -1089,12 +1035,11 @@ All(args::SelectorOrInterval...) = All(args) Base.show(io::IO, x::All) = print(io, "All(", x.selectors, ")") -@inline function selectindices(lookup::Lookup, sel::All) +@inline function _selectindices(lookup::Lookup, sel::All) results = map(s -> selectindices(lookup, s), sel.selectors) sort!(union(results...)) end - # selectindices ========================================================================== @@ -1104,17 +1049,49 @@ end Converts [`Selector`](@ref) to regular indices. """ function selectindices end -@inline selectindices(lookups::LookupTuple, s1, ss...) = selectindices(lookups, (s1, ss...)) -@inline selectindices(lookups::LookupTuple, selectors::Tuple) = - map((l, s) -> selectindices(l, s), lookups, selectors) -@inline selectindices(lookups::LookupTuple, selectors::Tuple{}) = () +@inline selectindices(lookups::LookupTuple, s1, ss...; kw...) = + selectindices(lookups, (s1, ss...); kw...) +@inline selectindices(lookups::LookupTuple, selectors::Tuple; kw...) = + map((l, s) -> selectindices(l, s), lookups, selectors; kw...) +@inline selectindices(lookups::LookupTuple, selectors::Tuple{}; kw...) = () # @inline selectindices(dim::Lookup, sel::Val) = selectindices(val(dim), At(sel)) # Standard indices are just returned. -@inline selectindices(::Lookup, sel::StandardIndices) = sel +@inline selectindices(::Lookup, sel::StandardIndices; kw...) = sel + # Vectors are mapped -@inline selectindices(lookup::Lookup, sel::Selector{<:AbstractVector}) = - [selectindices(lookup, rebuild(sel; val=v)) for v in val(sel)] +@inline selectindices(lookup::Lookup, sel::Selector{<:AbstractVector}; kw...) = + Int[selectindices(lookup, rebuild(sel; val=v); kw...) for v in val(sel)] +# Tuples may become ranges, unless the lookup is a tuple +@inline selectindices(l::Lookup, sel::IntSelector{<:Tuple}; kw...) = + _selecttuple(l, sel; kw...) +@inline selectindices(l::Lookup{<:Tuple}, sel::IntSelector{<:Tuple}; kw...) = + _selectindices(l, sel; kw...) +@inline selectindices(l::Lookup{<:Tuple}, sel::IntSelector{<:Tuple{<:Tuple,<:Tuple}}; kw...) = + _selecttuple(l, sel; kw...) +selectindices(l::Lookup, sel::SelectorOrInterval; kw...) = _selectindices(l, sel; kw...) +# @inline function selectindices(l::Lookup, sel; kw...) +# selstr = sprint(show, sel) +# throw(ArgumentError("Invalid index `$selstr`. Did you mean `At($selstr)`? Use stardard indices, `Selector`s, or `Val` for compile-time `At`.")) +# end + +# Separated _selectindices methods reduce ambiguity issues +# `Not` form InvertedIndices.jl +@inline function _selectindices(l::Lookup, sel::Not; kw...) + indices = selectindices(l, sel.skip; kw...) + return first(to_indices(l, (Not(indices),))) +end +@inline _selectindices(l::Lookup, sel::Touches) = touches(l, sel) +@inline _selectindices(l::Lookup, sel::Union{Between{<:Tuple},Interval}) = between(l, sel) +@inline function _selectindices(lookup::Lookup, sel::Between{<:AbstractVector}) + inds = Int[] + for v in val(sel) + append!(inds, selectindices(lookup, rebuild(sel, v))) + end +end +@inline _selectindices(l::Lookup, sel::Contains; kw...) = contains(l, sel; kw...) +@inline _selectindices(l::Lookup, sel::Near; kw...) = near(l, sel; kw...) +@inline _selectindices(l::Lookup, sel::At; kw...) = at(l, sel; kw...) # Unaligned Lookup ------------------------------------------