Skip to content

Instantly share code, notes, and snippets.

@dbuenzli
Last active October 21, 2023 01:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dbuenzli/68b92432afb2d167aa48162ff5782bcd to your computer and use it in GitHub Desktop.
Save dbuenzli/68b92432afb2d167aa48162ff5782bcd to your computer and use it in GitHub Desktop.
Bigarray mmap RW
(* SPDX-License-Identifier: CC0-1.0 *)
let bigbytes_of_file ?(trunc = false) ?length access file =
let module Bigarray = Stdlib.Bigarray (* OCaml < 5 install woes *) in
let flags, shared = match access with
| `R -> Unix.[O_RDONLY], false
| `RW -> Unix.(O_CREAT :: O_RDWR :: if trunc then [O_TRUNC] else []), true
in
let fd = Unix.openfile file flags 0o644 in
let finally () = try Unix.close fd with Unix.Unix_error _ -> () in
Fun.protect ~finally @@ fun () ->
(* mmap on macOS returns EINVAL rather ENODEV on dirs so we check before *)
let stat = Unix.fstat fd in
if stat.st_kind <> S_REG
then raise (Unix.Unix_error (ENODEV, "bigbytes_of_file'", file)) else
let length = match length with
| None -> -1
| Some length when access = `RW -> length
| Some length -> Int.min length (Unix.lseek fd 0 Unix.SEEK_END)
in
let typ = Bigarray.int8_unsigned and layout = Bigarray.C_layout in
let map = Unix.map_file fd typ layout shared [|length|] in
Bigarray.array1_of_genarray map
let bigbytes_of_file' ?trunc ?length access file =
try Ok (bigbytes_of_file ?trunc ?length access file) with
| Unix.Unix_error (ENODEV, _, _) -> Error "Not a file"
| Unix.Unix_error (e, _, _) -> Error (Unix.error_message e)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment