diff options
Diffstat (limited to 'lib/stdlib/test/select_SUITE.erl')
-rw-r--r-- | lib/stdlib/test/select_SUITE.erl | 804 |
1 files changed, 804 insertions, 0 deletions
diff --git a/lib/stdlib/test/select_SUITE.erl b/lib/stdlib/test/select_SUITE.erl new file mode 100644 index 0000000000..54664fbb00 --- /dev/null +++ b/lib/stdlib/test/select_SUITE.erl @@ -0,0 +1,804 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(select_SUITE). +-author('[email protected]'). + +-export([test/0]). + +%% +%% Define to run outside of test server +%% +%%-define(STANDALONE,1). + +%% +%% Define for debug output +%% +%%-define(debug,1). + +-ifdef(STANDALONE). +-define(config(A,B),config(A,B)). +-export([config/2]). +-define(fmt(A,B),io:format(A,B)). +-else. +-include("test_server.hrl"). +-define(fmt(A,B),test_server:format(A,B)). +-endif. + +-ifdef(debug). +-ifdef(STANDALONE). +-define(line, erlang:display({?MODULE,?LINE}), ). +-endif. +-define(dbgformat(A,B),io:format(A,B)). +-else. +-ifdef(STANDALONE). +-define(line, noop, ). +-endif. +-define(dbgformat(A,B),noop). +-endif. + +-ifdef(STANDALONE). +config(priv_dir,_) -> + ".". +-else. +%% When run in test server. +-export([all/1,select_test/1,init_per_testcase/2, fin_per_testcase/2, + return_values/1]). + +init_per_testcase(_Case, Config) when is_list(Config) -> + ?line Dog=test_server:timetrap(test_server:seconds(1200)), + [{watchdog, Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog=?config(watchdog, Config), + test_server:timetrap_cancel(Dog), + ok. + +all(doc) -> + ["Test ets:select"]; +all(suite) -> + [return_values, select_test]. + +select_test(suite) -> + []; +select_test(doc) -> + ["Tests select in numerous ways"]; +select_test(Config) when list(Config) -> + do_test(Config). + +return_values(suite) -> + []; +return_values(doc) -> + ["Tests return values in specific situations for select/3 and select/1"]; +return_values(Config) when list(Config) -> + do_return_values(). + +-endif. + + +table_factor({dets,_}) -> + 1; +table_factor({ets,_}) -> + 100. + +gen_dets_filename(Config,N) -> + filename:join(?config(priv_dir,Config), + "testdets_" ++ integer_to_list(N) ++ ".dets"). + +create_tables(Config) -> + Hash = ets:new(xxx, []), + Tree = ets:new(yyy, [ordered_set]), + Bag = ets:new(yyy, [bag]), + DBag = ets:new(yyy, [duplicate_bag]), + F1 = gen_dets_filename(Config,1), + (catch file:delete(F1)), + {ok,DetsPlain} = dets:open_file(testdets_1, + [{file, F1}]), + F3 = gen_dets_filename(Config,3), + (catch file:delete(F3)), + {ok,DetsBag} = dets:open_file(testdets_3, + [{file, F3},{type, bag}]), + F4 = gen_dets_filename(Config,4), + (catch file:delete(F4)), + {ok,DetsDBag} = dets:open_file(testdets_4, + [{file, F4},{type, duplicate_bag}]), + [{ets,Hash}, {ets,Tree}, {ets,Bag}, {ets,DBag}, + {dets, DetsPlain}, {dets, DetsBag}, {dets, DetsDBag}]. + + +gen_key(N,list) -> + [N,N+1,N+2]; +gen_key(N,tuple) -> + {N,N+1,N+2}; +gen_key(N,complex) -> + {[N,N+1],N+2}. + +gen_fun(N) -> + fun() -> + N + end. + +gen_bin(N) -> + list_to_binary(integer_to_list(N)). + +gen_object(N,Type) -> + L = integer_to_list(N), + A = list_to_atom("a" ++ L), + {gen_key(N,Type), L, A, gen_fun(N), gen_bin(N)}. +gen_object1(N,Type) -> + L = integer_to_list(N), + A = list_to_atom("a" ++ L), + {gen_key(N,Type), A, L, gen_fun(N), gen_bin(N)}. + +fill_table(_,0,_) -> + ok; +fill_table({Mod,Tab},N,Type) -> + Obj1 = gen_object1(N,Type), + Obj = gen_object(N,Type), + Mod:insert(Tab, Obj1), + case Mod:info(Tab,type) of + bag -> + Mod:insert(Tab, Obj); + duplicate_bag -> + Mod:insert(Tab, Obj), + Mod:insert(Tab, Obj1); + _ -> + ok + end, + fill_table({Mod,Tab},N-1,Type). + +table_size(Tab) -> + 15 *table_factor(Tab). + +build_tables(Config,Type) -> + L = create_tables(Config), + ?dbgformat("Tables: ~p~n",[L]), + lists:foreach(fun(TD) -> + fill_table(TD,table_size(TD),Type) + end, + L), + L. + +destroy_tables([]) -> + ok; +destroy_tables([{ets,Tab}|T]) -> + ets:delete(Tab), + destroy_tables(T); +destroy_tables([{dets,Tab}|T]) -> + dets:close(Tab), + destroy_tables(T). + + +init_random(Config) -> + WriteDir = ReadDir = ?config(priv_dir,Config), + (catch file:make_dir(WriteDir)), + Seed = case file:consult(filename:join([ReadDir, + "preset_random_seed2.txt"])) of + {ok,[X]} -> + X; + _ -> + {A,B,C} = erlang:now(), + random:seed(A,B,C), + get(random_seed) + end, + put(random_seed,Seed), + {ok, F} = file:open(filename:join([WriteDir, "last_random_seed2.txt"]), + [write]), + io:format(F,"~p. ~n",[Seed]), + file:close(F), + ok. + +create_random_key(N,Type) -> + gen_key(random:uniform(N),Type). + +create_pb_key(N,list) -> + X = random:uniform(N), + case random:uniform(4) of + 3 -> {[X, X+1, '_'], fun([Z,Z1,P1]) -> + [Z,Z1,P1] =:= [X,X+1,P1] end}; + 2 -> {[X, '_', '_'], fun([Z,P1,P2]) -> [Z,P1,P2] =:= [X,P1,P2] end}; + 1 -> {[X, X+1, '$1'], fun([Z,Z1,P1]) -> + [Z,Z1,P1] =:= [X,X+1,P1] end}; + _ -> {[X, '$1', '$2'], fun([Z,P1,P2]) -> [Z,P1,P2] =:= [X,P1,P2] end} + end; +create_pb_key(N, tuple) -> + X = random:uniform(N), + case random:uniform(2) of + 1 -> {{X, X+1, '$1'},fun({Z,Z1,P1}) -> {Z,Z1,P1} =:= {X,X+1,P1} end}; + _ -> {{X, '$1', '$2'},fun({Z,P1,P2}) -> {Z,P1,P2} =:= {X,P1,P2} end} + end; +create_pb_key(N, complex) -> + X = random:uniform(N), + case random:uniform(2) of + 1 -> {{[X, X+1], '$1'}, fun({[Z,Z1],P1}) -> + {[Z,Z1],P1} =:= {[X,X+1],P1} end}; + _ -> {{[X, '$1'], '$2'},fun({[Z,P1],P2}) -> + {[Z,P1],P2} =:= {[X,P1],P2} end} + end. +table_foldl(_Fun, Acc,{_Mod,_Tab},'$end_of_table') -> + Acc; +table_foldl(Fun, Acc,{Mod,Tab},Key) -> + Objs = Mod:lookup(Tab,Key), + Acc2 = lists:foldl(Fun,Acc,Objs), + ?dbgformat("Objs: ~p, Acc2: ~p~n",[Objs,Acc2]), + table_foldl(Fun, Acc2, {Mod,Tab}, Mod:next(Tab,Key)). +table_foldl(Fun, Acc,{Mod,Tab}) -> + table_foldl(Fun, Acc,{Mod,Tab},Mod:first(Tab)). + +chunked_select(Mod,Tab,MS,0) -> + Mod:select(Tab,MS); +chunked_select(Mod,Tab,MS,Chunk) when Chunk > 0-> + do_chunk_select(Mod, Mod:select(Tab,MS,Chunk),[]); +chunked_select(Mod,Tab,MS,Chunk) when Chunk < 0-> + case Mod of + ets -> + do_chunk_select_reverse(Mod, + Mod:select_reverse(Tab,MS,-Chunk),[]); + _ -> + chunked_select(Mod,Tab,MS,-Chunk) + end. + + +do_chunk_select_reverse(_Mod, '$end_of_table',Acc) -> + %% OK, all this reversing is only needed for ordered_set, but + %% this is only testcases, right? + erlang:display(did_chunked_select_reverse), + Acc; +do_chunk_select_reverse(Mod, {L,C},Acc) -> + NewAcc = lists:reverse(L)++Acc, + do_chunk_select(Mod, Mod:select(C), NewAcc). + +do_chunk_select(_Mod, '$end_of_table',Acc) -> + %% OK, all this reversing is only needed for ordered_set, but + %% this is only testcases, right? + lists:reverse(Acc); +do_chunk_select(Mod, {L,C},Acc) -> + NewAcc = lists:reverse(L)++Acc, + do_chunk_select(Mod, Mod:select(C), NewAcc). + +cmp_ms_to_fun({Mod,Tab}, MS, Fun1, Fun2) -> + cmp_ms_to_fun({Mod,Tab}, MS, Fun1, Fun2, 0). + +cmp_ms_to_fun({Mod,Tab}, MS, Fun1, Fun2, ChunkSize) -> + MSRes = lists:sort(chunked_select(Mod,Tab,MS,ChunkSize)), + FunRes0 = table_foldl(Fun1,[],{Mod,Tab}), + FunRes = case Fun2 of + F when function(F) -> + FunRes1 = table_foldl(F,[],{Mod,Tab}), + lists:merge(FunRes0,FunRes1); + [] -> + lists:sort(FunRes0) + end, + case MSRes =:= FunRes of + true -> + true; + false -> + ?fmt("Match_spec result differs from fun result:~n",[]), + ?fmt("Parameters: ~p,~p,~p,~p~n", + [{Mod,Tab}, MS, Fun1, Fun2]), + ?fmt("Match_spec Result: ~p~n", [MSRes]), + ?fmt("Fun Result: ~p~n", [FunRes]), + Info = (catch Mod:info(Tab)), + ?fmt("Table info:~p~n", [Info]), + {'EXIT', {hej, ST}} = (catch erlang:error(hej)), + ?fmt("Stack backtrace: ~p~n", [ST]), + erlang:error(badmatch) + end. + +do_n(0,_) -> ok; +do_n(N,Fun) -> + Fun(), + do_n(N-1,Fun). + +%% +%% We want some misses too, so pretend the tables are slightly +%% larger than they really are. +%% +num_els(Tab) -> + 16 * table_factor(Tab). + + +test() -> + do_return_values(), + do_test([]). + +do_test(Config) -> + init_random(Config), + whitebox(), + lists:foreach(fun(Type) -> + Tabs = build_tables(Config,Type), + basic_key(Tabs,Type), + ?fmt("basic_key done for type ~w~n",[Type]), + basic_pb_key(Tabs,Type), + ?fmt("basic_pb_key done for type ~w~n",[Type]), + double_pb_key(Tabs,Type), + ?fmt("double_pb_key done for type ~w~n",[Type]), + multi_key(Tabs,Type), + ?fmt("multi_key done for type ~w~n",[Type]), + multi_mixed_key(Tabs,Type), + ?fmt("multi_mixed_key done for type ~w~n", + [Type]), + destroy_tables(Tabs) + end, + [tuple, list, complex]), + ok. + +basic_key(Tabs,Type) -> + Fun = fun() -> + lists:map(fun(Tab) -> + ?line Key = + create_random_key(num_els(Tab),Type), + ?line MS = + [{{Key,'_','_','_','_'},[],['$_']}], + MF = fun({Key0,A,B,F,Bi},Acc) -> + case Key =:= Key0 of + true -> + [{Key0,A,B,F,Bi} | + Acc]; + _ -> + Acc + end + end, + ?line cmp_ms_to_fun(Tab,MS,MF,[]) + end, + Tabs) + end, + ?line do_n(50,Fun), + ok. + +basic_pb_key(Tabs,Type) -> + InnerFun = fun(Tab) -> + ?line {Key,KeyFun} = + create_pb_key(num_els(Tab),Type), + ?line MS = [{{Key,'_','_','_','_'},[],['$_']}], + MF = fun({Key0,A,B,F,Bi},Acc) -> + case KeyFun(Key0) of + true -> + [{Key0,A,B,F,Bi} | + Acc]; + _ -> + Acc + end + end, + ?line cmp_ms_to_fun(Tab,MS,MF,[]) + end, + ?line {Etses, Detses} = split_by_type(Tabs), + + ?line FunEts = fun() -> + ?line lists:foreach(InnerFun, + Etses) + end, + ?line FunDets = fun() -> + ?line lists:foreach(InnerFun, + Detses) + end, + ?line do_n(table_factor(hd(Etses)) div 2,FunEts), + ?line do_n(10,FunDets), + ok. + +double_pb_key(Tabs,Type) -> + InnerFun = fun(Tab) -> + ?line {KeyA,KeyFunA} = + create_pb_key(num_els(Tab),Type), + ?line {KeyB,KeyFunB} = + create_pb_key(num_els(Tab),Type), + MS = [{{KeyA,'_','_','_','_'},[],['$_']}, + {{KeyB,'_','_','_','_'},[],['$_']}], + ?dbgformat("Tab: ~p, MS: ~p~n", + [Tab,MS]), + MF = fun({Key0,A,B,F,Bi},Acc) -> + case KeyFunA(Key0) of + true -> + ?dbgformat + ("FunMatched:" + " ~p~n", + [{Key0,A, + B,F,Bi}]), + [{Key0,A,B,F,Bi} | + Acc]; + _ -> + case KeyFunB(Key0) of + true -> + ?dbgformat + ("Fun" + "Matched:" + " ~p~n", + [{Key0,A, + B,F, + Bi}]), + [{Key0,A,B, + F,Bi} | + Acc]; + _ -> + Acc + end + end + end, + ?line cmp_ms_to_fun(Tab,MS,MF,[]) + end, + ?line {Etses, Detses} = split_by_type(Tabs), + + ?line FunEts = fun() -> + ?line lists:foreach(InnerFun, + Etses) + end, + ?line FunDets = fun() -> + ?line lists:foreach(InnerFun, + Detses) + end, + ?line do_n(table_factor(hd(Etses)) div 2,FunEts), + ?line do_n(10,FunDets), + ok. + + +multi_key(Tabs,Type) -> + Fun = fun() -> + lists:map(fun(Tab) -> + ?line KeyA = + create_random_key(num_els(Tab),Type), + ?line KeyB = + create_random_key(num_els(Tab),Type), + ?line KeyC = + create_random_key(num_els(Tab),Type), + ?line KeyD = + create_random_key(num_els(Tab),Type), + ?line KeyE = + create_random_key(num_els(Tab),Type), + ?line KeyF = + create_random_key(num_els(Tab),Type), + ?line KeyG = + create_random_key(num_els(Tab),Type), + ?line KeyH = + create_random_key(num_els(Tab),Type), + ?line KeyI = + create_random_key(num_els(Tab),Type), + ?line KeyJ = + create_random_key(num_els(Tab),Type), + ?line KeyK = + create_random_key(num_els(Tab),Type), + ?line KeyL = + create_random_key(num_els(Tab),Type), + + MS = [{{KeyA,'$1','_','$2','_'},[], + [{{'$1','$2'}}]}, + {{KeyB,'$1','_','$2','_'},[], + [{{'$1','$2'}}]}, + {{KeyC,'$1','_','$2','_'},[], + [{{'$1','$2'}}]}, + {{KeyD,'$1','_','$2','_'},[], + [{{'$1','$2'}}]}, + {{KeyE,'$1','_','$2','_'},[], + [{{'$1','$2'}}]}, + {{KeyF,'$1','_','$2','_'},[], + [{{'$1','$2'}}]}, + {{KeyG,'$1','_','$2','_'},[], + [{{'$1','$2'}}]}, + {{KeyH,'$1','_','$2','_'},[], + [{{'$1','$2'}}]}, + {{KeyI,'$1','_','$2','_'},[], + [{{'$1','$2'}}]}, + {{KeyJ,'$1','_','$2','_'},[], + [{{'$1','$2'}}]}, + {{KeyK,'$1','_','$2','_'},[], + [{{'$1','$2'}}]}, + {{KeyL,'$1','_','$2','_'},[], + [{{'$1','$2'}}]} + ], + ?dbgformat("Tab: ~p, MS: ~p~n", + [Tab,MS]), + MF = fun({Key0,A,_B,F,_Bi},Acc) -> + case Key0 of + KeyA -> + [ {A,F} | + Acc]; + KeyB -> + [ {A,F} | + Acc]; + KeyC -> + [ {A,F} | + Acc]; + KeyD -> + [ {A,F} | + Acc]; + KeyE -> + [ {A,F} | + Acc]; + KeyF -> + [ {A,F} | + Acc]; + KeyG -> + [ {A,F} | + Acc]; + KeyH -> + [ {A,F} | + Acc]; + KeyI -> + [ {A,F} | + Acc]; + KeyJ -> + [ {A,F} | + Acc]; + KeyK -> + [ {A,F} | + Acc]; + KeyL -> + [ {A,F} | + Acc]; + _ -> + Acc + end + end, + ?line cmp_ms_to_fun(Tab,MS,MF,[]) + end, + Tabs) + end, + ?line do_n(33,Fun), + ok. + +multi_mixed_key(Tabs,Type) -> + InnerFun = fun(Tab) -> + ?line KeyA = + create_random_key(num_els(Tab),Type), + ?line KeyB = + create_random_key(num_els(Tab),Type), + ?line KeyC = + create_random_key(num_els(Tab),Type), + ?line KeyD = + create_random_key(num_els(Tab),Type), + ?line {KeyE, FunE} = + create_pb_key(num_els(Tab),Type), + ?line KeyF = + create_random_key(num_els(Tab),Type), + ?line {KeyG, FunG} = + create_pb_key(num_els(Tab),Type), + ?line KeyH = + create_random_key(num_els(Tab),Type), + ?line KeyI = + create_random_key(num_els(Tab),Type), + ?line {KeyJ, FunJ} = + create_pb_key(num_els(Tab),Type), + ?line KeyK = + create_random_key(num_els(Tab),Type), + ?line KeyL = + create_random_key(num_els(Tab),Type), + + MS = [{{KeyA,'$1','_','$2','_'},[], + [{{'$1','$2'}}]}, + {{KeyB,'$1','_','$2','_'},[], + [{{'$1','$2'}}]}, + {{KeyC,'$1','_','$2','_'},[], + [{{'$1','$2'}}]}, + {{KeyD,'$1','_','$2','_'},[], + [{{'$1','$2'}}]}, + {{KeyE,'$100','_','$200','_'},[], + [{{'$100','$200'}}]}, + {{KeyF,'$1','_','$2','_'},[], + [{{'$1','$2'}}]}, + {{KeyG,'$100','_','$200','_'},[], + [{{'$100','$200'}}]}, + {{KeyH,'$1','_','$2','_'},[], + [{{'$1','$2'}}]}, + {{KeyI,'$1','_','$2','_'},[], + [{{'$1','$2'}}]}, + {{KeyJ,'$100','_','$200','_'},[], + [{{'$100','$200'}}]}, + {{KeyK,'$1','_','$2','_'},[], + [{{'$1','$2'}}]}, + {{KeyL,'$1','_','$2','_'},[], + [{{'$1','$2'}}]} + ], + ?dbgformat("Tab: ~p, MS: ~p~n", + [Tab,MS]), + MF = fun({Key0,A,_B,F,_Bi},Acc) -> + case Key0 of + KeyA -> + [ {A,F} | + Acc]; + KeyB -> + [ {A,F} | + Acc]; + KeyC -> + [ {A,F} | + Acc]; + KeyD -> + [ {A,F} | + Acc]; + KeyF -> + [ {A,F} | + Acc]; + KeyH -> + [ {A,F} | + Acc]; + KeyI -> + [ {A,F} | + Acc]; + KeyK -> + [ {A,F} | + Acc]; + KeyL -> + [ {A,F} | + Acc]; + Else -> + case FunE(Else) or + FunG(Else) or + FunJ(Else) of + true -> + [ {A,F} | + Acc]; + _ -> + Acc + end + end + end, + ?line cmp_ms_to_fun(Tab,MS,MF,[]), + ?line case Tab of + {ets,_} -> + ?line cmp_ms_to_fun(Tab,MS,MF,[],1), + ?line cmp_ms_to_fun(Tab,MS,MF,[],10), + ?line cmp_ms_to_fun(Tab,MS,MF,[],1000000), + ?line cmp_ms_to_fun(Tab,MS,MF,[],-1), + ?line cmp_ms_to_fun(Tab,MS,MF,[],-10), + ?line cmp_ms_to_fun(Tab,MS,MF,[],-1000000); + _ -> + ok + end + end, + ?line {Etses, Detses} = split_by_type(Tabs), + + ?line FunEts = fun() -> + ?line lists:foreach(InnerFun, + Etses) + end, + ?line FunDets = fun() -> + ?line lists:foreach(InnerFun, + Detses) + end, + ?line do_n(table_factor(hd(Etses)) div 2,FunEts), + ?line do_n(table_factor(hd(Detses)) div 2,FunDets), + ok. + + +split_by_type(List) -> + split_by_type(List,[],[]). +split_by_type([],AccEts,AccDets) -> + {AccEts,AccDets}; +split_by_type([{dets,Tab}|T],AccEts,AccDets) -> + split_by_type(T,AccEts,[{dets,Tab}|AccDets]); +split_by_type([{ets,Tab}|T],AccEts,AccDets) -> + split_by_type(T,[{ets,Tab}|AccEts],AccDets). + +whitebox() -> + ?line ets:new(xxx,[named_table, ordered_set]), + ?line ets:new(yyy,[named_table]), + ?line E = fun(0,_)->ok; + (N,F) -> + ?line ets:insert(xxx,{N,N rem 10}), + ?line ets:insert(yyy,{N,N rem 10}), + F(N-1,F) + end, + ?line E(10000,E), + + ?line G = fun(F,C,A) -> + ?line case ets:select(C) of + {L,C2} -> + ?line F(F,C2,A+length(L)); + '$end_of_table' -> + ?line A + end + end, + ?line H=fun({L,C}) -> + ?line G(G,C,length(L)) + end, + + ?line 1 = H(ets:select(xxx,[{{'$1','$2'},[{'<','$1',2}],['$_']}],7)), + ?line 10000 = H(ets:select(xxx,[{{'$1','$2'},[],['$_']}],1)), + ?line 1 = H(ets:select(yyy,[{{'$1','$2'},[{'<','$1',2}],['$_']}],7)), + ?line 10000 = H(ets:select(yyy,[{{'$1','$2'},[],['$_']}],1)), + + ?line {[{5,5}],_} = ets:select(xxx,[{{5,'$2'},[],['$_']}],1), + ?line {[{5,5}],_} = ets:select(yyy,[{{5,'$2'},[],['$_']}],1), + + ?line I = fun(_,0) -> + ok; + (I,N) -> + ?line 10000 = + H(ets:select(xxx,[{{'$1','$2'},[],['$_']}],N)), + I(I,N-1) + end, + ?line I(I,2000), + ?line J = fun(F,C,A) -> + ?line case ets:select(C) of + {L,C2} -> + ?line F(F,C2,lists:reverse(L)++A); + '$end_of_table' -> + ?line lists:reverse(A) + end + end, + ?line K = fun({L,C}) -> + ?line J(J,C,lists:reverse(L)) + end, + ?line M = fun(_, _, 0) -> + ok; + (F, What, N) -> + ?line What = + K(ets:select(xxx,[{{'$1','$2'},[],['$_']}],N)), + F(F, What, N-1) + end, + ?line N = fun(HM) -> + ?line What = ets:select(xxx,[{{'$1','$2'},[],['$_']}]), + ?line What = lists:sort(What), + M(M, What, HM) + end, + ?line N(2000), + ?line ets:delete(xxx), + ?line ets:delete(yyy). + + +do_return_values() -> + ?line T = ets:new(xxx,[ordered_set]), + ?line U = ets:new(xxx,[]), + ?line '$end_of_table' = ets:select(T,[{'_',[],['$_']}],1), + ?line '$end_of_table' = ets:select(U,[{'_',[],['$_']}],1), + ?line ets:insert(T,{ett,1}), + ?line ets:insert(U,{ett,1}), + ?line {[{ett,1}],C1} = ets:select(T,[{'_',[],['$_']}],1), + ?line '$end_of_table' = ets:select(C1), + ?line {[{ett,1}],C2} = ets:select(U,[{'_',[],['$_']}],1), + ?line '$end_of_table' = ets:select(C2), + ?line {[{ett,1}],C3} = ets:select(T,[{'_',[],['$_']}],2), + ?line '$end_of_table' = ets:select(C3), + ?line {[{ett,1}],C4} = ets:select(U,[{'_',[],['$_']}],2), + ?line '$end_of_table' = ets:select(C4), + ?line E = fun(0,_)->ok; + (N,F) -> + ?line ets:insert(T,{N,N rem 10}), + ?line ets:insert(U,{N,N rem 10}), + F(N-1,F) + end, + ?line E(10000,E), + ?line '$end_of_table' = ets:select(T,[{{hej, hopp},[],['$_']}],1), + ?line '$end_of_table' = ets:select(U,[{{hej,hopp},[],['$_']}],1), + ?line {[{ett,1}],CC1} = ets:select(T,[{{'$1','_'},[{is_atom, '$1'}], + ['$_']}],1), + ?line '$end_of_table' = ets:select(CC1), + ?line {[{ett,1}],CC2} = ets:select(U,[{{'$1','_'},[{is_atom, '$1'}], + ['$_']}],1), + ?line '$end_of_table' = ets:select(CC2), + ?line {[{ett,1}],CC3} = ets:select(T,[{{'$1','_'},[{is_atom, '$1'}], + ['$_']}],2), + ?line '$end_of_table' = ets:select(CC3), + ?line {[{ett,1}],CC4} = ets:select(U,[{{'$1','_'},[{is_atom, '$1'}], + ['$_']}],2), + ?line '$end_of_table' = ets:select(CC4), + ?line ets:delete(T), + ?line ets:delete(U), + ?line V = ets:new(xxx,[{keypos, 4}]), + ?line X = ets:new(xxx,[ordered_set, {keypos, 4}]), + ?line ets:insert(V,{1,1,1,ett}), + ?line ets:insert(X,{1,1,1,ett}), + ?line '$end_of_table' = ets:select(V,[{{1,1,1},[],['$_']}],1), + ?line '$end_of_table' = ets:select(X,[{{1,1,1},[],['$_']}],1), + ?line ets:delete(V), + ?line ets:delete(X), + ok. + + + + + |