public
Description: Imperative and functional finite map implementations, head to head
Homepage:
Clone URL: git://github.com/mfp/ocaml-finite-maps.git
mfp (author)
Fri Jun 19 04:14:02 -0700 2009
commit  a6d250e4109411af58711e4f90ff25db53ee625d
tree    b3c2fdd83877f05819e13698f860c5f1fa0130c1
parent  e4606f57ac2a4cc2d442ecdfc98d1ac1e15183c5
ocaml-finite-maps / fasthashtbl.ml
100644 140 lines (121 sloc) 4.734 kb
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
(* Copyright (C) 2009 Mauricio Fernandez <mfp@acm.org> http://eigenclass.org *)
 
type ('k, 'v) t =
    { mutable size : int;
      mutable deletions : int;
      mutable data : ('k, 'v) entry array }
 
and ('k, 'v) entry = Empty | Removed | Data of 'k * 'v * int
 
(* max_array_length is odd, want an even factor *)
let max_len = (Sys.max_array_length + 1) / 2
 
let hash = Hashtbl.hash
 
let pow_of_two_size n =
  let rec loop m =
    if m > max_len then max_len
    else if m >= n then m
    else loop (2 * m)
  in loop 8
 
let mask h = Array.length h.data - 1
 
let length h = h.size
 
let stride hval mask = (((hval lsr 16) lor (hval lsl 16)) land mask) lor 1
 
let max_deletions h = Array.length h.data lsr 1
 
let create initial_size =
  let s = pow_of_two_size initial_size in
    { size = 0; deletions = 0; data = Array.make s Empty }
 
let resize h nsize =
  let odata = h.data in
  let nsize = pow_of_two_size nsize in
  let osize = Array.length odata in
    if nsize <> osize then begin
      let ndata = Array.create nsize Empty in
      let nmask = nsize - 1 in
        for i = 0 to osize - 1 do
          match odata.(i) with
              Empty -> ()
            | Removed -> ()
            | Data (_, _, hash) as data ->
                let pos = hash land nmask in
                  match ndata.(pos) with
                      Empty -> ndata.(pos) <- data
                    | Removed -> assert false
                    | Data _ ->
                        let stride = stride hash nmask in
                        let rec attempt pos =
                          match ndata.(pos) with
                            Empty -> ndata.(pos) <- data
                          | Removed -> assert false (* no removed at first *)
                          | Data _ -> attempt ((pos + stride) land nmask)
                        in attempt ((pos + stride) land nmask)
        done;
        h.data <- ndata;
        h.deletions <- 0
    end
 
let add h k v =
  let () =
    let osize = Array.length h.data in
      if h.size + 1 > osize lsr 1 then resize h (osize * 2) in
  let mask = mask h in
  let hval = hash k in
  let i = hval land mask in
    h.size <- h.size + 1;
    match h.data.(i) with
        Empty -> h.data.(i) <- Data (k, v, hval)
      | Removed -> h.deletions <- h.deletions - 1;
                   h.data.(i) <- Data (k, v, hval)
      | Data (k', _, hval') when hval = hval' && k = k' ->
          h.data.(i) <- Data (k, v, hval)
      | Data (k', v', hval') ->
          let m = stride hval mask in
          let rec walk_and_add n =
            let n = (n + m) land mask in
              match h.data.(n) with
                  Empty -> h.data.(n) <- Data (k, v, hval)
                | Removed -> h.deletions <- h.deletions - 1;
                             h.data.(n) <- Data (k, v, hval)
                | Data (k', _, hval') when hval = hval' && k = k' ->
                    h.data.(n) <- Data (k, v, hval)
                | _ -> walk_and_add n
          in walk_and_add i
 
let resize_after_remove h =
  if h.deletions > max_deletions h then
    resize h (pow_of_two_size (2 * h.size))
 
let remove h k =
  let mask = mask h in
  let hval = hash k in
  let i = hval land mask in
    match h.data.(i) with
        Empty -> ()
      | Data (k', _, hval') when hval = hval' && k = k' ->
          h.data.(i) <- Removed;
          h.deletions <- h.deletions + 1;
          h.size <- h.size - 1;
          resize_after_remove h
      | _ ->
          let stride = stride hval mask in
          let rec walk_and_remove n =
            let n = (n + stride) land mask in
              match h.data.(n) with
                  Empty -> ()
                | Data (k', _, hval') when hval = hval' && k = k' ->
                    h.data.(n) <- Removed;
                    h.deletions <- h.deletions + 1;
                    h.size <- h.size - 1
                | _ -> walk_and_remove n
          in walk_and_remove i;
             resize_after_remove h
 
let find h k =
  let mask = mask h in
  let hval = hash k in
  let i = hval land mask in
    match h.data.(i) with
        Empty -> raise Not_found
      | Data (k', v, hval') when hval = hval' && k = k' -> v
      | _ ->
          let rec walk data n stride mask =
            let n = (n + stride) land mask in
              match data.(n) with
                  Empty -> raise Not_found
                | Data (k', v, hval') when hval = hval' && k = k' -> v
                | _ -> walk data n stride mask
          in walk h.data i (stride hval mask) mask
 
let mem h k = try ignore (find h k); true with Not_found -> false
 
let load_factor h = float h.size /. float (Array.length h.data)
 
let del_factor h = float h.deletions /. float (Array.length h.data)