1%% %CopyrightBegin%
2%%
3%% Copyright Ericsson AB 2013. All Rights Reserved.
4%%
5%% Licensed under the Apache License, Version 2.0 (the "License");
6%% you may not use this file except in compliance with the License.
7%% You may obtain a copy of the License at
8%%
9%%     http://www.apache.org/licenses/LICENSE-2.0
10%%
11%% Unless required by applicable law or agreed to in writing, software
12%% distributed under the License is distributed on an "AS IS" BASIS,
13%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14%% See the License for the specific language governing permissions and
15%% limitations under the License.
16%%
17%% %CopyrightEnd%
18%%
19-module(map_SUITE).
20-export([all/0, suite/0]).
21
22-export([t_build_and_match_literals/1, t_build_and_match_literals_large/1,
23         t_update_literals/1, t_update_literals_large/1,
24         t_match_and_update_literals/1, t_match_and_update_literals_large/1,
25         t_update_map_expressions/1,
26         t_update_assoc/1, t_update_assoc_large/1,
27         t_update_exact/1, t_update_exact_large/1,
28         t_guard_bifs/1,
29         t_guard_sequence/1, t_guard_sequence_large/1,
30         t_guard_update/1, t_guard_update_large/1,
31         t_guard_receive/1, t_guard_receive_large/1,
32         t_guard_fun/1,
33         t_update_deep/1,
34         t_list_comprehension/1,
35         t_map_sort_literals/1,
36         t_map_equal/1,
37         t_map_compare/1,
38         t_map_size/1,
39         t_map_get/1,
40         t_is_map/1,
41         t_is_map_key/1,
42
43         %% Specific Map BIFs
44         t_bif_map_get/1,
45         t_bif_map_find/1,
46         t_bif_map_is_key/1,
47         t_bif_map_keys/1,
48         t_bif_map_merge/1,
49         t_bif_map_new/1,
50         t_bif_map_put/1,
51         t_bif_map_remove/1,
52         t_bif_map_take/1, t_bif_map_take_large/1,
53         t_bif_map_update/1,
54         t_bif_map_values/1,
55         t_bif_map_to_list/1,
56         t_bif_map_from_list/1,
57         t_bif_map_next/1,
58
59         %% erlang
60         t_erlang_hash/1,
61         t_map_encode_decode/1,
62         t_gc_rare_map_overflow/1,
63
64         %% non specific BIF related
65         t_bif_build_and_check/1,
66         t_bif_merge_and_check/1,
67
68         %% maps module not bifs
69         t_maps_fold/1,
70         t_maps_map/1,
71         t_maps_size/1,
72         t_maps_without/1,
73
74         %% misc
75         t_hashmap_balance/1,
76         t_erts_internal_order/1,
77         t_erts_internal_hash/1,
78         t_pdict/1,
79         t_ets/1,
80         t_dets/1,
81         t_tracing/1,
82         t_hash_entropy/1,
83
84         %% instruction-level tests
85         t_has_map_fields/1,
86         y_regs/1,
87         badmap_17/1]).
88
89-include_lib("stdlib/include/ms_transform.hrl").
90
91-define(CHECK(Cond,Term),
92	case (catch (Cond)) of
93	    true -> true;
94	    _ -> io:format("###### CHECK FAILED ######~nINPUT:  ~p~n", [Term]),
95		 exit(Term)
96	end).
97
98suite() -> [].
99
100all() -> [t_build_and_match_literals, t_build_and_match_literals_large,
101          t_update_literals, t_update_literals_large,
102          t_match_and_update_literals, t_match_and_update_literals_large,
103          t_update_map_expressions,
104          t_update_assoc, t_update_assoc_large,
105          t_update_exact, t_update_exact_large,
106          t_guard_bifs,
107          t_guard_sequence, t_guard_sequence_large,
108          t_guard_update, t_guard_update_large,
109          t_guard_receive, t_guard_receive_large,
110          t_guard_fun, t_list_comprehension,
111          t_update_deep,
112          t_map_equal, t_map_compare,
113          t_map_sort_literals,
114
115          %% Specific Map BIFs
116          t_bif_map_get,t_bif_map_find,t_bif_map_is_key,
117          t_bif_map_keys, t_bif_map_merge, t_bif_map_new,
118          t_bif_map_put,
119          t_bif_map_remove,
120          t_bif_map_take, t_bif_map_take_large,
121          t_bif_map_update,
122          t_bif_map_values,
123          t_bif_map_to_list, t_bif_map_from_list,
124          t_bif_map_next,
125
126          %% erlang
127          t_erlang_hash, t_map_encode_decode,
128          t_gc_rare_map_overflow,
129          t_map_size, t_map_get, t_is_map,
130
131          %% non specific BIF related
132          t_bif_build_and_check,
133          t_bif_merge_and_check,
134
135          %% maps module
136          t_maps_fold, t_maps_map,
137          t_maps_size, t_maps_without,
138
139
140          %% Other functions
141          t_hashmap_balance,
142          t_erts_internal_order,
143          t_erts_internal_hash,
144          t_pdict,
145          t_ets,
146          t_tracing,
147          t_hash_entropy,
148
149          %% instruction-level tests
150          t_has_map_fields,
151          y_regs,
152          badmap_17].
153
154%% tests
155
156t_build_and_match_literals(Config) when is_list(Config) ->
157    #{} = id(#{}),
158    #{1:=a} = id(#{1=>a}),
159    #{1:=a,2:=b} = id(#{1=>a,2=>b}),
160    #{1:=a,2:=b,3:="c"} = id(#{1=>a,2=>b,3=>"c"}),
161    #{1:=a,2:=b,3:="c","4":="d"} = id(#{1=>a,2=>b,3=>"c","4"=>"d"}),
162    #{1:=a,2:=b,3:="c","4":="d",<<"5">>:=<<"e">>} =
163	id(#{1=>a,2=>b,3=>"c","4"=>"d",<<"5">>=><<"e">>}),
164    #{1:=a,2:=b,3:="c","4":="d",<<"5">>:=<<"e">>,{"6",7}:="f"} =
165	id(#{1=>a,2=>b,3=>"c","4"=>"d",<<"5">>=><<"e">>,{"6",7}=>"f"}),
166    #{1:=a,2:=b,3:="c","4":="d",<<"5">>:=<<"e">>,{"6",7}:="f",8:=g} =
167	id(#{1=>a,2=>b,3=>"c","4"=>"d",<<"5">>=><<"e">>,{"6",7}=>"f",8=>g}),
168
169    #{[]:=a,42.0:=b,x:={x,y},[a,b]:=list} =
170         id(#{[]=>a,42.0=>b,x=>{x,y},[a,b]=>list}),
171
172    #{<<"hi all">> := 1} = id(#{<<"hi",32,"all">> => 1}),
173
174    #{a:=X,a:=X=3,b:=4} = id(#{a=>3,b=>4}), % weird but ok =)
175
176    #{ a:=#{ b:=#{c := third, b:=second}}, b:=first} =
177	id(#{ b=>first, a=>#{ b=>#{c => third, b=> second}}}),
178
179    M = #{ map_1=>#{ map_2=>#{value_3 => third}, value_2=> second}, value_1=>first},
180    M = #{ map_1:=#{ map_2:=#{value_3 := third}, value_2:= second}, value_1:=first} =
181	 id(#{ map_1=>#{ map_2=>#{value_3 => third}, value_2=> second}, value_1=>first}),
182
183    %% error case
184    %V = 32,
185    %{'EXIT',{{badmatch,_},_}} = (catch (#{<<"hi all">> => 1} = id(#{<<"hi",V,"all">> => 1}))),
186    {'EXIT',{{badmatch,_},_}} = (catch (#{x:=3,x:=2} = id(#{x=>3}))),
187    {'EXIT',{{badmatch,_},_}} = (catch (#{x:=2} = id(#{x=>3}))),
188    {'EXIT',{{badmatch,_},_}} = (catch (#{x:=3} = id({a,b,c}))),
189    {'EXIT',{{badmatch,_},_}} = (catch (#{x:=3} = id(#{y=>3}))),
190    {'EXIT',{{badmatch,_},_}} = (catch (#{x:=3} = id(#{x=>"three"}))),
191    ok.
192
193t_build_and_match_literals_large(Config) when is_list(Config) ->
194    % normal non-repeating
195    M0 = id(#{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
196               11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
197               12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
198               13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
199               14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
200
201               15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
202               16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
203               17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
204               18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
205               19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" }),
206
207    #{10:=a0,20:=b0,30:="c0","40":="d0",<<"50">>:="e0",{["00"]}:="10"} = M0,
208    #{11:=a1,21:=b1,31:="c1","41":="d1",<<"51">>:="e1",{["01"]}:="11"} = M0,
209    #{12:=a2,22:=b2,32:="c2","42":="d2",<<"52">>:="e2",{["02"]}:="12"} = M0,
210    #{13:=a3,23:=b3,33:="c3","43":="d3",<<"53">>:="e3",{["03"]}:="13"} = M0,
211    #{14:=a4,24:=b4,34:="c4","44":="d4",<<"54">>:="e4",{["04"]}:="14"} = M0,
212
213    #{15:=a5,25:=b5,35:="c5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M0,
214    #{16:=a6,26:=b6,36:="c6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M0,
215    #{17:=a7,27:=b7,37:="c7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M0,
216    #{18:=a8,28:=b8,38:="c8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M0,
217    #{19:=a9,29:=b9,39:="c9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M0,
218
219    60 = map_size(M0),
220    60 = maps:size(M0),
221
222    % with repeating
223    M1 = id(#{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
224               11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
225               12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
226               13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
227               14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
228
229               10=>na0,20=>nb0,30=>"nc0","40"=>"nd0",<<"50">>=>"ne0",{["00"]}=>"n10",
230               11=>na1,21=>nb1,31=>"nc1","41"=>"nd1",<<"51">>=>"ne1",{["01"]}=>"n11",
231               12=>na2,22=>nb2,32=>"nc2","42"=>"nd2",<<"52">>=>"ne2",{["02"]}=>"n12",
232
233               15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
234               16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
235               17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
236
237               13=>na3,23=>nb3,33=>"nc3","43"=>"nd3",<<"53">>=>"ne3",{["03"]}=>"n13",
238               14=>na4,24=>nb4,34=>"nc4","44"=>"nd4",<<"54">>=>"ne4",{["04"]}=>"n14",
239
240               18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
241               19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" }),
242
243    #{10:=na0,20:=nb0,30:="nc0","40":="nd0",<<"50">>:="ne0",{["00"]}:="n10"} = M1,
244    #{11:=na1,21:=nb1,31:="nc1","41":="nd1",<<"51">>:="ne1",{["01"]}:="n11"} = M1,
245    #{12:=na2,22:=nb2,32:="nc2","42":="nd2",<<"52">>:="ne2",{["02"]}:="n12"} = M1,
246    #{13:=na3,23:=nb3,33:="nc3","43":="nd3",<<"53">>:="ne3",{["03"]}:="n13"} = M1,
247    #{14:=na4,24:=nb4,34:="nc4","44":="nd4",<<"54">>:="ne4",{["04"]}:="n14"} = M1,
248
249    #{15:=a5,25:=b5,35:="c5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M1,
250    #{16:=a6,26:=b6,36:="c6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M1,
251    #{17:=a7,27:=b7,37:="c7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M1,
252    #{18:=a8,28:=b8,38:="c8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M1,
253    #{19:=a9,29:=b9,39:="c9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M1,
254
255    60 = map_size(M1),
256    60 = maps:size(M1),
257
258    % with floats
259
260    M2 = id(#{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
261               11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
262               12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
263               13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
264               14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
265
266               15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
267               16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
268               17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
269               18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
270               19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19",
271
272               10.0=>fa0,20.0=>fb0,30.0=>"fc0",
273               11.0=>fa1,21.0=>fb1,31.0=>"fc1",
274               12.0=>fa2,22.0=>fb2,32.0=>"fc2",
275               13.0=>fa3,23.0=>fb3,33.0=>"fc3",
276               14.0=>fa4,24.0=>fb4,34.0=>"fc4",
277
278               15.0=>fa5,25.0=>fb5,35.0=>"fc5",
279               16.0=>fa6,26.0=>fb6,36.0=>"fc6",
280               17.0=>fa7,27.0=>fb7,37.0=>"fc7",
281               18.0=>fa8,28.0=>fb8,38.0=>"fc8",
282               19.0=>fa9,29.0=>fb9,39.0=>"fc9"}),
283
284    #{10:=a0,20:=b0,30:="c0","40":="d0",<<"50">>:="e0",{["00"]}:="10"} = M2,
285    #{11:=a1,21:=b1,31:="c1","41":="d1",<<"51">>:="e1",{["01"]}:="11"} = M2,
286    #{12:=a2,22:=b2,32:="c2","42":="d2",<<"52">>:="e2",{["02"]}:="12"} = M2,
287    #{13:=a3,23:=b3,33:="c3","43":="d3",<<"53">>:="e3",{["03"]}:="13"} = M2,
288    #{14:=a4,24:=b4,34:="c4","44":="d4",<<"54">>:="e4",{["04"]}:="14"} = M2,
289
290    #{15:=a5,25:=b5,35:="c5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M2,
291    #{16:=a6,26:=b6,36:="c6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M2,
292    #{17:=a7,27:=b7,37:="c7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M2,
293    #{18:=a8,28:=b8,38:="c8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M2,
294    #{19:=a9,29:=b9,39:="c9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M2,
295
296    #{10.0:=fa0,20.0:=fb0,30.0:="fc0","40":="d0",<<"50">>:="e0",{["00"]}:="10"} = M2,
297    #{11.0:=fa1,21.0:=fb1,31.0:="fc1","41":="d1",<<"51">>:="e1",{["01"]}:="11"} = M2,
298    #{12.0:=fa2,22.0:=fb2,32.0:="fc2","42":="d2",<<"52">>:="e2",{["02"]}:="12"} = M2,
299    #{13.0:=fa3,23.0:=fb3,33.0:="fc3","43":="d3",<<"53">>:="e3",{["03"]}:="13"} = M2,
300    #{14.0:=fa4,24.0:=fb4,34.0:="fc4","44":="d4",<<"54">>:="e4",{["04"]}:="14"} = M2,
301
302    #{15.0:=fa5,25.0:=fb5,35.0:="fc5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M2,
303    #{16.0:=fa6,26.0:=fb6,36.0:="fc6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M2,
304    #{17.0:=fa7,27.0:=fb7,37.0:="fc7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M2,
305    #{18.0:=fa8,28.0:=fb8,38.0:="fc8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M2,
306    #{19.0:=fa9,29.0:=fb9,39.0:="fc9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M2,
307
308    90 = map_size(M2),
309    90 = maps:size(M2),
310
311    % with bignums
312    M3 = id(#{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
313               11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
314               12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
315               13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
316               14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
317
318               15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
319               16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
320               17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
321               18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
322               19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19",
323
324               10.0=>fa0,20.0=>fb0,30.0=>"fc0",
325               11.0=>fa1,21.0=>fb1,31.0=>"fc1",
326               12.0=>fa2,22.0=>fb2,32.0=>"fc2",
327               13.0=>fa3,23.0=>fb3,33.0=>"fc3",
328               14.0=>fa4,24.0=>fb4,34.0=>"fc4",
329
330               15.0=>fa5,25.0=>fb5,35.0=>"fc5",
331               16.0=>fa6,26.0=>fb6,36.0=>"fc6",
332               17.0=>fa7,27.0=>fb7,37.0=>"fc7",
333               18.0=>fa8,28.0=>fb8,38.0=>"fc8",
334               19.0=>fa9,29.0=>fb9,39.0=>"fc9",
335
336               36893488147419103232=>big1,  73786976294838206464=>big2,
337               147573952589676412928=>big3, 18446744073709551616=>big4,
338               4294967296=>big5,            8589934592=>big6,
339               4294967295=>big7,            67108863=>big8
340             }),
341
342    #{10:=a0,20:=b0,30:="c0","40":="d0",<<"50">>:="e0",{["00"]}:="10"} = M3,
343    #{11:=a1,21:=b1,31:="c1","41":="d1",<<"51">>:="e1",{["01"]}:="11"} = M3,
344    #{12:=a2,22:=b2,32:="c2","42":="d2",<<"52">>:="e2",{["02"]}:="12"} = M3,
345    #{13:=a3,23:=b3,33:="c3","43":="d3",<<"53">>:="e3",{["03"]}:="13"} = M3,
346    #{14:=a4,24:=b4,34:="c4","44":="d4",<<"54">>:="e4",{["04"]}:="14"} = M3,
347
348    #{15:=a5,25:=b5,35:="c5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M3,
349    #{16:=a6,26:=b6,36:="c6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M3,
350    #{17:=a7,27:=b7,37:="c7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M3,
351    #{18:=a8,28:=b8,38:="c8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M3,
352    #{19:=a9,29:=b9,39:="c9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M3,
353
354    #{10.0:=fa0,20.0:=fb0,30.0:="fc0","40":="d0",<<"50">>:="e0",{["00"]}:="10"} = M3,
355    #{11.0:=fa1,21.0:=fb1,31.0:="fc1","41":="d1",<<"51">>:="e1",{["01"]}:="11"} = M3,
356    #{12.0:=fa2,22.0:=fb2,32.0:="fc2","42":="d2",<<"52">>:="e2",{["02"]}:="12"} = M3,
357    #{13.0:=fa3,23.0:=fb3,33.0:="fc3","43":="d3",<<"53">>:="e3",{["03"]}:="13"} = M3,
358    #{14.0:=fa4,24.0:=fb4,34.0:="fc4","44":="d4",<<"54">>:="e4",{["04"]}:="14"} = M3,
359
360    #{15.0:=fa5,25.0:=fb5,35.0:="fc5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M3,
361    #{16.0:=fa6,26.0:=fb6,36.0:="fc6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M3,
362    #{17.0:=fa7,27.0:=fb7,37.0:="fc7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M3,
363    #{18.0:=fa8,28.0:=fb8,38.0:="fc8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M3,
364    #{19.0:=fa9,29.0:=fb9,39.0:="fc9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M3,
365
366    #{36893488147419103232:=big1,67108863:=big8,"45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M3,
367    #{147573952589676412928:=big3,8589934592:=big6,"46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M3,
368    #{4294967296:=big5,18446744073709551616:=big4,"47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M3,
369    #{4294967295:=big7,73786976294838206464:=big2,"48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M3,
370
371    98 = map_size(M3),
372    98 = maps:size(M3),
373
374    %% with maps
375
376    M4 = id(#{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
377               11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
378               12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
379               13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
380               14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
381
382               15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
383               16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
384               17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
385               18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
386               19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19",
387
388               10.0=>fa0,20.0=>fb0,30.0=>"fc0",
389               11.0=>fa1,21.0=>fb1,31.0=>"fc1",
390               12.0=>fa2,22.0=>fb2,32.0=>"fc2",
391               13.0=>fa3,23.0=>fb3,33.0=>"fc3",
392               14.0=>fa4,24.0=>fb4,34.0=>"fc4",
393
394               15.0=>fa5,25.0=>fb5,35.0=>"fc5",
395               16.0=>fa6,26.0=>fb6,36.0=>"fc6",
396               17.0=>fa7,27.0=>fb7,37.0=>"fc7",
397               18.0=>fa8,28.0=>fb8,38.0=>"fc8",
398               19.0=>fa9,29.0=>fb9,39.0=>"fc9",
399
400               #{ one => small, map => key } => "small map key 1",
401               #{ second => small, map => key } => "small map key 2",
402               #{ third => small, map => key } => "small map key 3",
403
404               #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
405                  11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
406                  12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
407                  13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
408                  14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
409
410                  15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
411                  16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
412                  17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
413                  18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
414                  19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 1",
415
416               #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
417                  11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
418                  12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
419                  13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
420                  14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
421
422                  15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
423                  k16=>a6,k26=>b6,k36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
424                  17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
425                  18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
426                  19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 2" }),
427
428    #{10:=a0,20:=b0,30:="c0","40":="d0",<<"50">>:="e0",{["00"]}:="10"} = M4,
429    #{11:=a1,21:=b1,31:="c1","41":="d1",<<"51">>:="e1",{["01"]}:="11"} = M4,
430    #{12:=a2,22:=b2,32:="c2","42":="d2",<<"52">>:="e2",{["02"]}:="12"} = M4,
431    #{13:=a3,23:=b3,33:="c3","43":="d3",<<"53">>:="e3",{["03"]}:="13"} = M4,
432    #{14:=a4,24:=b4,34:="c4","44":="d4",<<"54">>:="e4",{["04"]}:="14"} = M4,
433
434    #{15:=a5,25:=b5,35:="c5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M4,
435    #{16:=a6,26:=b6,36:="c6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M4,
436    #{17:=a7,27:=b7,37:="c7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M4,
437    #{18:=a8,28:=b8,38:="c8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M4,
438    #{19:=a9,29:=b9,39:="c9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M4,
439
440    #{ #{ one => small, map => key }    := "small map key 1",
441       #{ second => small, map => key } := "small map key 2",
442       #{ third => small, map => key }  := "small map key 3" } = M4,
443
444    #{ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
445          11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
446          12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
447          13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
448          14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
449
450          15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
451          16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
452          17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
453          18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
454          19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } := "large map key 1",
455
456       #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
457          11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
458          12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
459          13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
460          14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
461
462          15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
463          k16=>a6,k26=>b6,k36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
464          17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
465          18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
466          19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } := "large map key 2" } = M4,
467
468
469    #{ 15:=V1,25:=b5,35:=V2,"45":="d5",<<"55">>:=V3,{["05"]}:="15",
470       #{ one => small, map => key }    := "small map key 1",
471       #{ second => small, map => key } := V4,
472       #{ third => small, map => key }  := "small map key 3",
473       #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
474          11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
475          12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
476          13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
477          14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
478
479          15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
480          16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
481          17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
482          18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
483          19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } := V5 } = M4,
484
485    a5   = V1,
486    "c5" = V2,
487    "e5" = V3,
488    "small map key 2" = V4,
489    "large map key 1" = V5,
490
491    95 = map_size(M4),
492    95 = maps:size(M4),
493
494    % call for value
495
496    M5 = id(#{ 10=>id(a0),20=>b0,30=>id("c0"),"40"=>"d0",<<"50">>=>id("e0"),{["00"]}=>"10",
497               11=>id(a1),21=>b1,31=>id("c1"),"41"=>"d1",<<"51">>=>id("e1"),{["01"]}=>"11",
498               12=>id(a2),22=>b2,32=>id("c2"),"42"=>"d2",<<"52">>=>id("e2"),{["02"]}=>"12",
499               13=>id(a3),23=>b3,33=>id("c3"),"43"=>"d3",<<"53">>=>id("e3"),{["03"]}=>"13",
500               14=>id(a4),24=>b4,34=>id("c4"),"44"=>"d4",<<"54">>=>id("e4"),{["04"]}=>"14",
501
502               15=>id(a5),25=>b5,35=>id("c5"),"45"=>"d5",<<"55">>=>id("e5"),{["05"]}=>"15",
503               16=>id(a6),26=>b6,36=>id("c6"),"46"=>"d6",<<"56">>=>id("e6"),{["06"]}=>"16",
504               17=>id(a7),27=>b7,37=>id("c7"),"47"=>"d7",<<"57">>=>id("e7"),{["07"]}=>"17",
505               18=>id(a8),28=>b8,38=>id("c8"),"48"=>"d8",<<"58">>=>id("e8"),{["08"]}=>"18",
506               19=>id(a9),29=>b9,39=>id("c9"),"49"=>"d9",<<"59">>=>id("e9"),{["09"]}=>"19",
507
508               10.0=>fa0,20.0=>id(fb0),30.0=>id("fc0"),
509               11.0=>fa1,21.0=>id(fb1),31.0=>id("fc1"),
510               12.0=>fa2,22.0=>id(fb2),32.0=>id("fc2"),
511               13.0=>fa3,23.0=>id(fb3),33.0=>id("fc3"),
512               14.0=>fa4,24.0=>id(fb4),34.0=>id("fc4"),
513
514               15.0=>fa5,25.0=>id(fb5),35.0=>id("fc5"),
515               16.0=>fa6,26.0=>id(fb6),36.0=>id("fc6"),
516               17.0=>fa7,27.0=>id(fb7),37.0=>id("fc7"),
517               18.0=>fa8,28.0=>id(fb8),38.0=>id("fc8"),
518               19.0=>fa9,29.0=>id(fb9),39.0=>id("fc9"),
519
520               #{ one => small, map => key } => id("small map key 1"),
521               #{ second => small, map => key } => "small map key 2",
522               #{ third => small, map => key } => "small map key 3",
523
524               #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
525                  11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
526                  12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
527                  13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
528                  14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
529
530                  15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
531                  16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
532                  17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
533                  18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
534                  19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 1",
535
536               #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
537                  11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
538                  12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
539                  13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
540                  14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
541
542                  15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
543                  k16=>a6,k26=>b6,k36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
544                  17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
545                  18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
546                  19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => id("large map key 2") }),
547
548    #{10:=a0,20:=b0,30:="c0","40":="d0",<<"50">>:="e0",{["00"]}:="10"} = M5,
549    #{11:=a1,21:=b1,31:="c1","41":="d1",<<"51">>:="e1",{["01"]}:="11"} = M5,
550    #{12:=a2,22:=b2,32:="c2","42":="d2",<<"52">>:="e2",{["02"]}:="12"} = M5,
551    #{13:=a3,23:=b3,33:="c3","43":="d3",<<"53">>:="e3",{["03"]}:="13"} = M5,
552    #{14:=a4,24:=b4,34:="c4","44":="d4",<<"54">>:="e4",{["04"]}:="14"} = M5,
553
554    #{15:=a5,25:=b5,35:="c5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M5,
555    #{16:=a6,26:=b6,36:="c6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M5,
556    #{17:=a7,27:=b7,37:="c7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M5,
557    #{18:=a8,28:=b8,38:="c8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M5,
558    #{19:=a9,29:=b9,39:="c9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M5,
559
560    #{ #{ one => small, map => key }    := "small map key 1",
561       #{ second => small, map => key } := "small map key 2",
562       #{ third => small, map => key }  := "small map key 3" } = M5,
563
564    #{ #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
565          11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
566          12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
567          13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
568          14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
569
570          15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
571          16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
572          17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
573          18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
574          19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } := "large map key 1",
575
576       #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
577          11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
578          12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
579          13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
580          14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
581
582          15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
583          k16=>a6,k26=>b6,k36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
584          17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
585          18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
586          19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } := "large map key 2" } = M5,
587
588    95 = map_size(M5),
589    95 = maps:size(M5),
590
591    %% remember
592
593    #{10:=a0,20:=b0,30:="c0","40":="d0",<<"50">>:="e0",{["00"]}:="10"} = M0,
594    #{11:=a1,21:=b1,31:="c1","41":="d1",<<"51">>:="e1",{["01"]}:="11"} = M0,
595    #{12:=a2,22:=b2,32:="c2","42":="d2",<<"52">>:="e2",{["02"]}:="12"} = M0,
596    #{13:=a3,23:=b3,33:="c3","43":="d3",<<"53">>:="e3",{["03"]}:="13"} = M0,
597    #{14:=a4,24:=b4,34:="c4","44":="d4",<<"54">>:="e4",{["04"]}:="14"} = M0,
598
599    #{10:=na0,20:=nb0,30:="nc0","40":="nd0",<<"50">>:="ne0",{["00"]}:="n10"} = M1,
600    #{11:=na1,21:=nb1,31:="nc1","41":="nd1",<<"51">>:="ne1",{["01"]}:="n11"} = M1,
601    #{12:=na2,22:=nb2,32:="nc2","42":="nd2",<<"52">>:="ne2",{["02"]}:="n12"} = M1,
602    #{13:=na3,23:=nb3,33:="nc3","43":="nd3",<<"53">>:="ne3",{["03"]}:="n13"} = M1,
603    #{14:=na4,24:=nb4,34:="nc4","44":="nd4",<<"54">>:="ne4",{["04"]}:="n14"} = M1,
604
605    #{15:=a5,25:=b5,35:="c5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M1,
606    #{16:=a6,26:=b6,36:="c6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M1,
607    #{17:=a7,27:=b7,37:="c7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M1,
608    #{18:=a8,28:=b8,38:="c8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M1,
609    #{19:=a9,29:=b9,39:="c9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M1,
610
611    #{15:=a5,25:=b5,35:="c5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M2,
612    #{16:=a6,26:=b6,36:="c6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M2,
613    #{17:=a7,27:=b7,37:="c7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M2,
614    #{18:=a8,28:=b8,38:="c8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M2,
615    #{19:=a9,29:=b9,39:="c9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M2,
616
617    #{10.0:=fa0,20.0:=fb0,30.0:="fc0","40":="d0",<<"50">>:="e0",{["00"]}:="10"} = M2,
618    #{11.0:=fa1,21.0:=fb1,31.0:="fc1","41":="d1",<<"51">>:="e1",{["01"]}:="11"} = M2,
619    #{12.0:=fa2,22.0:=fb2,32.0:="fc2","42":="d2",<<"52">>:="e2",{["02"]}:="12"} = M2,
620    #{13.0:=fa3,23.0:=fb3,33.0:="fc3","43":="d3",<<"53">>:="e3",{["03"]}:="13"} = M2,
621    #{14.0:=fa4,24.0:=fb4,34.0:="fc4","44":="d4",<<"54">>:="e4",{["04"]}:="14"} = M2,
622
623    #{15:=a5,25:=b5,35:="c5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M3,
624    #{16:=a6,26:=b6,36:="c6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M3,
625    #{17:=a7,27:=b7,37:="c7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M3,
626    #{18:=a8,28:=b8,38:="c8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M3,
627    #{19:=a9,29:=b9,39:="c9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M3,
628
629    #{10.0:=fa0,20.0:=fb0,30.0:="fc0","40":="d0",<<"50">>:="e0",{["00"]}:="10"} = M3,
630    #{11.0:=fa1,21.0:=fb1,31.0:="fc1","41":="d1",<<"51">>:="e1",{["01"]}:="11"} = M3,
631    #{12.0:=fa2,22.0:=fb2,32.0:="fc2","42":="d2",<<"52">>:="e2",{["02"]}:="12"} = M3,
632    #{13.0:=fa3,23.0:=fb3,33.0:="fc3","43":="d3",<<"53">>:="e3",{["03"]}:="13"} = M3,
633    #{14.0:=fa4,24.0:=fb4,34.0:="fc4","44":="d4",<<"54">>:="e4",{["04"]}:="14"} = M3,
634
635    #{15.0:=fa5,25.0:=fb5,35.0:="fc5","45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M3,
636    #{16.0:=fa6,26.0:=fb6,36.0:="fc6","46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M3,
637    #{17.0:=fa7,27.0:=fb7,37.0:="fc7","47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M3,
638    #{18.0:=fa8,28.0:=fb8,38.0:="fc8","48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M3,
639    #{19.0:=fa9,29.0:=fb9,39.0:="fc9","49":="d9",<<"59">>:="e9",{["09"]}:="19"} = M3,
640
641    #{36893488147419103232:=big1,67108863:=big8,"45":="d5",<<"55">>:="e5",{["05"]}:="15"} = M3,
642    #{147573952589676412928:=big3,8589934592:=big6,"46":="d6",<<"56">>:="e6",{["06"]}:="16"} = M3,
643    #{4294967296:=big5,18446744073709551616:=big4,"47":="d7",<<"57">>:="e7",{["07"]}:="17"} = M3,
644    #{4294967295:=big7,73786976294838206464:=big2,"48":="d8",<<"58">>:="e8",{["08"]}:="18"} = M3,
645
646    ok.
647
648
649t_map_size(Config) when is_list(Config) ->
650    0 = map_size(id(#{})),
651    1 = map_size(id(#{a=>1})),
652    1 = map_size(id(#{a=>"wat"})),
653    2 = map_size(id(#{a=>1, b=>2})),
654    3 = map_size(id(#{a=>1, b=>2, b=>"3","33"=><<"n">>})),
655
656    true = map_is_size(#{a=>1}, 1),
657    true = map_is_size(#{a=>1, a=>2}, 1),
658    M = #{ "a" => 1, "b" => 2},
659    true  = map_is_size(M, 2),
660    false = map_is_size(M, 3),
661    true  = map_is_size(M#{ "a" => 2}, 2),
662    false = map_is_size(M#{ "c" => 2}, 2),
663
664    Ks = [build_key(fun(K) -> <<1,K:32,1>> end,I)||I<-lists:seq(1,100)],
665    ok = build_and_check_size(Ks,0,#{}),
666
667    %% try deep collisions
668    %% statistically we get another subtree at 50k -> 100k elements
669    %% Try to be nice and don't use too much memory in the testcase,
670
671    N  = 500000,
672    Is = lists:seq(1,N),
673    N  = map_size(maps:from_list([{I,I}||I<-Is])),
674    N  = map_size(maps:from_list([{<<I:32>>,I}||I<-Is])),
675    N  = map_size(maps:from_list([{integer_to_list(I),I}||I<-Is])),
676    N  = map_size(maps:from_list([{float(I),I}||I<-Is])),
677
678    %% Error cases.
679    do_badmap(fun(T) ->
680                    {'EXIT',{{badmap,T},_}} =
681                      (catch map_size(T))
682              end),
683    ok.
684
685t_map_get(Config) when is_list(Config) ->
686    %% small map
687    1    = map_get(a, id(#{a=>1})),
688    2    = map_get(b, id(#{a=>1, b=>2})),
689    "hi" = map_get("hello", id(#{a=>1, "hello"=>"hi"})),
690    "tuple hi" = map_get({1,1.0}, id(#{a=>a, {1,1.0}=>"tuple hi"})),
691
692    M0    = id(#{ k1=>"v1", <<"k2">> => <<"v3">> }),
693    "v4" = map_get(<<"k2">>, M0#{<<"k2">> => "v4"}),
694
695    %% large map
696    M1   = maps:from_list([{I,I}||I<-lists:seq(1,100)] ++
697			  [{a,1},{b,2},{"hello","hi"},{{1,1.0},"tuple hi"},
698			   {k1,"v1"},{<<"k2">>,"v3"}]),
699    1    = map_get(a, M1),
700    2    = map_get(b, M1),
701    "hi" = map_get("hello", M1),
702    "tuple hi" = map_get({1,1.0}, M1),
703    "v3" = map_get(<<"k2">>, M1),
704
705    %% error cases
706    do_badmap(fun(T) ->
707		      {'EXIT',{{badmap,T},[{erlang,map_get,_,_}|_]}} =
708			  (catch map_get(a, T))
709	      end),
710
711    {'EXIT',{{badkey,{1,1}},[{erlang,map_get,_,_}|_]}} =
712	(catch map_get({1,1}, id(#{{1,1.0}=>"tuple"}))),
713    {'EXIT',{{badkey,a},[{erlang,map_get,_,_}|_]}} = (catch map_get(a, id(#{}))),
714    {'EXIT',{{badkey,a},[{erlang,map_get,_,_}|_]}} =
715	(catch map_get(a, id(#{b=>1, c=>2}))),
716
717    %% in guards
718    M2 = id(#{a=>1}),
719    true = if map_get(a, M2) =:= 1 -> true; true -> false end,
720    false = if map_get(x, M2) =:= 1 -> true; true -> false end,
721    do_badmap(fun
722        (T) when map_get(x, T) =:= 1 -> ok;
723        (T) -> false = is_map(T)
724    end),
725    ok.
726
727t_is_map_key(Config) when is_list(Config) ->
728    %% small map
729    true = is_map_key(a, id(#{a=>1})),
730    true = is_map_key(b, id(#{a=>1, b=>2})),
731    true = is_map_key("hello", id(#{a=>1, "hello"=>"hi"})),
732    true = is_map_key({1,1.0}, id(#{a=>a, {1,1.0}=>"tuple hi"})),
733
734    M0   = id(#{ k1=>"v1", <<"k2">> => <<"v3">> }),
735    true = is_map_key(<<"k2">>, M0#{<<"k2">> => "v4"}),
736
737    %% large map
738    M1   = maps:from_list([{I,I}||I<-lists:seq(1,100)] ++
739			  [{a,1},{b,2},{"hello","hi"},{{1,1.0},"tuple hi"},
740			   {k1,"v1"},{<<"k2">>,"v3"}]),
741    true = is_map_key(a, M1),
742    true = is_map_key(b, M1),
743    true = is_map_key("hello", M1),
744    true = is_map_key({1,1.0}, M1),
745    true = is_map_key(<<"k2">>, M1),
746
747    %% error cases
748    do_badmap(fun(T) ->
749		      {'EXIT',{{badmap,T},[{erlang,is_map_key,_,_}|_]}} =
750			  (catch is_map_key(a, T))
751	      end),
752
753    false = is_map_key({1,1}, id(#{{1,1.0}=>"tuple"})),
754    false = is_map_key(a, id(#{})),
755    false = is_map_key(a, id(#{b=>1, c=>2})),
756
757    %% in guards
758    M2 = id(#{a=>1}),
759    true = if is_map_key(a, M2) -> true; true -> false end,
760    false = if is_map_key(x, M2) -> true; true -> false end,
761    do_badmap(fun
762        (T) when is_map_key(T, x) =:= 1 -> ok;
763        (T) -> false = is_map(T)
764    end),
765    ok.
766
767build_and_check_size([K|Ks],N,M0) ->
768    N = map_size(M0),
769    M1 = M0#{ K => K },
770    build_and_check_size(Ks,N + 1,M1);
771build_and_check_size([],N,M) ->
772    N = map_size(M),
773    ok.
774
775map_is_size(M,N) when map_size(M) =:= N -> true;
776map_is_size(_,_) -> false.
777
778t_is_map(Config) when is_list(Config) ->
779    true = is_map(#{}),
780    true = is_map(#{a=>1}),
781    false = is_map({a,b}),
782    false = is_map(x),
783    if is_map(#{}) -> ok end,
784    if is_map(#{b=>1}) -> ok end,
785    if not is_map([1,2,3]) -> ok end,
786    if not is_map(x) -> ok end,
787    ok.
788
789% test map updates without matching
790t_update_literals_large(Config) when is_list(Config) ->
791    Map = id(#{ 10=>id(a0),20=>b0,30=>id("c0"),"40"=>"d0",<<"50">>=>id("e0"),{["00"]}=>"10",
792                11=>id(a1),21=>b1,31=>id("c1"),"41"=>"d1",<<"51">>=>id("e1"),{["01"]}=>"11",
793                12=>id(a2),22=>b2,32=>id("c2"),"42"=>"d2",<<"52">>=>id("e2"),{["02"]}=>"12",
794                13=>id(a3),23=>b3,33=>id("c3"),"43"=>"d3",<<"53">>=>id("e3"),{["03"]}=>"13",
795                14=>id(a4),24=>b4,34=>id("c4"),"44"=>"d4",<<"54">>=>id("e4"),{["04"]}=>"14",
796
797                15=>id(a5),25=>b5,35=>id("c5"),"45"=>"d5",<<"55">>=>id("e5"),{["05"]}=>"15",
798                16=>id(a6),26=>b6,36=>id("c6"),"46"=>"d6",<<"56">>=>id("e6"),{["06"]}=>"16",
799                17=>id(a7),27=>b7,37=>id("c7"),"47"=>"d7",<<"57">>=>id("e7"),{["07"]}=>"17",
800                18=>id(a8),28=>b8,38=>id("c8"),"48"=>"d8",<<"58">>=>id("e8"),{["08"]}=>"18",
801                19=>id(a9),29=>b9,39=>id("c9"),"49"=>"d9",<<"59">>=>id("e9"),{["09"]}=>"19",
802
803                10.0=>fa0,20.0=>id(fb0),30.0=>id("fc0"),
804                11.0=>fa1,21.0=>id(fb1),31.0=>id("fc1"),
805                12.0=>fa2,22.0=>id(fb2),32.0=>id("fc2"),
806                13.0=>fa3,23.0=>id(fb3),33.0=>id("fc3"),
807                14.0=>fa4,24.0=>id(fb4),34.0=>id("fc4"),
808
809                15.0=>fa5,25.0=>id(fb5),35.0=>id("fc5"),
810                16.0=>fa6,26.0=>id(fb6),36.0=>id("fc6"),
811                17.0=>fa7,27.0=>id(fb7),37.0=>id("fc7"),
812                18.0=>fa8,28.0=>id(fb8),38.0=>id("fc8"),
813                19.0=>fa9,29.0=>id(fb9),39.0=>id("fc9"),
814
815                #{ one => small, map => key } => id("small map key 1"),
816                #{ second => small, map => key } => "small map key 2",
817                #{ third => small, map => key } => "small map key 3",
818
819                #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
820                   11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
821                   12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
822                   13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
823                   14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
824
825                   15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
826                   16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
827                   17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
828                   18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
829                   19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 1",
830
831                #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
832                   11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
833                   12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
834                   13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
835                   14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
836
837                   15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
838                   k16=>a6,k26=>b6,k36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
839                   17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
840                   18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
841                   19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => id("large map key 2") }),
842
843    #{x:="d",q:="4"} = loop_update_literals_x_q(Map, [
844		{"a","1"},{"b","2"},{"c","3"},{"d","4"}
845	]),
846    ok.
847
848t_update_literals(Config) when is_list(Config) ->
849    Map = #{x=>1,y=>2,z=>3,q=>4},
850    #{x:="d",q:="4"} = loop_update_literals_x_q(Map, [
851		{"a","1"},{"b","2"},{"c","3"},{"d","4"}
852	]),
853    ok.
854
855
856loop_update_literals_x_q(Map, []) -> Map;
857loop_update_literals_x_q(Map, [{X,Q}|Vs]) ->
858    loop_update_literals_x_q(Map#{q=>Q,x=>X},Vs).
859
860% test map updates with matching
861t_match_and_update_literals(Config) when is_list(Config) ->
862    Map = #{ x=>0,y=>"untouched",z=>"also untouched",q=>1,
863             #{ "one" => small, map => key } => "small map key 1" },
864    #{x:=16,q:=21,y:="untouched",z:="also untouched"} = loop_match_and_update_literals_x_q(Map, [
865	    {1,2},{3,4},{5,6},{7,8}
866	]),
867    M0 = id(#{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
868	    4 => number, 18446744073709551629 => wat}),
869    M1 = id(#{}),
870    M2 = M1#{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
871	4 => number, 18446744073709551629 => wat},
872    M0 = M2,
873
874    #{ 4 := another_number, int := 3 } = M2#{ 4 => another_number },
875    ok.
876
877t_match_and_update_literals_large(Config) when is_list(Config) ->
878    Map = id(#{ 10=>id(a0),20=>b0,30=>id("c0"),"40"=>"d0",<<"50">>=>id("e0"),{["00"]}=>"10",
879                11=>id(a1),21=>b1,31=>id("c1"),"41"=>"d1",<<"51">>=>id("e1"),{["01"]}=>"11",
880                12=>id(a2),22=>b2,32=>id("c2"),"42"=>"d2",<<"52">>=>id("e2"),{["02"]}=>"12",
881                13=>id(a3),23=>b3,33=>id("c3"),"43"=>"d3",<<"53">>=>id("e3"),{["03"]}=>"13",
882                14=>id(a4),24=>b4,34=>id("c4"),"44"=>"d4",<<"54">>=>id("e4"),{["04"]}=>"14",
883
884                15=>id(a5),25=>b5,35=>id("c5"),"45"=>"d5",<<"55">>=>id("e5"),{["05"]}=>"15",
885                16=>id(a6),26=>b6,36=>id("c6"),"46"=>"d6",<<"56">>=>id("e6"),{["06"]}=>"16",
886                17=>id(a7),27=>b7,37=>id("c7"),"47"=>"d7",<<"57">>=>id("e7"),{["07"]}=>"17",
887                18=>id(a8),28=>b8,38=>id("c8"),"48"=>"d8",<<"58">>=>id("e8"),{["08"]}=>"18",
888                19=>id(a9),29=>b9,39=>id("c9"),"49"=>"d9",<<"59">>=>id("e9"),{["09"]}=>"19",
889
890                10.0=>fa0,20.0=>id(fb0),30.0=>id("fc0"),
891                11.0=>fa1,21.0=>id(fb1),31.0=>id("fc1"),
892                12.0=>fa2,22.0=>id(fb2),32.0=>id("fc2"),
893                13.0=>fa3,23.0=>id(fb3),33.0=>id("fc3"),
894                14.0=>fa4,24.0=>id(fb4),34.0=>id("fc4"),
895
896                15.0=>fa5,25.0=>id(fb5),35.0=>id("fc5"),
897                16.0=>fa6,26.0=>id(fb6),36.0=>id("fc6"),
898                17.0=>fa7,27.0=>id(fb7),37.0=>id("fc7"),
899                18.0=>fa8,28.0=>id(fb8),38.0=>id("fc8"),
900                19.0=>fa9,29.0=>id(fb9),39.0=>id("fc9"),
901
902                x=>0,y=>"untouched",z=>"also untouched",q=>1,
903
904                #{ "one" => small, map => key } => id("small map key 1"),
905                #{ second => small, map => key } => "small map key 2",
906                #{ third => small, map => key } => "small map key 3",
907
908                #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
909                   11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
910                   12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
911                   13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
912                   14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
913
914                   15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
915                   16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
916                   17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
917                   18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
918                   19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 1",
919
920                #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
921                   11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
922                   12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
923                   13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
924                   14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
925
926                   15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
927                   k16=>a6,k26=>b6,k36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
928                   17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
929                   18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
930                   19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => id("large map key 2") }),
931
932    #{x:=16,q:=21,y:="untouched",z:="also untouched"} = loop_match_and_update_literals_x_q(Map, [
933	    {1,2},{3,4},{5,6},{7,8}
934	]),
935    M0 = id(Map#{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
936                  4 => number, 18446744073709551629 => wat}),
937    M1 = id(Map#{}),
938    M2 = M1#{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
939              4 => number, 18446744073709551629 => wat},
940    M0 = M2,
941
942    #{ 4 := another_number, int := 3 } = M2#{ 4 => another_number },
943    ok.
944
945
946loop_match_and_update_literals_x_q(Map, []) -> Map;
947loop_match_and_update_literals_x_q(#{ q:=Q0, x:=X0,
948                                     #{ "one" => small, map => key } := "small map key 1" } = Map, [{X,Q}|Vs]) ->
949    loop_match_and_update_literals_x_q(Map#{q=>Q0+Q,x=>X0+X},Vs).
950
951
952t_update_map_expressions(Config) when is_list(Config) ->
953    M = maps:new(),
954    #{ a := 1 } = M#{a => 1},
955
956    #{ b := 2 } = (maps:new())#{ b => 2 },
957
958    #{ a :=42, b:=42, c:=42 } = (maps:from_list([{a,1},{b,2},{c,3}]))#{ a := 42, b := 42, c := 42 },
959    #{ "a" :=1, "b":=42, "c":=42 } = (maps:from_list([{"a",1},{"b",2}]))#{ "b" := 42, "c" => 42 },
960    Ks = lists:seq($a,$z),
961    #{ "aa" := {$a,$a}, "ac":=41, "dc":=42 } =
962        (maps:from_list([{[K1,K2],{K1,K2}}|| K1 <- Ks, K2 <- Ks]))#{ "ac" := 41, "dc" => 42 },
963
964    %% Error cases.
965    do_badmap(fun(T) ->
966		      {'EXIT',{{badmap,T},_}} =
967			  (catch (T)#{a:=42,b=>2})
968	      end),
969    ok.
970
971t_update_assoc(Config) when is_list(Config) ->
972    M0 = id(#{1=>a,2=>b,3.0=>c,4=>d,5=>e}),
973
974    M1 = M0#{1=>42,2=>100,4=>[a,b,c]},
975    #{1:=42,2:=100,3.0:=c,4:=[a,b,c],5:=e} = M1,
976    #{1:=42,2:=b,4:=d,5:=e,2.0:=100,3.0:=c,4.0:=[a,b,c]} = M0#{1.0=>float,1:=42,2.0=>wrong,2.0=>100,4.0=>[a,b,c]},
977
978    M2 = M0#{3.0=>new},
979    #{1:=a,2:=b,3.0:=new,4:=d,5:=e} = M2,
980    M2 = M0#{3.0:=wrong,3.0=>new},
981
982    %% Errors cases.
983    do_badmap(fun(T) ->
984		      {'EXIT',{{badmap,T},_}} =
985			  (catch T#{nonexisting=>val})
986	      end),
987    ok.
988
989
990t_update_assoc_large(Config) when is_list(Config) ->
991    M0 = id(#{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
992               11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
993               12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
994               13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
995               14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
996
997               15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
998               16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
999               17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
1000               18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
1001               19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19",
1002
1003               10.0=>fa0,20.0=>fb0,30.0=>"fc0",
1004               11.0=>fa1,21.0=>fb1,31.0=>"fc1",
1005               12.0=>fa2,22.0=>fb2,32.0=>"fc2",
1006               13.0=>fa3,23.0=>fb3,33.0=>"fc3",
1007               14.0=>fa4,24.0=>fb4,34.0=>"fc4",
1008
1009               15.0=>fa5,25.0=>fb5,35.0=>"fc5",
1010               16.0=>fa6,26.0=>fb6,36.0=>"fc6",
1011               17.0=>fa7,27.0=>fb7,37.0=>"fc7",
1012               18.0=>fa8,28.0=>fb8,38.0=>"fc8",
1013               19.0=>fa9,29.0=>fb9,39.0=>"fc9",
1014
1015               #{ one => small, map => key } => "small map key 1",
1016               #{ second => small, map => key } => "small map key 2",
1017               #{ third => small, map => key } => "small map key 3",
1018
1019               #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
1020                  11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
1021                  12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
1022                  13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
1023                  14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
1024
1025                  15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
1026                  16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
1027                  17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
1028                  18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
1029                  19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 1",
1030
1031               #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
1032                  11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
1033                  12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
1034                  13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
1035                  14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
1036
1037                  15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
1038                  k16=>a6,k26=>b6,k36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
1039                  17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
1040                  18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
1041                  19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 2" }),
1042
1043
1044    M1 = M0#{1=>42,2=>100,4=>[a,b,c]},
1045    #{1:=42,2:=100,10.0:=fa0,4:=[a,b,c],25:=b5} = M1,
1046    #{ 10:=43, 24:=b4, 15:=a5, 35:="c5", 2.0:=100, 13.0:=fa3, 4.0:=[a,b,c]} =
1047        M0#{1.0=>float,10:=43,2.0=>wrong,2.0=>100,4.0=>[a,b,c]},
1048
1049    M2 = M0#{13.0=>new},
1050    #{10:=a0,20:=b0,13.0:=new,"40":="d0",<<"50">>:="e0"} = M2,
1051    M2 = M0#{13.0:=wrong,13.0=>new},
1052
1053    ok.
1054
1055t_update_exact(Config) when is_list(Config) ->
1056    M0 = id(#{1=>a,2=>b,3.0=>c,4=>d,5=>e}),
1057
1058    M1 = M0#{1:=42,2:=100,4:=[a,b,c]},
1059    #{1:=42,2:=100,3.0:=c,4:=[a,b,c],5:=e} = M1,
1060    M1 = M0#{1:=wrong,1=>42,2=>wrong,2:=100,4:=[a,b,c]},
1061
1062    M2 = M0#{3.0:=new},
1063    #{1:=a,2:=b,3.0:=new,4:=d,5:=e} = M2,
1064    M2 = M0#{3.0=>wrong,3.0:=new},
1065    true = M2 =/= M0#{3=>right,3.0:=new},
1066    #{ 3 := right, 3.0 := new } = M0#{3=>right,3.0:=new},
1067
1068    M3 = id(#{ 1 => val}),
1069    #{1 := update2,1.0 := new_val4} = M3#{
1070	1.0 => new_val1, 1 := update, 1=> update3,
1071	1 := update2, 1.0 := new_val2, 1.0 => new_val3,
1072	1.0 => new_val4 },
1073
1074    %% Errors cases.
1075    do_badmap(fun(T) ->
1076		      {'EXIT',{{badmap,T},_}} =
1077			  (catch T#{nonexisting=>val})
1078	      end),
1079    Empty = id(#{}),
1080    {'EXIT',{{badkey,nonexisting},_}} = (catch Empty#{nonexisting:=val}),
1081    {'EXIT',{{badkey,nonexisting},_}} = (catch M0#{nonexisting:=val}),
1082    {'EXIT',{{badkey,1.0},_}} = (catch M0#{1.0:=v,1.0=>v2}),
1083    {'EXIT',{{badkey,42},_}} = (catch M0#{42.0:=v,42:=v2}),
1084    {'EXIT',{{badkey,42.0},_}} = (catch M0#{42=>v1,42.0:=v2,42:=v3}),
1085
1086    ok.
1087
1088t_update_exact_large(Config) when is_list(Config) ->
1089    M0 = id(#{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
1090               11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
1091               12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
1092               13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
1093               14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
1094
1095               15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
1096               16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
1097               17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
1098               18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
1099               19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19",
1100
1101               10.0=>fa0,20.0=>fb0,30.0=>"fc0",
1102               11.0=>fa1,21.0=>fb1,31.0=>"fc1",
1103               12.0=>fa2,22.0=>fb2,32.0=>"fc2",
1104               13.0=>fa3,23.0=>fb3,33.0=>"fc3",
1105               14.0=>fa4,24.0=>fb4,34.0=>"fc4",
1106
1107               15.0=>fa5,25.0=>fb5,35.0=>"fc5",
1108               16.0=>fa6,26.0=>fb6,36.0=>"fc6",
1109               17.0=>fa7,27.0=>fb7,37.0=>"fc7",
1110               18.0=>fa8,28.0=>fb8,38.0=>"fc8",
1111               19.0=>fa9,29.0=>fb9,39.0=>"fc9",
1112
1113               #{ one => small, map => key } => "small map key 1",
1114               #{ second => small, map => key } => "small map key 2",
1115               #{ third => small, map => key } => "small map key 3",
1116
1117               #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
1118                  11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
1119                  12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
1120                  13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
1121                  14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
1122
1123                  15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
1124                  16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
1125                  17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
1126                  18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
1127                  19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 1",
1128
1129               #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
1130                  11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
1131                  12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
1132                  13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
1133                  14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
1134
1135                  15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
1136                  k16=>a6,k26=>b6,k36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
1137                  17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
1138                  18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
1139                  19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 2" }),
1140
1141
1142    M1 = M0#{10:=42,<<"55">>:=100,10.0:=[a,b,c]},
1143    #{ 10:=42,<<"55">>:=100,{["05"]}:="15",10.0:=[a,b,c],
1144       #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
1145          11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
1146          12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
1147          13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
1148          14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
1149
1150          15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
1151          16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
1152          17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
1153          18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
1154          19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } := "large map key 1" } = M1,
1155
1156    M1 = M0#{10:=wrong,10=>42,<<"55">>=>wrong,<<"55">>:=100,10.0:=[a,b,c]},
1157
1158    M2 = M0#{13.0:=new},
1159    #{10:=a0,20:=b0,13.0:=new} = M2,
1160    M2 = M0#{13.0=>wrong,13.0:=new},
1161
1162    %% Errors cases.
1163    {'EXIT',{{badkey,nonexisting},_}} = (catch M0#{nonexisting:=val}),
1164    {'EXIT',{{badkey,1.0},_}} = (catch M0#{1.0:=v,1.0=>v2}),
1165    {'EXIT',{{badkey,42},_}} = (catch M0#{42.0:=v,42:=v2}),
1166    {'EXIT',{{badkey,42.0},_}} = (catch M0#{42=>v1,42.0:=v2,42:=v3}),
1167
1168    ok.
1169
1170t_update_deep(Config) when is_list(Config) ->
1171    N = 250000,
1172    M0 = maps:from_list([{integer_to_list(I),a}||I<-lists:seq(1,N)]),
1173    #{ "1" := a, "10" := a, "100" := a, "1000" := a, "10000" := a } = M0,
1174
1175    M1 = M0#{ "1" := b, "10" := b, "100" := b, "1000" := b, "10000" := b },
1176    #{ "1" := a, "10" := a, "100" := a, "1000" := a, "10000" := a } = M0,
1177    #{ "1" := b, "10" := b, "100" := b, "1000" := b, "10000" := b } = M1,
1178
1179    M2 = M0#{ "1" => c, "10" => c, "100" => c, "1000" => c, "10000" => c },
1180    #{ "1" := a, "10" := a, "100" := a, "1000" := a, "10000" := a } = M0,
1181    #{ "1" := b, "10" := b, "100" := b, "1000" := b, "10000" := b } = M1,
1182    #{ "1" := c, "10" := c, "100" := c, "1000" := c, "10000" := c } = M2,
1183
1184    M3 = M2#{ "n1" => d, "n10" => d, "n100" => d, "n1000" => d, "n10000" => d },
1185    #{  "1" := a,  "10" := a,  "100" := a,  "1000" := a,  "10000" := a } = M0,
1186    #{  "1" := b,  "10" := b,  "100" := b,  "1000" := b,  "10000" := b } = M1,
1187    #{  "1" := c,  "10" := c,  "100" := c,  "1000" := c,  "10000" := c } = M2,
1188    #{  "1" := c,  "10" := c,  "100" := c,  "1000" := c,  "10000" := c } = M3,
1189    #{ "n1" := d, "n10" := d, "n100" := d, "n1000" := d, "n10000" := d } = M3,
1190    ok.
1191
1192t_guard_bifs(Config) when is_list(Config) ->
1193    true   = map_guard_head(#{a=>1}),
1194    false  = map_guard_head([]),
1195    true   = map_guard_body(#{a=>1}),
1196    false  = map_guard_body({}),
1197    true   = map_guard_pattern(#{a=>1, <<"hi">> => "hi" }),
1198    false  = map_guard_pattern("list"),
1199    ok.
1200
1201map_guard_head(M) when is_map(M) -> true;
1202map_guard_head(_) -> false.
1203
1204map_guard_body(M) -> is_map(M).
1205
1206map_guard_pattern(#{}) -> true;
1207map_guard_pattern(_)   -> false.
1208
1209t_guard_sequence(Config) when is_list(Config) ->
1210	{1, "a"} = map_guard_sequence_1(#{seq=>1,val=>id("a")}),
1211	{2, "b"} = map_guard_sequence_1(#{seq=>2,val=>id("b")}),
1212	{3, "c"} = map_guard_sequence_1(#{seq=>3,val=>id("c")}),
1213	{4, "d"} = map_guard_sequence_1(#{seq=>4,val=>id("d")}),
1214	{5, "e"} = map_guard_sequence_1(#{seq=>5,val=>id("e")}),
1215
1216	{1,M1}       = map_guard_sequence_2(M1 = id(#{a=>3})),
1217	{2,M2}       = map_guard_sequence_2(M2 = id(#{a=>4, b=>4})),
1218	{3,gg,M3}    = map_guard_sequence_2(M3 = id(#{a=>gg, b=>4})),
1219	{4,sc,sc,M4} = map_guard_sequence_2(M4 = id(#{a=>sc, b=>3, c=>sc2})),
1220	{5,kk,kk,M5} = map_guard_sequence_2(M5 = id(#{a=>kk, b=>other, c=>sc2})),
1221
1222	%% error case
1223	{'EXIT',{function_clause,_}} = (catch map_guard_sequence_1(#{seq=>6,val=>id("e")})),
1224	{'EXIT',{function_clause,_}} = (catch map_guard_sequence_2(#{b=>5})),
1225	ok.
1226
1227t_guard_sequence_large(Config) when is_list(Config) ->
1228    M0 = id(#{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00",03]}=>"10",
1229               11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01",03]}=>"11",
1230               12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02",03]}=>"12",
1231               13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03",03]}=>"13",
1232               14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04",03]}=>"14",
1233
1234               15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05",03]}=>"15",
1235               16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06",03]}=>"16",
1236               17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07",03]}=>"17",
1237               18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08",03]}=>"18",
1238               19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09",03]}=>"19",
1239
1240               10.0=>fa0,20.0=>fb0,30.0=>"fc0",
1241               11.0=>fa1,21.0=>fb1,31.0=>"fc1",
1242               12.0=>fa2,22.0=>fb2,32.0=>"fc2",
1243               13.0=>fa3,23.0=>fb3,33.0=>"fc3",
1244               14.0=>fa4,24.0=>fb4,34.0=>"fc4",
1245
1246               15.0=>fa5,25.0=>fb5,35.0=>"fc5",
1247               16.0=>fa6,26.0=>fb6,36.0=>"fc6",
1248               17.0=>fa7,27.0=>fb7,37.0=>"fc7",
1249               18.0=>fa8,28.0=>fb8,38.0=>"fc8",
1250               19.0=>fa9,29.0=>fb9,39.0=>"fc9",
1251
1252               #{ one => small, map => key } => "small map key 1",
1253               #{ second => small, map => key } => "small map key 2",
1254               #{ third => small, map => key } => "small map key 3",
1255
1256               #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
1257                  11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
1258                  12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
1259                  13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
1260                  14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
1261
1262                  15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
1263                  16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
1264                  17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
1265                  18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
1266                  19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 1",
1267
1268               #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
1269                  11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
1270                  12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
1271                  13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
1272                  14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
1273
1274                  15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
1275                  k16=>a6,k26=>b6,k36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
1276                  17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
1277                  18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
1278                  19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 2" }),
1279
1280	{1, "a"} = map_guard_sequence_1(M0#{seq=>1,val=>id("a")}),
1281	{2, "b"} = map_guard_sequence_1(M0#{seq=>2,val=>id("b")}),
1282	{3, "c"} = map_guard_sequence_1(M0#{seq=>3,val=>id("c")}),
1283	{4, "d"} = map_guard_sequence_1(M0#{seq=>4,val=>id("d")}),
1284	{5, "e"} = map_guard_sequence_1(M0#{seq=>5,val=>id("e")}),
1285
1286	{1,M1}       = map_guard_sequence_2(M1 = id(M0#{a=>3})),
1287	{2,M2}       = map_guard_sequence_2(M2 = id(M0#{a=>4, b=>4})),
1288	{3,gg,M3}    = map_guard_sequence_2(M3 = id(M0#{a=>gg, b=>4})),
1289	{4,sc,sc,M4} = map_guard_sequence_2(M4 = id(M0#{a=>sc, b=>3, c=>sc2})),
1290	{5,kk,kk,M5} = map_guard_sequence_2(M5 = id(M0#{a=>kk, b=>other, c=>sc2})),
1291
1292	{'EXIT',{function_clause,_}} = (catch map_guard_sequence_1(M0#{seq=>6,val=>id("e")})),
1293	{'EXIT',{function_clause,_}} = (catch map_guard_sequence_2(M0#{b=>5})),
1294        ok.
1295
1296
1297map_guard_sequence_1(#{seq:=1=Seq, val:=Val}) -> {Seq,Val};
1298map_guard_sequence_1(#{seq:=2=Seq, val:=Val}) -> {Seq,Val};
1299map_guard_sequence_1(#{seq:=3=Seq, val:=Val}) -> {Seq,Val};
1300map_guard_sequence_1(#{seq:=4=Seq, val:=Val}) -> {Seq,Val};
1301map_guard_sequence_1(#{seq:=5=Seq, val:=Val}) -> {Seq,Val}.
1302
1303map_guard_sequence_2(#{ a:=3 }=M) -> {1, M};
1304map_guard_sequence_2(#{ a:=4 }=M) -> {2, M};
1305map_guard_sequence_2(#{ a:=X, a:=X, b:=4 }=M) -> {3,X,M};
1306map_guard_sequence_2(#{ a:=X, a:=Y, b:=3 }=M) when X =:= Y -> {4,X,Y,M};
1307map_guard_sequence_2(#{ a:=X, a:=Y }=M) when X =:= Y -> {5,X,Y,M}.
1308
1309
1310t_guard_update(Config) when is_list(Config) ->
1311    error  = map_guard_update(#{},#{}),
1312    first  = map_guard_update(#{}, #{x=>first}),
1313    second = map_guard_update(#{y=>old}, #{x=>second,y=>old}),
1314    ok.
1315
1316t_guard_update_large(Config) when is_list(Config) ->
1317    M0 = id(#{ 70=>a0,80=>b0,90=>"c0","40"=>"d0",<<"50">>=>"e0",{["00",03]}=>"10",
1318               71=>a1,81=>b1,91=>"c1","41"=>"d1",<<"51">>=>"e1",{["01",03]}=>"11",
1319               72=>a2,82=>b2,92=>"c2","42"=>"d2",<<"52">>=>"e2",{["02",03]}=>"12",
1320               73=>a3,83=>b3,93=>"c3","43"=>"d3",<<"53">>=>"e3",{["03",03]}=>"13",
1321               74=>a4,84=>b4,94=>"c4","44"=>"d4",<<"54">>=>"e4",{["04",03]}=>"14",
1322
1323               75=>a5,85=>b5,95=>"c5","45"=>"d5",<<"55">>=>"e5",{["05",03]}=>"15",
1324               76=>a6,86=>b6,96=>"c6","46"=>"d6",<<"56">>=>"e6",{["06",03]}=>"16",
1325               77=>a7,87=>b7,97=>"c7","47"=>"d7",<<"57">>=>"e7",{["07",03]}=>"17",
1326               78=>a8,88=>b8,98=>"c8","48"=>"d8",<<"58">>=>"e8",{["08",03]}=>"18",
1327               79=>a9,89=>b9,99=>"c9","49"=>"d9",<<"59">>=>"e9",{["09",03]}=>"19",
1328
1329               70.0=>fa0,80.0=>fb0,90.0=>"fc0",
1330               71.0=>fa1,81.0=>fb1,91.0=>"fc1",
1331               72.0=>fa2,82.0=>fb2,92.0=>"fc2",
1332               73.0=>fa3,83.0=>fb3,93.0=>"fc3",
1333               74.0=>fa4,84.0=>fb4,94.0=>"fc4",
1334
1335               75.0=>fa5,85.0=>fb5,95.0=>"fc5",
1336               76.0=>fa6,86.0=>fb6,96.0=>"fc6",
1337               77.0=>fa7,87.0=>fb7,97.0=>"fc7",
1338               78.0=>fa8,88.0=>fb8,98.0=>"fc8",
1339               79.0=>fa9,89.0=>fb9,99.0=>"fc9",
1340
1341               #{ one => small, map => key } => "small map key 1",
1342               #{ second => small, map => key } => "small map key 2",
1343               #{ third => small, map => key } => "small map key 3",
1344
1345               #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
1346                  11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
1347                  12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
1348                  13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
1349                  14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
1350
1351                  15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
1352                  16=>a6,26=>b6,36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
1353                  17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
1354                  18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
1355                  19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 1",
1356
1357               #{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00"]}=>"10",
1358                  11=>a1,21=>b1,31=>"c1","41"=>"d1",<<"51">>=>"e1",{["01"]}=>"11",
1359                  12=>a2,22=>b2,32=>"c2","42"=>"d2",<<"52">>=>"e2",{["02"]}=>"12",
1360                  13=>a3,23=>b3,33=>"c3","43"=>"d3",<<"53">>=>"e3",{["03"]}=>"13",
1361                  14=>a4,24=>b4,34=>"c4","44"=>"d4",<<"54">>=>"e4",{["04"]}=>"14",
1362
1363                  15=>a5,25=>b5,35=>"c5","45"=>"d5",<<"55">>=>"e5",{["05"]}=>"15",
1364                  k16=>a6,k26=>b6,k36=>"c6","46"=>"d6",<<"56">>=>"e6",{["06"]}=>"16",
1365                  17=>a7,27=>b7,37=>"c7","47"=>"d7",<<"57">>=>"e7",{["07"]}=>"17",
1366                  18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
1367                  19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 2" }),
1368
1369
1370    error  = map_guard_update(M0#{},M0#{}),
1371    first  = map_guard_update(M0#{},M0#{x=>first}),
1372    second = map_guard_update(M0#{y=>old}, M0#{x=>second,y=>old}),
1373    ok.
1374
1375
1376map_guard_update(M1, M2) when M1#{x=>first}  =:= M2 -> first;
1377map_guard_update(M1, M2) when M1#{x=>second} =:= M2 -> second;
1378map_guard_update(_, _) -> error.
1379
1380t_guard_receive(Config) when is_list(Config) ->
1381    M0  = #{ id => 0 },
1382    Pid = spawn_link(fun() -> guard_receive_loop() end),
1383    Big = 36893488147419103229,
1384    B1  = <<"some text">>,
1385    B2  = <<"was appended">>,
1386    B3  = <<B1/binary, B2/binary>>,
1387
1388    #{id:=1, res:=Big} = M1 = call(Pid, M0#{op=>sub,in=>{1 bsl 65, 3}}),
1389    #{id:=2, res:=26}  = M2 = call(Pid, M1#{op=>idiv,in=>{53,2}}),
1390    #{id:=3, res:=832} = M3 = call(Pid, M2#{op=>imul,in=>{26,32}}),
1391    #{id:=4, res:=4}   = M4 = call(Pid, M3#{op=>add,in=>{1,3}}),
1392    #{id:=5, res:=Big} = M5 = call(Pid, M4#{op=>sub,in=>{1 bsl 65, 3}}),
1393    #{id:=6, res:=B3}  = M6 = call(Pid, M5#{op=>"append",in=>{B1,B2}}),
1394    #{id:=7, res:=4}   = _  = call(Pid, M6#{op=>add,in=>{1,3}}),
1395
1396
1397    %% update old maps and check id update
1398    #{id:=2, res:=B3} = call(Pid, M1#{op=>"append",in=>{B1,B2}}),
1399    #{id:=5, res:=99} = call(Pid, M4#{op=>add,in=>{33, 66}}),
1400
1401    %% cleanup
1402    done = call(Pid, done),
1403    ok.
1404
1405-define(t_guard_receive_large_procs, 1500).
1406
1407t_guard_receive_large(Config) when is_list(Config) ->
1408    M = lists:foldl(fun(_,#{procs := Ps } = M) ->
1409                            M#{ procs := Ps#{ spawn_link(fun() -> grecv_loop() end) => 0 }}
1410                    end, #{procs => #{}, done => 0}, lists:seq(1,?t_guard_receive_large_procs)),
1411    lists:foreach(fun(Pid) ->
1412                          Pid ! {self(), hello}
1413                  end, maps:keys(maps:get(procs,M))),
1414    ok = guard_receive_large_loop(M),
1415    ok.
1416
1417guard_receive_large_loop(#{done := ?t_guard_receive_large_procs}) ->
1418    ok;
1419guard_receive_large_loop(M) ->
1420    receive
1421        #{pid := Pid, msg := hello} ->
1422            case M of
1423                #{done := Count, procs := #{Pid := 150}} ->
1424                    Pid ! {self(), done},
1425                    guard_receive_large_loop(M#{done := Count + 1});
1426                #{procs := #{Pid := Count} = Ps} ->
1427                    Pid ! {self(), hello},
1428                    guard_receive_large_loop(M#{procs := Ps#{Pid := Count + 1}})
1429            end
1430    end.
1431
1432grecv_loop() ->
1433    receive
1434        {_, done} ->
1435            ok;
1436        {Pid, hello} ->
1437            Pid ! #{pid=>self(), msg=>hello},
1438            grecv_loop()
1439    end.
1440
1441call(Pid, M) ->
1442    Pid ! {self(), M}, receive {Pid, Res} -> Res end.
1443
1444guard_receive_loop() ->
1445    receive
1446	{Pid, #{ id:=Id, op:="append", in:={X,Y}}=M} when is_binary(X), is_binary(Y) ->
1447	    Pid ! {self(), M#{ id=>Id+1, res=><<X/binary,Y/binary>>}},
1448	    guard_receive_loop();
1449	{Pid, #{ id:=Id, op:=add, in:={X,Y}}} ->
1450	    Pid ! {self(), #{ id=>Id+1, res=>X+Y}},
1451	    guard_receive_loop();
1452	{Pid, #{ id:=Id, op:=sub,  in:={X,Y}}=M} ->
1453	    Pid ! {self(), M#{ id=>Id+1, res=>X-Y}},
1454	    guard_receive_loop();
1455	{Pid, #{ id:=Id, op:=idiv, in:={X,Y}}=M} ->
1456	    Pid ! {self(), M#{ id=>Id+1, res=>X div Y}},
1457	    guard_receive_loop();
1458	{Pid, #{ id:=Id, op:=imul, in:={X,Y}}=M} ->
1459	    Pid ! {self(), M#{ id=>Id+1, res=>X * Y}},
1460	    guard_receive_loop();
1461	{Pid, done} ->
1462	    Pid ! {self(), done};
1463	{Pid, Other} ->
1464	    Pid ! {error, Other},
1465	    guard_receive_loop()
1466    end.
1467
1468
1469t_list_comprehension(Config) when is_list(Config) ->
1470    [#{k:=1},#{k:=2},#{k:=3}] = [#{k=>I} || I <- [1,2,3]],
1471
1472    Ks = lists:seq($a,$z),
1473    Ms = [#{[K1,K2]=>{K1,K2}} || K1 <- Ks, K2 <- Ks],
1474    [#{"aa" := {$a,$a}},#{"ab":={$a,$b}}|_] = Ms,
1475    [#{"zz" := {$z,$z}},#{"zy":={$z,$y}}|_] = lists:reverse(Ms),
1476    ok.
1477
1478t_guard_fun(Config) when is_list(Config) ->
1479    F1 = fun
1480	    (#{s:=v,v:=V})     -> {v,V};
1481	    (#{s:=t,v:={V,V}}) -> {t,V};
1482	    (#{s:=l,v:=[V,V]}) -> {l,V}
1483    end,
1484
1485    F2 = fun
1486	    (#{s:=T,v:={V,V}}) -> {T,V};
1487	    (#{s:=T,v:=[V,V]}) -> {T,V};
1488	    (#{s:=T,v:=V})     -> {T,V}
1489    end,
1490    V = <<"hi">>,
1491
1492    {v,V} = F1(#{s=>v,v=>V}),
1493    {t,V} = F1(#{s=>t,v=>{V,V}}),
1494    {l,V} = F1(#{s=>l,v=>[V,V]}),
1495
1496    {v,V} = F2(#{s=>v,v=>V}),
1497    {t,V} = F2(#{s=>t,v=>{V,V}}),
1498    {l,V} = F2(#{s=>l,v=>[V,V]}),
1499
1500    %% error case
1501    {'EXIT', {function_clause,[{?MODULE,_,[#{s:=none,v:=none}],_}|_]}} = (catch F1(#{s=>none,v=>none})),
1502    ok.
1503
1504
1505t_map_sort_literals(Config) when is_list(Config) ->
1506    % test relation
1507
1508    %% size order
1509    true  = #{ a => 1, b => 2} < id(#{ a => 1, b => 1, c => 1}),
1510    true  = #{ b => 1, a => 1} < id(#{ c => 1, a => 1, b => 1}),
1511    false = #{ c => 1, b => 1, a => 1} < id(#{ c => 1, a => 1}),
1512
1513    %% key order
1514    true  = #{ a => 1 } < id(#{ b => 1}),
1515    false = #{ b => 1 } < id(#{ a => 1}),
1516    true  = #{ a => 1, b => 1, c => 1 } < id(#{ b => 1, c => 1, d => 1}),
1517    true  = #{ b => 1, c => 1, d => 1 } > id(#{ a => 1, b => 1, c => 1}),
1518    true  = #{ c => 1, b => 1, a => 1 } < id(#{ b => 1, c => 1, d => 1}),
1519    true  = #{ "a" => 1 } < id(#{ <<"a">> => 1}),
1520    false = #{ <<"a">> => 1 } < id(#{ "a" => 1}),
1521    true  = #{ 1 => 1 } < id(#{ 1.0 => 1}),
1522    false = #{ 1.0 => 1 } < id(#{ 1 => 1}),
1523
1524    %% value order
1525    true  = #{ a => 1 } < id(#{ a => 2}),
1526    false = #{ a => 2 } < id(#{ a => 1}),
1527    false = #{ a => 2, b => 1 } < id(#{ a => 1, b => 3}),
1528    true  = #{ a => 1, b => 1 } < id(#{ a => 1, b => 3}),
1529    false = #{ a => 1 } < id(#{ a => 1.0}),
1530    false = #{ a => 1.0 } < id(#{ a => 1}),
1531
1532    true  = #{ "a" => "hi", b => 134 } == id(#{ b => 134,"a" => "hi"}),
1533
1534    %% large maps
1535
1536    M = maps:from_list([{I,I}||I <- lists:seq(1,500)]),
1537
1538    %% size order
1539    true  = M#{ a => 1, b => 2} < id(M#{ a => 1, b => 1, c => 1}),
1540    true  = M#{ b => 1, a => 1} < id(M#{ c => 1, a => 1, b => 1}),
1541    false = M#{ c => 1, b => 1, a => 1} < id(M#{ c => 1, a => 1}),
1542
1543    %% key order
1544    true  = M#{ a => 1 } < id(M#{ b => 1}),
1545    false = M#{ b => 1 } < id(M#{ a => 1}),
1546    true  = M#{ a => 1, b => 1, c => 1 } < id(M#{ b => 1, c => 1, d => 1}),
1547    true  = M#{ b => 1, c => 1, d => 1 } > id(M#{ a => 1, b => 1, c => 1}),
1548    true  = M#{ c => 1, b => 1, a => 1 } < id(M#{ b => 1, c => 1, d => 1}),
1549    true  = M#{ "a" => 1 } < id(M#{ <<"a">> => 1}),
1550    false = M#{ <<"a">> => 1 } < id(#{ "a" => 1}),
1551    true  = M#{ 1 => 1 } < id(maps:remove(1,M#{ 1.0 => 1})),
1552    false = M#{ 1.0 => 1 } < id(M#{ 1 => 1}),
1553
1554    %% value order
1555    true  = M#{ a => 1 } < id(M#{ a => 2}),
1556    false = M#{ a => 2 } < id(M#{ a => 1}),
1557    false = M#{ a => 2, b => 1 } < id(M#{ a => 1, b => 3}),
1558    true  = M#{ a => 1, b => 1 } < id(M#{ a => 1, b => 3}),
1559    false = M#{ a => 1 } < id(M#{ a => 1.0}),
1560    false = M#{ a => 1.0 } < id(M#{ a => 1}),
1561
1562    true  = M#{ "a" => "hi", b => 134 } == id(M#{ b => 134,"a" => "hi"}),
1563
1564    %% lists:sort
1565
1566    SortVs = [#{"a"=>1},#{a=>2},#{1=>3},#{<<"a">>=>4}],
1567    [#{1:=ok},#{a:=ok},#{"a":=ok},#{<<"a">>:=ok}] = lists:sort([#{"a"=>ok},#{a=>ok},#{1=>ok},#{<<"a">>=>ok}]),
1568    [#{1:=3},#{a:=2},#{"a":=1},#{<<"a">>:=4}] = lists:sort(SortVs),
1569    [#{1:=3},#{a:=2},#{"a":=1},#{<<"a">>:=4}] = lists:sort(lists:reverse(SortVs)),
1570    ok.
1571
1572t_map_equal(Config) when is_list(Config) ->
1573    true  = id(#{}) =:= id(#{}),
1574    false = id(#{}) =:= id(#{a=>1}),
1575    false = id(#{a=>1}) =:= id(#{}),
1576    true  = id(#{ "a" => "hi", b => 134 }) =:= id(#{ b => 134,"a" => "hi"}),
1577
1578    false = id(#{ a => 1 }) =:= id(#{ a => 2}),
1579    false = id(#{ a => 2 }) =:= id(#{ a => 1}),
1580    false = id(#{ a => 2, b => 1 }) =:= id(#{ a => 1, b => 3}),
1581    false = id(#{ a => 1, b => 1 }) =:= id(#{ a => 1, b => 3}),
1582
1583    true = id(#{ a => 1 }) =:= id(#{ a => 1}),
1584    true = id(#{ "a" => 2 }) =:= id(#{ "a" => 2}),
1585    true = id(#{ "a" => 2, b => 3 }) =:= id(#{ "a" => 2, b => 3}),
1586    true = id(#{ a => 1, b => 3, c => <<"wat">> }) =:= id(#{ a => 1, b => 3, c=><<"wat">>}),
1587    ok.
1588
1589
1590t_map_compare(Config) when is_list(Config) ->
1591    rand:seed(exsplus),
1592    io:format("seed = ~p\n", [rand:export_seed()]),
1593    repeat(100, fun(_) -> float_int_compare() end, []),
1594    repeat(100, fun(_) -> recursive_compare() end, []),
1595    ok.
1596
1597float_int_compare() ->
1598    Terms = numeric_keys(3),
1599    %%io:format("Keys to use: ~p\n", [Terms]),
1600    Pairs = lists:map(fun(K) -> list_to_tuple([{K,V} || V <- Terms]) end, Terms),
1601    lists:foreach(fun(Size) ->
1602			  MapGen = fun() -> map_gen(list_to_tuple(Pairs), Size) end,
1603			  repeat(100, fun do_compare/1, [MapGen, MapGen])
1604		  end,
1605		  lists:seq(1,length(Terms))),
1606    ok.
1607
1608numeric_keys(N) ->
1609    lists:foldl(fun(_,Acc) ->
1610			Int = rand:uniform(N*4) - N*2,
1611			Float = float(Int),
1612			[Int, Float, Float * 0.99, Float * 1.01 | Acc]
1613		end,
1614		[],
1615		lists:seq(1,N)).
1616
1617
1618repeat(0, _, _) ->
1619    ok;
1620repeat(N, Fun, Arg) ->
1621    Fun(Arg),
1622    repeat(N-1, Fun, Arg).
1623
1624copy_term(T) ->
1625    Papa = self(),
1626    P = spawn_link(fun() -> receive Msg -> Papa ! Msg end end),
1627    P ! T,
1628    receive R -> R end.
1629
1630do_compare([Gen1, Gen2]) ->
1631    M1 = Gen1(),
1632    M2 = Gen2(),
1633    %%io:format("Maps to compare: ~p AND ~p\n", [M1, M2]),
1634    C = (M1 < M2),
1635    Erlang = maps_lessthan(M1, M2),
1636    C = Erlang,
1637    ?CHECK(M1==M1, M1),
1638
1639    %% Change one key from int to float (or vice versa) and check compare
1640    ML1 = maps:to_list(M1),
1641    {K1,V1} = lists:nth(rand:uniform(length(ML1)), ML1),
1642    case K1 of
1643	I when is_integer(I) ->
1644	    case maps:find(float(I),M1) of
1645		error ->
1646		    M1f = maps:remove(I, maps:put(float(I), V1, M1)),
1647		    ?CHECK(M1f > M1, [M1f, M1]);
1648		_ -> ok
1649	    end;
1650
1651	F when is_float(F), round(F) == F ->
1652	    case maps:find(round(F),M1) of
1653		error ->
1654		    M1i = maps:remove(F, maps:put(round(F), V1, M1)),
1655		    ?CHECK(M1i < M1, [M1i, M1]);
1656		_ -> ok
1657	    end;
1658
1659	_ -> ok   % skip floats with decimals
1660    end,
1661
1662    ?CHECK(M2 == M2, [M2]).
1663
1664
1665maps_lessthan(M1, M2) ->
1666  case {maps:size(M1),maps:size(M2)} of
1667      {_S,_S} ->
1668	  {K1,V1} = lists:unzip(term_sort(maps:to_list(M1))),
1669	  {K2,V2} = lists:unzip(term_sort(maps:to_list(M2))),
1670
1671	  case erts_internal:cmp_term(K1,K2) of
1672	      -1 -> true;
1673	      0 -> (V1 < V2);
1674	      1 -> false
1675	  end;
1676
1677      {S1, S2} ->
1678	  S1 < S2
1679  end.
1680
1681term_sort(L) ->
1682    lists:sort(fun(A,B) -> erts_internal:cmp_term(A,B) =< 0 end,
1683	       L).
1684
1685
1686cmp(T1, T2, Exact) when is_tuple(T1) and is_tuple(T2) ->
1687    case {size(T1),size(T2)} of
1688	{_S,_S} -> cmp(tuple_to_list(T1), tuple_to_list(T2), Exact);
1689	{S1,S2} when S1 < S2 -> -1;
1690	{S1,S2} when S1 > S2 -> 1
1691    end;
1692
1693cmp([H1|T1], [H2|T2], Exact) ->
1694    case cmp(H1,H2, Exact) of
1695	0 -> cmp(T1,T2, Exact);
1696	C -> C
1697    end;
1698
1699cmp(M1, M2, Exact) when is_map(M1) andalso is_map(M2) ->
1700    cmp_maps(M1,M2,Exact);
1701cmp(M1, M2, Exact) ->
1702    cmp_others(M1, M2, Exact).
1703
1704cmp_maps(M1, M2, Exact) ->
1705    case {maps:size(M1),maps:size(M2)} of
1706	{_S,_S} ->
1707	    {K1,V1} = lists:unzip(term_sort(maps:to_list(M1))),
1708	    {K2,V2} = lists:unzip(term_sort(maps:to_list(M2))),
1709
1710	    case cmp(K1, K2, true) of
1711		0 -> cmp(V1, V2, Exact);
1712		C -> C
1713	    end;
1714
1715	{S1,S2} when S1 < S2 -> -1;
1716	{S1,S2} when S1 > S2 -> 1
1717    end.
1718
1719cmp_others(I, F, true) when is_integer(I), is_float(F) ->
1720    -1;
1721cmp_others(F, I, true) when is_float(F), is_integer(I) ->
1722    1;
1723cmp_others(T1, T2, _) ->
1724    case {T1<T2, T1==T2} of
1725	{true,false} -> -1;
1726	{false,true} -> 0;
1727	{false,false} -> 1
1728    end.
1729
1730map_gen(Pairs, Size) ->
1731    {_,L} = lists:foldl(fun(_, {Keys, Acc}) ->
1732				KI = rand:uniform(size(Keys)),
1733				K = element(KI,Keys),
1734				KV = element(rand:uniform(size(K)), K),
1735				{erlang:delete_element(KI,Keys), [KV | Acc]}
1736			end,
1737			{Pairs, []},
1738			lists:seq(1,Size)),
1739
1740    maps:from_list(L).
1741
1742
1743recursive_compare() ->
1744    Leafs = {atom, 17, 16.9, 17.1, [], self(), spawn(fun() -> ok end), make_ref(), make_ref()},
1745    {A, B} = term_gen_recursive(Leafs, 0, 0),
1746    %%io:format("Recursive term A = ~p\n", [A]),
1747    %%io:format("Recursive term B = ~p\n", [B]),
1748
1749    ?CHECK({true,false} =:=  case do_cmp(A, B, false) of
1750				 -1 -> {A<B, A>=B};
1751				 0 -> {A==B, A/=B};
1752				 1 -> {A>B, A=<B}
1753			     end,
1754	   {A,B}),
1755    A2 = copy_term(A),
1756    ?CHECK(A == A2, {A,A2}),
1757    ?CHECK(0 =:= cmp(A, A2, false), {A,A2}),
1758
1759    B2 = copy_term(B),
1760    ?CHECK(B == B2, {B,B2}),
1761    ?CHECK(0 =:= cmp(B, B2, false), {B,B2}),
1762    ok.
1763
1764do_cmp(A, B, Exact) ->
1765    C = cmp(A, B, Exact),
1766    C.
1767
1768%% Generate two terms {A,B} that may only differ
1769%% at float vs integer types.
1770term_gen_recursive(Leafs, Flags, Depth) ->
1771    MaxDepth = 10,
1772    Rnd = case {Flags, Depth} of
1773	      {_, MaxDepth} -> % Only leafs
1774		  rand:uniform(size(Leafs)) + 3;
1775	      {0, 0} ->        % Only containers
1776		  rand:uniform(3);
1777	      {0,_} ->         % Anything
1778		  rand:uniform(size(Leafs)+3)
1779	  end,
1780    case Rnd of
1781	1 -> % Make map
1782	    Size = rand:uniform(size(Leafs)),
1783	    lists:foldl(fun(_, {Acc1,Acc2}) ->
1784				{K1,K2} = term_gen_recursive(Leafs, Flags,
1785							     Depth+1),
1786				{V1,V2} = term_gen_recursive(Leafs, Flags, Depth+1),
1787				{maps:put(K1,V1, Acc1), maps:put(K2,V2, Acc2)}
1788			end,
1789			{maps:new(), maps:new()},
1790			lists:seq(1,Size));
1791	2 -> % Make cons
1792	    {Car1,Car2} = term_gen_recursive(Leafs, Flags, Depth+1),
1793	    {Cdr1,Cdr2} = term_gen_recursive(Leafs, Flags, Depth+1),
1794	    {[Car1 | Cdr1], [Car2 | Cdr2]};
1795	3 -> % Make tuple
1796	    Size = rand:uniform(size(Leafs)),
1797	    L = lists:map(fun(_) -> term_gen_recursive(Leafs, Flags, Depth+1) end,
1798			  lists:seq(1,Size)),
1799	    {L1, L2} = lists:unzip(L),
1800	    {list_to_tuple(L1), list_to_tuple(L2)};
1801
1802	N -> % Make leaf
1803	    case element(N-3, Leafs) of
1804		I when is_integer(I) ->
1805		    case rand:uniform(4) of
1806			1 -> {I, float(I)};
1807			2 -> {float(I), I};
1808			_ -> {I,I}
1809		    end;
1810		T -> {T,T}
1811	    end
1812    end.
1813
1814
1815%% BIFs
1816t_bif_map_get(Config) when is_list(Config) ->
1817    %% small map
1818    1    = maps:get(a, #{ a=> 1}),
1819    2    = maps:get(b, #{ a=> 1, b => 2}),
1820    "hi" = maps:get("hello", #{ a=>1, "hello" => "hi"}),
1821    "tuple hi" = maps:get({1,1.0}, #{ a=>a, {1,1.0} => "tuple hi"}),
1822
1823    M0    = id(#{ k1=>"v1", <<"k2">> => <<"v3">> }),
1824    "v4" = maps:get(<<"k2">>, M0#{<<"k2">> => "v4"}),
1825
1826    %% large map
1827    M1   = maps:from_list([{I,I}||I<-lists:seq(1,100)] ++
1828			  [{a,1},{b,2},{"hello","hi"},{{1,1.0},"tuple hi"},
1829			   {k1,"v1"},{<<"k2">>,"v3"}]),
1830    1    = maps:get(a, M1),
1831    2    = maps:get(b, M1),
1832    "hi" = maps:get("hello", M1),
1833    "tuple hi" = maps:get({1,1.0}, M1),
1834    "v3" = maps:get(<<"k2">>, M1),
1835
1836    %% error cases
1837    do_badmap(fun(T) ->
1838		      {'EXIT',{{badmap,T},[{maps,get,_,_}|_]}} =
1839			  (catch maps:get(a, T))
1840	      end),
1841
1842    {'EXIT',{{badkey,{1,1}},[{maps,get,_,_}|_]}} =
1843	(catch maps:get({1,1}, #{{1,1.0} => "tuple"})),
1844    {'EXIT',{{badkey,a},[{maps,get,_,_}|_]}} = (catch maps:get(a, #{})),
1845    {'EXIT',{{badkey,a},[{maps,get,_,_}|_]}} =
1846	(catch maps:get(a, #{b=>1, c=>2})),
1847    ok.
1848
1849t_bif_map_find(Config) when is_list(Config) ->
1850    %% small map
1851    {ok, 1}     = maps:find(a, #{ a=> 1}),
1852    {ok, 2}     = maps:find(b, #{ a=> 1, b => 2}),
1853    {ok, "int"} = maps:find(1, #{ 1   => "int"}),
1854    {ok, "float"} = maps:find(1.0, #{ 1.0=> "float"}),
1855
1856    {ok, "hi"} = maps:find("hello", #{ a=>1, "hello" => "hi"}),
1857    {ok, "tuple hi"} = maps:find({1,1.0}, #{ a=>a, {1,1.0} => "tuple hi"}),
1858
1859    M0 = id(#{ k1=>"v1", <<"k2">> => <<"v3">> }),
1860    {ok, "v4"} = maps:find(<<"k2">>, M0#{ <<"k2">> => "v4" }),
1861
1862    %% large map
1863    M1   = maps:from_list([{I,I}||I<-lists:seq(1,100)] ++
1864			  [{a,1},{b,2},{"hello","hi"},{{1,1.0},"tuple hi"},
1865			   {k1,"v1"},{<<"k2">>,"v3"}]),
1866    {ok, 1}    = maps:find(a, M1),
1867    {ok, 2}    = maps:find(b, M1),
1868    {ok, "hi"} = maps:find("hello", M1),
1869    {ok, "tuple hi"} = maps:find({1,1.0}, M1),
1870    {ok, "v3"} = maps:find(<<"k2">>, M1),
1871
1872    %% error case
1873    error = maps:find(a,#{}),
1874    error = maps:find(a,#{b=>1, c=>2}),
1875    error = maps:find(1.0, #{ 1 => "int"}),
1876    error = maps:find(1, #{ 1.0  => "float"}),
1877    error = maps:find({1.0,1}, #{ a=>a, {1,1.0} => "tuple hi"}), % reverse types in tuple key
1878
1879    do_badmap(fun(T) ->
1880		      {'EXIT',{{badmap,T},[{maps,find,_,_}|_]}} =
1881			  (catch maps:find(a, T))
1882	      end),
1883    ok.
1884
1885
1886t_bif_map_is_key(Config) when is_list(Config) ->
1887    M1 = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>, 4 => number},
1888
1889    true  = maps:is_key("hi", M1),
1890    true  = maps:is_key(int, M1),
1891    true  = maps:is_key(<<"key">>, M1),
1892    true  = maps:is_key(4, M1),
1893
1894    false = maps:is_key(5, M1),
1895    false = maps:is_key(<<"key2">>, M1),
1896    false = maps:is_key("h", M1),
1897    false = maps:is_key("hello", M1),
1898    false = maps:is_key(atom, M1),
1899    false = maps:is_key(any, id(#{})),
1900
1901    false = maps:is_key("hi", maps:remove("hi", M1)),
1902    true  = maps:is_key("hi", M1),
1903    true  = maps:is_key(1, maps:put(1, "number", M1)),
1904    false = maps:is_key(1.0, maps:put(1, "number", M1)),
1905
1906    %% error case
1907    do_badmap(fun(T) ->
1908		      {'EXIT',{{badmap,T},[{maps,is_key,_,_}|_]}} =
1909			  (catch maps:is_key(a, T))
1910	      end),
1911    ok.
1912
1913t_bif_map_keys(Config) when is_list(Config) ->
1914    [] = maps:keys(#{}),
1915
1916    [1,2,3,4,5] = lists:sort(maps:keys(#{ 1 => a, 2 => b, 3 => c, 4 => d, 5 => e})),
1917    [1,2,3,4,5] = lists:sort(maps:keys(#{ 4 => d, 5 => e, 1 => a, 2 => b, 3 => c})),
1918
1919    % values in key order: [4,int,"hi",<<"key">>]
1920    M1 = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>, 4 => number},
1921    [4,int,"hi",<<"key">>] = lists:sort(maps:keys(M1)),
1922
1923    %% error case
1924    do_badmap(fun(T) ->
1925		      {'EXIT',{{badmap,T},[{maps,keys,_,_}|_]}} =
1926			  (catch maps:keys(T))
1927	      end),
1928    ok.
1929
1930t_bif_map_new(Config) when is_list(Config) ->
1931    #{} = maps:new(),
1932    0   = erlang:map_size(maps:new()),
1933    ok.
1934
1935t_bif_map_merge(Config) when is_list(Config) ->
1936    0   = erlang:map_size(maps:merge(#{},#{})),
1937
1938    M0 = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
1939	4 => number, 18446744073709551629 => wat},
1940
1941    #{ "hi" := "hello", int := 3, <<"key">> := <<"value">>,
1942	4 := number, 18446744073709551629 := wat} = maps:merge(#{}, M0),
1943
1944    #{ "hi" := "hello", int := 3, <<"key">> := <<"value">>,
1945	4 := number, 18446744073709551629 := wat} = maps:merge(M0, #{}),
1946
1947    M1 = #{ "hi" => "hello again", float => 3.3, {1,2} => "tuple", 4 => integer },
1948
1949    #{4 := number, 18446744073709551629 := wat, float := 3.3, int := 3,
1950	{1,2} := "tuple", "hi" := "hello", <<"key">> := <<"value">>} = maps:merge(M1,M0),
1951
1952    #{4 := integer, 18446744073709551629 := wat, float := 3.3, int := 3,
1953	{1,2} := "tuple", "hi" := "hello again", <<"key">> := <<"value">>} = maps:merge(M0,M1),
1954
1955    %% try deep collisions
1956    N  = 150000,
1957    Is = lists:seq(1,N),
1958    M2 = maps:from_list([{I,I}||I<-Is]),
1959    150000 = maps:size(M2),
1960    M3 = maps:from_list([{<<I:32>>,I}||I<-Is]),
1961    150000 = maps:size(M3),
1962    M4 = maps:merge(M2,M3),
1963    300000 = maps:size(M4),
1964    M5 = maps:from_list([{integer_to_list(I),I}||I<-Is]),
1965    150000 = maps:size(M5),
1966    M6 = maps:merge(M4,M5),
1967    450000 = maps:size(M6),
1968    M7 = maps:from_list([{float(I),I}||I<-Is]),
1969    150000 = maps:size(M7),
1970    M8 = maps:merge(M7,M6),
1971    600000 = maps:size(M8),
1972
1973    #{      1 := 1,           "1" := 1,           <<1:32>> := 1      } = M8,
1974    #{     10 := 10,         "10" := 10,         <<10:32>> := 10     } = M8,
1975    #{    100 := 100,       "100" := 100,       <<100:32>> := 100    } = M8,
1976    #{   1000 := 1000,     "1000" := 1000,     <<1000:32>> := 1000   } = M8,
1977    #{  10000 := 10000,   "10000" := 10000,   <<10000:32>> := 10000  } = M8,
1978    #{ 100000 := 100000, "100000" := 100000, <<100000:32>> := 100000 } = M8,
1979
1980    %% overlapping
1981    M8 = maps:merge(M2,M8),
1982    M8 = maps:merge(M3,M8),
1983    M8 = maps:merge(M4,M8),
1984    M8 = maps:merge(M5,M8),
1985    M8 = maps:merge(M6,M8),
1986    M8 = maps:merge(M7,M8),
1987    M8 = maps:merge(M8,M8),
1988
1989    %% maps:merge/2 and mixed
1990
1991    Ks1 = [764492191,2361333849], %% deep collision
1992    Ks2 = lists:seq(1,33),
1993    M9  = maps:from_list([{K,K}||K <- Ks1]),
1994    M10 = maps:from_list([{K,K}||K <- Ks2]),
1995    M11 = maps:merge(M9,M10),
1996    ok = check_keys_exist(Ks1 ++ Ks2, M11),
1997
1998    %% error case
1999    do_badmap(fun(T) ->
2000		      {'EXIT',{{badmap,T},[{maps,merge,_,_}|_]}} =
2001			  (catch maps:merge(#{}, T)),
2002		      {'EXIT',{{badmap,T},[{maps,merge,_,_}|_]}} =
2003			  (catch maps:merge(T, #{})),
2004		      {'EXIT',{{badmap,T},[{maps,merge,_,_}|_]}} =
2005			  (catch maps:merge(T, T))
2006	      end),
2007    ok.
2008
2009
2010t_bif_map_put(Config) when is_list(Config) ->
2011    M0 = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
2012	4 => number, 18446744073709551629 => wat},
2013
2014    M1 = #{ "hi" := "hello"} = maps:put("hi", "hello", #{}),
2015
2016    true = is_members(["hi"],maps:keys(M1)),
2017    true = is_members(["hello"],maps:values(M1)),
2018
2019    M2 = #{ int := 3 } = maps:put(int, 3, M1),
2020
2021    true = is_members([int,"hi"],maps:keys(M2)),
2022    true = is_members([3,"hello"],maps:values(M2)),
2023
2024    M3 = #{ <<"key">> := <<"value">> } = maps:put(<<"key">>, <<"value">>, M2),
2025
2026    true = is_members([int,"hi",<<"key">>],maps:keys(M3)),
2027    true = is_members([3,"hello",<<"value">>],maps:values(M3)),
2028
2029    M4 = #{ 18446744073709551629 := wat } = maps:put(18446744073709551629, wat, M3),
2030
2031    true = is_members([18446744073709551629,int,"hi",<<"key">>],maps:keys(M4)),
2032    true = is_members([wat,3,"hello",<<"value">>],maps:values(M4)),
2033
2034    M0 = #{ 4 := number } = M5 = maps:put(4, number, M4),
2035
2036    true = is_members([4,18446744073709551629,int,"hi",<<"key">>],maps:keys(M5)),
2037    true = is_members([number,wat,3,"hello",<<"value">>],maps:values(M5)),
2038
2039    M6 = #{ <<"key">> := <<"other value">> } = maps:put(<<"key">>, <<"other value">>, M5),
2040
2041    true = is_members([4,18446744073709551629,int,"hi",<<"key">>],maps:keys(M6)),
2042    true = is_members([number,wat,3,"hello",<<"other value">>],maps:values(M6)),
2043
2044    %% error case
2045    do_badmap(fun(T) ->
2046		      {'EXIT',{{badmap,T},[{maps,put,_,_}|_]}} =
2047			  (catch maps:put(1, a, T))
2048	      end),
2049    ok.
2050
2051is_members(Ks,Ls) when length(Ks) =/= length(Ls) -> false;
2052is_members(Ks,Ls) -> is_members_do(Ks,Ls).
2053
2054is_members_do([],[]) -> true;
2055is_members_do([],_) -> false;
2056is_members_do([K|Ks],Ls) ->
2057    is_members_do(Ks, lists:delete(K,Ls)).
2058
2059t_bif_map_remove(Config) when is_list(Config) ->
2060    0  = erlang:map_size(maps:remove(some_key, #{})),
2061
2062    M0 = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
2063            4 => number, 18446744073709551629 => wat},
2064
2065    M1 = maps:remove("hi", M0),
2066    true = is_members([4,18446744073709551629,int,<<"key">>],maps:keys(M1)),
2067    true = is_members([number,wat,3,<<"value">>],maps:values(M1)),
2068
2069    M2 = maps:remove(int, M1),
2070    true = is_members([4,18446744073709551629,<<"key">>],maps:keys(M2)),
2071    true = is_members([number,wat,<<"value">>],maps:values(M2)),
2072
2073    M3 = maps:remove(<<"key">>, M2),
2074    true = is_members([4,18446744073709551629],maps:keys(M3)),
2075    true = is_members([number,wat],maps:values(M3)),
2076
2077    M4 = maps:remove(18446744073709551629, M3),
2078    true = is_members([4],maps:keys(M4)),
2079    true = is_members([number],maps:values(M4)),
2080
2081    M5 = maps:remove(4, M4),
2082    [] = maps:keys(M5),
2083    [] = maps:values(M5),
2084
2085    M0 = maps:remove(5,M0),
2086    M0 = maps:remove("hi there",M0),
2087
2088    #{ "hi" := "hello", int := 3, 4 := number} = maps:remove(18446744073709551629,maps:remove(<<"key">>,M0)),
2089
2090    %% error case
2091    do_badmap(fun(T) ->
2092		      {'EXIT',{{badmap,T},[{maps,remove,_,_}|_]}} = (catch maps:remove(a, T))
2093	      end),
2094    ok.
2095
2096t_bif_map_take(Config) when is_list(Config) ->
2097    error = maps:take(some_key, #{}),
2098
2099    M0 = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
2100            4 => number, 18446744073709551629 => wat},
2101
2102    5 = maps:size(M0),
2103    {"hello", M1} = maps:take("hi", M0),
2104    true = is_members([4,18446744073709551629,int,<<"key">>],maps:keys(M1)),
2105    true = is_members([number,wat,3,<<"value">>],maps:values(M1)),
2106    error = maps:take("hi", M1),
2107    4 = maps:size(M1),
2108
2109    {3, M2} = maps:take(int, M1),
2110    true = is_members([4,18446744073709551629,<<"key">>],maps:keys(M2)),
2111    true = is_members([number,wat,<<"value">>],maps:values(M2)),
2112    error = maps:take(int, M2),
2113    3 = maps:size(M2),
2114
2115    {<<"value">>,M3} = maps:take(<<"key">>, M2),
2116    true = is_members([4,18446744073709551629],maps:keys(M3)),
2117    true = is_members([number,wat],maps:values(M3)),
2118    error = maps:take(<<"key">>, M3),
2119    2 = maps:size(M3),
2120
2121    {wat,M4} = maps:take(18446744073709551629, M3),
2122    true = is_members([4],maps:keys(M4)),
2123    true = is_members([number],maps:values(M4)),
2124    error = maps:take(18446744073709551629, M4),
2125    1 = maps:size(M4),
2126
2127    {number,M5} = maps:take(4, M4),
2128    [] = maps:keys(M5),
2129    [] = maps:values(M5),
2130    error = maps:take(4, M5),
2131    0 = maps:size(M5),
2132
2133    {wat,#{ "hi" := "hello", int := 3, 4 := number, <<"key">> := <<"value">>}} = maps:take(18446744073709551629,M0),
2134
2135    %% error case
2136    do_badmap(fun(T) ->
2137		      {'EXIT',{{badmap,T},[{maps,take,_,_}|_]}} = (catch maps:take(a, T))
2138	      end),
2139    ok.
2140
2141t_bif_map_take_large(Config) when is_list(Config) ->
2142    KVs = [{{erlang:md5(<<I:64>>),I}, I}|| I <- lists:seq(1,500)],
2143    M0 = maps:from_list(KVs),
2144    ok = bif_map_take_all(KVs, M0),
2145    ok.
2146
2147bif_map_take_all([], M0) ->
2148    0 = maps:size(M0),
2149    ok;
2150bif_map_take_all([{K,V}|KVs],M0) ->
2151    {ok,V} = maps:find(K,M0),
2152    {V,M1} = maps:take(K,M0),
2153    error  = maps:find(K,M1),
2154    error  = maps:take(K,M1),
2155    bif_map_take_all(KVs,M1).
2156
2157
2158t_bif_map_update(Config) when is_list(Config) ->
2159    M0 = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
2160	4 => number, 18446744073709551629 => wat},
2161
2162    #{ "hi" := "hello again", int := 3, <<"key">> := <<"value">>,
2163	4 := number, 18446744073709551629 := wat} = maps:update("hi", "hello again", M0),
2164
2165    #{ "hi" := "hello", int := 1337, <<"key">> := <<"value">>,
2166	4 := number, 18446744073709551629 := wat} = maps:update(int, 1337, M0),
2167
2168    #{ "hi" := "hello", int := 3, <<"key">> := <<"new value">>,
2169	4 := number, 18446744073709551629 := wat} = maps:update(<<"key">>, <<"new value">>, M0),
2170
2171    #{ "hi" := "hello", int := 3, <<"key">> := <<"value">>,
2172	4 := integer, 18446744073709551629 := wat} = maps:update(4, integer, M0),
2173
2174    #{ "hi" := "hello", int := 3, <<"key">> := <<"value">>,
2175	4 := number, 18446744073709551629 := wazzup} = maps:update(18446744073709551629, wazzup, M0),
2176
2177    %% error case
2178    do_badmap(fun(T) ->
2179		      {'EXIT',{{badmap,T},[{maps,update,_,_}|_]}} =
2180			  (catch maps:update(1, none, T))
2181	      end),
2182    ok.
2183
2184
2185
2186t_bif_map_values(Config) when is_list(Config) ->
2187
2188    [] = maps:values(#{}),
2189    [1] = maps:values(#{a=>1}),
2190
2191    true = is_members([a,b,c,d,e],maps:values(#{ 1 => a, 2 => b, 3 => c, 4 => d, 5 => e})),
2192    true = is_members([a,b,c,d,e],maps:values(#{ 4 => d, 5 => e, 1 => a, 2 => b, 3 => c})),
2193
2194    M1 = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>, 4 => number},
2195    M2 = M1#{ "hi" => "hello2", <<"key">> => <<"value2">> },
2196    true = is_members([number,3,"hello2",<<"value2">>],maps:values(M2)),
2197    true = is_members([number,3,"hello",<<"value">>],maps:values(M1)),
2198
2199    Vs = lists:seq(1000,20000),
2200    M3 = maps:from_list([{K,K}||K<-Vs]),
2201    M4 = maps:merge(M1,M3),
2202    M5 = maps:merge(M2,M3),
2203    true = is_members(Vs,maps:values(M3)),
2204    true = is_members([number,3,"hello",<<"value">>]++Vs,maps:values(M4)),
2205    true = is_members([number,3,"hello2",<<"value2">>]++Vs,maps:values(M5)),
2206
2207    %% error case
2208    do_badmap(fun(T) ->
2209		      {'EXIT',{{badmap,T},[{maps,values,_,_}|_]}} =
2210			  (catch maps:values(T))
2211	      end),
2212    ok.
2213
2214t_erlang_hash(Config) when is_list(Config) ->
2215
2216    ok = t_bif_erlang_phash2(),
2217    ok = t_bif_erlang_phash(),
2218    ok.
2219
2220t_bif_erlang_phash2() ->
2221
2222    39679005 = erlang:phash2(#{}),
2223    33667975 = erlang:phash2(#{ a => 1, "a" => 2, <<"a">> => 3, {a,b} => 4 }), % 78942764
2224    95332690 = erlang:phash2(#{ 1 => a, 2 => "a", 3 => <<"a">>, 4 => {a,b} }), % 37338230
2225    108954384 = erlang:phash2(#{ 1 => a }), % 14363616
2226    59617982 = erlang:phash2(#{ a => 1 }), % 51612236
2227
2228    42770201 = erlang:phash2(#{{} => <<>>}), % 37468437
2229    71687700 = erlang:phash2(#{<<>> => {}}), % 44049159
2230
2231    M0 = #{ a => 1, "key" => <<"value">> },
2232    M1 = maps:remove("key",M0),
2233    M2 = M1#{ "key" => <<"value">> },
2234
2235    70249457 = erlang:phash2(M0), % 118679416
2236    59617982 = erlang:phash2(M1), % 51612236
2237    70249457 = erlang:phash2(M2), % 118679416
2238    ok.
2239
2240t_bif_erlang_phash() ->
2241    Sz = 1 bsl 32,
2242    1113425985 = erlang:phash(#{},Sz), % 268440612
2243    1510068139 = erlang:phash(#{ a => 1, "a" => 2, <<"a">> => 3, {a,b} => 4 },Sz), % 1196461908
2244    3182345590 = erlang:phash(#{ 1 => a, 2 => "a", 3 => <<"a">>, 4 => {a,b} },Sz), % 3944426064
2245    2927531828 = erlang:phash(#{ 1 => a },Sz), % 1394238263
2246    1670235874 = erlang:phash(#{ a => 1 },Sz), % 4066388227
2247
2248    3935089469 = erlang:phash(#{{} => <<>>},Sz), % 1578050717
2249    71692856   = erlang:phash(#{<<>> => {}},Sz), % 1578050717
2250
2251    M0 = #{ a => 1, "key" => <<"value">> },
2252    M1 = maps:remove("key",M0),
2253    M2 = M1#{ "key" => <<"value">> },
2254
2255    2620391445 = erlang:phash(M0,Sz), % 3590546636
2256    1670235874 = erlang:phash(M1,Sz), % 4066388227
2257    2620391445 = erlang:phash(M2,Sz), % 3590546636
2258    ok.
2259
2260t_map_encode_decode(Config) when is_list(Config) ->
2261    <<131,116,0,0,0,0>> = erlang:term_to_binary(#{}),
2262    Pairs = [
2263	{a,b},{"key","values"},{<<"key">>,<<"value">>},
2264	{1,b},{[atom,1],{<<"wat">>,1,2,3}},
2265	{aa,"values"},
2266	{1 bsl 64 + (1 bsl 50 - 1), sc1},
2267	{99, sc2},
2268	{1 bsl 65 + (1 bsl 51 - 1), sc3},
2269	{88, sc4},
2270	{1 bsl 66 + (1 bsl 52 - 1), sc5},
2271	{77, sc6},
2272	{1 bsl 67 + (1 bsl 53 - 1), sc3},
2273	{75, sc6}, {-10,sc8},
2274	{<<>>, sc9}, {3.14158, sc10},
2275	{[3.14158], sc11}, {more_atoms, sc12},
2276	{{more_tuples}, sc13}, {self(), sc14},
2277	{{},{}},{[],[]},
2278        {map_s, #{a=>a, 2=>b, 3=>c}},
2279        {map_l, maps:from_list([{I,I}||I <- lists:seq(1,74)])}
2280    ],
2281    ok = map_encode_decode_and_match(Pairs,[],#{}),
2282
2283    %% check sorting
2284
2285    %% literally #{ b=>2, a=>1 } in the internal order
2286    #{ a:=1, b:=2 } =
2287	erlang:binary_to_term(<<131,116,0,0,0,2,100,0,1,98,97,2,100,0,1,97,97,1>>),
2288
2289
2290    %% literally #{ "hi" => "value", a=>33, b=>55 } in the internal order
2291    #{ a:=33, b:=55, "hi" := "value"} = erlang:binary_to_term(<<131,116,0,0,0,3,
2292	107,0,2,104,105,            % "hi" :: list()
2293	107,0,5,118,97,108,117,101, % "value" :: list()
2294	100,0,1,97,                 % a :: atom()
2295	97,33,                      % 33 :: integer()
2296	100,0,1,98,                 % b :: atom()
2297	97,55                       % 55 :: integer()
2298	>>),
2299
2300    %% Maps of different sizes
2301    lists:foldl(fun(Key, M0) ->
2302			M1 = M0#{Key => Key},
2303			case Key rem 17 of
2304			    0 ->
2305				M1 = binary_to_term(term_to_binary(M1));
2306			    _ ->
2307				ok
2308			end,
2309			M1
2310		end,
2311		#{},
2312		lists:seq(1,10000)),
2313
2314    %% many maps in same binary
2315    MapList = lists:foldl(fun(K, [M|_]=Acc) -> [M#{K => K} | Acc] end,
2316			  [#{}],
2317			  lists:seq(1,100)),
2318    MapList = binary_to_term(term_to_binary(MapList)),
2319    MapListR = lists:reverse(MapList),
2320    MapListR = binary_to_term(term_to_binary(MapListR)),
2321
2322    %% error cases
2323    %% template: <<131,116,0,0,0,2,100,0,1,97,100,0,1,98,97,1,97,1>>
2324    %% which is: #{ a=>1, b=>1 }
2325
2326    %% uniqueness violation
2327    %% literally #{ a=>1, "hi"=>"value", a=>2 }
2328    {'EXIT',{badarg,[{_,_,_,_}|_]}} = (catch
2329	erlang:binary_to_term(<<131,116,0,0,0,3,
2330			       100,0,1,97,
2331			       97,1,
2332			       107,0,2,104,105,
2333			       107,0,5,118,97,108,117,101,
2334			       100,0,1,97,
2335			       97,2>>)),
2336
2337    %% bad size (too large)
2338    {'EXIT',{badarg,[{_,_,_,_}|_]}} = (catch
2339	erlang:binary_to_term(<<131,116,0,0,0,12,100,0,1,97,97,1,100,0,1,98,97,1>>)),
2340
2341    %% bad size (too small) .. should fail just truncate it .. weird.
2342    %% possibly change external format so truncated will be #{a:=1}
2343    #{ a:=b } = erlang:binary_to_term(<<131,116,0,0,0,1,100,0,1,97,100,0,1,98,97,1,97,1>>),
2344
2345    %% specific fannerl (opensource app) binary_to_term error in 18.1
2346
2347    #{bias := {1,1,0},
2348      bit_fail := 0,
2349      connections := #{{2,9}   := _,
2350                       {8,14}  := _,
2351                       {2,12}  := _,
2352                       {5,7}   := _,
2353                       {11,16} := _,
2354                       {11,15} := _},
2355      layers := {5,7,3},
2356      network_type := fann_nettype_layer,
2357      num_input := 5,
2358      num_layers := 3,
2359      num_output := 3,
2360      rprop_delta_max := _,
2361      rprop_delta_min := _,
2362      total_connections := 66,
2363      total_neurons := 17,
2364      train_error_function := fann_errorfunc_tanh,
2365      train_stop_function := fann_stopfunc_mse,
2366      training_algorithm := fann_train_rprop} = erlang:binary_to_term(fannerl()),
2367    ok.
2368
2369map_encode_decode_and_match([{K,V}|Pairs], EncodedPairs, M0) ->
2370    M1 = maps:put(K,V,M0),
2371    B0 = erlang:term_to_binary(M1),
2372    Ls = [{erlang:term_to_binary(K), erlang:term_to_binary(V)}|EncodedPairs],
2373    ok = match_encoded_map(B0, length(Ls), Ls),
2374    %% decode and match it
2375    M1 = erlang:binary_to_term(B0),
2376    map_encode_decode_and_match(Pairs,Ls,M1);
2377map_encode_decode_and_match([],_,_) -> ok.
2378
2379match_encoded_map(<<131,116,Size:32,Encoded/binary>>,Size,Items) ->
2380    match_encoded_map_stripped_size(Encoded,Items,Items);
2381match_encoded_map(_,_,_) -> no_match_size.
2382
2383match_encoded_map_stripped_size(<<>>,_,_) -> ok;
2384match_encoded_map_stripped_size(B0,[{<<131,K/binary>>,<<131,V/binary>>}|Items],Ls) ->
2385    Ksz = byte_size(K),
2386    Vsz = byte_size(V),
2387    case B0 of
2388	<<K:Ksz/binary,V:Vsz/binary,B1/binary>> ->
2389	    match_encoded_map_stripped_size(B1,Ls,Ls);
2390	_ ->
2391	    match_encoded_map_stripped_size(B0,Items,Ls)
2392    end;
2393match_encoded_map_stripped_size(_,[],_) -> fail.
2394
2395
2396t_bif_map_to_list(Config) when is_list(Config) ->
2397    [] = maps:to_list(#{}),
2398    [{a,1},{b,2}] = lists:sort(maps:to_list(#{a=>1,b=>2})),
2399    [{a,1},{b,2},{c,3}] = lists:sort(maps:to_list(#{c=>3,a=>1,b=>2})),
2400    [{a,1},{b,2},{g,3}] = lists:sort(maps:to_list(#{g=>3,a=>1,b=>2})),
2401    [{a,1},{b,2},{g,3},{"c",4}] = lists:sort(maps:to_list(#{g=>3,a=>1,b=>2,"c"=>4})),
2402    [{3,v2},{hi,v4},{{hi,3},v5},{"hi",v3},{<<"hi">>,v1}] =
2403	lists:sort(maps:to_list(#{<<"hi">>=>v1,3=>v2,"hi"=>v3,hi=>v4,{hi,3}=>v5})),
2404
2405    [{3,v7},{hi,v9},{{hi,3},v10},{"hi",v8},{<<"hi">>,v6}] =
2406	lists:sort(maps:to_list(#{<<"hi">>=>v1,3=>v2,"hi"=>v3,hi=>v4,{hi,3}=>v5,
2407				  <<"hi">>=>v6,3=>v7,"hi"=>v8,hi=>v9,{hi,3}=>v10})),
2408
2409    %% error cases
2410    do_badmap(fun(T) ->
2411		      {'EXIT', {{badmap,T},_}} =
2412			  (catch maps:to_list(T))
2413	      end),
2414    ok.
2415
2416
2417t_bif_map_from_list(Config) when is_list(Config) ->
2418    #{} = maps:from_list([]),
2419    A   = maps:from_list([]),
2420    0   = erlang:map_size(A),
2421
2422    #{a:=1,b:=2}      = maps:from_list([{a,1},{b,2}]),
2423    #{c:=3,a:=1,b:=2} = maps:from_list([{a,1},{b,2},{c,3}]),
2424    #{g:=3,a:=1,b:=2} = maps:from_list([{a,1},{b,2},{g,3}]),
2425
2426    #{a:=2} = maps:from_list([{a,1},{a,3},{a,2}]),
2427
2428    #{ <<"hi">>:=v1,3:=v3,"hi":=v6,hi:=v4,{hi,3}:=v5} =
2429	maps:from_list([{3,v3},{"hi",v6},{hi,v4},{{hi,3},v5},{<<"hi">>,v1}]),
2430
2431    #{<<"hi">>:=v6,3:=v8,"hi":=v11,hi:=v9,{hi,3}:=v10} =
2432	maps:from_list([ {{hi,3},v3}, {"hi",v0},{3,v1}, {<<"hi">>,v4}, {hi,v2},
2433	    {<<"hi">>,v6}, {{hi,3},v10},{"hi",v11}, {hi,v9}, {3,v8}]),
2434
2435    %% repeated keys (large -> small)
2436    Ps1 = [{a,I}|| I <- lists:seq(1,32)],
2437    Ps2 = [{a,I}|| I <- lists:seq(33,64)],
2438
2439    M = maps:from_list(Ps1 ++ [{b,1},{c,1}] ++ Ps2),
2440    #{ a := 64, b := 1, c := 1 } = M,
2441
2442    %% error cases
2443    {'EXIT', {badarg,_}} = (catch maps:from_list(id([{a,b},b]))),
2444    {'EXIT', {badarg,_}} = (catch maps:from_list(id([{a,b},{b,b,3}]))),
2445    {'EXIT', {badarg,_}} = (catch maps:from_list(id([{a,b},<<>>]))),
2446    {'EXIT', {badarg,_}} = (catch maps:from_list(id([{a,b}|{b,a}]))),
2447    {'EXIT', {badarg,_}} = (catch maps:from_list(id(a))),
2448    {'EXIT', {badarg,_}} = (catch maps:from_list(id(42))),
2449    ok.
2450
2451t_bif_map_next(Config) when is_list(Config) ->
2452
2453    erts_debug:set_internal_state(available_internal_state, true),
2454
2455    try
2456
2457        none = maps:next(maps:iterator(id(#{}))),
2458
2459        verify_iterator(#{}),
2460        verify_iterator(#{a => 1, b => 2, c => 3}),
2461
2462        %% Use fatmap in order to test iterating in very deep maps
2463        FM = fatmap(43),
2464        verify_iterator(FM),
2465
2466        {'EXIT', {{badmap,[{a,b},b]},_}} = (catch maps:iterator(id([{a,b},b]))),
2467        {'EXIT', {badarg,_}} = (catch maps:next(id(a))),
2468        {'EXIT', {badarg,_}} = (catch maps:next(id([a|FM]))),
2469        {'EXIT', {badarg,_}} = (catch maps:next(id([1|#{}]))),
2470        {'EXIT', {badarg,_}} = (catch maps:next(id([-1|#{}]))),
2471        {'EXIT', {badarg,_}} = (catch maps:next(id([-1|FM]))),
2472        {'EXIT', {badarg,_}} = (catch maps:next(id([16#FFFFFFFFFFFFFFFF|FM]))),
2473        {'EXIT', {badarg,_}} = (catch maps:next(id([-16#FFFFFFFFFFFFFFFF|FM]))),
2474
2475        %% This us a whitebox test that the error code works correctly.
2476        %% It uses a path for a tree of depth 4 and tries to do next on
2477        %% each of those paths.
2478        (fun F(0) -> ok;
2479             F(N) ->
2480                 try maps:next([N|FM]) of
2481                     none ->
2482                         F(N-1);
2483                     {_K,_V,_I} ->
2484                         F(N-1)
2485                 catch error:badarg ->
2486                         F(N-1)
2487                 end
2488         end)(16#FFFF),
2489
2490        ok
2491    after
2492            erts_debug:set_internal_state(available_internal_state, false)
2493    end.
2494
2495verify_iterator(Map) ->
2496    KVs = t_fold(fun(K, V, A) -> [{K, V} | A] end, [], Map),
2497
2498    %% Verify that KVs created by iterating Map is of
2499    %% correct size and contains all elements
2500    true = length(KVs) == maps:size(Map),
2501    [maps:get(K, Map) || {K, _} <- KVs],
2502    ok.
2503
2504
2505t_fold(Fun, Init, Map) ->
2506    t_fold_1(Fun, Init, maps:iterator(Map)).
2507
2508t_fold_1(Fun, Acc, Iter) ->
2509    case maps:next(Iter) of
2510        {K, V, NextIter} ->
2511            t_fold_1(Fun, Fun(K,V,Acc), NextIter);
2512        none ->
2513            Acc
2514    end.
2515
2516t_bif_build_and_check(Config) when is_list(Config) ->
2517    ok = check_build_and_remove(750,[fun(K) -> [K,K] end,
2518				     fun(K) -> [float(K),K] end,
2519				     fun(K) -> K end,
2520				     fun(K) -> {1,K} end,
2521				     fun(K) -> {K} end,
2522				     fun(K) -> [K|K] end,
2523				     fun(K) -> [K,1,2,3,4] end,
2524				     fun(K) -> {K,atom} end,
2525				     fun(K) -> float(K) end,
2526				     fun(K) -> integer_to_list(K) end,
2527				     fun(K) -> list_to_atom(integer_to_list(K)) end,
2528				     fun(K) -> [K,{K,[K,{K,[K]}]}] end,
2529				     fun(K) -> <<K:32>> end]),
2530    ok.
2531
2532check_build_and_remove(_,[]) -> ok;
2533check_build_and_remove(N,[F|Fs]) ->
2534    {M,Ks} = build_and_check(N, maps:new(), F, []),
2535    ok     = remove_and_check(Ks,M),
2536    check_build_and_remove(N,Fs).
2537
2538build_and_check(0, M0, _, Ks) -> {M0, Ks};
2539build_and_check(N, M0, F, Ks) ->
2540    K  = build_key(F,N),
2541    M1 = maps:put(K,K,M0),
2542    ok = check_keys_exist([I||{I,_} <- [{K,M1}|Ks]], M1),
2543    M2 = maps:update(K,v,M1),
2544    v  = maps:get(K,M2),
2545    build_and_check(N-1,M1,F,[{K,M1}|Ks]).
2546
2547remove_and_check([],_) -> ok;
2548remove_and_check([{K,Mc}|Ks], M0) ->
2549    K     = maps:get(K,M0),
2550    true  = maps:is_key(K,M0),
2551    true  = Mc =:= M0,
2552    true  = M0 == Mc,
2553    M1    = maps:remove(K,M0),
2554    false = M1 =:= Mc,
2555    false = Mc == M1,
2556    false = maps:is_key(K,M1),
2557    true  = maps:is_key(K,M0),
2558    ok    = check_keys_exist([I||{I,_} <- Ks],M1),
2559    error = maps:find(K,M1),
2560    remove_and_check(Ks, M1).
2561
2562build_key(F,N) when N rem 3 =:= 0 -> F(N);
2563build_key(F,N) when N rem 3 =:= 1 -> K = F(N), {K,K};
2564build_key(F,N) when N rem 3 =:= 2 -> K = F(N), [K,K].
2565
2566check_keys_exist([], _) -> ok;
2567check_keys_exist([K|Ks],M) ->
2568    true = maps:is_key(K,M),
2569    check_keys_exist(Ks,M).
2570
2571t_bif_merge_and_check(Config) when is_list(Config) ->
2572
2573    io:format("rand:export_seed() -> ~p\n",[rand:export_seed()]),
2574
2575    %% simple disjunct ones
2576    %% make sure all keys are unique
2577    Kss = [[a,b,c,d],
2578	   [1,2,3,4],
2579	   [],
2580	   ["hi"],
2581	   [e],
2582	   [build_key(fun(K) -> {small,K} end, I) || I <- lists:seq(1,32)],
2583	   lists:seq(5, 28),
2584	   lists:seq(29, 59),
2585	   [build_key(fun(K) -> integer_to_list(K) end, I) || I <- lists:seq(2000,10000)],
2586	   [build_key(fun(K) -> <<K:32>> end, I) || I <- lists:seq(1,80)],
2587	   [build_key(fun(K) -> {<<K:32>>} end, I) || I <- lists:seq(100,1000)]],
2588
2589
2590    KsMs = build_keys_map_pairs(Kss),
2591    Cs   = [{CKs1,CM1,CKs2,CM2} || {CKs1,CM1} <- KsMs, {CKs2,CM2} <- KsMs],
2592    ok   = merge_and_check_combo(Cs),
2593
2594    %% overlapping ones
2595
2596    KVs1 = [{a,1},{b,2},{c,3}],
2597    KVs2 = [{b,3},{c,4},{d,5}],
2598    KVs  = [{I,I} || I <- lists:seq(1,32)],
2599    KVs3 = KVs1 ++ KVs,
2600    KVs4 = KVs2 ++ KVs,
2601
2602    M1  = maps:from_list(KVs1),
2603    M2  = maps:from_list(KVs2),
2604    M3  = maps:from_list(KVs3),
2605    M4  = maps:from_list(KVs4),
2606
2607    M12 = maps:merge(M1,M2),
2608    ok  = check_key_values(KVs2 ++ [{a,1}], M12),
2609    M21 = maps:merge(M2,M1),
2610    ok  = check_key_values(KVs1 ++ [{d,5}], M21),
2611
2612    M34 = maps:merge(M3,M4),
2613    ok  = check_key_values(KVs4 ++ [{a,1}], M34),
2614    M43 = maps:merge(M4,M3),
2615    ok  = check_key_values(KVs3 ++ [{d,5}], M43),
2616
2617    M14 = maps:merge(M1,M4),
2618    ok  = check_key_values(KVs4 ++ [{a,1}], M14),
2619    M41 = maps:merge(M4,M1),
2620    ok  = check_key_values(KVs1 ++ [{d,5}] ++ KVs, M41),
2621
2622    [begin Ma = random_map(SzA, a),
2623	   Mb = random_map(SzB, b),
2624	   ok = merge_maps(Ma, Mb)
2625     end || SzA <- [3,10,20,100,200,1000], SzB <- [3,10,20,100,200,1000]],
2626
2627    ok.
2628
2629% Generate random map with an average of Sz number of pairs: K -> {V,K}
2630random_map(Sz, V) ->
2631    random_map_insert(#{}, 0, V, Sz*2).
2632
2633random_map_insert(M0, K0, _, Sz) when K0 > Sz ->
2634    M0;
2635random_map_insert(M0, K0, V, Sz) ->
2636    Key = K0 + rand:uniform(3),
2637    random_map_insert(M0#{Key => {V,Key}}, Key, V, Sz).
2638
2639
2640merge_maps(A, B) ->
2641    AB = maps:merge(A, B),
2642    %%io:format("A=~p\nB=~p\n",[A,B]),
2643    maps_foreach(fun(K,VB) -> VB = maps:get(K, AB)
2644		 end, B),
2645    maps_foreach(fun(K,VA) ->
2646			 case {maps:get(K, AB),maps:find(K, B)} of
2647			     {VA, error} -> ok;
2648			     {VB, {ok, VB}} -> ok
2649			 end
2650		 end, A),
2651
2652    maps_foreach(fun(K,V) ->
2653			 case {maps:find(K, A),maps:find(K, B)} of
2654			     {{ok, V}, error} -> ok;
2655			     {error, {ok, V}} -> ok;
2656			     {{ok,_}, {ok, V}} -> ok
2657			 end
2658		 end, AB),
2659    ok.
2660
2661maps_foreach(Fun, Map) ->
2662    maps:fold(fun(K,V,_) -> Fun(K,V) end, void, Map).
2663
2664
2665check_key_values([],_) -> ok;
2666check_key_values([{K,V}|KVs],M) ->
2667    V = maps:get(K,M),
2668    check_key_values(KVs,M).
2669
2670merge_and_check_combo([]) -> ok;
2671merge_and_check_combo([{Ks1,M1,Ks2,M2}|Cs]) ->
2672    M12 = maps:merge(M1,M2),
2673    ok  = check_keys_exist(Ks1 ++ Ks2, M12),
2674    M21 = maps:merge(M2,M1),
2675    ok  = check_keys_exist(Ks1 ++ Ks2, M21),
2676
2677    true = M12 =:= M21,
2678    M12  = M21,
2679
2680    merge_and_check_combo(Cs).
2681
2682build_keys_map_pairs([]) -> [];
2683build_keys_map_pairs([Ks|Kss]) ->
2684    M  = maps:from_list(keys_to_pairs(Ks)),
2685    ok = check_keys_exist(Ks, M),
2686    [{Ks,M}|build_keys_map_pairs(Kss)].
2687
2688keys_to_pairs(Ks) -> [{K,K} || K <- Ks].
2689
2690
2691%% Maps module, not BIFs
2692t_maps_fold(_Config) ->
2693    Vs = lists:seq(1,100),
2694    M  = maps:from_list([{{k,I},{v,I}}||I<-Vs]),
2695
2696    %% fold
2697    5050 = maps:fold(fun({k,_},{v,V},A) -> V + A end, 0, M),
2698
2699    ok.
2700
2701t_maps_map(_Config) ->
2702    Vs = lists:seq(1,100),
2703    M1 = maps:from_list([{I,I}||I<-Vs]),
2704    M2 = maps:from_list([{I,{token,I}}||I<-Vs]),
2705
2706    M2 = maps:map(fun(_K,V) -> {token,V} end, M1),
2707    ok.
2708
2709t_maps_size(_Config) ->
2710    Vs = lists:seq(1,100),
2711    lists:foldl(fun(I,M) ->
2712		M1 = maps:put(I,I,M),
2713		I  = maps:size(M1),
2714		M1
2715	end, #{}, Vs),
2716    ok.
2717
2718
2719t_maps_without(_Config) ->
2720    Ki = [11,22,33,44,55,66,77,88,99],
2721    M0 = maps:from_list([{{k,I},{v,I}}||I<-lists:seq(1,100)]),
2722    M1 = maps:from_list([{{k,I},{v,I}}||I<-lists:seq(1,100) -- Ki]),
2723    M1 = maps:without([{k,I}||I <- Ki],M0),
2724    ok.
2725
2726
2727%% MISC
2728
2729%% Verify that the the number of nodes in hashmaps
2730%% of different types and sizes does not deviate too
2731%% much from the theoretical model.
2732t_hashmap_balance(_Config) ->
2733    io:format("Integer keys\n", []),
2734    hashmap_balance(fun(I) -> I end),
2735    io:format("Float keys\n", []),
2736    hashmap_balance(fun(I) -> float(I) end),
2737    io:format("String keys\n", []),
2738    hashmap_balance(fun(I) -> integer_to_list(I) end),
2739    io:format("Binary (big) keys\n", []),
2740    hashmap_balance(fun(I) -> <<I:16/big>> end),
2741    io:format("Binary (little) keys\n", []),
2742    hashmap_balance(fun(I) -> <<I:16/little>> end),
2743    io:format("Atom keys\n", []),
2744    erts_debug:set_internal_state(available_internal_state, true),
2745    hashmap_balance(fun(I) -> erts_debug:get_internal_state({atom,I}) end),
2746    erts_debug:set_internal_state(available_internal_state, false),
2747
2748    ok.
2749
2750hashmap_balance(KeyFun) ->
2751    F = fun(I, {M0,Max0}) ->
2752		Key = KeyFun(I),
2753		M1 = M0#{Key => Key},
2754		Max1 = case erts_internal:term_type(M1) of
2755			   hashmap ->
2756			       Nodes = hashmap_nodes(M1),
2757			       Avg = maps:size(M1) * 0.4,
2758			       StdDev = math:sqrt(maps:size(M1)) / 3,
2759			       SD_diff = abs(Nodes - Avg) / StdDev,
2760			       %%io:format("~p keys: ~p nodes avg=~p SD_diff=~p\n",
2761			       %%          [maps:size(M1), Nodes, Avg, SD_diff]),
2762			       {MaxDiff0, _} = Max0,
2763			       case {Nodes > Avg, SD_diff > MaxDiff0} of
2764				   {true, true} -> {SD_diff, M1};
2765				   _ -> Max0
2766			       end;
2767
2768			   flatmap -> Max0
2769		       end,
2770		{M1, Max1}
2771	end,
2772
2773    {_,{MaxDiff,MaxMap}} = lists:foldl(F,
2774				       {#{}, {0, 0}},
2775				       lists:seq(1,10000)),
2776    io:format("Max std dev diff ~p for map of size ~p (nodes=~p, flatsize=~p)\n",
2777	      [MaxDiff, maps:size(MaxMap), hashmap_nodes(MaxMap), erts_debug:flat_size(MaxMap)]),
2778
2779    true = (MaxDiff < 6),  % The probability of this line failing is about 0.000000001
2780                           % for a uniform hash. I've set the probability this "high" for now
2781                           % to detect flaws in our make_internal_hash.
2782                           % Hard limit is 15 (see hashmap_over_estimated_heap_size).
2783    ok.
2784
2785hashmap_nodes(M) ->
2786    Info = erts_debug:map_info(M),
2787    lists:foldl(fun(Tpl,Acc) ->
2788			case element(1,Tpl) of
2789			    bitmaps -> Acc + element(2,Tpl);
2790			    arrays -> Acc + element(2,Tpl);
2791			    _ -> Acc
2792			end
2793		end,
2794		0,
2795		Info).
2796
2797t_erts_internal_order(_Config) when is_list(_Config) ->
2798
2799    -1 = erts_internal:cmp_term(1,2),
2800    1  = erts_internal:cmp_term(2,1),
2801    0  = erts_internal:cmp_term(2,2),
2802
2803
2804    -1 = erts_internal:cmp_term(1,a),
2805    1  = erts_internal:cmp_term(a,1),
2806    0  = erts_internal:cmp_term(a,a),
2807
2808    -1 = erts_internal:cmp_term(1,1.0),
2809    1  = erts_internal:cmp_term(1.0,1),
2810    0  = erts_internal:cmp_term(1.0,1.0),
2811
2812    -1 = erts_internal:cmp_term(1,1 bsl 65),
2813    1  = erts_internal:cmp_term(1 bsl 65,1),
2814    0  = erts_internal:cmp_term(1 bsl 65, 1 bsl 65),
2815
2816    -1 = erts_internal:cmp_term(1 bsl 65,float(1)),
2817    1  = erts_internal:cmp_term(float(1),1 bsl 65),
2818    -1 = erts_internal:cmp_term(1,float(1 bsl 65)),
2819    1  = erts_internal:cmp_term(float(1 bsl 65),1),
2820    0  = erts_internal:cmp_term(float(1 bsl 65), float(1 bsl 65)),
2821
2822    %% reported errors
2823    -1 = erts_internal:cmp_term(0,2147483648),
2824    0  = erts_internal:cmp_term(2147483648,2147483648),
2825    1  = erts_internal:cmp_term(2147483648,0),
2826
2827    M = #{0 => 0,2147483648 => 0},
2828    true = M =:= binary_to_term(term_to_binary(M)),
2829
2830    F1 = fun(_, _) -> 0 end,
2831    F2 = fun(_, _) -> 1 end,
2832    M0 = maps:from_list( [{-2147483649, 0}, {0,0}, {97, 0}, {false, 0}, {flower, 0}, {F1, 0}, {F2, 0}, {<<>>, 0}]),
2833    M1 = maps:merge(M0, #{0 => 1}),
2834    8  = maps:size(M1),
2835    1  = maps:get(0,M1),
2836    ok.
2837
2838t_erts_internal_hash(_Config) when is_list(_Config) ->
2839    K1 = 0.0,
2840    K2 = 0.0/-1,
2841    M  = maps:from_list([{I,I}||I<-lists:seq(1,32)]),
2842
2843    M1 = M#{ K1 => a, K2 => b },
2844    b  = maps:get(K2,M1),
2845
2846    M2 = M#{ K2 => a, K1 => b },
2847    b  = maps:get(K1,M2),
2848
2849    %% test previously faulty hash list optimization
2850
2851    M3 = M#{[0] => a, [0,0] => b, [0,0,0] => c, [0,0,0,0] => d},
2852    a  = maps:get([0],M3),
2853    b  = maps:get([0,0],M3),
2854    c  = maps:get([0,0,0],M3),
2855    d  = maps:get([0,0,0,0],M3),
2856
2857    M4 = M#{{[0]} => a, {[0,0]} => b, {[0,0,0]} => c, {[0,0,0,0]} => d},
2858    a  = maps:get({[0]},M4),
2859    b  = maps:get({[0,0]},M4),
2860    c  = maps:get({[0,0,0]},M4),
2861    d  = maps:get({[0,0,0,0]},M4),
2862
2863    M5 = M3#{[0,0,0] => e, [0,0,0,0] => f, [0,0,0,0,0] => g,
2864             [0,0,0,0,0,0] => h, [0,0,0,0,0,0,0] => i,
2865             [0,0,0,0,0,0,0,0] => j, [0,0,0,0,0,0,0,0,0] => k},
2866
2867    a  = maps:get([0],M5),
2868    b  = maps:get([0,0],M5),
2869    e  = maps:get([0,0,0],M5),
2870    f  = maps:get([0,0,0,0],M5),
2871    g  = maps:get([0,0,0,0,0],M5),
2872    h  = maps:get([0,0,0,0,0,0],M5),
2873    i  = maps:get([0,0,0,0,0,0,0],M5),
2874    j  = maps:get([0,0,0,0,0,0,0,0],M5),
2875    k  = maps:get([0,0,0,0,0,0,0,0,0],M5),
2876
2877    M6 = M4#{{[0,0,0]} => e, {[0,0,0,0]} => f, {[0,0,0,0,0]} => g,
2878             {[0,0,0,0,0,0]} => h, {[0,0,0,0,0,0,0]} => i,
2879             {[0,0,0,0,0,0,0,0]} => j, {[0,0,0,0,0,0,0,0,0]} => k},
2880
2881    a  = maps:get({[0]},M6),
2882    b  = maps:get({[0,0]},M6),
2883    e  = maps:get({[0,0,0]},M6),
2884    f  = maps:get({[0,0,0,0]},M6),
2885    g  = maps:get({[0,0,0,0,0]},M6),
2886    h  = maps:get({[0,0,0,0,0,0]},M6),
2887    i  = maps:get({[0,0,0,0,0,0,0]},M6),
2888    j  = maps:get({[0,0,0,0,0,0,0,0]},M6),
2889    k  = maps:get({[0,0,0,0,0,0,0,0,0]},M6),
2890
2891    M7 = maps:merge(M5,M6),
2892
2893    a  = maps:get([0],M7),
2894    b  = maps:get([0,0],M7),
2895    e  = maps:get([0,0,0],M7),
2896    f  = maps:get([0,0,0,0],M7),
2897    g  = maps:get([0,0,0,0,0],M7),
2898    h  = maps:get([0,0,0,0,0,0],M7),
2899    i  = maps:get([0,0,0,0,0,0,0],M7),
2900    j  = maps:get([0,0,0,0,0,0,0,0],M7),
2901    k  = maps:get([0,0,0,0,0,0,0,0,0],M7),
2902    a  = maps:get({[0]},M7),
2903    b  = maps:get({[0,0]},M7),
2904    e  = maps:get({[0,0,0]},M7),
2905    f  = maps:get({[0,0,0,0]},M7),
2906    g  = maps:get({[0,0,0,0,0]},M7),
2907    h  = maps:get({[0,0,0,0,0,0]},M7),
2908    i  = maps:get({[0,0,0,0,0,0,0]},M7),
2909    j  = maps:get({[0,0,0,0,0,0,0,0]},M7),
2910    k  = maps:get({[0,0,0,0,0,0,0,0,0]},M7),
2911    ok.
2912
2913t_pdict(_Config) ->
2914
2915    put(#{ a => b, b => a},#{ c => d}),
2916    put(get(#{ a => b, b => a}),1),
2917    1 = get(#{ c => d}),
2918    #{ c := d } = get(#{ a => b, b => a}).
2919
2920t_ets(_Config) ->
2921
2922    Tid = ets:new(map_table,[]),
2923
2924    [ets:insert(Tid,{maps:from_list([{I,-I}]),I}) || I <- lists:seq(1,100)],
2925
2926
2927    [{#{ 2 := -2},2}] = ets:lookup(Tid,#{ 2 => -2 }),
2928
2929    %% Test equal
2930    [3,4] = lists:sort(
2931	      ets:select(Tid,[{{'$1','$2'},
2932			       [{'or',{'==','$1',#{ 3 => -3 }},
2933				 {'==','$1',#{ 4 => -4 }}}],
2934			       ['$2']}])),
2935    %% Test match
2936    [30,50] = lists:sort(
2937		ets:select(Tid,
2938			   [{{#{ 30 => -30}, '$1'},[],['$1']},
2939			    {{#{ 50 => -50}, '$1'},[],['$1']}]
2940			  )),
2941
2942    ets:insert(Tid,{#{ a => b, b => c, c => a},transitivity}),
2943
2944    %% Test equal with map of different size
2945    [] = ets:select(Tid,[{{'$1','_'},[{'==','$1',#{ b => c }}],['$_']}]),
2946
2947    %% Test match with map of different size
2948    %[{#{ a := b },_}] = ets:select(Tid,[{{#{ b => c },'_'},[],['$_']}]),
2949
2950    %%% Test match with don't care value
2951    %[{#{ a := b },_}] = ets:select(Tid,[{{#{ b => '_' },'_'},[],['$_']}]),
2952
2953    %% Test is_map bif
2954    101 = length(ets:select(Tid,[{'$1',[{is_map,{element,1,'$1'}}],['$1']}])),
2955    ets:insert(Tid,{not_a_map,2}),
2956    101 = length(ets:select(Tid,[{'$1',[{is_map,{element,1,'$1'}}],['$1']}])),
2957    ets:insert(Tid,{{nope,a,tuple},2}),
2958    101 = length(ets:select(Tid,[{'$1',[{is_map,{element,1,'$1'}}],['$1']}])),
2959
2960    %% Test map_size bif
2961    [3] = ets:select(Tid,[{{'$1','_'},[{'==',{map_size,'$1'},3}],
2962			   [{map_size,'$1'}]}]),
2963
2964    true = ets:delete(Tid,#{50 => -50}),
2965    [] = ets:lookup(Tid,#{50 => -50}),
2966
2967    ets:delete(Tid),
2968    ok.
2969
2970t_dets(_Config) ->
2971    ok.
2972
2973t_tracing(_Config) ->
2974
2975    dbg:stop_clear(),
2976    {ok,Tracer} = dbg:tracer(process,{fun trace_collector/2, self()}),
2977    dbg:p(self(),c),
2978
2979    %% Test basic map call
2980    {ok,_} = dbg:tpl(?MODULE,id,x),
2981    id(#{ a => b }),
2982    {trace,_,call,{?MODULE,id,[#{ a := b }]}} = getmsg(Tracer),
2983    {trace,_,return_from,{?MODULE,id,1},#{ a := b }} = getmsg(Tracer),
2984    dbg:ctpl(),
2985
2986    %% Test equals in argument list
2987    {ok,_} = dbg:tpl(?MODULE,id,[{['$1'],[{'==','$1',#{ b => c}}],
2988				  [{return_trace}]}]),
2989    id(#{ a => b }),
2990    id(#{ b => c }),
2991    {trace,_,call,{?MODULE,id,[#{ b := c }]}} = getmsg(Tracer),
2992    {trace,_,return_from,{?MODULE,id,1},#{ b := c }} = getmsg(Tracer),
2993    dbg:ctpl(),
2994
2995    %% Test match in head
2996    {ok,_} = dbg:tpl(?MODULE,id,[{[#{b => c}],[],[]}]),
2997    id(#{ a => b }),
2998    id(#{ b => c }),
2999    {trace,_,call,{?MODULE,id,[#{ b := c }]}} = getmsg(Tracer),
3000    dbg:ctpl(),
3001
3002    % Test map guard bifs
3003    {ok,_} = dbg:tpl(?MODULE,id,[{['$1'],[{is_map,{element,1,'$1'}}],[]}]),
3004    id(#{ a => b }),
3005    id({1,2}),
3006    id({#{ a => b},2}),
3007    {trace,_,call,{?MODULE,id,[{#{ a := b },2}]}} = getmsg(Tracer),
3008    dbg:ctpl(),
3009
3010    {ok,_} = dbg:tpl(?MODULE,id,[{['$1'],[{'==',{map_size,{element,1,'$1'}},2}],[]}]),
3011    id(#{ a => b }),
3012    id({1,2}),
3013    id({#{ a => b},2}),
3014    id({#{ a => b, b => c},atom}),
3015    {trace,_,call,{?MODULE,id,[{#{ a := b, b := c },atom}]}} = getmsg(Tracer),
3016    dbg:ctpl(),
3017
3018    %MS = dbg:fun2ms(fun([A]) when A == #{ a => b} -> ok end),
3019    %dbg:tpl(?MODULE,id,MS),
3020    %id(#{ a => b }),
3021    %id(#{ b => c }),
3022    %{trace,_,call,{?MODULE,id,[#{ a := b }]}} = getmsg(Tracer),
3023    %dbg:ctpl(),
3024
3025    %% Check to extra messages
3026    timeout = getmsg(Tracer),
3027
3028    dbg:stop_clear(),
3029    ok.
3030
3031getmsg(_Tracer) ->
3032    receive V -> V after 100 -> timeout end.
3033
3034trace_collector(Msg,Parent) ->
3035    io:format("~p~n",[Msg]),
3036    Parent ! Msg,
3037    Parent.
3038
3039t_has_map_fields(Config) when is_list(Config) ->
3040    true = has_map_fields_1(#{one=>1}),
3041    true = has_map_fields_1(#{one=>1,two=>2}),
3042    false = has_map_fields_1(#{two=>2}),
3043    false = has_map_fields_1(#{}),
3044
3045    true = has_map_fields_2(#{c=>1,b=>2,a=>3}),
3046    true = has_map_fields_2(#{c=>1,b=>2,a=>3,x=>42}),
3047    false = has_map_fields_2(#{b=>2,c=>1}),
3048    false = has_map_fields_2(#{x=>y}),
3049    false = has_map_fields_2(#{}),
3050
3051    true = has_map_fields_3(#{c=>1,b=>2,a=>3}),
3052    true = has_map_fields_3(#{c=>1,b=>2,a=>3,[]=>42}),
3053    true = has_map_fields_3(#{b=>2,a=>3,[]=>42,42.0=>43}),
3054    true = has_map_fields_3(#{a=>3,[]=>42,42.0=>43}),
3055    true = has_map_fields_3(#{[]=>42,42.0=>43}),
3056    false = has_map_fields_3(#{b=>2,c=>1}),
3057    false = has_map_fields_3(#{[]=>y}),
3058    false = has_map_fields_3(#{42.0=>x,a=>99}),
3059    false = has_map_fields_3(#{}),
3060
3061    ok.
3062
3063has_map_fields_1(#{one:=_}) -> true;
3064has_map_fields_1(#{}) -> false.
3065
3066has_map_fields_2(#{a:=_,b:=_,c:=_}) -> true;
3067has_map_fields_2(#{}) -> false.
3068
3069has_map_fields_3(#{a:=_,b:=_}) -> true;
3070has_map_fields_3(#{[]:=_,42.0:=_}) -> true;
3071has_map_fields_3(#{}) -> false.
3072
3073y_regs(Config) when is_list(Config) ->
3074    Val = [length(Config)],
3075    Map0 = y_regs_update(#{}, Val),
3076    Map2 = y_regs_update(Map0, Val),
3077
3078    Map3 = maps:from_list([{I,I*I} || I <- lists:seq(1, 100)]),
3079    Map4 = y_regs_update(Map3, Val),
3080
3081    true = is_map(Map2) andalso is_map(Map4),
3082
3083    gurka = y_regs_literal(0),
3084    gaffel = y_regs_literal(1),
3085
3086    ok.
3087
3088y_regs_literal(Key) when is_integer(Key) ->
3089    %% Forces the key to be placed in a Y register.
3090    lists:seq(1, 2),
3091    case is_map_key(Key, #{ 0 => 0 }) of
3092        true -> gurka;
3093        false -> gaffel
3094    end.
3095
3096y_regs_update(Map0, Val0) ->
3097    Val1 = {t,Val0},
3098    K1 = id({key,1}),
3099    K2 = id({key,2}),
3100    Map1 = Map0#{K1=>K1,
3101		 a=>Val0,b=>Val0,c=>Val0,d=>Val0,e=>Val0,
3102		 f=>Val0,g=>Val0,h=>Val0,i=>Val0,j=>Val0,
3103		 k=>Val0,l=>Val0,m=>Val0,n=>Val0,o=>Val0,
3104		 p=>Val0,q=>Val0,r=>Val0,s=>Val0,t=>Val0,
3105		 u=>Val0,v=>Val0,w=>Val0,x=>Val0,y=>Val0,
3106		 z=>Val0,
3107		 aa=>Val0,ab=>Val0,ac=>Val0,ad=>Val0,ae=>Val0,
3108		 af=>Val0,ag=>Val0,ah=>Val0,ai=>Val0,aj=>Val0,
3109		 ak=>Val0,al=>Val0,am=>Val0,an=>Val0,ao=>Val0,
3110		 ap=>Val0,aq=>Val0,ar=>Val0,as=>Val0,at=>Val0,
3111		 au=>Val0,av=>Val0,aw=>Val0,ax=>Val0,ay=>Val0,
3112		 az=>Val0,
3113		 K2=>[a,b,c]},
3114    Map2 = Map1#{K1=>K1,
3115		 a:=Val1,b:=Val1,c:=Val1,d:=Val1,e:=Val1,
3116		 f:=Val1,g:=Val1,h:=Val1,i:=Val1,j:=Val1,
3117		 k:=Val1,l:=Val1,m:=Val1,n:=Val1,o:=Val1,
3118		 p:=Val1,q:=Val1,r:=Val1,s:=Val1,t:=Val1,
3119		 u:=Val1,v:=Val1,w:=Val1,x:=Val1,y:=Val1,
3120		 z:=Val1,
3121		 aa:=Val1,ab:=Val1,ac:=Val1,ad:=Val1,ae:=Val1,
3122		 af:=Val1,ag:=Val1,ah:=Val1,ai:=Val1,aj:=Val1,
3123		 ak:=Val1,al:=Val1,am:=Val1,an:=Val1,ao:=Val1,
3124		 ap:=Val1,aq:=Val1,ar:=Val1,as:=Val1,at:=Val1,
3125		 au:=Val1,av:=Val1,aw:=Val1,ax:=Val1,ay:=Val1,
3126		 az:=Val1,
3127		 K2=>[a,b,c]},
3128
3129    %% Traverse the maps to validate them.
3130    _ = erlang:phash2({Map1,Map2}, 100000),
3131
3132    _ = id({K1,K2,Val0,Val1}),			%Force use of Y registers.
3133    Map2.
3134
3135do_badmap(Test) ->
3136    Terms = [Test,fun erlang:abs/1,make_ref(),self(),0.0/id(-1),
3137	     <<0:1024>>,<<1:1>>,<<>>,<<1,2,3>>,
3138	     [],{a,b,c},[a,b],atom,10.0,42,(1 bsl 65) + 3],
3139    [Test(T) || T <- Terms].
3140
3141%% Test that a module compiled with the OTP 17 compiler will
3142%% generate the correct 'badmap' exception.
3143badmap_17(Config) ->
3144    case ?MODULE of
3145	map_SUITE -> do_badmap_17(Config);
3146	_ -> {skip,"Run in map_SUITE"}
3147    end.
3148
3149do_badmap_17(Config) ->
3150    Mod = badmap_17,
3151    DataDir = test_server:lookup_config(data_dir, Config),
3152    Beam = filename:join(DataDir, Mod),
3153    {module,Mod} = code:load_abs(Beam),
3154    do_badmap(fun Mod:update/1).
3155
3156%% Use this function to avoid compile-time evaluation of an expression.
3157id(I) -> I.
3158
3159
3160%% OTP-13763
3161t_hash_entropy(Config) when is_list(Config)  ->
3162    %% entropy bug in 18.3, 19.0
3163    M1 = maps:from_list([{#{"id" => I}, ok}||I <- lists:seq(1,50000)]),
3164
3165    #{ #{"id" => 100} := ok,
3166       #{"id" => 200} := ok,
3167       #{"id" => 300} := ok,
3168       #{"id" => 400} := ok,
3169       #{"id" => 500} := ok,
3170       #{"id" => 600} := ok,
3171       #{"id" => 700} := ok,
3172       #{"id" => 800} := ok,
3173       #{"id" => 900} := ok,
3174       #{"id" => 25061} := ok,
3175       #{"id" => 39766} := ok } = M1,
3176
3177    M0 = maps:from_list([{I,ok}||I <- lists:seq(1,33)]),
3178    M2 = maps:from_list([{M0#{"id" => I}, ok}||I <- lists:seq(1,50000)]),
3179
3180    ok = maps:get(M0#{"id" => 100}, M2),
3181    ok = maps:get(M0#{"id" => 200}, M2),
3182    ok = maps:get(M0#{"id" => 300}, M2),
3183    ok = maps:get(M0#{"id" => 400}, M2),
3184    ok = maps:get(M0#{"id" => 500}, M2),
3185    ok = maps:get(M0#{"id" => 600}, M2),
3186    ok = maps:get(M0#{"id" => 700}, M2),
3187    ok = maps:get(M0#{"id" => 800}, M2),
3188    ok = maps:get(M0#{"id" => 900}, M2),
3189    ok = maps:get(M0#{"id" => 25061}, M2),
3190    ok = maps:get(M0#{"id" => 39766}, M2),
3191    ok.
3192
3193%% OTP-13146
3194%% Provoke major GC with a lot of "fat" maps on external format in msg queue
3195%% causing heap fragments to be allocated.
3196t_gc_rare_map_overflow(Config) when is_list(Config) ->
3197    Pa = filename:dirname(code:which(?MODULE)),
3198    {ok, Node} = test_server:start_node(gc_rare_map_overflow, slave, [{args, "-pa \""++Pa++"\""}]),
3199    erts_debug:set_internal_state(available_internal_state, true),
3200    try
3201	Echo = spawn_link(Node, fun Loop() -> receive {From,Msg} -> From ! Msg
3202					      end,
3203					      Loop()
3204				end),
3205	FatMap = fatmap(34),
3206	false = (flatmap =:= erts_internal:term_type(FatMap)),
3207
3208	t_gc_rare_map_overflow_do(Echo, FatMap, fun() -> erlang:garbage_collect() end),
3209
3210	%% Repeat test for minor gc:
3211	t_gc_rare_map_overflow_do(Echo, FatMap, fun() -> minor_collect() end),
3212
3213	unlink(Echo),
3214
3215	%% Test fatmap in exit signal
3216	Exiter = spawn_link(Node, fun Loop() -> receive {_From,Msg} ->
3217							"not_a_map" = Msg  % badmatch!
3218						end,
3219						Loop()
3220				  end),
3221	process_flag(trap_exit, true),
3222	Exiter ! {self(), FatMap},
3223	{'EXIT', Exiter, {{badmatch,FatMap}, _}} = receive M -> M end,
3224	ok
3225
3226    after
3227	process_flag(trap_exit, false),
3228	erts_debug:set_internal_state(available_internal_state, false),
3229	test_server:stop_node(Node)
3230    end.
3231
3232t_gc_rare_map_overflow_do(Echo, FatMap, GcFun) ->
3233    Master = self(),
3234    true = receive _M -> false after 0 -> true end,   % assert empty msg queue
3235    Echo ! {Master, token},
3236    repeat(1000, fun(_) -> Echo ! {Master, FatMap} end, void),
3237
3238    timer:sleep(100),                % Wait for maps to arrive in our msg queue
3239    token = receive Tok -> Tok end,  % and provoke move from outer to inner msg queue
3240
3241    %% Do GC that will "overflow" and create heap frags due to all the fat maps
3242    GcFun(),
3243
3244    %% Now check that all maps in msg queueu are intact
3245    %% Will crash emulator in OTP-18.1
3246    repeat(1000, fun(_) -> FatMap = receive FM -> FM end end, void),
3247    ok.
3248
3249minor_collect() ->
3250    Before = minor_gcs(),
3251    erts_debug:set_internal_state(force_gc, self()),
3252    erlang:yield(),
3253    After = minor_gcs(),
3254    io:format("minor_gcs: ~p -> ~p\n", [Before, After]).
3255
3256minor_gcs() ->
3257    {garbage_collection, Info} = process_info(self(), garbage_collection),
3258    {minor_gcs, GCS} = lists:keyfind(minor_gcs, 1, Info),
3259    GCS.
3260
3261%% Generate a map with N (or N+1) keys that has an abnormal heap demand.
3262%% Done by finding keys that collide in the first 32-bit hash.
3263fatmap(N) ->
3264    %%erts_debug:set_internal_state(available_internal_state, true),
3265    Table = ets:new(void, [bag, private]),
3266
3267    Seed0 = rand:seed_s(exsplus, {4711, 3141592, 2718281}),
3268    Seed1 = fatmap_populate(Table, Seed0, (1 bsl 16)),
3269    Keys = fatmap_generate(Table, Seed1, N, []),
3270    ets:delete(Table),
3271    maps:from_list([{K,K} || K <- Keys]).
3272
3273fatmap_populate(_, Seed, 0) -> Seed;
3274fatmap_populate(Table, Seed, N) ->
3275    {I, NextSeed} = rand:uniform_s(1 bsl 48, Seed),
3276    Hash = internal_hash(I),
3277    ets:insert(Table, [{Hash, I}]),
3278    fatmap_populate(Table, NextSeed, N-1).
3279
3280
3281fatmap_generate(_, _, N, Acc) when N =< 0 ->
3282    Acc;
3283fatmap_generate(Table, Seed, N0, Acc0) ->
3284    {I, NextSeed} = rand:uniform_s(1 bsl 48, Seed),
3285    Hash = internal_hash(I),
3286    case ets:member(Table, Hash) of
3287	true ->
3288	    NewKeys = [I | ets:lookup_element(Table, Hash, 2)],
3289	    Acc1 = lists:usort(Acc0 ++ NewKeys),
3290	    N1 = N0 - (length(Acc1) - length(Acc0)),
3291	    fatmap_generate(Table, NextSeed, N1, Acc1);
3292	false ->
3293	    fatmap_generate(Table, NextSeed, N0, Acc0)
3294    end.
3295
3296internal_hash(Term) ->
3297    erts_debug:get_internal_state({internal_hash, Term}).
3298
3299
3300%% map external_format (fannerl).
3301fannerl() ->
3302    <<131,116,0,0,0,28,100,0,13,108,101,97,114,110,105,110,103,95,114,
3303      97,116,101,70,63,230,102,102,96,0,0,0,100,0,17,108,101,97,114,110,105,110,
3304      103,95,109,111,109,101,110,116,117,109,70,0,0,0,0,0,0,0,0,100,0,
3305      18,116,114,97,105,110,105,110,103,95,97,108,103,111,114,105,116,104,109,100,0,
3306      16,102,97,110,110,95,116,114,97,105,110,95,114,112,114,111,112,
3307      100,0,17,109,101,97,110,95,115,113,117,97,114,101,95,101,114,114,111,114,70,
3308      0,0,0,0,0,0,0,0,100,0,8,98,105,116,95,102,97,105,108,97,0,100,0,20,
3309      116,114,97,105,110,95,101,114,114,111,114,95,102,117,110,99,116,105,111,
3310      110,100,0,19,102,97,110,110,95,101,114,114,111,114,102,117,110,99,
3311      95,116,97,110,104,100,0,9,110,117,109,95,105,110,112,117,116,97,5,100,0,10,110,
3312      117,109,95,111,117,116,112,117,116,97,3,100,0,13,116,111,116,97,108,
3313      95,110,101,117,114,111,110,115,97,17,100,0,17,116,111,116,97,108,95,99,111,110,
3314      110,101,99,116,105,111,110,115,97,66,100,0,12,110,101,116,119,111,114,107,
3315      95,116,121,112,101,100,0,18,102,97,110,110,95,110,101,116,116,121,112,101,
3316      95,108,97,121,101,114,100,0,15,99,111,110,110,101,99,116,105,111,110,95,
3317      114,97,116,101,70,63,240,0,0,0,0,0,0,100,0,10,110,117,109,95,108,97,121,101,
3318      114,115,97,3,100,0,19,116,114,97,105,110,95,115,116,111,112,95,102,117,110,
3319      99,116,105,111,110,100,0,17,102,97,110,110,95,115,116,111,112,102,117,110,
3320      99,95,109,115,101,100,0,15,113,117,105,99,107,112,114,111,112,95,100,101,99,
3321      97,121,70,191,26,54,226,224,0,0,0,100,0,12,113,117,105,99,107,112,114,
3322      111,112,95,109,117,70,63,252,0,0,0,0,0,0,100,0,21,114,112,114,111,112,95,105,
3323      110,99,114,101,97,115,101,95,102,97,99,116,111,114,70,63,243,51,51,
3324      64,0,0,0,100,0,21,114,112,114,111,112,95,100,101,99,114,101,97,115,101,
3325      95,102,97,99,116,111,114,70,63,224,0,0,0,0,0,0,100,0,15,114,112,114,111,112,
3326      95,100,101,108,116,97,95,109,105,110,70,0,0,0,0,0,0,0,0,100,0,15,114,112,114,
3327      111,112,95,100,101,108,116,97,95,109,97,120,70,64,73,0,0,0,0,0,0,100,0,
3328      16,114,112,114,111,112,95,100,101,108,116,97,95,122,101,114,111,70,63,185,153,
3329      153,160,0,0,0,100,0,26,115,97,114,112,114,111,112,95,119,101,105,103,
3330      104,116,95,100,101,99,97,121,95,115,104,105,102,116,70,192,26,147,116,192,0,0,0,
3331      100,0,35,115,97,114,112,114,111,112,95,115,116,101,112,95,101,114,
3332      114,111,114,95,116,104,114,101,115,104,111,108,100,95,102,97,99,116,111,114,70,
3333      63,185,153,153,160,0,0,0,100,0,24,115,97,114,112,114,111,112,95,115,
3334      116,101,112,95,101,114,114,111,114,95,115,104,105,102,116,70,63,246,40,245,
3335      192,0,0,0,100,0,19,115,97,114,112,114,111,112,95,116,101,109,112,101,114,
3336      97,116,117,114,101,70,63,142,184,81,224,0,0,0,100,0,6,108,97,121,101,114,115,
3337      104,3,97,5,97,7,97,3,100,0,4,98,105,97,115,104,3,97,1,97,1,97,0,100,0,11,
3338      99,111,110,110,101,99,116,105,111,110,115,116,0,0,0,66,104,2,97,0,97,6,70,
3339      191,179,51,44,64,0,0,0,104,2,97,1,97,6,70,63,178,130,90,32,0,0,0,104,2,97,2,
3340      97,6,70,63,82,90,88,0,0,0,0,104,2,97,3,97,6,70,63,162,91,63,192,0,0,0,104,2,
3341      97,4,97,6,70,191,151,70,169,0,0,0,0,104,2,97,5,97,6,70,191,117,52,222,0,0,0,
3342      0,104,2,97,0,97,7,70,63,152,240,139,0,0,0,0,104,2,97,1,97,7,70,191,166,31,
3343      187,160,0,0,0,104,2,97,2,97,7,70,191,150,70,63,0,0,0,0,104,2,97,3,97,7,70,
3344      63,152,181,126,128,0,0,0,104,2,97,4,97,7,70,63,151,187,162,128,0,0,0,104,2,
3345      97,5,97,7,70,191,143,161,101,0,0,0,0,104,2,97,0,97,8,70,191,153,102,36,128,0,
3346      0,0,104,2,97,1,97,8,70,63,160,139,250,64,0,0,0,104,2,97,2,97,8,70,63,164,62,
3347      196,64,0,0,0,104,2,97,3,97,8,70,191,178,78,209,192,0,0,0,104,2,97,4,97,8,70,
3348      191,185,19,76,224,0,0,0,104,2,97,5,97,8,70,63,183,142,196,96,0,0,0,104,2,97,0,
3349      97,9,70,63,150,104,248,0,0,0,0,104,2,97,1,97,9,70,191,164,4,100,224,0,0,0,
3350      104,2,97,2,97,9,70,191,169,42,42,224,0,0,0,104,2,97,3,97,9,70,63,145,54,78,128,0,
3351      0,0,104,2,97,4,97,9,70,63,126,243,134,0,0,0,0,104,2,97,5,97,9,70,63,177,
3352      203,25,96,0,0,0,104,2,97,0,97,10,70,63,172,104,47,64,0,0,0,104,2,97,1,97,10,
3353      70,63,161,242,193,64,0,0,0,104,2,97,2,97,10,70,63,175,208,241,192,0,0,0,104,2,
3354      97,3,97,10,70,191,129,202,161,0,0,0,0,104,2,97,4,97,10,70,63,178,151,55,32,0,0,0,
3355      104,2,97,5,97,10,70,63,137,155,94,0,0,0,0,104,2,97,0,97,11,70,191,179,
3356      106,160,0,0,0,0,104,2,97,1,97,11,70,63,184,253,164,96,0,0,0,104,2,97,2,97,11,
3357      70,191,143,30,157,0,0,0,0,104,2,97,3,97,11,70,63,153,225,140,128,0,0,0,104,
3358      2,97,4,97,11,70,63,161,35,85,192,0,0,0,104,2,97,5,97,11,70,63,175,200,55,192,
3359      0,0,0,104,2,97,0,97,12,70,191,180,116,132,96,0,0,0,104,2,97,1,97,12,70,191,
3360      165,151,152,0,0,0,0,104,2,97,2,97,12,70,191,180,197,91,160,0,0,0,104,2,97,3,97,12,
3361      70,191,91,30,160,0,0,0,0,104,2,97,4,97,12,70,63,180,251,45,32,0,0,0,
3362      104,2,97,5,97,12,70,63,165,134,77,64,0,0,0,104,2,97,6,97,14,70,63,181,56,242,96,
3363      0,0,0,104,2,97,7,97,14,70,191,165,239,234,224,0,0,0,104,2,97,8,97,14,
3364      70,191,154,65,216,128,0,0,0,104,2,97,9,97,14,70,63,150,250,236,0,0,0,0,104,2,97,
3365      10,97,14,70,191,141,105,108,0,0,0,0,104,2,97,11,97,14,70,191,152,40,
3366      165,0,0,0,0,104,2,97,12,97,14,70,63,141,159,46,0,0,0,0,104,2,97,13,97,14,70,
3367      191,183,172,137,32,0,0,0,104,2,97,6,97,15,70,63,163,26,123,192,0,0,0,104,
3368      2,97,7,97,15,70,63,176,184,106,32,0,0,0,104,2,97,8,97,15,70,63,152,234,144,
3369      0,0,0,0,104,2,97,9,97,15,70,191,172,58,70,160,0,0,0,104,2,97,10,97,15,70,
3370      63,161,211,211,192,0,0,0,104,2,97,11,97,15,70,191,148,171,120,128,0,0,0,104,
3371      2,97,12,97,15,70,63,180,117,214,224,0,0,0,104,2,97,13,97,15,70,191,104,
3372      230,216,0,0,0,0,104,2,97,6,97,16,70,63,178,53,103,96,0,0,0,104,2,97,7,97,16,
3373      70,63,170,230,232,64,0,0,0,104,2,97,8,97,16,70,191,183,45,100,192,0,0,0,
3374      104,2,97,9,97,16,70,63,184,100,97,32,0,0,0,104,2,97,10,97,16,70,63,169,174,
3375      254,64,0,0,0,104,2,97,11,97,16,70,191,119,121,234,0,0,0,0,104,2,97,12,97,
3376      16,70,63,149,12,170,128,0,0,0,104,2,97,13,97,16,70,191,144,193,191,0,0,0,0>>.
3377