1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 1997-2013. 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: %%% Purpose: Test suite for the 'lists' module. 21: %%%----------------------------------------------------------------- 22: 23: -module(lists_SUITE). 24: -include_lib("test_server/include/test_server.hrl"). 25: 26: 27: % Default timetrap timeout (set in init_per_testcase). 28: % This should be set relatively high (10-15 times the expected 29: % max testcasetime). 30: -define(default_timeout, ?t:minutes(4)). 31: 32: % Test server specific exports 33: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 34: init_per_group/2,end_per_group/2]). 35: -export([init_per_testcase/2, end_per_testcase/2]). 36: 37: % Test cases must be exported. 38: -export([member/1, reverse/1, 39: keymember/1, keysearch_keyfind/1, 40: keystore/1, keytake/1, 41: append_1/1, append_2/1, 42: seq_loop/1, seq_2/1, seq_3/1, seq_2_e/1, seq_3_e/1, 43: 44: sublist_2/1, sublist_3/1, sublist_2_e/1, sublist_3_e/1, 45: flatten_1/1, flatten_2/1, flatten_1_e/1, flatten_2_e/1, 46: dropwhile/1, 47: sort_1/1, sort_stable/1, merge/1, rmerge/1, sort_rand/1, 48: usort_1/1, usort_stable/1, umerge/1, rumerge/1,usort_rand/1, 49: keymerge/1, rkeymerge/1, 50: keysort_1/1, keysort_i/1, keysort_stable/1, 51: keysort_rand/1, keysort_error/1, 52: ukeymerge/1, rukeymerge/1, 53: ukeysort_1/1, ukeysort_i/1, ukeysort_stable/1, 54: ukeysort_rand/1, ukeysort_error/1, 55: funmerge/1, rfunmerge/1, 56: funsort_1/1, funsort_stable/1, funsort_rand/1, 57: funsort_error/1, 58: ufunmerge/1, rufunmerge/1, 59: ufunsort_1/1, ufunsort_stable/1, ufunsort_rand/1, 60: ufunsort_error/1, 61: zip_unzip/1, zip_unzip3/1, zipwith/1, zipwith3/1, 62: filter_partition/1, 63: otp_5939/1, otp_6023/1, otp_6606/1, otp_7230/1, 64: suffix/1, subtract/1]). 65: 66: %% Sort randomized lists until stopped. 67: %% 68: %% If you update some of the sort or merge functions, you should 69: %% definitely let sort_loop work for a couple of hours or days. Try 70: %% both sort_loop/0 and sort_loop/1 with a small argument (30-50 say). 71: 72: -export([sort_loop/0, sort_loop/1, sloop/1]). 73: 74: %% Internal export. 75: -export([make_fun/1]). 76: 77: %% 78: %% all/1 79: %% 80: suite() -> [{ct_hooks,[ts_install_cth]}]. 81: 82: all() -> 83: [{group, append}, reverse, member, keymember, 84: keysearch_keyfind, keystore, keytake, dropwhile, {group,sort}, 85: {group, usort}, {group, keysort}, {group, ukeysort}, 86: {group, funsort}, {group, ufunsort}, {group, sublist}, 87: {group, flatten}, {group, seq}, zip_unzip, zip_unzip3, 88: zipwith, zipwith3, filter_partition, {group, tickets}, 89: suffix, subtract]. 90: 91: groups() -> 92: [{append, [], [append_1, append_2]}, 93: {usort, [], 94: [umerge, rumerge, usort_1, usort_rand, usort_stable]}, 95: {keysort, [], 96: [keymerge, rkeymerge, keysort_1, keysort_rand, 97: keysort_i, keysort_stable, keysort_error]}, 98: {sort,[],[merge, rmerge, sort_1, sort_rand]}, 99: {ukeysort, [], 100: [ukeymerge, rukeymerge, ukeysort_1, ukeysort_rand, 101: ukeysort_i, ukeysort_stable, ukeysort_error]}, 102: {funsort, [], 103: [funmerge, rfunmerge, funsort_1, funsort_stable, 104: funsort_error, funsort_rand]}, 105: {ufunsort, [], 106: [ufunmerge, rufunmerge, ufunsort_1, ufunsort_stable, 107: ufunsort_error, ufunsort_rand]}, 108: {seq, [], [seq_loop, seq_2, seq_3, seq_2_e, seq_3_e]}, 109: {sublist, [], 110: [sublist_2, sublist_3, sublist_2_e, sublist_3_e]}, 111: {flatten, [], 112: [flatten_1, flatten_2, flatten_1_e, flatten_2_e]}, 113: {tickets, [], [otp_5939, otp_6023, otp_6606, otp_7230]}]. 114: 115: init_per_suite(Config) -> 116: Config. 117: 118: end_per_suite(_Config) -> 119: ok. 120: 121: init_per_group(_GroupName, Config) -> 122: Config. 123: 124: end_per_group(_GroupName, Config) -> 125: Config. 126: 127: 128: init_per_testcase(_Case, Config) -> 129: ?line Dog=test_server:timetrap(?default_timeout), 130: [{watchdog, Dog}|Config]. 131: 132: end_per_testcase(_Case, Config) -> 133: Dog=?config(watchdog, Config), 134: test_server:timetrap_cancel(Dog), 135: ok. 136: 137: % 138: % Test cases starts here. 139: % 140: 141: append_1(doc) -> []; 142: append_1(suite) -> []; 143: append_1(Config) when is_list(Config) -> 144: ?line "abcdef"=lists:append(["abc","def"]), 145: ?line [hej, du,[glade, [bagare]]]= 146: lists:append([[hej], [du], [[glade, [bagare]]]]), 147: ?line [10, [elem]]=lists:append([[10], [[elem]]]), 148: ok. 149: 150: append_2(doc) -> []; 151: append_2(suite) -> []; 152: append_2(Config) when is_list(Config) -> 153: ?line "abcdef"=lists:append("abc", "def"), 154: ?line [hej, du]=lists:append([hej], [du]), 155: ?line [10, [elem]]=lists:append([10], [[elem]]), 156: ok. 157: 158: reverse(suite) -> 159: []; 160: reverse(doc) -> 161: ["Tests the lists:reverse() implementation. The function is " 162: "`non-blocking', and only processes a fixed number of elements " 163: "at a time."]; 164: reverse(Config) when is_list(Config) -> 165: ?line reverse_test(0), 166: ?line reverse_test(1), 167: ?line reverse_test(2), 168: ?line reverse_test(128), 169: ?line reverse_test(256), 170: ?line reverse_test(1000), 171: ?line reverse_test(1998), 172: ?line reverse_test(1999), 173: ?line reverse_test(2000), 174: ?line reverse_test(2001), 175: ?line reverse_test(3998), 176: ?line reverse_test(3999), 177: ?line reverse_test(4000), 178: ?line reverse_test(4001), 179: ?line reverse_test(60001), 180: ?line reverse_test(100007), 181: ok. 182: 183: reverse_test(0) -> 184: case lists:reverse([]) of 185: [] -> 186: ok; 187: _Other -> 188: error 189: end; 190: reverse_test(Num) -> 191: List0 = ['The Element'|lists:duplicate(Num, 'Ele')], 192: List = lists:reverse(List0), 193: ['Ele'|_] = List, 194: 'The Element' = lists:last(List), 195: List0 = lists:reverse(List), 196: ok. 197: 198: member(doc) -> 199: ["Tests the lists:member() implementation." 200: "This test case depends on lists:reverse() to work, " 201: "wich is tested in a separate test case."]; 202: member(Config) when is_list(Config) -> 203: ?line {'EXIT',{badarg,_}} = (catch lists:member(45, {a,b,c})), 204: ?line {'EXIT',{badarg,_}} = (catch lists:member(45, [0|non_list_tail])), 205: ?line false = lists:member(4233, []), 206: ?line member_test(1), 207: ?line member_test(100), 208: ?line member_test(256), 209: ?line member_test(1000), 210: ?line member_test(1998), 211: ?line member_test(1999), 212: ?line member_test(2000), 213: ?line member_test(2001), 214: ?line member_test(3998), 215: ?line member_test(3999), 216: ?line member_test(4000), 217: ?line member_test(4001), 218: ?line member_test(100008), 219: ok. 220: 221: member_test(Num) -> 222: List0 = ['The Element'|lists:duplicate(Num, 'Elem')], 223: true = lists:member('The Element', List0), 224: true = lists:member('Elem', List0), 225: false = lists:member(arne_anka, List0), 226: false = lists:member({a,b,c}, List0), 227: List = lists:reverse(List0), 228: true = lists:member('The Element', List), 229: true = lists:member('Elem', List), 230: false = lists:member(arne_anka, List), 231: false = lists:member({a,b,c}, List). 232: 233: keymember(Config) when is_list(Config) -> 234: ?line false = lists:keymember(anything_goes, 1, []), 235: ?line {'EXIT',{badarg,_}} = (catch lists:keymember(anything_goes, -1, [])), 236: ?line {'EXIT',{badarg,_}} = (catch lists:keymember(anything_goes, 0, [])), 237: ?line {'EXIT',{badarg,_}} = (catch lists:keymember(anything_goes, 1, {1,2,3})), 238: List = [{52.0,a},{-19,b,c},{37.5,d},an_atom,42.0,{39},{45,{x,y,z}}], 239: 240: ?line false = lists:keymember(333, 5, List), 241: ?line false = lists:keymember(333, 999, List), 242: ?line false = lists:keymember(37, 1, List), 243: 244: ?line true = lists:keymember(52.0, 1, List), 245: ?line true = lists:keymember(52, 1, List), 246: ?line true = lists:keymember(-19, 1, List), 247: ?line true = lists:keymember(-19.0, 1, List), 248: ?line true = lists:keymember(37.5, 1, List), 249: ?line true = lists:keymember(39, 1, List), 250: ?line true = lists:keymember(39.0, 1, List), 251: ?line true = lists:keymember(45, 1, List), 252: ?line true = lists:keymember(45.0, 1, List), 253: 254: ?line true = lists:keymember(a, 2, List), 255: ?line true = lists:keymember(b, 2, List), 256: ?line true = lists:keymember(c, 3, List), 257: ?line true = lists:keymember(d, 2, List), 258: ?line true = lists:keymember({x,y,z}, 2, List), 259: 260: ?line Long0 = lists:seq(1, 100007), 261: ?line false = lists:keymember(kalle, 1, Long0), 262: ?line Long = lists:foldl(fun(E, A) -> [{1/E,E}|A] end, [], Long0), 263: ?line true = lists:keymember(1, 2, Long), 264: ?line true = lists:keymember(2, 2, Long), 265: ?line true = lists:keymember(1.0, 2, Long), 266: ?line true = lists:keymember(2.0, 2, Long), 267: ?line true = lists:keymember(100006, 2, Long), 268: ok. 269: 270: keysearch_keyfind(Config) when is_list(Config) -> 271: ?line false = key_search_find(anything_goes, 1, []), 272: ?line {'EXIT',{badarg,_}} = (catch key_search_find(anything_goes, -1, [])), 273: ?line {'EXIT',{badarg,_}} = (catch key_search_find(anything_goes, 0, [])), 274: ?line {'EXIT',{badarg,_}} = (catch key_search_find(anything_goes, 1, {1,2,3})), 275: 276: First = {x,42.0}, 277: Second = {y,-77}, 278: Third = {z,[a,b,c],{5.0}}, 279: List = [First,Second,Third], 280: 281: ?line false = key_search_find(333, 1, []), 282: ?line false = key_search_find(333, 5, List), 283: ?line false = key_search_find(333, 999, List), 284: ?line false = key_search_find(37, 1, List), 285: 286: ?line {value,First} = key_search_find(42, 2, List), 287: ?line {value,First} = key_search_find(42.0, 2, List), 288: 289: ?line {value,Second} = key_search_find(-77, 2, List), 290: ?line {value,Second} = key_search_find(-77.0, 2, List), 291: 292: ?line {value,Third} = key_search_find(z, 1, List), 293: ?line {value,Third} = key_search_find([a,b,c], 2, List), 294: ?line {value,Third} = key_search_find({5}, 3, List), 295: ?line {value,Third} = key_search_find({5.0}, 3, List), 296: 297: ?line Long0 = lists:seq(1, 100007), 298: ?line false = key_search_find(kalle, 1, Long0), 299: ?line Long = lists:foldl(fun(E, A) -> [{1/E,float(E)}|A] end, [], Long0), 300: ?line {value,{_,1.0}} = key_search_find(1, 2, Long), 301: ?line {value,{_,1.0}} = key_search_find(1.0, 2, Long), 302: ?line {value,{_,2.0}} = key_search_find(2, 2, Long), 303: ?line {value,{_,2.0}} = key_search_find(2.0, 2, Long), 304: ?line {value,{_,33988.0}} = key_search_find(33988, 2, Long), 305: ?line {value,{_,33988.0}} = key_search_find(33988.0, 2, Long), 306: ok. 307: 308: %% Test both lists:keysearch/3 and lists:keyfind/3. The only 309: %% difference between these two functions is that lists:keysearch/3 310: %% wraps a successfully returned tuple in a value tuple. 311: %% 312: key_search_find(Key, Pos, List) -> 313: case lists:keyfind(Key, Pos, List) of 314: false -> 315: false = lists:keysearch(Key, Pos, List); 316: Tuple when is_tuple(Tuple) -> 317: {value,Tuple} = lists:keysearch(Key, Pos, List) 318: end. 319: 320: dropwhile(Config) when is_list(Config) -> 321: ?line F = fun(C) -> C =:= $@ end, 322: 323: ?line [] = lists:dropwhile(F, []), 324: ?line [a] = lists:dropwhile(F, [a]), 325: ?line [a,b] = lists:dropwhile(F, [a,b]), 326: ?line [a,b,c] = lists:dropwhile(F, [a,b,c]), 327: 328: ?line [] = lists:dropwhile(F, [$@]), 329: ?line [] = lists:dropwhile(F, [$@,$@]), 330: ?line [a,$@] = lists:dropwhile(F, [$@,a,$@]), 331: 332: ?line [$k] = lists:dropwhile(F, [$@,$k]), 333: ?line [$k,$l] = lists:dropwhile(F, [$@,$@,$k,$l]), 334: ?line [a] = lists:dropwhile(F, [$@,$@,$@,a]), 335: 336: ?line [a,$@,b] = lists:dropwhile(F, [$@,a,$@,b]), 337: ?line [a,$@,b] = lists:dropwhile(F, [$@,$@,a,$@,b]), 338: ?line [a,$@,b] = lists:dropwhile(F, [$@,$@,$@,a,$@,b]), 339: 340: Long = lists:seq(1, 1024), 341: Shorter = lists:seq(800, 1024), 342: 343: ?line Shorter = lists:dropwhile(fun(E) -> E < 800 end, Long), 344: 345: ok. 346: 347: keystore(doc) -> 348: ["OTP-XXX."]; 349: keystore(suite) -> []; 350: keystore(Config) when is_list(Config) -> 351: ?line {'EXIT',_} = (catch lists:keystore(key, 0, [], {1})), 352: ?line {'EXIT',_} = (catch lists:keystore(key, 1, {}, {})), 353: ?line {'EXIT',_} = (catch lists:keystore(key, 1, {a,b}, {})), 354: ?line {'EXIT', _} = (catch lists:keystore(a, 2, [{1,a}], b)), 355: T = {k,17}, 356: ?line [T] = lists:keystore(a, 2, [], T), 357: ?line [{1,a},{2,b},{k,17}] = lists:keystore(c, 2, [{1,a},{2,b}],T), 358: L = [{1,a},{2,b},{3,c}], 359: ?line [{k,17},{2,b},{3,c}] = lists:keystore(a, 2, L, T), 360: ?line [{1,a},{k,17},{3,c}] = lists:keystore(b, 2, L, T), 361: ?line [{1,a},{2,b},{k,17}] = lists:keystore(c, 2, L, T), 362: ?line [{2,b}] = lists:keystore(a, 2, [{1,a}], {2,b}), 363: ?line [{1,a}] = lists:keystore(foo, 1, [], {1,a}), 364: ok. 365: 366: keytake(doc) -> 367: ["OTP-XXX."]; 368: keytake(suite) -> []; 369: keytake(Config) when is_list(Config) -> 370: ?line {'EXIT',_} = (catch lists:keytake(key, 0, [])), 371: ?line {'EXIT',_} = (catch lists:keytake(key, 1, {})), 372: ?line {'EXIT',_} = (catch lists:keytake(key, 1, {a,b})), 373: ?line false = lists:keytake(key, 2, [{a}]), 374: ?line false = lists:keytake(key, 1, [a]), 375: ?line false = lists:keytake(k, 1, []), 376: ?line false = lists:keytake(k, 1, [{a},{b},{c}]), 377: L = [{a,1},{b,2},{c,3}], 378: ?line {value,{a,1},[{b,2},{c,3}]} = lists:keytake(1, 2, L), 379: ?line {value,{b,2},[{a,1},{c,3}]} = lists:keytake(2, 2, L), 380: ?line {value,{c,3},[{a,1},{b,2}]} = lists:keytake(3, 2, L), 381: ?line false = lists:keytake(4, 2, L), 382: ok. 383: 384: merge(doc) -> ["merge functions"]; 385: merge(suite) -> []; 386: merge(Config) when is_list(Config) -> 387: 388: %% merge list of lists 389: ?line [] = lists:merge([]), 390: ?line [] = lists:merge([[]]), 391: ?line [] = lists:merge([[],[]]), 392: ?line [] = lists:merge([[],[],[]]), 393: ?line [1] = lists:merge([[1]]), 394: ?line [1,1,2,2] = lists:merge([[1,2],[1,2]]), 395: ?line [1] = lists:merge([[1],[],[]]), 396: ?line [1] = lists:merge([[],[1],[]]), 397: ?line [1] = lists:merge([[],[],[1]]), 398: ?line [1,2] = lists:merge([[1],[2],[]]), 399: ?line [1,2] = lists:merge([[1],[],[2]]), 400: ?line [1,2] = lists:merge([[],[1],[2]]), 401: ?line [1,2,3,4,5,6] = lists:merge([[1,2],[],[5,6],[],[3,4],[]]), 402: ?line [1,2,3,4] = lists:merge([[4],[3],[2],[1]]), 403: ?line [1,2,3,4,5] = lists:merge([[1],[2],[3],[4],[5]]), 404: ?line [1,2,3,4,5,6] = lists:merge([[1],[2],[3],[4],[5],[6]]), 405: ?line [1,2,3,4,5,6,7,8,9] = 406: lists:merge([[1],[2],[3],[4],[5],[6],[7],[8],[9]]), 407: Seq = lists:seq(1,100), 408: ?line true = Seq == lists:merge(lists:map(fun(E) -> [E] end, Seq)), 409: 410: Two = [1,2], 411: Six = [1,2,3,4,5,6], 412: 413: %% 2-way merge 414: ?line [] = lists:merge([], []), 415: ?line Two = lists:merge(Two, []), 416: ?line Two = lists:merge([], Two), 417: ?line Six = lists:merge([1,3,5], [2,4,6]), 418: ?line Six = lists:merge([2,4,6], [1,3,5]), 419: ?line Six = lists:merge([1,2,3], [4,5,6]), 420: ?line Six = lists:merge([4,5,6], [1,2,3]), 421: ?line Six = lists:merge([1,2,5],[3,4,6]), 422: ?line [1,2,3,5,7] = lists:merge([1,3,5,7], [2]), 423: ?line [1,2,3,4,5,7] = lists:merge([1,3,5,7], [2,4]), 424: ?line [1,2,3,4,5,6,7] = lists:merge([1,3,5,7], [2,4,6]), 425: ?line [1,2,3,5,7] = lists:merge([2], [1,3,5,7]), 426: ?line [1,2,3,4,5,7] = lists:merge([2,4], [1,3,5,7]), 427: ?line [1,2,3,4,5,6,7] = lists:merge([2,4,6], [1,3,5,7]), 428: 429: %% 3-way merge 430: ?line [] = lists:merge3([], [], []), 431: ?line Two = lists:merge3([], [], Two), 432: ?line Two = lists:merge3([], Two, []), 433: ?line Two = lists:merge3(Two, [], []), 434: ?line Six = lists:merge3([], [1,3,5], [2,4,6]), 435: ?line Six = lists:merge3([1,3,5], [], [2,4,6]), 436: ?line Six = lists:merge3([1,3,5], [2,4,6], []), 437: ?line Nine = lists:merge3([1,4,7],[2,5,8],[3,6,9]), 438: ?line Nine = lists:merge3([1,4,7],[3,6,9],[2,5,8]), 439: ?line Nine = lists:merge3([3,6,9],[1,4,7],[2,5,8]), 440: ?line Nine = lists:merge3([4,5,6],[1,2,3],[7,8,9]), 441: ?line Nine = lists:merge3([1,2,3],[4,5,6],[7,8,9]), 442: ?line Nine = lists:merge3([7,8,9],[4,5,6],[1,2,3]), 443: ?line Nine = lists:merge3([4,5,6],[7,8,9],[1,2,3]), 444: 445: ok. 446: 447: rmerge(doc) -> ["reverse merge functions"]; 448: rmerge(suite) -> []; 449: rmerge(Config) when is_list(Config) -> 450: 451: Two = [2,1], 452: Six = [6,5,4,3,2,1], 453: 454: %% 2-way reversed merge 455: ?line [] = lists:rmerge([], []), 456: ?line Two = lists:rmerge(Two, []), 457: ?line Two = lists:rmerge([], Two), 458: ?line Six = lists:rmerge([5,3,1], [6,4,2]), 459: ?line Six = lists:rmerge([6,4,2], [5,3,1]), 460: ?line Six = lists:rmerge([3,2,1], [6,5,4]), 461: ?line Six = lists:rmerge([6,5,4], [3,2,1]), 462: ?line Six = lists:rmerge([4,3,2],[6,5,1]), 463: ?line [7,6,5,3,1] = lists:rmerge([7,5,3,1], [6]), 464: ?line [7,6,5,4,3,1] = lists:rmerge([7,5,3,1], [6,4]), 465: ?line [7,6,5,4,3,2,1] = lists:rmerge([7,5,3,1], [6,4,2]), 466: ?line [7,5,3,2,1] = lists:rmerge([2], [7,5,3,1]), 467: ?line [7,5,4,3,2,1] = lists:rmerge([4,2], [7,5,3,1]), 468: ?line [7,6,5,4,3,2,1] = lists:rmerge([6,4,2], [7,5,3,1]), 469: 470: Nine = [9,8,7,6,5,4,3,2,1], 471: 472: %% 3-way reversed merge 473: ?line [] = lists:rmerge3([], [], []), 474: ?line Two = lists:rmerge3([], [], Two), 475: ?line Two = lists:rmerge3([], Two, []), 476: ?line Two = lists:rmerge3(Two, [], []), 477: ?line Six = lists:rmerge3([], [5,3,1], [6,4,2]), 478: ?line Six = lists:rmerge3([5,3,1], [], [6,4,2]), 479: ?line Six = lists:rmerge3([5,3,1], [6,4,2], []), 480: ?line Nine = lists:rmerge3([7,4,1],[8,5,2],[9,6,3]), 481: ?line Nine = lists:rmerge3([7,4,1],[9,6,3],[8,5,2]), 482: ?line Nine = lists:rmerge3([9,6,3],[7,4,1],[8,5,2]), 483: ?line Nine = lists:rmerge3([6,5,4],[3,2,1],[9,8,7]), 484: ?line Nine = lists:rmerge3([3,2,1],[6,5,4],[9,8,7]), 485: ?line Nine = lists:rmerge3([9,8,7],[6,5,4],[3,2,1]), 486: ?line Nine = lists:rmerge3([6,5,4],[9,8,7],[3,2,1]), 487: 488: ok. 489: 490: sort_1(doc) -> ["sort/1"]; 491: sort_1(suite) -> []; 492: sort_1(Config) when is_list(Config) -> 493: ?line [] = lists:sort([]), 494: ?line [a] = lists:sort([a]), 495: ?line [a,a] = lists:sort([a,a]), 496: ?line [a,b] = lists:sort([a,b]), 497: ?line [a,b] = lists:sort([b,a]), 498: ?line [1,1] = lists:sort([1,1]), 499: ?line [1,1,2,3] = lists:sort([1,1,3,2]), 500: ?line [1,2,3,3] = lists:sort([3,3,1,2]), 501: ?line [1,1,1,1] = lists:sort([1,1,1,1]), 502: ?line [1,1,1,2,2,2,3,3,3] = lists:sort([3,3,3,2,2,2,1,1,1]), 503: ?line [1,1,1,2,2,2,3,3,3] = lists:sort([1,1,1,2,2,2,3,3,3]), 504: 505: ?line lists:foreach(fun check/1, perms([1,2,3])), 506: ?line lists:foreach(fun check/1, perms([1,2,3,4,5,6,7,8])), 507: ok. 508: 509: sort_rand(doc) -> ["sort/1 on big randomized lists"]; 510: sort_rand(suite) -> []; 511: sort_rand(Config) when is_list(Config) -> 512: ?line ok = check(biglist(10)), 513: ?line ok = check(biglist(100)), 514: ?line ok = check(biglist(1000)), 515: ?line ok = check(biglist(10000)), 516: ok. 517: 518: %% sort/1 was really stable for a while - the order of equal elements 519: %% was kept - but since the performance suffered a bit, this "feature" 520: %% was removed. 521: sort_stable(doc) -> ["sort/1 should be stable for equal terms."]; 522: sort_stable(suite) -> []; 523: sort_stable(Config) when is_list(Config) -> 524: ?line ok = check_stability(bigfunlist(10)), 525: ?line ok = check_stability(bigfunlist(100)), 526: ?line ok = check_stability(bigfunlist(1000)), 527: ?line case erlang:system_info(modified_timing_level) of 528: undefined -> ok = check_stability(bigfunlist(10000)); 529: _ -> ok 530: end, 531: ok. 532: 533: check([]) -> 534: ok; 535: check(L) -> 536: S = lists:sort(L), 537: case {length(L) == length(S), check(hd(S), tl(S))} of 538: {true,ok} -> 539: ok; 540: _ -> 541: io:format("~w~n", [L]), 542: erlang:error(check) 543: end. 544: 545: check(_A, []) -> 546: ok; 547: check(A, [B | L]) when A =< B -> 548: check(B, L); 549: check(_A, _L) -> 550: no. 551: 552: %% The check that sort/1 is stable is no longer used. 553: %% Equal elements are no longer always kept in order. 554: check_stability(L) -> 555: S = lists:sort(L), 556: LP = explicit_pid(L), 557: SP = explicit_pid(S), 558: check_sorted(1, 2, LP, SP). 559: 560: explicit_pid(L) -> 561: lists:reverse(expl_pid(L, [])). 562: 563: expl_pid([{I,F} | T], L) when is_function(F) -> 564: expl_pid(T, [{I,fun_pid(F)} | L]); 565: expl_pid([], L) -> 566: L. 567: 568: 569: usort_1(suite) -> []; 570: usort_1(doc) -> [""]; 571: usort_1(Conf) when is_list(Conf) -> 572: ?line [] = lists:usort([]), 573: ?line [1] = lists:usort([1]), 574: ?line [1] = lists:usort([1,1]), 575: ?line [1] = lists:usort([1,1,1,1,1]), 576: ?line [1,2] = lists:usort([1,2]), 577: ?line [1,2] = lists:usort([1,2,1]), 578: ?line [1,2] = lists:usort([1,2,2]), 579: ?line [1,2,3] = lists:usort([1,3,2]), 580: ?line [1,3] = lists:usort([3,1,3]), 581: ?line [0,1,3] = lists:usort([3,1,0]), 582: ?line [1,2,3] = lists:usort([3,1,2]), 583: ?line [1,2] = lists:usort([2,1,1]), 584: ?line [1,2] = lists:usort([2,1]), 585: ?line [0,3,4,8,9] = lists:usort([3,8,9,0,9,4]), 586: 587: ?line lists:foreach(fun ucheck/1, perms([1,2,3])), 588: ?line lists:foreach(fun ucheck/1, perms([1,2,3,4,5,6,2,1])), 589: 590: ok. 591: 592: umerge(suite) -> []; 593: umerge(doc) -> [""]; 594: umerge(Conf) when is_list(Conf) -> 595: %% merge list of lists 596: ?line [] = lists:umerge([]), 597: ?line [] = lists:umerge([[]]), 598: ?line [] = lists:umerge([[],[]]), 599: ?line [] = lists:umerge([[],[],[]]), 600: ?line [1] = lists:umerge([[1]]), 601: ?line [1,2] = lists:umerge([[1,2],[1,2]]), 602: ?line [1] = lists:umerge([[1],[],[]]), 603: ?line [1] = lists:umerge([[],[1],[]]), 604: ?line [1] = lists:umerge([[],[],[1]]), 605: ?line [1,2] = lists:umerge([[1],[2],[]]), 606: ?line [1,2] = lists:umerge([[1],[],[2]]), 607: ?line [1,2] = lists:umerge([[],[1],[2]]), 608: ?line [1,2,3,4,5,6] = lists:umerge([[1,2],[],[5,6],[],[3,4],[]]), 609: ?line [1,2,3,4] = lists:umerge([[4],[3],[2],[1]]), 610: ?line [1,2,3,4,5] = lists:umerge([[1],[2],[3],[4],[5]]), 611: ?line [1,2,3,4,5,6] = lists:umerge([[1],[2],[3],[4],[5],[6]]), 612: ?line [1,2,3,4,5,6,7,8,9] = 613: lists:umerge([[1],[2],[3],[4],[5],[6],[7],[8],[9]]), 614: ?line [1,2,4,6,8] = lists:umerge([[1,2],[2,4,6,8]]), 615: Seq = lists:seq(1,100), 616: ?line true = Seq == lists:umerge(lists:map(fun(E) -> [E] end, Seq)), 617: 618: Two = [1,2], 619: Six = [1,2,3,4,5,6], 620: 621: %% 2-way unique merge 622: ?line [] = lists:umerge([], []), 623: ?line Two = lists:umerge(Two, []), 624: ?line Two = lists:umerge([], Two), 625: ?line Six = lists:umerge([1,3,5], [2,4,6]), 626: ?line Six = lists:umerge([2,4,6], [1,3,5]), 627: ?line Six = lists:umerge([1,2,3], [4,5,6]), 628: ?line Six = lists:umerge([4,5,6], [1,2,3]), 629: ?line Six = lists:umerge([1,2,5],[3,4,6]), 630: ?line [1,2,3,5,7] = lists:umerge([1,3,5,7], [2]), 631: ?line [1,2,3,4,5,7] = lists:umerge([1,3,5,7], [2,4]), 632: ?line [1,2,3,4,5,6,7] = lists:umerge([1,3,5,7], [2,4,6]), 633: ?line [1,2,3,5,7] = lists:umerge([2], [1,3,5,7]), 634: ?line [1,2,3,4,5,7] = lists:umerge([2,4], [1,3,5,7]), 635: ?line [1,2,3,4,5,6,7] = lists:umerge([2,4,6], [1,3,5,7]), 636: 637: ?line [1,2,3,5,7] = lists:umerge([1,2,3,5,7], [2]), 638: ?line [1,2,3,4,5,7] = lists:umerge([1,2,3,4,5,7], [2,4]), 639: ?line [1,2,3,4,5,6,7] = lists:umerge([1,2,3,4,5,6,7], [2,4,6]), 640: ?line [1,2,3,5,7] = lists:umerge([2], [1,2,3,5,7]), 641: ?line [1,2,3,4,5,7] = lists:umerge([2,4], [1,2,3,4,5,7]), 642: ?line [1,2,3,4,5,6,7] = lists:umerge([2,4,6], [1,2,3,4,5,6,7]), 643: 644: %% 3-way unique merge 645: ?line [] = lists:umerge3([], [], []), 646: ?line Two = lists:umerge3([], [], Two), 647: ?line Two = lists:umerge3([], Two, []), 648: ?line Two = lists:umerge3(Two, [], []), 649: ?line Six = lists:umerge3([], [1,3,5], [2,4,6]), 650: ?line Six = lists:umerge3([1,3,5], [], [2,4,6]), 651: ?line Six = lists:umerge3([1,3,5], [2,4,6], []), 652: ?line Nine = lists:umerge3([1,4,7],[2,5,8],[3,6,9]), 653: ?line Nine = lists:umerge3([1,4,7],[3,6,9],[2,5,8]), 654: ?line Nine = lists:umerge3([3,6,9],[1,4,7],[2,5,8]), 655: ?line Nine = lists:umerge3([4,5,6],[1,2,3],[7,8,9]), 656: ?line Nine = lists:umerge3([1,2,3],[4,5,6],[7,8,9]), 657: ?line Nine = lists:umerge3([7,8,9],[4,5,6],[1,2,3]), 658: ?line Nine = lists:umerge3([4,5,6],[7,8,9],[1,2,3]), 659: 660: ?line [1,2,3] = lists:umerge3([1,2,3],[1,2,3],[1,2,3]), 661: ?line [1,2,3,4] = lists:umerge3([2,3,4],[1,2,3],[2,3,4]), 662: ?line [1,2,3] = lists:umerge3([1,2,3],[2,3],[1,2,3]), 663: ?line [1,2,3,4] = lists:umerge3([2,3,4],[3,4],[1,2,3]), 664: 665: ok. 666: 667: rumerge(suite) -> []; 668: rumerge(doc) -> [""]; 669: rumerge(Conf) when is_list(Conf) -> 670: Two = [2,1], 671: Six = [6,5,4,3,2,1], 672: 673: %% 2-way reversed unique merge 674: ?line [] = lists:rumerge([], []), 675: ?line Two = lists:rumerge(Two, []), 676: ?line Two = lists:rumerge([], Two), 677: ?line Six = lists:rumerge([5,3,1], [6,4,2]), 678: ?line Six = lists:rumerge([6,4,2], [5,3,1]), 679: ?line Six = lists:rumerge([3,2,1], [6,5,4]), 680: ?line Six = lists:rumerge([6,5,4], [3,2,1]), 681: ?line Six = lists:rumerge([4,3,2],[6,5,1]), 682: ?line [7,6,5,3,1] = lists:rumerge([7,5,3,1], [6]), 683: ?line [7,6,5,4,3,1] = lists:rumerge([7,5,3,1], [6,4]), 684: ?line [7,6,5,4,3,2,1] = lists:rumerge([7,5,3,1], [6,4,2]), 685: ?line [7,5,3,2,1] = lists:rumerge([2], [7,5,3,1]), 686: ?line [7,5,4,3,2,1] = lists:rumerge([4,2], [7,5,3,1]), 687: ?line [7,6,5,4,3,2,1] = lists:rumerge([6,4,2], [7,5,3,1]), 688: 689: ?line [7,6,5,3,1] = lists:rumerge([7,6,5,3,1], [6]), 690: ?line [7,6,5,4,3,1] = lists:rumerge([7,6,5,4,3,1], [6,4]), 691: ?line [7,6,5,4,3,2,1] = lists:rumerge([7,6,5,4,3,2,1], [6,4,2]), 692: ?line [7,5,3,2,1] = lists:rumerge([2], [7,5,3,2,1]), 693: ?line [7,5,4,3,2,1] = lists:rumerge([4,2], [7,5,4,3,2,1]), 694: ?line [7,6,5,4,3,2,1] = lists:rumerge([6,4,2], [7,6,5,4,3,2,1]), 695: 696: Nine = [9,8,7,6,5,4,3,2,1], 697: 698: %% 3-way reversed unique merge 699: ?line [] = lists:rumerge3([], [], []), 700: ?line Two = lists:rumerge3([], [], Two), 701: ?line Two = lists:rumerge3([], Two, []), 702: ?line Two = lists:rumerge3(Two, [], []), 703: ?line Six = lists:rumerge3([], [5,3,1], [6,4,2]), 704: ?line Six = lists:rumerge3([5,3,1], [], [6,4,2]), 705: ?line Six = lists:rumerge3([5,3,1], [6,4,2], []), 706: ?line Nine = lists:rumerge3([7,4,1],[8,5,2],[9,6,3]), 707: ?line Nine = lists:rumerge3([7,4,1],[9,6,3],[8,5,2]), 708: ?line Nine = lists:rumerge3([9,6,3],[7,4,1],[8,5,2]), 709: ?line Nine = lists:rumerge3([6,5,4],[3,2,1],[9,8,7]), 710: ?line Nine = lists:rumerge3([3,2,1],[6,5,4],[9,8,7]), 711: ?line Nine = lists:rumerge3([9,8,7],[6,5,4],[3,2,1]), 712: ?line Nine = lists:rumerge3([6,5,4],[9,8,7],[3,2,1]), 713: 714: ?line [3,2,1] = lists:rumerge3([3,2,1],[3,2,1],[3,2,1]), 715: ?line [4,3,2,1] = lists:rumerge3([4,3,2],[3,2,1],[3,2,1]), 716: ?line [5,4,3,2,1] = lists:rumerge3([4,3,2],[5,4,3,2],[5,4,3,2,1]), 717: ?line [6,5,4,3,2] = lists:rumerge3([4,3,2],[5,4,3,2],[6,5,4,3]), 718: 719: L1 = [c,d,e], 720: L2 = [b,c,d], 721: ?line true = 722: lists:umerge(L1, L2) == 723: lists:reverse(lists:rumerge(lists:reverse(L1), lists:reverse(L2))), 724: ok. 725: 726: usort_rand(doc) -> ["usort/1 on big randomized lists"]; 727: usort_rand(suite) -> []; 728: usort_rand(Config) when is_list(Config) -> 729: ?line ok = ucheck(biglist(10)), 730: ?line ok = ucheck(biglist(100)), 731: ?line ok = ucheck(biglist(1000)), 732: ?line ok = ucheck(biglist(10000)), 733: 734: ?line ok = ucheck(ubiglist(10)), 735: ?line ok = ucheck(ubiglist(100)), 736: ?line ok = ucheck(ubiglist(1000)), 737: ?line ok = ucheck(ubiglist(10000)), 738: ok. 739: 740: usort_stable(doc) -> ["usort/1 should keep the first duplicate."]; 741: usort_stable(suite) -> []; 742: usort_stable(Config) when is_list(Config) -> 743: ?line ok = ucheck_stability(bigfunlist(3)), 744: ?line ok = ucheck_stability(bigfunlist(10)), 745: ?line ok = ucheck_stability(bigfunlist(100)), 746: ?line ok = ucheck_stability(bigfunlist(1000)), 747: ?line case erlang:system_info(modified_timing_level) of 748: undefined -> ok = ucheck_stability(bigfunlist(10000)); 749: _ -> ok 750: end, 751: ok. 752: 753: ucheck([]) -> 754: ok; 755: ucheck(L) -> 756: S = lists:usort(L), 757: case ucheck(hd(S), tl(S)) of 758: ok -> 759: ok; 760: _ -> 761: io:format("~w~n", [L]), 762: erlang:error(ucheck) 763: end. 764: 765: ucheck(_A, []) -> 766: ok; 767: ucheck(A, [B | L]) when A < B -> 768: ucheck(B, L); 769: ucheck(_A, _L) -> 770: no. 771: 772: %% Check that usort/1 is stable and correct relative ukeysort/2. 773: ucheck_stability(L) -> 774: S = no_dups(lsort(L)), 775: U = lists:usort(L), 776: check_stab(L, U, S, "usort/1", "ukeysort/2"). 777: 778: 779: keymerge(doc) -> ["Key merge two lists."]; 780: keymerge(suite) -> []; 781: keymerge(Config) when is_list(Config) -> 782: 783: Two = [{1,a},{2,b}], 784: Six = [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f}], 785: 786: %% 2-way keymerge 787: ?line [] = lists:keymerge(1, [], []), 788: ?line Two = lists:keymerge(1, Two, []), 789: ?line Two = lists:keymerge(1, [], Two), 790: ?line Six = lists:keymerge(1, [{1,a},{3,c},{5,e}], [{2,b},{4,d},{6,f}]), 791: ?line Six = lists:keymerge(1, [{2,b},{4,d},{6,f}], [{1,a},{3,c},{5,e}]), 792: ?line Six = lists:keymerge(1, [{1,a},{2,b},{3,c}], [{4,d},{5,e},{6,f}]), 793: ?line Six = lists:keymerge(1, [{4,d},{5,e},{6,f}], [{1,a},{2,b},{3,c}]), 794: ?line Six = lists:keymerge(1, [{1,a},{2,b},{5,e}],[{3,c},{4,d},{6,f}]), 795: ?line [{1,a},{2,b},{3,c},{5,e},{7,g}] = 796: lists:keymerge(1, [{1,a},{3,c},{5,e},{7,g}], [{2,b}]), 797: ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}] = 798: lists:keymerge(1, [{1,a},{3,c},{5,e},{7,g}], [{2,b},{4,d}]), 799: ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g}] = 800: lists:keymerge(1, [{1,a},{3,c},{5,e},{7,g}], [{2,b},{4,d},{6,f}]), 801: ?line [{1,a},{2,b},{3,c},{5,e},{7,g}] = 802: lists:keymerge(1, [{2,b}], [{1,a},{3,c},{5,e},{7,g}]), 803: ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}] = 804: lists:keymerge(1, [{2,b},{4,d}], [{1,a},{3,c},{5,e},{7,g}]), 805: ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g}] = 806: lists:keymerge(1, [{2,b},{4,d},{6,f}], [{1,a},{3,c},{5,e},{7,g}]), 807: 808: ?line [{b,2},{c,11},{c,12},{c,21},{c,22},{e,5}] = 809: lists:keymerge(1,[{c,11},{c,12},{e,5}], [{b,2},{c,21},{c,22}]), 810: 811: ok. 812: 813: rkeymerge(doc) -> ["Reverse key merge two lists."]; 814: rkeymerge(suite) -> []; 815: rkeymerge(Config) when is_list(Config) -> 816: 817: Two = [{2,b},{1,a}], 818: Six = [{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}], 819: 820: %% 2-way reversed keymerge 821: ?line [] = lists:rkeymerge(1, [], []), 822: ?line Two = lists:rkeymerge(1, Two, []), 823: ?line Two = lists:rkeymerge(1, [], Two), 824: ?line Six = lists:rkeymerge(1, [{5,e},{3,c},{1,a}], [{6,f},{4,d},{2,b}]), 825: ?line Six = lists:rkeymerge(1, [{6,f},{4,d},{2,b}], [{5,e},{3,c},{1,a}]), 826: ?line Six = lists:rkeymerge(1, [{3,c},{2,b},{1,a}], [{6,f},{5,e},{4,d}]), 827: ?line Six = lists:rkeymerge(1, [{6,f},{5,e},{4,d}], [{3,c},{2,b},{1,a}]), 828: ?line Six = lists:rkeymerge(1, [{4,d},{3,c},{2,b}],[{6,f},{5,e},{1,a}]), 829: ?line [{7,g},{6,f},{5,e},{3,c},{1,a}] = 830: lists:rkeymerge(1, [{7,g},{5,e},{3,c},{1,a}], [{6,f}]), 831: ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{1,a}] = 832: lists:rkeymerge(1, [{7,g},{5,e},{3,c},{1,a}], [{6,f},{4,d}]), 833: ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}] = 834: lists:rkeymerge(1, [{7,g},{5,e},{3,c},{1,a}], [{6,f},{4,d},{2,b}]), 835: ?line [{7,g},{5,e},{3,c},{2,b},{1,a}] = 836: lists:rkeymerge(1, [{2,b}], [{7,g},{5,e},{3,c},{1,a}]), 837: ?line [{7,g},{5,e},{4,d},{3,c},{2,b},{1,a}] = 838: lists:rkeymerge(1, [{4,d},{2,b}], [{7,g},{5,e},{3,c},{1,a}]), 839: ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}] = 840: lists:rkeymerge(1, [{6,f},{4,d},{2,b}], [{7,g},{5,e},{3,c},{1,a}]), 841: 842: L1 = [{c,11},{c,12},{e,5}], 843: L2 = [{b,2},{c,21},{c,22}], 844: ?line true = 845: lists:keymerge(1, L1, L2) == 846: lists:reverse(lists:rkeymerge(1,lists:reverse(L1), 847: lists:reverse(L2))), 848: 849: ok. 850: 851: keysort_1(doc) -> ["keysort"]; 852: keysort_1(suite) -> []; 853: keysort_1(Config) when is_list(Config) -> 854: ?line ok = keysort_check(1, [], []), 855: ?line ok = keysort_check(1, [{a,b}], [{a,b}]), 856: ?line ok = keysort_check(1, [{a,b},{a,b}], [{a,b},{a,b}]), 857: ?line ok = keysort_check(1, [{a,b},{b,c}], [{a,b},{b,c}]), 858: ?line ok = keysort_check(1, [{b,c},{a,b}], [{a,b},{b,c}]), 859: ?line ok = keysort_check(1, 860: [{1,e},{3,f},{2,y},{0,z},{x,14}], 861: [{0,z},{1,e},{2,y},{3,f},{x,14}]), 862: ?line ok = keysort_check(1, 863: [{1,a},{1,a},{1,a},{1,a}], 864: [{1,a},{1,a},{1,a},{1,a}]), 865: 866: ?line [{b,1},{c,1}] = lists:keysort(1, [{c,1},{b,1}]), 867: ?line [{a,0},{b,2},{c,3},{d,4}] = 868: lists:keysort(1, [{d,4},{c,3},{b,2},{a,0}]), 869: ?line [{a,0},{b,1},{b,2},{c,1}] = 870: lists:keysort(1, [{c,1},{b,1},{b,2},{a,0}]), 871: ?line [{a,0},{b,1},{b,2},{c,1},{d,4}] = 872: lists:keysort(1, [{c,1},{b,1},{b,2},{a,0},{d,4}]), 873: 874: SFun = fun(L) -> fun(X) -> keysort_check(1, X, L) end end, 875: L1 = [{1,a},{2,b},{3,c}], 876: ?line lists:foreach(SFun(L1), perms(L1)), 877: L2 = [{1,a},{1,a},{2,b}], 878: ?line lists:foreach(SFun(L2), perms(L2)), 879: L3 = [{1,a},{1,a},{1,a},{2,b}], 880: ?line lists:foreach(SFun(L3), perms(L3)), 881: L4 = [{a,1},{a,1},{b,2},{b,2},{c,3},{d,4},{e,5},{f,6}], 882: ?line lists:foreach(SFun(L4), perms(L4)), 883: 884: ok. 885: 886: keysort_stable(doc) -> ["keysort should be stable"]; 887: keysort_stable(suite) -> []; 888: keysort_stable(Config) when is_list(Config) -> 889: ?line ok = keysort_check(1, [{1,b},{1,c}], [{1,b},{1,c}]), 890: ?line ok = keysort_check(1, [{1,c},{1,b}], [{1,c},{1,b}]), 891: ?line ok = keysort_check(1, 892: [{1,c},{1,b},{2,x},{3,p},{2,a}], 893: [{1,c},{1,b},{2,x},{2,a},{3,p}]), 894: ?line ok = keysort_check(1, 895: [{1,a},{1,b},{1,a},{1,a}], 896: [{1,a},{1,b},{1,a},{1,a}]), 897: ok. 898: 899: keysort_error(doc) -> ["keysort should exit when given bad arguments"]; 900: keysort_error(suite) -> []; 901: keysort_error(Config) when is_list(Config) -> 902: ?line {'EXIT', _} = (catch lists:keysort(0, [{1,b},{1,c}])), 903: ?line {'EXIT', _} = (catch lists:keysort(3, [{1,b},{1,c}])), 904: ?line {'EXIT', _} = (catch lists:keysort(1.5, [{1,b},{1,c}])), 905: ?line {'EXIT', _} = (catch lists:keysort(x, [{1,b},{1,c}])), 906: ?line {'EXIT', _} = (catch lists:keysort(x, [])), 907: ?line {'EXIT', _} = (catch lists:keysort(x, [{1,b}])), 908: ?line {'EXIT', _} = (catch lists:keysort(1, [a,b])), 909: ?line {'EXIT', _} = (catch lists:keysort(1, [{1,b} | {1,c}])), 910: ok. 911: 912: keysort_i(doc) -> ["keysort with other key than first element"]; 913: keysort_i(suite) -> []; 914: keysort_i(Config) when is_list(Config) -> 915: ?line ok = keysort_check(2, [{a,2},{b,1},{c,3}], [{b,1},{a,2},{c,3}]), 916: ok. 917: 918: keysort_rand(doc) -> ["keysort on big randomized lists"]; 919: keysort_rand(suite) -> []; 920: keysort_rand(Config) when is_list(Config) -> 921: ?line ok = keysort_check3(1, biglist(10)), 922: ?line ok = keysort_check3(1, biglist(100)), 923: ?line ok = keysort_check3(1, biglist(1000)), 924: ?line ok = keysort_check3(1, biglist(10000)), 925: 926: ?line ok = keysort_check3(2, biglist(10)), 927: ?line ok = keysort_check3(2, biglist(100)), 928: ?line ok = keysort_check3(2, biglist(1000)), 929: ?line ok = keysort_check3(2, biglist(10000)), 930: ok. 931: 932: %%% Keysort a list, check that the returned list is what we expected, 933: %%% and that it is actually sorted. 934: keysort_check(I, Input, Expected) -> 935: ?line Expected = lists:keysort(I, Input), 936: check_sorted(I, Input, Expected). 937: 938: keysort_check3(I, Input) -> 939: check_sorted(I, 3, Input, lists:keysort(I, Input)). 940: 941: check_sorted(I, Input, L) -> 942: check_sorted(I, I, Input, L). 943: 944: %%% Check that a list is keysorted by element I. Elements comparing equal 945: %%% should be sorted according to element J. 946: check_sorted(_I, _J, _Input, []) -> 947: ok; 948: check_sorted(I, J, Input, [A | Rest]) -> 949: case catch check_sorted1(I, J, A, Rest) of 950: {'EXIT', _} -> 951: io:format("~w~n", [Input]), 952: erlang:error(check_sorted); 953: Reply -> 954: Reply 955: end. 956: 957: check_sorted1(_I, _J, _A, []) -> 958: ok; 959: check_sorted1(I, J, A, [B | Rest]) -> 960: ok = keycompare(I, J, A, B), 961: check_sorted1(I, J, B, Rest). 962: 963: keycompare(I, _J, A, B) when element(I, A) < element(I, B) -> 964: ok; 965: keycompare(I, J, A, B) when element(I, A) == element(I, B), 966: element(J, A) =< element(J, B) -> 967: ok. 968: 969: 970: ukeymerge(suite) -> []; 971: ukeymerge(doc) -> ["Merge two lists while removing duplicates."]; 972: ukeymerge(Conf) when is_list(Conf) -> 973: 974: Two = [{1,a},{2,b}], 975: Six = [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f}], 976: 977: %% 2-way unique keymerge 978: ?line [] = lists:ukeymerge(1, [], []), 979: ?line Two = lists:ukeymerge(1, Two, []), 980: ?line Two = lists:ukeymerge(1, [], Two), 981: ?line [] = lists:ukeymerge(1, [], []), 982: ?line Two = lists:ukeymerge(1, Two, []), 983: ?line Two = lists:ukeymerge(1, [], Two), 984: ?line Six = lists:ukeymerge(1, [{1,a},{3,c},{5,e}], [{2,b},{4,d},{6,f}]), 985: ?line Six = lists:ukeymerge(1, [{2,b},{4,d},{6,f}], [{1,a},{3,c},{5,e}]), 986: ?line Six = lists:ukeymerge(1, [{1,a},{2,b},{3,c}], [{4,d},{5,e},{6,f}]), 987: ?line Six = lists:ukeymerge(1, [{4,d},{5,e},{6,f}], [{1,a},{2,b},{3,c}]), 988: ?line Six = lists:ukeymerge(1, [{1,a},{2,b},{5,e}],[{3,c},{4,d},{6,f}]), 989: ?line [{1,a},{2,b},{3,c},{5,e},{7,g}] = 990: lists:ukeymerge(1, [{1,a},{3,c},{5,e},{7,g}], [{2,b}]), 991: ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}] = 992: lists:ukeymerge(1, [{1,a},{3,c},{5,e},{7,g}], [{2,b},{4,d}]), 993: ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g}] = 994: lists:ukeymerge(1, [{1,a},{3,c},{5,e},{7,g}], [{2,b},{4,d},{6,f}]), 995: ?line [{1,a},{2,b},{3,c},{5,e},{7,g}] = 996: lists:ukeymerge(1, [{2,b}], [{1,a},{3,c},{5,e},{7,g}]), 997: ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}] = 998: lists:ukeymerge(1, [{2,b},{4,d}], [{1,a},{3,c},{5,e},{7,g}]), 999: ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g}] = 1000: lists:ukeymerge(1, [{2,b},{4,d},{6,f}], [{1,a},{3,c},{5,e},{7,g}]), 1001: 1002: ?line [{1,a},{2,b},{3,c},{5,e},{7,g}] = 1003: lists:ukeymerge(1, [{1,a},{2,b},{3,c},{5,e},{7,g}], [{2,b}]), 1004: ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}] = 1005: lists:ukeymerge(1, [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}], 1006: [{2,b},{4,d}]), 1007: ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g}] = 1008: lists:ukeymerge(1, [{1,a},{3,c},{5,e},{6,f},{7,g}], 1009: [{2,b},{4,d},{6,f}]), 1010: ?line [{1,a},{2,b},{3,c},{5,e},{7,g}] = 1011: lists:ukeymerge(1, [{2,b}], [{1,a},{2,b},{3,c},{5,e},{7,g}]), 1012: ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}] = 1013: lists:ukeymerge(1, [{2,b},{4,d}], 1014: [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}]), 1015: ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g}] = 1016: lists:ukeymerge(1, [{2,b},{4,d},{6,f}], 1017: [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g}]), 1018: 1019: L1 = [{a,1},{a,3},{a,5},{a,7}], 1020: L2 = [{b,1},{b,3},{b,5},{b,7}], 1021: ?line L1 = lists:ukeymerge(2, L1, L2), 1022: 1023: ok. 1024: 1025: rukeymerge(suite) -> []; 1026: rukeymerge(doc) -> 1027: ["Reverse merge two lists while removing duplicates."]; 1028: rukeymerge(Conf) when is_list(Conf) -> 1029: 1030: Two = [{2,b},{1,a}], 1031: Six = [{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}], 1032: 1033: %% 2-way reversed unique keymerge 1034: ?line [] = lists:rukeymerge(1, [], []), 1035: ?line Two = lists:rukeymerge(1, Two, []), 1036: ?line Two = lists:rukeymerge(1, [], Two), 1037: ?line Six = lists:rukeymerge(1, [{5,e},{3,c},{1,a}], [{6,f},{4,d},{2,b}]), 1038: ?line Six = lists:rukeymerge(1, [{6,f},{4,d},{2,b}], [{5,e},{3,c},{1,a}]), 1039: ?line Six = lists:rukeymerge(1, [{3,c},{2,b},{1,a}], [{6,f},{5,e},{4,d}]), 1040: ?line Six = lists:rukeymerge(1, [{6,f},{5,e},{4,d}], [{3,c},{2,b},{1,a}]), 1041: ?line Six = lists:rukeymerge(1, [{4,d},{3,c},{2,b}],[{6,f},{5,e},{1,a}]), 1042: ?line [{7,g},{6,f},{5,e},{3,c},{1,a}] = 1043: lists:rukeymerge(1, [{7,g},{5,e},{3,c},{1,a}], [{6,f}]), 1044: ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{1,a}] = 1045: lists:rukeymerge(1, [{7,g},{5,e},{3,c},{1,a}], [{6,f},{4,d}]), 1046: ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}] = 1047: lists:rukeymerge(1, [{7,g},{5,e},{3,c},{1,a}], [{6,f},{4,d},{2,b}]), 1048: ?line [{7,g},{5,e},{3,c},{2,b},{1,a}] = 1049: lists:rukeymerge(1, [{2,b}], [{7,g},{5,e},{3,c},{1,a}]), 1050: ?line [{7,g},{5,e},{4,d},{3,c},{2,b},{1,a}] = 1051: lists:rukeymerge(1, [{4,d},{2,b}], [{7,g},{5,e},{3,c},{1,a}]), 1052: ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}] = 1053: lists:rukeymerge(1, [{6,f},{4,d},{2,b}], [{7,g},{5,e},{3,c},{1,a}]), 1054: 1055: ?line [{7,g},{6,f},{5,e},{3,c},{1,a}] = 1056: lists:rukeymerge(1, [{7,g},{6,f},{5,e},{3,c},{1,a}], [{6,f}]), 1057: ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{1,a}] = 1058: lists:rukeymerge(1, [{7,g},{6,f},{5,e},{4,d},{3,c},{1,a}], 1059: [{6,f},{4,d}]), 1060: ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}] = 1061: lists:rukeymerge(1, [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}], 1062: [{6,f},{4,d},{2,b}]), 1063: ?line [{7,g},{5,e},{3,c},{2,b},{1,a}] = 1064: lists:rukeymerge(1, [{2,b}], [{7,g},{5,e},{3,c},{2,b},{1,a}]), 1065: ?line [{7,g},{5,e},{4,d},{3,c},{2,b},{1,a}] = 1066: lists:rukeymerge(1, [{4,d},{2,b}], 1067: [{7,g},{5,e},{4,d},{3,c},{2,b},{1,a}]), 1068: ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}] = 1069: lists:rukeymerge(1, [{6,f},{4,d},{2,b}], 1070: [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}]), 1071: 1072: L1 = [{a,1},{a,3},{a,5},{a,7}], 1073: L2 = [{b,1},{b,3},{b,5},{b,7}], 1074: ?line true = 1075: lists:ukeymerge(2, L1, L2) == 1076: lists:reverse(lists:rukeymerge(2, lists:reverse(L1), 1077: lists:reverse(L2))), 1078: 1079: ok. 1080: 1081: ukeysort_1(doc) -> ["ukeysort"]; 1082: ukeysort_1(suite) -> []; 1083: ukeysort_1(Config) when is_list(Config) -> 1084: ?line ok = ukeysort_check(1, [], []), 1085: ?line ok = ukeysort_check(1, [{a,b}], [{a,b}]), 1086: ?line ok = ukeysort_check(1, [{a,b},{a,b}], [{a,b}]), 1087: ?line ok = ukeysort_check(1, [{a,b},{b,c}], [{a,b},{b,c}]), 1088: ?line ok = ukeysort_check(1, [{b,c},{a,b}], [{a,b},{b,c}]), 1089: ?line ok = ukeysort_check(1, 1090: [{1,e},{3,f},{2,y},{0,z},{x,14}], 1091: [{0,z},{1,e},{2,y},{3,f},{x,14}]), 1092: ?line ok = ukeysort_check(1, [{1,a},{1,a},{1,a},{1,a}], [{1,a}]), 1093: 1094: L1 = [{1,a},{1,b},{1,a}], 1095: L1u = lists:ukeysort(1, L1), 1096: L2 = [{1,a},{1,b},{1,a}], 1097: L2u = lists:ukeysort(1, L2), 1098: ?line ok = ukeysort_check(1, lists:keymerge(1, L1, L2), 1099: lists:ukeymerge(1, L1u, L2u)), 1100: L3 = [{1,a},{1,b},{1,a},{2,a}], 1101: L3u = lists:ukeysort(1, L3), 1102: ?line ok = ukeysort_check(1, lists:keymerge(1, L3, L2), 1103: lists:ukeymerge(1, L3u, L2u)), 1104: L4 = [{1,b},{1,a}], 1105: L4u = lists:ukeysort(1, L4), 1106: ?line ok = ukeysort_check(1, lists:keymerge(1, L1, L4), 1107: lists:ukeymerge(1, L1u, L4u)), 1108: L5 = [{1,a},{1,b},{1,a},{2,a}], 1109: L5u = lists:ukeysort(1, L5), 1110: ?line ok = ukeysort_check(1, lists:keymerge(1, [], L5), 1111: lists:ukeymerge(1, [], L5u)), 1112: ?line ok = ukeysort_check(1, lists:keymerge(1, L5, []), 1113: lists:ukeymerge(1, L5u, [])), 1114: L6 = [{3,a}], 1115: L6u = lists:ukeysort(1, L6), 1116: ?line ok = ukeysort_check(1, lists:keymerge(1, L5, L6), 1117: lists:ukeymerge(1, L5u, L6u)), 1118: 1119: ?line [{b,1},{c,1}] = lists:ukeysort(1, [{c,1},{c,1},{c,1},{c,1},{b,1}]), 1120: ?line [{a,0},{b,2},{c,3},{d,4}] = 1121: lists:ukeysort(1, [{d,4},{c,3},{b,2},{b,2},{a,0}]), 1122: ?line [{a,0},{b,1},{c,1}] = 1123: lists:ukeysort(1, [{c,1},{b,1},{b,1},{b,2},{b,2},{a,0}]), 1124: ?line [{a,0},{b,1},{c,1},{d,4}] = 1125: lists:ukeysort(1, [{c,1},{b,1},{b,2},{a,0},{a,0},{d,4},{d,4}]), 1126: 1127: SFun = fun(L) -> fun(X) -> ukeysort_check(2, X, L) end end, 1128: PL = [{a,1},{b,2},{c,3},{d,4},{e,5},{f,6}], 1129: Ps = perms([{a,1},{b,2},{c,3},{d,4},{e,5},{f,6},{b,2},{a,1}]), 1130: ?line lists:foreach(SFun(PL), Ps), 1131: 1132: M1L = [{1,a},{1,a},{2,b}], 1133: M1s = [{1,a},{2,b}], 1134: ?line lists:foreach(SFun(M1s), perms(M1L)), 1135: M2L = [{1,a},{2,b},{2,b}], 1136: M2s = [{1,a},{2,b}], 1137: ?line lists:foreach(SFun(M2s), perms(M2L)), 1138: M3 = [{1,a},{2,b},{3,c}], 1139: ?line lists:foreach(SFun(M3), perms(M3)), 1140: 1141: ok. 1142: 1143: ukeysort_stable(doc) -> ["ukeysort should keep the first duplicate"]; 1144: ukeysort_stable(suite) -> []; 1145: ukeysort_stable(Config) when is_list(Config) -> 1146: ?line ok = ukeysort_check(1, [{1,b},{1,c}], [{1,b}]), 1147: ?line ok = ukeysort_check(1, [{1,c},{1,b}], [{1,c}]), 1148: ?line ok = ukeysort_check(1, 1149: [{1,c},{1,b},{2,x},{3,p},{2,a}], 1150: [{1,c},{2,x},{3,p}]), 1151: 1152: ?line ok = ukeysort_check(1, [{1,a},{1,b},{1,b}], [{1,a}]), 1153: ?line ok = ukeysort_check(1, [{2,a},{1,b},{2,a}], [{1,b},{2,a}]), 1154: 1155: ?line ok = ukeysort_check_stability(bigfunlist(3)), 1156: ?line ok = ukeysort_check_stability(bigfunlist(10)), 1157: ?line ok = ukeysort_check_stability(bigfunlist(100)), 1158: ?line ok = ukeysort_check_stability(bigfunlist(1000)), 1159: ?line case erlang:system_info(modified_timing_level) of 1160: undefined -> ok = ukeysort_check_stability(bigfunlist(10000)); 1161: _ -> ok 1162: end, 1163: ok. 1164: 1165: ukeysort_error(doc) -> ["ukeysort should exit when given bad arguments"]; 1166: ukeysort_error(suite) -> []; 1167: ukeysort_error(Config) when is_list(Config) -> 1168: ?line {'EXIT', _} = (catch lists:ukeysort(0, [{1,b},{1,c}])), 1169: ?line {'EXIT', _} = (catch lists:ukeysort(3, [{1,b},{1,c}])), 1170: ?line {'EXIT', _} = (catch lists:ukeysort(1.5, [{1,b},{1,c}])), 1171: ?line {'EXIT', _} = (catch lists:ukeysort(x, [{1,b},{1,c}])), 1172: ?line {'EXIT', _} = (catch lists:ukeysort(x, [])), 1173: ?line {'EXIT', _} = (catch lists:ukeysort(x, [{1,b}])), 1174: ?line {'EXIT', _} = (catch lists:ukeysort(1, [a,b])), 1175: ?line {'EXIT', _} = (catch lists:ukeysort(1, [{1,b} | {1,c}])), 1176: ok. 1177: 1178: ukeysort_i(doc) -> ["ukeysort with other key than first element"]; 1179: ukeysort_i(suite) -> []; 1180: ukeysort_i(Config) when is_list(Config) -> 1181: ?line ok = ukeysort_check(2, [{a,2},{b,1},{c,3}], [{b,1},{a,2},{c,3}]), 1182: ok. 1183: 1184: ukeysort_rand(doc) -> ["ukeysort on big randomized lists"]; 1185: ukeysort_rand(suite) -> []; 1186: ukeysort_rand(Config) when is_list(Config) -> 1187: ?line ok = ukeysort_check3(2, biglist(10)), 1188: ?line ok = ukeysort_check3(2, biglist(100)), 1189: ?line ok = ukeysort_check3(2, biglist(1000)), 1190: ?line ok = ukeysort_check3(2, biglist(10000)), 1191: 1192: ?line ok = gen_ukeysort_check(1, ubiglist(10)), 1193: ?line ok = gen_ukeysort_check(1, ubiglist(100)), 1194: ?line ok = gen_ukeysort_check(1, ubiglist(1000)), 1195: ?line ok = gen_ukeysort_check(1, ubiglist(10000)), 1196: ok. 1197: 1198: %% Check that ukeysort/2 is stable and correct relative keysort/2. 1199: %% (this is not affected by the fact that keysort/2 is no longer really 1200: %% stable; ucheck_stability/1 checks ukeysort/2 (and usort/1, of course)) 1201: gen_ukeysort_check(I, Input) -> 1202: U = lists:ukeysort(I, Input), 1203: S = lists:keysort(I, Input), 1204: case U == no_dups_keys(S, I) of 1205: true -> 1206: ok; 1207: false -> 1208: io:format("~w~n", [Input]), 1209: erlang:error(gen_ukeysort_check) 1210: end. 1211: 1212: %% Used for checking that the first copy is kept. 1213: ukeysort_check_stability(L) -> 1214: I = 1, 1215: U = lists:ukeysort(I, L), 1216: S = no_dups_keys(lkeysort(I, L), I), 1217: check_stab(L, U, S, "ukeysort/2", "usort/2"). 1218: 1219: %%% Uniquely keysort a list, check that the returned list is what we 1220: %%% expected, and that it is actually sorted. 1221: ukeysort_check(I, Input, Expected) -> 1222: ?line Expected = lists:ukeysort(I, Input), 1223: ucheck_sorted(I, Input, Expected). 1224: 1225: ukeysort_check3(I, Input) -> 1226: ucheck_sorted(I, 3, Input, lists:ukeysort(I, Input)). 1227: 1228: ucheck_sorted(I, Input, L) -> 1229: ucheck_sorted(I, I, Input, L). 1230: 1231: %%% Check that a list is ukeysorted by element I. Elements comparing 1232: %%% equal should be sorted according to element J. 1233: ucheck_sorted(_I, _J, _Input, []) -> 1234: ok; 1235: ucheck_sorted(I, J, Input, [A | Rest]) -> 1236: case catch ucheck_sorted1(I, J, A, Rest) of 1237: {'EXIT', _} -> 1238: io:format("~w~n", [Input]), 1239: erlang:error(ucheck_sorted); 1240: Reply -> 1241: Reply 1242: end. 1243: 1244: ucheck_sorted1(_I, _J, _A, []) -> 1245: ok; 1246: ucheck_sorted1(I, J, A, [B | Rest]) -> 1247: ok = ukeycompare(I, J, A, B), 1248: ucheck_sorted1(I, J, B, Rest). 1249: 1250: ukeycompare(I, _J, A, B) when element(I, A) < element(I, B) -> 1251: ok; 1252: ukeycompare(I, J, A, B) when A =/= B, 1253: element(I, A) == element(I, B), 1254: element(J, A) =< element(J, B) -> 1255: ok. 1256: 1257: 1258: 1259: funmerge(doc) -> ["Merge two lists using a fun."]; 1260: funmerge(suite) -> []; 1261: funmerge(Config) when is_list(Config) -> 1262: 1263: Two = [1,2], 1264: Six = [1,2,3,4,5,6], 1265: F = fun(X, Y) -> X =< Y end, 1266: 1267: %% 2-way merge 1268: ?line [] = lists:merge(F, [], []), 1269: ?line Two = lists:merge(F, Two, []), 1270: ?line Two = lists:merge(F, [], Two), 1271: ?line Six = lists:merge(F, [1,3,5], [2,4,6]), 1272: ?line Six = lists:merge(F, [2,4,6], [1,3,5]), 1273: ?line Six = lists:merge(F, [1,2,3], [4,5,6]), 1274: ?line Six = lists:merge(F, [4,5,6], [1,2,3]), 1275: ?line Six = lists:merge(F, [1,2,5],[3,4,6]), 1276: ?line [1,2,3,5,7] = lists:merge(F, [1,3,5,7], [2]), 1277: ?line [1,2,3,4,5,7] = lists:merge(F, [1,3,5,7], [2,4]), 1278: ?line [1,2,3,4,5,6,7] = lists:merge(F, [1,3,5,7], [2,4,6]), 1279: ?line [1,2,3,5,7] = lists:merge(F, [2], [1,3,5,7]), 1280: ?line [1,2,3,4,5,7] = lists:merge(F, [2,4], [1,3,5,7]), 1281: ?line [1,2,3,4,5,6,7] = lists:merge(F, [2,4,6], [1,3,5,7]), 1282: 1283: F2 = fun(X,Y) -> element(1,X) =< element(1,Y) end, 1284: ?line [{b,2},{c,11},{c,12},{c,21},{c,22},{e,5}] = 1285: lists:merge(F2,[{c,11},{c,12},{e,5}], [{b,2},{c,21},{c,22}]), 1286: 1287: ok. 1288: 1289: rfunmerge(doc) -> ["Reverse merge two lists using a fun."]; 1290: rfunmerge(suite) -> []; 1291: rfunmerge(Config) when is_list(Config) -> 1292: 1293: Two = [2,1], 1294: Six = [6,5,4,3,2,1], 1295: F = fun(X, Y) -> X =< Y end, 1296: 1297: %% 2-way reversed merge 1298: ?line [] = lists:rmerge(F, [], []), 1299: ?line Two = lists:rmerge(F, Two, []), 1300: ?line Two = lists:rmerge(F, [], Two), 1301: ?line Six = lists:rmerge(F, [5,3,1], [6,4,2]), 1302: ?line Six = lists:rmerge(F, [6,4,2], [5,3,1]), 1303: ?line Six = lists:rmerge(F, [3,2,1], [6,5,4]), 1304: ?line Six = lists:rmerge(F, [6,5,4], [3,2,1]), 1305: ?line Six = lists:rmerge(F, [4,3,2],[6,5,1]), 1306: ?line [7,6,5,3,1] = lists:rmerge(F, [7,5,3,1], [6]), 1307: ?line [7,6,5,4,3,1] = lists:rmerge(F, [7,5,3,1], [6,4]), 1308: ?line [7,6,5,4,3,2,1] = lists:rmerge(F, [7,5,3,1], [6,4,2]), 1309: ?line [7,5,3,2,1] = lists:rmerge(F, [2], [7,5,3,1]), 1310: ?line [7,5,4,3,2,1] = lists:rmerge(F, [4,2], [7,5,3,1]), 1311: ?line [7,6,5,4,3,2,1] = lists:rmerge(F, [6,4,2], [7,5,3,1]), 1312: 1313: F2 = fun(X,Y) -> element(1,X) =< element(1,Y) end, 1314: L1 = [{c,11},{c,12},{e,5}], 1315: L2 = [{b,2},{c,21},{c,22}], 1316: ?line true = 1317: lists:merge(F2, L1, L2) == 1318: lists:reverse(lists:rmerge(F2,lists:reverse(L1), lists:reverse(L2))), 1319: 1320: ok. 1321: 1322: 1323: funsort_1(doc) -> ["sort/2"]; 1324: funsort_1(suite) -> []; 1325: funsort_1(Config) when is_list(Config) -> 1326: ?line ok = funsort_check(1, [], []), 1327: ?line ok = funsort_check(1, [{a,b}], [{a,b}]), 1328: ?line ok = funsort_check(1, [{a,b},{a,b}], [{a,b},{a,b}]), 1329: ?line ok = funsort_check(1, [{a,b},{b,c}], [{a,b},{b,c}]), 1330: ?line ok = funsort_check(1, [{b,c},{a,b}], [{a,b},{b,c}]), 1331: ?line ok = funsort_check(1, 1332: [{1,e},{3,f},{2,y},{0,z},{x,14}], 1333: [{0,z},{1,e},{2,y},{3,f},{x,14}]), 1334: F = funsort_fun(1), 1335: 1336: ?line [{b,1},{c,1}] = lists:sort(F, [{c,1},{b,1}]), 1337: ?line [{a,0},{b,2},{c,3},{d,4}] = 1338: lists:sort(F, [{d,4},{c,3},{b,2},{a,0}]), 1339: ?line [{a,0},{b,1},{b,2},{c,1}] = 1340: lists:sort(F, [{c,1},{b,1},{b,2},{a,0}]), 1341: ?line [{a,0},{b,1},{b,2},{c,1},{d,4}] = 1342: lists:sort(F, [{c,1},{b,1},{b,2},{a,0},{d,4}]), 1343: 1344: SFun = fun(L) -> fun(X) -> funsort_check(1, X, L) end end, 1345: L1 = [{1,a},{1,a},{2,b},{2,b},{3,c},{4,d},{5,e},{6,f}], 1346: ?line lists:foreach(SFun(L1), perms(L1)), 1347: 1348: ok. 1349: 1350: funsort_stable(doc) -> ["sort/2 should be stable"]; 1351: funsort_stable(suite) -> []; 1352: funsort_stable(Config) when is_list(Config) -> 1353: ?line ok = funsort_check(1, [{1,b},{1,c}], [{1,b},{1,c}]), 1354: ?line ok = funsort_check(1, [{1,c},{1,b}], [{1,c},{1,b}]), 1355: ?line ok = funsort_check(1, 1356: [{1,c},{1,b},{2,x},{3,p},{2,a}], 1357: [{1,c},{1,b},{2,x},{2,a},{3,p}]), 1358: ok. 1359: 1360: funsort_error(doc) -> ["sort/2 should exit when given bad arguments"]; 1361: funsort_error(suite) -> []; 1362: funsort_error(Config) when is_list(Config) -> 1363: ?line {'EXIT', _} = (catch lists:sort(1, [{1,b} , {1,c}])), 1364: ?line {'EXIT', _} = (catch lists:sort(fun(X,Y) -> X =< Y end, 1365: [{1,b} | {1,c}])), 1366: ok. 1367: 1368: funsort_rand(doc) -> ["sort/2 on big randomized lists"]; 1369: funsort_rand(suite) -> []; 1370: funsort_rand(Config) when is_list(Config) -> 1371: ?line ok = funsort_check3(1, biglist(10)), 1372: ?line ok = funsort_check3(1, biglist(100)), 1373: ?line ok = funsort_check3(1, biglist(1000)), 1374: ?line ok = funsort_check3(1, biglist(10000)), 1375: ok. 1376: 1377: % Do a keysort 1378: funsort(I, L) -> 1379: lists:sort(funsort_fun(I), L). 1380: 1381: funsort_check3(I, Input) -> 1382: check_sorted(I, 3, Input, funsort(I, Input)). 1383: 1384: %%% Keysort a list, check that the returned list is what we expected, 1385: %%% and that it is actually sorted. 1386: funsort_check(I, Input, Expected) -> 1387: ?line Expected = funsort(I, Input), 1388: check_sorted(I, Input, Expected). 1389: 1390: 1391: ufunmerge(suite) -> []; 1392: ufunmerge(doc) -> ["Merge two lists while removing duplicates using a fun."]; 1393: ufunmerge(Conf) when is_list(Conf) -> 1394: 1395: Two = [1,2], 1396: Six = [1,2,3,4,5,6], 1397: F = fun(X, Y) -> X =< Y end, 1398: 1399: %% 2-way unique merge 1400: ?line [] = lists:umerge(F, [], []), 1401: ?line Two = lists:umerge(F, Two, []), 1402: ?line Two = lists:umerge(F, [], Two), 1403: ?line Six = lists:umerge(F, [1,3,5], [2,4,6]), 1404: ?line Six = lists:umerge(F, [2,4,6], [1,3,5]), 1405: ?line Six = lists:umerge(F, [1,2,3], [4,5,6]), 1406: ?line Six = lists:umerge(F, [4,5,6], [1,2,3]), 1407: ?line Six = lists:umerge(F, [1,2,5],[3,4,6]), 1408: ?line [1,2,3,5,7] = lists:umerge(F, [1,3,5,7], [2]), 1409: ?line [1,2,3,4,5,7] = lists:umerge(F, [1,3,5,7], [2,4]), 1410: ?line [1,2,3,4,5,6,7] = lists:umerge(F, [1,3,5,7], [2,4,6]), 1411: ?line [1,2,3,5,7] = lists:umerge(F, [2], [1,3,5,7]), 1412: ?line [1,2,3,4,5,7] = lists:umerge(F, [2,4], [1,3,5,7]), 1413: ?line [1,2,3,4,5,6,7] = lists:umerge(F, [2,4,6], [1,3,5,7]), 1414: 1415: ?line [1,2,3,5,7] = lists:umerge(F, [1,2,3,5,7], [2]), 1416: ?line [1,2,3,4,5,7] = lists:umerge(F, [1,2,3,4,5,7], [2,4]), 1417: ?line [1,2,3,4,5,6,7] = lists:umerge(F, [1,3,5,6,7], [2,4,6]), 1418: ?line [1,2,3,5,7] = lists:umerge(F, [2], [1,2,3,5,7]), 1419: ?line [1,2,3,4,5,7] = lists:umerge(F, [2,4], [1,2,3,4,5,7]), 1420: ?line [1,2,3,4,5,6,7] = lists:umerge(F, [2,4,6], [1,2,3,4,5,6,7]), 1421: 1422: L1 = [{a,1},{a,3},{a,5},{a,7}], 1423: L2 = [{b,1},{b,3},{b,5},{b,7}], 1424: F2 = fun(X,Y) -> element(2,X) =< element(2,Y) end, 1425: ?line L1 = lists:umerge(F2, L1, L2), 1426: ?line [{b,2},{e,5},{c,11},{c,12},{c,21},{c,22}] = 1427: lists:umerge(F2, [{e,5},{c,11},{c,12}], [{b,2},{c,21},{c,22}]), 1428: 1429: ok. 1430: 1431: rufunmerge(suite) -> []; 1432: rufunmerge(doc) -> 1433: ["Reverse merge two lists while removing duplicates using a fun."]; 1434: rufunmerge(Conf) when is_list(Conf) -> 1435: Two = [2,1], 1436: Six = [6,5,4,3,2,1], 1437: F = fun(X, Y) -> X =< Y end, 1438: 1439: %% 2-way reversed unique merge 1440: ?line [] = lists:rumerge(F, [], []), 1441: ?line Two = lists:rumerge(F, Two, []), 1442: ?line Two = lists:rumerge(F, [], Two), 1443: ?line Six = lists:rumerge(F, [5,3,1], [6,4,2]), 1444: ?line Six = lists:rumerge(F, [6,4,2], [5,3,1]), 1445: ?line Six = lists:rumerge(F, [3,2,1], [6,5,4]), 1446: ?line Six = lists:rumerge(F, [6,5,4], [3,2,1]), 1447: ?line Six = lists:rumerge(F, [4,3,2],[6,5,1]), 1448: ?line [7,6,5,3,1] = lists:rumerge(F, [7,5,3,1], [6]), 1449: ?line [7,6,5,4,3,1] = lists:rumerge(F, [7,5,3,1], [6,4]), 1450: ?line [7,6,5,4,3,2,1] = lists:rumerge(F, [7,5,3,1], [6,4,2]), 1451: ?line [7,5,3,2,1] = lists:rumerge(F, [2], [7,5,3,1]), 1452: ?line [7,5,4,3,2,1] = lists:rumerge(F, [4,2], [7,5,3,1]), 1453: ?line [7,6,5,4,3,2,1] = lists:rumerge(F, [6,4,2], [7,5,3,1]), 1454: 1455: ?line [7,6,5,3,1] = lists:rumerge(F, [7,6,5,3,1], [6]), 1456: ?line [7,6,5,4,3,1] = lists:rumerge(F, [7,6,5,4,3,1], [6,4]), 1457: ?line [7,6,5,4,3,2,1] = lists:rumerge(F, [7,6,5,4,3,2,1], [6,4,2]), 1458: ?line [7,5,3,2,1] = lists:rumerge(F, [2], [7,5,3,2,1]), 1459: ?line [7,5,4,3,2,1] = lists:rumerge(F, [4,2], [7,5,4,3,2,1]), 1460: ?line [7,6,5,4,3,2,1] = lists:rumerge(F, [6,4,2], [7,6,5,4,3,2,1]), 1461: 1462: F2 = fun(X,Y) -> element(1,X) =< element(1,Y) end, 1463: L1 = [{1,a},{1,b},{1,a}], 1464: L2 = [{1,a},{1,b},{1,a}], 1465: ?line true = lists:umerge(F2, L1, L2) == 1466: lists:reverse(lists:rumerge(F, lists:reverse(L2), lists:reverse(L1))), 1467: 1468: L3 = [{c,11},{c,12},{e,5}], 1469: L4 = [{b,2},{c,21},{c,22}], 1470: ?line true = 1471: lists:umerge(F2, L3, L4) == 1472: lists:reverse(lists:rumerge(F2,lists:reverse(L3), lists:reverse(L4))), 1473: 1474: ok. 1475: 1476: ufunsort_1(doc) -> ["usort/2"]; 1477: ufunsort_1(suite) -> []; 1478: ufunsort_1(Config) when is_list(Config) -> 1479: ?line ok = ufunsort_check(1, [], []), 1480: ?line ok = ufunsort_check(1, [{a,b}], [{a,b}]), 1481: ?line ok = ufunsort_check(1, [{a,b},{a,b}], [{a,b}]), 1482: ?line ok = ufunsort_check(1, [{a,b},{b,c}], [{a,b},{b,c}]), 1483: ?line ok = ufunsort_check(1, [{b,c},{a,b}], [{a,b},{b,c}]), 1484: ?line ok = ufunsort_check(1, 1485: [{1,e},{3,f},{2,y},{0,z},{x,14}], 1486: [{0,z},{1,e},{2,y},{3,f},{x,14}]), 1487: ?line ok = ufunsort_check(1, 1488: [{1,a},{2,b},{3,c},{2,b},{1,a},{2,b},{3,c}, 1489: {2,b},{1,a}], 1490: [{1,a},{2,b},{3,c}]), 1491: ?line ok = ufunsort_check(1, 1492: [{1,a},{1,a},{1,b},{1,b},{1,a},{2,a}], 1493: [{1,a},{2,a}]), 1494: 1495: F = funsort_fun(1), 1496: L1 = [{1,a},{1,b},{1,a}], 1497: L2 = [{1,a},{1,b},{1,a}], 1498: ?line ok = ufunsort_check(1, lists:keymerge(1, L1, L2), 1499: lists:umerge(F, lists:usort(F, L1), 1500: lists:usort(F, L2))), 1501: L3 = [{1,a},{1,b},{1,a},{2,a}], 1502: ?line ok = ufunsort_check(1, lists:keymerge(1, L3, L2), 1503: lists:umerge(F, lists:usort(F, L3), 1504: lists:usort(F, L2))), 1505: L4 = [{1,b},{1,a}], 1506: ?line ok = ufunsort_check(1, lists:keymerge(1, L1, L4), 1507: lists:umerge(F, lists:usort(F, L1), 1508: lists:usort(F, L4))), 1509: L5 = [{1,a},{1,b},{1,a},{2,a}], 1510: ?line ok = ufunsort_check(1, lists:keymerge(1, L5, []), 1511: lists:umerge(F, lists:usort(F, L5), [])), 1512: L6 = [{3,a}], 1513: ?line ok = ufunsort_check(1, lists:keymerge(1, L5, L6), 1514: lists:umerge(F, lists:usort(F, L5), 1515: lists:usort(F, L6))), 1516: 1517: ?line [{b,1},{c,1}] = lists:usort(F, [{c,1},{c,1},{b,1}]), 1518: ?line [{a,0},{b,2},{c,3},{d,4}] = 1519: lists:usort(F, [{d,4},{c,3},{b,2},{b,2},{a,0}]), 1520: ?line [{a,0},{b,1},{c,1}] = 1521: lists:usort(F, [{c,1},{b,1},{b,1},{b,2},{b,2},{a,0}]), 1522: ?line [{a,0},{b,1},{c,1},{d,4}] = 1523: lists:usort(F, [{c,1},{b,1},{b,2},{a,0},{a,0},{d,4},{d,4}]), 1524: 1525: SFun = fun(L) -> fun(X) -> ufunsort_check(1, X, L) end end, 1526: PL = [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f}], 1527: Ps = perms([{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{2,b},{1,a}]), 1528: ?line lists:foreach(SFun(PL), Ps), 1529: 1530: ok. 1531: 1532: ufunsort_stable(doc) -> ["usort/2 should be stable"]; 1533: ufunsort_stable(suite) -> []; 1534: ufunsort_stable(Config) when is_list(Config) -> 1535: ?line ok = ufunsort_check(1, [{1,b},{1,c}], [{1,b}]), 1536: ?line ok = ufunsort_check(1, [{1,c},{1,b}], [{1,c}]), 1537: ?line ok = ufunsort_check(1, 1538: [{1,c},{1,b},{2,x},{3,p},{2,a}], 1539: [{1,c},{2,x},{3,p}]), 1540: 1541: ?line ok = ufunsort_check_stability(bigfunlist(10)), 1542: ?line ok = ufunsort_check_stability(bigfunlist(100)), 1543: ?line ok = ufunsort_check_stability(bigfunlist(1000)), 1544: ?line case erlang:system_info(modified_timing_level) of 1545: undefined -> ok = ufunsort_check_stability(bigfunlist(10000)); 1546: _ -> ok 1547: end, 1548: ok. 1549: 1550: ufunsort_error(doc) -> ["usort/2 should exit when given bad arguments"]; 1551: ufunsort_error(suite) -> []; 1552: ufunsort_error(Config) when is_list(Config) -> 1553: ?line {'EXIT', _} = (catch lists:usort(1, [{1,b} , {1,c}])), 1554: ?line {'EXIT', _} = (catch lists:usort(fun(X,Y) -> X =< Y end, 1555: [{1,b} | {1,c}])), 1556: ok. 1557: 1558: ufunsort_rand(doc) -> ["usort/2 on big randomized lists"]; 1559: ufunsort_rand(suite) -> []; 1560: ufunsort_rand(Config) when is_list(Config) -> 1561: ?line ok = ufunsort_check3(1, biglist(10)), 1562: ?line ok = ufunsort_check3(1, biglist(100)), 1563: ?line ok = ufunsort_check3(1, biglist(1000)), 1564: ?line ok = ufunsort_check3(1, biglist(10000)), 1565: 1566: ?line ok = gen_ufunsort_check(1, ubiglist(100)), 1567: ?line ok = gen_ufunsort_check(1, ubiglist(1000)), 1568: ?line ok = gen_ufunsort_check(1, ubiglist(10000)), 1569: ok. 1570: 1571: %% Check that usort/2 is stable and correct relative sort/2. 1572: gen_ufunsort_check(I, Input) -> 1573: U = ufunsort(I, Input), 1574: S = funsort(I, Input), 1575: case U == no_dups_keys(S, I) of 1576: true -> 1577: ok; 1578: false -> 1579: io:format("~w~n", [Input]), 1580: erlang:error(gen_ufunsort_check) 1581: end. 1582: 1583: %% Used for checking that the first copy is kept. 1584: ufunsort_check_stability(L) -> 1585: I = 1, 1586: U = ufunsort(I, L), 1587: S = no_dups(funsort(I, L)), 1588: check_stab(L, U, S, "usort/2", "sort/2"). 1589: 1590: ufunsort_check3(I, Input) -> 1591: ucheck_sorted(I, 3, Input, ufunsort(I, Input)). 1592: 1593: %%% Keysort a list, check that the returned list is what we expected, 1594: %%% and that it is actually sorted. 1595: ufunsort_check(I, Input, Expected) -> 1596: ?line Expected = ufunsort(I, Input), 1597: ucheck_sorted(I, Input, Expected). 1598: 1599: % Do a keysort 1600: ufunsort(I, L) -> 1601: lists:usort(funsort_fun(I), L). 1602: 1603: funsort_fun(I) -> 1604: fun(A, B) when tuple_size(A) >= I, tuple_size(B) >= I -> 1605: element(I, A) =< element(I, B) 1606: end. 1607: 1608: check_stab(L, U, S, US, SS) -> 1609: UP = explicit_pid(U), 1610: SP = explicit_pid(S), 1611: case UP == SP of 1612: true -> 1613: ok; 1614: false -> 1615: io:format("In: ~w~n", [explicit_pid(L)]), 1616: io:format("~s: ~w~n", [US, UP]), 1617: io:format("~s: ~w~n", [SS, SP]), 1618: erlang:error(unstable) 1619: end. 1620: 1621: %%%------------------------------------------------------------ 1622: %%% Generate lists of given length, containing 3-tuples with 1623: %%% random integer elements in the range 0..44 as elements 1 and 2. 1624: %%% Element 3 in the tuple is the position of the tuple in the list. 1625: 1626: biglist(N) -> 1627: {A, B, C} = get_seed(), 1628: random:seed(A, B, C), 1629: biglist(N, []). 1630: 1631: biglist(0, L) -> 1632: L; 1633: biglist(N, L) -> 1634: E = random_tuple(45, N), 1635: biglist(N-1, [E|L]). 1636: 1637: %%%------------------------------------------------------------ 1638: %%% Generate lists of given length, containing 2-tuples with 1639: %%% random integer elements in the range 0..10 as element 1. 1640: %%% Element 2 in the tuple is a random integer in the range 0..5. 1641: %%% No sequence number. 1642: 1643: ubiglist(N) -> 1644: {A, B, C} = get_seed(), 1645: random:seed(A, B, C), 1646: ubiglist(N, []). 1647: 1648: ubiglist(0, L) -> 1649: L; 1650: ubiglist(N, L) -> 1651: E = urandom_tuple(11, 6), 1652: ubiglist(N-1, [E|L]). 1653: 1654: urandom_tuple(N, I) -> 1655: R1 = randint(N), 1656: R2 = randint(I), 1657: {R1, R2}. 1658: 1659: %%%------------------------------------------------------------ 1660: %%% Generate lists of given length, containing 2-tuples with random 1661: %%% integer elements in the range 0..10 as elements 1. All tuples have 1662: %%% the same function as element 2, but every function is created in a 1663: %%% unique process. ==/2 will return 'true' for any pair of functions, 1664: %%% but erlang:fun_info(Fun, pid) can be used for distinguishing 1665: %%% functions created in different processes. The pid acts like a 1666: %%% sequence number. 1667: 1668: bigfunlist(N) -> 1669: {A, B, C} = get_seed(), 1670: random:seed(A, B, C), 1671: bigfunlist_1(N). 1672: 1673: bigfunlist_1(N) when N < 30000 -> % Now (R8) max 32000 different pids. 1674: case catch bigfunlist(N, 0, []) of 1675: {'EXIT', _} -> 1676: bigfunlist_1(N); 1677: Reply -> 1678: Reply 1679: end. 1680: 1681: bigfunlist(0, _P, L) -> 1682: lists:reverse(L); 1683: bigfunlist(N, P, L) -> 1684: {E, NP} = random_funtuple(P, 11), 1685: bigfunlist(N-1, NP, [E | L]). 1686: 1687: random_funtuple(P, N) -> 1688: R = randint(N), 1689: F = make_fun(), 1690: NP = fun_pid(F), 1691: true = NP > P, 1692: {{R, F}, NP}. 1693: 1694: make_fun() -> 1695: Pid = spawn(?MODULE, make_fun, [self()]), 1696: receive {Pid, Fun} -> Fun end. 1697: 1698: make_fun(Pid) -> 1699: Pid ! {self(), fun make_fun/1}. 1700: 1701: fun_pid(Fun) -> 1702: erlang:fun_info(Fun, pid). 1703: 1704: get_seed() -> 1705: case random:seed() of 1706: undefined -> 1707: now(); 1708: Tuple -> 1709: Tuple 1710: end. 1711: 1712: random_tuple(N, Seq) -> 1713: R1 = randint(N), 1714: R2 = randint(N), 1715: {R1, R2, Seq}. 1716: 1717: randint(N) -> 1718: trunc(random:uniform() * N). 1719: 1720: %% The first "duplicate" is kept. 1721: no_dups([]) -> 1722: []; 1723: no_dups([H | T]) -> 1724: no_dups(H, T, []). 1725: 1726: no_dups(H, [H1 | T], L) when H == H1 -> 1727: no_dups(H, T, L); 1728: no_dups(H, [H1 | T], L) -> 1729: no_dups(H1, T, [H | L]); 1730: no_dups(H, [], L) -> 1731: lists:reverse([H | L]). 1732: 1733: %% The first "duplicate" is kept. 1734: no_dups_keys([], _I) -> 1735: []; 1736: no_dups_keys([H | T], I) -> 1737: no_dups_keys(H, T, [], I). 1738: 1739: no_dups_keys(H, [H1 | T], L, I) when element(I, H) == element(I, H1) -> 1740: no_dups_keys(H, T, L, I); 1741: no_dups_keys(H, [H1 | T], L, I) -> 1742: no_dups_keys(H1, T, [H | L], I); 1743: no_dups_keys(H, [], L, _I) -> 1744: lists:reverse([H | L]). 1745: 1746: perms([]) -> 1747: [[]]; 1748: perms(L) -> 1749: [[H|T] || H <- L, T <- perms(L--[H])]. 1750: 1751: %%%------------------------------------------------------------ 1752: %%% Test the sort routines with randomly generated lists. 1753: 1754: -record(state, {sort = 0, usort = 0, stable = 0}). 1755: 1756: %% Run it interactively. 'stop' or 'info' recognized commands. 1757: sort_loop() -> 1758: sort_loop(5000). 1759: 1760: sort_loop(N) when is_integer(N), N > 0 -> 1761: Pid = spawn_link(?MODULE, sloop, [N]), 1762: sort_loop_1(Pid). 1763: 1764: sort_loop_1(Pid) -> 1765: case io:get_line('? ') of 1766: eof -> 1767: ok; 1768: "stop\n" -> 1769: Pid ! {self(), stop}, 1770: receive {Pid, S} -> display_state(S) end; 1771: "info\n" -> 1772: Pid ! {self(), info}, 1773: receive {Pid, S} -> display_state(S) end, 1774: sort_loop_1(Pid); 1775: _Other -> 1776: sort_loop_1(Pid) 1777: end. 1778: 1779: sloop(N) -> 1780: {A, B, C} = get_seed(), 1781: random:seed(A, B, C), 1782: sloop(N, #state{}). 1783: 1784: sloop(N, S) -> 1785: receive 1786: {From, stop} -> 1787: From ! {self(), S}; 1788: {From, info} -> 1789: From ! {self(), S}, 1790: sloop(N, S) 1791: after 0 -> 1792: Len = randint(N), 1793: NS = case randint(3) of 1794: 0 -> 1795: BL = biglist(Len, []), 1796: ok = check(BL), 1797: ok = keysort_check3(1, BL), 1798: ok = funsort_check3(1, BL), 1799: S#state{sort = S#state.sort + 1}; 1800: 1 -> 1801: BL = ubiglist(Len, []), 1802: ok = ucheck(BL), 1803: ok = gen_ukeysort_check(1, BL), 1804: ok = gen_ufunsort_check(1, BL), 1805: S#state{usort = S#state.usort + 1}; 1806: 2 -> 1807: BL = bigfunlist(Len), 1808: %% ok = check_stability(BL), 1809: ok = ucheck_stability(BL), 1810: ok = ukeysort_check_stability(BL), 1811: ok = ufunsort_check_stability(BL), 1812: S#state{stable = S#state.stable + 1} 1813: end, 1814: sloop(N, NS) 1815: end. 1816: 1817: display_state(S) -> 1818: io:format("sort: ~p~n", [S#state.sort]), 1819: io:format("usort: ~p~n", [S#state.usort]), 1820: io:format("stable: ~p~n", [S#state.stable]). 1821: 1822: %% This version of sort/1 is really stable; the order of equal 1823: %% elements is kept. It is used for checking the current 1824: %% implementation of usort/1 etc. 1825: 1826: lsort([X, Y | L] = L0) when X =< Y -> 1827: case L of 1828: [] -> 1829: L0; 1830: [Z] when Y =< Z -> 1831: L0; 1832: [Z] when X =< Z -> 1833: [X, Z, Y]; 1834: [Z] -> 1835: [Z, X, Y]; 1836: _ -> 1837: split_1(X, Y, L, [], []) 1838: end; 1839: lsort([X, Y | L]) -> 1840: case L of 1841: [] -> 1842: [Y, X]; 1843: [Z] when X =< Z -> 1844: [Y, X | L]; 1845: [Z] when Y =< Z -> 1846: [Y, Z, X]; 1847: [Z] -> 1848: [Z, Y, X]; 1849: _ -> 1850: split_2(X, Y, L, [], []) 1851: end; 1852: lsort([_] = L) -> 1853: L; 1854: lsort([] = L) -> 1855: L. 1856: 1857: split_1(X, Y, [Z | L], R, Rs) when Z >= Y -> 1858: split_1(Y, Z, L, [X | R], Rs); 1859: split_1(X, Y, [Z | L], R, Rs) when Z >= X -> 1860: split_1(Z, Y, L, [X | R], Rs); 1861: split_1(X, Y, [Z | L], [], Rs) -> 1862: split_1(X, Y, L, [Z], Rs); 1863: split_1(X, Y, [Z | L], R, Rs) -> 1864: split_1_1(X, Y, L, R, Rs, Z); 1865: split_1(X, Y, [], R, Rs) -> 1866: rmergel([[Y, X | R] | Rs], [], asc). 1867: 1868: split_1_1(X, Y, [Z | L], R, Rs, S) when Z >= Y -> 1869: split_1_1(Y, Z, L, [X | R], Rs, S); 1870: split_1_1(X, Y, [Z | L], R, Rs, S) when Z >= X -> 1871: split_1_1(Z, Y, L, [X | R], Rs, S); 1872: split_1_1(X, Y, [Z | L], R, Rs, S) when S =< Z -> 1873: split_1(S, Z, L, [], [[Y, X | R] | Rs]); 1874: split_1_1(X, Y, [Z | L], R, Rs, S) -> 1875: split_1(Z, S, L, [], [[Y, X | R] | Rs]); 1876: split_1_1(X, Y, [], R, Rs, S) -> 1877: rmergel([[S], [Y, X | R] | Rs], [], asc). 1878: 1879: split_2(X, Y, [Z | L], R, Rs) when Z < Y -> 1880: split_2(Y, Z, L, [X | R], Rs); 1881: split_2(X, Y, [Z | L], R, Rs) when Z < X -> 1882: split_2(Z, Y, L, [X | R], Rs); 1883: split_2(X, Y, [Z | L], [], Rs) -> 1884: split_2(X, Y, L, [Z], Rs); 1885: split_2(X, Y, [Z | L], R, Rs) -> 1886: split_2_1(X, Y, L, R, Rs, Z); 1887: split_2(X, Y, [], R, Rs) -> 1888: mergel([[Y, X | R] | Rs], [], desc). 1889: 1890: split_2_1(X, Y, [Z | L], R, Rs, S) when Z < Y -> 1891: split_2_1(Y, Z, L, [X | R], Rs, S); 1892: split_2_1(X, Y, [Z | L], R, Rs, S) when Z < X -> 1893: split_2_1(Z, Y, L, [X | R], Rs, S); 1894: split_2_1(X, Y, [Z | L], R, Rs, S) when S > Z -> 1895: split_2(S, Z, L, [], [[Y, X | R] | Rs]); 1896: split_2_1(X, Y, [Z | L], R, Rs, S) -> 1897: split_2(Z, S, L, [], [[Y, X | R] | Rs]); 1898: split_2_1(X, Y, [], R, Rs, S) -> 1899: mergel([[S], [Y, X | R] | Rs], [], desc). 1900: 1901: mergel([[] | L], Acc, O) -> 1902: mergel(L, Acc, O); 1903: mergel([T1, [H2 | T2] | L], Acc, asc) -> 1904: mergel(L, [merge2_1(T1, H2, T2, []) | Acc], asc); 1905: mergel([[H2 | T2], T1 | L], Acc, desc) -> 1906: mergel(L, [merge2_1(T1, H2, T2, []) | Acc], desc); 1907: mergel([L], [], _O) -> 1908: L; 1909: mergel([L], Acc, O) -> 1910: rmergel([lists:reverse(L, []) | Acc], [], O); 1911: mergel([], [], _O) -> 1912: []; 1913: mergel([], Acc, O) -> 1914: rmergel(Acc, [], O); 1915: mergel([A, [] | L], Acc, O) -> 1916: mergel([A | L], Acc, O); 1917: mergel([A, B, [] | L], Acc, O) -> 1918: mergel([A, B | L], Acc, O). 1919: 1920: rmergel([[H2 | T2], T1 | L], Acc, asc) -> 1921: rmergel(L, [rmerge2_1(T1, H2, T2, []) | Acc], asc); 1922: rmergel([T1, [H2 | T2] | L], Acc, desc) -> 1923: rmergel(L, [rmerge2_1(T1, H2, T2, []) | Acc], desc); 1924: rmergel([L], Acc, O) -> 1925: mergel([lists:reverse(L, []) | Acc], [], O); 1926: rmergel([], Acc, O) -> 1927: mergel(Acc, [], O). 1928: 1929: merge2_1([H1 | T1], H2, T2, M) when H1 =< H2 -> 1930: merge2_1(T1, H2, T2, [H1 | M]); 1931: merge2_1([H1 | T1], H2, T2, M) -> 1932: merge2_2(T1, H1, T2, [H2 | M]); 1933: merge2_1([], H2, T2, M) -> 1934: lists:reverse(T2, [H2 | M]). 1935: 1936: merge2_2(T1, H1, [H2 | T2], M) when H1 =< H2 -> 1937: merge2_1(T1, H2, T2, [H1 | M]); 1938: merge2_2(T1, H1, [H2 | T2], M) -> 1939: merge2_2(T1, H1, T2, [H2 | M]); 1940: merge2_2(T1, H1, [], M) -> 1941: lists:reverse(T1, [H1 | M]). 1942: 1943: rmerge2_1([H1 | T1], H2, T2, M) when H1 =< H2 -> 1944: rmerge2_2(T1, H1, T2, [H2 | M]); 1945: rmerge2_1([H1 | T1], H2, T2, M) -> 1946: rmerge2_1(T1, H2, T2, [H1 | M]); 1947: rmerge2_1([], H2, T2, M) -> 1948: lists:reverse(T2, [H2 | M]). 1949: 1950: rmerge2_2(T1, H1, [H2 | T2], M) when H1 =< H2 -> 1951: rmerge2_2(T1, H1, T2, [H2 | M]); 1952: rmerge2_2(T1, H1, [H2 | T2], M) -> 1953: rmerge2_1(T1, H2, T2, [H1 | M]); 1954: rmerge2_2(T1, H1, [], M) -> 1955: lists:reverse(T1, [H1 | M]). 1956: 1957: 1958: 1959: %% This version of keysort/2 is really stable; the order of equal 1960: %% elements is kept. It is used for checking the current 1961: %% implementation of ukeysort/2 etc. 1962: 1963: lkeysort(Index, L) when is_integer(Index), Index > 0 -> 1964: case L of 1965: [] -> L; 1966: [_] -> L; 1967: [X, Y | T] -> 1968: EX = element(Index, X), 1969: EY = element(Index, Y), 1970: if 1971: EX =< EY -> 1972: keysplit_1(Index, X, EX, Y, EY, T, [], []); 1973: true -> 1974: keysplit_2(Index, Y, EY, T, [X]) 1975: end 1976: end. 1977: 1978: keysplit_1(I, X, EX, Y, EY, [Z | L], R, Rs) -> 1979: EZ = element(I, Z), 1980: if 1981: EY =< EZ -> 1982: keysplit_1(I, Y, EY, Z, EZ, L, [X | R], Rs); 1983: EX =< EZ -> 1984: keysplit_1(I, Z, EZ, Y, EY, L, [X | R], Rs); 1985: true, R == [] -> 1986: keysplit_1(I, X, EX, Y, EY, L, [Z], Rs); 1987: true -> 1988: keysplit_1_1(I, X, EX, Y, EY, L, R, Rs, Z, EZ) 1989: end; 1990: keysplit_1(I, X, _EX, Y, _EY, [], R, Rs) -> 1991: rkeymergel(I, [[Y, X | R] | Rs], []). 1992: 1993: %% One out-of-order element, S. 1994: keysplit_1_1(I, X, EX, Y, EY, [Z | L], R, Rs, S, ES) -> 1995: EZ = element(I, Z), 1996: if 1997: EY =< EZ -> 1998: keysplit_1_1(I, Y, EY, Z, EZ, L, [X | R], Rs, S, ES); 1999: EX =< EZ -> 2000: keysplit_1_1(I, Z, EZ, Y, EY, L, [X | R], Rs, S, ES); 2001: ES =< EZ -> 2002: keysplit_1(I, S, ES, Z, EZ, L, [], [[Y, X | R] | Rs]); 2003: true -> 2004: keysplit_1(I, Z, EZ, S, ES, L, [], [[Y, X | R] | Rs]) 2005: end; 2006: keysplit_1_1(I, X, _EX, Y, _EY, [], R, Rs, S, _ES) -> 2007: rkeymergel(I, [[S], [Y, X | R] | Rs], []). 2008: 2009: %% Descending. 2010: keysplit_2(I, Y, EY, [Z | L], R) -> 2011: EZ = element(I, Z), 2012: if 2013: EY =< EZ -> 2014: keysplit_1(I, Y, EY, Z, EZ, L, [], [lists:reverse(R, [])]); 2015: true -> 2016: keysplit_2(I, Z, EZ, L, [Y | R]) 2017: end; 2018: keysplit_2(_I, Y, _EY, [], R) -> 2019: [Y | R]. 2020: 2021: keymergel(I, [T1, [H2 | T2] | L], Acc) -> 2022: keymergel(I, L, [keymerge2_1(I, T1, element(I, H2), H2, T2, []) | Acc]); 2023: keymergel(_I, [L], []) -> 2024: L; 2025: keymergel(I, [L], Acc) -> 2026: rkeymergel(I, [lists:reverse(L, []) | Acc], []); 2027: keymergel(I, [], Acc) -> 2028: rkeymergel(I, Acc, []). 2029: 2030: rkeymergel(I, [[H2 | T2], T1 | L], Acc) -> 2031: rkeymergel(I, L, [rkeymerge2_1(I, T1, element(I, H2), H2, T2, []) | Acc]); 2032: rkeymergel(I, [L], Acc) -> 2033: keymergel(I, [lists:reverse(L, []) | Acc], []); 2034: rkeymergel(I, [], Acc) -> 2035: keymergel(I, Acc, []). 2036: 2037: keymerge2_1(I, [H1 | T1], E2, H2, T2, M) -> 2038: E1 = element(I, H1), 2039: if 2040: E1 =< E2 -> 2041: keymerge2_1(I, T1, E2, H2, T2, [H1 | M]); 2042: true -> 2043: keymerge2_2(I, T1, E1, H1, T2, [H2 | M]) 2044: end; 2045: keymerge2_1(_I, [], _E2, H2, T2, M) -> 2046: lists:reverse(T2, [H2 | M]). 2047: 2048: keymerge2_2(I, T1, E1, H1, [H2 | T2], M) -> 2049: E2 = element(I, H2), 2050: if 2051: E1 =< E2 -> 2052: keymerge2_1(I, T1, E2, H2, T2, [H1 | M]); 2053: true -> 2054: keymerge2_2(I, T1, E1, H1, T2, [H2 | M]) 2055: end; 2056: keymerge2_2(_I, T1, _E1, H1, [], M) -> 2057: lists:reverse(T1, [H1 | M]). 2058: 2059: rkeymerge2_1(I, [H1 | T1], E2, H2, T2, M) -> 2060: E1 = element(I, H1), 2061: if 2062: E1 =< E2 -> 2063: rkeymerge2_2(I, T1, E1, T2, [H2 | M], H1); 2064: true -> 2065: rkeymerge2_1(I, T1, E2, H2, T2, [H1 | M]) 2066: end; 2067: rkeymerge2_1(_I, [], _E2, H2, T2, M) -> 2068: lists:reverse(T2, [H2 | M]). 2069: 2070: rkeymerge2_2(I, T1, E1, [H2 | T2], M, H1) -> 2071: E2 = element(I, H2), 2072: if 2073: E1 =< E2 -> 2074: rkeymerge2_2(I, T1, E1, T2, [H2 | M], H1); 2075: true -> 2076: rkeymerge2_1(I, T1, E2, H2, T2, [H1 | M]) 2077: end; 2078: rkeymerge2_2(_I, T1, _E1, [], M, H1) -> 2079: lists:reverse(T1, [H1 | M]). 2080: 2081: 2082: %%%------------------------------------------------------------ 2083: 2084: 2085: seq_loop(doc) -> 2086: ["Test for infinite loop (OTP-2404)."]; 2087: seq_loop(suite) -> 2088: []; 2089: seq_loop(Config) when is_list(Config) -> 2090: ?line _ = (catch lists:seq(1, 5, -1)), 2091: ok. 2092: 2093: seq_2(doc) -> 2094: ["Non-error cases for seq/2"]; 2095: seq_2(suite) -> 2096: []; 2097: seq_2(Config) when is_list(Config) -> 2098: ?line [1,2,3] = lists:seq(1,3), 2099: ?line [1] = lists:seq(1,1), 2100: ?line Big = 748274827583793785928592859, 2101: ?line Big1 = Big+1, 2102: ?line Big2 = Big+2, 2103: ?line [Big, Big1, Big2] = lists:seq(Big, Big+2), 2104: ok. 2105: 2106: seq_2_e(doc) -> 2107: ["Error cases for seq/2"]; 2108: seq_2_e(suite) -> 2109: []; 2110: seq_2_e(Config) when is_list(Config) -> 2111: ?line seq_error([4, 2]), 2112: ?line seq_error([1, a]), 2113: ?line seq_error([1.0, 2.0]), 2114: ok. 2115: 2116: seq_error(Args) -> 2117: {'EXIT', _} = (catch apply(lists, seq, Args)). 2118: 2119: seq_3(doc) -> 2120: ["Non-error cases for seq/3"]; 2121: seq_3(suite) -> 2122: []; 2123: seq_3(Config) when is_list(Config) -> 2124: ?line [1,2,3] = lists:seq(1,3,1), 2125: ?line [1] = lists:seq(1,1,1), 2126: ?line Big = 748274827583793785928592859, 2127: ?line Big1 = Big+1, 2128: ?line Big2 = Big+2, 2129: ?line [Big, Big1, Big2] = lists:seq(Big, Big+2,1), 2130: 2131: ?line [3,2,1] = lists:seq(3,1,-1), 2132: ?line [1] = lists:seq(1,1,-1), 2133: 2134: ?line [3,1] = lists:seq(3,1,-2), 2135: ?line [1] = lists:seq(1, 10, 10), 2136: ?line [1, 4, 7, 10, 13, 16, 19] = lists:seq(1, 19, 3), 2137: ?line [1, 4, 7, 10, 13, 16, 19] = lists:seq(1, 20, 3), 2138: ?line [1, 4, 7, 10, 13, 16, 19] = lists:seq(1, 21, 3), 2139: 2140: ?line [1] = lists:seq(1, 1, 0), %OTP-2613 2141: ok. 2142: 2143: seq_3_e(doc) -> 2144: ["Error cases for seq/3"]; 2145: seq_3_e(suite) -> 2146: []; 2147: seq_3_e(Config) when is_list(Config) -> 2148: ?line seq_error([4, 2, 1]), 2149: ?line seq_error([3, 5, -1]), 2150: ?line seq_error([1, a, 1]), 2151: ?line seq_error([1.0, 2.0, 1]), 2152: 2153: ?line seq_error([1, 3, 1.0]), 2154: ?line seq_error([1, 3, a]), 2155: ?line seq_error([1, 3, 0]), 2156: 2157: ?line seq_error([a, a, 0]), 2158: ok. 2159: 2160: otp_7230(doc) -> 2161: ["OTP-7230. seq/1,2 returns the empty list"]; 2162: otp_7230(suite) -> 2163: []; 2164: otp_7230(Config) when is_list(Config) -> 2165: From = -10, 2166: To = 10, 2167: StepFrom = -10, 2168: StepTo = 10, 2169: 2170: L = lists:seq(From, To), 2171: SL = lists:seq(StepFrom, StepTo), 2172: ?line [] = 2173: [{F, T, S} || 2174: F <- L, T <- L, S <- SL, 2175: not check_seq(F, T, S, catch lists:seq(F, T, S)) 2176: orelse 2177: S =:= 1 andalso not check_seq(F, T, S, catch lists:seq(F, T)) 2178: ]. 2179: 2180: check_seq(From, To, 0, R) -> 2181: From =:= To andalso R =:= [From] 2182: orelse 2183: From =/= To andalso is_tuple(R) andalso element(1, R) =:= 'EXIT'; 2184: check_seq(From, To, Step, []) when Step =/= 0 -> 2185: 0 =:= property(From, To, Step) 2186: andalso 2187: ( 2188: Step > 0 andalso To < From andalso From-To =< Step 2189: orelse 2190: Step < 0 andalso To > From andalso To-From =< -Step 2191: ); 2192: check_seq(From, To, Step, R) when R =/= [], To < From, Step > 0 -> 2193: is_tuple(R) andalso element(1, R) =:= 'EXIT'; 2194: check_seq(From, To, Step, R) when R =/= [], To > From, Step < 0 -> 2195: is_tuple(R) andalso element(1, R) =:= 'EXIT'; 2196: check_seq(From, To, Step, L) when is_list(L), L =/= [], Step =/= 0 -> 2197: First = hd(L), 2198: Last = lists:last(L), 2199: Min = lists:min(L), 2200: Max = lists:max(L), 2201: 2202: [] =:= [E || E <- L, not is_integer(E)] 2203: andalso 2204: %% The difference between two consecutive elements is Step: 2205: begin 2206: LS = [First-Step]++L, 2207: LR = L++[Last+Step], 2208: [Step] =:= lists:usort([B-A || {A,B} <- lists:zip(LS, LR)]) 2209: end 2210: andalso 2211: %% The first element of L is From: 2212: From =:= First 2213: andalso 2214: %% No element outside the given interval: 2215: Min >= lists:min([From, To]) 2216: andalso 2217: Max =< lists:max([From, To]) 2218: andalso 2219: %% All elements are present: 2220: abs(To-Last) < abs(Step) 2221: andalso 2222: length(L) =:= property(From, To, Step); 2223: check_seq(_From, _To, _Step, _R) -> 2224: false. 2225: 2226: property(From, To, Step) -> 2227: ((To-From+Step) div Step). 2228: 2229: %%%------------------------------------------------------------ 2230: 2231: 2232: -define(sublist_error2(X,Y), ?line {'EXIT', _} = (catch lists:sublist(X,Y))). 2233: -define(sublist_error3(X,Y,Z), ?line {'EXIT', _} = (catch lists:sublist(X,Y,Z))). 2234: 2235: sublist_2(doc) -> ["sublist/2"]; 2236: sublist_2(suite) -> []; 2237: sublist_2(Config) when is_list(Config) -> 2238: ?line [] = lists:sublist([], 0), 2239: ?line [] = lists:sublist([], 1), 2240: ?line [] = lists:sublist([a], 0), 2241: ?line [a] = lists:sublist([a], 1), 2242: ?line [a] = lists:sublist([a], 2), 2243: ?line [a] = lists:sublist([a|b], 1), 2244: 2245: ?line [a,b] = lists:sublist([a,b|c], 2), 2246: 2247: ok. 2248: 2249: sublist_2_e(doc) -> ["sublist/2 error cases"]; 2250: sublist_2_e(suite) -> []; 2251: sublist_2_e(Config) when is_list(Config) -> 2252: ?sublist_error2([], -1), 2253: ?sublist_error2(a, -1), 2254: ?sublist_error2(a, 0), 2255: ?sublist_error2([a|b], 2), 2256: ?sublist_error2([a], x), 2257: ?sublist_error2([a], 1.5), 2258: ?sublist_error2([], x), 2259: ?sublist_error2([], 1.5), 2260: ok. 2261: 2262: sublist_3(doc) -> ["sublist/3"]; 2263: sublist_3(suite) -> []; 2264: sublist_3(Config) when is_list(Config) -> 2265: ?line [] = lists:sublist([], 1, 0), 2266: ?line [] = lists:sublist([], 1, 1), 2267: ?line [] = lists:sublist([a], 1, 0), 2268: ?line [a] = lists:sublist([a], 1, 1), 2269: ?line [a] = lists:sublist([a], 1, 2), 2270: ?line [a] = lists:sublist([a|b], 1, 1), 2271: 2272: ?line [] = lists:sublist([], 1, 0), 2273: ?line [] = lists:sublist([], 1, 1), 2274: ?line [] = lists:sublist([a], 1, 0), 2275: ?line [a] = lists:sublist([a], 1, 1), 2276: ?line [a] = lists:sublist([a], 1, 2), 2277: ?line [] = lists:sublist([a], 2, 1), 2278: ?line [] = lists:sublist([a], 2, 2), 2279: ?line [] = lists:sublist([a], 2, 79), 2280: ?line [] = lists:sublist([a,b|c], 1, 0), 2281: ?line [] = lists:sublist([a,b|c], 2, 0), 2282: ?line [a] = lists:sublist([a,b|c], 1, 1), 2283: ?line [b] = lists:sublist([a,b|c], 2, 1), 2284: ?line [a,b] = lists:sublist([a,b|c], 1, 2), 2285: 2286: ?line [] = lists:sublist([a], 2, 0), 2287: 2288: ok. 2289: 2290: sublist_3_e(doc) -> ["sublist/3 error cases"]; 2291: sublist_3_e(suite) -> []; 2292: sublist_3_e(Config) when is_list(Config) -> 2293: ?sublist_error3([], 1, -1), 2294: ?sublist_error3(a, 1, -1), 2295: ?sublist_error3(a, 1, 0), 2296: ?sublist_error3([a|b], 1, 2), 2297: ?sublist_error3([a], 1, x), 2298: ?sublist_error3([a], 1, 1.5), 2299: ?sublist_error3([], 1, x), 2300: ?sublist_error3([], 1, 1.5), 2301: 2302: ?sublist_error3([], -1, 0), 2303: ?sublist_error3(a, x, -1), 2304: ?sublist_error3([a,b], 0.5, 1), 2305: ?sublist_error3([a,b], 1.5, 1), 2306: ?sublist_error3([a], 1, x), 2307: ?sublist_error3([a], 1, 1.5), 2308: ?sublist_error3([], 1, x), 2309: ?sublist_error3([], 1, 1.5), 2310: 2311: ?sublist_error3([a], 0, -1), 2312: ?sublist_error3([a], 1, -1), 2313: ?sublist_error3([a], 2, -1), 2314: ?sublist_error3([a], 0, 0), 2315: ?sublist_error3([a], 0, 1), 2316: 2317: ?sublist_error3([a,b|c], 2, 2), 2318: ?sublist_error3([a,b|c], 3, 0), 2319: ?sublist_error3([a,b|c], 3, 1), 2320: ok. 2321: 2322: %%%------------------------------------------------------------ 2323: 2324: 2325: -define(flatten_error1(X), ?line {'EXIT', _} = (catch lists:flatten(X))). 2326: -define(flatten_error2(X,Y), ?line {'EXIT', _} = (catch lists:flatten(X,Y))). 2327: 2328: flatten_1(doc) -> ["flatten/1"]; 2329: flatten_1(suite) -> []; 2330: flatten_1(Config) when is_list(Config) -> 2331: ?line [] = lists:flatten([]), 2332: ?line [1,2] = lists:flatten([1,2]), 2333: ?line [1,2] = lists:flatten([1,[2]]), 2334: ?line [1,2] = lists:flatten([[1],2]), 2335: ?line [1,2] = lists:flatten([[1],[2]]), 2336: ?line [1,2] = lists:flatten([[1,2]]), 2337: ?line [a,b,c,d] = lists:flatten([[a],[b,c,[d]]]), 2338: 2339: ok. 2340: 2341: flatten_1_e(doc) -> ["flatten/1 error cases"]; 2342: flatten_1_e(suite) -> []; 2343: flatten_1_e(Config) when is_list(Config) -> 2344: ?flatten_error1(a), 2345: ?flatten_error1([a|b]), 2346: ?flatten_error1([[a],[b|c],[d]]), 2347: ok. 2348: 2349: %%% [arndt] What if second arg isn't a proper list? This issue isn't 2350: %%% clear-cut. Right now, I think that any term should be allowed. 2351: %%% But I also wish this function didn't exist at all. 2352: 2353: flatten_2(doc) -> ["flatten/2"]; 2354: flatten_2(suite) -> []; 2355: flatten_2(Config) when is_list(Config) -> 2356: ?line [] = lists:flatten([]), 2357: ?line [a] = lists:flatten([a]), 2358: ok. 2359: 2360: flatten_2_e(doc) -> ["flatten/2 error cases"]; 2361: flatten_2_e(suite) -> []; 2362: flatten_2_e(Config) when is_list(Config) -> 2363: ok. 2364: 2365: %% Test lists:zip/2, lists:unzip/1. 2366: zip_unzip(Config) when is_list(Config) -> 2367: ?line [] = lists:zip([], []), 2368: ?line [{a,b}] = lists:zip([a], [b]), 2369: ?line [{42.0,{kalle,nisse}},{a,b}] = lists:zip([42.0,a], [{kalle,nisse},b]), 2370: 2371: %% Longer lists. 2372: ?line SeqA = lists:seq(45, 200), 2373: ?line SeqB = [A*A || A <- SeqA], 2374: ?line AB = lists:zip(SeqA, SeqB), 2375: ?line SeqA = [A || {A,_} <- AB], 2376: ?line SeqB = [B || {_,B} <- AB], 2377: ?line {SeqA,SeqB} = lists:unzip(AB), 2378: 2379: %% Some more unzip/1. 2380: ?line {[],[]} = lists:unzip([]), 2381: ?line {[a],[b]} = lists:unzip([{a,b}]), 2382: ?line {[a,c],[b,d]} = lists:unzip([{a,b},{c,d}]), 2383: 2384: %% Error cases. 2385: ?line {'EXIT',{function_clause,_}} = (catch lists:zip([], [b])), 2386: ?line {'EXIT',{function_clause,_}} = (catch lists:zip([a], [])), 2387: ?line {'EXIT',{function_clause,_}} = (catch lists:zip([a], [b,c])), 2388: ?line {'EXIT',{function_clause,_}} = (catch lists:zip([a], [b,c])), 2389: ok. 2390: 2391: %% Test lists:zip3/3, lists:unzip3/1. 2392: zip_unzip3(Config) when is_list(Config) -> 2393: ?line [] = lists:zip3([], [], []), 2394: ?line [{a,b,c}] = lists:zip3([a], [b], [c]), 2395: 2396: %% Longer lists. 2397: ?line SeqA = lists:seq(45, 200), 2398: ?line SeqB = [2*A || A <- SeqA], 2399: ?line SeqC = [A*A || A <- SeqA], 2400: ?line ABC = lists:zip3(SeqA, SeqB, SeqC), 2401: ?line SeqA = [A || {A,_,_} <- ABC], 2402: ?line SeqB = [B || {_,B,_} <- ABC], 2403: ?line SeqC = [C || {_,_,C} <- ABC], 2404: ?line {SeqA,SeqB,SeqC} = lists:unzip3(ABC), 2405: 2406: %% Some more unzip3/1. 2407: ?line {[],[],[]} = lists:unzip3([]), 2408: ?line {[a],[b],[c]} = lists:unzip3([{a,b,c}]), 2409: 2410: %% Error cases. 2411: ?line {'EXIT',{function_clause,_}} = (catch lists:zip3([], [], [c])), 2412: ?line {'EXIT',{function_clause,_}} = (catch lists:zip3([], [b], [])), 2413: ?line {'EXIT',{function_clause,_}} = (catch lists:zip3([a], [], [])), 2414: 2415: ok. 2416: 2417: %% Test lists:zipwith/3. 2418: zipwith(Config) when is_list(Config) -> 2419: Zip = fun(A, B) -> [A|B] end, 2420: 2421: ?line [] = lists:zipwith(Zip, [], []), 2422: ?line [[a|b]] = lists:zipwith(Zip, [a], [b]), 2423: 2424: %% Longer lists. 2425: ?line SeqA = lists:seq(77, 300), 2426: ?line SeqB = [A*A || A <- SeqA], 2427: ?line AB = lists:zipwith(Zip, SeqA, SeqB), 2428: ?line SeqA = [A || [A|_] <- AB], 2429: ?line SeqB = [B || [_|B] <- AB], 2430: 2431: %% Error cases. 2432: ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith(badfun, [], [])), 2433: ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith(Zip, [], [b])), 2434: ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith(Zip, [a], [])), 2435: ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith(Zip, [a], [b,c])), 2436: ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith(Zip, [a], [b,c])), 2437: ok. 2438: 2439: %% Test lists:zipwith3/4. 2440: zipwith3(Config) when is_list(Config) -> 2441: Zip = fun(A, B, C) -> [A,B,C] end, 2442: 2443: ?line [] = lists:zipwith3(Zip, [], [], []), 2444: ?line [[a,b,c]] = lists:zipwith3(Zip, [a], [b], [c]), 2445: 2446: %% Longer lists. 2447: ?line SeqA = lists:seq(45, 200), 2448: ?line SeqB = [2*A || A <- SeqA], 2449: ?line SeqC = [A*A || A <- SeqA], 2450: ?line ABC = lists:zipwith3(Zip, SeqA, SeqB, SeqC), 2451: ?line SeqA = [A || [A,_,_] <- ABC], 2452: ?line SeqB = [B || [_,B,_] <- ABC], 2453: ?line SeqC = [C || [_,_,C] <- ABC], 2454: 2455: %% Error cases. 2456: ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith3(badfun, [], [], [])), 2457: ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith3(Zip, [], [], [c])), 2458: ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith3(Zip, [], [b], [])), 2459: ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith3(Zip, [a], [], [])), 2460: 2461: ok. 2462: 2463: %% Test lists:filter/2, lists:partition/2. 2464: filter_partition(Config) when is_list(Config) -> 2465: F = fun(I) -> I rem 2 =:= 0 end, 2466: ?line filpart(F, [], []), 2467: ?line filpart(F, [1], []), 2468: ?line filpart(F, [1,3,17], []), 2469: ?line filpart(F, [1,2,3,17], [2]), 2470: ?line filpart(F, [6,8,1,2,3,17], [6,8,2]), 2471: ?line filpart(F, [6,8,1,2,42,3,17], [6,8,2,42]), 2472: 2473: %% Error cases. 2474: ?line {'EXIT',{function_clause,_}} = (catch lists:filter(badfun, [])), 2475: ?line {'EXIT',{function_clause,_}} = (catch lists:partition(badfun, [])), 2476: ok. 2477: 2478: filpart(F, All, Exp) -> 2479: Exp = lists:filter(F, All), 2480: Other = lists:filter(fun(E) -> not F(E) end, All), 2481: {Exp,Other} = lists:partition(F, All). 2482: 2483: 2484: otp_5939(doc) -> ["OTP-5939. Guard tests added."]; 2485: otp_5939(suite) -> []; 2486: otp_5939(Config) when is_list(Config) -> 2487: Fun1 = fun(A) -> A end, 2488: Fun2 = fun(A, B) -> {A,B} end, 2489: Fun3 = fun(A, B, C) -> {A,B,C} end, 2490: Pred = fun(_A) -> true end, 2491: Fold = fun(_E, A) -> A end, 2492: MapFold = fun(E, A) -> {E,A} end, 2493: 2494: ?line {'EXIT', _} = (catch lists:usort( [asd], [qwe])), 2495: 2496: ?line {'EXIT', _} = (catch lists:zipwith(func, [], [])), 2497: ?line [] = lists:zipwith(Fun2, [], []), 2498: ?line {'EXIT', _} = (catch lists:zipwith3(func, [], [], [])), 2499: ?line [] = lists:zipwith3(Fun3, [], [], []), 2500: ?line {'EXIT', _} = (catch lists:keymap(func, 1, [])), 2501: ?line {'EXIT', _} = (catch lists:keymap(Fun1, 0, [])), 2502: ?line [] = lists:keymap(Fun1, 1, []), 2503: ?line {'EXIT', _} = (catch lists:merge(func, [], [1])), 2504: ?line {'EXIT', _} = (catch lists:merge(func, [1], [])), 2505: ?line [] = lists:merge(Fun2, [], []), 2506: ?line {'EXIT', _} = (catch lists:rmerge(func, [], [1])), 2507: ?line {'EXIT', _} = (catch lists:rmerge(func, [1], [])), 2508: ?line [] = lists:rmerge(Fun2, [], []), 2509: ?line {'EXIT', _} = (catch lists:usort(func, [])), 2510: ?line {'EXIT', _} = (catch lists:usort(func, [a])), 2511: ?line {'EXIT', _} = (catch lists:usort(func, [a, b])), 2512: ?line [] = lists:usort(Fun2, []), 2513: ?line {'EXIT', _} = (catch lists:umerge(func, [], [1])), 2514: ?line {'EXIT', _} = (catch lists:merge(func, [1], [])), 2515: ?line [] = lists:umerge(Fun2, [], []), 2516: ?line {'EXIT', _} = (catch lists:rumerge(func, [], [1])), 2517: ?line {'EXIT', _} = (catch lists:rumerge(func, [1], [])), 2518: ?line [] = lists:rumerge(Fun2, [], []), 2519: ?line {'EXIT', _} = (catch lists:all(func, [])), 2520: ?line true = lists:all(Pred, []), 2521: ?line {'EXIT', _} = (catch lists:any(func, [])), 2522: ?line false = lists:any(Pred, []), 2523: ?line {'EXIT', _} = (catch lists:map(func, [])), 2524: ?line [] = lists:map(Fun1, []), 2525: ?line {'EXIT', _} = (catch lists:flatmap(func, [])), 2526: ?line [] = lists:flatmap(Fun1, []), 2527: ?line {'EXIT', _} = (catch lists:foldl(func, [], [])), 2528: ?line [] = lists:foldl(Fold, [], []), 2529: ?line {'EXIT', _} = (catch lists:foldr(func, [], [])), 2530: ?line [] = lists:foldr(Fold, [], []), 2531: ?line {'EXIT', _} = (catch lists:filter(func, [])), 2532: ?line [] = lists:filter(Pred, []), 2533: ?line {'EXIT', _} = (catch lists:partition(func, [])), 2534: ?line {[],[]} = lists:partition(Pred, []), 2535: ?line {'EXIT', _} = (catch lists:filtermap(func, [])), 2536: ?line [] = lists:filtermap(Fun1, []), 2537: ?line {'EXIT', _} = (catch lists:foreach(func, [])), 2538: ?line ok = lists:foreach(Fun1, []), 2539: ?line {'EXIT', _} = (catch lists:mapfoldl(func, [], [])), 2540: ?line {[],[]} = lists:mapfoldl(MapFold, [], []), 2541: ?line {'EXIT', _} = (catch lists:mapfoldr(func, [], [])), 2542: ?line {[],[]} = lists:mapfoldr(MapFold, [], []), 2543: ?line {'EXIT', _} = (catch lists:takewhile(func, [])), 2544: ?line [] = lists:takewhile(Pred, []), 2545: ?line {'EXIT', _} = (catch lists:dropwhile(func, [])), 2546: ?line [] = lists:dropwhile(Pred, []), 2547: ?line {'EXIT', _} = (catch lists:splitwith(func, [])), 2548: ?line {[],[]} = lists:splitwith(Pred, []), 2549: 2550: ok. 2551: 2552: otp_6023(doc) -> ["OTP-6023. lists:keyreplace/4, a typecheck."]; 2553: otp_6023(suite) -> []; 2554: otp_6023(Config) when is_list(Config) -> 2555: ?line {'EXIT', _} = (catch lists:keyreplace(a, 2, [{1,a}], b)), 2556: ?line [{2,b}] = lists:keyreplace(a, 2, [{1,a}], {2,b}), 2557: 2558: ok. 2559: 2560: otp_6606(doc) -> ["OTP-6606. sort and keysort bug"]; 2561: otp_6606(suite) -> []; 2562: otp_6606(Config) when is_list(Config) -> 2563: I = 1, 2564: F = float(1), 2565: L1 = [{F,I},{F,F},{I,I},{I,F}], 2566: ?line L1 = lists:keysort(1, L1), 2567: ?line L1 = lists:sort(L1), 2568: L2 = [{I,I},{I,F},{F,I},{F,F}], 2569: ?line L2 = lists:keysort(1, L2), 2570: ?line L2 = lists:sort(L2), 2571: ok. 2572: 2573: %% Test lists:suffix/2. 2574: suffix(Config) when is_list(Config) -> 2575: ?line true = lists:suffix([], []), 2576: ?line true = lists:suffix([], [a]), 2577: ?line true = lists:suffix([], [a,b]), 2578: ?line true = lists:suffix([], [a,b,c]), 2579: ?line true = lists:suffix([a], lists:duplicate(200000, a)), 2580: ?line true = lists:suffix(lists:seq(1, 1024), 2581: lists:seq(2, 64000) ++ lists:seq(1, 1024)), 2582: ?line true = lists:suffix(lists:duplicate(20000, a), 2583: lists:duplicate(200000, a)), 2584: ?line true = lists:suffix([2.0,3.0], [1.0,2.0,3.0]), 2585: 2586: %% False cases. 2587: ?line false = lists:suffix([a], []), 2588: ?line false = lists:suffix([a,b,c], []), 2589: ?line false = lists:suffix([a,b,c], [b,c]), 2590: ?line false = lists:suffix([a,b,c], [a,b,c,a,b]), 2591: ?line false = lists:suffix(lists:duplicate(199999, a)++[b], 2592: lists:duplicate(200000, a)), 2593: ?line false = lists:suffix([2.0,3.0], [1,2,3]), 2594: 2595: %% Error cases. 2596: ?line {'EXIT',_} = (catch lists:suffix({a,b,c}, [])), 2597: ?line {'EXIT',_} = (catch lists:suffix([], {a,b})), 2598: ?line {'EXIT',_} = (catch lists:suffix([a|b], [])), 2599: ?line {'EXIT',_} = (catch lists:suffix([a,b|c], [a|b])), 2600: ?line {'EXIT',_} = (catch lists:suffix([a|b], [a,b|c])), 2601: ?line {'EXIT',_} = (catch lists:suffix([a|b], [a|b])), 2602: 2603: ok. 2604: 2605: %% Test lists:subtract/2 and the '--' operator. 2606: subtract(Config) when is_list(Config) -> 2607: ?line [] = sub([], []), 2608: ?line [] = sub([], [a]), 2609: ?line [] = sub([], lists:seq(1, 1024)), 2610: ?line sub_non_matching([a], []), 2611: ?line sub_non_matching([1,2], [make_ref()]), 2612: ?line sub_non_matching(lists:seq(1, 1024), [make_ref(),make_ref()]), 2613: 2614: %% Matching subtracts. 2615: ?line [] = sub([a], [a]), 2616: ?line [a] = sub([a,b], [b]), 2617: ?line [a] = sub([a,b], [b,c]), 2618: ?line [a] = sub([a,b,c], [b,c]), 2619: ?line [a] = sub([a,b,c], [b,c]), 2620: ?line [d,a,a] = sub([a,b,c,d,a,a], [a,b,c]), 2621: ?line [d,x,a] = sub([a,b,c,d,a,x,a], [a,b,c,a]), 2622: ?line [1,2,3,4,5,6,7,8,9,9999,10000,20,21,22] = 2623: sub(lists:seq(1, 10000)++[20,21,22], lists:seq(10, 9998)), 2624: 2625: %% Floats/integers. 2626: ?line [42.0,42.0] = sub([42.0,42,42.0], [42,42,42]), 2627: ?line [1,2,3,4,43.0] = sub([1,2,3,4,5,42.0,43.0], [42.0,5]), 2628: 2629: %% Crashing subtracts. 2630: ?line {'EXIT',_} = (catch sub([], [a|b])), 2631: ?line {'EXIT',_} = (catch sub([a], [a|b])), 2632: ?line {'EXIT',_} = (catch sub([a|b], [])), 2633: ?line {'EXIT',_} = (catch sub([a|b], [])), 2634: ?line {'EXIT',_} = (catch sub([a|b], [a])), 2635: 2636: ok. 2637: 2638: sub_non_matching(A, B) -> 2639: A = sub(A, B). 2640: 2641: sub(A, B) -> 2642: Res = A -- B, 2643: Res = lists:subtract(A, B). 2644: