Skip to content

Commit b91ed5d

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 896d599 commit b91ed5d

File tree

14 files changed

+152
-128
lines changed

14 files changed

+152
-128
lines changed

NEWS.md

+8
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ 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+
103106
Breaking changes
104107
----------------
105108

@@ -221,6 +224,9 @@ This section lists changes that do not have deprecation warnings.
221224
consistent with its documentation. Previously it would return a `BitArray{0}` for scalar
222225
`x` ([#20233]).
223226

227+
* `reverse(::AbstractString)` now unconditionally returns a `String`. Previously it
228+
returned a `RepString`, which has been removed from Base ([#23612]).
229+
224230
Library improvements
225231
--------------------
226232

@@ -1315,6 +1321,7 @@ Command-line option changes
13151321
[#22532]: https://github.com/JuliaLang/julia/issues/22532
13161322
[#22588]: https://github.com/JuliaLang/julia/issues/22588
13171323
[#22605]: https://github.com/JuliaLang/julia/issues/22605
1324+
[#22611]: https://github.com/JuliaLang/julia/issues/22611
13181325
[#22666]: https://github.com/JuliaLang/julia/issues/22666
13191326
[#22696]: https://github.com/JuliaLang/julia/issues/22696
13201327
[#22703]: https://github.com/JuliaLang/julia/issues/22703
@@ -1344,3 +1351,4 @@ Command-line option changes
13441351
[#23233]: https://github.com/JuliaLang/julia/issues/23233
13451352
[#23342]: https://github.com/JuliaLang/julia/issues/23342
13461353
[#23404]: https://github.com/JuliaLang/julia/issues/23404
1354+
[#23612]: https://github.com/JuliaLang/julia/issues/23612

base/deprecated.jl

+3
Original file line numberDiff line numberDiff line change
@@ -1855,6 +1855,9 @@ end
18551855
nothing
18561856
end
18571857

1858+
# Issue #22611
1859+
@deprecate_moved RevString "LegacyStrings"
1860+
18581861
# END 0.7 deprecations
18591862

18601863
# 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
@@ -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

+7-8
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/basic.jl

+74
Original file line numberDiff line numberDiff line change
@@ -566,3 +566,77 @@ function filter(f, s::AbstractString)
566566
end
567567
String(take!(out))
568568
end
569+
570+
"""
571+
reverse(s::AbstractString) -> String
572+
573+
Reverse a string. The result is always a `String`, regardless of the input type.
574+
575+
Technically, this function reverses the codepoints in a string, and its
576+
main utility is for reversed-order string processing, especially for reversed
577+
regular-expression searches. See also [`reverseind`](@ref) to convert indices
578+
in `s` to indices in `reverse(s)` and vice-versa, and [`graphemes`](@ref)
579+
to operate on user-visible "characters" (graphemes) rather than codepoints.
580+
581+
# Examples
582+
```jldoctest
583+
julia> reverse("JuliaLang")
584+
"gnaLailuJ"
585+
586+
julia> reverse("ax̂e") # combining characters can lead to surprising results
587+
"êxa"
588+
589+
julia> join(reverse(collect(graphemes("ax̂e")))) # reverses graphemes
590+
"ex̂a"
591+
```
592+
"""
593+
reverse(s::AbstractString) = reverse(convert(String, s))
594+
595+
## reverse an index i so that reverse(s)[i] == s[reverseind(s,i)]
596+
597+
"""
598+
reverseind(v, i)
599+
600+
Given an index `i` in [`reverse(v)`](@ref), return the corresponding index in `v` so that
601+
`v[reverseind(v,i)] == reverse(v)[i]`. (This can be nontrivial in cases where `v` contains
602+
non-ASCII characters.)
603+
604+
# Examples
605+
```jldoctest
606+
julia> r = reverse("Julia")
607+
"ailuJ"
608+
609+
julia> for i in 1:length(r)
610+
print(r[reverseind("Julia", i)])
611+
end
612+
Julia
613+
```
614+
"""
615+
reverseind(s::AbstractString, i) = chr2ind(s, length(s) + 1 - ind2chr(reverse(s), i))
616+
617+
"""
618+
repeat(s::AbstractString, r::Integer)
619+
620+
Repeat a string `r` times. This can equivalently be accomplished by calling [`s^r`](@ref ^).
621+
622+
# Examples
623+
```jldoctest
624+
julia> repeat("ha", 3)
625+
"hahaha"
626+
```
627+
"""
628+
repeat(s::AbstractString, r::Integer) = repeat(convert(String, s), r)
629+
630+
"""
631+
^(s::Union{AbstractString,Char}, n::Integer)
632+
633+
Repeat a string or character `n` times.
634+
The [`repeat`](@ref) function is an alias to this operator.
635+
636+
# Examples
637+
```jldoctest
638+
julia> "Test "^3
639+
"Test Test Test "
640+
```
641+
"""
642+
(^)(s::Union{AbstractString,Char}, r::Integer) = repeat(s, r)

base/strings/search.jl

+30-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,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

+1-43
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,47 +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-
Technically, this function reverses the codepoints in a string, and its
121-
main utility is for reversed-order string processing, especially for reversed
122-
regular-expression searches. See also [`reverseind`](@ref) to convert indices
123-
in `s` to indices in `reverse(s)` and vice-versa, and [`graphemes`](@ref)
124-
to operate on user-visible "characters" (graphemes) rather than codepoints.
125-
126-
# Examples
127-
```jldoctest
128-
julia> reverse("JuliaLang")
129-
"gnaLailuJ"
130-
131-
julia> reverse("ax̂e") # combining characters can lead to surprising results
132-
"êxa"
133-
134-
julia> join(reverse(collect(graphemes("ax̂e")))) # reverses graphemes
135-
"ex̂a"
136-
```
137-
"""
138-
reverse(s::AbstractString) = RevString(s)
139-
reverse(s::RevString) = s.string
140-
141100
## reverse an index i so that reverse(s)[i] == s[reverseind(s,i)]
142101

143102
"""
@@ -160,7 +119,6 @@ Julia
160119
"""
161120
reverseind(s::AbstractString, i) = chr2ind(s, length(s) + 1 - ind2chr(reverse(s), i))
162121
reverseind(s::Union{DirectIndexString,SubString{DirectIndexString}}, i::Integer) = length(s) + 1 - i
163-
reverseind(s::RevString, i::Integer) = endof(s) - i + 1
164122
reverseind(s::SubString{String}, i::Integer) =
165123
reverseind(s.string, nextind(s.string, endof(s.string))-s.offset-s.endof+i-1) - s.offset
166124

base/strings/util.jl

+4-8
Original file line numberDiff line numberDiff line change
@@ -173,14 +173,10 @@ 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+
s[i] in chars || return SubString(s, 1, i)
179+
i = prevind(s, i)
184180
end
185181
SubString(s, 1, 0)
186182
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>

0 commit comments

Comments
 (0)