mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2025-12-07 03:35:30 -05:00
wip: compact hashtrie on removal
This commit is contained in:
parent
394656660c
commit
1a68ab4024
2 changed files with 74 additions and 95 deletions
|
|
@ -11,12 +11,13 @@ type 'a ktree = unit -> [`Nil | `Node of 'a * 'a ktree list]
|
||||||
module type FIXED_ARRAY = sig
|
module type FIXED_ARRAY = sig
|
||||||
type 'a t
|
type 'a t
|
||||||
val create : 'a -> 'a t
|
val create : 'a -> 'a t
|
||||||
val length : int
|
val length_log : int
|
||||||
|
val length : int (* 2 power length_log *)
|
||||||
val get : 'a t -> int -> 'a
|
val get : 'a t -> int -> 'a
|
||||||
val set : 'a t -> int -> 'a -> 'a t
|
val set : 'a t -> int -> 'a -> 'a t
|
||||||
|
val update : 'a t -> int -> ('a -> 'a) -> 'a t
|
||||||
val iter : ('a -> unit) -> 'a t -> unit
|
val iter : ('a -> unit) -> 'a t -> unit
|
||||||
val fold : ('b -> 'a -> 'b) -> 'b -> 'a t -> 'b
|
val foldi : (int -> 'b -> 'a -> 'b) -> 'b -> 'a t -> 'b
|
||||||
val for_all : ('a -> bool) -> 'a t -> bool
|
|
||||||
end
|
end
|
||||||
|
|
||||||
(* TODO: add an "update" function? *)
|
(* TODO: add an "update" function? *)
|
||||||
|
|
@ -67,99 +68,64 @@ module type KEY = sig
|
||||||
end
|
end
|
||||||
|
|
||||||
(** {2 Arrays} *)
|
(** {2 Arrays} *)
|
||||||
module A8 : FIXED_ARRAY = struct
|
|
||||||
type 'a t = {
|
|
||||||
a0 : 'a;
|
|
||||||
a1 : 'a;
|
|
||||||
a2 : 'a;
|
|
||||||
a3 : 'a;
|
|
||||||
a4 : 'a;
|
|
||||||
a5 : 'a;
|
|
||||||
a6 : 'a;
|
|
||||||
a7 : 'a;
|
|
||||||
}
|
|
||||||
|
|
||||||
let create x = {a0=x; a1=x; a2=x; a3=x; a4=x; a5=x; a6=x;a7=x}
|
module A32 : FIXED_ARRAY = struct
|
||||||
|
type 'a t = 'a array
|
||||||
|
|
||||||
let length = 8
|
let length_log = 5
|
||||||
|
|
||||||
let get a i = match i with
|
let length = 32
|
||||||
| 0 -> a.a0
|
|
||||||
| 1 -> a.a1
|
|
||||||
| 2 -> a.a2
|
|
||||||
| 3 -> a.a3
|
|
||||||
| 4 -> a.a4
|
|
||||||
| 5 -> a.a5
|
|
||||||
| 6 -> a.a6
|
|
||||||
| 7 -> a.a7
|
|
||||||
| _ -> invalid_arg "A8.get"
|
|
||||||
|
|
||||||
let set a i x = match i with
|
let create x = Array.make length x
|
||||||
| 0 -> {a with a0=x}
|
|
||||||
| 1 -> {a with a1=x}
|
|
||||||
| 2 -> {a with a2=x}
|
|
||||||
| 3 -> {a with a3=x}
|
|
||||||
| 4 -> {a with a4=x}
|
|
||||||
| 5 -> {a with a5=x}
|
|
||||||
| 6 -> {a with a6=x}
|
|
||||||
| 7 -> {a with a7=x}
|
|
||||||
| _ -> invalid_arg "A8.set"
|
|
||||||
|
|
||||||
let iter f a =
|
let get a i = a.(i)
|
||||||
f a.a0;
|
|
||||||
f a.a1;
|
|
||||||
f a.a2;
|
|
||||||
f a.a3;
|
|
||||||
f a.a4;
|
|
||||||
f a.a5;
|
|
||||||
f a.a6;
|
|
||||||
f a.a7;
|
|
||||||
()
|
|
||||||
|
|
||||||
let fold f acc a =
|
let set a i x =
|
||||||
let acc = f acc a.a0 in
|
let a' = Array.copy a in
|
||||||
let acc = f acc a.a1 in
|
a'.(i) <- x;
|
||||||
let acc = f acc a.a2 in
|
a'
|
||||||
let acc = f acc a.a3 in
|
|
||||||
let acc = f acc a.a4 in
|
|
||||||
let acc = f acc a.a5 in
|
|
||||||
let acc = f acc a.a6 in
|
|
||||||
let acc = f acc a.a7 in
|
|
||||||
acc
|
|
||||||
|
|
||||||
let for_all p a =
|
let update a i f =
|
||||||
p a.a0 &&
|
let x = a.(i) in
|
||||||
p a.a1 &&
|
let y = f a.(i) in
|
||||||
p a.a2 &&
|
if x==y then a else set a i x
|
||||||
p a.a3 &&
|
|
||||||
p a.a4 &&
|
let iter = Array.iter
|
||||||
p a.a5 &&
|
|
||||||
p a.a6 &&
|
let foldi f acc a =
|
||||||
p a.a7
|
let rec aux f acc a i =
|
||||||
|
if i = length then acc
|
||||||
|
else
|
||||||
|
let acc = f i acc (Array.unsafe_get a i) in
|
||||||
|
aux f acc a (i+1)
|
||||||
|
in
|
||||||
|
aux f acc a 0
|
||||||
end
|
end
|
||||||
|
|
||||||
(** {2 Functors} *)
|
(** {2 Functors} *)
|
||||||
|
|
||||||
module Hash : sig
|
|
||||||
type t = private int
|
|
||||||
val make_unsafe : int -> t
|
|
||||||
val rem : t -> int (* 3 last bits *)
|
|
||||||
val quotient : t -> t (* remove 3 last bits *)
|
|
||||||
end = struct
|
|
||||||
type t = int
|
|
||||||
let make_unsafe i = i
|
|
||||||
let rem h = h land 7
|
|
||||||
let quotient h = h lsr 3
|
|
||||||
end
|
|
||||||
|
|
||||||
module Make(Key : KEY)
|
module Make(Key : KEY)
|
||||||
: S with module A = A8 and type key = Key.t
|
: S with type key = Key.t
|
||||||
= struct
|
= struct
|
||||||
module A = A8
|
module A = A32
|
||||||
|
|
||||||
let () = assert (A.length = 8)
|
let () = assert (A.length = 1 lsl A.length_log)
|
||||||
|
|
||||||
let hash_ x = Hash.make_unsafe (Key.hash x)
|
module Hash : sig
|
||||||
|
type t = private int
|
||||||
|
val make : Key.t -> t
|
||||||
|
val rem : t -> int (* [A.length_log] last bits *)
|
||||||
|
val quotient : t -> t (* remove [A.length_log] last bits *)
|
||||||
|
val combine : t -> int -> t
|
||||||
|
end = struct
|
||||||
|
type t = int
|
||||||
|
let make = Key.hash
|
||||||
|
let rem h = h land (A.length - 1)
|
||||||
|
let quotient h = h lsr A.length_log
|
||||||
|
let combine q r = (q lsl A.length_log) lor r
|
||||||
|
end
|
||||||
|
|
||||||
|
let hash_ = Hash.make
|
||||||
|
|
||||||
type key = Key.t
|
type key = Key.t
|
||||||
|
|
||||||
|
|
@ -209,8 +175,6 @@ module Make(Key : KEY)
|
||||||
try Some (get_exn_ k ~h:(hash_ k) m)
|
try Some (get_exn_ k ~h:(hash_ k) m)
|
||||||
with Not_found -> None
|
with Not_found -> None
|
||||||
|
|
||||||
(* TODO: use Hash.combine if array only has one non-empty element *)
|
|
||||||
|
|
||||||
(* [h]: hash, with the part required to reach this leaf removed *)
|
(* [h]: hash, with the part required to reach this leaf removed *)
|
||||||
let rec add_ k v ~h m = match m with
|
let rec add_ k v ~h m = match m with
|
||||||
| E -> leaf_ k v ~h
|
| E -> leaf_ k v ~h
|
||||||
|
|
@ -241,11 +205,22 @@ module Make(Key : KEY)
|
||||||
(* insert in a bucket *)
|
(* insert in a bucket *)
|
||||||
let i = Hash.rem h in
|
let i = Hash.rem h in
|
||||||
let h' = Hash.quotient h in
|
let h' = Hash.quotient h in
|
||||||
A.set a i (add_ k v ~h:h' (A.get a i))
|
A.update a i (fun x -> add_ k v ~h:h' x)
|
||||||
|
|
||||||
let add k v m = add_ k v ~h:(hash_ k) m
|
let add k v m = add_ k v ~h:(hash_ k) m
|
||||||
|
|
||||||
let is_empty_arr_ a = A.for_all is_empty a
|
type count_array = {
|
||||||
|
num_non_empty : int; (* number of non empty slots *)
|
||||||
|
idx_non_empty : int; (* the index of a non-empty element, if any *)
|
||||||
|
}
|
||||||
|
|
||||||
|
let count_arr_ a =
|
||||||
|
A.foldi
|
||||||
|
(fun i acc t ->
|
||||||
|
if is_empty t
|
||||||
|
then acc
|
||||||
|
else {num_non_empty=acc.num_non_empty+1; idx_non_empty=i}
|
||||||
|
) {num_non_empty=0; idx_non_empty=0} a
|
||||||
|
|
||||||
let rec remove_list_ k l = match l with
|
let rec remove_list_ k l = match l with
|
||||||
| Nil -> Nil
|
| Nil -> Nil
|
||||||
|
|
@ -265,9 +240,12 @@ module Make(Key : KEY)
|
||||||
let i = Hash.rem h in
|
let i = Hash.rem h in
|
||||||
let h' = Hash.quotient h in
|
let h' = Hash.quotient h in
|
||||||
let a' = A.set a i (remove_rec_ k ~h:h' (A.get a i)) in
|
let a' = A.set a i (remove_rec_ k ~h:h' (A.get a i)) in
|
||||||
if is_empty_arr_ a'
|
match count_arr_ a' with
|
||||||
then E
|
| {num_non_empty=0; _} -> E
|
||||||
else N a'
|
| {num_non_empty=1; idx_non_empty=j} ->
|
||||||
|
(* remove array since it has only one bucket *)
|
||||||
|
A.get a' j
|
||||||
|
| _ -> N a'
|
||||||
|
|
||||||
let remove k m = remove_rec_ k ~h:(hash_ k) m
|
let remove k m = remove_rec_ k ~h:(hash_ k) m
|
||||||
|
|
||||||
|
|
@ -283,15 +261,15 @@ module Make(Key : KEY)
|
||||||
aux t
|
aux t
|
||||||
|
|
||||||
let fold f acc t =
|
let fold f acc t =
|
||||||
let rec aux acc t = match t with
|
let rec aux _ acc t = match t with
|
||||||
| E -> acc
|
| E -> acc
|
||||||
| L (_,l) -> aux_list acc l
|
| L (_,l) -> aux_list acc l
|
||||||
| N a -> A.fold aux acc a
|
| N a -> A.foldi aux acc a
|
||||||
and aux_list acc l = match l with
|
and aux_list acc l = match l with
|
||||||
| Nil -> acc
|
| Nil -> acc
|
||||||
| Cons (k, v, tl) -> let acc = f acc k v in aux_list acc tl
|
| Cons (k, v, tl) -> let acc = f acc k v in aux_list acc tl
|
||||||
in
|
in
|
||||||
aux acc t
|
aux 0 (* any int *) acc t
|
||||||
|
|
||||||
let cardinal m = fold (fun n _ _ -> n+1) 0 m
|
let cardinal m = fold (fun n _ _ -> n+1) 0 m
|
||||||
|
|
||||||
|
|
@ -318,5 +296,5 @@ module Make(Key : KEY)
|
||||||
and list_as_tree_ l = match l with
|
and list_as_tree_ l = match l with
|
||||||
| Nil -> []
|
| Nil -> []
|
||||||
| Cons (k, v, tail) -> (k,v) :: list_as_tree_ tail
|
| Cons (k, v, tail) -> (k,v) :: list_as_tree_ tail
|
||||||
and array_as_tree_ a = A.fold (fun acc t -> as_tree t :: acc) [] a
|
and array_as_tree_ a = A.foldi (fun _ acc t -> as_tree t :: acc) [] a
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -21,12 +21,13 @@ type 'a ktree = unit -> [`Nil | `Node of 'a * 'a ktree list]
|
||||||
module type FIXED_ARRAY = sig
|
module type FIXED_ARRAY = sig
|
||||||
type 'a t
|
type 'a t
|
||||||
val create : 'a -> 'a t
|
val create : 'a -> 'a t
|
||||||
val length : int
|
val length_log : int
|
||||||
|
val length : int (* 2 power length_log *)
|
||||||
val get : 'a t -> int -> 'a
|
val get : 'a t -> int -> 'a
|
||||||
val set : 'a t -> int -> 'a -> 'a t
|
val set : 'a t -> int -> 'a -> 'a t
|
||||||
|
val update : 'a t -> int -> ('a -> 'a) -> 'a t
|
||||||
val iter : ('a -> unit) -> 'a t -> unit
|
val iter : ('a -> unit) -> 'a t -> unit
|
||||||
val fold : ('b -> 'a -> 'b) -> 'b -> 'a t -> 'b
|
val foldi : (int -> 'b -> 'a -> 'b) -> 'b -> 'a t -> 'b
|
||||||
val for_all : ('a -> bool) -> 'a t -> bool
|
|
||||||
end
|
end
|
||||||
|
|
||||||
(** {2 Signature} *)
|
(** {2 Signature} *)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue