forked from rescript-lang/rescript
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhash.cppo.ml
144 lines (124 loc) · 4.63 KB
/
hash.cppo.ml
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
#if defined TYPE_IDENT
type key = Ident.t
type 'a t = (key, 'a) Hash_gen.t
let key_index (h : _ t ) (key : key) =
(Bs_hash_stubs.hash_stamp_and_name key.stamp key.name ) land (Array.length h.data - 1)
(* (Bs_hash_stubs.hash_string_int key.name key.stamp ) land (Array.length h.data - 1) *)
let eq_key = Ext_ident.equal
#elif defined TYPE_STRING
type key = string
type 'a t = (key, 'a) Hash_gen.t
let key_index (h : _ t ) (key : key) =
(Bs_hash_stubs.hash_string key ) land (Array.length h.data - 1)
let eq_key = Ext_string.equal
#elif defined TYPE_INT
type key = int
type 'a t = (key, 'a) Hash_gen.t
let key_index (h : _ t ) (key : key) =
(Bs_hash_stubs.hash_int key ) land (Array.length h.data - 1)
let eq_key = Ext_int.equal
#elif defined TYPE_FUNCTOR
module Make (Key : Hashtbl.HashedType) = struct
type key = Key.t
type 'a t = (key, 'a) Hash_gen.t
let key_index (h : _ t ) (key : key) =
(Key.hash key ) land (Array.length h.data - 1)
let eq_key = Key.equal
#else
[%error "unknown type"]
#endif
type ('a, 'b) bucket = ('a,'b) Hash_gen.bucket
let create = Hash_gen.create
let clear = Hash_gen.clear
let reset = Hash_gen.reset
let iter = Hash_gen.iter
let to_list = Hash_gen.to_list
let fold = Hash_gen.fold
let length = Hash_gen.length
(* let stats = Hash_gen.stats *)
let add (h : _ t) key data =
let i = key_index h key in
let h_data = h.data in
Array.unsafe_set h_data i (Cons{key; data; next=Array.unsafe_get h_data i});
h.size <- h.size + 1;
if h.size > Array.length h_data lsl 1 then Hash_gen.resize key_index h
(* after upgrade to 4.04 we should provide an efficient [replace_or_init] *)
let add_or_update
(h : 'a t)
(key : key)
~update:(modf : 'a -> 'a)
(default : 'a) : unit =
let rec find_bucket (bucketlist : _ bucket) : bool =
match bucketlist with
| Cons rhs ->
if eq_key rhs.key key then begin rhs.data <- modf rhs.data; false end
else find_bucket rhs.next
| Empty -> true in
let i = key_index h key in
let h_data = h.data in
if find_bucket (Array.unsafe_get h_data i) then
begin
Array.unsafe_set h_data i (Cons{key; data=default; next = Array.unsafe_get h_data i});
h.size <- h.size + 1 ;
if h.size > Array.length h_data lsl 1 then Hash_gen.resize key_index h
end
let remove (h : _ t ) key =
let i = key_index h key in
let h_data = h.data in
Hash_gen.remove_bucket h i key ~prec:Empty (Array.unsafe_get h_data i) eq_key
(* for short bucket list, [find_rec is not called ] *)
let rec find_rec key (bucketlist : _ bucket) = match bucketlist with
| Empty ->
raise Not_found
| Cons rhs ->
if eq_key key rhs.key then rhs.data else find_rec key rhs.next
let find_exn (h : _ t) key =
match Array.unsafe_get h.data (key_index h key) with
| Empty -> raise Not_found
| Cons rhs ->
if eq_key key rhs.key then rhs.data else
match rhs.next with
| Empty -> raise Not_found
| Cons rhs ->
if eq_key key rhs.key then rhs.data else
match rhs.next with
| Empty -> raise Not_found
| Cons rhs ->
if eq_key key rhs.key then rhs.data else find_rec key rhs.next
let find_opt (h : _ t) key =
Hash_gen.small_bucket_opt eq_key key (Array.unsafe_get h.data (key_index h key))
let find_key_opt (h : _ t) key =
Hash_gen.small_bucket_key_opt eq_key key (Array.unsafe_get h.data (key_index h key))
let find_default (h : _ t) key default =
Hash_gen.small_bucket_default eq_key key default (Array.unsafe_get h.data (key_index h key))
let find_all (h : _ t) key =
let rec find_in_bucket (bucketlist : _ bucket) = match bucketlist with
| Empty ->
[]
| Cons rhs ->
if eq_key key rhs.key
then rhs.data :: find_in_bucket rhs.next
else find_in_bucket rhs.next in
find_in_bucket (Array.unsafe_get h.data (key_index h key))
let replace h key data =
let i = key_index h key in
let h_data = h.data in
let l = Array.unsafe_get h_data i in
if Hash_gen.replace_bucket key data l eq_key then
begin
Array.unsafe_set h_data i (Cons{key; data; next=l});
h.size <- h.size + 1;
if h.size > Array.length h_data lsl 1 then Hash_gen.resize key_index h;
end
let mem (h : _ t) key =
Hash_gen.small_bucket_mem
(Array.unsafe_get h.data (key_index h key))
eq_key key
let of_list2 ks vs =
let len = List.length ks in
let map = create len in
List.iter2 (fun k v -> add map k v) ks vs ;
map
#if defined TYPE_FUNCTOR
end
#endif