package forester
A tool for tending mathematical forests
Install
Dune Dependency
Authors
Maintainers
Sources
5.0.tar.gz
md5=24f4aed96a8b8af33aba13fba66f1b37
sha512=d36b896aca11858bb4a00fc704c16cc27a1f197bdb3e479d6132fd70f70d67d7158096285cb0b6fb00db14417f0f822cc27fe65d82f0971e42378fd8271ce573
doc/src/forester.compiler/Cache.ml.html
Source file Cache.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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
(* * SPDX-FileCopyrightText: 2024 The Forester Project Contributors * * SPDX-License-Identifier: GPL-3.0-or-later *) open Forester_prelude open Forester_core open struct module T = Types end (*Inspired by https://rustc-dev-guide.rust-lang.org/queries/incremental-compilation-in-detail.html *) module Item = struct type color = Red | Green | Unknown type meta = { timestamp: float option; color: color; } type t = (* Key *) | Tree of URI.t | Path of Trie.path | Asset of string (* TODO: Hand-roll these for performance? *) let compare = compare let hash = Hashtbl.hash let equal = (=) let check_timestamp = fun path timestamp -> match timestamp with | Some timestamp -> let last_modified = Eio.Path.(stat ~follow: true @@ path).mtime in if last_modified > timestamp then Red else Green | _ -> Red end (* The core datastructure here is a {graph; hashtbl} We shadow many functions from both datastructures. *) module Dependency_tbl = Hashtbl.Make(Item) module Dependecy_graph : sig type t type vertex = Item.t val add_vertex : t -> vertex -> t val create : ?size: int -> unit -> t val pred : t -> vertex -> vertex list val empty : unit -> t end = struct module G = Graph.Imperative.Digraph.ConcreteBidirectional(Item) type t = G.t type vertex = Item.t let create = G.create let pred = G.pred let add_vertex g v = G.add_vertex g v; g let empty = G.create ?size: None end type t = { tbl: Item.meta Dependency_tbl.t; graph: Dependecy_graph.t; db: Datalog_engine.db; } let empty = { tbl = Dependency_tbl.create 1000; graph = Dependecy_graph.create (); db = Datalog_engine.db_create (); } let find_opt t uri = Dependency_tbl.find_opt t.tbl uri let add_vertex t v color = ignore @@ Dependecy_graph.add_vertex t.graph v; Dependency_tbl.add t.tbl v color let pred t v = Dependecy_graph.pred t.graph v let get_changed_paths ~(config : Config.t) (cache : t) (dirs : Eio.Fs.dir_ty Eio.Path.t List.t) : Eio.Fs.dir_ty Eio.Path.t Seq.t = let@ path = Seq.filter_map @~ Dir_scanner.scan_directories dirs in let path_str = Eio.Path.native_exn path in let uri = URI_scheme.path_to_uri ~base: config.url path_str in let last_modified = Eio.Path.(stat ~follow: true path).mtime in (* "flipped" bind, by default returns the current path. IDK, I am being lazy. *) let (let*) o f = match o with None -> Some path | Some v -> f v in let* {timestamp; _} = Dependency_tbl.find_opt cache.tbl (Tree uri) in let* last_seen = timestamp in if last_modified > last_seen then Some path else None let rec try_mark_green t node = let exception Done of bool in let dependencies = let@ v = List.filter_map @~ pred t node in match Dependency_tbl.find_opt t.tbl v with | None -> None | Some c -> Some (v, c) in let result = try List.fold_right (fun (dep, Item.{color; _}) acc -> match color with | Red -> raise (Done false) | Green -> true && acc | Unknown -> if try_mark_green t dep then true && acc else raise (Done false) ) dependencies true with | Done b -> b in if result then Dependency_tbl.replace t.tbl node { color = Green; timestamp = Some (Unix.time ()) } else assert false; result let marshal filename (v : t) = let oc = open_out_bin filename in Fun.protect ~finally: (fun () -> close_out oc) (fun () -> Marshal.to_channel oc v []) let unmarshal filename : t = let ic = open_in_bin filename in Fun.protect ~finally: (fun () -> close_in ic) (fun () -> Marshal.from_channel ic)
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>