From 742a539993b9df98bad883cacae5507a2d717f01 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Mon, 8 Jan 2018 13:36:46 -0600 Subject: [PATCH 1/2] Rename endof->lastindex and introduce firstindex. Fixes #23354 --- NEWS.md | 8 +++- base/abstractarray.jl | 23 ++++++++--- base/char.jl | 3 +- base/deprecated.jl | 13 +++++-- base/dict.jl | 2 +- base/essentials.jl | 3 +- base/exports.jl | 3 +- base/gmp.jl | 4 +- base/int.jl | 4 +- base/io.jl | 10 ++--- base/markdown/parse/parse.jl | 3 +- base/namedtuple.jl | 3 +- base/number.jl | 3 +- base/pair.jl | 3 +- base/parse.jl | 8 ++-- base/precompile.jl | 8 ++-- base/printf.jl | 2 +- base/process.jl | 2 +- base/reduce.jl | 4 +- base/regex.jl | 6 +-- base/strings/basic.jl | 15 ++++---- base/strings/io.jl | 10 ++--- base/strings/search.jl | 20 +++++----- base/strings/substring.jl | 10 ++--- base/strings/util.jl | 31 +++++++-------- base/subarray.jl | 12 +++--- base/tuple.jl | 3 +- doc/src/base/collections.md | 3 +- doc/src/base/punctuation.md | 2 +- doc/src/manual/functions.md | 3 +- doc/src/manual/interfaces.md | 11 ++++-- doc/src/manual/strings.md | 25 +++++++----- doc/src/manual/style-guide.md | 4 +- src/common_symbols2.inc | 2 +- src/julia-syntax.scm | 42 +++++++++++++-------- stdlib/Base64/src/buffer.jl | 5 ++- stdlib/Base64/src/decode.jl | 4 +- stdlib/Dates/src/io.jl | 4 +- stdlib/Dates/src/parse.jl | 8 ++-- stdlib/DelimitedFiles/src/DelimitedFiles.jl | 4 +- stdlib/REPL/docs/src/index.md | 2 +- stdlib/REPL/src/LineEdit.jl | 18 ++++----- stdlib/REPL/src/REPL.jl | 10 ++--- stdlib/REPL/src/REPLCompletions.jl | 10 ++--- stdlib/REPL/test/replcompletions.jl | 22 +++++------ stdlib/Random/src/generation.jl | 6 +-- test/char.jl | 4 +- test/dict.jl | 6 +-- test/numbers.jl | 2 +- test/offsetarray.jl | 2 +- test/operators.jl | 4 +- test/parse.jl | 2 +- test/read.jl | 4 +- test/strings/basic.jl | 20 +++++----- test/strings/search.jl | 40 ++++++++++---------- test/strings/types.jl | 10 ++--- test/tuple.jl | 6 +-- 57 files changed, 280 insertions(+), 221 deletions(-) diff --git a/NEWS.md b/NEWS.md index 2e90e85584bd4..38bb0df50134e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -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 ---------------- @@ -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 @@ -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]). @@ -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 diff --git a/base/abstractarray.jl b/base/abstractarray.jl index bef63860b787b..9eb87fee2647c 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -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 @@ -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))] @@ -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 diff --git a/base/char.jl b/base/char.jl index 6e7b051008258..be185b4c55581 100644 --- a/base/char.jl +++ b/base/char.jl @@ -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()) diff --git a/base/deprecated.jl b/base/deprecated.jl index c5d925fdd4709..0b108ede155e9 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -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)) @@ -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) diff --git a/base/dict.jl b/base/dict.jl index 6ff7532e3dcd3..82227b06376d0 100644 --- a/base/dict.jl +++ b/base/dict.jl @@ -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) diff --git a/base/essentials.jl b/base/essentials.jl index 1af26f6bb01ac..d14ae396a3549 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -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) diff --git a/base/exports.jl b/base/exports.jl index d1aeb9be89694..714ace76f8c1d 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -505,6 +505,7 @@ export allunique, any!, any, + firstindex, collect, count, delete!, @@ -512,7 +513,7 @@ export eltype, empty!, empty, - endof, + lastindex, filter!, filter, foldl, diff --git a/base/gmp.jl b/base/gmp.jl index aefe62110d65f..1fb35619f187e 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -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 diff --git a/base/int.jl b/base/int.jl index a046a2c344ef2..6e655b06ac929 100644 --- a/base/int.jl +++ b/base/int.jl @@ -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]) diff --git a/base/io.jl b/base/io.jl index d9d598df13737..79190b8ff511b 100644 --- a/base/io.jl +++ b/base/io.jl @@ -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 diff --git a/base/markdown/parse/parse.jl b/base/markdown/parse/parse.jl index a47dcc627f481..0da5f98a9a5ee 100644 --- a/base/markdown/parse/parse.jl +++ b/base/markdown/parse/parse.jl @@ -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)) diff --git a/base/namedtuple.jl b/base/namedtuple.jl index b3c7a717d16fe..6ff93d98bf132 100644 --- a/base/namedtuple.jl +++ b/base/namedtuple.jl @@ -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) diff --git a/base/number.jl b/base/number.jl index 4e6b010a1d176..fc7952ba88edb 100644 --- a/base/number.jl +++ b/base/number.jl @@ -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) diff --git a/base/pair.jl b/base/pair.jl index d8f3a4e2465d7..2cec78a646be0 100644 --- a/base/pair.jl +++ b/base/pair.jl @@ -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 diff --git a/base/parse.jl b/base/parse.jl index d17514ede97ed..be911c6ff2152 100644 --- a/base/parse.jl +++ b/base/parse.jl @@ -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 ## @@ -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 @@ -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) diff --git a/base/precompile.jl b/base/precompile.jl index 0a1707eb8075b..2fe437bde7a6f 100644 --- a/base/precompile.jl +++ b/base/precompile.jl @@ -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}) @@ -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}) diff --git a/base/printf.jl b/base/printf.jl index d2f1f00ecc025..2ade992935391 100644 --- a/base/printf.jl +++ b/base/printf.jl @@ -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) diff --git a/base/process.jl b/base/process.jl index 32f749d88b95e..f04efc35eab3e 100644 --- a/base/process.jl +++ b/base/process.jl @@ -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)) diff --git a/base/reduce.jl b/base/reduce.jl index 811798e6651e6..b60f82d817ae8 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -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) @@ -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 diff --git a/base/regex.jl b/base/regex.jl index 06b3768159708..68a957c1d0e5b 100644 --- a/base/regex.jl +++ b/base/regex.jl @@ -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 @@ -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) @@ -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) diff --git a/base/strings/basic.jl b/base/strings/basic.jl index 8ed6dab404919..9a6dbb3e3c7fc 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -51,7 +51,7 @@ are valid – they may not be the start of a character, but they will return a code unit value when calling `codeunit(s,i)`. See also: [`codeunit`](@ref), [`checkbounds`](@ref), [`sizeof`](@ref), -[`length`](@ref), [`endof`](@ref) +[`length`](@ref), [`lastindex`](@ref) """ ncodeunits(s::AbstractString) @@ -142,7 +142,8 @@ start(s::AbstractString) = 1 done(s::AbstractString, i::Integer) = i > ncodeunits(s) eltype(::Type{<:AbstractString}) = Char sizeof(s::AbstractString) = ncodeunits(s) * sizeof(codeunit(s)) -endof(s::AbstractString) = thisind(s, ncodeunits(s)) +firstindex(s::AbstractString) = 1 +lastindex(s::AbstractString) = thisind(s, ncodeunits(s)) function getindex(s::AbstractString, i::Integer) @boundscheck checkbounds(s, i) @@ -324,7 +325,7 @@ indices in the string `s`. In addition to in-bounds values, `i` may take the out-of-bounds value `ncodeunits(s) + 1` and `j` may take the out-of-bounds value `0`. -See also: [`isvalid`](@ref), [`ncodeunits`](@ref), [`endof`](@ref), +See also: [`isvalid`](@ref), [`ncodeunits`](@ref), [`lastindex`](@ref), [`thisind`](@ref), [`nextind`](@ref), [`prevind`](@ref) # Examples @@ -450,7 +451,7 @@ julia> nextind(str, 1) julia> nextind(str, 1, 2) 5 -julia> endof(str) +julia> lastindex(str) 9 julia> nextind(str, 9) @@ -481,7 +482,7 @@ keys(s::AbstractString) = EachStringIndex(s) length(e::EachStringIndex) = length(e.s) first(::EachStringIndex) = 1 -last(e::EachStringIndex) = endof(e.s) +last(e::EachStringIndex) = lastindex(e.s) start(e::EachStringIndex) = start(e.s) next(e::EachStringIndex, state) = (state, nextind(e.s, state)) done(e::EachStringIndex, state) = done(e.s, state) @@ -624,10 +625,10 @@ julia> "Test "^3 (^)(s::Union{AbstractString,Char}, r::Integer) = repeat(s, r) # reverse-order iteration for strings and indices thereof -start(r::Iterators.Reverse{<:AbstractString}) = endof(r.itr) +start(r::Iterators.Reverse{<:AbstractString}) = lastindex(r.itr) done(r::Iterators.Reverse{<:AbstractString}, i) = i < start(r.itr) next(r::Iterators.Reverse{<:AbstractString}, i) = (r.itr[i], prevind(r.itr, i)) -start(r::Iterators.Reverse{<:EachStringIndex}) = endof(r.itr.s) +start(r::Iterators.Reverse{<:EachStringIndex}) = lastindex(r.itr.s) done(r::Iterators.Reverse{<:EachStringIndex}, i) = i < start(r.itr.s) next(r::Iterators.Reverse{<:EachStringIndex}, i) = (i, prevind(r.itr.s, i)) diff --git a/base/strings/io.jl b/base/strings/io.jl index 399eae5748795..95c295d70a619 100644 --- a/base/strings/io.jl +++ b/base/strings/io.jl @@ -94,7 +94,7 @@ function sprint(f::Function, args...; context=nothing, sizehint::Integer=0) end tostr_sizehint(x) = 0 -tostr_sizehint(x::AbstractString) = endof(x) +tostr_sizehint(x::AbstractString) = lastindex(x) tostr_sizehint(x::Float64) = 20 tostr_sizehint(x::Float32) = 12 @@ -266,8 +266,8 @@ General escaping of traditional C and Unicode escape sequences. Any characters in `esc` are also escaped (with a backslash). The reverse is [`unescape_string`](@ref). """ -escape_string(s::AbstractString, esc::AbstractString) = sprint(escape_string, s, esc, sizehint=endof(s)) -escape_string(s::AbstractString) = sprint(escape_string, s, "\"", sizehint=endof(s)) +escape_string(s::AbstractString, esc::AbstractString) = sprint(escape_string, s, esc, sizehint=lastindex(s)) +escape_string(s::AbstractString) = sprint(escape_string, s, "\"", sizehint=lastindex(s)) """ escape_string(io, str::AbstractString[, esc::AbstractString]) -> Nothing @@ -320,7 +320,7 @@ end General unescaping of traditional C and Unicode escape sequences. Reverse of [`escape_string`](@ref). """ -unescape_string(s::AbstractString) = sprint(unescape_string, s, sizehint=endof(s)) +unescape_string(s::AbstractString) = sprint(unescape_string, s, sizehint=lastindex(s)) """ unescape_string(io, str::AbstractString) -> Nothing @@ -451,7 +451,7 @@ Returns: function unindent(str::AbstractString, indent::Int; tabwidth=8) indent == 0 && return str pos = start(str) - endpos = endof(str) + endpos = lastindex(str) # Note: this loses the type of the original string buf = IOBuffer(StringVector(endpos), true, true) truncate(buf,0) diff --git a/base/strings/search.jl b/base/strings/search.jl index 82434b40689e1..d2c1b6944ef83 100644 --- a/base/strings/search.jl +++ b/base/strings/search.jl @@ -122,7 +122,7 @@ function _searchindex(s::Union{AbstractString,ByteArray}, t::Union{AbstractString,Char,Int8,UInt8}, i::Integer) if isempty(t) - return 1 <= i <= nextind(s,endof(s)) ? i : + return 1 <= i <= nextind(s,lastindex(s)) ? i : throw(BoundsError(s, i)) end t1, j2 = next(t,start(t)) @@ -162,7 +162,7 @@ _nthbyte(a::Union{AbstractVector{UInt8},AbstractVector{Int8}}, i) = a[i] function _searchindex(s::String, t::String, i::Integer) # Check for fast case of a single byte - endof(t) == 1 && return coalesce(findnext(equalto(t[1]), s, i), 0) + lastindex(t) == 1 && return coalesce(findnext(equalto(t[1]), s, i), 0) _searchindex(unsafe_wrap(Vector{UInt8},s), unsafe_wrap(Vector{UInt8},t), i) end @@ -234,7 +234,7 @@ function _search(s::Union{AbstractString,ByteArray}, if isempty(t) idx:idx-1 else - idx:(idx > 0 ? idx + endof(t) - 1 : -1) + idx:(idx > 0 ? idx + lastindex(t) - 1 : -1) end end @@ -271,7 +271,7 @@ findnext(t::AbstractString, s::AbstractString, i::Integer) = _search(s, t, i) findlast(pattern::Regex, string::String) Find the last occurrence of `pattern` in `string`. Equivalent to -[`findlast(pattern, string, endof(s))`](@ref). +[`findlast(pattern, string, lastindex(s))`](@ref). # Examples ```jldoctest @@ -283,7 +283,7 @@ julia> findfirst("Julia", "JuliaLang") ``` """ findlast(pattern::AbstractString, string::AbstractString) = - findprev(pattern, string, endof(string)) + findprev(pattern, string, lastindex(string)) # AbstractString implementation of the generic findprev interface function findprev(testf::Function, s::AbstractString, i::Integer) @@ -305,12 +305,12 @@ function _rsearchindex(s::AbstractString, t::Union{AbstractString,Char,Int8,UInt8}, i::Integer) if isempty(t) - return 1 <= i <= nextind(s, endof(s)) ? i : + return 1 <= i <= nextind(s, lastindex(s)) ? i : throw(BoundsError(s, i)) end t = t isa AbstractString ? reverse(t) : t rs = reverse(s) - l = endof(s) + l = lastindex(s) t1, j2 = next(t, start(t)) while true i = findprev(equalto(t1), s, i) @@ -337,9 +337,9 @@ end function _rsearchindex(s::String, t::String, i::Integer) # Check for fast case of a single byte - if endof(t) == 1 + if lastindex(t) == 1 return coalesce(findprev(equalto(t[1]), s, i), 0) - elseif endof(t) != 0 + elseif lastindex(t) != 0 j = i ≤ ncodeunits(s) ? nextind(s, i)-1 : i return _rsearchindex(unsafe_wrap(Vector{UInt8}, s), unsafe_wrap(Vector{UInt8}, t), j) elseif i > sizeof(s) @@ -419,7 +419,7 @@ function _rsearch(s::Union{AbstractString,ByteArray}, if isempty(t) idx:idx-1 else - idx:(idx > 0 ? idx + endof(t) - 1 : -1) + idx:(idx > 0 ? idx + lastindex(t) - 1 : -1) end end diff --git a/base/strings/substring.jl b/base/strings/substring.jl index f4cf3c9311537..06d9e3cf954c2 100644 --- a/base/strings/substring.jl +++ b/base/strings/substring.jl @@ -1,7 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license """ - SubString(s::AbstractString, i::Integer, j::Integer=endof(s)) + SubString(s::AbstractString, i::Integer, j::Integer=lastindex(s)) SubString(s::AbstractString, r::UnitRange{<:Integer}) Like [`getindex`](@ref), but returns a view into the parent string `s` @@ -36,7 +36,7 @@ struct SubString{T<:AbstractString} <: AbstractString end SubString(s::T, i::Int, j::Int) where {T<:AbstractString} = SubString{T}(s, i, j) -SubString(s::AbstractString, i::Integer, j::Integer=endof(s)) = SubString(s, Int(i), Int(j)) +SubString(s::AbstractString, i::Integer, j::Integer=lastindex(s)) = SubString(s, Int(i), Int(j)) SubString(s::AbstractString, r::UnitRange{<:Integer}) = SubString(s, first(r), last(r)) function SubString(s::SubString, i::Int, j::Int) @@ -44,8 +44,8 @@ function SubString(s::SubString, i::Int, j::Int) SubString(s.string, s.offset+i, s.offset+j) end -SubString(s::AbstractString) = SubString(s, 1, endof(s)) -SubString{T}(s::T) where {T<:AbstractString} = SubString{T}(s, 1, endof(s)) +SubString(s::AbstractString) = SubString(s, 1, lastindex(s)) +SubString{T}(s::T) where {T<:AbstractString} = SubString{T}(s, 1, lastindex(s)) convert(::Type{SubString{S}}, s::AbstractString) where {S<:AbstractString} = SubString(convert(S, s)) @@ -148,7 +148,7 @@ julia> join(reverse(collect(graphemes("ax̂e")))) # reverses graphemes """ function reverse(s::Union{String,SubString{String}})::String sprint() do io - i, j = start(s), endof(s) + i, j = start(s), lastindex(s) while i ≤ j c, j = s[j], prevind(s, j) write(io, c) diff --git a/base/strings/util.jl b/base/strings/util.jl index 91afc96de9997..7f98a458dd0b5 100644 --- a/base/strings/util.jl +++ b/base/strings/util.jl @@ -45,8 +45,8 @@ true ``` """ function endswith(a::AbstractString, b::AbstractString) - i = endof(a) - j = endof(b) + i = lastindex(a) + j = lastindex(b) a1 = start(a) b1 = start(b) while a1 <= i && b1 <= j @@ -93,11 +93,11 @@ julia> chop(a, head = 5, tail = 5) ``` """ function chop(s::AbstractString; head::Integer = 0, tail::Integer = 1) - SubString(s, nextind(s, start(s), head), prevind(s, endof(s), tail)) + SubString(s, nextind(s, start(s), head), prevind(s, lastindex(s), tail)) end # TODO: optimization for the default case based on -# chop(s::AbstractString) = SubString(s, start(s), prevind(s, endof(s))) +# chop(s::AbstractString) = SubString(s, start(s), prevind(s, lastindex(s))) """ chomp(s::AbstractString) @@ -111,14 +111,14 @@ julia> chomp("Hello\\n") ``` """ function chomp(s::AbstractString) - i = endof(s) + i = lastindex(s) (i < 1 || s[i] != '\n') && (return SubString(s, 1, i)) j = prevind(s,i) (j < 1 || s[j] != '\r') && (return SubString(s, 1, j)) return SubString(s, 1, prevind(s,j)) end function chomp(s::String) - i = endof(s) + i = lastindex(s) if i < 1 || codeunit(s,i) != 0x0a SubString(s, 1, i) elseif i < 2 || codeunit(s,i-1) != 0x0d @@ -149,7 +149,7 @@ julia> lstrip(a) ``` """ function lstrip(s::AbstractString, chars::Chars=_default_delims) - e = endof(s) + e = lastindex(s) i = start(s) while !done(s,i) c, j = next(s,i) @@ -180,8 +180,9 @@ julia> rstrip(a) ``` """ function rstrip(s::AbstractString, chars::Chars=_default_delims) - i = endof(s) - while 1 ≤ i + a = firstindex(s) + i = lastindex(s) + while a ≤ i c = s[i] j = prevind(s, i) c in chars || return SubString(s, 1:i) @@ -300,8 +301,8 @@ split(str::T, splitter::Char; function _split(str::AbstractString, splitter, limit::Integer, keep_empty::Bool, strs::Array) i = start(str) - n = endof(str) - r = coalesce(findfirst(splitter,str), 0) + n = lastindex(str) + r = coalesce(findfirst(splitter,str), i - 1) if r != 0:-1 j, k = first(r), nextind(str,last(r)) while 0 < j <= n && length(strs) != limit-1 @@ -367,8 +368,8 @@ rsplit(str::T, splitter::Char; function _rsplit(str::AbstractString, splitter, limit::Integer, keep_empty::Bool, strs::Array) i = start(str) - n = endof(str) - r = coalesce(findlast(splitter, str), 0) + n = lastindex(str) + r = coalesce(findlast(splitter, str), i - 1) j = first(r)-1 k = last(r) while((0 <= j < n) && (length(strs) != limit-1)) @@ -400,7 +401,7 @@ function replace(str::String, pat_repl::Pair; count::Integer=typemax(Int)) count == 0 && return str count < 0 && throw(DomainError(count, "`count` must be non-negative.")) n = 1 - e = endof(str) + e = lastindex(str) i = a = start(str) r = coalesce(findnext(pattern,str,i), 0) j, k = first(r), last(r) @@ -503,7 +504,7 @@ hex2bytes(s::Union{String,AbstractVector{UInt8}}) = hex2bytes!(Vector{UInt8}(uni _firstbyteidx(s::String) = 1 _firstbyteidx(s::AbstractVector{UInt8}) = first(eachindex(s)) _lastbyteidx(s::String) = sizeof(s) -_lastbyteidx(s::AbstractVector{UInt8}) = endof(s) +_lastbyteidx(s::AbstractVector{UInt8}) = lastindex(s) """ hex2bytes!(d::AbstractVector{UInt8}, s::Union{String,AbstractVector{UInt8}}) diff --git a/base/subarray.jl b/base/subarray.jl index d1a2b9bd94b1b..d0d91e7b97194 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -375,14 +375,14 @@ end replace_ref_end!(ex) Recursively replace occurrences of the symbol :end in a "ref" expression (i.e. A[...]) `ex` -with the appropriate function calls (`endof` or `size`). Replacement uses +with the appropriate function calls (`lastindex` or `size`). Replacement uses the closest enclosing ref, so A[B[end]] should transform to - A[B[endof(B)]] + A[B[lastindex(B)]] """ replace_ref_end!(ex) = replace_ref_end_!(ex, nothing)[1] @@ -402,11 +402,11 @@ function replace_ref_end_!(ex, withex) if nargs == 0 return ex, used_withex elseif nargs == 1 - # replace with endof(S) - ex.args[2], used_S = replace_ref_end_!(ex.args[2],:($endof($S))) + # replace with lastindex(S) + ex.args[2], used_S = replace_ref_end_!(ex.args[2],:($lastindex($S))) else n = 1 - J = endof(ex.args) + J = lastindex(ex.args) for j = 2:J exj, used = replace_ref_end_!(ex.args[j],:($size($S,$n))) used_S |= used @@ -499,7 +499,7 @@ end # _views implements the transformation for the @views macro. # @views calls esc(_views(...)) to work around #20241, # so any function calls we insert (to maybeview, or to -# size and endof in replace_ref_end!) must be interpolated +# size and lastindex in replace_ref_end!) must be interpolated # as values rather than as symbols to ensure that they are called # from Base rather than from the caller's scope. _views(x) = x diff --git a/base/tuple.jl b/base/tuple.jl index fe9c0746ce7cf..506a9e33ba832 100644 --- a/base/tuple.jl +++ b/base/tuple.jl @@ -16,7 +16,8 @@ NTuple ## indexing ## length(t::Tuple) = nfields(t) -endof(t::Tuple) = length(t) +firstindex(t::Tuple) = 1 +lastindex(t::Tuple) = length(t) size(t::Tuple, d) = (d == 1) ? length(t) : throw(ArgumentError("invalid tuple dimension $d")) @eval getindex(t::Tuple, i::Int) = getfield(t, i, $(Expr(:boundscheck))) @eval getindex(t::Tuple, i::Real) = getfield(t, convert(Int, i), $(Expr(:boundscheck))) diff --git a/doc/src/base/collections.md b/doc/src/base/collections.md index 4b3dd8574c8cc..ee50b10837285 100644 --- a/doc/src/base/collections.md +++ b/doc/src/base/collections.md @@ -143,7 +143,8 @@ Base.replace! ```@docs Base.getindex Base.setindex! -Base.endof +Base.firstindex +Base.lastindex ``` Fully implemented by: diff --git a/doc/src/base/punctuation.md b/doc/src/base/punctuation.md index 13fab22b8d277..19f2604df3f61 100644 --- a/doc/src/base/punctuation.md +++ b/doc/src/base/punctuation.md @@ -38,7 +38,7 @@ Extended documentation for mathematical symbols & functions is [here](@ref math- | `.` | access named fields in objects/modules (calling [`getproperty`](@ref Base.getproperty) or [`setproperty!`](@ref Base.setproperty!)), also prefixes elementwise function calls (calling [`broadcast`](@ref)) | | `a:b` | range a, a+1, a+2, ..., b (calling [`colon`](@ref)) | | `a:s:b` | range a, a+s, a+2s, ..., b (also calling [`colon`](@ref)) | -| `:` | index an entire dimension (1:endof), see [`Colon`](@ref)) | +| `:` | index an entire dimension (firstindex:lastindex), see [`Colon`](@ref)) | | `::` | type annotation or [`typeassert`](@ref), depending on context | | `:( )` | quoted expression | | `:a` | symbol a | diff --git a/doc/src/manual/functions.md b/doc/src/manual/functions.md index c4ce2e98b7ae2..0664f6f758f98 100644 --- a/doc/src/manual/functions.md +++ b/doc/src/manual/functions.md @@ -692,7 +692,8 @@ the results (see [Pre-allocating outputs](@ref)). A convenient syntax for this i is equivalent to `broadcast!(identity, X, ...)` except that, as above, the `broadcast!` loop is fused with any nested "dot" calls. For example, `X .= sin.(Y)` is equivalent to `broadcast!(sin, X, Y)`, overwriting `X` with `sin.(Y)` in-place. If the left-hand side is an array-indexing expression, -e.g. `X[2:end] .= sin.(Y)`, then it translates to `broadcast!` on a `view`, e.g. `broadcast!(sin, view(X, 2:endof(X)), Y)`, +e.g. `X[begin+1:end] .= sin.(Y)`, then it translates to `broadcast!` on a `view`, e.g. +`broadcast!(sin, view(X, firstindex(X)+1:lastindex(X)), Y)`, so that the left-hand side is updated in-place. Since adding dots to many operations and function calls in an expression diff --git a/doc/src/manual/interfaces.md b/doc/src/manual/interfaces.md index 89e8c66f306d7..3e19bbf93357c 100644 --- a/doc/src/manual/interfaces.md +++ b/doc/src/manual/interfaces.md @@ -161,7 +161,8 @@ julia> collect(Iterators.reverse(Squares(10)))' # transposed to save space |:-------------------- |:-------------------------------- | | `getindex(X, i)` | `X[i]`, indexed element access | | `setindex!(X, v, i)` | `X[i] = v`, indexed assignment | -| `endof(X)` | The last index, used in `X[end]` | +| `firstindex(X)` | The first index, used in `X[begin]` | +| `lastindex(X)` | The last index, used in `X[end]` | For the `Squares` iterable above, we can easily compute the `i`th element of the sequence by squaring it. We can expose this as an indexing expression `S[i]`. To opt into this behavior, `Squares` @@ -177,11 +178,13 @@ julia> Squares(100)[23] 529 ``` -Additionally, to support the syntax `S[end]`, we must define [`endof`](@ref) to specify the last valid -index: +Additionally, to support the syntax `S[begin]` and `S[end]`, we must define [`firstindex`](@ref) and +[`lastindex`](@ref) to specify the first and last valid +index, respectively: ```jldoctest squaretype -julia> Base.endof(S::Squares) = length(S) +julia> Base.firstindex(S::Squares) = 1 +julia> Base.lastindex(S::Squares) = length(S) julia> Squares(23)[end] 529 diff --git a/doc/src/manual/strings.md b/doc/src/manual/strings.md index 7949d57be095e..1f0339864fe3d 100644 --- a/doc/src/manual/strings.md +++ b/doc/src/manual/strings.md @@ -168,6 +168,9 @@ julia> """Contains "quote" characters""" If you want to extract a character from a string, you index into it: ```jldoctest helloworldstring +julia> str[begin] +'H': ASCII/Unicode U+0048 (category Lu: Letter, uppercase) + julia> str[1] 'H': ASCII/Unicode U+0048 (category Lu: Letter, uppercase) @@ -178,12 +181,15 @@ julia> str[end] '\n': ASCII/Unicode U+000a (category Cc: Other, control) ``` -All indexing in Julia is 1-based: the first element of any integer-indexed object is found at +Many Julia objects, including strings, can be indexed with integers. The index of the first +element is returned by [`firstindex(str)`](@ref), and the index of the last element +with [`lastindex(str)`](@ref). The keywords `begin` and `end` can be used inside an indexing +operation as shorthand for the first and last index along the given dimension. +Most indexing in Julia is 1-based: the first element of many integer-indexed objects is found at index 1. (As we will see below, this does not necessarily mean that the last element is found at index `n`, where `n` is the length of the string.) -In any indexing expression, the keyword `end` can be used as a shorthand for the last index (computed -by [`endof(str)`](@ref)). You can perform arithmetic and other operations with `end`, just like +You can perform arithmetic and other operations with `end`, just like a normal value: ```jldoctest helloworldstring @@ -197,7 +203,7 @@ julia> str[end÷2] Using an index less than 1 or greater than `end` raises an error: ```jldoctest helloworldstring -julia> str[0] +julia> str[begin-1] ERROR: BoundsError: attempt to access "Hello, world.\n" at index [0] [...] @@ -302,14 +308,14 @@ julia> s[1:4] ``` Because of variable-length encodings, the number of characters in a string (given by [`length(s)`](@ref)) -is not always the same as the last index. If you iterate through the indices 1 through [`endof(s)`](@ref) +is not always the same as the last index. If you iterate through the indices 1 through [`lastindex(s)`](@ref) and index into `s`, the sequence of characters returned when errors aren't thrown is the sequence -of characters comprising the string `s`. Thus we have the identity that `length(s) <= endof(s)`, +of characters comprising the string `s`. Thus we have the identity that `length(s) <= lastindex(s)`, since each character in a string must have its own index. The following is an inefficient and verbose way to iterate through the characters of `s`: ```jldoctest unicodestring -julia> for i = 1:endof(s) +julia> for i = begindex(s):lastindex(s) try println(s[i]) catch @@ -562,13 +568,14 @@ julia> join(["apples", "bananas", "pineapples"], ", ", " and ") Some other useful functions include: - * [`endof(str)`](@ref) gives the maximal (byte) index that can be used to index into `str`. + * [`firstindex(str)`](@ref) gives the minimal (byte) index that can be used to index into `str` (always 1 for strings, not necessarily true for other containers). + * [`lastindex(str)`](@ref) gives the maximal (byte) index that can be used to index into `str`. * [`length(str)`](@ref) the number of characters in `str`. * [`length(str, i, j)`](@ref) the number of valid character indices in `str` from `i` to `j`. * [`i = start(str)`](@ref start) gives the first valid index at which a character can be found in `str` (typically 1). * [`c, j = next(str,i)`](@ref next) returns next character at or after the index `i` and the next valid - character index following that. With [`start`](@ref) and [`endof`](@ref), can be used to iterate + character index following that. With [`start`](@ref) and [`lastindex`](@ref), can be used to iterate through the characters in `str`. * [`thisind(str, i)`](@ref) given an arbitrary index into a string find the first index of the character into which the index points. * [`nextind(str, i, n=1)`](@ref) find the start of the `n`th character starting after index `i`. diff --git a/doc/src/manual/style-guide.md b/doc/src/manual/style-guide.md index f2a24be8e45d3..cb59a416e48a4 100644 --- a/doc/src/manual/style-guide.md +++ b/doc/src/manual/style-guide.md @@ -92,7 +92,7 @@ Instead of: ```julia function double(a::AbstractArray{<:Number}) - for i = 1:endof(a) + for i = firstindex(a):lastindex(a) a[i] *= 2 end return a @@ -103,7 +103,7 @@ use: ```julia function double!(a::AbstractArray{<:Number}) - for i = 1:endof(a) + for i = firstindex(a):lastindex(a) a[i] *= 2 end return a diff --git a/src/common_symbols2.inc b/src/common_symbols2.inc index 391a447489353..54e8f8dc6e1ce 100644 --- a/src/common_symbols2.inc +++ b/src/common_symbols2.inc @@ -24,7 +24,7 @@ jl_symbol("push!"), jl_symbol("iter"), jl_symbol(">"), jl_symbol("Base"), -jl_symbol("endof"), +jl_symbol("lastindex"), jl_symbol("shl_int"), jl_symbol("Any"), jl_symbol("Enums.jl"), diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 8b23fdcd1d331..86890b5557364 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -86,35 +86,46 @@ (define (expand-compare-chain e) (car (expand-vector-compare e))) -;; return the appropriate computation for an `end` symbol for indexing +;; return the appropriate computation for a `begin` or `end` symbol for indexing ;; 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 endof(a) or size(a,n) +;; returns a call to, e.g., lastindex(a) or last(axes(a,n)) (define (end-val a n tuples last) (if (null? tuples) (if (and last (= n 1)) - `(call (top endof) ,a) - `(call (top size) ,a ,n)) + `(call (top lastindex) ,a) + `(call (top last) (call (top axes) ,a ,n))) (let ((dimno `(call (top +) ,(- n (length tuples)) ,.(map (lambda (t) `(call (top length) ,t)) tuples)))) - `(call (top size) ,a ,dimno)))) + `(call (top last) (call (top axes) ,a ,dimno))))) -;; replace `end` for the closest ref expression, so doesn't go inside nested refs -(define (replace-end ex a n tuples last) +(define (begin-val a n tuples last) + (if (null? tuples) + (if (and last (= n 1)) + `(call (top firstindex) ,a) + `(call (top first) (call (top axes) ,a ,n))) + (let ((dimno `(call (top +) ,(- n (length tuples)) + ,.(map (lambda (t) `(call (top length) ,t)) + tuples)))) + `(call (top first) (call (top axes) ,a ,dimno))))) + +;; replace `begin` and `end` for the closest ref expression, so doesn't go inside nested refs +(define (replace-beginend ex a n tuples last) (cond ((eq? ex 'end) (end-val a n tuples last)) + ((eq? ex 'begin) (begin-val a n tuples last)) ((or (atom? ex) (quoted? ex)) ex) ((eq? (car ex) 'ref) ;; inside ref only replace within the first argument - (list* 'ref (replace-end (cadr ex) a n tuples last) + (list* 'ref (replace-beginend (cadr ex) a n tuples last) (cddr ex))) (else (cons (car ex) - (map (lambda (x) (replace-end x a n tuples last)) + (map (lambda (x) (replace-beginend x a n tuples last)) (cdr ex)))))) -;; go through indices and replace the `end` symbol +;; go through indices and replace the `begin` or `end` symbol ;; a = array being indexed, i = list of indices ;; returns (values index-list stmts) where stmts are statements that need ;; to execute first. @@ -133,17 +144,17 @@ (loop (cdr lst) (+ n 1) stmts (cons (cadr idx) tuples) - (cons `(... ,(replace-end (cadr idx) a n tuples last)) + (cons `(... ,(replace-beginend (cadr idx) a n tuples last)) ret)) (let ((g (make-ssavalue))) (loop (cdr lst) (+ n 1) - (cons `(= ,g ,(replace-end (cadr idx) a n tuples last)) + (cons `(= ,g ,(replace-beginend (cadr idx) a n tuples last)) stmts) (cons g tuples) (cons `(... ,g) ret)))) (loop (cdr lst) (+ n 1) stmts tuples - (cons (replace-end idx a n tuples last) ret))))))) + (cons (replace-beginend idx a n tuples last) ret))))))) ;; GF method does not need to keep decl expressions on lambda args ;; except for rest arg @@ -1500,7 +1511,8 @@ (idxs (cddr e))) (let* ((reuse (and (pair? a) (contains (lambda (x) - (or (eq? x 'end) + (or (eq? x 'begin) + (eq? x 'end) (eq? x ':) (and (pair? x) (eq? (car x) ':)))) @@ -1515,7 +1527,7 @@ (define (expand-update-operator op op= lhs rhs . declT) (cond ((and (pair? lhs) (eq? (car lhs) 'ref)) - ;; expand indexing inside op= first, to remove "end" and ":" + ;; expand indexing inside op= first, to remove "begin", "end", and ":" (let* ((ex (partially-expand-ref lhs)) (stmts (butlast (cdr ex))) (refex (last (cdr ex))) diff --git a/stdlib/Base64/src/buffer.jl b/stdlib/Base64/src/buffer.jl index b992c36b81587..06856a831cd0c 100644 --- a/stdlib/Base64/src/buffer.jl +++ b/stdlib/Base64/src/buffer.jl @@ -15,9 +15,10 @@ end Base.empty!(buffer::Buffer) = buffer.size = 0 Base.getindex(buffer::Buffer, i::Integer) = unsafe_load(buffer.ptr, i) Base.setindex!(buffer::Buffer, v::UInt8, i::Integer) = unsafe_store!(buffer.ptr, v, i) -Base.endof(buffer::Buffer) = buffer.size +Base.firstindex(buffer::Buffer) = 1 +Base.lastindex(buffer::Buffer) = buffer.size Base.pointer(buffer::Buffer) = buffer.ptr -capacity(buffer::Buffer) = Int(pointer(buffer.data, endof(buffer.data) + 1) - buffer.ptr) +capacity(buffer::Buffer) = Int(pointer(buffer.data, lastindex(buffer.data) + 1) - buffer.ptr) function consumed!(buffer::Buffer, n::Integer) @assert n ≤ buffer.size diff --git a/stdlib/Base64/src/decode.jl b/stdlib/Base64/src/decode.jl index e1741f270c5bc..5e15de0bfbaca 100644 --- a/stdlib/Base64/src/decode.jl +++ b/stdlib/Base64/src/decode.jl @@ -77,7 +77,7 @@ function read_until_end(pipe::Base64DecodePipe, ptr::Ptr{UInt8}, n::UInt) end end if p < p_end - if i + 4 ≤ endof(buffer) + if i + 4 ≤ lastindex(buffer) b1 = decode(buffer[i+1]) b2 = decode(buffer[i+2]) b3 = decode(buffer[i+3]) @@ -140,7 +140,7 @@ function decode_slow(b1, b2, b3, b4, buffer, i, input, ptr, n, rest) else break end - if i + 1 ≤ endof(buffer) + if i + 1 ≤ lastindex(buffer) b4 = decode(buffer[i+=1]) elseif !eof(input) b4 = decode(read(input, UInt8)) diff --git a/stdlib/Dates/src/io.jl b/stdlib/Dates/src/io.jl index 6d77e845d36bc..e3657d3e45665 100644 --- a/stdlib/Dates/src/io.jl +++ b/stdlib/Dates/src/io.jl @@ -154,7 +154,7 @@ end # the last n digits of y # will be 0 padded if y has less than n digits str = dec(y, n) - l = endof(str) + l = lastindex(str) if l == n # fast path write(io, str) @@ -348,7 +348,7 @@ function DateFormat(f::AbstractString, locale::DateLocale=ENGLISH) prev_offset = m.offset + width end - tran = replace(f[prev_offset:endof(f)], r"\\(.)" => s"\1") + tran = replace(f[prev_offset:lastindex(f)], r"\\(.)" => s"\1") if !isempty(prev) letter, width = prev diff --git a/stdlib/Dates/src/parse.jl b/stdlib/Dates/src/parse.jl index 8908ee92a1897..770a6e10ca8c1 100644 --- a/stdlib/Dates/src/parse.jl +++ b/stdlib/Dates/src/parse.jl @@ -198,7 +198,7 @@ end end function Base.parse(::Type{DateTime}, s::AbstractString, df::typeof(ISODateTimeFormat)) - i, end_pos = start(s), endof(s) + i, end_pos = start(s), lastindex(s) dm = dd = Int64(1) th = tm = ts = tms = Int64(0) @@ -265,13 +265,13 @@ function Base.parse(::Type{DateTime}, s::AbstractString, df::typeof(ISODateTimeF end function Base.parse(::Type{T}, str::AbstractString, df::DateFormat=default_format(T)) where T<:TimeType - pos, len = start(str), endof(str) + pos, len = start(str), lastindex(str) values, pos = tryparsenext_internal(T, str, pos, len, df, true) T(values...) end function Base.tryparse(::Type{T}, str::AbstractString, df::DateFormat=default_format(T)) where T<:TimeType - pos, len = start(str), endof(str) + pos, len = start(str), lastindex(str) values, pos = tryparsenext_internal(T, str, pos, len, df, false) if values === nothing nothing @@ -296,7 +296,7 @@ number of components may be less than the total number of `DatePart`. tokens = Type[CONVERSION_SPECIFIERS[letter] for letter in letters] quote - pos, len = start(str), endof(str) + pos, len = start(str), lastindex(str) values, pos, num_parsed = tryparsenext_core(str, pos, len, df, true) t = values types = $(Expr(:tuple, tokens...)) diff --git a/stdlib/DelimitedFiles/src/DelimitedFiles.jl b/stdlib/DelimitedFiles/src/DelimitedFiles.jl index 5b17981cb4222..c211cc98dad13 100644 --- a/stdlib/DelimitedFiles/src/DelimitedFiles.jl +++ b/stdlib/DelimitedFiles/src/DelimitedFiles.jl @@ -381,7 +381,7 @@ function store_cell(dlmstore::DLMStore{T}, row::Int, col::Int, # fill data if quoted && _chrinstr(sbuff, UInt8('"'), startpos, endpos) unescaped = replace(SubString(sbuff, startpos, endpos), r"\"\"" => "\"") - fail = colval(unescaped, 1, endof(unescaped), cells, drow, col) + fail = colval(unescaped, 1, lastindex(unescaped), cells, drow, col) else fail = colval(sbuff, startpos, endpos, cells, drow, col) end @@ -400,7 +400,7 @@ function store_cell(dlmstore::DLMStore{T}, row::Int, col::Int, # fill header if quoted && _chrinstr(sbuff, UInt8('"'), startpos, endpos) unescaped = replace(SubString(sbuff, startpos, endpos), r"\"\"" => "\"") - colval(unescaped, 1, endof(unescaped), dlmstore.hdr, 1, col) + colval(unescaped, 1, lastindex(unescaped), dlmstore.hdr, 1, col) else colval(sbuff, startpos, endpos, dlmstore.hdr, 1, col) end diff --git a/stdlib/REPL/docs/src/index.md b/stdlib/REPL/docs/src/index.md index fd43037224561..158b077b16060 100644 --- a/stdlib/REPL/docs/src/index.md +++ b/stdlib/REPL/docs/src/index.md @@ -314,7 +314,7 @@ Fields for output from functions can also be completed: ```julia-repl julia> split("","")[1].[TAB] -endof offset string +lastindex offset string ``` The completion of fields for output from functions uses type inference, and it can only suggest diff --git a/stdlib/REPL/src/LineEdit.jl b/stdlib/REPL/src/LineEdit.jl index d33735253c739..743360fd59817 100644 --- a/stdlib/REPL/src/LineEdit.jl +++ b/stdlib/REPL/src/LineEdit.jl @@ -261,10 +261,10 @@ function common_prefix(completions) cc, nexti = next(c1, i) while true for c in completions - (i > endof(c) || c[i] != cc) && return ret + (i > lastindex(c) || c[i] != cc) && return ret end ret = string(ret, cc) - i >= endof(c1) && return ret + i >= lastindex(c1) && return ret i = nexti cc, nexti = next(c1, i) end @@ -729,7 +729,7 @@ _notspace(c) = c != _space beginofline(buf, pos=position(buf)) = coalesce(findprev(equalto(_newline), buf.data, pos), 0) -function endofline(buf, pos=position(buf)) +function lastindexline(buf, pos=position(buf)) eol = findnext(equalto(_newline), buf.data[pos+1:buf.size], 1) eol === nothing ? buf.size : pos + eol - 1 end @@ -870,7 +870,7 @@ function push_kill!(s::MIState, killed::String, concat = s.key_repeats > 0; rev= push!(s.kill_ring, killed) length(s.kill_ring) > options(s).kill_ring_max && popfirst!(s.kill_ring) end - s.kill_idx = endof(s.kill_ring) + s.kill_idx = lastindex(s.kill_ring) true end @@ -884,7 +884,7 @@ function edit_kill_line(s::MIState, backwards::Bool=false) else set_action!(s, :edit_kill_line_forwards) pos = position(buf) - endpos = endofline(buf) + endpos = lastindexline(buf) endpos == pos && buf.size > pos && (endpos += 1) end push_undo(s) @@ -978,7 +978,7 @@ function edit_transpose_lines_up!(buf::IOBuffer, reg::Region) line1 = edit_splice!(buf, b1 => b2) # delete whole previous line line1 = '\n'*line1[1:end-1] # don't include the final '\n' pos = position(buf) # save pos in case it's at the end of line - b = endofline(buf, last(reg) - b2 + b1) # b2-b1 is the size of the removed line1 + b = lastindexline(buf, last(reg) - b2 + b1) # b2-b1 is the size of the removed line1 edit_splice!(buf, b => b, line1) seek(buf, pos) true @@ -986,9 +986,9 @@ end # swap all lines intersecting the region with line below function edit_transpose_lines_down!(buf::IOBuffer, reg::Region) - e1 = endofline(buf, last(reg)) + e1 = lastindexline(buf, last(reg)) e1 == buf.size && return false - e2 = endofline(buf, e1+1) + e2 = lastindexline(buf, e1+1) line2 = edit_splice!(buf, e1 => e2) # delete whole next line line2 = line2[2:end]*'\n' # don't include leading '\n' b = beginofline(buf, first(reg)) @@ -1096,7 +1096,7 @@ function get_lines_in_region(s)::Vector{Int} b, e = region(buf) bol = Int[beginofline(buf, b)] # begin of lines while true - b = endofline(buf, b) + b = lastindexline(buf, b) b >= e && break # b < e ==> b+1 <= e <= buf.size push!(bol, b += 1) diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index 9436e1b2732f1..25c4d5166995b 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -332,7 +332,7 @@ beforecursor(buf::IOBuffer) = String(buf.data[1:buf.ptr-1]) function complete_line(c::REPLCompletionProvider, s) partial = beforecursor(s.input_buffer) full = LineEdit.input_string(s) - ret, range, should_complete = completions(full, endof(partial)) + ret, range, should_complete = completions(full, lastindex(partial)) return ret, partial[range], should_complete end @@ -340,14 +340,14 @@ function complete_line(c::ShellCompletionProvider, s) # First parse everything up to the current position partial = beforecursor(s.input_buffer) full = LineEdit.input_string(s) - ret, range, should_complete = shell_completions(full, endof(partial)) + ret, range, should_complete = shell_completions(full, lastindex(partial)) return ret, partial[range], should_complete end function complete_line(c::LatexCompletions, s) partial = beforecursor(LineEdit.buffer(s)) full = LineEdit.input_string(s) - ret, range, should_complete = bslash_completions(full, endof(partial))[2] + ret, range, should_complete = bslash_completions(full, lastindex(partial))[2] return ret, partial[range], should_complete end @@ -612,7 +612,7 @@ function history_search(hist::REPLHistoryProvider, query_buffer::IOBuffer, respo # into the search data to index into the response string b = a + sizeof(searchdata) b = b ≤ ncodeunits(response_str) ? prevind(response_str, b) : b-1 - b = min(endof(response_str), b) # ensure that b is valid + b = min(lastindex(response_str), b) # ensure that b is valid !skip_current && searchdata == response_str[a:b] && return true @@ -623,7 +623,7 @@ function history_search(hist::REPLHistoryProvider, query_buffer::IOBuffer, respo # Start searching # First the current response buffer - if 1 <= searchstart <= endof(response_str) + if 1 <= searchstart <= lastindex(response_str) match = searchfunc2(searchdata, response_str, searchstart) if match != 0:-1 seek(response_buffer, first(match) - 1) diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index 8de33ff9d6e69..85142a5075399 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -201,10 +201,10 @@ function complete_path(path::AbstractString, pos; use_envpath=false) end matchList = String[replace(s, r"\s" => "\\ ") for s in matches] - startpos = pos - endof(prefix) + 1 - length(matchall(r" ", prefix)) - # The pos - endof(prefix) + 1 is correct due to `endof(prefix)-endof(prefix)==0`, + startpos = pos - lastindex(prefix) + 1 - length(matchall(r" ", prefix)) + # The pos - lastindex(prefix) + 1 is correct due to `lastindex(prefix)-lastindex(prefix)==0`, # hence we need to add one to get the first index. This is also correct when considering - # pos, because pos is the `endof` a larger string which `endswith(path)==true`. + # pos, because pos is the `lastindex` a larger string which `endswith(path)==true`. return matchList, startpos:pos, !isempty(matchList) end @@ -269,7 +269,7 @@ function find_start_brace(s::AbstractString; c_start='(', c_end=')') braces != 1 && return 0:-1, -1 method_name_end = reverseind(s, i) startind = nextind(s, coalesce(findprev(occursin(non_identifier_chars), s, method_name_end), 0)) - return (startind:endof(s), method_name_end) + return (startind:lastindex(s), method_name_end) end # Returns the value in a expression if sym is defined in current namespace fn. @@ -647,7 +647,7 @@ function shell_completions(string, pos) elseif isexpr(arg, :incomplete) || isexpr(arg, :error) r = first(last_parse):prevind(last_parse, last(last_parse)) partial = scs[r] - ret, range = completions(partial, endof(partial)) + ret, range = completions(partial, lastindex(partial)) range = range .+ (first(r) - 1) return ret, range, true end diff --git a/stdlib/REPL/test/replcompletions.jl b/stdlib/REPL/test/replcompletions.jl index 34fea57bfcac5..2c5426f99e0e5 100644 --- a/stdlib/REPL/test/replcompletions.jl +++ b/stdlib/REPL/test/replcompletions.jl @@ -101,9 +101,9 @@ function temp_pkg_dir_noinit(fn::Function) end end -test_complete(s) = completions(s,endof(s)) -test_scomplete(s) = shell_completions(s,endof(s)) -test_bslashcomplete(s) = bslash_completions(s,endof(s))[2] +test_complete(s) = completions(s,lastindex(s)) +test_scomplete(s) = shell_completions(s,lastindex(s)) +test_bslashcomplete(s) = bslash_completions(s,lastindex(s))[2] let s = "" c, r = test_complete(s) @@ -446,35 +446,35 @@ end let s = "(1+2im)." c,r = test_complete(s) @test length(c) == 2 - @test r == (endof(s) + 1):endof(s) + @test r == (lastindex(s) + 1):lastindex(s) @test c == ["im", "re"] end let s = "((1+2im))." c, r = test_complete(s) @test length(c) == 2 - @test r == (endof(s) + 1):endof(s) + @test r == (lastindex(s) + 1):lastindex(s) @test c == ["im", "re"] end let s = "CompletionFoo.test_y_array[1]." c, r = test_complete(s) @test length(c) == 1 - @test r == (endof(s) + 1):endof(s) + @test r == (lastindex(s) + 1):lastindex(s) @test c[1] == "yy" end let s = "CompletionFoo.Test_y(rand()).y" c, r = test_complete(s) @test length(c) == 1 - @test r == endof(s):endof(s) + @test r == lastindex(s):lastindex(s) @test c[1] == "yy" end let s = "CompletionFoo.test6()[1](CompletionFoo.Test_y(rand())).y" c, r = test_complete(s) @test length(c) == 1 - @test r == endof(s):endof(s) + @test r == lastindex(s):lastindex(s) @test c[1] == "yy" end @@ -721,12 +721,12 @@ let path = tempdir(), open(joinpath(space_folder, "space .file"),"w") do f s = Sys.iswindows() ? "rm $dir_space\\\\space" : "cd $dir_space/space" c,r = test_scomplete(s) - @test r == endof(s)-4:endof(s) + @test r == lastindex(s)-4:lastindex(s) @test "space\\ .file" in c s = Sys.iswindows() ? "cd(\"β $dir_space\\\\space" : "cd(\"β $dir_space/space" c,r = test_complete(s) - @test r == endof(s)-4:endof(s) + @test r == lastindex(s)-4:lastindex(s) @test "space\\ .file\"" in c end # Test for issue #10324 @@ -834,7 +834,7 @@ function test_dict_completion(dict_name) c, r = test_complete(s) @test c == Any["\"abcd\"]"] s = "$dict_name[\"abcd]" # trailing close bracket - c, r = completions(s, endof(s) - 1) + c, r = completions(s, lastindex(s) - 1) @test c == Any["\"abcd\""] s = "$dict_name[:b" c, r = test_complete(s) diff --git a/stdlib/Random/src/generation.jl b/stdlib/Random/src/generation.jl index 427157f106ef3..14112e1697e6a 100644 --- a/stdlib/Random/src/generation.jl +++ b/stdlib/Random/src/generation.jl @@ -416,12 +416,12 @@ Sampler(rng::AbstractRNG, str::AbstractString, n::Val{Inf}) = Sampler(rng, colle # when generating only one char from a string, the specialized method below # is usually more efficient Sampler(rng::AbstractRNG, str::AbstractString, ::Val{1}) = - SamplerSimple(str, Sampler(rng, 1:_endof(str), Val(Inf))) + SamplerSimple(str, Sampler(rng, 1:_lastindex(str), Val(Inf))) isvalid_unsafe(s::String, i) = !Base.is_valid_continuation(GC.@preserve s unsafe_load(pointer(s), i)) isvalid_unsafe(s::AbstractString, i) = isvalid(s, i) -_endof(s::String) = sizeof(s) -_endof(s::AbstractString) = endof(s) +_lastindex(s::String) = sizeof(s) +_lastindex(s::AbstractString) = lastindex(s) function rand(rng::AbstractRNG, sp::SamplerSimple{<:AbstractString,<:Sampler})::Char str = sp[] diff --git a/test/char.jl b/test/char.jl index 1e11b37ff3fcd..a431925df7e5a 100644 --- a/test/char.jl +++ b/test/char.jl @@ -88,9 +88,9 @@ let @test length(x) == 1 end - #endof(c::Char) = 1 + #lastindex(c::Char) = 1 for x in testarrays - @test endof(x) == 1 + @test lastindex(x) == 1 end #getindex(c::Char) = c diff --git a/test/dict.jl b/test/dict.jl index 4347939db6dc4..f4d9a4b1f4399 100644 --- a/test/dict.jl +++ b/test/dict.jl @@ -12,7 +12,7 @@ using Random @test !done(p,2) @test done(p,3) @test !done(p,0) - @test endof(p) == length(p) == 2 + @test lastindex(p) == length(p) == 2 @test Base.indexed_next(p, 1, (1,2)) == (10,2) @test Base.indexed_next(p, 2, (1,2)) == (20,3) @test (1=>2) < (2=>3) @@ -655,13 +655,13 @@ import Base.== const global hashoffset = [UInt(190)] Base.hash(s::MyString) = hash(s.str) + hashoffset[] -Base.endof(s::MyString) = endof(s.str) +Base.lastindex(s::MyString) = lastindex(s.str) Base.next(s::MyString, v::Int) = next(s.str, v) Base.isequal(a::MyString, b::MyString) = isequal(a.str, b.str) ==(a::MyString, b::MyString) = (a.str == b.str) Base.hash(v::MyInt) = v.val + hashoffset[] -Base.endof(v::MyInt) = endof(v.val) +Base.lastindex(v::MyInt) = lastindex(v.val) Base.next(v::MyInt, i::Int) = next(v.val, i) Base.isequal(a::MyInt, b::MyInt) = isequal(a.val, b.val) ==(a::MyInt, b::MyInt) = (a.val == b.val) diff --git a/test/numbers.jl b/test/numbers.jl index 0d609e66f2c4b..b3616d295557c 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -2858,7 +2858,7 @@ end @test !isinteger(π) @test size(1) == () @test length(1) == 1 - @test endof(1) == 1 + @test lastindex(1) == 1 @test eltype(Integer) == Integer end # issue #15920 diff --git a/test/offsetarray.jl b/test/offsetarray.jl index c46c9cda49e34..631bfee14c5aa 100644 --- a/test/offsetarray.jl +++ b/test/offsetarray.jl @@ -314,7 +314,7 @@ a = OffsetArray(a0, (-1,2,3,4,5)) # other functions v = OffsetArray(v0, (-3,)) -@test endof(v) == 1 +@test lastindex(v) == 1 @test v ≈ v @test axes(v') === (Base.OneTo(1),-2:1) @test parent(v) == collect(v) diff --git a/test/operators.jl b/test/operators.jl index 51a3094f025c9..31b95174df3b1 100644 --- a/test/operators.jl +++ b/test/operators.jl @@ -47,8 +47,8 @@ p = 1=>:foo @test last(p) == :foo @test first(reverse(p)) == :foo @test last(reverse(p)) == 1 -@test endof(p) == 2 -@test p[endof(p)] == p[end] == p[2] == :foo +@test lastindex(p) == 2 +@test p[lastindex(p)] == p[end] == p[2] == :foo @test (|)(2) == 2 @test xor(2) == 2 diff --git a/test/parse.jl b/test/parse.jl index 6114a6c34a1ef..47f862bcc2624 100644 --- a/test/parse.jl +++ b/test/parse.jl @@ -75,7 +75,7 @@ for T in vcat(subtypes(Signed), subtypes(Unsigned)) # Test that the entire input string appears in error messages let s = " false true " result = @test_throws(ArgumentError, - Base.tryparse_internal(Bool, s, start(s), endof(s), 0, true)) + Base.tryparse_internal(Bool, s, start(s), lastindex(s), 0, true)) @test result.value.msg == "invalid Bool representation: $(repr(s))" end diff --git a/test/read.jl b/test/read.jl index 80d8c26edb925..f9cc60061a7f7 100644 --- a/test/read.jl +++ b/test/read.jl @@ -165,8 +165,8 @@ for (name, f) in l local t, s, m, kept @test readuntil(io(t), s) == m @test readuntil(io(t), s, keep=true) == kept - @test readuntil(io(t), SubString(s, start(s), endof(s))) == m - @test readuntil(io(t), SubString(s, start(s), endof(s)), keep=true) == kept + @test readuntil(io(t), SubString(s, start(s), lastindex(s))) == m + @test readuntil(io(t), SubString(s, start(s), lastindex(s)), keep=true) == kept @test readuntil(io(t), GenericString(s)) == m @test readuntil(io(t), GenericString(s), keep=true) == kept @test readuntil(io(t), unsafe_wrap(Vector{UInt8},s)) == unsafe_wrap(Vector{UInt8},m) diff --git a/test/strings/basic.jl b/test/strings/basic.jl index 8e78a166c46e6..d730d4df23823 100644 --- a/test/strings/basic.jl +++ b/test/strings/basic.jl @@ -166,11 +166,11 @@ end let srep = repeat("Σβ",2) s="Σβ" - ss=SubString(s,1,endof(s)) + ss=SubString(s,1,lastindex(s)) @test repeat(ss,2) == "ΣβΣβ" - @test endof(srep) == 7 + @test lastindex(srep) == 7 @test next(srep, 3) == ('β',5) @test next(srep, 7) == ('β',9) @@ -217,7 +217,7 @@ end @test_throws MethodError isvalid(tstr, true) @test_throws MethodError next(tstr, 1) @test_throws MethodError next(tstr, true) - @test_throws MethodError endof(tstr) + @test_throws MethodError lastindex(tstr) gstr = GenericString("12") @test string(gstr) isa GenericString @@ -235,7 +235,7 @@ end @test first(eachindex("foobar")) === 1 @test first(eachindex("")) === 1 - @test last(eachindex("foobar")) === endof("foobar") + @test last(eachindex("foobar")) === lastindex("foobar") @test done(eachindex("foobar"),7) @test eltype(Base.EachStringIndex) == Int @test map(uppercase, "foó") == "FOÓ" @@ -461,9 +461,9 @@ end @test_throws ArgumentError ascii("Hello, ∀") @test_throws ArgumentError ascii(GenericString("Hello, ∀")) end -@testset "issue #17271: endof() doesn't throw an error even with invalid strings" begin - @test endof("\x90") == 1 - @test endof("\xce") == 1 +@testset "issue #17271: lastindex() doesn't throw an error even with invalid strings" begin + @test lastindex("\x90") == 1 + @test lastindex("\xce") == 1 end # issue #17624, missing getindex method for String @test "abc"[:] == "abc" @@ -471,8 +471,8 @@ end @testset "issue #18280: next/nextind must return past String's underlying data" begin for s in ("Hello", "Σ", "こんにちは", "😊😁") local s - @test next(s, endof(s))[2] > sizeof(s) - @test nextind(s, endof(s)) > sizeof(s) + @test next(s, lastindex(s))[2] > sizeof(s) + @test nextind(s, lastindex(s)) > sizeof(s) end end # Test cmp with AbstractStrings that don't index the same as UTF-8, which would include @@ -485,7 +485,7 @@ end Base.start(x::CharStr) = start(x.chars) Base.next(x::CharStr, i::Int) = next(x.chars, i) Base.done(x::CharStr, i::Int) = done(x.chars, i) -Base.endof(x::CharStr) = endof(x.chars) +Base.lastindex(x::CharStr) = lastindex(x.chars) @testset "cmp without UTF-8 indexing" begin # Simple case, with just ANSI Latin 1 characters @test "áB" != CharStr("áá") # returns false with bug diff --git a/test/strings/search.jl b/test/strings/search.jl index 0608e869e65ea..b494d72c83ee4 100644 --- a/test/strings/search.jl +++ b/test/strings/search.jl @@ -39,8 +39,8 @@ for str in [astr, GenericString(astr)] @test findnext(equalto(','), str, 7) == nothing @test findfirst(equalto('\n'), str) == 14 @test findnext(equalto('\n'), str, 15) == nothing - @test_throws BoundsError findnext(equalto('ε'), str, nextind(str,endof(str))+1) - @test_throws BoundsError findnext(equalto('a'), str, nextind(str,endof(str))+1) + @test_throws BoundsError findnext(equalto('ε'), str, nextind(str,lastindex(str))+1) + @test_throws BoundsError findnext(equalto('a'), str, nextind(str,lastindex(str))+1) end # ascii backward search @@ -85,10 +85,10 @@ for str in (u8str, GenericString(u8str)) @test findfirst(equalto('ε'), str) == 5 @test findnext(equalto('ε'), str, nextind(str,5)) == 54 @test findnext(equalto('ε'), str, nextind(str,54)) == nothing - @test findnext(equalto('ε'), str, nextind(str,endof(str))) == nothing - @test findnext(equalto('a'), str, nextind(str,endof(str))) == nothing - @test_throws BoundsError findnext(equalto('ε'), str, nextind(str,endof(str))+1) - @test_throws BoundsError findnext(equalto('a'), str, nextind(str,endof(str))+1) + @test findnext(equalto('ε'), str, nextind(str,lastindex(str))) == nothing + @test findnext(equalto('a'), str, nextind(str,lastindex(str))) == nothing + @test_throws BoundsError findnext(equalto('ε'), str, nextind(str,lastindex(str))+1) + @test_throws BoundsError findnext(equalto('a'), str, nextind(str,lastindex(str))+1) end # utf-8 backward search @@ -192,38 +192,38 @@ end @test findfirst(r"ε", u8str) == 5:5 @test findnext(r"ε", u8str, 7) == 54:54 @test findnext(r"ε", u8str, 56) == 0:-1 -for i = 1:endof(astr) +for i = 1:lastindex(astr) @test findnext(r"."s, astr, i) == i:i end -for i = 1:endof(u8str) +for i = 1:lastindex(u8str) if isvalid(u8str,i) @test findnext(r"."s, u8str, i) == i:i end end # string forward search with a zero-char string -for i = 1:endof(astr) +for i = 1:lastindex(astr) @test findnext("", astr, i) == i:i-1 end -for i = 1:endof(u8str) +for i = 1:lastindex(u8str) @test findnext("", u8str, i) == i:i-1 end @test findfirst("", "") == 1:0 # string backward search with a zero-char string -for i = 1:endof(astr) +for i = 1:lastindex(astr) @test findprev("", astr, i) == i:i-1 end -for i = 1:endof(u8str) +for i = 1:lastindex(u8str) @test findprev("", u8str, i) == i:i-1 end @test findlast("", "") == 1:0 # string forward search with a zero-char regex -for i = 1:endof(astr) +for i = 1:lastindex(astr) @test findnext(r"", astr, i) == i:i-1 end -for i = 1:endof(u8str) +for i = 1:lastindex(u8str) # TODO: should regex search fast-forward invalid indices? if isvalid(u8str,i) @test findnext(r"", u8str, i) == i:i-1 @@ -267,23 +267,23 @@ end # string backward search with a two-char UTF-8 (2 byte) string literal @test findlast("éé", "ééé") == 3:5 -@test findprev("éé", "ééé", endof("ééé")) == 3:5 +@test findprev("éé", "ééé", lastindex("ééé")) == 3:5 # string backward search with a two-char UTF-8 (3 byte) string literal @test findlast("€€", "€€€") == 4:7 -@test findprev("€€", "€€€", endof("€€€")) == 4:7 +@test findprev("€€", "€€€", lastindex("€€€")) == 4:7 # string backward search with a two-char UTF-8 (4 byte) string literal @test findlast("\U1f596\U1f596", "\U1f596\U1f596\U1f596") == 5:9 -@test findprev("\U1f596\U1f596", "\U1f596\U1f596\U1f596", endof("\U1f596\U1f596\U1f596")) == 5:9 +@test findprev("\U1f596\U1f596", "\U1f596\U1f596\U1f596", lastindex("\U1f596\U1f596\U1f596")) == 5:9 # string backward search with a two-char UTF-8 (2 byte) string literal @test findlast("éé", "éé") == 1:3 # should really be 1:4! -@test findprev("éé", "éé", endof("ééé")) == 1:3 +@test findprev("éé", "éé", lastindex("ééé")) == 1:3 # string backward search with a two-char UTF-8 (3 byte) string literal @test findlast("€€", "€€") == 1:4 # should really be 1:6! -@test findprev("€€", "€€", endof("€€€")) == 1:4 +@test findprev("€€", "€€", lastindex("€€€")) == 1:4 # string backward search with a two-char UTF-8 (4 byte) string literal @test findlast("\U1f596\U1f596", "\U1f596\U1f596") == 1:5 # should really be 1:8! -@test findprev("\U1f596\U1f596", "\U1f596\U1f596", endof("\U1f596\U1f596\U1f596")) == 1:5 +@test findprev("\U1f596\U1f596", "\U1f596\U1f596", lastindex("\U1f596\U1f596\U1f596")) == 1:5 # string backward search with a two-char string literal @test findlast("xx", "foo,bar,baz") == 0:-1 diff --git a/test/strings/types.jl b/test/strings/types.jl index 48df6715da005..02156f10bfe64 100644 --- a/test/strings/types.jl +++ b/test/strings/types.jl @@ -55,7 +55,7 @@ for idx in [0, 1, 4] @test SubString("∀∀", 4, idx) == "∀∀"[4:idx] end -# index beyond endof("∀∀") +# index beyond lastindex("∀∀") for idx in [2:3; 5:6] @test_throws StringIndexError SubString("∀∀", 1, idx) end @@ -64,10 +64,10 @@ for idx in 7:8 end let str="tempus fugit" #length(str)==12 - ss=SubString(str,1,endof(str)) #match source string + ss=SubString(str,1,lastindex(str)) #match source string @test length(ss)==length(str) - ss=SubString(str,1:endof(str)) + ss=SubString(str,1:lastindex(str)) @test length(ss)==length(str) ss=SubString(str,1,0) #empty SubString @@ -241,8 +241,8 @@ end @test c == s[reverseind(s, ri)] == r[ri] s = convert(T, string(prefix, prefix, c, suffix, suffix)) pre = convert(T, prefix) - sb = SubString(s, nextind(pre, endof(pre)), - endof(convert(T, string(prefix, prefix, c, suffix)))) + sb = SubString(s, nextind(pre, lastindex(pre)), + lastindex(convert(T, string(prefix, prefix, c, suffix)))) r = reverse(sb) ri = findfirst(equalto(c), r) @test c == sb[reverseind(sb, ri)] == r[ri] diff --git a/test/tuple.jl b/test/tuple.jl index 713592d2e1980..252a708943ee0 100644 --- a/test/tuple.jl +++ b/test/tuple.jl @@ -95,9 +95,9 @@ end @test_throws ArgumentError Base.front(()) @test_throws ArgumentError first(()) - @test endof(()) === 0 - @test endof((1,)) === 1 - @test endof((1,2)) === 2 + @test lastindex(()) === 0 + @test lastindex((1,)) === 1 + @test lastindex((1,2)) === 2 @test size((), 1) === 0 @test size((1,), 1) === 1 From e016f11a617296cf207749bfb83e14fd4e8e7f23 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Mon, 22 Jan 2018 17:15:12 -0500 Subject: [PATCH 2/2] Back out `a[begin]` syntax It was decided to delay this syntax change until after 1.0, since it is non-breaking. Once somebody wants to take this up again, they can simply revert this commit. --- NEWS.md | 3 --- doc/src/manual/functions.md | 4 ++-- doc/src/manual/interfaces.md | 9 ++++----- doc/src/manual/strings.md | 9 +++------ src/julia-syntax.scm | 36 ++++++++++++------------------------ 5 files changed, 21 insertions(+), 40 deletions(-) diff --git a/NEWS.md b/NEWS.md index 38bb0df50134e..4bc1c5c37c8ec 100644 --- a/NEWS.md +++ b/NEWS.md @@ -44,9 +44,6 @@ 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 ---------------- diff --git a/doc/src/manual/functions.md b/doc/src/manual/functions.md index 0664f6f758f98..fc3aaa87dd938 100644 --- a/doc/src/manual/functions.md +++ b/doc/src/manual/functions.md @@ -692,8 +692,8 @@ the results (see [Pre-allocating outputs](@ref)). A convenient syntax for this i is equivalent to `broadcast!(identity, X, ...)` except that, as above, the `broadcast!` loop is fused with any nested "dot" calls. For example, `X .= sin.(Y)` is equivalent to `broadcast!(sin, X, Y)`, overwriting `X` with `sin.(Y)` in-place. If the left-hand side is an array-indexing expression, -e.g. `X[begin+1:end] .= sin.(Y)`, then it translates to `broadcast!` on a `view`, e.g. -`broadcast!(sin, view(X, firstindex(X)+1:lastindex(X)), Y)`, +e.g. `X[2:end] .= sin.(Y)`, then it translates to `broadcast!` on a `view`, e.g. +`broadcast!(sin, view(X, 2:lastindex(X)), Y)`, so that the left-hand side is updated in-place. Since adding dots to many operations and function calls in an expression diff --git a/doc/src/manual/interfaces.md b/doc/src/manual/interfaces.md index 3e19bbf93357c..1ca83709c9587 100644 --- a/doc/src/manual/interfaces.md +++ b/doc/src/manual/interfaces.md @@ -161,8 +161,8 @@ julia> collect(Iterators.reverse(Squares(10)))' # transposed to save space |:-------------------- |:-------------------------------- | | `getindex(X, i)` | `X[i]`, indexed element access | | `setindex!(X, v, i)` | `X[i] = v`, indexed assignment | -| `firstindex(X)` | The first index, used in `X[begin]` | -| `lastindex(X)` | The last index, used in `X[end]` | +| `firstindex(X)` | The first index | +| `lastindex(X)` | The last index, used in `X[end]` | For the `Squares` iterable above, we can easily compute the `i`th element of the sequence by squaring it. We can expose this as an indexing expression `S[i]`. To opt into this behavior, `Squares` @@ -178,9 +178,8 @@ julia> Squares(100)[23] 529 ``` -Additionally, to support the syntax `S[begin]` and `S[end]`, we must define [`firstindex`](@ref) and -[`lastindex`](@ref) to specify the first and last valid -index, respectively: +Additionally, to support the syntax `S[end]`, we must define [`lastindex`](@ref) to specify the last +valid index. It is recommended to also define [`firstindex`](@ref) to specify the first valid index: ```jldoctest squaretype julia> Base.firstindex(S::Squares) = 1 diff --git a/doc/src/manual/strings.md b/doc/src/manual/strings.md index 1f0339864fe3d..2f680f7b4b41f 100644 --- a/doc/src/manual/strings.md +++ b/doc/src/manual/strings.md @@ -168,9 +168,6 @@ julia> """Contains "quote" characters""" If you want to extract a character from a string, you index into it: ```jldoctest helloworldstring -julia> str[begin] -'H': ASCII/Unicode U+0048 (category Lu: Letter, uppercase) - julia> str[1] 'H': ASCII/Unicode U+0048 (category Lu: Letter, uppercase) @@ -183,8 +180,8 @@ julia> str[end] Many Julia objects, including strings, can be indexed with integers. The index of the first element is returned by [`firstindex(str)`](@ref), and the index of the last element -with [`lastindex(str)`](@ref). The keywords `begin` and `end` can be used inside an indexing -operation as shorthand for the first and last index along the given dimension. +with [`lastindex(str)`](@ref). The keyword`end` can be used inside an indexing +operation as shorthand for the last index along the given dimension. Most indexing in Julia is 1-based: the first element of many integer-indexed objects is found at index 1. (As we will see below, this does not necessarily mean that the last element is found at index `n`, where `n` is the length of the string.) @@ -203,7 +200,7 @@ julia> str[end÷2] Using an index less than 1 or greater than `end` raises an error: ```jldoctest helloworldstring -julia> str[begin-1] +julia> str[0] ERROR: BoundsError: attempt to access "Hello, world.\n" at index [0] [...] diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 86890b5557364..aef2a8485da17 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -86,11 +86,11 @@ (define (expand-compare-chain e) (car (expand-vector-compare e))) -;; return the appropriate computation for a `begin` or `end` symbol for indexing +;; return the appropriate computation for an `end` symbol for indexing ;; 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, e.g., lastindex(a) or last(axes(a,n)) +;; returns a call to lastindex(a) or last(axes(a,n)) (define (end-val a n tuples last) (if (null? tuples) (if (and last (= n 1)) @@ -101,31 +101,20 @@ tuples)))) `(call (top last) (call (top axes) ,a ,dimno))))) -(define (begin-val a n tuples last) - (if (null? tuples) - (if (and last (= n 1)) - `(call (top firstindex) ,a) - `(call (top first) (call (top axes) ,a ,n))) - (let ((dimno `(call (top +) ,(- n (length tuples)) - ,.(map (lambda (t) `(call (top length) ,t)) - tuples)))) - `(call (top first) (call (top axes) ,a ,dimno))))) - -;; replace `begin` and `end` for the closest ref expression, so doesn't go inside nested refs -(define (replace-beginend ex a n tuples last) +;; replace `end` for the closest ref expression, so doesn't go inside nested refs +(define (replace-end ex a n tuples last) (cond ((eq? ex 'end) (end-val a n tuples last)) - ((eq? ex 'begin) (begin-val a n tuples last)) ((or (atom? ex) (quoted? ex)) ex) ((eq? (car ex) 'ref) ;; inside ref only replace within the first argument - (list* 'ref (replace-beginend (cadr ex) a n tuples last) + (list* 'ref (replace-end (cadr ex) a n tuples last) (cddr ex))) (else (cons (car ex) - (map (lambda (x) (replace-beginend x a n tuples last)) + (map (lambda (x) (replace-end x a n tuples last)) (cdr ex)))))) -;; go through indices and replace the `begin` or `end` symbol +;; go through indices and replace the `end` symbol ;; a = array being indexed, i = list of indices ;; returns (values index-list stmts) where stmts are statements that need ;; to execute first. @@ -144,17 +133,17 @@ (loop (cdr lst) (+ n 1) stmts (cons (cadr idx) tuples) - (cons `(... ,(replace-beginend (cadr idx) a n tuples last)) + (cons `(... ,(replace-end (cadr idx) a n tuples last)) ret)) (let ((g (make-ssavalue))) (loop (cdr lst) (+ n 1) - (cons `(= ,g ,(replace-beginend (cadr idx) a n tuples last)) + (cons `(= ,g ,(replace-end (cadr idx) a n tuples last)) stmts) (cons g tuples) (cons `(... ,g) ret)))) (loop (cdr lst) (+ n 1) stmts tuples - (cons (replace-beginend idx a n tuples last) ret))))))) + (cons (replace-end idx a n tuples last) ret))))))) ;; GF method does not need to keep decl expressions on lambda args ;; except for rest arg @@ -1511,8 +1500,7 @@ (idxs (cddr e))) (let* ((reuse (and (pair? a) (contains (lambda (x) - (or (eq? x 'begin) - (eq? x 'end) + (or (eq? x 'end) (eq? x ':) (and (pair? x) (eq? (car x) ':)))) @@ -1527,7 +1515,7 @@ (define (expand-update-operator op op= lhs rhs . declT) (cond ((and (pair? lhs) (eq? (car lhs) 'ref)) - ;; expand indexing inside op= first, to remove "begin", "end", and ":" + ;; expand indexing inside op= first, to remove "end" and ":" (let* ((ex (partially-expand-ref lhs)) (stmts (butlast (cdr ex))) (refex (last (cdr ex)))