1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 2000-2011. All Rights Reserved. 5: %% 6: %% The contents of this file are subject to the Erlang Public License, 7: %% Version 1.1, (the "License"); you may not use this file except in 8: %% compliance with the License. You should have received a copy of the 9: %% Erlang Public License along with this software. If not, it can be 10: %% retrieved online at http://www.erlang.org/. 11: %% 12: %% Software distributed under the License is distributed on an "AS IS" 13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 14: %% the License for the specific language governing rights and limitations 15: %% under the License. 16: %% 17: %% %CopyrightEnd% 18: %% 19: 20: -module(select_SUITE). 21: -author('pan@erix.ericsson.se'). 22: 23: -export([test/0]). 24: 25: %% 26: %% Define to run outside of test server 27: %% 28: %%-define(STANDALONE,1). 29: 30: %% 31: %% Define for debug output 32: %% 33: %%-define(debug,1). 34: 35: -ifdef(STANDALONE). 36: -define(config(A,B),config(A,B)). 37: -export([config/2]). 38: -define(fmt(A,B),io:format(A,B)). 39: -else. 40: -include_lib("test_server/include/test_server.hrl"). 41: -define(fmt(A,B),test_server:format(A,B)). 42: -endif. 43: 44: -ifdef(debug). 45: -ifdef(STANDALONE). 46: -define(line, erlang:display({?MODULE,?LINE}), ). 47: -endif. 48: -define(dbgformat(A,B),io:format(A,B)). 49: -else. 50: -ifdef(STANDALONE). 51: -define(line, noop, ). 52: -endif. 53: -define(dbgformat(A,B),noop). 54: -endif. 55: 56: -ifdef(STANDALONE). 57: config(priv_dir,_) -> 58: ".". 59: -else. 60: %% When run in test server. 61: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 62: init_per_group/2,end_per_group/2,select_test/1, 63: init_per_testcase/2, end_per_testcase/2, 64: return_values/1]). 65: 66: init_per_testcase(_Case, Config) when is_list(Config) -> 67: ?line Dog=test_server:timetrap(test_server:seconds(1200)), 68: [{watchdog, Dog}|Config]. 69: 70: end_per_testcase(_Case, Config) -> 71: Dog=?config(watchdog, Config), 72: test_server:timetrap_cancel(Dog), 73: ok. 74: 75: suite() -> [{ct_hooks,[ts_install_cth]}]. 76: 77: all() -> 78: [return_values, select_test]. 79: 80: groups() -> 81: []. 82: 83: init_per_suite(Config) -> 84: Config. 85: 86: end_per_suite(_Config) -> 87: ok. 88: 89: init_per_group(_GroupName, Config) -> 90: Config. 91: 92: end_per_group(_GroupName, Config) -> 93: Config. 94: 95: 96: select_test(suite) -> 97: []; 98: select_test(doc) -> 99: ["Tests select in numerous ways"]; 100: select_test(Config) when is_list(Config) -> 101: do_test(Config). 102: 103: return_values(suite) -> 104: []; 105: return_values(doc) -> 106: ["Tests return values in specific situations for select/3 and select/1"]; 107: return_values(Config) when is_list(Config) -> 108: do_return_values(). 109: 110: -endif. 111: 112: 113: table_factor({dets,_}) -> 114: 1; 115: table_factor({ets,_}) -> 116: 100. 117: 118: gen_dets_filename(Config,N) -> 119: filename:join(?config(priv_dir,Config), 120: "testdets_" ++ integer_to_list(N) ++ ".dets"). 121: 122: create_tables(Config) -> 123: Hash = ets:new(xxx, []), 124: Tree = ets:new(yyy, [ordered_set]), 125: Bag = ets:new(yyy, [bag]), 126: DBag = ets:new(yyy, [duplicate_bag]), 127: F1 = gen_dets_filename(Config,1), 128: (catch file:delete(F1)), 129: {ok,DetsPlain} = dets:open_file(testdets_1, 130: [{file, F1}]), 131: F3 = gen_dets_filename(Config,3), 132: (catch file:delete(F3)), 133: {ok,DetsBag} = dets:open_file(testdets_3, 134: [{file, F3},{type, bag}]), 135: F4 = gen_dets_filename(Config,4), 136: (catch file:delete(F4)), 137: {ok,DetsDBag} = dets:open_file(testdets_4, 138: [{file, F4},{type, duplicate_bag}]), 139: [{ets,Hash}, {ets,Tree}, {ets,Bag}, {ets,DBag}, 140: {dets, DetsPlain}, {dets, DetsBag}, {dets, DetsDBag}]. 141: 142: 143: gen_key(N,list) -> 144: [N,N+1,N+2]; 145: gen_key(N,tuple) -> 146: {N,N+1,N+2}; 147: gen_key(N,complex) -> 148: {[N,N+1],N+2}. 149: 150: gen_fun(N) -> 151: fun() -> 152: N 153: end. 154: 155: gen_bin(N) -> 156: list_to_binary(integer_to_list(N)). 157: 158: gen_object(N,Type) -> 159: L = integer_to_list(N), 160: A = list_to_atom("a" ++ L), 161: {gen_key(N,Type), L, A, gen_fun(N), gen_bin(N)}. 162: gen_object1(N,Type) -> 163: L = integer_to_list(N), 164: A = list_to_atom("a" ++ L), 165: {gen_key(N,Type), A, L, gen_fun(N), gen_bin(N)}. 166: 167: fill_table(_,0,_) -> 168: ok; 169: fill_table({Mod,Tab},N,Type) -> 170: Obj1 = gen_object1(N,Type), 171: Obj = gen_object(N,Type), 172: Mod:insert(Tab, Obj1), 173: case Mod:info(Tab,type) of 174: bag -> 175: Mod:insert(Tab, Obj); 176: duplicate_bag -> 177: Mod:insert(Tab, Obj), 178: Mod:insert(Tab, Obj1); 179: _ -> 180: ok 181: end, 182: fill_table({Mod,Tab},N-1,Type). 183: 184: table_size(Tab) -> 185: 15 *table_factor(Tab). 186: 187: build_tables(Config,Type) -> 188: L = create_tables(Config), 189: ?dbgformat("Tables: ~p~n",[L]), 190: lists:foreach(fun(TD) -> 191: fill_table(TD,table_size(TD),Type) 192: end, 193: L), 194: L. 195: 196: destroy_tables([]) -> 197: ok; 198: destroy_tables([{ets,Tab}|T]) -> 199: ets:delete(Tab), 200: destroy_tables(T); 201: destroy_tables([{dets,Tab}|T]) -> 202: dets:close(Tab), 203: destroy_tables(T). 204: 205: 206: init_random(Config) -> 207: WriteDir = ReadDir = ?config(priv_dir,Config), 208: (catch file:make_dir(WriteDir)), 209: Seed = case file:consult(filename:join([ReadDir, 210: "preset_random_seed2.txt"])) of 211: {ok,[X]} -> 212: X; 213: _ -> 214: {A,B,C} = erlang:now(), 215: random:seed(A,B,C), 216: get(random_seed) 217: end, 218: put(random_seed,Seed), 219: {ok, F} = file:open(filename:join([WriteDir, "last_random_seed2.txt"]), 220: [write]), 221: io:format(F,"~p. ~n",[Seed]), 222: file:close(F), 223: ok. 224: 225: create_random_key(N,Type) -> 226: gen_key(random:uniform(N),Type). 227: 228: create_pb_key(N,list) -> 229: X = random:uniform(N), 230: case random:uniform(4) of 231: 3 -> {[X, X+1, '_'], fun([Z,Z1,P1]) -> 232: [Z,Z1,P1] =:= [X,X+1,P1] end}; 233: 2 -> {[X, '_', '_'], fun([Z,P1,P2]) -> [Z,P1,P2] =:= [X,P1,P2] end}; 234: 1 -> {[X, X+1, '$1'], fun([Z,Z1,P1]) -> 235: [Z,Z1,P1] =:= [X,X+1,P1] end}; 236: _ -> {[X, '$1', '$2'], fun([Z,P1,P2]) -> [Z,P1,P2] =:= [X,P1,P2] end} 237: end; 238: create_pb_key(N, tuple) -> 239: X = random:uniform(N), 240: case random:uniform(2) of 241: 1 -> {{X, X+1, '$1'},fun({Z,Z1,P1}) -> {Z,Z1,P1} =:= {X,X+1,P1} end}; 242: _ -> {{X, '$1', '$2'},fun({Z,P1,P2}) -> {Z,P1,P2} =:= {X,P1,P2} end} 243: end; 244: create_pb_key(N, complex) -> 245: X = random:uniform(N), 246: case random:uniform(2) of 247: 1 -> {{[X, X+1], '$1'}, fun({[Z,Z1],P1}) -> 248: {[Z,Z1],P1} =:= {[X,X+1],P1} end}; 249: _ -> {{[X, '$1'], '$2'},fun({[Z,P1],P2}) -> 250: {[Z,P1],P2} =:= {[X,P1],P2} end} 251: end. 252: table_foldl(_Fun, Acc,{_Mod,_Tab},'$end_of_table') -> 253: Acc; 254: table_foldl(Fun, Acc,{Mod,Tab},Key) -> 255: Objs = Mod:lookup(Tab,Key), 256: Acc2 = lists:foldl(Fun,Acc,Objs), 257: ?dbgformat("Objs: ~p, Acc2: ~p~n",[Objs,Acc2]), 258: table_foldl(Fun, Acc2, {Mod,Tab}, Mod:next(Tab,Key)). 259: table_foldl(Fun, Acc,{Mod,Tab}) -> 260: table_foldl(Fun, Acc,{Mod,Tab},Mod:first(Tab)). 261: 262: chunked_select(Mod,Tab,MS,0) -> 263: Mod:select(Tab,MS); 264: chunked_select(Mod,Tab,MS,Chunk) when Chunk > 0-> 265: do_chunk_select(Mod, Mod:select(Tab,MS,Chunk),[]); 266: chunked_select(Mod,Tab,MS,Chunk) when Chunk < 0-> 267: case Mod of 268: ets -> 269: do_chunk_select_reverse(Mod, 270: Mod:select_reverse(Tab,MS,-Chunk),[]); 271: _ -> 272: chunked_select(Mod,Tab,MS,-Chunk) 273: end. 274: 275: 276: do_chunk_select_reverse(_Mod, '$end_of_table',Acc) -> 277: %% OK, all this reversing is only needed for ordered_set, but 278: %% this is only testcases, right? 279: erlang:display(did_chunked_select_reverse), 280: Acc; 281: do_chunk_select_reverse(Mod, {L,C},Acc) -> 282: NewAcc = lists:reverse(L)++Acc, 283: do_chunk_select(Mod, Mod:select(C), NewAcc). 284: 285: do_chunk_select(_Mod, '$end_of_table',Acc) -> 286: %% OK, all this reversing is only needed for ordered_set, but 287: %% this is only testcases, right? 288: lists:reverse(Acc); 289: do_chunk_select(Mod, {L,C},Acc) -> 290: NewAcc = lists:reverse(L)++Acc, 291: do_chunk_select(Mod, Mod:select(C), NewAcc). 292: 293: cmp_ms_to_fun({Mod,Tab}, MS, Fun1, Fun2) -> 294: cmp_ms_to_fun({Mod,Tab}, MS, Fun1, Fun2, 0). 295: 296: cmp_ms_to_fun({Mod,Tab}, MS, Fun1, Fun2, ChunkSize) -> 297: MSRes = lists:sort(chunked_select(Mod,Tab,MS,ChunkSize)), 298: FunRes0 = table_foldl(Fun1,[],{Mod,Tab}), 299: FunRes = case Fun2 of 300: F when is_function(F) -> 301: FunRes1 = table_foldl(F,[],{Mod,Tab}), 302: lists:merge(FunRes0,FunRes1); 303: [] -> 304: lists:sort(FunRes0) 305: end, 306: case MSRes =:= FunRes of 307: true -> 308: true; 309: false -> 310: ?fmt("Match_spec result differs from fun result:~n",[]), 311: ?fmt("Parameters: ~p,~p,~p,~p~n", 312: [{Mod,Tab}, MS, Fun1, Fun2]), 313: ?fmt("Match_spec Result: ~p~n", [MSRes]), 314: ?fmt("Fun Result: ~p~n", [FunRes]), 315: Info = (catch Mod:info(Tab)), 316: ?fmt("Table info:~p~n", [Info]), 317: {'EXIT', {hej, ST}} = (catch erlang:error(hej)), 318: ?fmt("Stack backtrace: ~p~n", [ST]), 319: erlang:error(badmatch) 320: end. 321: 322: do_n(0,_) -> ok; 323: do_n(N,Fun) -> 324: Fun(), 325: do_n(N-1,Fun). 326: 327: %% 328: %% We want some misses too, so pretend the tables are slightly 329: %% larger than they really are. 330: %% 331: num_els(Tab) -> 332: 16 * table_factor(Tab). 333: 334: 335: test() -> 336: do_return_values(), 337: do_test([]). 338: 339: do_test(Config) -> 340: init_random(Config), 341: whitebox(), 342: lists:foreach(fun(Type) -> 343: Tabs = build_tables(Config,Type), 344: basic_key(Tabs,Type), 345: ?fmt("basic_key done for type ~w~n",[Type]), 346: basic_pb_key(Tabs,Type), 347: ?fmt("basic_pb_key done for type ~w~n",[Type]), 348: double_pb_key(Tabs,Type), 349: ?fmt("double_pb_key done for type ~w~n",[Type]), 350: multi_key(Tabs,Type), 351: ?fmt("multi_key done for type ~w~n",[Type]), 352: multi_mixed_key(Tabs,Type), 353: ?fmt("multi_mixed_key done for type ~w~n", 354: [Type]), 355: destroy_tables(Tabs) 356: end, 357: [tuple, list, complex]), 358: ok. 359: 360: basic_key(Tabs,Type) -> 361: Fun = fun() -> 362: lists:map(fun(Tab) -> 363: ?line Key = 364: create_random_key(num_els(Tab),Type), 365: ?line MS = 366: [{{Key,'_','_','_','_'},[],['$_']}], 367: MF = fun({Key0,A,B,F,Bi},Acc) -> 368: case Key =:= Key0 of 369: true -> 370: [{Key0,A,B,F,Bi} | 371: Acc]; 372: _ -> 373: Acc 374: end 375: end, 376: ?line cmp_ms_to_fun(Tab,MS,MF,[]) 377: end, 378: Tabs) 379: end, 380: ?line do_n(50,Fun), 381: ok. 382: 383: basic_pb_key(Tabs,Type) -> 384: InnerFun = fun(Tab) -> 385: ?line {Key,KeyFun} = 386: create_pb_key(num_els(Tab),Type), 387: ?line MS = [{{Key,'_','_','_','_'},[],['$_']}], 388: MF = fun({Key0,A,B,F,Bi},Acc) -> 389: case KeyFun(Key0) of 390: true -> 391: [{Key0,A,B,F,Bi} | 392: Acc]; 393: _ -> 394: Acc 395: end 396: end, 397: ?line cmp_ms_to_fun(Tab,MS,MF,[]) 398: end, 399: ?line {Etses, Detses} = split_by_type(Tabs), 400: 401: ?line FunEts = fun() -> 402: ?line lists:foreach(InnerFun, 403: Etses) 404: end, 405: ?line FunDets = fun() -> 406: ?line lists:foreach(InnerFun, 407: Detses) 408: end, 409: ?line do_n(table_factor(hd(Etses)) div 2,FunEts), 410: ?line do_n(10,FunDets), 411: ok. 412: 413: double_pb_key(Tabs,Type) -> 414: InnerFun = fun(Tab) -> 415: ?line {KeyA,KeyFunA} = 416: create_pb_key(num_els(Tab),Type), 417: ?line {KeyB,KeyFunB} = 418: create_pb_key(num_els(Tab),Type), 419: MS = [{{KeyA,'_','_','_','_'},[],['$_']}, 420: {{KeyB,'_','_','_','_'},[],['$_']}], 421: ?dbgformat("Tab: ~p, MS: ~p~n", 422: [Tab,MS]), 423: MF = fun({Key0,A,B,F,Bi},Acc) -> 424: case KeyFunA(Key0) of 425: true -> 426: ?dbgformat 427: ("FunMatched:" 428: " ~p~n", 429: [{Key0,A, 430: B,F,Bi}]), 431: [{Key0,A,B,F,Bi} | 432: Acc]; 433: _ -> 434: case KeyFunB(Key0) of 435: true -> 436: ?dbgformat 437: ("Fun" 438: "Matched:" 439: " ~p~n", 440: [{Key0,A, 441: B,F, 442: Bi}]), 443: [{Key0,A,B, 444: F,Bi} | 445: Acc]; 446: _ -> 447: Acc 448: end 449: end 450: end, 451: ?line cmp_ms_to_fun(Tab,MS,MF,[]) 452: end, 453: ?line {Etses, Detses} = split_by_type(Tabs), 454: 455: ?line FunEts = fun() -> 456: ?line lists:foreach(InnerFun, 457: Etses) 458: end, 459: ?line FunDets = fun() -> 460: ?line lists:foreach(InnerFun, 461: Detses) 462: end, 463: ?line do_n(table_factor(hd(Etses)) div 2,FunEts), 464: ?line do_n(10,FunDets), 465: ok. 466: 467: 468: multi_key(Tabs,Type) -> 469: Fun = fun() -> 470: lists:map(fun(Tab) -> 471: ?line KeyA = 472: create_random_key(num_els(Tab),Type), 473: ?line KeyB = 474: create_random_key(num_els(Tab),Type), 475: ?line KeyC = 476: create_random_key(num_els(Tab),Type), 477: ?line KeyD = 478: create_random_key(num_els(Tab),Type), 479: ?line KeyE = 480: create_random_key(num_els(Tab),Type), 481: ?line KeyF = 482: create_random_key(num_els(Tab),Type), 483: ?line KeyG = 484: create_random_key(num_els(Tab),Type), 485: ?line KeyH = 486: create_random_key(num_els(Tab),Type), 487: ?line KeyI = 488: create_random_key(num_els(Tab),Type), 489: ?line KeyJ = 490: create_random_key(num_els(Tab),Type), 491: ?line KeyK = 492: create_random_key(num_els(Tab),Type), 493: ?line KeyL = 494: create_random_key(num_els(Tab),Type), 495: 496: MS = [{{KeyA,'$1','_','$2','_'},[], 497: [{{'$1','$2'}}]}, 498: {{KeyB,'$1','_','$2','_'},[], 499: [{{'$1','$2'}}]}, 500: {{KeyC,'$1','_','$2','_'},[], 501: [{{'$1','$2'}}]}, 502: {{KeyD,'$1','_','$2','_'},[], 503: [{{'$1','$2'}}]}, 504: {{KeyE,'$1','_','$2','_'},[], 505: [{{'$1','$2'}}]}, 506: {{KeyF,'$1','_','$2','_'},[], 507: [{{'$1','$2'}}]}, 508: {{KeyG,'$1','_','$2','_'},[], 509: [{{'$1','$2'}}]}, 510: {{KeyH,'$1','_','$2','_'},[], 511: [{{'$1','$2'}}]}, 512: {{KeyI,'$1','_','$2','_'},[], 513: [{{'$1','$2'}}]}, 514: {{KeyJ,'$1','_','$2','_'},[], 515: [{{'$1','$2'}}]}, 516: {{KeyK,'$1','_','$2','_'},[], 517: [{{'$1','$2'}}]}, 518: {{KeyL,'$1','_','$2','_'},[], 519: [{{'$1','$2'}}]} 520: ], 521: ?dbgformat("Tab: ~p, MS: ~p~n", 522: [Tab,MS]), 523: MF = fun({Key0,A,_B,F,_Bi},Acc) -> 524: case Key0 of 525: KeyA -> 526: [ {A,F} | 527: Acc]; 528: KeyB -> 529: [ {A,F} | 530: Acc]; 531: KeyC -> 532: [ {A,F} | 533: Acc]; 534: KeyD -> 535: [ {A,F} | 536: Acc]; 537: KeyE -> 538: [ {A,F} | 539: Acc]; 540: KeyF -> 541: [ {A,F} | 542: Acc]; 543: KeyG -> 544: [ {A,F} | 545: Acc]; 546: KeyH -> 547: [ {A,F} | 548: Acc]; 549: KeyI -> 550: [ {A,F} | 551: Acc]; 552: KeyJ -> 553: [ {A,F} | 554: Acc]; 555: KeyK -> 556: [ {A,F} | 557: Acc]; 558: KeyL -> 559: [ {A,F} | 560: Acc]; 561: _ -> 562: Acc 563: end 564: end, 565: ?line cmp_ms_to_fun(Tab,MS,MF,[]) 566: end, 567: Tabs) 568: end, 569: ?line do_n(33,Fun), 570: ok. 571: 572: multi_mixed_key(Tabs,Type) -> 573: InnerFun = fun(Tab) -> 574: ?line KeyA = 575: create_random_key(num_els(Tab),Type), 576: ?line KeyB = 577: create_random_key(num_els(Tab),Type), 578: ?line KeyC = 579: create_random_key(num_els(Tab),Type), 580: ?line KeyD = 581: create_random_key(num_els(Tab),Type), 582: ?line {KeyE, FunE} = 583: create_pb_key(num_els(Tab),Type), 584: ?line KeyF = 585: create_random_key(num_els(Tab),Type), 586: ?line {KeyG, FunG} = 587: create_pb_key(num_els(Tab),Type), 588: ?line KeyH = 589: create_random_key(num_els(Tab),Type), 590: ?line KeyI = 591: create_random_key(num_els(Tab),Type), 592: ?line {KeyJ, FunJ} = 593: create_pb_key(num_els(Tab),Type), 594: ?line KeyK = 595: create_random_key(num_els(Tab),Type), 596: ?line KeyL = 597: create_random_key(num_els(Tab),Type), 598: 599: MS = [{{KeyA,'$1','_','$2','_'},[], 600: [{{'$1','$2'}}]}, 601: {{KeyB,'$1','_','$2','_'},[], 602: [{{'$1','$2'}}]}, 603: {{KeyC,'$1','_','$2','_'},[], 604: [{{'$1','$2'}}]}, 605: {{KeyD,'$1','_','$2','_'},[], 606: [{{'$1','$2'}}]}, 607: {{KeyE,'$100','_','$200','_'},[], 608: [{{'$100','$200'}}]}, 609: {{KeyF,'$1','_','$2','_'},[], 610: [{{'$1','$2'}}]}, 611: {{KeyG,'$100','_','$200','_'},[], 612: [{{'$100','$200'}}]}, 613: {{KeyH,'$1','_','$2','_'},[], 614: [{{'$1','$2'}}]}, 615: {{KeyI,'$1','_','$2','_'},[], 616: [{{'$1','$2'}}]}, 617: {{KeyJ,'$100','_','$200','_'},[], 618: [{{'$100','$200'}}]}, 619: {{KeyK,'$1','_','$2','_'},[], 620: [{{'$1','$2'}}]}, 621: {{KeyL,'$1','_','$2','_'},[], 622: [{{'$1','$2'}}]} 623: ], 624: ?dbgformat("Tab: ~p, MS: ~p~n", 625: [Tab,MS]), 626: MF = fun({Key0,A,_B,F,_Bi},Acc) -> 627: case Key0 of 628: KeyA -> 629: [ {A,F} | 630: Acc]; 631: KeyB -> 632: [ {A,F} | 633: Acc]; 634: KeyC -> 635: [ {A,F} | 636: Acc]; 637: KeyD -> 638: [ {A,F} | 639: Acc]; 640: KeyF -> 641: [ {A,F} | 642: Acc]; 643: KeyH -> 644: [ {A,F} | 645: Acc]; 646: KeyI -> 647: [ {A,F} | 648: Acc]; 649: KeyK -> 650: [ {A,F} | 651: Acc]; 652: KeyL -> 653: [ {A,F} | 654: Acc]; 655: Else -> 656: case FunE(Else) or 657: FunG(Else) or 658: FunJ(Else) of 659: true -> 660: [ {A,F} | 661: Acc]; 662: _ -> 663: Acc 664: end 665: end 666: end, 667: ?line cmp_ms_to_fun(Tab,MS,MF,[]), 668: ?line case Tab of 669: {ets,_} -> 670: ?line cmp_ms_to_fun(Tab,MS,MF,[],1), 671: ?line cmp_ms_to_fun(Tab,MS,MF,[],10), 672: ?line cmp_ms_to_fun(Tab,MS,MF,[],1000000), 673: ?line cmp_ms_to_fun(Tab,MS,MF,[],-1), 674: ?line cmp_ms_to_fun(Tab,MS,MF,[],-10), 675: ?line cmp_ms_to_fun(Tab,MS,MF,[],-1000000); 676: _ -> 677: ok 678: end 679: end, 680: ?line {Etses, Detses} = split_by_type(Tabs), 681: 682: ?line FunEts = fun() -> 683: ?line lists:foreach(InnerFun, 684: Etses) 685: end, 686: ?line FunDets = fun() -> 687: ?line lists:foreach(InnerFun, 688: Detses) 689: end, 690: ?line do_n(table_factor(hd(Etses)) div 2,FunEts), 691: ?line do_n(table_factor(hd(Detses)) div 2,FunDets), 692: ok. 693: 694: 695: split_by_type(List) -> 696: split_by_type(List,[],[]). 697: split_by_type([],AccEts,AccDets) -> 698: {AccEts,AccDets}; 699: split_by_type([{dets,Tab}|T],AccEts,AccDets) -> 700: split_by_type(T,AccEts,[{dets,Tab}|AccDets]); 701: split_by_type([{ets,Tab}|T],AccEts,AccDets) -> 702: split_by_type(T,[{ets,Tab}|AccEts],AccDets). 703: 704: whitebox() -> 705: ?line ets:new(xxx,[named_table, ordered_set]), 706: ?line ets:new(yyy,[named_table]), 707: ?line E = fun(0,_)->ok; 708: (N,F) -> 709: ?line ets:insert(xxx,{N,N rem 10}), 710: ?line ets:insert(yyy,{N,N rem 10}), 711: F(N-1,F) 712: end, 713: ?line E(10000,E), 714: 715: ?line G = fun(F,C,A) -> 716: ?line case ets:select(C) of 717: {L,C2} -> 718: ?line F(F,C2,A+length(L)); 719: '$end_of_table' -> 720: ?line A 721: end 722: end, 723: ?line H=fun({L,C}) -> 724: ?line G(G,C,length(L)) 725: end, 726: 727: ?line 1 = H(ets:select(xxx,[{{'$1','$2'},[{'<','$1',2}],['$_']}],7)), 728: ?line 10000 = H(ets:select(xxx,[{{'$1','$2'},[],['$_']}],1)), 729: ?line 1 = H(ets:select(yyy,[{{'$1','$2'},[{'<','$1',2}],['$_']}],7)), 730: ?line 10000 = H(ets:select(yyy,[{{'$1','$2'},[],['$_']}],1)), 731: 732: ?line {[{5,5}],_} = ets:select(xxx,[{{5,'$2'},[],['$_']}],1), 733: ?line {[{5,5}],_} = ets:select(yyy,[{{5,'$2'},[],['$_']}],1), 734: 735: ?line I = fun(_,0) -> 736: ok; 737: (I,N) -> 738: ?line 10000 = 739: H(ets:select(xxx,[{{'$1','$2'},[],['$_']}],N)), 740: I(I,N-1) 741: end, 742: ?line I(I,2000), 743: ?line J = fun(F,C,A) -> 744: ?line case ets:select(C) of 745: {L,C2} -> 746: ?line F(F,C2,lists:reverse(L)++A); 747: '$end_of_table' -> 748: ?line lists:reverse(A) 749: end 750: end, 751: ?line K = fun({L,C}) -> 752: ?line J(J,C,lists:reverse(L)) 753: end, 754: ?line M = fun(_, _, 0) -> 755: ok; 756: (F, What, N) -> 757: ?line What = 758: K(ets:select(xxx,[{{'$1','$2'},[],['$_']}],N)), 759: F(F, What, N-1) 760: end, 761: ?line N = fun(HM) -> 762: ?line What = ets:select(xxx,[{{'$1','$2'},[],['$_']}]), 763: ?line What = lists:sort(What), 764: M(M, What, HM) 765: end, 766: ?line N(2000), 767: ?line ets:delete(xxx), 768: ?line ets:delete(yyy). 769: 770: 771: do_return_values() -> 772: ?line T = ets:new(xxx,[ordered_set]), 773: ?line U = ets:new(xxx,[]), 774: ?line '$end_of_table' = ets:select(T,[{'_',[],['$_']}],1), 775: ?line '$end_of_table' = ets:select(U,[{'_',[],['$_']}],1), 776: ?line ets:insert(T,{ett,1}), 777: ?line ets:insert(U,{ett,1}), 778: ?line {[{ett,1}],C1} = ets:select(T,[{'_',[],['$_']}],1), 779: ?line '$end_of_table' = ets:select(C1), 780: ?line {[{ett,1}],C2} = ets:select(U,[{'_',[],['$_']}],1), 781: ?line '$end_of_table' = ets:select(C2), 782: ?line {[{ett,1}],C3} = ets:select(T,[{'_',[],['$_']}],2), 783: ?line '$end_of_table' = ets:select(C3), 784: ?line {[{ett,1}],C4} = ets:select(U,[{'_',[],['$_']}],2), 785: ?line '$end_of_table' = ets:select(C4), 786: ?line E = fun(0,_)->ok; 787: (N,F) -> 788: ?line ets:insert(T,{N,N rem 10}), 789: ?line ets:insert(U,{N,N rem 10}), 790: F(N-1,F) 791: end, 792: ?line E(10000,E), 793: ?line '$end_of_table' = ets:select(T,[{{hej, hopp},[],['$_']}],1), 794: ?line '$end_of_table' = ets:select(U,[{{hej,hopp},[],['$_']}],1), 795: ?line {[{ett,1}],CC1} = ets:select(T,[{{'$1','_'},[{is_atom, '$1'}], 796: ['$_']}],1), 797: ?line '$end_of_table' = ets:select(CC1), 798: ?line {[{ett,1}],CC2} = ets:select(U,[{{'$1','_'},[{is_atom, '$1'}], 799: ['$_']}],1), 800: ?line '$end_of_table' = ets:select(CC2), 801: ?line {[{ett,1}],CC3} = ets:select(T,[{{'$1','_'},[{is_atom, '$1'}], 802: ['$_']}],2), 803: ?line '$end_of_table' = ets:select(CC3), 804: ?line {[{ett,1}],CC4} = ets:select(U,[{{'$1','_'},[{is_atom, '$1'}], 805: ['$_']}],2), 806: ?line '$end_of_table' = ets:select(CC4), 807: ?line ets:delete(T), 808: ?line ets:delete(U), 809: ?line V = ets:new(xxx,[{keypos, 4}]), 810: ?line X = ets:new(xxx,[ordered_set, {keypos, 4}]), 811: ?line ets:insert(V,{1,1,1,ett}), 812: ?line ets:insert(X,{1,1,1,ett}), 813: ?line '$end_of_table' = ets:select(V,[{{1,1,1},[],['$_']}],1), 814: ?line '$end_of_table' = ets:select(X,[{{1,1,1},[],['$_']}],1), 815: ?line ets:delete(V), 816: ?line ets:delete(X), 817: ok. 818: 819: 820: 821: 822: