Source file carbonated_map.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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
open Alpha_context
module type S = sig
type 'a t
type key
val empty : 'a t
val singleton : key -> 'a -> 'a t
val size : 'a t -> int
val find : context -> key -> 'a t -> ('a option * context) tzresult
val update :
context ->
key ->
(context -> 'a option -> ('a option * context) tzresult) ->
'a t ->
('a t * context) tzresult
val to_list : context -> 'a t -> ((key * 'a) list * context) tzresult
val of_list :
context ->
merge_overlap:(context -> 'a -> 'a -> ('a * context) tzresult) ->
(key * 'a) list ->
('a t * context) tzresult
val merge :
context ->
merge_overlap:(context -> 'a -> 'a -> ('a * context) tzresult) ->
'a t ->
'a t ->
('a t * context) tzresult
val map :
context ->
(context -> key -> 'a -> ('b * context) tzresult) ->
'a t ->
('b t * context) tzresult
val fold :
context ->
(context -> 'state -> key -> 'value -> ('state * context) tzresult) ->
'state ->
'value t ->
('state * context) tzresult
end
module type COMPARABLE = sig
include Compare.COMPARABLE
val compare_cost : t -> Gas.cost
end
module Make (C : COMPARABLE) = struct
module M = Map.Make (C)
type 'a t = {map : 'a M.t; size : int}
let empty = {map = M.empty; size = 0}
let singleton key value = {map = M.singleton key value; size = 1}
let size {size; _} = size
let find_cost ~key ~size =
Carbonated_map_costs.find_cost ~compare_key_cost:(C.compare_cost key) ~size
let update_cost ~key ~size =
Carbonated_map_costs.update_cost
~compare_key_cost:(C.compare_cost key)
~size
let find ctxt key {map; size} =
Gas.consume ctxt (find_cost ~key ~size) >|? fun ctxt ->
(M.find key map, ctxt)
let update ctxt key f {map; size} =
let find_cost = find_cost ~key ~size in
let update_cost = update_cost ~key ~size in
Gas.consume ctxt find_cost >>? fun ctxt ->
let old_val_opt = M.find key map in
f ctxt old_val_opt >>? fun (new_val_opt, ctxt) ->
match (old_val_opt, new_val_opt) with
| (Some _, Some new_val) ->
Gas.consume ctxt update_cost >|? fun ctxt ->
({map = M.add key new_val map; size}, ctxt)
| (Some _, None) ->
Gas.consume ctxt update_cost >|? fun ctxt ->
({map = M.remove key map; size = size - 1}, ctxt)
| (None, Some new_val) ->
Gas.consume ctxt update_cost >|? fun ctxt ->
({map = M.add key new_val map; size = size + 1}, ctxt)
| (None, None) -> ok ({map; size}, ctxt)
let to_list ctxt {map; size} =
Gas.consume ctxt (Carbonated_map_costs.fold_cost ~size) >|? fun ctxt ->
(M.bindings map, ctxt)
let add ctxt ~merge_overlap key value {map; size} =
Gas.consume ctxt (find_cost ~key ~size) >>? fun ctxt ->
Gas.consume ctxt (update_cost ~key ~size) >>? fun ctxt ->
match M.find key map with
| Some old_val ->
merge_overlap ctxt old_val value >|? fun (new_value, ctxt) ->
({map = M.add key new_value map; size}, ctxt)
| None -> Ok ({map = M.add key value map; size = size + 1}, ctxt)
let add_key_values_to_map ctxt ~merge_overlap map key_values =
let accum (map, ctxt) (key, value) =
add ctxt ~merge_overlap key value map
in
List.fold_left_e accum (map, ctxt) key_values
let of_list ctxt ~merge_overlap =
add_key_values_to_map ctxt ~merge_overlap empty
let merge ctxt ~merge_overlap map1 {map; size} =
Gas.consume ctxt (Carbonated_map_costs.fold_cost ~size) >>? fun ctxt ->
M.fold_e
(fun key value (map, ctxt) -> add ctxt ~merge_overlap key value map)
map
(map1, ctxt)
let fold ctxt f empty {map; size} =
Gas.consume ctxt (Carbonated_map_costs.fold_cost ~size) >>? fun ctxt ->
M.fold_e
(fun key value (acc, ctxt) ->
f ctxt acc key value)
map
(empty, ctxt)
let map ctxt f {map; size} =
fold
ctxt
(fun ctxt map key value ->
f ctxt key value >>? fun (value, ctxt) ->
Gas.consume ctxt (update_cost ~key ~size) >|? fun ctxt ->
(M.add key value map, ctxt))
M.empty
{map; size}
>|? fun (map, ctxt) -> ({map; size}, ctxt)
end