Skip to content

Commit 1c46181

Browse files
committed
Separate low-level and high-level mmap wrappers to separate functions
This cleans up the method list for the intended user-facing `mmap` function just a little bit --- namely, the function signature involving a `RawFD` argument is no longer shown. Simultaneously, we slightly relax the type constraints on all of the high-level `mmap` methods to accept any `<:Array{T}` type so that both specific-shape arrays (i.e. `Vector{T}`, `Matrix{T}`) and the generic `Array{T}` argument can be used in user code to do the same thing. (Only the number of dimensions arguments matters in the end, so the confusing `UnixMmap.mmap(Vector{Float64}, (3, 64))` actually returns a matrix, but I find that less objectionable than not permitting `UnixMmap.mmap(Matrix{Float64}, (3, 64))` to even work.)
1 parent 4cb7be9 commit 1c46181

File tree

4 files changed

+65
-23
lines changed

4 files changed

+65
-23
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@ julia> using UnixMmap
1919
A file can be memory mapped (read-only by default) by giving the filename and the `Array`
2020
type (optionally with dimensions to give a shape):
2121
```julia
22-
julia> UnixMmap.mmap("arbitrary.dat", Array{Float64})
22+
julia> UnixMmap.mmap("arbitrary.dat", Vector{Float64})
2323
192-element Vector{Float64}:
2424
0.0
2525
0.0
2626
2727
0.0
2828
0.0
2929

30-
julia> UnixMmap.mmap("arbitrary.dat", Array{Float64}, (64, 3))
30+
julia> UnixMmap.mmap("arbitrary.dat", Matrix{Float64}, (64, 3))
3131
64×3 Matrix{Float64}:
3232
0.0 0.0 0.0
3333
0.0 0.0 0.0
@@ -38,7 +38,7 @@ julia> UnixMmap.mmap("arbitrary.dat", Array{Float64}, (64, 3))
3838
while an anonymous memory map can be created by instead specifying the `Array` type and
3939
dimensions:
4040
```julia
41-
julia> UnixMmap.mmap(Array{Float64}, (128, 3))
41+
julia> UnixMmap.mmap(Matrix{Float64}, (128, 3))
4242
128×3 Matrix{Float64}:
4343
0.0 0.0 0.0
4444
0.0 0.0 0.0

docs/src/index.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ A file can be memory mapped (read-only by default) by calling [`UnixMmap.mmap`](
1111
with a filename and the `Array` type to be applied (and optionally with dimensions to give a
1212
shape):
1313
```julia-repl
14-
julia> UnixMmap.mmap("arbitrary.dat", Array{Float64})
14+
julia> UnixMmap.mmap("arbitrary.dat", Vector{Float64})
1515
192-element Vector{Float64}:
1616
0.0
1717
0.0
1818
1919
0.0
2020
0.0
2121
22-
julia> UnixMmap.mmap("arbitrary.dat", Array{Float64}, (64, 3))
22+
julia> UnixMmap.mmap("arbitrary.dat", Matrix{Float64}, (64, 3))
2323
64×3 Matrix{Float64}:
2424
0.0 0.0 0.0
2525
0.0 0.0 0.0
@@ -30,7 +30,7 @@ julia> UnixMmap.mmap("arbitrary.dat", Array{Float64}, (64, 3))
3030
while an anonymous memory map can be created by instead specifying the `Array` type and
3131
dimensions:
3232
```julia-repl
33-
julia> UnixMmap.mmap(Array{Float64}, (128, 3))
33+
julia> UnixMmap.mmap(Matrix{Float64}, (128, 3))
3434
128×3 Matrix{Float64}:
3535
0.0 0.0 0.0
3636
0.0 0.0 0.0
@@ -44,7 +44,7 @@ is the ability to set Unix-specific flags during mapping.
4444
For example, on Linux the `MAP_POPULATE` flag can be used to advise the kernel to
4545
prefault all mapped pages into active memory.
4646
```julia-repl
47-
julia> UnixMmap.mmap("arbitrary.dat", Array{Float64}, (64, 3);
47+
julia> UnixMmap.mmap("arbitrary.dat", Matrix{Float64}, (64, 3);
4848
flags = UnixMmap.MAP_SHARED | UnixMmap.MAP_POPULATE)
4949
64×3 Matrix{Float64}:
5050
0.0 0.0 0.0

src/mmap.jl

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ fileflags(::IO) = MAP_SHARED
3939
###
4040

4141
# Raw call to mmap syscall
42-
function _mmap(ptr::Ptr{Cvoid}, len::Int,
42+
function _sys_mmap(ptr::Ptr{Cvoid}, len::Int,
4343
prot::MmapProtection, flags::MmapFlags,
4444
fd::RawFD, offset::Int64)
4545

@@ -53,7 +53,7 @@ function _mmap(ptr::Ptr{Cvoid}, len::Int,
5353
return ret
5454
end
5555

56-
function _unmap!(ptr::Ptr{Cvoid}, len::Int)
56+
function _sys_unmap!(ptr::Ptr{Cvoid}, len::Int)
5757
ret = ccall(:munmap, Cint, (Ptr{Cvoid}, Csize_t), ptr, len)
5858
Base.systemerror("munmap", ret != 0)
5959
return
@@ -62,7 +62,7 @@ end
6262
# Low-level form which mirrors a raw mmap, but constructs a Julia array of given
6363
# dimension(s) at a specific offset within a file (includes accounting for page alignment
6464
# requirement).
65-
function mmap(::Type{Array{T}}, dims::NTuple{N,Integer},
65+
function _mmap(::Type{Array{T}}, dims::NTuple{N,Integer},
6666
prot::MmapProtection, flags::MmapFlags,
6767
fd::RawFD, offset::Integer) where {T, N}
6868
isbitstype(T) || throw(ArgumentError("unable to mmap type $T; must satisfy `isbitstype(T) == true`"))
@@ -75,19 +75,19 @@ function mmap(::Type{Array{T}}, dims::NTuple{N,Integer},
7575
page_pad = rem(Int64(offset), PAGESIZE)
7676
mmaplen::Int = len + page_pad
7777

78-
ptr = _mmap(C_NULL, mmaplen, prot, flags, fd, Int64(offset) - page_pad)
78+
ptr = _sys_mmap(C_NULL, mmaplen, prot, flags, fd, Int64(offset) - page_pad)
7979
aptr = convert(Ptr{T}, ptr + page_pad)
8080
array = unsafe_wrap(Array{T,N}, aptr, dims)
81-
finalizer(_ -> _unmap!(ptr, mmaplen), array)
81+
finalizer(_ -> _sys_unmap!(ptr, mmaplen), array)
8282
return array
8383
end
84-
function mmap(::Type{Array{T}}, len::Int, prot::MmapProtection, flags::MmapFlags,
84+
function _mmap(::Type{Array{T}}, len::Int, prot::MmapProtection, flags::MmapFlags,
8585
fd::RawFD, offset::Int) where {T}
86-
return mmap(Array{T}, (Int(len),), prot, flags, fd, offset)
86+
return _mmap(Array{T}, (Int(len),), prot, flags, fd, offset)
8787
end
8888

8989
# Higher-level interface which takes an IO object and sets default flag values.
90-
function mmap(io::IO, ::Type{Array{T}}, dims::NTuple{N,Integer};
90+
function mmap(io::IO, ::Type{<:Array{T}}, dims::NTuple{N,Integer};
9191
offset::Union{Integer,Nothing} = nothing,
9292
prot::Union{MmapProtection,Nothing} = nothing,
9393
flags::Union{MmapFlags,Nothing} = nothing,
@@ -107,9 +107,9 @@ function mmap(io::IO, ::Type{Array{T}}, dims::NTuple{N,Integer};
107107

108108
grow && iswritable(io) && grow!(io, offset, len)
109109

110-
return mmap(Array{T}, dims, prot, flags, gethandle(io), offset)
110+
return _mmap(Array{T}, dims, prot, flags, gethandle(io), offset)
111111
end
112-
function mmap(io::IO, ::Type{Array{T}}, len::Integer;
112+
function mmap(io::IO, ::Type{<:Array{T}}, len::Integer;
113113
offset::Union{Integer,Nothing} = nothing,
114114
prot::Union{MmapProtection,Nothing} = nothing,
115115
flags::Union{MmapFlags,Nothing} = nothing,
@@ -118,7 +118,7 @@ function mmap(io::IO, ::Type{Array{T}}, len::Integer;
118118
return mmap(io, Array{T}, (len,);
119119
offset = offset, prot = prot, flags = flags, grow = grow)
120120
end
121-
function mmap(io::IO, ::Type{Array{T}} = Array{UInt8};
121+
function mmap(io::IO, ::Type{<:Array{T}} = Array{UInt8};
122122
offset::Union{Integer,Nothing} = nothing,
123123
prot::Union{MmapProtection,Nothing} = nothing,
124124
flags::Union{MmapFlags,Nothing} = nothing,
@@ -129,7 +129,7 @@ function mmap(io::IO, ::Type{Array{T}} = Array{UInt8};
129129
end
130130

131131
# Mapping of files
132-
function mmap(file::AbstractString, ::Type{Array{T}}, dims::NTuple{N,Integer};
132+
function mmap(file::AbstractString, ::Type{<:Array{T}}, dims::NTuple{N,Integer};
133133
offset::Union{Integer,Nothing} = nothing,
134134
prot::Union{MmapProtection,Nothing} = nothing,
135135
flags::Union{MmapFlags,Nothing} = nothing,
@@ -154,7 +154,7 @@ function mmap(file::AbstractString, ::Type{Array{T}}, dims::NTuple{N,Integer};
154154
offset = offset, prot = prot, flags = flags, grow = grow)
155155
end
156156
end
157-
function mmap(file::AbstractString, ::Type{Array{T}}, len::Integer;
157+
function mmap(file::AbstractString, ::Type{<:Array{T}}, len::Integer;
158158
offset::Union{Integer,Nothing} = nothing,
159159
prot::Union{MmapProtection,Nothing} = nothing,
160160
flags::Union{MmapFlags,Nothing} = nothing,
@@ -164,7 +164,7 @@ function mmap(file::AbstractString, ::Type{Array{T}}, len::Integer;
164164
offset = offset, prot = prot, flags = flags, grow = grow)
165165
end
166166
# Default mapping of the [rest of] given file
167-
function mmap(file::AbstractString, ::Type{Array{T}} = Array{UInt8};
167+
function mmap(file::AbstractString, ::Type{<:Array{T}} = Array{UInt8};
168168
offset::Union{Integer,Nothing} = nothing,
169169
prot::Union{MmapProtection,Nothing} = nothing,
170170
flags::Union{MmapFlags,Nothing} = nothing,
@@ -175,7 +175,7 @@ function mmap(file::AbstractString, ::Type{Array{T}} = Array{UInt8};
175175
end
176176

177177
# form to construct anonymous memory maps
178-
function mmap(::Type{Array{T}}, dims::NTuple{N,Integer};
178+
function mmap(::Type{<:Array{T}}, dims::NTuple{N,Integer};
179179
prot::Union{MmapProtection,Nothing} = nothing,
180180
flags::Union{MmapFlags,Nothing} = nothing
181181
) where {T, N}
@@ -184,7 +184,7 @@ function mmap(::Type{Array{T}}, dims::NTuple{N,Integer};
184184
return mmap(Anonymous(), Array{T}, dims;
185185
offset = Int64(0), prot = prot, flags = flags, grow = false)
186186
end
187-
function mmap(::Type{Array{T}}, len::Integer;
187+
function mmap(::Type{<:Array{T}}, len::Integer;
188188
prot::Union{MmapProtection,Nothing} = nothing,
189189
flags::Union{MmapFlags,Nothing} = nothing
190190
) where {T}

test/runtests.jl

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,48 @@ end
169169
end
170170
end
171171

172+
@testset "Inferring return types" begin
173+
# N.B. also tests that any <:Array{T} works as the array type argument
174+
data = repeat(1.0:16.0, 1, 3)
175+
mktemp() do path, io
176+
write(io, data)
177+
flush(io)
178+
seek(io, 0)
179+
@testset "IO handle - $AT" for AT in (Array, Vector, Matrix)
180+
# dims isa Tuple{Int}, so V isa Vector no matter AT
181+
V = @inferred mmap(io, AT{Float64}, (16*3,))
182+
@test V isa Vector
183+
@test V == vec(data)
184+
# dims isa Tuple{Int,Int}, so M isa Matrix no matter AT
185+
M = @inferred mmap(io, AT{Float64}, (16, 3))
186+
@test M isa Matrix
187+
@test M == data
188+
end
189+
close(io)
190+
@testset "File name - $AT" for AT in (Array, Vector, Matrix)
191+
# dims isa Tuple{Int}, so V isa Vector no matter AT
192+
V = @inferred mmap(path, AT{Float64}, (16*3,))
193+
@test V isa Vector
194+
@test V == vec(data)
195+
# dims isa Tuple{Int,Int}, so M isa Matrix no matter AT
196+
M = @inferred mmap(path, AT{Float64}, (16, 3))
197+
@test M isa Matrix
198+
@test M == data
199+
end
200+
@testset "Anonymous - $AT" for AT in (Array, Vector, Matrix)
201+
# dims isa Tuple{Int}, so V isa Vector no matter AT
202+
V = @inferred mmap(AT{Float64}, (16*3,))
203+
@test V isa Vector
204+
@test all(iszero, V)
205+
# dims isa Tuple{Int,Int}, so M isa Matrix no matter AT
206+
M = @inferred mmap(AT{Float64}, (16, 3))
207+
@test M isa Matrix
208+
@test all(iszero, M)
209+
end
210+
GC.gc()
211+
end
212+
end
213+
172214
@testset "Anonymous memory maps" begin
173215
A = mmap(Array{Int16}, 500)
174216
@test size(A) == (500,)

0 commit comments

Comments
 (0)