@@ -36,18 +36,67 @@ struct SubString{T<:AbstractString} <: AbstractString
3636        end 
3737        return  new (s, i- 1 , nextind (s,j)- i)
3838    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 
4654    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)
4797end 
4898
4999@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)
51100@propagate_inbounds  SubString (s:: AbstractString , i:: Integer , j:: Integer = lastindex (s)) =  SubString (s, Int (i):: Int , Int (j):: Int )
52101@propagate_inbounds  SubString (s:: AbstractString , r:: AbstractUnitRange{<:Integer} ) =  SubString (s, first (r), last (r))
53102
56105    SubString (s. string, s. offset+ i, s. offset+ j)
57106end 
58107
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
61111
62112@propagate_inbounds  view (s:: AbstractString , r:: AbstractUnitRange{<:Integer} ) =  SubString (s, r)
63113@propagate_inbounds  maybeview (s:: AbstractString , r:: AbstractUnitRange{<:Integer} ) =  view (s, r)
0 commit comments