Skip to content

Commit

Permalink
Add test for SubString
Browse files Browse the repository at this point in the history
  • Loading branch information
jakobnissen committed Sep 28, 2024
1 parent 0150982 commit 081943f
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 10 deletions.
5 changes: 3 additions & 2 deletions src/basic.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
memory(v::MemoryView) = v.ref.mem

function Base.setindex!(v::MutableMemoryView{T}, x, i::Int) where {T}
@boundscheck checkbounds(v, i)
xT = x isa T ? x : convert(T, x)::T
Expand All @@ -8,6 +6,9 @@ function Base.setindex!(v::MutableMemoryView{T}, x, i::Int) where {T}
return v
end

# TODO: This uses the internal `.mem` field of `MemoryRef`, but AFAIK there is no
# API in Base to get the memory from a `MemoryRef`
Base.parent(v::MemoryView) = v.ref.mem
Base.size(v::MemoryView) = (v.len,)
Base.IndexStyle(::Type{<:MemoryView}) = Base.IndexLinear()

Expand Down
10 changes: 2 additions & 8 deletions src/construction.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,8 @@ MemoryView(A::Array{T}) where {T} = MutableMemoryView{T}(unsafe, A.ref, length(A
# Strings
MemoryView(s::String) = ImmutableMemoryView(unsafe_wrap(Memory{UInt8}, s))
function MemoryView(s::SubString)
memview = MemoryView(parent(s))
codesize = sizeof(codeunit(s))
offset = codesize * s.offset
len = s.ncodeunits * codesize
mem = memview.ref.mem
span = (offset + 1):len
@boundscheck checkbounds(mem, span)
@inbounds typeof(memview)(unsafe, memoryref(mem, offset + 1), s.ncodeunits * codesize)
v = ImmutableMemoryView(parent(s))
@inbounds v[(s.offset + 1):(s.offset + s.ncodeunits)]
end

# Special implementation for SubString{String}, which we can guarantee never
Expand Down
66 changes: 66 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,64 @@ end
@test mem == v
end

struct CharString <: AbstractString
x::Vector{Char}
end
Base.codeunit(s::CharString, i::Int) = reinterpret(UInt32, s.x[i])
Base.codeunit(s::CharString) = UInt32
Base.ncodeunits(s::CharString) = length(s.x)
Base.thisind(s::CharString, i) = i
Base.isvalid(s::CharString, i::Integer) = in(i, 1:ncodeunits(s))
CharString(s::String) = CharString(collect(s))

function Base.nextind(s::CharString, i::Int, n::Int)
if iszero(n)
if !(iszero(i) || in(i, eachindex(s.x)))
throw(BoundsError(s, i))
else
i
end
else
in(i, 0:lastindex(s.x)) ? i + n : throw(BoundsError(s, i))
end
end

function Base.iterate(s::CharString, i::Int=1)
i > ncodeunits(s) ? nothing : (s.x[i], i + 1)
end

MemoryView(s::CharString) = MemoryView(s.x)

@testset "Substrings" begin
for (s, i) in [
("æøåac", 1:5),
("æøåac", 2:4),
("æøåac", 4:3),
("æøåac", 1:1),
("", 1:0),
("儒家孟子", 2:4),
]
ss = SubString(CharString(s), i)
v1 = MemoryView(ss)
@test v1 isa ImmutableMemoryView{Char}
v2 = ImmutableMemoryView(collect(s)[i])
@test v1 == v2
end

for (s, i) in [
("æøåac", 1:8),
("æøåac", 3:7),
("æøåac", 5:4),
("æøåac", 1:1),
("", 1:0),
("儒家孟子", 4:10),
]
ss = SubString(s, i)
@test MemoryView(ss) isa ImmutableMemoryView{UInt8}
@test MemoryView(ss) == MemoryView(String(ss))
end
end

memlen(x) = length(MemoryView(x))
@testset "Zero allocation" begin
for v in MUT_BACKINGS
Expand Down Expand Up @@ -330,6 +388,14 @@ end
@test cmp(MemoryView(a), MemoryView(b)) == y
end
end

@testset "Parent" begin
mem = Memory{UInt16}(undef, 3)
vec = Base.wrap(Array, mem, (3,))
v = MemoryView(vec)
@test parent(v) === mem
@test parent(ImmutableMemoryView(mem)) === mem
end
end

@testset "Equality" begin
Expand Down

0 comments on commit 081943f

Please sign in to comment.