|
rpm-build |
0f2925 |
(*
|
|
rpm-build |
0f2925 |
* PMap - Polymorphic maps
|
|
rpm-build |
0f2925 |
* Copyright (C) 1996-2003 Xavier Leroy, Nicolas Cannasse, Markus Mottl
|
|
rpm-build |
0f2925 |
*
|
|
rpm-build |
0f2925 |
* This library is free software; you can redistribute it and/or
|
|
rpm-build |
0f2925 |
* modify it under the terms of the GNU Lesser General Public
|
|
rpm-build |
0f2925 |
* License as published by the Free Software Foundation; either
|
|
rpm-build |
0f2925 |
* version 2.1 of the License, or (at your option) any later version,
|
|
rpm-build |
0f2925 |
* with the special exception on linking described in file LICENSE.
|
|
rpm-build |
0f2925 |
*
|
|
rpm-build |
0f2925 |
* This library is distributed in the hope that it will be useful,
|
|
rpm-build |
0f2925 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
rpm-build |
0f2925 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
rpm-build |
0f2925 |
* Lesser General Public License for more details.
|
|
rpm-build |
0f2925 |
*
|
|
rpm-build |
0f2925 |
* You should have received a copy of the GNU Lesser General Public
|
|
rpm-build |
0f2925 |
* License along with this library; if not, write to the Free Software
|
|
rpm-build |
0f2925 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
rpm-build |
0f2925 |
*)
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
type ('k, 'v) map =
|
|
rpm-build |
0f2925 |
| Empty
|
|
rpm-build |
0f2925 |
| Node of ('k, 'v) map * 'k * 'v * ('k, 'v) map * int
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
type ('k, 'v) t =
|
|
rpm-build |
0f2925 |
{
|
|
rpm-build |
0f2925 |
cmp : 'k -> 'k -> int;
|
|
rpm-build |
0f2925 |
map : ('k, 'v) map;
|
|
rpm-build |
0f2925 |
}
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
let height = function
|
|
rpm-build |
0f2925 |
| Node (_, _, _, _, h) -> h
|
|
rpm-build |
0f2925 |
| Empty -> 0
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
let make l k v r = Node (l, k, v, r, max (height l) (height r) + 1)
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
let bal l k v r =
|
|
rpm-build |
0f2925 |
let hl = height l in
|
|
rpm-build |
0f2925 |
let hr = height r in
|
|
rpm-build |
0f2925 |
if hl > hr + 2 then
|
|
rpm-build |
0f2925 |
match l with
|
|
rpm-build |
0f2925 |
| Node (ll, lk, lv, lr, _) ->
|
|
rpm-build |
0f2925 |
if height ll >= height lr then make ll lk lv (make lr k v r)
|
|
rpm-build |
0f2925 |
else
|
|
rpm-build |
0f2925 |
(match lr with
|
|
rpm-build |
0f2925 |
| Node (lrl, lrk, lrv, lrr, _) ->
|
|
rpm-build |
0f2925 |
make (make ll lk lv lrl) lrk lrv (make lrr k v r)
|
|
rpm-build |
0f2925 |
| Empty -> assert false)
|
|
rpm-build |
0f2925 |
| Empty -> assert false
|
|
rpm-build |
0f2925 |
else if hr > hl + 2 then
|
|
rpm-build |
0f2925 |
match r with
|
|
rpm-build |
0f2925 |
| Node (rl, rk, rv, rr, _) ->
|
|
rpm-build |
0f2925 |
if height rr >= height rl then make (make l k v rl) rk rv rr
|
|
rpm-build |
0f2925 |
else
|
|
rpm-build |
0f2925 |
(match rl with
|
|
rpm-build |
0f2925 |
| Node (rll, rlk, rlv, rlr, _) ->
|
|
rpm-build |
0f2925 |
make (make l k v rll) rlk rlv (make rlr rk rv rr)
|
|
rpm-build |
0f2925 |
| Empty -> assert false)
|
|
rpm-build |
0f2925 |
| Empty -> assert false
|
|
rpm-build |
0f2925 |
else Node (l, k, v, r, max hl hr + 1)
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
let rec min_binding = function
|
|
rpm-build |
0f2925 |
| Node (Empty, k, v, _, _) -> k, v
|
|
rpm-build |
0f2925 |
| Node (l, _, _, _, _) -> min_binding l
|
|
rpm-build |
0f2925 |
| Empty -> raise Not_found
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
let rec remove_min_binding = function
|
|
rpm-build |
0f2925 |
| Node (Empty, _, _, r, _) -> r
|
|
rpm-build |
0f2925 |
| Node (l, k, v, r, _) -> bal (remove_min_binding l) k v r
|
|
rpm-build |
0f2925 |
| Empty -> invalid_arg "PMap.remove_min_binding"
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
let merge t1 t2 =
|
|
rpm-build |
0f2925 |
match t1, t2 with
|
|
rpm-build |
0f2925 |
| Empty, _ -> t2
|
|
rpm-build |
0f2925 |
| _, Empty -> t1
|
|
rpm-build |
0f2925 |
| _ ->
|
|
rpm-build |
0f2925 |
let k, v = min_binding t2 in
|
|
rpm-build |
0f2925 |
bal t1 k v (remove_min_binding t2)
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
let create cmp = { cmp = cmp; map = Empty }
|
|
rpm-build |
0f2925 |
let empty = { cmp = compare; map = Empty }
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
let is_empty x =
|
|
rpm-build |
0f2925 |
x.map = Empty
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
let add x d { cmp = cmp; map = map } =
|
|
rpm-build |
0f2925 |
let rec loop = function
|
|
rpm-build |
0f2925 |
| Node (l, k, v, r, h) ->
|
|
rpm-build |
0f2925 |
let c = cmp x k in
|
|
rpm-build |
0f2925 |
if c = 0 then Node (l, x, d, r, h)
|
|
rpm-build |
0f2925 |
else if c < 0 then
|
|
rpm-build |
0f2925 |
let nl = loop l in
|
|
rpm-build |
0f2925 |
bal nl k v r
|
|
rpm-build |
0f2925 |
else
|
|
rpm-build |
0f2925 |
let nr = loop r in
|
|
rpm-build |
0f2925 |
bal l k v nr
|
|
rpm-build |
0f2925 |
| Empty -> Node (Empty, x, d, Empty, 1) in
|
|
rpm-build |
0f2925 |
{ cmp = cmp; map = loop map }
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
let find x { cmp = cmp; map = map } =
|
|
rpm-build |
0f2925 |
let rec loop = function
|
|
rpm-build |
0f2925 |
| Node (l, k, v, r, _) ->
|
|
rpm-build |
0f2925 |
let c = cmp x k in
|
|
rpm-build |
0f2925 |
if c < 0 then loop l
|
|
rpm-build |
0f2925 |
else if c > 0 then loop r
|
|
rpm-build |
0f2925 |
else v
|
|
rpm-build |
0f2925 |
| Empty -> raise Not_found in
|
|
rpm-build |
0f2925 |
loop map
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
let remove x { cmp = cmp; map = map } =
|
|
rpm-build |
0f2925 |
let rec loop = function
|
|
rpm-build |
0f2925 |
| Node (l, k, v, r, _) ->
|
|
rpm-build |
0f2925 |
let c = cmp x k in
|
|
rpm-build |
0f2925 |
if c = 0 then merge l r else
|
|
rpm-build |
0f2925 |
if c < 0 then bal (loop l) k v r else bal l k v (loop r)
|
|
rpm-build |
0f2925 |
| Empty -> Empty in
|
|
rpm-build |
0f2925 |
{ cmp = cmp; map = loop map }
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
let mem x { cmp = cmp; map = map } =
|
|
rpm-build |
0f2925 |
let rec loop = function
|
|
rpm-build |
0f2925 |
| Node (l, k, v, r, _) ->
|
|
rpm-build |
0f2925 |
let c = cmp x k in
|
|
rpm-build |
0f2925 |
c = 0 || loop (if c < 0 then l else r)
|
|
rpm-build |
0f2925 |
| Empty -> false in
|
|
rpm-build |
0f2925 |
loop map
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
let exists = mem
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
let iter f { map = map } =
|
|
rpm-build |
0f2925 |
let rec loop = function
|
|
rpm-build |
0f2925 |
| Empty -> ()
|
|
rpm-build |
0f2925 |
| Node (l, k, v, r, _) -> loop l; f k v; loop r in
|
|
rpm-build |
0f2925 |
loop map
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
let map f { cmp = cmp; map = map } =
|
|
rpm-build |
0f2925 |
let rec loop = function
|
|
rpm-build |
0f2925 |
| Empty -> Empty
|
|
rpm-build |
0f2925 |
| Node (l, k, v, r, h) ->
|
|
rpm-build |
0f2925 |
let l = loop l in
|
|
rpm-build |
0f2925 |
let r = loop r in
|
|
rpm-build |
0f2925 |
Node (l, k, f v, r, h) in
|
|
rpm-build |
0f2925 |
{ cmp = cmp; map = loop map }
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
let mapi f { cmp = cmp; map = map } =
|
|
rpm-build |
0f2925 |
let rec loop = function
|
|
rpm-build |
0f2925 |
| Empty -> Empty
|
|
rpm-build |
0f2925 |
| Node (l, k, v, r, h) ->
|
|
rpm-build |
0f2925 |
let l = loop l in
|
|
rpm-build |
0f2925 |
let r = loop r in
|
|
rpm-build |
0f2925 |
Node (l, k, f k v, r, h) in
|
|
rpm-build |
0f2925 |
{ cmp = cmp; map = loop map }
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
let fold f { cmp = cmp; map = map } acc =
|
|
rpm-build |
0f2925 |
let rec loop acc = function
|
|
rpm-build |
0f2925 |
| Empty -> acc
|
|
rpm-build |
0f2925 |
| Node (l, k, v, r, _) ->
|
|
rpm-build |
0f2925 |
loop (f v (loop acc l)) r in
|
|
rpm-build |
0f2925 |
loop acc map
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
let foldi f { cmp = cmp; map = map } acc =
|
|
rpm-build |
0f2925 |
let rec loop acc = function
|
|
rpm-build |
0f2925 |
| Empty -> acc
|
|
rpm-build |
0f2925 |
| Node (l, k, v, r, _) ->
|
|
rpm-build |
0f2925 |
loop (f k v (loop acc l)) r in
|
|
rpm-build |
0f2925 |
loop acc map
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
let rec enum m =
|
|
rpm-build |
0f2925 |
let rec make l =
|
|
rpm-build |
0f2925 |
let l = ref l in
|
|
rpm-build |
0f2925 |
let rec next() =
|
|
rpm-build |
0f2925 |
match !l with
|
|
rpm-build |
0f2925 |
| [] -> raise Enum.No_more_elements
|
|
rpm-build |
0f2925 |
| Empty :: tl -> l := tl; next()
|
|
rpm-build |
0f2925 |
| Node (m1, key, data, m2, h) :: tl ->
|
|
rpm-build |
0f2925 |
l := m1 :: m2 :: tl;
|
|
rpm-build |
0f2925 |
(key, data)
|
|
rpm-build |
0f2925 |
in
|
|
rpm-build |
0f2925 |
let count() =
|
|
rpm-build |
0f2925 |
let n = ref 0 in
|
|
rpm-build |
0f2925 |
let r = !l in
|
|
rpm-build |
0f2925 |
try
|
|
rpm-build |
0f2925 |
while true do
|
|
rpm-build |
0f2925 |
ignore (next());
|
|
rpm-build |
0f2925 |
incr n
|
|
rpm-build |
0f2925 |
done;
|
|
rpm-build |
0f2925 |
assert false
|
|
rpm-build |
0f2925 |
with
|
|
rpm-build |
0f2925 |
Enum.No_more_elements -> l := r; !n
|
|
rpm-build |
0f2925 |
in
|
|
rpm-build |
0f2925 |
let clone() = make !l in
|
|
rpm-build |
0f2925 |
Enum.make ~next ~count ~clone
|
|
rpm-build |
0f2925 |
in
|
|
rpm-build |
0f2925 |
make [m.map]
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
|
|
rpm-build |
0f2925 |
let uncurry_add (k, v) m = add k v m
|
|
rpm-build |
0f2925 |
let of_enum ?(cmp = compare) e = Enum.fold uncurry_add (create cmp) e
|