package asai

  1. Overview
  2. Docs

Source file SourceReader.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
type bigstring = (char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t

module M = Map.Make (String)
module E = Algaeff.State.Make (struct type state = (Unix.file_descr * bigstring) M.t end)

module FileInternal =
struct
  let load file_path =
    match M.find_opt file_path (E.get ()) with
    | Some (fd, str) -> fd, str
    | None ->
      let fd =
        try Unix.openfile file_path [Unix.O_RDONLY] 0o777
        with _ -> raise @@ Sys_error ("could not open file " ^ file_path)
      in
      let str =
        try Bigarray.array1_of_genarray @@ Unix.map_file fd Bigarray.char Bigarray.c_layout false [|-1|]
        with _ ->
          (* the fd is already open! *)
          (try Unix.close fd with _ -> ());
          raise @@ Sys_error ("could not read file " ^ file_path)
      in
      E.modify (M.add file_path (fd, str));
      fd, str

  let close_all () =
    M.iter (fun _ (fd, _) -> try Unix.close fd with _ -> ()) (E.get ());
    E.set M.empty
end

type source = File of bigstring | String of string

let load : Range.source -> _ =
  function
  | `File file_path -> File (snd @@ FileInternal.load file_path)
  | `String {content; _} -> String content

let length =
  function
  | File arr -> Bigarray.Array1.size_in_bytes arr
  | String str -> String.length str

let[@inline] unsafe_get res i =
  match res with
  | File arr -> Bigarray.Array1.unsafe_get arr i
  | String str -> String.unsafe_get str i

let run f =
  E.run ~init:M.empty @@ fun () ->
  Fun.protect ~finally:FileInternal.close_all f