add rotating cache data structure
This commit is contained in:
parent
5bc37c132b
commit
fde89493b2
|
@ -0,0 +1,54 @@
|
||||||
|
open! Import
|
||||||
|
|
||||||
|
include (val Logging.sublogs logger "Wheel")
|
||||||
|
|
||||||
|
type ('k, 'v) t = {
|
||||||
|
mutable index : int;
|
||||||
|
entries : ('k, 'v) entry array;
|
||||||
|
lookup : ('k, int Dllist.t) Hashtbl.t;
|
||||||
|
}
|
||||||
|
|
||||||
|
and ('k, 'v) entry =
|
||||||
|
| Empty
|
||||||
|
| Entry of 'k * 'v
|
||||||
|
|
||||||
|
let make n = {
|
||||||
|
index = 0;
|
||||||
|
entries = Array.make n Empty;
|
||||||
|
lookup = Hashtbl.create (n * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
let find_all t k =
|
||||||
|
match Hashtbl.find t.lookup k with
|
||||||
|
| hist ->
|
||||||
|
Dllist.fold_r
|
||||||
|
(fun i vs ->
|
||||||
|
match t.entries.(i) with
|
||||||
|
| Empty -> failwith "Cache.find: BUG! empty entry"
|
||||||
|
| Entry (_, v) -> v :: vs)
|
||||||
|
hist []
|
||||||
|
| exception Not_found ->
|
||||||
|
[]
|
||||||
|
|
||||||
|
let evict t =
|
||||||
|
match t.entries.(t.index) with
|
||||||
|
| Empty -> ()
|
||||||
|
| Entry (k, _) ->
|
||||||
|
let hist = Hashtbl.find t.lookup k in
|
||||||
|
let i = Dllist.take_r hist in
|
||||||
|
assert (i = t.index);
|
||||||
|
if Dllist.is_empty hist then Hashtbl.remove t.lookup k;
|
||||||
|
t.entries.(i) <- Empty
|
||||||
|
|
||||||
|
let add t k v =
|
||||||
|
evict t;
|
||||||
|
let i = t.index in
|
||||||
|
let hist = try Hashtbl.find t.lookup k
|
||||||
|
with Not_found ->
|
||||||
|
let l = Dllist.create () in
|
||||||
|
Hashtbl.replace t.lookup k l;
|
||||||
|
l
|
||||||
|
in
|
||||||
|
Dllist.add_l i hist |> ignore;
|
||||||
|
t.entries.(i) <- Entry (k, v);
|
||||||
|
t.index <- succ i mod Array.length t.entries
|
|
@ -0,0 +1,49 @@
|
||||||
|
let%expect_test _ =
|
||||||
|
let print_list print_ele xs =
|
||||||
|
let rec iter pre post = function
|
||||||
|
| [] -> print_string post
|
||||||
|
| x :: xs ->
|
||||||
|
print_string pre;
|
||||||
|
print_ele x;
|
||||||
|
iter ";" "]" xs
|
||||||
|
in
|
||||||
|
iter "[" "[]" xs
|
||||||
|
in
|
||||||
|
|
||||||
|
let print_history_nl ch k =
|
||||||
|
print_list print_int (Cache.find_all ch k);
|
||||||
|
print_newline ()
|
||||||
|
in
|
||||||
|
|
||||||
|
let ch = Cache.make 4 in
|
||||||
|
Cache.add ch "x" 1;
|
||||||
|
Cache.add ch "y" 2;
|
||||||
|
Cache.add ch "y" 3;
|
||||||
|
Cache.add ch "z" 4;
|
||||||
|
|
||||||
|
print_history_nl ch "x"; [%expect {| [1] |}];
|
||||||
|
print_history_nl ch "y"; [%expect {| [3;2] |}];
|
||||||
|
print_history_nl ch "z"; [%expect {| [4] |}];
|
||||||
|
print_history_nl ch "w"; [%expect {| [] |}];
|
||||||
|
|
||||||
|
Cache.add ch "w" 5; (* evict "x:=1" *)
|
||||||
|
|
||||||
|
print_history_nl ch "x"; [%expect {| [] |}];
|
||||||
|
print_history_nl ch "y"; [%expect {| [3;2] |}];
|
||||||
|
print_history_nl ch "z"; [%expect {| [4] |}];
|
||||||
|
print_history_nl ch "w"; [%expect {| [5] |}];
|
||||||
|
|
||||||
|
Cache.add ch "w" 6; (* evict "y:=2" *)
|
||||||
|
|
||||||
|
print_history_nl ch "x"; [%expect {| [] |}];
|
||||||
|
print_history_nl ch "y"; [%expect {| [3] |}];
|
||||||
|
print_history_nl ch "z"; [%expect {| [4] |}];
|
||||||
|
print_history_nl ch "w"; [%expect {| [6;5] |}];
|
||||||
|
|
||||||
|
Cache.add ch "x" 7; (* evict "y:=3" *)
|
||||||
|
Cache.add ch "w" 8; (* evict "z:=4" *)
|
||||||
|
|
||||||
|
print_history_nl ch "x"; [%expect {| [7] |}];
|
||||||
|
print_history_nl ch "y"; [%expect {| [] |}];
|
||||||
|
print_history_nl ch "z"; [%expect {| [] |}];
|
||||||
|
print_history_nl ch "w"; [%expect {| [8;6;5] |}];
|
Loading…
Reference in New Issue