summaryrefslogtreecommitdiff
path: root/hashtable.sml
blob: 24e5bba2ff706830bb288bcd9ec31a7820cd8583 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
structure Hashtable :> HASHTABLE = struct
    (* (Array, (cells occupied, total size)) *)
  type 'a t = ((string * 'a) option) array * (int * int)

  exception HashtableFull
  exception Exists

  fun create size = (Array.array (size, NONE), (0, size))

  val fillLimit = 0.75

  val ` = Word32.fromInt

  fun hashFunc key =
  let
    open Word32
  in
    List.foldl (fn (x, acc) => acc * `31 + `(ord x)) (`0) $ explode key
  end

  fun insert (buf, (taken, total)) key value =
    if Real.fromInt (taken + 1) / Real.fromInt total > fillLimit then
      raise HashtableFull
    else
      let
        open Array
        val hash = hashFunc key

        (* TODO: use bitwise manipulation instead of mod *)
        val i = ref $ Word32.toInt $ Word32.mod (hash, `(length buf))
        val flag = ref true
      in
        while !flag do (
          case sub (buf, !i) of
            NONE => (update (buf, !i, SOME (key, value)); flag := false)
          | SOME (key', _) =>
              if key' = key then
                raise Exists
              else
                i := (!i + 1) mod (length buf)
        )
      end

  fun lookup (buf, _) key =
  let
    open Array
    val hash = hashFunc key

    val i = ref $ Word32.toInt $ Word32.mod (hash, `(length buf))
    val flag = ref true
    val result = ref NONE
  in
    while !flag do (
        case sub (buf, !i) of
          SOME (key', value) =>
            if key' = key then
              (result := SOME value; flag := false)
            else
              i := (!i + 1) mod (length buf)
        | NONE => flag := false
    );
    !result
  end
end