Blame src/pMap.ml

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