162 lines · 4.5 KB · Standard ML
RawDownload
(* Hasht.sml *) (* Hash tables *) (* We do dynamic hashing, and we double the size of the table when   buckets become too long, but without re-hashing the elements. *) open Array;infix 9 sub; datatype ('a, 'b) bucketlist =    Cons of 'a * int * 'b * ('a, 'b) bucketlist  | Empty; type ('a, 'b) TCell =  { max_len: int,                      (* max length of a bucket *)    data: ('a, 'b) bucketlist array }  (* the buckets *); type ('a, 'b) t = ('a, 'b) TCell ref; fun forup f a b =  let fun loop i = if i > b then () else (f i; loop (i+1))  in loop a end; fun new initial_size =  ref { max_len = 3, data = array(initial_size, Empty) }; fun clear h =  let val {data, max_len} = !h in    forup (fn i => update(data, i, Empty))      0 (Array.length data - 1)  end; fun resize h =  let val {data, max_len} = !h      val len = Array.length data      val newlen = len+len+1      val newdata = array(newlen, Empty)      fun dispatch Empty = ()        | dispatch (Cons(k, c, v, rest)) =            let val () = dispatch rest                val i = c mod newlen            in update(newdata, i, Cons(k, c, v, newdata sub i)) end  in    forup (fn i => dispatch(data sub i)) 0 (len-1);    h := { data = newdata, max_len = 2 * max_len};    ()  end; fun bucket_too_long n bucket =  if n < 0 then true else  case bucket of      Empty => false    | Cons(_, _, _, rest) => bucket_too_long (n-1) rest; prim_val hash_param : int -> int -> 'a -> int = 3 "hash_univ_param"; fun hash x = hash_param 50 500 x; fun insert h key value =  let val {data, max_len} = !h      val code = hash_param 10 100 key      fun insert_bucket Empty =            Cons(key, code, value, Empty)        | insert_bucket (Cons(k, c, v, next)) =            if code = c andalso k = key then              Cons(key, code, value, next)            else Cons(k, c, v, insert_bucket next)      val i = code mod (Array.length data)      val bucket = insert_bucket (data sub i)  in    update(data, i, bucket);    if bucket_too_long max_len bucket then resize h else ()  end; fun remove h key =  let val {data, max_len : int} = !h      val code = hash_param 10 100 key      fun remove_bucket Empty = Empty        | remove_bucket (Cons(k, c, v, next)) =            if code = c andalso k = key then              next            else Cons(k, c, v, remove_bucket next)      val i = code mod (Array.length data)  in update(data, i, remove_bucket (data sub i)) end; fun find h key =  let val {data, max_len : int} = !h      val code = (hash_param 10 100 key)  in  case data sub (code mod (Array.length data)) of      Empty => raise Subscript    | Cons(k1, c1, d1, rest1) =>        if code = c1 andalso key = k1 then d1 else        case rest1 of          Empty => raise Subscript        | Cons(k2, c2, d2, rest2) =>            if code = c2 andalso key = k2 then d2 else            case rest2 of                Empty => raise Subscript              | Cons(k3, c3, d3, rest3) =>                if code = c3 andalso key = k3 then d3 else                let fun find Empty = raise Subscript                      | find (Cons(k, c, d, rest)) =                          if code = c andalso key = k then d else find rest                in find rest3 end  end; fun peek h key =  let val {data, max_len : int} = !h      val code = (hash_param 10 100 key)  in  case data sub (code mod (Array.length data)) of      Empty => NONE    | Cons(k1, c1, d1, rest1) =>        if code = c1 andalso key = k1 then SOME d1 else        case rest1 of          Empty => NONE        | Cons(k2, c2, d2, rest2) =>            if code = c2 andalso key = k2 then SOME d2 else            case rest2 of                Empty => NONE              | Cons(k3, c3, d3, rest3) =>                if code = c3 andalso key = k3 then SOME d3 else                let fun peek Empty = NONE                      | peek (Cons(k, c, d, rest)) =                          if code = c andalso key = k then SOME d 			  else peek rest                in peek rest3 end  end; fun apply f h =  let val {data, max_len : int} = !h      val len = Array.length data  in    forup (fn i =>        let fun scan_bucket Empty = ()              | scan_bucket (Cons(k, c, d, rest)) =                  ( f k d : unit; scan_bucket rest )        in scan_bucket (data sub i) end)      0 (len - 1)  end; fun fold f e h =  let val {data, max_len : int} = !h      fun fold_bucket (Empty, res) = res	| fold_bucket (Cons(k, c, d, rest), res) = 	  fold_bucket (rest, f k d res)  in      Array.foldl fold_bucket e data   end;