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