Skip to content

Commit ff9744e

Browse files
committed
Remove RevString
The `RevString` type for lazily reversed strings has been moved to the LegacyStrings package. Fixes #22611.
1 parent 96f64ce commit ff9744e

13 files changed

+80
-96
lines changed

NEWS.md

+8
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ Language changes
9595
* Prefix `&` for by-reference arguments to `ccall` has been deprecated in favor of
9696
`Ref` argument types ([#6080]).
9797

98+
* The `RevString` type for lazily reversed strings has been moved to the LegacyStrings
99+
package ([#22611]).
100+
98101
Breaking changes
99102
----------------
100103

@@ -202,6 +205,10 @@ This section lists changes that do not have deprecation warnings.
202205
They now return `CartesianIndex`es for all but 1-d arrays, and in general return
203206
the `keys` of indexed collections (e.g. dictionaries) ([#22907]).
204207

208+
* `reverse(s::AbstractString)` now returns a `String` regardless of the input string type.
209+
Previously `reverse` returned a `RevString` for string types other than `String`
210+
([#23612]).
211+
205212
Library improvements
206213
--------------------
207214

@@ -1277,6 +1284,7 @@ Command-line option changes
12771284
[#22532]: https://github.com/JuliaLang/julia/issues/22532
12781285
[#22588]: https://github.com/JuliaLang/julia/issues/22588
12791286
[#22605]: https://github.com/JuliaLang/julia/issues/22605
1287+
[#22611]: https://github.com/JuliaLang/julia/issues/22611
12801288
[#22666]: https://github.com/JuliaLang/julia/issues/22666
12811289
[#22696]: https://github.com/JuliaLang/julia/issues/22696
12821290
[#22703]: https://github.com/JuliaLang/julia/issues/22703

base/deprecated.jl

+3
Original file line numberDiff line numberDiff line change
@@ -1766,6 +1766,9 @@ import .Iterators.enumerate
17661766
# issue #5794
17671767
@deprecate map(f, d::T) where {T<:Associative} T( f(p) for p in pairs(d) )
17681768

1769+
# Issue #22611
1770+
@deprecate_moved RevString "LegacyStrings"
1771+
17691772
# END 0.7 deprecations
17701773

17711774
# BEGIN 1.0 deprecations

base/exports.jl

-1
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

-3
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

+9-8
Original file line numberDiff line numberDiff line change
@@ -219,13 +219,13 @@ end
219219
# closed start brace from the end of the string.
220220
function find_start_brace(s::AbstractString; c_start='(', c_end=')')
221221
braces = 0
222-
r = RevString(s)
223-
i = start(r)
222+
i = endof(s)
224223
in_single_quotes = false
225224
in_double_quotes = false
226225
in_back_ticks = false
227-
while !done(r, i)
228-
c, i = next(r, i)
226+
while i > 0
227+
c = s[i]
228+
nexti = prevind(s, i)
229229
if !in_single_quotes && !in_double_quotes && !in_back_ticks
230230
if c == c_start
231231
braces += 1
@@ -239,18 +239,19 @@ function find_start_brace(s::AbstractString; c_start='(', c_end=')')
239239
in_back_ticks = true
240240
end
241241
else
242-
if !in_back_ticks && !in_double_quotes && c == '\'' && !done(r, i) && next(r, i)[1]!='\\'
242+
if !in_back_ticks && !in_double_quotes && c == '\'' && i > 0 && s[nexti] != '\\'
243243
in_single_quotes = !in_single_quotes
244-
elseif !in_back_ticks && !in_single_quotes && c == '"' && !done(r, i) && next(r, i)[1]!='\\'
244+
elseif !in_back_ticks && !in_single_quotes && c == '"' && i > 0 && s[nexti] != '\\'
245245
in_double_quotes = !in_double_quotes
246-
elseif !in_single_quotes && !in_double_quotes && c == '`' && !done(r, i) && next(r, i)[1]!='\\'
246+
elseif !in_single_quotes && !in_double_quotes && c == '`' && i > 0 && s[nexti] != '\\'
247247
in_back_ticks = !in_back_ticks
248248
end
249249
end
250250
braces == 1 && break
251+
i = nexti
251252
end
252253
braces != 1 && return 0:-1, -1
253-
method_name_end = reverseind(r, i)
254+
method_name_end = i - 1
254255
startind = nextind(s, rsearch(s, non_identifier_chars, method_name_end))
255256
return (startind:endof(s), method_name_end)
256257
end

base/shell.jl

+8-9
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
23-
elseif !(c in _default_delims)
22+
elseif !in(c, _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

+28-28
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,50 @@ 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 = i
213+
while j > 0
214+
d = s[j]
215+
d in c && return j
216+
j = prevind(s, j)
217+
end
218+
return 0
220219
end
221220

222221
function _rsearchindex(s, t, i)
223222
if isempty(t)
224-
return 1 <= i <= nextind(s,endof(s)) ? i :
225-
throw(BoundsError(s, i))
223+
@boundscheck checkbounds(s, i)
224+
return i
226225
end
227-
t = RevString(t)
228-
rs = RevString(s)
229226
l = endof(s)
230-
t1, j2 = next(t,start(t))
227+
t1, j2 = last(t), endof(t)
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+
c, k = let rs_k = reverseind(s, k)
241+
s[rs_k], prevind(s, rs_k)
242+
end
243+
d, j = let rt_j = reverseind(t, j)
244+
t[rt_j], prevind(t, rt_j)
245+
end
244246
if c != d
245247
matched = false
246248
break
247249
end
248250
end
249-
if matched
250-
return nextind(s,l-k+1)
251-
end
252-
i = l-ii+1
251+
matched && return nextind(s, k)
252+
i = ii
253253
end
254254
end
255255

base/strings/types.jl

+4-19
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,34 +97,20 @@ 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
100+
## reversed strings ##
114101

115102
"""
116103
reverse(s::AbstractString) -> AbstractString
117104
118-
Reverses a string.
105+
Reverse a string.
119106
120107
# Examples
121108
```jldoctest
122109
julia> reverse("JuliaLang")
123110
"gnaLailuJ"
124111
```
125112
"""
126-
reverse(s::AbstractString) = RevString(s)
127-
reverse(s::RevString) = s.string
113+
reverse(s::AbstractString) = reverse(convert(String, s))
128114

129115
## reverse an index i so that reverse(s)[i] == s[reverseind(s,i)]
130116

@@ -148,7 +134,6 @@ Julia
148134
"""
149135
reverseind(s::AbstractString, i) = chr2ind(s, length(s) + 1 - ind2chr(reverse(s), i))
150136
reverseind(s::Union{DirectIndexString,SubString{DirectIndexString}}, i::Integer) = length(s) + 1 - i
151-
reverseind(s::RevString, i::Integer) = endof(s) - i + 1
152137
reverseind(s::SubString{String}, i::Integer) =
153138
reverseind(s.string, nextind(s.string, endof(s.string))-s.offset-s.endof+i-1) - s.offset
154139

base/strings/util.jl

+5-8
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

+1-1
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

-1
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

+1-1
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

+13-17
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)| < ε"
@@ -157,15 +157,6 @@ end
157157

158158
## Reverse strings ##
159159

160-
rs = RevString("foobar")
161-
@test length(rs) == 6
162-
@test sizeof(rs) == 6
163-
@test isascii(rs)
164-
165-
# issue #4586
166-
@test rsplit(RevString("ailuj"),'l') == ["ju","ia"]
167-
@test parse(Float64,RevString("64")) === 46.0
168-
169160
# reverseind
170161
for T in (String, GenericString)
171162
for prefix in ("", "abcd", "\U0001d6a4\U0001d4c1", "\U0001d6a4\U0001d4c1c", " \U0001d6a4\U0001d4c1")
@@ -174,18 +165,23 @@ for T in (String, GenericString)
174165
s = convert(T, string(prefix, c, suffix))
175166
r = reverse(s)
176167
ri = search(r, c)
177-
@test r == RevString(s)
178-
@test c == s[reverseind(s, ri)] == r[ri]
179-
s = RevString(s)
180-
r = reverse(s)
181-
ri = search(r, c)
182-
@test c == s[reverseind(s, ri)] == r[ri]
168+
if T === String
169+
@test c == s[reverseind(s, ri)] == r[ri]
170+
else
171+
# reverseind(s, ri) may not be the correct (or even a valid) index in s
172+
@test c == r[i]
173+
end
183174
s = convert(T, string(prefix, prefix, c, suffix, suffix))
184175
pre = convert(T, prefix)
185176
sb = SubString(s, nextind(pre, endof(pre)), endof(convert(T, string(prefix, prefix, c, suffix))))
186177
r = reverse(sb)
178+
@test r isa String
187179
ri = search(r, c)
188-
@test c == sb[reverseind(sb, ri)] == r[ri]
180+
if T === String
181+
@test c == sb[reverseind(sb, ri)] == r[ri]
182+
else
183+
@test c == r[ri]
184+
end
189185
end
190186
end
191187
end

0 commit comments

Comments
 (0)