Skip to content

Commit

Permalink
Merge 1a189da into ed5366d
Browse files Browse the repository at this point in the history
  • Loading branch information
jakobnissen authored Jun 22, 2024
2 parents ed5366d + 1a189da commit fa4d5ad
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 27 deletions.
10 changes: 5 additions & 5 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ makedocs(;
remotes=nothing,
)

deploydocs(
repo = "github.com/BioJulia/MemViews.jl.git",
push_preview = true,
deps = nothing,
make = nothing,
deploydocs(;
repo="github.com/BioJulia/MemViews.jl.git",
push_preview=true,
deps=nothing,
make=nothing,
)
31 changes: 19 additions & 12 deletions src/MemViews.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
module MemViews

export MemView,
ImmutableMemView, MutableMemView, MemKind, IsMemory, NotMemory, inner
export MemView, ImmutableMemView, MutableMemView, MemKind, IsMemory, NotMemory, inner

"""
Unsafe
Expand All @@ -14,6 +13,16 @@ struct Unsafe end
"Singleton instance of the trait type `Unsafe`"
const unsafe = Unsafe()

"""
Trait struct, only used in the mutability parameter of `MemView`
"""
struct Mutable end

"""
Trait struct, only used in the mutability parameter of `MemView`
"""
struct Immutable end

"""
MemView{T, M} <: DenseVector{T}
Expand All @@ -24,7 +33,7 @@ Construct from memory-backed values `x` with `MemView(x)`.
except where they have size zero.
The parameter `M` controls the mutability of the memory view,
and may be `:mutable` or `:immutable`, corresponding to the
and may be `Mutable` or `Immutable`, corresponding to the
the aliases `MutableMemView{T}` and `ImmutableMemView{T}`.
See also: `MemKind`
Expand Down Expand Up @@ -63,25 +72,23 @@ may be stored as pointers, and [isbits Union optimisations]
(https://docs.julialang.org/en/v1/devdocs/isbitsunionarrays/).
"""
struct MemView{T, M} <: DenseVector{T}
struct MemView{T, M <: Union{Mutable, Immutable}} <: DenseVector{T}
# If the memview is empty, there is no guarantees where the ref points to
ref::MemoryRef{T}
len::Int

function MemView{T, M}(ref::MemoryRef{T}, len::Int) where {T, M}
if M !== :mutable && M !== :immutable
error("Parameter M must be :mutable or :immutable")
end
function MemView{T, M}(::Unsafe, ref::MemoryRef{T}, len::Int) where {T, M}
M == Union{} && error("Parameter M must be Mutable or Immutable")
new{T, M}(ref, len)
end
end

const MutableMemView{T} = MemView{T, :mutable}
const ImmutableMemView{T} = MemView{T, :immutable}
const MutableMemView{T} = MemView{T, Mutable}
const ImmutableMemView{T} = MemView{T, Immutable}

# Mutable mem views can turn into immutable ones, but not vice versa
ImmutableMemView(x) = ImmutableMemView(MemView(x)::MemView)
ImmutableMemView(x::MutableMemView{T}) where {T} = ImmutableMemView{T}(x.ref, x.len)
ImmutableMemView(x::MutableMemView{T}) where {T} = ImmutableMemView{T}(unsafe, x.ref, x.len)
ImmutableMemView(x::ImmutableMemView) = x

"""
Expand All @@ -91,7 +98,7 @@ Convert a memory view into a mutable memory view.
Note that it may cause undefined behaviour, if supposedly immutable data
is observed to be mutated.
"""
MutableMemView(::Unsafe, x::MemView{T}) where {T} = MemView{T, :mutable}(x.ref, x.len)
MutableMemView(::Unsafe, x::MemView{T}) where {T} = MutableMemView{T}(unsafe, x.ref, x.len)

"""
MemKind
Expand Down
12 changes: 6 additions & 6 deletions src/basic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ end
function Base.copy(x::MemView)
isempty(x) && return x
newmem = @inbounds x.ref.mem[parentindices(x)]
typeof(x)(memoryref(newmem), x.len)
typeof(x)(unsafe, memoryref(newmem), x.len)
end

function Base.getindex(v::MemView, i::Integer)
Expand All @@ -35,14 +35,14 @@ end
function Base.similar(mem::MemView{T1, M}, ::Type{T2}, dims::Tuple{Int}) where {T1, T2, M}
len = Int(only(dims))::Int
memory = Memory{T2}(undef, len)
MemView{T2, M}(memoryref(memory), len)
MemView{T2, M}(unsafe, memoryref(memory), len)
end

function Base.empty(mem::MemView{T1, M}, ::Type{T2}) where {T1, T2, M}
MemView{T2, M}(memoryref(Memory{T2}()), 0)
MemView{T2, M}(unsafe, memoryref(Memory{T2}()), 0)
end

Base.empty(T::Type{<:MemView{E}}) where {E} = T(memoryref(Memory{E}()), 0)
Base.empty(T::Type{<:MemView{E}}) where {E} = T(unsafe, memoryref(Memory{E}()), 0)

Base.pointer(x::MemView{T}) where {T} = Ptr{T}(pointer(x.ref))
Base.unsafe_convert(::Type{Ptr{T}}, v::MemView{T}) where {T} = pointer(v)
Expand All @@ -54,10 +54,10 @@ function Base.getindex(v::MemView, idx::AbstractUnitRange)
# This branch is necessary, because the memoryref can't point out of bounds.
# So if the user gives an empty slice that is out of bounds, the boundscheck
# may pass, but the memoryref construction will be OOB.
isempty(idx) && return typeof(v)(memoryref(v.ref.mem), 0)
isempty(idx) && return typeof(v)(unsafe, memoryref(v.ref.mem), 0)
@boundscheck checkbounds(v, idx)
newref = @inbounds memoryref(v.ref, Int(first(idx))::Int)
typeof(v)(newref, length(idx))
typeof(v)(unsafe, newref, length(idx))
end

Base.getindex(v::MemView, ::Colon) = v
Expand Down
8 changes: 4 additions & 4 deletions src/construction.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ MemView(v::MemView) = v
# Array and Memory
MemKind(::Type{<:Array{T}}) where {T} = IsMemory(MutableMemView{T})
MemKind(::Type{<:Memory{T}}) where {T} = IsMemory(MutableMemView{T})
MemView(A::Memory{T}) where {T} = MutableMemView{T}(memoryref(A), length(A))
MemView(A::Array{T}) where {T} = MutableMemView{T}(A.ref, length(A))
MemView(A::Memory{T}) where {T} = MutableMemView{T}(unsafe, memoryref(A), length(A))
MemView(A::Array{T}) where {T} = MutableMemView{T}(unsafe, A.ref, length(A))

# Strings
MemView(s::String) = ImmutableMemView(unsafe_wrap(Memory{UInt8}, s))
Expand All @@ -16,15 +16,15 @@ function MemView(s::SubString)
mem = memview.ref.mem
span = (offset + 1):len
@boundscheck checkbounds(mem, span)
@inbounds typeof(memview)(memoryref(mem, offset + 1), s.ncodeunits * codesize)
@inbounds typeof(memview)(unsafe, memoryref(mem, offset + 1), s.ncodeunits * codesize)
end

# Special implementation for SubString{String}, which we can guarantee never
# has out of bounds indices, unless the user previously misused @inbounds
function MemView(s::SubString{String})
memview = MemView(parent(s))
newref = @inbounds memoryref(memview.ref, s.offset + 1)
ImmutableMemView{UInt8}(newref, s.ncodeunits)
ImmutableMemView{UInt8}(unsafe, newref, s.ncodeunits)
end

# CodeUnits are semantically IsMemory, but only if the underlying string
Expand Down

0 comments on commit fa4d5ad

Please sign in to comment.