mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2025-12-06 11:15:31 -05:00
fix the LRU algorithm to really be "least recently used"
This commit is contained in:
parent
fbc278907a
commit
62135fc9b7
1 changed files with 40 additions and 29 deletions
|
|
@ -152,13 +152,13 @@ module LRU(X:HASH) = struct
|
||||||
type 'a t = {
|
type 'a t = {
|
||||||
table : 'a node H.t; (* hashtable key -> node *)
|
table : 'a node H.t; (* hashtable key -> node *)
|
||||||
mutable first : 'a node option;
|
mutable first : 'a node option;
|
||||||
mutable last : 'a node option;
|
|
||||||
size : int; (* max size *)
|
size : int; (* max size *)
|
||||||
}
|
}
|
||||||
and 'a node = {
|
and 'a node = {
|
||||||
mutable key : key;
|
mutable key : key;
|
||||||
mutable value : 'a;
|
mutable value : 'a;
|
||||||
mutable next : 'a node option;
|
mutable next : 'a node;
|
||||||
|
mutable prev : 'a node;
|
||||||
} (** Meta data for the value, making a chained list *)
|
} (** Meta data for the value, making a chained list *)
|
||||||
|
|
||||||
let make size =
|
let make size =
|
||||||
|
|
@ -166,71 +166,82 @@ module LRU(X:HASH) = struct
|
||||||
{ table = H.create size;
|
{ table = H.create size;
|
||||||
size;
|
size;
|
||||||
first=None;
|
first=None;
|
||||||
last=None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let clear c =
|
let clear c =
|
||||||
H.clear c.table;
|
H.clear c.table;
|
||||||
c.first <- None;
|
c.first <- None;
|
||||||
c.last <- None;
|
|
||||||
()
|
()
|
||||||
|
|
||||||
let get c x = (H.find c.table x).value
|
|
||||||
|
|
||||||
let get_opt = function
|
let get_opt = function
|
||||||
| None -> assert false
|
| None -> assert false
|
||||||
| Some x -> x
|
| Some x -> x
|
||||||
|
|
||||||
(* reverse the list *)
|
|
||||||
let rec reverse_ prev = function
|
|
||||||
| None -> prev
|
|
||||||
| Some n as node ->
|
|
||||||
let next = n.next in
|
|
||||||
n.next <- prev;
|
|
||||||
reverse_ node next
|
|
||||||
|
|
||||||
(* take first from queue *)
|
(* take first from queue *)
|
||||||
let take_ c =
|
let take_ c =
|
||||||
match c.first with
|
match c.first with
|
||||||
|
| Some n when n.next == n ->
|
||||||
|
(* last element *)
|
||||||
|
c.first <- None;
|
||||||
|
n
|
||||||
| Some n ->
|
| Some n ->
|
||||||
c.first <- n.next;
|
c.first <- Some n.next;
|
||||||
|
n.prev.next <- n.next;
|
||||||
|
n.next.prev <- n.prev;
|
||||||
n
|
n
|
||||||
| None ->
|
| None ->
|
||||||
(* re-fill front list *)
|
failwith "LRU: empty queue"
|
||||||
match reverse_ None c.last with
|
|
||||||
| None -> assert false
|
|
||||||
| Some n ->
|
|
||||||
c.first <- n.next;
|
|
||||||
n
|
|
||||||
|
|
||||||
|
(* push at back of queue *)
|
||||||
let push_ c n =
|
let push_ c n =
|
||||||
n.next <- c.last;
|
match c.first with
|
||||||
c.last <- Some n
|
| None ->
|
||||||
|
n.next <- n;
|
||||||
|
n.prev <- n;
|
||||||
|
c.first <- Some n
|
||||||
|
| Some n1 when n1==n -> ()
|
||||||
|
| Some n1 ->
|
||||||
|
n.prev <- n1.prev;
|
||||||
|
n.next <- n1;
|
||||||
|
n1.prev.next <- n;
|
||||||
|
n1.prev <- n
|
||||||
|
|
||||||
|
(* remove from queue *)
|
||||||
|
let remove_ n =
|
||||||
|
n.prev.next <- n.next;
|
||||||
|
n.next.prev <- n.prev
|
||||||
|
|
||||||
(* Replace least recently used element of [c] by x->y *)
|
(* Replace least recently used element of [c] by x->y *)
|
||||||
let replace_ c x y =
|
let replace_ c x y =
|
||||||
(* remove old *)
|
(* remove old *)
|
||||||
let n = take_ c in
|
let n = take_ c in
|
||||||
H.remove c.table n.key;
|
H.remove c.table n.key;
|
||||||
(* add x->y *)
|
(* add x->y, at the back of the queue *)
|
||||||
H.add c.table x n;
|
|
||||||
n.key <- x;
|
n.key <- x;
|
||||||
n.value <- y;
|
n.value <- y;
|
||||||
(* push at back of queue *)
|
H.add c.table x n;
|
||||||
push_ c n;
|
push_ c n;
|
||||||
()
|
()
|
||||||
|
|
||||||
(* Insert x->y in the cache, increasing its entry count *)
|
(* Insert x->y in the cache, increasing its entry count *)
|
||||||
let insert_ c x y =
|
let insert_ c x y =
|
||||||
let n = {
|
let rec n = {
|
||||||
key = x;
|
key = x;
|
||||||
value = y;
|
value = y;
|
||||||
next = c.last;
|
next = n;
|
||||||
|
prev = n;
|
||||||
} in
|
} in
|
||||||
H.add c.table x n;
|
H.add c.table x n;
|
||||||
c.last <- Some n;
|
push_ c n;
|
||||||
()
|
()
|
||||||
|
|
||||||
|
let get c x =
|
||||||
|
let n = H.find c.table x in
|
||||||
|
(* put n at the back of the queue *)
|
||||||
|
remove_ n;
|
||||||
|
push_ c n;
|
||||||
|
n.value
|
||||||
|
|
||||||
let set c x y =
|
let set c x y =
|
||||||
let len = H.length c.table in
|
let len = H.length c.table in
|
||||||
assert (len <= c.size);
|
assert (len <= c.size);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue