Skip to content

Commit 7f274a0

Browse files
committed
Deprecate linearindices in favor of LinearIndices
LinearIndices is strictly more powerful than linearindices: these two functions return arrays holding the same elements, but the former also preserves the shape and indices of the original array. Also improve docstrings.
1 parent 18ac6e6 commit 7f274a0

27 files changed

+193
-179
lines changed

NEWS.md

+6-3
Original file line numberDiff line numberDiff line change
@@ -624,8 +624,10 @@ Library improvements
624624
other containers, by taking the multiplicity of the arguments into account.
625625
Use `unique` to get the old behavior.
626626

627-
* The type `LinearIndices` has been added, providing conversion from
628-
cartesian indices to linear indices using the normal indexing operation. ([#24715])
627+
* The `linearindices` function has been deprecated in favor of the new
628+
`LinearIndices` type, which additionnally provides conversion from
629+
cartesian indices to linear indices using the normal indexing operation.
630+
([#24715], [#26775]).
629631

630632
* `IdDict{K,V}` replaces `ObjectIdDict`. It has type parameters
631633
like other `AbstractDict` subtypes and its constructors mirror the
@@ -1446,4 +1448,5 @@ Command-line option changes
14461448
[#26436]: https://github.com/JuliaLang/julia/issues/26436
14471449
[#26442]: https://github.com/JuliaLang/julia/issues/26442
14481450
[#26600]: https://github.com/JuliaLang/julia/issues/26600
1449-
[#26670]: https://github.com/JuliaLang/julia/issues/26670
1451+
[#26670]: https://github.com/JuliaLang/julia/issues/26670
1452+
[#26775]: https://github.com/JuliaLang/julia/issues/26775

base/abstractarray.jl

+18-83
Original file line numberDiff line numberDiff line change
@@ -96,33 +96,8 @@ indices1(iter) = OneTo(length(iter))
9696
unsafe_indices(A) = axes(A)
9797
unsafe_indices(r::AbstractRange) = (OneTo(unsafe_length(r)),) # Ranges use checked_sub for size
9898

99-
"""
100-
linearindices(A)
101-
102-
Return a `UnitRange` specifying the valid range of indices for `A[i]`
103-
where `i` is an `Int`. For arrays with conventional indexing (indices
104-
start at 1), or any multidimensional array, this is `1:length(A)`;
105-
however, for one-dimensional arrays with unconventional indices, this
106-
is `axes(A, 1)`.
107-
108-
Calling this function is the "safe" way to write algorithms that
109-
exploit linear indexing.
110-
111-
# Examples
112-
```jldoctest
113-
julia> A = fill(1, (5,6,7));
114-
115-
julia> b = linearindices(A);
116-
117-
julia> extrema(b)
118-
(1, 210)
119-
```
120-
"""
121-
linearindices(A::AbstractArray) = (@_inline_meta; OneTo(_length(A)))
122-
linearindices(A::AbstractVector) = (@_inline_meta; indices1(A))
123-
12499
keys(a::AbstractArray) = CartesianIndices(axes(a))
125-
keys(a::AbstractVector) = linearindices(a)
100+
keys(a::AbstractVector) = LinearIndices(a)
126101

127102
prevind(::AbstractArray, i::Integer) = Int(i)-1
128103
nextind(::AbstractArray, i::Integer) = Int(i)+1
@@ -187,7 +162,7 @@ julia> lastindex(rand(3,4,5), 2)
187162
4
188163
```
189164
"""
190-
lastindex(a::AbstractArray) = (@_inline_meta; last(linearindices(a)))
165+
lastindex(a::AbstractArray) = (@_inline_meta; last(LinearIndices(a)))
191166
lastindex(a::AbstractArray, d) = (@_inline_meta; last(axes(a, d)))
192167

193168
"""
@@ -205,7 +180,7 @@ julia> firstindex(rand(3,4,5), 2)
205180
1
206181
```
207182
"""
208-
firstindex(a::AbstractArray) = (@_inline_meta; first(linearindices(a)))
183+
firstindex(a::AbstractArray) = (@_inline_meta; first(LinearIndices(a)))
209184
firstindex(a::AbstractArray, d) = (@_inline_meta; first(axes(a, d)))
210185

211186
first(a::AbstractArray) = a[first(eachindex(a))]
@@ -321,49 +296,6 @@ function trailingsize(inds::Indices)
321296
prod(map(unsafe_length, inds))
322297
end
323298

324-
## Traits for array types ##
325-
326-
abstract type IndexStyle end
327-
struct IndexLinear <: IndexStyle end
328-
struct IndexCartesian <: IndexStyle end
329-
330-
"""
331-
IndexStyle(A)
332-
IndexStyle(typeof(A))
333-
334-
`IndexStyle` specifies the "native indexing style" for array `A`. When
335-
you define a new `AbstractArray` type, you can choose to implement
336-
either linear indexing or cartesian indexing. If you decide to
337-
implement linear indexing, then you must set this trait for your array
338-
type:
339-
340-
Base.IndexStyle(::Type{<:MyArray}) = IndexLinear()
341-
342-
The default is `IndexCartesian()`.
343-
344-
Julia's internal indexing machinery will automatically (and invisibly)
345-
convert all indexing operations into the preferred style. This allows users
346-
to access elements of your array using any indexing style, even when explicit
347-
methods have not been provided.
348-
349-
If you define both styles of indexing for your `AbstractArray`, this
350-
trait can be used to select the most performant indexing style. Some
351-
methods check this trait on their inputs, and dispatch to different
352-
algorithms depending on the most efficient access pattern. In
353-
particular, [`eachindex`](@ref) creates an iterator whose type depends
354-
on the setting of this trait.
355-
"""
356-
IndexStyle(A::AbstractArray) = IndexStyle(typeof(A))
357-
IndexStyle(::Type{Union{}}) = IndexLinear()
358-
IndexStyle(::Type{<:AbstractArray}) = IndexCartesian()
359-
IndexStyle(::Type{<:Array}) = IndexLinear()
360-
IndexStyle(::Type{<:AbstractRange}) = IndexLinear()
361-
362-
IndexStyle(A::AbstractArray, B::AbstractArray) = IndexStyle(IndexStyle(A), IndexStyle(B))
363-
IndexStyle(A::AbstractArray, B::AbstractArray...) = IndexStyle(IndexStyle(A), IndexStyle(B...))
364-
IndexStyle(::IndexLinear, ::IndexLinear) = IndexLinear()
365-
IndexStyle(::IndexStyle, ::IndexStyle) = IndexCartesian()
366-
367299
## Bounds checking ##
368300

369301
# The overall hierarchy is
@@ -411,10 +343,11 @@ function checkbounds(::Type{Bool}, A::AbstractArray, I...)
411343
@_inline_meta
412344
checkbounds_indices(Bool, axes(A), I)
413345
end
346+
414347
# Linear indexing is explicitly allowed when there is only one (non-cartesian) index
415348
function checkbounds(::Type{Bool}, A::AbstractArray, i)
416349
@_inline_meta
417-
checkindex(Bool, linearindices(A), i)
350+
checkindex(Bool, eachindex(IndexLinear(), A), i)
418351
end
419352
# As a special extension, allow using logical arrays that match the source array exactly
420353
function checkbounds(::Type{Bool}, A::AbstractArray{<:Any,N}, I::AbstractArray{Bool,N}) where N
@@ -674,7 +607,7 @@ function copyto!(dest::AbstractArray, dstart::Integer, src, sstart::Integer, n::
674607
n < 0 && throw(ArgumentError(string("tried to copy n=", n, " elements, but n should be nonnegative")))
675608
n == 0 && return dest
676609
dmax = dstart + n - 1
677-
inds = linearindices(dest)
610+
inds = LinearIndices(dest)
678611
if (dstart inds || dmax inds) | (sstart < 1)
679612
sstart < 1 && throw(ArgumentError(string("source start offset (",sstart,") is < 1")))
680613
throw(BoundsError(dest, dstart:dmax))
@@ -704,7 +637,7 @@ copyto!(dest::AbstractArray, src::AbstractArray) =
704637
copyto!(IndexStyle(dest), dest, IndexStyle(src), src)
705638

706639
function copyto!(::IndexStyle, dest::AbstractArray, ::IndexStyle, src::AbstractArray)
707-
destinds, srcinds = linearindices(dest), linearindices(src)
640+
destinds, srcinds = LinearIndices(dest), LinearIndices(src)
708641
isempty(srcinds) || (first(srcinds) destinds && last(srcinds) destinds) ||
709642
throw(BoundsError(dest, srcinds))
710643
@inbounds for i in srcinds
@@ -714,7 +647,7 @@ function copyto!(::IndexStyle, dest::AbstractArray, ::IndexStyle, src::AbstractA
714647
end
715648

716649
function copyto!(::IndexStyle, dest::AbstractArray, ::IndexCartesian, src::AbstractArray)
717-
destinds, srcinds = linearindices(dest), linearindices(src)
650+
destinds, srcinds = LinearIndices(dest), LinearIndices(src)
718651
isempty(srcinds) || (first(srcinds) destinds && last(srcinds) destinds) ||
719652
throw(BoundsError(dest, srcinds))
720653
i = 0
@@ -725,11 +658,11 @@ function copyto!(::IndexStyle, dest::AbstractArray, ::IndexCartesian, src::Abstr
725658
end
726659

727660
function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray)
728-
copyto!(dest, dstart, src, first(linearindices(src)), _length(src))
661+
copyto!(dest, dstart, src, first(LinearIndices(src)), _length(src))
729662
end
730663

731664
function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray, sstart::Integer)
732-
srcinds = linearindices(src)
665+
srcinds = LinearIndices(src)
733666
sstart srcinds || throw(BoundsError(src, sstart))
734667
copyto!(dest, dstart, src, sstart, last(srcinds)-sstart+1)
735668
end
@@ -739,7 +672,7 @@ function copyto!(dest::AbstractArray, dstart::Integer,
739672
n::Integer)
740673
n == 0 && return dest
741674
n < 0 && throw(ArgumentError(string("tried to copy n=", n, " elements, but n should be nonnegative")))
742-
destinds, srcinds = linearindices(dest), linearindices(src)
675+
destinds, srcinds = LinearIndices(dest), LinearIndices(src)
743676
(dstart destinds && dstart+n-1 destinds) || throw(BoundsError(dest, dstart:dstart+n-1))
744677
(sstart srcinds && sstart+n-1 srcinds) || throw(BoundsError(src, sstart:sstart+n-1))
745678
@inbounds for i = 0:(n-1)
@@ -868,11 +801,13 @@ function eachindex(A::AbstractArray, B::AbstractArray...)
868801
@_inline_meta
869802
eachindex(IndexStyle(A,B...), A, B...)
870803
end
871-
eachindex(::IndexLinear, A::AbstractArray) = linearindices(A)
804+
eachindex(::IndexLinear, A::AbstractArray) = (@_inline_meta; OneTo(_length(A)))
805+
eachindex(::IndexLinear, A::AbstractVector) = (@_inline_meta; indices1(A))
872806
function eachindex(::IndexLinear, A::AbstractArray, B::AbstractArray...)
873807
@_inline_meta
874-
indsA = linearindices(A)
875-
_all_match_first(linearindices, indsA, B...) || throw_eachindex_mismatch(IndexLinear(), A, B...)
808+
indsA = eachindex(IndexLinear(), A)
809+
_all_match_first(X->eachindex(IndexLinear(), X), indsA, B...) ||
810+
throw_eachindex_mismatch(IndexLinear(), A, B...)
876811
indsA
877812
end
878813
function _all_match_first(f::F, inds, A, B...) where F<:Function
@@ -911,7 +846,7 @@ end
911846
pointer(x::AbstractArray{T}) where {T} = unsafe_convert(Ptr{T}, x)
912847
function pointer(x::AbstractArray{T}, i::Integer) where T
913848
@_inline_meta
914-
unsafe_convert(Ptr{T}, x) + (i - first(linearindices(x)))*elsize(x)
849+
unsafe_convert(Ptr{T}, x) + (i - first(LinearIndices(x)))*elsize(x)
915850
end
916851

917852
## Approach:
@@ -2025,7 +1960,7 @@ end
20251960
@inline ith_all(i, as) = (as[1][i], ith_all(i, tail(as))...)
20261961

20271962
function map_n!(f::F, dest::AbstractArray, As) where F
2028-
for i = linearindices(As[1])
1963+
for i = LinearIndices(As[1])
20291964
dest[i] = f(ith_all(i, As)...)
20301965
end
20311966
return dest

base/array.jl

+7-7
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ function _collect(c, itr, ::EltypeUnknown, isz::Union{HasLength,HasShape})
567567
end
568568

569569
function collect_to_with_first!(dest::AbstractArray, v1, itr, st)
570-
i1 = first(linearindices(dest))
570+
i1 = first(LinearIndices(dest))
571571
dest[i1] = v1
572572
return collect_to!(dest, itr, i1+1, st)
573573
end
@@ -1385,15 +1385,15 @@ julia> reverse(A, 3, 5)
13851385
3
13861386
```
13871387
"""
1388-
function reverse(A::AbstractVector, s=first(linearindices(A)), n=last(linearindices(A)))
1388+
function reverse(A::AbstractVector, s=first(LinearIndices(A)), n=last(LinearIndices(A)))
13891389
B = similar(A)
1390-
for i = first(linearindices(A)):s-1
1390+
for i = first(LinearIndices(A)):s-1
13911391
B[i] = A[i]
13921392
end
13931393
for i = s:n
13941394
B[i] = A[n+s-i]
13951395
end
1396-
for i = n+1:last(linearindices(A))
1396+
for i = n+1:last(LinearIndices(A))
13971397
B[i] = A[i]
13981398
end
13991399
return B
@@ -1403,7 +1403,7 @@ end
14031403
reverse(A::Vector) = invoke(reverse, Tuple{AbstractVector}, A)
14041404

14051405
function reverseind(a::AbstractVector, i::Integer)
1406-
li = linearindices(a)
1406+
li = LinearIndices(a)
14071407
first(li) + last(li) - i
14081408
end
14091409

@@ -1433,8 +1433,8 @@ julia> A
14331433
1
14341434
```
14351435
"""
1436-
function reverse!(v::AbstractVector, s=first(linearindices(v)), n=last(linearindices(v)))
1437-
liv = linearindices(v)
1436+
function reverse!(v::AbstractVector, s=first(LinearIndices(v)), n=last(LinearIndices(v)))
1437+
liv = LinearIndices(v)
14381438
if n <= s # empty case; ok
14391439
elseif !(first(liv) s last(liv))
14401440
throw(BoundsError(v, s))

base/broadcast.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
module Broadcast
44

55
using .Base.Cartesian
6-
using .Base: Indices, OneTo, linearindices, tail, to_shape,
6+
using .Base: Indices, OneTo, tail, to_shape,
77
_msk_end, unsafe_bitgetindex, bitcache_chunks, bitcache_size, dumpbitcache,
88
isoperator, promote_typejoin, unalias
99
import .Base: broadcast, broadcast!

base/deprecated.jl

+2
Original file line numberDiff line numberDiff line change
@@ -1580,6 +1580,8 @@ function search(buf::IOBuffer, delim::UInt8)
15801580
return Int(q-p+1)
15811581
end
15821582

1583+
@deprecate linearindices(x::AbstractArray) LinearIndices(x)
1584+
15831585
# PR #26647
15841586
# The `keep` argument in `split` and `rpslit` has been renamed to `keepempty`.
15851587
# To remove this deprecation, remove the `keep` argument from the function signatures as well as

base/errorshow.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ function is_default_method(m::Method)
553553
end
554554

555555
@noinline function throw_eachindex_mismatch(::IndexLinear, A...)
556-
throw(DimensionMismatch("all inputs to eachindex must have the same indices, got $(join(linearindices.(A), ", ", " and "))"))
556+
throw(DimensionMismatch("all inputs to eachindex must have the same indices, got $(join(LinearIndices.(A), ", ", " and "))"))
557557
end
558558
@noinline function throw_eachindex_mismatch(::IndexCartesian, A...)
559559
throw(DimensionMismatch("all inputs to eachindex must have the same axes, got $(join(axes.(A), ", ", " and "))"))

base/essentials.jl

-1
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,6 @@ next(v::SimpleVector,i) = (v[i],i+1)
535535
done(v::SimpleVector,i) = (length(v) < i)
536536
isempty(v::SimpleVector) = (length(v) == 0)
537537
axes(v::SimpleVector) = (OneTo(length(v)),)
538-
linearindices(v::SimpleVector) = axes(v, 1)
539538
axes(v::SimpleVector, d) = d <= 1 ? axes(v)[d] : OneTo(1)
540539

541540
function ==(v1::SimpleVector, v2::SimpleVector)

base/exports.jl

-1
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,6 @@ export
392392
isperm,
393393
issorted,
394394
last,
395-
linearindices,
396395
mapslices,
397396
max,
398397
maximum!,

0 commit comments

Comments
 (0)