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
(** *)
(** {1:tuning Tuning} *)
(**/**)
(** Default for the initial size when creating a cache. *)
let default_cache_size = 512
(** Current value for the initial cache size. *)
let initial_cache_size = ref default_cache_size
(**/**)
(** Get the value used as an initial size when creating a cache. *)
let get_initial_cache_size () = !initial_cache_size
(** Set the value used as an initial size when creating a cache. *)
let set_initial_cache_size size = initial_cache_size := size
(** Reset to default the value used as an initial size when creating a cache. *)
let reset_initial_cache_size () = initial_cache_size := default_cache_size
(**/**)
(** [mk_memo create find add ff] gives a memoïzed version of the functional [ff]
using the functions [create], [find] and [add] for the cache. It's used
internally and you shouldn't have to use it. *)
let mk_memo create find add ff =
let cache = create (get_initial_cache_size ()) in
let rec f k =
try find cache k
with Not_found ->
let v = ff f k in
add cache k v ; v
in
f
(**/**)
(** {1:generic Generic interface} *)
(** [memo ff] gives you a memoïzed version of the [ff] functional. *)
let memo ff =
let open Hashtbl in
mk_memo create find add ff
(** {1:functors Functorial interface } *)
(** The output signature of the functors {!module:Mk}, {!module:Make}, {!module:MakeWeak} and {!module:Fake}.*)
module type S = sig
type t
val memo : ((t -> 'a) -> t -> 'a) -> t -> 'a
end
(** With the {!module:Mk} functor, you can also directly provide a [Cache] module, which
should have the signature [Hashtbl.S]. We will include your cache module and
use it to define a [memo] function. It should be useful only if you want to
use another [Hashtbl] implementation or things like this. *)
module Mk (Cache : Hashtbl.S) = struct
include Cache
let memo ff = mk_memo Cache.create Cache.find Cache.add ff
end
(** Functor that can be useful in case you don't want to use polymorphic
equality or you are doing things like hashconsing and you know how to compare
or hash your type more efficiently. *)
module Make (H : Hashtbl.HashedType) = Mk (Hashtbl.Make (H))
(** Functor that works like the [Make] one, but the bindings in the memoïzation
cache will be weak, allowing the garbage collector to remove them if they are
not used somewhere else. *)
module MakeWeak (H : Hashtbl.HashedType) = Mk (Ephemeron.K1.Make (H))
(** Functor that is useful if you want to quickly test a function you memoïzed
with our {!module:Make} or {!module:MakeWeak} functor, but without memoïzing it. It'll
basically do nothing and should be equivalent to your initial non-memoïzed
function. *)
module Fake (H : Hashtbl.HashedType) = Mk (struct
include Hashtbl.Make (H)
let find _ _ = raise_notrace Not_found
let add _ _ _ = ()
end)