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