Skip to content

Commit 427b123

Browse files
authored
Merge pull request #46410 from dalum/master
Add mutating `stat!` function for non-allocating filesystem `stat`
2 parents 82ab124 + 62e57f7 commit 427b123

File tree

1 file changed

+25
-9
lines changed

1 file changed

+25
-9
lines changed

base/stat.jl

+25-9
Original file line numberDiff line numberDiff line change
@@ -144,28 +144,44 @@ show(io::IO, ::MIME"text/plain", st::StatStruct) = show_statstruct(io, st, false
144144

145145
# stat & lstat functions
146146

147-
macro stat_call(sym, arg1type, arg)
147+
macro stat_call!(stat_buf, sym, arg1type, arg)
148148
return quote
149-
stat_buf = zeros(UInt8, Int(ccall(:jl_sizeof_stat, Int32, ())))
150-
r = ccall($(Expr(:quote, sym)), Int32, ($(esc(arg1type)), Ptr{UInt8}), $(esc(arg)), stat_buf)
149+
r = ccall($(Expr(:quote, sym)), Int32, ($(esc(arg1type)), Ptr{UInt8}), $(esc(arg)), $(esc(stat_buf)))
151150
if !(r in (0, Base.UV_ENOENT, Base.UV_ENOTDIR, Base.UV_EINVAL))
152151
uv_error(string("stat(", repr($(esc(arg))), ")"), r)
153152
end
154-
st = StatStruct($(esc(arg)), stat_buf)
153+
st = StatStruct($(esc(arg)), $(esc(stat_buf)))
155154
if ispath(st) != (r == 0)
156155
error("stat returned zero type for a valid path")
157156
end
158157
return st
159158
end
160159
end
161160

162-
stat(fd::OS_HANDLE) = @stat_call jl_fstat OS_HANDLE fd
163-
stat(path::AbstractString) = @stat_call jl_stat Cstring path
164-
lstat(path::AbstractString) = @stat_call jl_lstat Cstring path
161+
"""
162+
stat!(stat_buf::Vector{UInt8}, file)
163+
164+
Like [`stat`](@ref), but avoids internal allocations by using a pre-allocated buffer,
165+
`stat_buf`. For a small performance gain over `stat`, consecutive calls to `stat!` can use
166+
the same `stat_buf`. See also [`Base.Filesystem.get_stat_buf`](@ref).
167+
"""
168+
stat!(stat_buf::Vector{UInt8}, fd::OS_HANDLE) = @stat_call! stat_buf jl_fstat OS_HANDLE fd
169+
stat!(stat_buf::Vector{UInt8}, path::AbstractString) = @stat_call! stat_buf jl_stat Cstring path
170+
lstat!(stat_buf::Vector{UInt8}, path::AbstractString) = @stat_call! stat_buf jl_lstat Cstring path
165171
if RawFD !== OS_HANDLE
166-
global stat(fd::RawFD) = stat(Libc._get_osfhandle(fd))
172+
global stat!(stat_buf::Vector{UInt8}, fd::RawFD) = stat!(stat_buf, Libc._get_osfhandle(fd))
167173
end
168-
stat(fd::Integer) = stat(RawFD(fd))
174+
stat!(stat_buf::Vector{UInt8}, fd::Integer) = stat!(stat_buf, RawFD(fd))
175+
176+
stat(x) = stat!(get_stat_buf(), x)
177+
lstat(x) = lstat!(get_stat_buf(), x)
178+
179+
"""
180+
get_stat_buf()
181+
182+
Return a buffer of bytes of the right size for [`stat!`](@ref).
183+
"""
184+
get_stat_buf() = zeros(UInt8, Int(ccall(:jl_sizeof_stat, Int32, ())))
169185

170186
"""
171187
stat(file)

0 commit comments

Comments
 (0)