CCache.{size,iter}

This commit is contained in:
Simon Cruanes 2014-11-23 13:49:04 +01:00
parent f010bc6ebc
commit 6e3b0f534a
2 changed files with 56 additions and 45 deletions

View file

@ -23,7 +23,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*) *)
(** {1 Memoization caches} *) (** {1 Caches} *)
type 'a equal = 'a -> 'a -> bool type 'a equal = 'a -> 'a -> bool
type 'a hash = 'a -> int type 'a hash = 'a -> int
@ -36,6 +36,8 @@ let default_hash_ = Hashtbl.hash
type ('a,'b) t = { type ('a,'b) t = {
set : 'a -> 'b -> unit; set : 'a -> 'b -> unit;
get : 'a -> 'b; (* or raise Not_found *) get : 'a -> 'b; (* or raise Not_found *)
size : unit -> int;
iter : ('a -> 'b -> unit) -> unit;
clear : unit -> unit; clear : unit -> unit;
} }
@ -53,10 +55,16 @@ let with_cache_rec c f =
let rec f' x = with_cache c (f f') x in let rec f' x = with_cache c (f f') x in
f' f'
let size c = c.size ()
let iter c f = c.iter f
let dummy = { let dummy = {
set=(fun _ _ -> ()); set=(fun _ _ -> ());
get=(fun _ -> raise Not_found); get=(fun _ -> raise Not_found);
clear=(fun _ -> ()); clear=(fun _ -> ());
size=(fun _ -> 0);
iter=(fun _ -> ());
} }
module Linear = struct module Linear = struct
@ -91,6 +99,14 @@ module Linear = struct
let set c x y = let set c x y =
c.arr.(c.i) <- Pair (x,y); c.arr.(c.i) <- Pair (x,y);
c.i <- (c.i + 1) mod Array.length c.arr c.i <- (c.i + 1) mod Array.length c.arr
let iter c f =
Array.iter (function Pair (x,y) -> f x y | Empty -> ()) c.arr
let size c () =
let r = ref 0 in
iter c (fun _ _ -> incr r);
!r
end end
let linear ?(eq=default_eq_) size = let linear ?(eq=default_eq_) size =
@ -99,6 +115,8 @@ let linear ?(eq=default_eq_) size =
{ get=(fun x -> Linear.get arr x); { get=(fun x -> Linear.get arr x);
set=(fun x y -> Linear.set arr x y); set=(fun x y -> Linear.set arr x y);
clear=(fun () -> Linear.clear arr); clear=(fun () -> Linear.clear arr);
size=Linear.size arr;
iter=Linear.iter arr;
} }
module Replacing = struct module Replacing = struct
@ -110,13 +128,15 @@ module Replacing = struct
eq : 'a equal; eq : 'a equal;
hash : 'a hash; hash : 'a hash;
arr : ('a,'b) bucket array; arr : ('a,'b) bucket array;
mutable c_size : int;
} }
let make eq hash size = let make eq hash size =
assert (size>0); assert (size>0);
{arr=Array.make size Empty; eq; hash } {arr=Array.make size Empty; eq; hash; c_size=0 }
let clear c = let clear c =
c.c_size <- 0;
Array.fill c.arr 0 (Array.length c.arr) Empty Array.fill c.arr 0 (Array.length c.arr) Empty
let get c x = let get c x =
@ -128,7 +148,13 @@ module Replacing = struct
let set c x y = let set c x y =
let i = c.hash x mod Array.length c.arr in let i = c.hash x mod Array.length c.arr in
if c.arr.(i) = Empty then c.c_size <- c.c_size + 1;
c.arr.(i) <- Pair (x,y) c.arr.(i) <- Pair (x,y)
let iter c f =
Array.iter (function Empty -> () | Pair (x,y) -> f x y) c.arr
let size c () = c.c_size
end end
let replacing ?(eq=default_eq_) ?(hash=default_hash_) size = let replacing ?(eq=default_eq_) ?(hash=default_hash_) size =
@ -136,6 +162,8 @@ let replacing ?(eq=default_eq_) ?(hash=default_hash_) size =
{ get=(fun x -> Replacing.get c x); { get=(fun x -> Replacing.get c x);
set=(fun x y -> Replacing.set c x y); set=(fun x y -> Replacing.set c x y);
clear=(fun () -> Replacing.clear c); clear=(fun () -> Replacing.clear c);
size=Replacing.size c;
iter=Replacing.iter c;
} }
module type HASH = sig module type HASH = sig
@ -173,10 +201,6 @@ module LRU(X:HASH) = struct
c.first <- None; c.first <- None;
() ()
let get_opt = function
| None -> assert false
| Some x -> x
(* take first from queue *) (* take first from queue *)
let take_ c = let take_ c =
match c.first with match c.first with
@ -248,6 +272,11 @@ module LRU(X:HASH) = struct
if len = c.size if len = c.size
then replace_ c x y then replace_ c x y
else insert_ c x y else insert_ c x y
let size c () = H.length c.table
let iter c f =
H.iter (fun x node -> f x node.value) c.table
end end
let lru (type a) ?(eq=default_eq_) ?(hash=default_hash_) size = let lru (type a) ?(eq=default_eq_) ?(hash=default_hash_) size =
@ -260,15 +289,13 @@ let lru (type a) ?(eq=default_eq_) ?(hash=default_hash_) size =
{ get=(fun x -> L.get c x); { get=(fun x -> L.get c x);
set=(fun x y -> L.set c x y); set=(fun x y -> L.set c x y);
clear=(fun () -> L.clear c); clear=(fun () -> L.clear c);
size=L.size c;
iter=L.iter c;
} }
module UNBOUNDED(X:HASH) = struct module UNBOUNDED(X:HASH) = struct
type key = X.t
module H = Hashtbl.Make(X) module H = Hashtbl.Make(X)
type 'a t = 'a H.t
let make size = let make size =
assert (size > 0); assert (size > 0);
H.create size H.create size
@ -278,6 +305,10 @@ module UNBOUNDED(X:HASH) = struct
let get c x = H.find c x let get c x = H.find c x
let set c x y = H.replace c x y let set c x y = H.replace c x y
let size c () = H.length c
let iter c f = H.iter f c
end end
let unbounded (type a) ?(eq=default_eq_) ?(hash=default_hash_) size = let unbounded (type a) ?(eq=default_eq_) ?(hash=default_hash_) size =
@ -290,4 +321,6 @@ let unbounded (type a) ?(eq=default_eq_) ?(hash=default_hash_) size =
{ get=(fun x -> C.get c x); { get=(fun x -> C.get c x);
set=(fun x y -> C.set c x y); set=(fun x y -> C.set c x y);
clear=(fun () -> C.clear c); clear=(fun () -> C.clear c);
iter=C.iter c;
size=C.size c;
} }

