mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2026-01-28 11:54:51 -05:00
wip: CCIntMap (big-endian patricia trees) in containers.data
This commit is contained in:
parent
4b409ca34f
commit
2a2250faa6
4 changed files with 315 additions and 1 deletions
2
_oasis
2
_oasis
|
|
@ -71,7 +71,7 @@ Library "containers_data"
|
||||||
Path: src/data
|
Path: src/data
|
||||||
Modules: CCMultiMap, CCMultiSet, CCTrie, CCFlatHashtbl, CCCache,
|
Modules: CCMultiMap, CCMultiSet, CCTrie, CCFlatHashtbl, CCCache,
|
||||||
CCPersistentHashtbl, CCDeque, CCFQueue, CCBV, CCMixtbl,
|
CCPersistentHashtbl, CCDeque, CCFQueue, CCBV, CCMixtbl,
|
||||||
CCMixmap, CCRingBuffer
|
CCMixmap, CCRingBuffer, CCIntMap
|
||||||
BuildDepends: bytes
|
BuildDepends: bytes
|
||||||
FindlibParent: containers
|
FindlibParent: containers
|
||||||
FindlibName: data
|
FindlibName: data
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ CCBV
|
||||||
CCCache
|
CCCache
|
||||||
CCFQueue
|
CCFQueue
|
||||||
CCFlatHashtbl
|
CCFlatHashtbl
|
||||||
|
CCIntMap
|
||||||
CCMixmap
|
CCMixmap
|
||||||
CCMixtbl
|
CCMixtbl
|
||||||
CCMultiMap
|
CCMultiMap
|
||||||
|
|
|
||||||
220
src/data/CCIntMap.ml
Normal file
220
src/data/CCIntMap.ml
Normal file
|
|
@ -0,0 +1,220 @@
|
||||||
|
|
||||||
|
(*
|
||||||
|
copyright (c) 2013-2015, simon cruanes
|
||||||
|
all rights reserved.
|
||||||
|
|
||||||
|
redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer. redistributions in binary
|
||||||
|
form must reproduce the above copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other materials provided with
|
||||||
|
the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
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.
|
||||||
|
*)
|
||||||
|
|
||||||
|
(** {1 Map specialized for Int keys} *)
|
||||||
|
|
||||||
|
(* "Fast Mergeable Integer Maps", Okasaki & Gill.
|
||||||
|
We use big-endian trees. *)
|
||||||
|
|
||||||
|
type 'a t =
|
||||||
|
| E (* empty *)
|
||||||
|
| L of int * 'a (* leaf *)
|
||||||
|
| N of int (* common prefix *) * int (* bit switch *) * 'a t * 'a t
|
||||||
|
|
||||||
|
let empty = E
|
||||||
|
|
||||||
|
let bit_is_0_ x ~bit = x land bit = 0
|
||||||
|
|
||||||
|
let mask_ x ~mask = (x lor (mask -1)) land (lnot mask)
|
||||||
|
(* low endian: let mask_ x ~mask = x land (mask - 1) *)
|
||||||
|
|
||||||
|
let is_prefix_ ~prefix y ~bit = prefix = mask_ y ~mask:bit
|
||||||
|
|
||||||
|
let lowest_bit_ a = a land (- a)
|
||||||
|
|
||||||
|
(* loop down until x=lowest_bit_ x *)
|
||||||
|
let rec highest_bit x =
|
||||||
|
let m = lowest_bit_ x in
|
||||||
|
if x = m then m else highest_bit (x-m)
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
Q.int (fun i -> \
|
||||||
|
let b = highest_bit i in \
|
||||||
|
i < 0 || (b <= i && (i-b) < b))
|
||||||
|
*)
|
||||||
|
|
||||||
|
(* helper:
|
||||||
|
|
||||||
|
let b_of_i i =
|
||||||
|
let rec f acc i =
|
||||||
|
if i=0 then acc else let q, r = i/2, i mod 2
|
||||||
|
in
|
||||||
|
f (r::acc) q in f [] i;;
|
||||||
|
*)
|
||||||
|
|
||||||
|
(* low endian: let branching_bit_ a _ b _ = lowest_bit_ (a lxor b) *)
|
||||||
|
let branching_bit_ a b =
|
||||||
|
highest_bit (a lxor b)
|
||||||
|
|
||||||
|
let rec find_exn k t = match t with
|
||||||
|
| E -> raise Not_found
|
||||||
|
| L (k', v) when k = k' -> v
|
||||||
|
| L _ -> raise Not_found
|
||||||
|
| N (prefix, _, l, r) ->
|
||||||
|
if k <= prefix (* search tree *)
|
||||||
|
then find_exn k l
|
||||||
|
else find_exn k r
|
||||||
|
|
||||||
|
let find k t =
|
||||||
|
try Some (find_exn k t)
|
||||||
|
with Not_found -> None
|
||||||
|
|
||||||
|
let mem k t =
|
||||||
|
try ignore (find_exn k t); true
|
||||||
|
with Not_found -> false
|
||||||
|
|
||||||
|
let mk_node_ prefix switch l r = match l, r with
|
||||||
|
| E, o | o, E -> o
|
||||||
|
| _ -> N (prefix, switch, l, r)
|
||||||
|
|
||||||
|
(* join trees t1 and t2 with prefix p1 and p2 respectively
|
||||||
|
(p1 and p2 do not overlap) *)
|
||||||
|
let join_ t1 p1 t2 p2 =
|
||||||
|
let switch = branching_bit_ p1 p2 in
|
||||||
|
let prefix = mask_ p1 ~mask:switch in
|
||||||
|
if bit_is_0_ p1 ~bit:switch
|
||||||
|
then mk_node_ prefix switch t1 t2
|
||||||
|
else (assert (bit_is_0_ p2 ~bit:switch); mk_node_ prefix switch t2 t1)
|
||||||
|
|
||||||
|
let singleton k v = L (k, v)
|
||||||
|
|
||||||
|
(* c: conflict function *)
|
||||||
|
let rec insert_ c k v t = match t with
|
||||||
|
| E -> L (k, v)
|
||||||
|
| L (k', v') ->
|
||||||
|
if k=k'
|
||||||
|
then L (k, c ~old:v' v)
|
||||||
|
else join_ t k' (L (k, v)) k
|
||||||
|
| N (prefix, switch, l, r) ->
|
||||||
|
if is_prefix_ ~prefix k ~bit:switch
|
||||||
|
then if bit_is_0_ k ~bit:switch
|
||||||
|
then N(prefix, switch, insert_ c k v l, r)
|
||||||
|
else N(prefix, switch, l, insert_ c k v r)
|
||||||
|
else join_ (L(k,v)) k t prefix
|
||||||
|
|
||||||
|
let add k v t = insert_ (fun ~old:_ v -> v) k v t
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
Q.(list (pair int int)) (fun l -> \
|
||||||
|
let l = CCList.Set.uniq l in let m = of_list l in \
|
||||||
|
List.for_all (fun (k,v) -> find_exn k m = v) l)
|
||||||
|
*)
|
||||||
|
|
||||||
|
let rec remove k t = match t with
|
||||||
|
| E -> E
|
||||||
|
| L (k', _) -> if k=k' then E else t
|
||||||
|
| N (prefix, switch, l, r) ->
|
||||||
|
if is_prefix_ ~prefix k ~bit:switch
|
||||||
|
then if bit_is_0_ k ~bit:switch
|
||||||
|
then mk_node_ prefix switch (remove k l) r
|
||||||
|
else mk_node_ prefix switch l (remove k r)
|
||||||
|
else t (* not present *)
|
||||||
|
|
||||||
|
let update k f t =
|
||||||
|
try
|
||||||
|
let v = find_exn k t in
|
||||||
|
begin match f (Some v) with
|
||||||
|
| None -> remove k t
|
||||||
|
| Some v' -> add k v' t
|
||||||
|
end
|
||||||
|
with Not_found ->
|
||||||
|
match f None with
|
||||||
|
| None -> t
|
||||||
|
| Some v -> add k v t
|
||||||
|
|
||||||
|
let doubleton k1 v1 k2 v2 = add k1 v1 (singleton k2 v2)
|
||||||
|
|
||||||
|
let rec iter f t = match t with
|
||||||
|
| E -> ()
|
||||||
|
| L (k, v) -> f k v
|
||||||
|
| N (_, _, l, r) -> iter f l; iter f r
|
||||||
|
|
||||||
|
let rec fold f t acc = match t with
|
||||||
|
| E -> acc
|
||||||
|
| L (k, v) -> f k v acc
|
||||||
|
| N (_, _, l, r) ->
|
||||||
|
let acc = fold f l acc in
|
||||||
|
fold f r acc
|
||||||
|
|
||||||
|
let cardinal t = fold (fun _ _ n -> n+1) t 0
|
||||||
|
|
||||||
|
let rec choose_exn = function
|
||||||
|
| E -> raise Not_found
|
||||||
|
| L (k, v) -> k, v
|
||||||
|
| N (_, _, l, _) -> choose_exn l
|
||||||
|
|
||||||
|
let choose t =
|
||||||
|
try Some (choose_exn t)
|
||||||
|
with Not_found -> None
|
||||||
|
|
||||||
|
let union _ _ _ = assert false
|
||||||
|
|
||||||
|
let inter _ _ _ = assert false
|
||||||
|
|
||||||
|
(** {2 Whole-collection operations} *)
|
||||||
|
|
||||||
|
type 'a sequence = ('a -> unit) -> unit
|
||||||
|
type 'a gen = unit -> 'a option
|
||||||
|
|
||||||
|
let add_list t l = List.fold_left (fun t (k,v) -> add k v t) t l
|
||||||
|
|
||||||
|
let of_list l = add_list empty l
|
||||||
|
|
||||||
|
let to_list t = fold (fun k v l -> (k,v) :: l) t []
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
Q.(list (pair int int)) (fun l -> \
|
||||||
|
let l = List.map (fun (k,v) -> abs k,v) l in \
|
||||||
|
let rec is_sorted = function [] | [_] -> true \
|
||||||
|
| x::y::tail -> x <= y && is_sorted (y::tail) in \
|
||||||
|
of_list l |> to_list |> List.rev_map fst |> is_sorted)
|
||||||
|
*)
|
||||||
|
|
||||||
|
(*$Q
|
||||||
|
Q.(list (pair int int)) (fun l -> \
|
||||||
|
of_list l |> cardinal = List.length l)
|
||||||
|
*)
|
||||||
|
|
||||||
|
let add_seq t seq =
|
||||||
|
let t = ref t in
|
||||||
|
seq (fun (k,v) -> t := add k v !t);
|
||||||
|
!t
|
||||||
|
|
||||||
|
let of_seq seq = add_seq empty seq
|
||||||
|
|
||||||
|
let to_seq t yield = iter (fun k v -> yield (k,v)) t
|
||||||
|
|
||||||
|
let keys t yield = iter (fun k _ -> yield k) t
|
||||||
|
|
||||||
|
let values t yield = iter (fun _ v -> yield v) t
|
||||||
|
|
||||||
|
type 'a tree = unit -> [`Nil | `Node of 'a * 'a tree list]
|
||||||
|
|
||||||
|
let rec as_tree t () = match t with
|
||||||
|
| E -> `Nil
|
||||||
|
| L (k, v) -> `Node (`Leaf (k, v), [])
|
||||||
|
| N (prefix, switch, l, r) ->
|
||||||
|
`Node (`Node (prefix, switch), [as_tree l; as_tree r])
|
||||||
93
src/data/CCIntMap.mli
Normal file
93
src/data/CCIntMap.mli
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
|
||||||
|
(*
|
||||||
|
copyright (c) 2013-2015, simon cruanes
|
||||||
|
all rights reserved.
|
||||||
|
|
||||||
|
redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer. redistributions in binary
|
||||||
|
form must reproduce the above copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other materials provided with
|
||||||
|
the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
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.
|
||||||
|
*)
|
||||||
|
|
||||||
|
(** {1 Map specialized for Int keys} *)
|
||||||
|
|
||||||
|
type 'a t
|
||||||
|
|
||||||
|
val empty : 'a t
|
||||||
|
|
||||||
|
val singleton : int -> 'a -> 'a t
|
||||||
|
|
||||||
|
val doubleton : int -> 'a -> int -> 'a -> 'a t
|
||||||
|
|
||||||
|
val mem : int -> _ t -> bool
|
||||||
|
|
||||||
|
val find : int -> 'a t -> 'a option
|
||||||
|
|
||||||
|
val find_exn : int -> 'a t -> 'a
|
||||||
|
(** Same as {!find} but unsafe
|
||||||
|
@raise Not_found if key not present *)
|
||||||
|
|
||||||
|
val add : int -> 'a -> 'a t -> 'a t
|
||||||
|
|
||||||
|
val remove : int -> 'a t -> 'a t
|
||||||
|
|
||||||
|
val update : int -> ('a option -> 'a option) -> 'a t -> 'a t
|
||||||
|
|
||||||
|
val cardinal : _ t -> int
|
||||||
|
|
||||||
|
val iter : (int -> 'a -> unit) -> 'a t -> unit
|
||||||
|
|
||||||
|
val fold : (int -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b
|
||||||
|
|
||||||
|
val choose : 'a t -> (int * 'a) option
|
||||||
|
|
||||||
|
val choose_exn : 'a t -> int * 'a
|
||||||
|
|
||||||
|
val union : (int -> 'a -> 'a -> 'a option) -> 'a t -> 'a t -> 'a t
|
||||||
|
|
||||||
|
val inter : (int -> 'a -> 'a -> 'a option) -> 'a t -> 'a t -> 'a t
|
||||||
|
|
||||||
|
(** {2 Whole-collection operations} *)
|
||||||
|
|
||||||
|
type 'a sequence = ('a -> unit) -> unit
|
||||||
|
type 'a gen = unit -> 'a option
|
||||||
|
|
||||||
|
val add_list : 'a t -> (int * 'a) list -> 'a t
|
||||||
|
|
||||||
|
val of_list : (int * 'a) list -> 'a t
|
||||||
|
|
||||||
|
val to_list : 'a t -> (int * 'a) list
|
||||||
|
|
||||||
|
val add_seq : 'a t -> (int * 'a) sequence -> 'a t
|
||||||
|
|
||||||
|
val of_seq : (int * 'a) sequence -> 'a t
|
||||||
|
|
||||||
|
val to_seq : 'a t -> (int * 'a) sequence
|
||||||
|
|
||||||
|
val keys : _ t -> int sequence
|
||||||
|
|
||||||
|
val values : 'a t -> 'a sequence
|
||||||
|
|
||||||
|
|
||||||
|
(** Helpers *)
|
||||||
|
|
||||||
|
val highest_bit : int -> int
|
||||||
|
|
||||||
|
type 'a tree = unit -> [`Nil | `Node of 'a * 'a tree list]
|
||||||
|
|
||||||
|
val as_tree : 'a t -> [`Node of int * int | `Leaf of int * 'a ] tree
|
||||||
Loading…
Add table
Reference in a new issue