Skip to content

Commit

Permalink
Simplify A[1, end] lowering with lastindex(A, n) (#25763)
Browse files Browse the repository at this point in the history
This implements a new method of `lastindex` to specify a given dimension, and then uses that new method in the lowering of `end` within multi-dimensional indices.  Previously, this would have lowered directly to `last(axes(A, d))` for `end` in position `d`.  Given that `axes` (and multidimensional indexing generally) are array-centric concepts, I have only implemented this for `::AbstractArray`, with a deprecation for all other types suggesting implemention if sensible.  I have similarly defined `firstindex(A, d)` - it will be available for its syntax transformation in the future.
  • Loading branch information
mbauman authored and JeffBezanson committed Jan 27, 2018
1 parent 56b9593 commit eea727c
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 5 deletions.
4 changes: 3 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -997,7 +997,9 @@ Deprecated or removed

* `scale!` has been deprecated in favor of `mul!`, `mul1!`, and `mul2!` ([#25701]).

* `endof(a)` has been renamed to `lastindex(a)` ([#23554]).
* `endof(a)` has been renamed to `lastindex(a)`, and the `end` keyword in indexing expressions now
lowers to either `lastindex(a)` (in the case with only one index) or `lastindex(a, d)` (in cases
where there is more than one index and `end` appears at dimension `d`) ([#23554], [#25763]).

* `DateTime()`, `Date()`, and `Time()` have been deprecated, instead use `DateTime(1)`, `Date(1)`
and `Time(0)` respectively ([#23724]).
Expand Down
2 changes: 2 additions & 0 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ julia> lastindex([1,2,4])
```
"""
lastindex(a::AbstractArray) = (@_inline_meta; last(linearindices(a)))
lastindex(a::AbstractArray, n) = (@_inline_meta; last(axes(a, n)))

"""
firstindex(collection) -> Integer
Expand All @@ -189,6 +190,7 @@ julia> firstindex([1,2,4])
```
"""
firstindex(a::AbstractArray) = (@_inline_meta; first(linearindices(a)))
firstindex(a::AbstractArray, n) = (@_inline_meta; first(axes(a, n)))

first(a::AbstractArray) = a[first(eachindex(a))]

Expand Down
6 changes: 6 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1392,6 +1392,12 @@ function firstindex(a)
1
end

# PR 25763
function lastindex(a, n)
depwarn("if appropriate you should implement `lastindex(a, n)` for type $(typeof(a))`, which might just return `last(axes(a, n))`", :lastindex)
last(axes(a, n))
end

@deprecate Timer(timeout, repeat) Timer(timeout, interval = repeat)
@deprecate Timer(callback, delay, repeat) Time(callback, delay, interval = repeat)
@deprecate names(m, all) names(m, all = all)
Expand Down
6 changes: 3 additions & 3 deletions src/julia-syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,16 @@
;; the array `a` in the `n`th index.
;; `tuples` are a list of the splatted arguments that precede index `n`
;; `last` = is this last index?
;; returns a call to lastindex(a) or last(axes(a,n))
;; returns a call to lastindex(a) or lastindex(a,n)
(define (end-val a n tuples last)
(if (null? tuples)
(if (and last (= n 1))
`(call (top lastindex) ,a)
`(call (top last) (call (top axes) ,a ,n)))
`(call (top lastindex) ,a ,n))
(let ((dimno `(call (top +) ,(- n (length tuples))
,.(map (lambda (t) `(call (top length) ,t))
tuples))))
`(call (top last) (call (top axes) ,a ,dimno)))))
`(call (top lastindex) ,a ,dimno))))

;; replace `end` for the closest ref expression, so doesn't go inside nested refs
(define (replace-end ex a n tuples last)
Expand Down
11 changes: 10 additions & 1 deletion test/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,16 @@ function test_primitives(::Type{T}, shape, ::Type{TestAbstractArray}) where T
B = T(A)

# last(a)
@test last(B) == B[length(B)]
@test last(B) == B[lastindex(B)] == B[end] == A[end]
@test lastindex(B) == lastindex(A) == last(linearindices(B))
@test lastindex(B, 1) == lastindex(A, 1) == last(axes(B, 1))
@test lastindex(B, 2) == lastindex(A, 2) == last(axes(B, 2))

# first(a)
@test first(B) == B[firstindex(B)] == B[1] == A[1] # TODO: use B[begin] once parser transforms it
@test firstindex(B) == firstindex(A) == first(linearindices(B))
@test firstindex(B, 1) == firstindex(A, 1) == first(axes(B, 1))
@test firstindex(B, 2) == firstindex(A, 2) == first(axes(B, 2))

# isassigned(a::AbstractArray, i::Int...)
j = rand(1:length(B))
Expand Down
3 changes: 3 additions & 0 deletions test/offsetarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,9 @@ cv = copy(v)
@test reverse!(cv) == rv

A = OffsetArray(rand(4,4), (-3,5))
@test lastindex(A) == 16
@test lastindex(A, 1) == 1
@test lastindex(A, 2) == 9
@test A A
@test axes(A') === (6:9, -2:1)
@test parent(copy(A')) == copy(parent(A)')
Expand Down

0 comments on commit eea727c

Please sign in to comment.