Skip to content

Commit a384401

Browse files
committed
Remove RevString and deprecate reverse(::AbstractString)
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 has been deprecated in favor of explicitly converting to `String` before reversing.
1 parent 83a89a1 commit a384401

File tree

13 files changed

+82
-116
lines changed

13 files changed

+82
-116
lines changed

NEWS.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@ Language changes
100100
* Prefix `&` for by-reference arguments to `ccall` has been deprecated in favor of
101101
`Ref` argument types ([#6080]).
102102

103+
* The `RevString` type for lazily reversed strings has been moved to the LegacyStrings
104+
package ([#22611]).
105+
106+
* `reverse` on `AbstractString`s has been deprecated in favor of converting to `String`
107+
before reversing ([#23612]).
108+
103109
Breaking changes
104110
----------------
105111

@@ -1311,6 +1317,7 @@ Command-line option changes
13111317
[#22532]: https://github.com/JuliaLang/julia/issues/22532
13121318
[#22588]: https://github.com/JuliaLang/julia/issues/22588
13131319
[#22605]: https://github.com/JuliaLang/julia/issues/22605
1320+
[#22611]: https://github.com/JuliaLang/julia/issues/22611
13141321
[#22666]: https://github.com/JuliaLang/julia/issues/22666
13151322
[#22696]: https://github.com/JuliaLang/julia/issues/22696
13161323
[#22703]: https://github.com/JuliaLang/julia/issues/22703
@@ -1340,3 +1347,4 @@ Command-line option changes
13401347
[#23233]: https://github.com/JuliaLang/julia/issues/23233
13411348
[#23342]: https://github.com/JuliaLang/julia/issues/23342
13421349
[#23404]: https://github.com/JuliaLang/julia/issues/23404
1350+
[#23612]: https://github.com/JuliaLang/julia/issues/23612

base/deprecated.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1855,6 +1855,12 @@ end
18551855
nothing
18561856
end
18571857

1858+
# Issue #22611
1859+
@deprecate_moved RevString "LegacyStrings"
1860+
1861+
# PR 23612
1862+
@deprecate reverse(s::AbstractString) reverse(String(s))
1863+
18581864
# END 0.7 deprecations
18591865

18601866
# BEGIN 1.0 deprecations

base/exports.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ export
9292
Rational,
9393
Regex,
9494
RegexMatch,
95-
RevString,
9695
RoundFromZero,
9796
RoundDown,
9897
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
@@ -12,21 +12,20 @@ function shell_parse(str::AbstractString, interpolate::Bool=true;
1212
special::AbstractString="")
1313
s = lstrip(str)
1414
# strips the end but respects the space when the string ends with "\\ "
15-
r = RevString(s)
16-
i = start(r)
17-
c_old = nothing
18-
while !done(r,i)
19-
c, j = next(r,i)
15+
i = endof(s)
16+
c_old = '\0' # initialized to a null byte for type stability
17+
while i > 0
18+
c = s[i]
2019
if c == '\\' && c_old == ' '
21-
i -= 1
20+
i += 1
2221
break
2322
elseif !(c in _default_delims)
2423
break
2524
end
26-
i = j
25+
i = prevind(s, i)
2726
c_old = c
2827
end
29-
s = s[1:end-i+1]
28+
s = s[1:i]
3029

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

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=start(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 > 0
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` mimics `next` but for iteration over
241+
# `reverse(s)` (without actually having to call `reverse`) since `reverseind`
242+
# is the current index in `reverse(s)` and `prevind` is the index for the
243+
# next iteration.
244+
rs_k = reverseind(s, k)
245+
c, k = s[rs_k], prevind(s, rs_k)
246+
rt_j = reverseind(t, j)
247+
d, j = t[rt_j], prevind(t, rt_j)
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 & 31 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

@@ -97,35 +97,6 @@ function unsafe_convert(::Type{Ptr{R}}, s::SubString{String}) where R<:Union{Int
9797
convert(Ptr{R}, pointer(s.string)) + s.offset
9898
end
9999

100-
## reversed strings without data movement ##
101-
102-
struct RevString{T<:AbstractString} <: AbstractString
103-
string::T
104-
end
105-
106-
endof(s::RevString) = endof(s.string)
107-
length(s::RevString) = length(s.string)
108-
sizeof(s::RevString) = sizeof(s.string)
109-
110-
function next(s::RevString, i::Int)
111-
n = endof(s); j = n-i+1
112-
(s.string[j], n-prevind(s.string,j)+1)
113-
end
114-
115-
"""
116-
reverse(s::AbstractString) -> AbstractString
117-
118-
Reverses a string.
119-
120-
# Examples
121-
```jldoctest
122-
julia> reverse("JuliaLang")
123-
"gnaLailuJ"
124-
```
125-
"""
126-
reverse(s::AbstractString) = RevString(s)
127-
reverse(s::RevString) = s.string
128-
129100
## reverse an index i so that reverse(s)[i] == s[reverseind(s,i)]
130101

131102
"""
@@ -148,7 +119,6 @@ Julia
148119
"""
149120
reverseind(s::AbstractString, i) = chr2ind(s, length(s) + 1 - ind2chr(reverse(s), i))
150121
reverseind(s::Union{DirectIndexString,SubString{DirectIndexString}}, i::Integer) = length(s) + 1 - i
151-
reverseind(s::RevString, i::Integer) = endof(s) - i + 1
152122
reverseind(s::SubString{String}, i::Integer) =
153123
reverseind(s.string, nextind(s.string, endof(s.string))-s.offset-s.endof+i-1) - s.offset
154124

base/strings/util.jl

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -173,14 +173,11 @@ julia> rstrip(a)
173173
```
174174
"""
175175
function rstrip(s::AbstractString, chars::Chars=_default_delims)
176-
r = RevString(s)
177-
i = start(r)
178-
while !done(r,i)
179-
c, j = next(r,i)
180-
if !(c in chars)
181-
return SubString(s, 1, endof(s)-i+1)
182-
end
183-
i = j
176+
i = endof(s)
177+
while i > 0
178+
c = s[i]
179+
c in chars || return SubString(s, 1, i)
180+
i = prevind(s, i)
184181
end
185182
SubString(s, 1, 0)
186183
end

contrib/Julia_Notepad++.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
<Keywords name="Folders in comment, middle"></Keywords>
2626
<Keywords name="Folders in comment, close"></Keywords>
2727
<Keywords name="Keywords1">true false C_NULL Inf NaN Inf32 NaN32 nothing</Keywords>
28-
<Keywords name="Keywords2">AbstractArray AbstractMatrix AbstractRange AbstractRemoteRef AbstractSparseMatrix AbstractString AbstractVector Any ArgumentError Array Associative BigFloat BigInt BitArray BitMatrix BitVector Bool BunchKaufman Cchar Cdouble Cfloat Char CharString CholeskyDense CholeskyPivotedDense Cint Cintmax_t Clong Clonglong Colon Complex Complex128 Complex64 ComplexPair Cptrdiff_t Cshort Csize_t Cuchar Cuint Cuintmax_t Culong Culonglong Cushort DArray Dict Dims DisconnectException EOFError EachLine EnvHash ErrorException Exception Expr Factorization Filter Float Float32 Float64 Function GSVDDense IO IOBuffer IOStream ImaginaryUnit InsertionSort Int Int128 Int16 Int32 Int64 Int8 IntSet Integer KeyError LDLTTridiagonal LUDense LUTridiagonal LoadError LocalProcess Matrix MergeSort MethodError NTuple Number ObjectIdDict ObjectIdDict OrdinalRange ParseError PipeBuffer ProcessGroup Ptr QRDense QRPivotedDense QuickSort RangeIndex Rational Real Regex RegexMatch RegexMatchIterator RepString RevString Reverse SVDDense Set Signed SparseMatrixCSC SpawnNullStream Stat StridedArray StridedMatrix StridedVecOrMat StridedVector String SubArray SubDArray SubOrDArray SubString SymTridiagonal Symbol SystemError Task TCPSocket TimSort Tridiagonal Tuple Type TypeError UInt UInt128 UInt16 UInt32 UInt64 UInt8 UVError Union UnitRange Unsigned VecOrMat Vector VersionNumber Void WeakKeyDict WeakRef Zip</Keywords>
28+
<Keywords name="Keywords2">AbstractArray AbstractMatrix AbstractRange AbstractRemoteRef AbstractSparseMatrix AbstractString AbstractVector Any ArgumentError Array Associative BigFloat BigInt BitArray BitMatrix BitVector Bool BunchKaufman Cchar Cdouble Cfloat Char CharString CholeskyDense CholeskyPivotedDense Cint Cintmax_t Clong Clonglong Colon Complex Complex128 Complex64 ComplexPair Cptrdiff_t Cshort Csize_t Cuchar Cuint Cuintmax_t Culong Culonglong Cushort DArray Dict Dims DisconnectException EOFError EachLine EnvHash ErrorException Exception Expr Factorization Filter Float Float32 Float64 Function GSVDDense IO IOBuffer IOStream ImaginaryUnit InsertionSort Int Int128 Int16 Int32 Int64 Int8 IntSet Integer KeyError LDLTTridiagonal LUDense LUTridiagonal LoadError LocalProcess Matrix MergeSort MethodError NTuple Number ObjectIdDict ObjectIdDict OrdinalRange ParseError PipeBuffer ProcessGroup Ptr QRDense QRPivotedDense QuickSort RangeIndex Rational Real Regex RegexMatch RegexMatchIterator RepString Reverse SVDDense Set Signed SparseMatrixCSC SpawnNullStream Stat StridedArray StridedMatrix StridedVecOrMat StridedVector String SubArray SubDArray SubOrDArray SubString SymTridiagonal Symbol SystemError Task TCPSocket TimSort Tridiagonal Tuple Type TypeError UInt UInt128 UInt16 UInt32 UInt64 UInt8 UVError Union UnitRange Unsigned VecOrMat Vector VersionNumber Void WeakKeyDict WeakRef Zip</Keywords>
2929
<Keywords name="Keywords3">abstract begin baremodule primitive break catch ccall const continue do else elseif end export finally for function global if struct import importall let local macro module quote return try mutable typealias using while</Keywords>
3030
<Keywords name="Keywords4">close enumerate error info open print println read write warn</Keywords>
3131
<Keywords name="Keywords5">print println</Keywords>

contrib/julia.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,6 @@
156156
<item> RegexMatch </item>
157157
<item> RegexMatchIterator </item>
158158
<item> RepString </item>
159-
<item> RevString </item>
160159
<item> Reverse </item>
161160
<item> Schur </item>
162161
<item> Set </item>

doc/src/manual/interacting-with-julia.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ When the cursor is at the beginning of the line, the prompt can be changed to a
6767
julia> ? # upon typing ?, the prompt changes (in place) to: help?>
6868
6969
help?> string
70-
search: string String stringmime Cstring Cwstring RevString randstring bytestring SubString
70+
search: string String stringmime Cstring Cwstring randstring bytestring SubString
7171
7272
string(xs...)
7373

test/strings/types.jl

Lines changed: 14 additions & 26 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, RevString and Cstring tests ##
3+
## SubString and Cstring tests ##
44

55
## SubString tests ##
66
u8str = "∀ ε > 0, ∃ δ > 0: |x-y| < δ ⇒ |f(x)-f(y)| < ε"
@@ -163,36 +163,24 @@ end
163163

164164
## Reverse strings ##
165165

166-
let rs = RevString("foobar")
167-
@test length(rs) == 6
168-
@test sizeof(rs) == 6
169-
@test isascii(rs)
170-
end
171-
172-
# issue #4586
173-
@test rsplit(RevString("ailuj"),'l') == ["ju","ia"]
174-
@test parse(Float64,RevString("64")) === 46.0
175-
176166
# reverseind
177167
for T in (String, GenericString)
178168
for prefix in ("", "abcd", "\U0001d6a4\U0001d4c1", "\U0001d6a4\U0001d4c1c", " \U0001d6a4\U0001d4c1")
179169
for suffix in ("", "abcde", "\U0001d4c1β\U0001d6a4", "\U0001d4c1β\U0001d6a4c", " \U0001d4c1β\U0001d6a4")
180170
for c in ('X', 'δ', '\U0001d6a5')
181-
s = convert(T, string(prefix, c, suffix))
182-
r = reverse(s)
183-
ri = search(r, c)
184-
@test r == RevString(s)
185-
@test c == s[reverseind(s, ri)] == r[ri]
186-
s = RevString(s)
187-
r = reverse(s)
188-
ri = search(r, c)
189-
@test c == s[reverseind(s, ri)] == r[ri]
190-
s = convert(T, string(prefix, prefix, c, suffix, suffix))
191-
pre = convert(T, prefix)
192-
sb = SubString(s, nextind(pre, endof(pre)), endof(convert(T, string(prefix, prefix, c, suffix))))
193-
r = reverse(sb)
194-
ri = search(r, c)
195-
@test c == sb[reverseind(sb, ri)] == r[ri]
171+
let s = convert(T, string(prefix, c, suffix))
172+
r = reverse(String(s))
173+
ri = search(r, c)
174+
@test c == s[reverseind(s, ri)] == r[ri]
175+
end
176+
let s = convert(T, string(prefix, prefix, c, suffix, suffix))
177+
pre = convert(T, prefix)
178+
sb = SubString(s, nextind(pre, endof(pre)), endof(convert(T, string(prefix, prefix, c, suffix))))
179+
r = reverse(String(sb))
180+
ri = search(r, c)
181+
sbs = String(sb)
182+
@test c == sbs[reverseind(sbs, ri)] == r[ri]
183+
end
196184
end
197185
end
198186
end

0 commit comments

Comments
 (0)