View file

@ -23,7 +23,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*) *)
(** {1 Memoization caches} *) (** {1 Caches}
Particularly useful for memoization. See {!with_cache} and {!with_cache_rec}
for more details.
@since NEXT_RELEASE *)
type 'a equal = 'a -> 'a -> bool type 'a equal = 'a -> 'a -> bool
type 'a hash = 'a -> int type 'a hash = 'a -> int
@ -72,6 +76,13 @@ fib 70;;
]} ]}
*) *)
val size : (_,_) t -> int
(** Size of the cache (number of entries). At most linear in the number
of entries. *)
val iter : ('a,'b) t -> ('a -> 'b -> unit) -> unit
(** Iterate on cached values. Should yield [size cache] pairs. *)
val dummy : ('a,'b) t val dummy : ('a,'b) t
(** dummy cache, never stores any value *) (** dummy cache, never stores any value *)
@ -92,42 +103,9 @@ val replacing : ?eq:'a equal -> ?hash:'a hash ->
val lru : ?eq:'a equal -> ?hash:'a hash -> val lru : ?eq:'a equal -> ?hash:'a hash ->
int -> ('a,'b) t int -> ('a,'b) t
(** LRU cache of the given size ("Least Recently Used": keys that have not been (** LRU cache of the given size ("Least Recently Used": keys that have not been
used recently are deleted first). Never grows wider. *) used recently are deleted first). Never grows wider than the given size. *)
val unbounded : ?eq:'a equal -> ?hash:'a hash -> val unbounded : ?eq:'a equal -> ?hash:'a hash ->
int -> ('a,'b) t int -> ('a,'b) t
(** Unbounded cache, backed by a Hash table. Will grow forever (** Unbounded cache, backed by a Hash table. Will grow forever
unless {!clear} is called manually. *) unless {!clear} is called manually. *)
(** {2 Binary Caches}
TODO
module C2 : sig
type ('a, 'b, 'c) t
val clear : (_,_,_) t -> unit
val with_cache : ('a, 'b, 'c) t -> ('a -> 'b -> 'c) -> 'a -> 'b -> 'c
val with_cache_rec : ('a,'b,'c) t ->
(('a -> 'b -> 'c) -> 'a -> 'b -> 'c) ->
'a -> 'b -> 'c
val dummy : ('a,'b,'c) t
val linear : ?eq1:('a -> 'a -> bool) -> ?eq2:('b -> 'b -> bool) ->
int -> ('a, 'b, 'c) t
val replacing : ?eq1:('a -> 'a -> bool) -> ?hash1:('a -> int) ->
?eq2:('b -> 'b -> bool) -> ?hash2:('b -> int) ->
int -> ('a,'b,'c) t
val lru : ?eq1:('a -> 'a -> bool) -> ?hash1:('a -> int) ->
?eq2:('b -> 'b -> bool) -> ?hash2:('b -> int) ->
int -> ('a,'b,'c) t
val unbounded : ?eq1:('a -> 'a -> bool) -> ?hash1:('a -> int) ->
?eq2:('b -> 'b -> bool) -> ?hash2:('b -> int) ->
int -> ('a,'b,'c) t
end
*)