Skip to content

Commit 0e7b347

Browse files
committed
Remove RevString
The `RevString` type for lazily reversed strings has been moved to the LegacyStrings package. Fixes #22611. Calling `reverse` on an `AbstractString` with no more specific method now unconditionally returns a `String`.
1 parent b8a488b commit 0e7b347

File tree

14 files changed

+152
-130
lines changed

14 files changed

+152
-130
lines changed

NEWS.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ Language changes
138138

139139
* The syntax `(x...)` for constructing a tuple is deprecated; use `(x...,)` instead (#24452).
140140

141+
* The `RevString` type for lazily reversed strings has been moved to the LegacyStrings
142+
package ([#22611]).
143+
141144
Breaking changes
142145
----------------
143146

@@ -288,6 +291,9 @@ This section lists changes that do not have deprecation warnings.
288291
Its return value has been removed. Use the `process_running` function
289292
to determine if a process has already exited.
290293

294+
* `reverse(::AbstractString)` now unconditionally returns a `String`. Previously it
295+
returned a `RevString`, which has been removed from Base ([#23612]).
296+
291297
Library improvements
292298
--------------------
293299

@@ -1525,6 +1531,7 @@ Command-line option changes
15251531
[#22572]: https://github.com/JuliaLang/julia/issues/22572
15261532
[#22588]: https://github.com/JuliaLang/julia/issues/22588
15271533
[#22605]: https://github.com/JuliaLang/julia/issues/22605
1534+
[#22611]: https://github.com/JuliaLang/julia/issues/22611
15281535
[#22666]: https://github.com/JuliaLang/julia/issues/22666
15291536
[#22696]: https://github.com/JuliaLang/julia/issues/22696
15301537
[#22703]: https://github.com/JuliaLang/julia/issues/22703
@@ -1580,6 +1587,7 @@ Command-line option changes
15801587
[#23529]: https://github.com/JuliaLang/julia/issues/23529
15811588
[#23530]: https://github.com/JuliaLang/julia/issues/23530
15821589
[#23570]: https://github.com/JuliaLang/julia/issues/23570
1590+
[#23612]: https://github.com/JuliaLang/julia/issues/23612
15831591
[#23628]: https://github.com/JuliaLang/julia/issues/23628
15841592
[#23665]: https://github.com/JuliaLang/julia/issues/23665
15851593
[#23690]: https://github.com/JuliaLang/julia/issues/23690

base/deprecated.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2200,7 +2200,6 @@ end
22002200
@deprecate chol!(x::Number, uplo) chol(x) false
22012201
end
22022202

2203-
22042203
# issue #16307
22052204
@deprecate finalizer(o, f::Function) finalizer(f, o)
22062205
# This misses other callables but they are very rare in the wild
@@ -2211,6 +2210,9 @@ end
22112210
finalizer(f::Ptr{Void}, o::Ptr{Void}) = invoke(finalizer, Tuple{Ptr{Void}, Any}, f, o)
22122211
finalizer(f::Ptr{Void}, o::Function) = invoke(finalizer, Tuple{Ptr{Void}, Any}, f, o)
22132212

2213+
# Issue #22611
2214+
@deprecate_moved RevString "LegacyStrings"
2215+
22142216
# END 0.7 deprecations
22152217

22162218
# BEGIN 1.0 deprecations

base/exports.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ export
8888
Rational,
8989
Regex,
9090
RegexMatch,
91-
RevString,
9291
RoundFromZero,
9392
RoundDown,
9493
RoundingMode,

base/precompile.jl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -581,9 +581,6 @@ precompile(Tuple{typeof(Base.LineEdit.complete_line), Base.LineEdit.PromptState,
581581
precompile(Tuple{typeof(Base.LineEdit.input_string_newlines_aftercursor), Base.LineEdit.PromptState})
582582
precompile(Tuple{typeof(Base.LineEdit.complete_line), Base.REPL.REPLCompletionProvider, Base.LineEdit.PromptState})
583583
precompile(Tuple{getfield(Base, Symbol("#kw##parse")), Array{Any, 1}, typeof(Base.parse), String})
584-
precompile(Tuple{typeof(Base.isvalid), Base.RevString{String}, Int64})
585-
precompile(Tuple{typeof(Base.nextind), Base.RevString{String}, Int64})
586-
precompile(Tuple{typeof(Base.search), Base.RevString{String}, Array{Char, 1}, Int64})
587584
precompile(Tuple{typeof(Base.rsearch), String, Array{Char, 1}, Int64})
588585
precompile(Tuple{getfield(Base.REPLCompletions, Symbol("#kw##find_start_brace")), Array{Any, 1}, typeof(Base.REPLCompletions.find_start_brace), String})
589586
precompile(Tuple{typeof(Core.Inference.isbits), Tuple{Void, Void, Void}})

base/repl/REPLCompletions.jl

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -225,13 +225,13 @@ end
225225
# closed start brace from the end of the string.
226226
function find_start_brace(s::AbstractString; c_start='(', c_end=')')
227227
braces = 0
228-
r = RevString(s)
229-
i = start(r)
228+
i = endof(s)
230229
in_single_quotes = false
231230
in_double_quotes = false
232231
in_back_ticks = false
233-
while !done(r, i)
234-
c, i = next(r, i)
232+
while i > 0
233+
c = s[i]
234+
nexti = prevind(s, i)
235235
if !in_single_quotes && !in_double_quotes && !in_back_ticks
236236
if c == c_start
237237
braces += 1
@@ -245,18 +245,19 @@ function find_start_brace(s::AbstractString; c_start='(', c_end=')')
245245
in_back_ticks = true
246246
end
247247
else
248-
if !in_back_ticks && !in_double_quotes && c == '\'' && !done(r, i) && next(r, i)[1]!='\\'
248+
if !in_back_ticks && !in_double_quotes && c == '\'' && i > 0 && s[nexti] != '\\'
249249
in_single_quotes = !in_single_quotes
250-
elseif !in_back_ticks && !in_single_quotes && c == '"' && !done(r, i) && next(r, i)[1]!='\\'
250+
elseif !in_back_ticks && !in_single_quotes && c == '"' && i > 0 && s[nexti] != '\\'
251251
in_double_quotes = !in_double_quotes
252-
elseif !in_single_quotes && !in_double_quotes && c == '`' && !done(r, i) && next(r, i)[1]!='\\'
252+
elseif !in_single_quotes && !in_double_quotes && c == '`' && i > 0 && s[nexti] != '\\'
253253
in_back_ticks = !in_back_ticks
254254
end
255255
end
256256
braces == 1 && break
257+
i = nexti
257258
end
258259
braces != 1 && return 0:-1, -1
259-
method_name_end = reverseind(r, i)
260+
method_name_end = i - 1
260261
startind = nextind(s, rsearch(s, non_identifier_chars, method_name_end))
261262
return (startind:endof(s), method_name_end)
262263
end

base/shell.jl

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,20 @@ function shell_parse(str::AbstractString, interpolate::Bool=true;
1414
special::AbstractString="")
1515
s = lstrip(str)
1616
# strips the end but respects the space when the string ends with "\\ "
17-
r = RevString(s)
18-
i = start(r)
19-
c_old = nothing
20-
while !done(r,i)
21-
c, j = next(r,i)
17+
i = endof(s)
18+
c_old = '\0' # initialized to a null byte for type stability
19+
while i > 0
20+
c = s[i]
2221
if c == '\\' && c_old == ' '
23-
i -= 1
22+
i += 1
2423
break
2524
elseif !(c in _default_delims)
2625
break
2726
end
28-
i = j
27+
i = prevind(s, i)
2928
c_old = c
3029
end
31-
s = s[1:end-i+1]
30+
s = s[1:i]
3231

3332
last_parse = 0:-1
3433
isempty(s) && return interpolate ? (Expr(:tuple,:()),last_parse) : ([],last_parse)

base/strings/basic.jl

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,3 +646,77 @@ next(r::Iterators.Reverse{<:AbstractString}, i) = (r.itr[i], prevind(r.itr, i))
646646
start(r::Iterators.Reverse{<:EachStringIndex}) = endof(r.itr.s)
647647
done(r::Iterators.Reverse{<:EachStringIndex}, i) = i < start(r.itr.s)
648648
next(r::Iterators.Reverse{<:EachStringIndex}, i) = (i, prevind(r.itr.s, i))
649+
650+
"""
651+
reverse(s::AbstractString) -> String
652+
653+
Reverse a string. The result is always a `String`, regardless of the input type.
654+
655+
Technically, this function reverses the codepoints in a string, and its
656+
main utility is for reversed-order string processing, especially for reversed
657+
regular-expression searches. See also [`reverseind`](@ref) to convert indices
658+
in `s` to indices in `reverse(s)` and vice-versa, and [`graphemes`](@ref)
659+
to operate on user-visible "characters" (graphemes) rather than codepoints.
660+
661+
# Examples
662+
```jldoctest
663+
julia> reverse("JuliaLang")
664+
"gnaLailuJ"
665+
666+
julia> reverse("ax̂e") # combining characters can lead to surprising results
667+
"êxa"
668+
669+
julia> join(reverse(collect(graphemes("ax̂e")))) # reverses graphemes
670+
"ex̂a"
671+
```
672+
"""
673+
reverse(s::AbstractString) = reverse(convert(String, s))
674+
675+
## reverse an index i so that reverse(s)[i] == s[reverseind(s,i)]
676+
677+
"""
678+
reverseind(v, i)
679+
680+
Given an index `i` in [`reverse(v)`](@ref), return the corresponding index in `v` so that
681+
`v[reverseind(v,i)] == reverse(v)[i]`. (This can be nontrivial in cases where `v` contains
682+
non-ASCII characters.)
683+
684+
# Examples
685+
```jldoctest
686+
julia> r = reverse("Julia")
687+
"ailuJ"
688+
689+
julia> for i in 1:length(r)
690+
print(r[reverseind("Julia", i)])
691+
end
692+
Julia
693+
```
694+
"""
695+
reverseind(s::AbstractString, i) = chr2ind(s, length(s) + 1 - ind2chr(reverse(s), i))
696+
697+
"""
698+
repeat(s::AbstractString, r::Integer)
699+
700+
Repeat a string `r` times. This can equivalently be accomplished by calling [`s^r`](@ref ^).
701+
702+
# Examples
703+
```jldoctest
704+
julia> repeat("ha", 3)
705+
"hahaha"
706+
```
707+
"""
708+
repeat(s::AbstractString, r::Integer) = repeat(convert(String, s), r)
709+
710+
"""
711+
^(s::Union{AbstractString,Char}, n::Integer)
712+
713+
Repeat a string or character `n` times.
714+
The [`repeat`](@ref) function is an alias to this operator.
715+
716+
# Examples
717+
```jldoctest
718+
julia> "Test "^3
719+
"Test Test Test "
720+
```
721+
"""
722+
(^)(s::Union{AbstractString,Char}, r::Integer) = repeat(s, r)

base/strings/search.jl

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -194,12 +194,6 @@ end
194194
search(s::AbstractString, t::AbstractString, i::Integer=start(s)) = _search(s, t, i)
195195
search(s::ByteArray, t::ByteArray, i::Integer=start(s)) = _search(s, t, i)
196196

197-
function rsearch(s::AbstractString, c::Chars)
198-
j = search(RevString(s), c)
199-
j == 0 && return 0
200-
endof(s)-j+1
201-
end
202-
203197
"""
204198
rsearch(s::AbstractString, chars::Chars, [start::Integer])
205199
@@ -212,44 +206,52 @@ julia> rsearch("aaabbb","b")
212206
6:6
213207
```
214208
"""
215-
function rsearch(s::AbstractString, c::Chars, i::Integer)
216-
e = endof(s)
217-
j = search(RevString(s), c, e-i+1)
218-
j == 0 && return 0
219-
e-j+1
209+
function rsearch(s::AbstractString, c::Chars, i::Integer=endof(s))
210+
@boundscheck checkbounds(s, i)
211+
isempty(c) && return i
212+
j = Int(i)
213+
@inbounds while j > 0
214+
s[j] in c && return j
215+
j = prevind(s, j)
216+
end
217+
return 0
220218
end
221219

222220
function _rsearchindex(s, t, i)
223221
if isempty(t)
224-
return 1 <= i <= nextind(s,endof(s)) ? i :
225-
throw(BoundsError(s, i))
222+
@boundscheck checkbounds(s, i)
223+
return i
226224
end
227-
t = RevString(t)
228-
rs = RevString(s)
229225
l = endof(s)
230-
t1, j2 = next(t,start(t))
226+
j2 = endof(t)
227+
t1 = t[j2]
231228
while true
232-
i = rsearch(s,t1,i)
233-
if i == 0 return 0 end
234-
c, ii = next(rs,l-i+1)
235-
j = j2; k = ii
229+
i = rsearch(s, t1, i)
230+
i == 0 && return 0
231+
c = s[i]
232+
ii = prevind(s, i)
233+
j, k = j2, ii
236234
matched = true
237-
while !done(t,j)
238-
if done(rs,k)
235+
while j > 1
236+
if k < 1
239237
matched = false
240238
break
241239
end
242-
c, k = next(rs,k)
243-
d, j = next(t,j)
240+
# Using `reverseind` with `prevind` in this way is like calling `nextind`
241+
# on the reversed string
242+
rk = reverseind(s, k)
243+
c = s[rk]
244+
k = prevind(s, rk)
245+
rj = reverseind(t, j)
246+
d = t[rj]
247+
j = prevind(t, rj)
244248
if c != d
245249
matched = false
246250
break
247251
end
248252
end
249-
if matched
250-
return nextind(s,l-k+1)
251-
end
252-
i = l-ii+1
253+
matched && return nextind(s, k)
254+
i = ii
253255
end
254256
end
255257

base/strings/types.jl

Lines changed: 1 addition & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# This file is a part of Julia. License is MIT: https://julialang.org/license
22

3-
# SubString and RevString types
3+
# SubString type
44

55
## substrings reference original strings ##
66

@@ -109,48 +109,6 @@ function unsafe_convert(::Type{Ptr{R}}, s::SubString{String}) where R<:Union{Int
109109
convert(Ptr{R}, pointer(s.string)) + s.offset
110110
end
111111

112-
## reversed strings without data movement ##
113-
114-
struct RevString{T<:AbstractString} <: AbstractString
115-
string::T
116-
end
117-
118-
endof(s::RevString) = endof(s.string)
119-
length(s::RevString) = length(s.string)
120-
sizeof(s::RevString) = sizeof(s.string)
121-
122-
function next(s::RevString, i::Int)
123-
n = endof(s); j = n-i+1
124-
(s.string[j], n-prevind(s.string,j)+1)
125-
end
126-
127-
"""
128-
reverse(s::AbstractString) -> AbstractString
129-
130-
Reverses a string.
131-
132-
Technically, this function reverses the codepoints in a string, and its
133-
main utility is for reversed-order string processing, especially for reversed
134-
regular-expression searches. See also [`reverseind`](@ref) to convert indices
135-
in `s` to indices in `reverse(s)` and vice-versa, and [`graphemes`](@ref)
136-
to operate on user-visible "characters" (graphemes) rather than codepoints.
137-
See also [`Iterators.reverse`](@ref) for reverse-order iteration without making a copy.
138-
139-
# Examples
140-
```jldoctest
141-
julia> reverse("JuliaLang")
142-
"gnaLailuJ"
143-
144-
julia> reverse("ax̂e") # combining characters can lead to surprising results
145-
"êxa"
146-
147-
julia> join(reverse(collect(graphemes("ax̂e")))) # reverses graphemes
148-
"ex̂a"
149-
```
150-
"""
151-
reverse(s::AbstractString) = RevString(s)
152-
reverse(s::RevString) = s.string
153-
154112
## reverse an index i so that reverse(s)[i] == s[reverseind(s,i)]
155113

156114
"""
@@ -172,7 +130,6 @@ Julia
172130
```
173131
"""
174132
reverseind(s::AbstractString, i) = chr2ind(s, length(s) + 1 - ind2chr(reverse(s), i))
175-
reverseind(s::RevString, i::Integer) = endof(s) - i + 1
176133
reverseind(s::SubString{String}, i::Integer) =
177134
reverseind(s.string, nextind(s.string, endof(s.string))-s.offset-s.endof+i-1) - s.offset
178135

base/strings/util.jl

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -190,14 +190,10 @@ julia> rstrip(a)
190190
```
191191
"""
192192
function rstrip(s::AbstractString, chars::Chars=_default_delims)
193-
r = RevString(s)
194-
i = start(r)
195-
while !done(r,i)
196-
c, j = next(r,i)
197-
if !(c in chars)
198-
return SubString(s, 1, endof(s)-i+1)
199-
end
200-
i = j
193+
i = endof(s)
194+
while i > 0
195+
s[i] in chars || return SubString(s, 1, i)
196+
i = prevind(s, i)
201197
end
202198
SubString(s, 1, 0)
203199
end

0 commit comments

Comments
 (0)