@@ -36,18 +36,67 @@ struct SubString{T<:AbstractString} <: AbstractString
36
36
end
37
37
return new (s, i- 1 , nextind (s,j)- i)
38
38
end
39
- function SubString {T} (s:: T , i:: Int , j:: Int , :: Val{:noshift} ) where T<: AbstractString
40
- @boundscheck if ! (i == j == 0 )
41
- si, sj = i + 1 , prevind (s, j + i + 1 )
42
- @inbounds isvalid (s, si) || string_index_err (s, si)
43
- @inbounds isvalid (s, sj) || string_index_err (s, sj)
44
- end
45
- new (s, i, j)
39
+ # We don't expose this, because the exposed constructor needs to avoid constructing
40
+ # a SubString{SubString{T}} when passed a substring.
41
+ global function _unsafe_substring (s:: T , offset:: Int , ncodeunits:: Int ) where {T <: AbstractString }
42
+ new {T} (s, offset, ncodeunits)
43
+ end
44
+ end
45
+
46
+ function check_codeunit_bounds (s:: AbstractString , first_index:: Int , n_codeunits:: Int )
47
+ last_index = first_index + n_codeunits - 1
48
+ bad_index = if first_index < 1
49
+ first_index
50
+ elseif last_index > ncodeunits (s)
51
+ last_index
52
+ else
53
+ return nothing
46
54
end
55
+ throw (BoundsError (s, bad_index))
56
+ end
57
+
58
+ """
59
+ unsafe_substring(s::AbstractString, first_index::Int, n_codeunits::Int)::SubString{typeof(s)}
60
+ unsafe_substring(s::SubString{S}, first_index::Int, n_codeunits::Int)::SubString{S}
61
+
62
+ Create a substring of `s` spanning the codeunits `first_index:(first_index + n_codeunits - 1)`.
63
+
64
+ If `first_index` < 1, or `first_index + n_codeunits - 1 > ncodeunits(s)`, throw a `BoundsError`.
65
+
66
+ This function does check bounds, but does not validate that the arguments corresponds to valid
67
+ start and end indices in `s`, and so the resulting substring may contain truncated characters.
68
+ The presence of truncated characters is safe and well-defined for `String` and `SubString{String}`,
69
+ but may not be permitted for custom subtypes of `AbstractString`.
70
+
71
+ # Examples
72
+ ```jldoctest
73
+ julia> s = "Hello, Bjørn!";
74
+
75
+ julia> ss = unsafe_substring(s, 3, 10)
76
+ "lo, Bjørn"
77
+
78
+ julia> typeof(ss)
79
+ SubString{String}
80
+
81
+ julia> ss2 = unsafe_substring(ss, 2, 6)
82
+ "o, Bj\\ xc3"
83
+
84
+ julia> typeof(ss2)
85
+ SubString{String}
86
+ ```
87
+ """
88
+ function unsafe_substring (s:: AbstractString , first_index:: Int , n_codeunits:: Int )
89
+ @boundscheck @inline checkbounds (codeunits (s), first_index: (first_index + n_codeunits - 1 ))
90
+ return _unsafe_substring (s, first_index - 1 , n_codeunits)
91
+ end
92
+
93
+ function unsafe_substring (s:: SubString , first_index:: Int , n_codeunits:: Int )
94
+ @boundscheck @inline check_codeunit_bounds (s, first_index, n_codeunits)
95
+ string = s. string
96
+ return _unsafe_substring (string, first_index + s. offset - 1 , n_codeunits)
47
97
end
48
98
49
99
@propagate_inbounds SubString (s:: T , i:: Int , j:: Int ) where {T<: AbstractString } = SubString {T} (s, i, j)
50
- @propagate_inbounds SubString (s:: T , i:: Int , j:: Int , v:: Val{:noshift} ) where {T<: AbstractString } = SubString {T} (s, i, j, v)
51
100
@propagate_inbounds SubString (s:: AbstractString , i:: Integer , j:: Integer = lastindex (s)) = SubString (s, Int (i):: Int , Int (j):: Int )
52
101
@propagate_inbounds SubString (s:: AbstractString , r:: AbstractUnitRange{<:Integer} ) = SubString (s, first (r), last (r))
53
102
56
105
SubString (s. string, s. offset+ i, s. offset+ j)
57
106
end
58
107
59
- SubString (s:: AbstractString ) = SubString (s, 1 , lastindex (s):: Int )
60
- SubString {T} (s:: T ) where {T<: AbstractString } = SubString {T} (s, 1 , lastindex (s):: Int )
108
+ SubString (s:: AbstractString ) = @inbounds unsafe_substring (s, 1 , Int (ncodeunits (s)):: Int )
109
+ SubString {T} (s:: T ) where {T<: AbstractString } = SubString (s)
110
+ SubString (s:: SubString ) = s
61
111
62
112
@propagate_inbounds view (s:: AbstractString , r:: AbstractUnitRange{<:Integer} ) = SubString (s, r)
63
113
@propagate_inbounds maybeview (s:: AbstractString , r:: AbstractUnitRange{<:Integer} ) = view (s, r)
0 commit comments