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