Skip to content

Commit

Permalink
Rename endof->lastindex and introduce firstindex. Fixes JuliaLang#23354
Browse files Browse the repository at this point in the history
  • Loading branch information
timholy authored and Keno committed Jan 25, 2018
1 parent ebc5b2c commit 742a539
Show file tree
Hide file tree
Showing 57 changed files with 280 additions and 221 deletions.
8 changes: 7 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ New language features
* Values for `Enum`s can now be specified inside of a `begin` block when using the
`@enum` macro ([#25424]).

* `a[begin]` can now be used to address the first element of an integer-indexed collection `a`.
The index is computed by `firstindex(a)` ([#23554]).

Language changes
----------------

Expand Down Expand Up @@ -516,7 +519,7 @@ Library improvements
has been changed to `KeySet{K, <:Associative{K}} <: AbstractSet{K}` ([#24580]).

* New function `ncodeunits(s::AbstractString)` gives the number of code units in a string.
The generic definition is constant time but calls `endof(s)` which may be inefficient.
The generic definition is constant time but calls `lastindex(s)` which may be inefficient.
Therefore custom string types may want to define direct `ncodeunits` methods.

* `reverseind(s::AbstractString, i::Integer)` now has an efficient generic fallback, so
Expand Down Expand Up @@ -993,6 +996,8 @@ Deprecated or removed

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

* `endof(a)` has been renamed to `lastindex(a)` ([#23554]).

* `DateTime()`, `Date()`, and `Time()` have been deprecated, instead use `DateTime(1)`, `Date(1)`
and `Time(0)` respectively ([#23724]).

Expand Down Expand Up @@ -1152,6 +1157,7 @@ Command-line option changes
[#23323]: https://github.com/JuliaLang/julia/issues/23323
[#23341]: https://github.com/JuliaLang/julia/issues/23341
[#23342]: https://github.com/JuliaLang/julia/issues/23342
[#23354]: https://github.com/JuliaLang/julia/issues/23354
[#23366]: https://github.com/JuliaLang/julia/issues/23366
[#23373]: https://github.com/JuliaLang/julia/issues/23373
[#23404]: https://github.com/JuliaLang/julia/issues/23404
Expand Down
23 changes: 18 additions & 5 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ ndims(::Type{T}) where {T<:AbstractArray} = ndims(supertype(T))
Return the number of elements in the collection.
Use [`endof`](@ref) to get the last valid index of an indexable collection.
Use [`lastindex`](@ref) to get the last valid index of an indexable collection.
# Examples
```jldoctest
Expand All @@ -165,17 +165,30 @@ _length(A::AbstractArray) = (@_inline_meta; prod(map(unsafe_length, axes(A)))) #
_length(A) = (@_inline_meta; length(A))

"""
endof(collection) -> Integer
lastindex(collection) -> Integer
Return the last index of the collection.
# Examples
```jldoctest
julia> endof([1,2,4])
julia> lastindex([1,2,4])
3
```
"""
endof(a::AbstractArray) = (@_inline_meta; last(linearindices(a)))
lastindex(a::AbstractArray) = (@_inline_meta; last(linearindices(a)))

"""
firstindex(collection) -> Integer
Return the first index of the collection.
# Examples
```jldoctest
julia> firstindex([1,2,4])
1
```
"""
firstindex(a::AbstractArray) = (@_inline_meta; first(linearindices(a)))

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

Expand Down Expand Up @@ -204,7 +217,7 @@ end
last(coll)
Get the last element of an ordered collection, if it can be computed in O(1) time. This is
accomplished by calling [`endof`](@ref) to get the last index. Return the end
accomplished by calling [`lastindex`](@ref) to get the last index. Return the end
point of an `AbstractRange` even if it is empty.
# Examples
Expand Down
3 changes: 2 additions & 1 deletion base/char.jl
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ size(c::Char,d) = convert(Int, d) < 1 ? throw(BoundsError()) : 1
ndims(c::Char) = 0
ndims(::Type{Char}) = 0
length(c::Char) = 1
endof(c::Char) = 1
firstindex(c::Char) = 1
lastindex(c::Char) = 1
getindex(c::Char) = c
getindex(c::Char, i::Integer) = i == 1 ? c : throw(BoundsError())
getindex(c::Char, I::Integer...) = all(x -> x == 1, I) ? c : throw(BoundsError())
Expand Down
13 changes: 10 additions & 3 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1298,9 +1298,9 @@ end
@deprecate rsearch(s::AbstractString, r::Regex) findlast(r, s)
@deprecate rsearch(s::AbstractString, c::Char, i::Integer) findprev(equalto(c), s, i)
@deprecate rsearch(s::AbstractString, c::Char) findlast(equalto(c), s)
@deprecate rsearch(a::Union{String,ByteArray}, b::Union{Int8,UInt8}, i::Integer = endof(a)) findprev(equalto(b), a, i)
@deprecate rsearch(a::String, b::Union{Int8,UInt8}, i::Integer = endof(a)) findprev(equalto(Char(b)), a, i)
@deprecate rsearch(a::ByteArray, b::Char, i::Integer = endof(a)) findprev(equalto(UInt8(b)), a, i)
@deprecate rsearch(a::Union{String,ByteArray}, b::Union{Int8,UInt8}, i::Integer = lastindex(a)) findprev(equalto(b), a, i)
@deprecate rsearch(a::String, b::Union{Int8,UInt8}, i::Integer = lastindex(a)) findprev(equalto(Char(b)), a, i)
@deprecate rsearch(a::ByteArray, b::Char, i::Integer = lastindex(a)) findprev(equalto(UInt8(b)), a, i)

@deprecate searchindex(s::AbstractString, t::AbstractString) first(findfirst(t, s))
@deprecate searchindex(s::AbstractString, t::AbstractString, i::Integer) first(findnext(t, s, i))
Expand Down Expand Up @@ -1385,6 +1385,13 @@ export readandwrite
@deprecate methodswith(typ, supertypes) methodswith(typ, supertypes = supertypes)
@deprecate code_lowered(f, types, generated) code_lowered(f, types, generated = generated)

# PR 25458
@deprecate endof(a) lastindex(a)
function firstindex(a)
depwarn("if appropriate you should implement `firstindex` for type $(typeof(a)), which might just return 1", :beginof)
1
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
2 changes: 1 addition & 1 deletion base/dict.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function _truncate_at_width_or_chars(str, width, chars="", truncmark="…")

lastidx != 0 && str[lastidx] in chars && (lastidx = prevind(str, lastidx))
truncidx == 0 && (truncidx = lastidx)
if lastidx < endof(str)
if lastidx < lastindex(str)
return String(SubString(str, 1, truncidx) * truncmark)
else
return String(str)
Expand Down
3 changes: 2 additions & 1 deletion base/essentials.jl
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,8 @@ function length(v::SimpleVector)
@_gc_preserve_end t
return l
end
endof(v::SimpleVector) = length(v)
firstindex(v::SimpleVector) = 1
lastindex(v::SimpleVector) = length(v)
start(v::SimpleVector) = 1
next(v::SimpleVector,i) = (v[i],i+1)
done(v::SimpleVector,i) = (length(v) < i)
Expand Down
3 changes: 2 additions & 1 deletion base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -505,14 +505,15 @@ export
allunique,
any!,
any,
firstindex,
collect,
count,
delete!,
deleteat!,
eltype,
empty!,
empty,
endof,
lastindex,
filter!,
filter,
foldl,
Expand Down
4 changes: 2 additions & 2 deletions base/gmp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,9 @@ hastypemax(::Type{BigInt}) = false

function tryparse_internal(::Type{BigInt}, s::AbstractString, startpos::Int, endpos::Int, base_::Integer, raise::Bool)
# don't make a copy in the common case where we are parsing a whole String
bstr = startpos == start(s) && endpos == endof(s) ? String(s) : String(SubString(s,startpos,endpos))
bstr = startpos == start(s) && endpos == lastindex(s) ? String(s) : String(SubString(s,startpos,endpos))

sgn, base, i = Base.parseint_preamble(true,Int(base_),bstr,start(bstr),endof(bstr))
sgn, base, i = Base.parseint_preamble(true,Int(base_),bstr,start(bstr),lastindex(bstr))
if !(2 <= base <= 62)
raise && throw(ArgumentError("invalid base: base must be 2 ≤ base ≤ 62, got $base"))
return nothing
Expand Down
4 changes: 2 additions & 2 deletions base/int.jl
Original file line number Diff line number Diff line change
Expand Up @@ -539,9 +539,9 @@ end
macro big_str(s)
if '_' in s
# remove _ in s[2:end-1]
bf = IOBuffer(endof(s))
bf = IOBuffer(lastindex(s))
print(bf, s[1])
for c in SubString(s, 2, endof(s)-1)
for c in SubString(s, 2, lastindex(s)-1)
c != '_' && print(bf, c)
end
print(bf, s[end])
Expand Down
10 changes: 4 additions & 6 deletions base/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -661,15 +661,13 @@ function readuntil(s::IO, delim::T; keep::Bool=false) where T
return out
end

# requires that indices for target are small ordered integers bounded by start and endof
# requires that indices for target are small ordered integers bounded by firstindex and lastindex
# returns whether the delimiter was matched
function readuntil_indexable(io::IO, target#=::Indexable{T}=#, out)
T = eltype(target)
first = start(target)
if done(target, first)
return true
end
len = endof(target)
isempty(target) && return true
first = firstindex(target)
len = lastindex(target)
local cache # will be lazy initialized when needed
second = next(target, first)[2]
max_pos = second
Expand Down
3 changes: 2 additions & 1 deletion base/markdown/parse/parse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ config(md::MD) = md.meta[:config]::Config
Base.push!(md::MD, x) = push!(md.content, x)
Base.getindex(md::MD, args...) = md.content[args...]
Base.setindex!(md::MD, args...) = setindex!(md.content, args...)
Base.endof(md::MD) = endof(md.content)
Base.lastindex(md::MD) = lastindex(md.content)
Base.firstindex(md::MD) = firstindex(md.content)
Base.length(md::MD) = length(md.content)
Base.isempty(md::MD) = isempty(md.content)
Base.copy(md::MD) = MD(copy(md.content), copy(md.meta))
Expand Down
3 changes: 2 additions & 1 deletion base/namedtuple.jl
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ length(t::NamedTuple) = nfields(t)
start(t::NamedTuple) = 1
done(t::NamedTuple, iter) = iter > nfields(t)
next(t::NamedTuple, iter) = (getfield(t, iter), iter + 1)
endof(t::NamedTuple) = nfields(t)
firstindex(t::NamedTuple) = 1
lastindex(t::NamedTuple) = nfields(t)
getindex(t::NamedTuple, i::Int) = getfield(t, i)
getindex(t::NamedTuple, i::Symbol) = getfield(t, i)
indexed_next(t::NamedTuple, i::Int, state) = (getfield(t, i), i+1)
Expand Down
3 changes: 2 additions & 1 deletion base/number.jl
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ eltype(::Type{T}) where {T<:Number} = T
ndims(x::Number) = 0
ndims(::Type{<:Number}) = 0
length(x::Number) = 1
endof(x::Number) = 1
firstindex(x::Number) = 1
lastindex(x::Number) = 1
IteratorSize(::Type{<:Number}) = HasShape{0}()
keys(::Number) = OneTo(1)

Expand Down
3 changes: 2 additions & 1 deletion base/pair.jl
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ getindex(p::Pair,i::Int) = getfield(p,i)
getindex(p::Pair,i::Real) = getfield(p, convert(Int, i))
reverse(p::Pair{A,B}) where {A,B} = Pair{B,A}(p.second, p.first)

endof(p::Pair) = 2
firstindex(p::Pair) = 1
lastindex(p::Pair) = 2
length(p::Pair) = 2
first(p::Pair) = p.first
last(p::Pair) = p.second
Expand Down
8 changes: 4 additions & 4 deletions base/parse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -209,11 +209,11 @@ or [`nothing`](@ref) if the string does not contain a valid number.
"""
function tryparse(::Type{T}, s::AbstractString; base::Union{Nothing,Integer} = nothing) where {T<:Integer}
# Zero base means, "figure it out"
tryparse_internal(T, s, start(s), endof(s), base===nothing ? 0 : check_valid_base(base), false)
tryparse_internal(T, s, start(s), lastindex(s), base===nothing ? 0 : check_valid_base(base), false)
end

function parse(::Type{T}, s::AbstractString; base::Union{Nothing,Integer} = nothing) where {T<:Integer}
tryparse_internal(T, s, start(s), endof(s), base===nothing ? 0 : check_valid_base(base), true)
tryparse_internal(T, s, start(s), lastindex(s), base===nothing ? 0 : check_valid_base(base), true)
end

## string to float functions ##
Expand Down Expand Up @@ -327,7 +327,7 @@ tryparse_internal(T::Type{<:Complex}, s::AbstractString, i::Int, e::Int, raise::

# fallback methods for tryparse_internal
tryparse_internal(::Type{T}, s::AbstractString, startpos::Int, endpos::Int) where T<:Real =
startpos == start(s) && endpos == endof(s) ? tryparse(T, s) : tryparse(T, SubString(s, startpos, endpos))
startpos == start(s) && endpos == lastindex(s) ? tryparse(T, s) : tryparse(T, SubString(s, startpos, endpos))
function tryparse_internal(::Type{T}, s::AbstractString, startpos::Int, endpos::Int, raise::Bool) where T<:Real
result = tryparse_internal(T, s, startpos, endpos)
if raise && result === nothing
Expand All @@ -339,4 +339,4 @@ tryparse_internal(::Type{T}, s::AbstractString, startpos::Int, endpos::Int, rais
tryparse_internal(T, s, startpos, endpos, 10, raise)

parse(::Type{T}, s::AbstractString) where T<:Union{Real,Complex} =
tryparse_internal(T, s, start(s), endof(s), true)
tryparse_internal(T, s, start(s), lastindex(s), true)
8 changes: 4 additions & 4 deletions base/precompile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -545,11 +545,11 @@ precompile(Tuple{Type{BoundsError}, Array{Expr, 1}, Base.UnitRange{Int64}})
precompile(Tuple{getfield(Base.Cartesian, Symbol("#@ncall")), Int64, Symbol, Symbol})
precompile(Tuple{typeof(Base.getindex), Tuple{Symbol}, Base.UnitRange{Int64}})
precompile(Tuple{getfield(Base.Cartesian, Symbol("#@ncall")), Int64, Symbol, Symbol, Expr})
precompile(Tuple{typeof(Base.endof), Tuple{Symbol, Expr}})
precompile(Tuple{typeof(Base.lastindex), Tuple{Symbol, Expr}})
precompile(Tuple{typeof(Base.getindex), Tuple{Symbol, Expr}, Base.UnitRange{Int64}})
precompile(Tuple{getfield(Base.Cartesian, Symbol("#@nloops")), Int64, Symbol, Expr, Expr})
precompile(Tuple{typeof(Base.endof), Tuple{Expr}})
precompile(Tuple{typeof(Base.endof), Tuple{Symbol, Symbol, Symbol}})
precompile(Tuple{typeof(Base.lastindex), Tuple{Expr}})
precompile(Tuple{typeof(Base.lastindex), Tuple{Symbol, Symbol, Symbol}})
precompile(Tuple{typeof(Base.getindex), Tuple{Symbol, Symbol, Symbol}, Base.UnitRange{Int64}})
precompile(Tuple{Type{Expr}, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol})
precompile(Tuple{typeof(Base.join), Base.GenericIOBuffer{Array{UInt8, 1}}, Tuple{String, String}, Char})
Expand Down Expand Up @@ -752,7 +752,7 @@ precompile(Tuple{typeof(Base.Markdown.terminline), Base.GenericIOBuffer{Array{UI
precompile(Tuple{typeof(Base._search), Base.SubString{String}, String, Int64})
precompile(Tuple{typeof(Base._split), Base.SubString{String}, String, Int64, Bool, Array{Base.SubString{String}, 1}})
precompile(Tuple{getfield(Base.Markdown, Symbol("#kw##wrapped_lines")), Array{Any, 1}, typeof(Base.Markdown.wrapped_lines), Base.SubString{String}})
precompile(Tuple{typeof(Base.endof), Array{AbstractString, 1}})
precompile(Tuple{typeof(Base.lastindex), Array{AbstractString, 1}})
precompile(Tuple{typeof(Base.getindex), Array{AbstractString, 1}, Base.UnitRange{Int64}})
precompile(Tuple{typeof(Base.throw_boundserror), Array{AbstractString, 1}, Tuple{Base.UnitRange{Int64}}})
precompile(Tuple{typeof(Base.unsafe_copyto!), Array{AbstractString, 1}, Int64, Array{AbstractString, 1}, Int64, Int64})
Expand Down
2 changes: 1 addition & 1 deletion base/printf.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function parse(s::AbstractString)
j1 = j
j = k
end
i > endof(s) || push!(list, s[i:end])
i > lastindex(s) || push!(list, s[i:end])
# coalesce adjacent strings
i = 1
while i < length(list)
Expand Down
2 changes: 1 addition & 1 deletion base/process.jl
Original file line number Diff line number Diff line change
Expand Up @@ -820,7 +820,7 @@ wait(x::ProcessChain) = for p in x.processes; wait(p); end
show(io::IO, p::Process) = print(io, "Process(", p.cmd, ", ", process_status(p), ")")

# allow the elements of the Cmd to be accessed as an array or iterator
for f in (:length, :endof, :start, :keys, :first, :last)
for f in (:length, :firstindex, :lastindex, :start, :keys, :first, :last)
@eval $f(cmd::Cmd) = $f(cmd.exec)
end
eltype(::Type{Cmd}) = eltype(fieldtype(Cmd, :exec))
Expand Down
4 changes: 2 additions & 2 deletions base/reduce.jl
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ end
Like [`mapreduce`](@ref), but with guaranteed right associativity, as in [`foldr`](@ref).
`v0` will be used exactly once.
"""
mapfoldr(f, op, v0, itr) = mapfoldr_impl(f, op, v0, itr, endof(itr))
mapfoldr(f, op, v0, itr) = mapfoldr_impl(f, op, v0, itr, lastindex(itr))

"""
mapfoldr(f, op, itr)
Expand All @@ -137,7 +137,7 @@ Specifically, `mapfoldr(f, op, itr)` produces the same result as
In general, this cannot be used with empty collections (see [`reduce(op, itr)`](@ref)).
"""
function mapfoldr(f, op, itr)
i = endof(itr)
i = lastindex(itr)
if isempty(itr)
return Base.mapreduce_empty_iter(f, op, itr, IteratorEltype(itr))
end
Expand Down
6 changes: 3 additions & 3 deletions base/regex.jl
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ matchall(re::Regex, str::SubString; overlap::Bool = false) =

# TODO: return only start index and update deprecation
function findnext(re::Regex, str::Union{String,SubString}, idx::Integer)
if idx > nextind(str,endof(str))
if idx > nextind(str,lastindex(str))
throw(BoundsError())
end
opts = re.match_options
Expand Down Expand Up @@ -315,7 +315,7 @@ function _replace(io, repl_s::SubstitutionString, str, r, re)
RBRACKET = '>'
repl = repl_s.string
i = start(repl)
e = endof(repl)
e = lastindex(repl)
while i <= e
if repl[i] == SUB_CHAR
next_i = nextind(repl, i)
Expand Down Expand Up @@ -393,7 +393,7 @@ function next(itr::RegexMatchIterator, prev_match)
offset = prev_match.offset
end
else
offset = prev_match.offset + endof(prev_match.match)
offset = prev_match.offset + lastindex(prev_match.match)
end

opts_nonempty = UInt32(PCRE.ANCHORED | PCRE.NOTEMPTY_ATSTART)
Expand Down
Loading

0 comments on commit 742a539

Please sign in to comment.