-
Notifications
You must be signed in to change notification settings - Fork 44
Idempotent indexing in range[IdOffsetRange] #161
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Codecov Report
@@ Coverage Diff @@
## master #161 +/- ##
=======================================
Coverage 99.21% 99.21%
=======================================
Files 4 4
Lines 256 256
=======================================
Hits 254 254
Misses 2 2
Continue to review full report at Codecov.
|
bump |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks really nice a fix to me but I'd still want to invite @timholy to double-check it.
It's a bit suspicious that the bodies of all the new methods are identical. Can you instead modify the generic |
It appears to be a bit difficult to achieve this in general without introducing ambiguities, as some of the range types have specific indexing behaviors defined in function getindex(r::StepRange, s::AbstractRange{<:Integer}) and function getindex(r::StepRangeLen{T,<:TwicePrecision,<:TwicePrecision}, s::OrdinalRange{<:Integer}) where T presumably indicate that we should specialize on the second argument? |
Ah, yeah, good point. At some point we probably want to have some tests for this kind of thing that introduce a novel range object (could use https://github.com/JuliaArrays/CustomUnitRanges.jl to make that easy), just to make sure we go as far as we can with generic operations. |
I have no other objections, though. This clearly improves the handling of range values and range indices 👍. So merge at will. |
Yes indeed. The present approach is patchwork at best, and a new range type introduced will not support idempotent indexing with an For example: julia> struct MyUnitRange <: AbstractUnitRange{Int}
start :: Int
stop :: Int
end
julia> Base.first(r::MyUnitRange) = r.start
julia> Base.last(r::MyUnitRange) = r.stop
julia> s = MyUnitRange(2,3);
julia> r = OffsetArrays.IdOffsetRange(4:5, -3)
OffsetArrays.IdOffsetRange(1:2)
julia> axes(r)
(OffsetArrays.IdOffsetRange(-2:-1),)
julia> s[r]
2:3
julia> axes(s[r])
(Base.OneTo(2),) Ideally we should be able to define getindex(r::AbstractRange, inds::IdOffsetRange) however the problem with this is that a type that defines getindex(r::CustomRange, inds::AbstractUnitRange{<:Integer}) will run into ambiguities. |
I'm still a little confused about how things are working under the hood, but tests look good. Very concise a patch, I agree that we need tests to make sure things don't get break unexpectedly. |
I suspect it's a sign we may need better "inner methods" and implement the core range algorithms with them...although ranges are already pretty close to the metal. I suspect this is a multistage process, where we get this working and then rethink range implementation in Base. |
I've added methods that return an before julia> a = collect(1:10);
julia> ur = 3:6;
julia> idr = Base.IdentityUnitRange(2:4);
julia> @btime $a[$ur[$idr]];
98.796 ns (1 allocation: 112 bytes)
julia> idor = OffsetArrays.IdOffsetRange(1:3, 1);
julia> @btime $a[$ur[$idor]];
102.616 ns (1 allocation: 112 bytes) after julia> @btime $a[$ur[$idr]];
76.405 ns (1 allocation: 112 bytes)
julia> @btime $a[$ur[$idor]];
84.349 ns (1 allocation: 112 bytes) |
This is great work, thanks @jishnub! |
A new patch release, maybe? |
After this PR:
On master:
As a consequence,
on master:
after this PR: