diff --git a/base/strings/basic.jl b/base/strings/basic.jl index 2d5f0cea26e36..6318490a1bcf6 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -790,7 +790,7 @@ iterate(r::Iterators.Reverse{<:EachStringIndex}, i=lastindex(r.itr.s)) = i < fir Wrap a string (without copying) in an immutable vector-like object that accesses the code units of the string's representation. """ -struct CodeUnits{T,S<:AbstractString} <: DenseVector{T} +struct CodeUnits{T,S<:AbstractString} <: AbstractVector{T} s::S CodeUnits(s::S) where {S<:AbstractString} = new{codeunit(s),S}(s) end diff --git a/base/strings/substring.jl b/base/strings/substring.jl index 2a6b4ae7b9a22..297647d91b1aa 100644 --- a/base/strings/substring.jl +++ b/base/strings/substring.jl @@ -72,6 +72,13 @@ convert(::Type{Union{String, SubString{String}}}, s::String) = s convert(::Type{Union{String, SubString{String}}}, s::SubString{String}) = s convert(::Type{Union{String, SubString{String}}}, s::AbstractString) = convert(String, s)::String +# This allows CodeUnits of known, memory-backed String types to act like a dense array +# See issue #53996 +function _memory_offset(x::CodeUnits{<:Any, <:Union{String, SubString{String}}}, I::Vararg{Any,N}) where {N} + (_to_linear_index(x, I...) - first(LinearIndices(x)))*elsize(x) +end +strides(x::CodeUnits{<:Any, <:Union{String, SubString{String}}}) = (1,) + function String(s::SubString{String}) parent = s.string copy = GC.@preserve parent unsafe_string(pointer(parent, s.offset+1), s.ncodeunits)