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