-
Notifications
You must be signed in to change notification settings - Fork 2
/
hash-array.sml
152 lines (118 loc) · 3.94 KB
/
hash-array.sml
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
141
142
143
144
145
146
147
148
149
150
151
152
signature HASHED =
sig
eqtype t
val hashValue : int -> t -> int
end
functor HashArray (Hashed:HASHED) :>
sig
type 'a hash
val hash : int -> 'a hash
val update : 'a hash * Hashed.t * 'a -> unit
val sub : 'a hash * Hashed.t -> 'a option
val delete : 'a hash * Hashed.t -> unit
val fold : (Hashed.t * 'a * 'b -> 'b) -> 'b -> 'a hash -> 'b
end
=
struct
val hashValue = Hashed.hashValue
datatype 'a status = Empty | Deleted | Used of Hashed.t * 'a
datatype 'a hash = Hash of { used: int ref, entries: 'a status array ref }
fun hash size = Hash { used = ref 0, entries = ref (Array.array (size, Empty)) }
fun prevId i length = if i = 0 then length - 1 else i - 1
fun update (Hash {entries as ref arr, used}, key, value) =
let
fun remove arr i =
case Array.sub (arr, i) of
Empty => ()
| Deleted => remove arr (prevId i (Array.length arr))
| Used (k, _) => if k = key
then Array.update (arr, i, Deleted)
else remove arr (prevId i (Array.length arr))
fun enter arr i (entry as (key, _)) =
case Array.sub (arr, i) of
Empty => ( Array.update (arr, i, Used entry); true )
| Deleted => ( remove arr i; Array.update (arr, i, Used entry); false )
(* check and remove old enter from other place, then enter new in freed place *)
| Used (k, _) => if k = key
then ( Array.update (arr, i, Used entry); false )
else enter arr (prevId i (Array.length arr)) entry
fun rehash newLength =
let
val newArr = Array.array (newLength, Empty)
val hashFromNewLength = hashValue newLength
fun doit ((Used (entry as (key, _))), r) = if enter newArr (hashFromNewLength key) entry then r + 1 else r
| doit (_, r) = r
in
used := Array.foldl doit 0 arr;
entries := newArr
end
fun maybyRehash () =
let
val length = Array.length arr
in
if !used * 5 > length * 4 (* if 80% then rehash *)
then rehash (length * 2)
else ()
end
in
if enter arr (hashValue (Array.length arr) key) (key, value)
then ( used := !used + 1 ; maybyRehash () )
else ()
end
fun fold f init (Hash { entries = ref e, ...}) =
let
fun doit (Used (k, v), r) = f (k, v, r)
| doit (_, r) = r
in
Array.foldl doit init e
end
fun sub (Hash {entries = ref arr, ...}, key) =
let
val length = Array.length arr
fun doit i = case Array.sub (arr, i) of
Empty => NONE
| Deleted => doit (prevId i length)
| Used (k, v) => if key = k
then SOME v
else doit (prevId i length)
in
doit (hashValue length key)
end
fun delete (Hash {entries = ref arr, ...}, key) =
let
val length = Array.length arr
fun doit i = case Array.sub (arr, i) of
Empty => ()
| Deleted => doit (prevId i length)
| Used (k, _) => if key = k
then Array.update (arr, i, Deleted)
else doit (prevId i length)
in
doit (hashValue length key)
end
end
structure HashArrayInt = HashArray (
struct
type t = int
fun hashValue length i = Int.mod (i, length)
end
)
structure HashArrayLargeInt = HashArray (
struct
type t = LargeInt.int
fun hashValue length i = Int.fromLarge (LargeInt.mod (i, (Int.toLarge length)))
end
)
structure HashArrayString = HashArray (
struct
type t = string
fun hashValue length str =
Word.toInt (
Word.mod (
CharVector.foldr
(fn (c, r) => Word.fromInt (Char.ord c) + 0w7 * r) 0w0 str,
(Word.fromInt length)
)
)
end
)