diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl index da618d9dda77..d322521a0ece 100644 --- a/lib/stdlib/test/ets_SUITE.erl +++ b/lib/stdlib/test/ets_SUITE.erl @@ -1956,7 +1956,7 @@ t_select_hashmap_term_copy_bug(_Config) -> _ -> {250, 32} end, - LM = maps:from_list([{V,1} || V <- lists:seq(1,LargeMapSize)]), + LM = maps:from_keys(lists:seq(1,LargeMapSize), 1), lists:foreach( fun(Key) -> @@ -1968,21 +1968,23 @@ t_select_hashmap_term_copy_bug(_Config) -> V = [LM#{ Key => Dollar1 }] end, maps:keys(LM)), - LMWithDollar = LM#{ '$1' => a }, + %% Create a hashmap with enough keys before and after the '$1' for it to + %% remain a hashmap when we remove those keys. + LMWithDollar = make_lm_with_dollar(LM#{ '$1' => a }, LargeMapSize, FlatmapSize), %% Test that hashmap with '$1' in first position works %% We rely on that fact that maps:keys return the keys %% in iteration order. lists:foldl( fun - (Key, M = #{ '$1' := _ }) -> + (Key, M = #{ '$1' := A }) when map_size(M) > FlatmapSize -> V = ets:select(T, [{{'$1'},[], [M]}]), erlang:garbage_collect(), V = ets:select(T, [{{'$1'},[], [M]}]), erlang:garbage_collect(), - V = [(maps:remove('$1',M))#{ Dollar1 => a }], + V = [(maps:remove('$1',M))#{ Dollar1 => A }], maps:remove(Key, M); (_, M) when map_size(M) > FlatmapSize -> @@ -1994,14 +1996,14 @@ t_select_hashmap_term_copy_bug(_Config) -> %% in iteration order. lists:foldl( fun - (Key, M = #{ '$1' := _ }) -> + (Key, M = #{ '$1' := A }) -> V = ets:select(T, [{{'$1'},[], [M]}]), erlang:garbage_collect(), V = ets:select(T, [{{'$1'},[], [M]}]), erlang:garbage_collect(), - V = [(maps:remove('$1',M))#{ Dollar1 => a }], + V = [(maps:remove('$1',M))#{ Dollar1 => A }], maps:remove(Key, M); (_, M) when map_size(M) > FlatmapSize -> @@ -2027,6 +2029,20 @@ t_select_hashmap_term_copy_bug(_Config) -> ets:delete(T), ok. +%% Create a hashmap that always has FlatmapSize keys before and after '$1'. +%% Since the atom index of '$1' is used as hash, we cannot know before the +%% code is run where exactly it will be placed, so in the rare cases when +%% there isn't enough keys in the map, we insert more until there are enough. +make_lm_with_dollar(Map, LargeMapSize, FlatmapSize) -> + {KeysBefore, KeysAfter} = lists:splitwith(fun erlang:is_integer/1, maps:keys(Map)), + if length(KeysBefore) =< FlatmapSize; + length(KeysAfter) - 1 =< FlatmapSize -> + NewMap = maps:from_keys(lists:seq(LargeMapSize, LargeMapSize*2), 1), + make_lm_with_dollar(maps:merge(Map, NewMap), LargeMapSize*2, FlatmapSize); + true -> + Map + end. + %% Test that partly bound keys gives faster matches. partly_bound(Config) when is_list(Config) -> case os:type() of