Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:26
erlang
1032-erts-Remove-deprecated-creator-pid-from-fu...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 1032-erts-Remove-deprecated-creator-pid-from-funs.patch of Package erlang
From aef9de493883b03eadf00aabda505563ef515057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20H=C3=B6gberg?= <john@erlang.org> Date: Mon, 22 May 2023 18:24:38 +0200 Subject: [PATCH 2/2] erts: Remove deprecated "creator pid" from funs To stay backwards compatible for another release, erlang:fun_info/1 will return the pid of the `init` process. --- erts/emulator/beam/copy.c | 190 ++-- erts/emulator/beam/emu/emu_load.c | 5 +- erts/emulator/beam/erl_bif_info.c | 2 +- erts/emulator/beam/erl_fun.c | 4 +- erts/emulator/beam/erl_fun.h | 10 +- erts/emulator/beam/erl_gc.h | 2 +- erts/emulator/beam/erl_process_dump.c | 1 - erts/emulator/beam/erl_term.h | 2 +- erts/emulator/beam/external.c | 17 +- erts/emulator/beam/generators.tab | 2 +- erts/emulator/beam/jit/asm_load.c | 5 +- erts/emulator/test/erts_debug_SUITE.erl | 2 +- erts/emulator/test/fun_SUITE.erl | 8 +- .../emulator/test/trace_call_memory_SUITE.erl | 2 +- lib/stdlib/test/lists_SUITE.erl | 845 +----------------- 15 files changed, 141 insertions(+), 956 deletions(-) diff --git a/erts/emulator/beam/copy.c b/erts/emulator/beam/copy.c index a22317f6c1..5a5ca58bcf 100644 --- a/erts/emulator/beam/copy.c +++ b/erts/emulator/beam/copy.c @@ -139,20 +139,24 @@ Uint size_object_x(Eterm obj, erts_literal_area_t *litopt) break; case FUN_SUBTAG: { - Eterm* bptr = fun_val(obj); - ErlFunThing* funp = (ErlFunThing *) bptr; - unsigned eterms = 1 /* creator */ + funp->num_free; - unsigned sz = thing_arityval(hdr); - sum += 1 /* header */ + sz + eterms; - bptr += 1 /* header */ + sz; - while (eterms-- > 1) { - obj = *bptr++; - if (!IS_CONST(obj)) { - ESTACK_PUSH(s, obj); - } - } - obj = *bptr; - break; + const ErlFunThing* funp = (ErlFunThing*)fun_val(obj); + + ASSERT(ERL_FUN_SIZE == (1 + thing_arityval(hdr))); + sum += ERL_FUN_SIZE + funp->num_free; + + for (int i = 1; i < funp->num_free; i++) { + obj = funp->env[i]; + if (!IS_CONST(obj)) { + ESTACK_PUSH(s, obj); + } + } + + if (funp->num_free > 0) { + obj = funp->env[0]; + break; + } + + goto pop_next; } case MAP_SUBTAG: switch (MAP_HEADER_TYPE(hdr)) { @@ -389,17 +393,18 @@ Uint size_shared(Eterm obj) goto pop_next; } case FUN_SUBTAG: { - ErlFunThing* funp = (ErlFunThing *) ptr; - unsigned eterms = 1 /* creator */ + funp->num_free; - unsigned sz = thing_arityval(hdr); - sum += 1 /* header */ + sz + eterms; - ptr += 1 /* header */ + sz; - while (eterms-- > 0) { - obj = *ptr++; - if (!IS_CONST(obj)) { - EQUEUE_PUT(s, obj); - } - } + const ErlFunThing* funp = (ErlFunThing *) ptr; + + ASSERT(ERL_FUN_SIZE == (1 + thing_arityval(hdr))); + sum += ERL_FUN_SIZE + funp->num_free; + + for (int i = 0; i < funp->num_free; i++) { + obj = funp->env[i]; + if (!IS_CONST(obj)) { + EQUEUE_PUT(s, obj); + } + } + goto pop_next; } case SUB_BINARY_SUBTAG: { @@ -551,16 +556,14 @@ cleanup: goto cleanup_next; } case FUN_SUBTAG: { - ErlFunThing* funp = (ErlFunThing *) ptr; - unsigned eterms = 1 /* creator */ + funp->num_free; - unsigned sz = thing_arityval(hdr); - ptr += 1 /* header */ + sz; - while (eterms-- > 0) { - obj = *ptr++; - if (!IS_CONST(obj)) { - EQUEUE_PUT_UNCHECKED(s, obj); - } - } + const ErlFunThing *funp = (ErlFunThing *) ptr; + + for (int i = 0; i < funp->num_free; i++) { + obj = funp->env[i]; + if (!IS_CONST(obj)) { + EQUEUE_PUT_UNCHECKED(s, obj); + } + } goto cleanup_next; } case MAP_SUBTAG: @@ -865,24 +868,26 @@ Eterm copy_struct_x(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap, break; case FUN_SUBTAG: { - ErlFunThing* funp = (ErlFunThing *) objp; + const ErlFunThing *src_fun = (const ErlFunThing *)objp; + ErlFunThing *dst_fun = (ErlFunThing *)htop; - i = thing_arityval(hdr) + 2 + funp->num_free; - tp = htop; - while (i--) { - *htop++ = *objp++; - } - funp = (ErlFunThing *) tp; + *dst_fun = *src_fun; - if (is_local_fun(funp)) { - funp->next = off_heap->first; - off_heap->first = (struct erl_off_heap_header*) funp; - erts_refc_inc(&funp->entry.fun->refc, 2); - } else { - ASSERT(is_external_fun(funp) && funp->next == NULL); + for (int i = 0; i < src_fun->num_free; i++) { + dst_fun->env[i] = src_fun->env[i]; } - *argp = make_fun(tp); + ASSERT(&htop[ERL_FUN_SIZE] == &dst_fun->env[0]); + htop = &dst_fun->env[dst_fun->num_free]; + *argp = make_fun(dst_fun); + + if (is_local_fun(dst_fun)) { + dst_fun->next = off_heap->first; + off_heap->first = (struct erl_off_heap_header*)dst_fun; + erts_refc_inc(&dst_fun->entry.fun->refc, 2); + } else { + ASSERT(is_external_fun(dst_fun) && dst_fun->next == NULL); + } } break; case EXTERNAL_PID_SUBTAG: @@ -1117,7 +1122,6 @@ Uint copy_shared_calculate(Eterm obj, erts_shcopy_t *info) { Uint sum; Uint e; - unsigned sz; Eterm* ptr; Eterm *lit_purge_ptr = info->lit_purge_ptr; Uint lit_purge_sz = info->lit_purge_sz; @@ -1259,17 +1263,18 @@ Uint copy_shared_calculate(Eterm obj, erts_shcopy_t *info) goto pop_next; } case FUN_SUBTAG: { - ErlFunThing* funp = (ErlFunThing *) ptr; - unsigned eterms = 1 /* creator */ + funp->num_free; - sz = thing_arityval(hdr); - sum += 1 /* header */ + sz + eterms; - ptr += 1 /* header */ + sz; - while (eterms-- > 0) { - obj = *ptr++; - if (!IS_CONST(obj)) { - EQUEUE_PUT(s, obj); - } - } + const ErlFunThing* funp = (ErlFunThing *) ptr; + + ASSERT(ERL_FUN_SIZE == (1 + thing_arityval(hdr))); + sum += ERL_FUN_SIZE + funp->num_free; + + for (int i = 0; i < funp->num_free; i++) { + obj = funp->env[i]; + if (!IS_CONST(obj)) { + EQUEUE_PUT(s, obj); + } + } + goto pop_next; } case SUB_BINARY_SUBTAG: { @@ -1596,32 +1601,36 @@ Uint copy_shared_perform_x(Eterm obj, Uint size, erts_shcopy_t *info, goto cleanup_next; } case FUN_SUBTAG: { - ErlFunThing* funp = (ErlFunThing *) ptr; - unsigned eterms = 1 /* creator */ + funp->num_free; - sz = thing_arityval(hdr); - funp = (ErlFunThing *) hp; - *resp = make_fun(hp); - *hp++ = hdr; - ptr++; - while (sz-- > 0) { - *hp++ = *ptr++; - } - while (eterms-- > 0) { - obj = *ptr++; - if (IS_CONST(obj)) { - *hp++ = obj; - } else { - EQUEUE_PUT_UNCHECKED(s, obj); - *hp++ = HEAP_ELEM_TO_BE_FILLED; - } - } + const ErlFunThing *src_fun = (const ErlFunThing *)ptr; + ErlFunThing *dst_fun = (ErlFunThing *)hp; + + *dst_fun = *src_fun; + + /* The header of the source fun may have been clobbered, + * restore it. */ + dst_fun->thing_word = hdr; - if (is_local_fun(funp)) { - funp->next = off_heap->first; - off_heap->first = (struct erl_off_heap_header*) funp; - erts_refc_inc(&funp->entry.fun->refc, 2); + for (int i = 0; i < src_fun->num_free; i++) { + obj = src_fun->env[i]; + + if (!IS_CONST(obj)) { + EQUEUE_PUT_UNCHECKED(s, obj); + obj = HEAP_ELEM_TO_BE_FILLED; + } + + dst_fun->env[i] = obj; + } + + ASSERT(&hp[ERL_FUN_SIZE] == &dst_fun->env[0]); + hp = &dst_fun->env[dst_fun->num_free]; + *resp = make_fun(dst_fun); + + if (is_local_fun(dst_fun)) { + dst_fun->next = off_heap->first; + off_heap->first = (struct erl_off_heap_header*) dst_fun; + erts_refc_inc(&dst_fun->entry.fun->refc, 2); } else { - ASSERT(is_external_fun(funp) && funp->next == NULL); + ASSERT(is_external_fun(dst_fun) && dst_fun->next == NULL); } goto cleanup_next; @@ -1827,10 +1836,11 @@ Uint copy_shared_perform_x(Eterm obj, Uint size, erts_shcopy_t *info, hscan++; break; case FUN_SUBTAG: { - ErlFunThing* funp = (ErlFunThing *) hscan; - hscan += 1 + thing_arityval(*hscan); - remaining = 1 + funp->num_free; - break; + const ErlFunThing* funp = (ErlFunThing *) hscan; + ASSERT(ERL_FUN_SIZE == (1 + thing_arityval(*hscan))); + hscan += ERL_FUN_SIZE; + remaining = funp->num_free; + break; } case MAP_SUBTAG: switch (MAP_HEADER_TYPE(*hscan)) { @@ -2170,7 +2180,7 @@ move_one_frag(Eterm** hpp, ErlHeapFragment* frag, ErlOffHeap* off_heap, int lite break; case FUN_SUBTAG: { - ErlFunThing *funp = (ErlFunThing*)hdr; + const ErlFunThing *funp = (ErlFunThing *) hdr; if (is_local_fun(funp)) { hdr->next = off_heap->first; diff --git a/erts/emulator/beam/emu/emu_load.c b/erts/emulator/beam/emu/emu_load.c index 8395a87076..9a078410d0 100644 --- a/erts/emulator/beam/emu/emu_load.c +++ b/erts/emulator/beam/emu/emu_load.c @@ -665,15 +665,14 @@ void beam_load_finalize_code(LoaderState* stp, struct erl_module_instance* inst_ literal = beamfile_get_literal(&stp->beam, stp->lambda_literals[i]); funp = (ErlFunThing *)fun_val(literal); - ASSERT(funp->creator == am_external); + ASSERT(funp->external == 1); funp->entry.fun = fun_entry; funp->next = literal_area->off_heap; literal_area->off_heap = (struct erl_off_heap_header *)funp; - ASSERT(erts_init_process_id != ERTS_INVALID_PID); - funp->creator = erts_init_process_id; + funp->external = 0; erts_refc_inc(&fun_entry->refc, 2); } diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index 4ba368ec7c..127fb84330 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -3674,7 +3674,7 @@ fun_info_2(BIF_ALIST_2) hp = HAlloc(p, 3); break; case am_pid: - val = is_local_fun(funp) ? funp->creator : am_undefined; + val = is_local_fun(funp) ? erts_init_process_id : am_undefined; hp = HAlloc(p, 3); break; case am_module: diff --git a/erts/emulator/beam/erl_fun.c b/erts/emulator/beam/erl_fun.c index ae6116ec19..cdac196472 100644 --- a/erts/emulator/beam/erl_fun.c +++ b/erts/emulator/beam/erl_fun.c @@ -308,7 +308,7 @@ ErlFunThing *erts_new_export_fun_thing(Eterm **hpp, Export *exp, int arity) funp->next = NULL; funp->entry.exp = exp; funp->num_free = 0; - funp->creator = am_external; + funp->external = 1; funp->arity = arity; #ifdef DEBUG @@ -335,7 +335,7 @@ ErlFunThing *erts_new_local_fun_thing(Process *p, ErlFunEntry *fe, MSO(p).first = (struct erl_off_heap_header*) funp; funp->entry.fun = fe; funp->num_free = num_free; - funp->creator = p->common.id; + funp->external = 0; funp->arity = arity; #ifdef DEBUG diff --git a/erts/emulator/beam/erl_fun.h b/erts/emulator/beam/erl_fun.h index 4c9ff5cda1..05d27da442 100644 --- a/erts/emulator/beam/erl_fun.h +++ b/erts/emulator/beam/erl_fun.h @@ -59,10 +59,10 @@ typedef struct erl_fun_thing { * pointer to improve performance. */ ErtsDispatchable *disp; - /* Pointer to function entry, valid iff `creator != am_external`.*/ + /* Pointer to function entry, valid iff `external == 0`.*/ ErlFunEntry *fun; - /* Pointer to export entry, valid iff `creator == am_external`.*/ + /* Pointer to export entry, valid iff `external == 1`.*/ Export *exp; } entry; @@ -71,14 +71,14 @@ typedef struct erl_fun_thing { byte arity; /* The _apparent_ arity of the fun. */ byte num_free; /* Number of free variables (in env). */ + byte external; /* Whether this is an external fun or not */ /* -- The following may be compound Erlang terms ---------------------- */ - Eterm creator; /* Pid of creator process (contains node). */ Eterm env[]; /* Environment (free variables). */ } ErlFunThing; -#define is_local_fun(FunThing) ((FunThing)->creator != am_external) -#define is_external_fun(FunThing) ((FunThing)->creator == am_external) +#define is_local_fun(FunThing) ((FunThing)->external == 0) +#define is_external_fun(FunThing) ((FunThing)->external != 0) /* ERL_FUN_SIZE does _not_ include space for the environment which is a * C99-style flexible array */ diff --git a/erts/emulator/beam/erl_gc.h b/erts/emulator/beam/erl_gc.h index c1760562c9..2b21f9e7be 100644 --- a/erts/emulator/beam/erl_gc.h +++ b/erts/emulator/beam/erl_gc.h @@ -82,7 +82,7 @@ ERTS_GLB_INLINE Eterm* move_boxed(Eterm *ERTS_RESTRICT ptr, Eterm hdr, Eterm **h if (is_flatmap_header(hdr)) nelts+=flatmap_get_size(ptr) + 1; else nelts += hashmap_bitcount(MAP_HEADER_VAL(hdr)); break; - case FUN_SUBTAG: nelts+=((ErlFunThing*)(ptr))->num_free+1; break; + case FUN_SUBTAG: nelts+=((ErlFunThing*)(ptr))->num_free; break; } gval = make_boxed(htop); *orig = gval; diff --git a/erts/emulator/beam/erl_term.h b/erts/emulator/beam/erl_term.h index 03211a6acd..fa06ba5afe 100644 --- a/erts/emulator/beam/erl_term.h +++ b/erts/emulator/beam/erl_term.h @@ -387,7 +387,7 @@ _ET_DECLARE_CHECKED(Eterm*,binary_val,Wterm) #define HEADER_PROC_BIN _make_header(PROC_BIN_SIZE-1,_TAG_HEADER_REFC_BIN) /* fun objects */ -#define HEADER_FUN _make_header(ERL_FUN_SIZE-2,_TAG_HEADER_FUN) +#define HEADER_FUN _make_header(ERL_FUN_SIZE-1,_TAG_HEADER_FUN) #define is_fun_header(x) ((x) == HEADER_FUN) #define make_fun(x) make_boxed((Eterm*)(x)) #define is_any_fun(x) (is_boxed((x)) && is_fun_header(*boxed_val((x)))) diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c index 081ce23e49..085d9ba603 100644 --- a/erts/emulator/beam/external.c +++ b/erts/emulator/beam/external.c @@ -3893,7 +3893,7 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, ep = enc_atom(acmp, fe->module, ep, dflags); ep = enc_term(acmp, make_small(fe->old_index), ep, dflags, off_heap); ep = enc_term(acmp, make_small(fe->old_uniq), ep, dflags, off_heap); - ep = enc_pid(acmp, funp->creator, ep, dflags); + ep = enc_pid(acmp, erts_init_process_id, ep, dflags); for (ei = funp->num_free-1; ei >= 0; ei--) { WSTACK_PUSH2(s, ENC_TERM, (UWord) funp->env[ei]); @@ -4981,6 +4981,7 @@ dec_term_atom_common: hp += num_free; funp->thing_word = HEADER_FUN; funp->num_free = num_free; + funp->external = 0; *objp = make_fun(funp); /* Module */ @@ -5006,6 +5007,15 @@ dec_term_atom_common: } old_uniq = unsigned_val(temp); + /* Creator pid, discarded */ + if ((ep = dec_term(edep, factory, ep, &temp, NULL, + internal_nc)) == NULL) { + goto error; + } + if (!is_pid(temp)) { + goto error; + } + /* * It is safe to link the fun into the fun list only when * no more validity tests can fail. @@ -5024,9 +5034,6 @@ dec_term_atom_common: funp->env[i] = (Eterm) next; next = funp->env + i; } - /* Creator */ - funp->creator = (Eterm) next; - next = &(funp->creator); break; } case ATOM_INTERNAL_REF2: @@ -5586,7 +5593,7 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, if (is_local_fun(funp)) { result += 20+1+1+4; /* New ID + Tag */ result += 4; /* Length field (number of free variables */ - result += encode_pid_size(acmp, funp->creator, dflags); + result += encode_pid_size(acmp, erts_init_process_id, dflags); result += encode_atom_size(acmp, funp->entry.fun->module, dflags); result += 2 * (1+4); /* Index, Uniq */ if (funp->num_free > 1) { diff --git a/erts/emulator/beam/generators.tab b/erts/emulator/beam/generators.tab index a737228c44..ae806e2062 100644 --- a/erts/emulator/beam/generators.tab +++ b/erts/emulator/beam/generators.tab @@ -323,7 +323,7 @@ MakeLiteralLambda(Op, Index, DstType, DstVal) { funp->next = NULL; funp->arity = entry->arity; funp->num_free = 0; - funp->creator = am_external; + funp->external = 1; literal = beamfile_add_literal(&S->beam, make_fun(tmp_hp), 0); S->lambda_literals[$Index] = literal; diff --git a/erts/emulator/beam/jit/asm_load.c b/erts/emulator/beam/jit/asm_load.c index 023f084051..f6e1f1c6ab 100644 --- a/erts/emulator/beam/jit/asm_load.c +++ b/erts/emulator/beam/jit/asm_load.c @@ -997,15 +997,14 @@ void beam_load_finalize_code(LoaderState *stp, literal = beamfile_get_literal(&stp->beam, stp->lambda_literals[i]); funp = (ErlFunThing *)fun_val(literal); - ASSERT(funp->creator == am_external); + ASSERT(funp->external == 1); funp->entry.fun = fun_entry; funp->next = literal_area->off_heap; literal_area->off_heap = (struct erl_off_heap_header *)funp; - ASSERT(erts_init_process_id != ERTS_INVALID_PID); - funp->creator = erts_init_process_id; + funp->external = 0; erts_refc_inc(&fun_entry->refc, 2); } diff --git a/erts/emulator/test/erts_debug_SUITE.erl b/erts/emulator/test/erts_debug_SUITE.erl index 2149eac41b..3240b800d6 100644 --- a/erts/emulator/test/erts_debug_SUITE.erl +++ b/erts/emulator/test/erts_debug_SUITE.erl @@ -82,7 +82,7 @@ test_size(Config) when is_list(Config) -> %% Fun environment size = 0 (the smallest fun possible) SimplestFun = fun() -> ok end, - FunSz0 = 5, + FunSz0 = 4, FunSz0 = do_test_size(SimplestFun), %% Fun environment size = 1 diff --git a/erts/emulator/test/fun_SUITE.erl b/erts/emulator/test/fun_SUITE.erl index 0f8e7af926..10cfc53a97 100644 --- a/erts/emulator/test/fun_SUITE.erl +++ b/erts/emulator/test/fun_SUITE.erl @@ -838,8 +838,7 @@ id(X) -> X. spawn_call(Node, AFun) -> - Parent = self(), - Init = erlang:whereis(init), + Self = self(), Pid = spawn_link(Node, fun() -> receive @@ -850,10 +849,7 @@ spawn_call(Node, AFun) -> _ -> lists:seq(0, Arity-1) end, Res = apply(Fun, Args), - case erlang:fun_info(Fun, pid) of - {pid,Init} -> Parent ! {result,Res}; - {pid,Creator} -> Creator ! {result,Res} - end + Self ! {result,Res} end end), Pid ! {AFun,AFun,AFun}, diff --git a/erts/emulator/test/trace_call_memory_SUITE.erl b/erts/emulator/test/trace_call_memory_SUITE.erl index 59d1873e49..a18dbdabf1 100644 --- a/erts/emulator/test/trace_call_memory_SUITE.erl +++ b/erts/emulator/test/trace_call_memory_SUITE.erl @@ -309,7 +309,7 @@ spawn_memory_lambda(Config) when is_list(Config) -> receive {'DOWN', MRef, process, Pid, _} -> ok end, 1 = erlang:trace(self(), false, [all]), %% 16-elements list translates into 34-words for spawn, and 6 more words for apply itself - {call_memory, [{Pid, 1, 40}]} = erlang:trace_info({erlang, apply, 2}, call_memory). + {call_memory, [{Pid, 1, 39}]} = erlang:trace_info({erlang, apply, 2}, call_memory). spawn_memory_internal(Array) -> Array. diff --git a/lib/stdlib/test/lists_SUITE.erl b/lib/stdlib/test/lists_SUITE.erl index 59f2e8bd03..7a73e1bc82 100644 --- a/lib/stdlib/test/lists_SUITE.erl +++ b/lib/stdlib/test/lists_SUITE.erl @@ -39,20 +39,14 @@ sublist_2/1, sublist_3/1, sublist_2_e/1, sublist_3_e/1, flatten_1/1, flatten_2/1, flatten_1_e/1, flatten_2_e/1, dropwhile/1, takewhile/1, - sort_1/1, sort_stable/1, merge/1, rmerge/1, sort_rand/1, - usort_1/1, usort_stable/1, umerge/1, rumerge/1,usort_rand/1, + sort_1/1, merge/1, rmerge/1, sort_rand/1, + usort_1/1, umerge/1, rumerge/1,usort_rand/1, keymerge/1, rkeymerge/1, - keysort_1/1, keysort_i/1, keysort_stable/1, + keysort_1/1, keysort_i/1, keysort_rand/1, keysort_error/1, ukeymerge/1, rukeymerge/1, - ukeysort_1/1, ukeysort_i/1, ukeysort_stable/1, + ukeysort_1/1, ukeysort_i/1, ukeysort_rand/1, ukeysort_error/1, - funmerge/1, rfunmerge/1, - funsort_1/1, funsort_stable/1, funsort_rand/1, - funsort_error/1, - ufunmerge/1, rufunmerge/1, - ufunsort_1/1, ufunsort_stable/1, ufunsort_rand/1, - ufunsort_error/1, uniq_1/1, uniq_2/1, zip_unzip/1, zip_unzip3/1, zipwith/1, zipwith3/1, zip_fail/1, zip_trim/1, zip_pad/1, @@ -73,9 +67,6 @@ -export([sort_loop/0, sort_loop/1, sloop/1]). -%% Internal export. --export([make_fun/1]). - %% %% all/1 %% @@ -91,8 +82,6 @@ all() -> {group, keysort}, {group, ukeysort}, {group, uniq}, - {group, funsort}, - {group, ufunsort}, {group, sublist}, {group, flatten}, {group, seq}, @@ -103,22 +92,16 @@ all() -> groups() -> [{append, [parallel], [append_1, append_2]}, {usort, [parallel], - [umerge, rumerge, usort_1, usort_rand, usort_stable]}, + [umerge, rumerge, usort_1, usort_rand]}, {keysort, [parallel], [keymerge, rkeymerge, keysort_1, keysort_rand, - keysort_i, keysort_stable, keysort_error]}, + keysort_i, keysort_error]}, {key, [parallel], [keymember, keysearch_keyfind, keystore, keytake, keyreplace]}, {sort,[parallel],[merge, rmerge, sort_1, sort_rand]}, {ukeysort, [parallel], [ukeymerge, rukeymerge, ukeysort_1, ukeysort_rand, - ukeysort_i, ukeysort_stable, ukeysort_error]}, - {funsort, [parallel], - [funmerge, rfunmerge, funsort_1, funsort_stable, - funsort_error, funsort_rand]}, - {ufunsort, [parallel], - [ufunmerge, rufunmerge, ufunsort_1, ufunsort_stable, - ufunsort_error, ufunsort_rand]}, + ukeysort_i, ukeysort_error]}, {seq, [parallel], [seq_loop, seq_2, seq_3, seq_2_e, seq_3_e]}, {sublist, [parallel], [sublist_2, sublist_3, sublist_2_e, sublist_3_e]}, @@ -647,21 +630,6 @@ sort_rand(Config) when is_list(Config) -> ok = check(biglist(10000)), ok. -%% sort/1 was really stable for a while - the order of equal elements -%% was kept - but since the performance suffered a bit, this "feature" -%% was removed. - -%% sort/1 should be stable for equal terms. -sort_stable(Config) when is_list(Config) -> - ok = check_stability(bigfunlist(10)), - ok = check_stability(bigfunlist(100)), - ok = check_stability(bigfunlist(1000)), - case erlang:system_info(modified_timing_level) of - undefined -> ok = check_stability(bigfunlist(10000)); - _ -> ok - end, - ok. - check([]) -> ok; check(L) -> @@ -681,23 +649,6 @@ check(A, [B | L]) when A =< B -> check(_A, _L) -> no. -%% The check that sort/1 is stable is no longer used. -%% Equal elements are no longer always kept in order. -check_stability(L) -> - S = lists:sort(L), - LP = explicit_pid(L), - SP = explicit_pid(S), - check_sorted(1, 2, LP, SP). - -explicit_pid(L) -> - lists:reverse(expl_pid(L, [])). - -expl_pid([{I,F} | T], L) when is_function(F) -> - expl_pid(T, [{I,fun_pid(F)} | L]); -expl_pid([], L) -> - L. - - usort_1(Conf) when is_list(Conf) -> [] = lists:usort([]), [1] = lists:usort([1]), @@ -944,18 +895,6 @@ usort_rand(Config) when is_list(Config) -> ok = ucheck(ubiglist(10000)), ok. -%% usort/1 should keep the first duplicate. -usort_stable(Config) when is_list(Config) -> - ok = ucheck_stability(bigfunlist(3)), - ok = ucheck_stability(bigfunlist(10)), - ok = ucheck_stability(bigfunlist(100)), - ok = ucheck_stability(bigfunlist(1000)), - case erlang:system_info(modified_timing_level) of - undefined -> ok = ucheck_stability(bigfunlist(10000)); - _ -> ok - end, - ok. - ucheck([]) -> ok; ucheck(L) -> @@ -975,13 +914,6 @@ ucheck(A, [B | L]) when A < B -> ucheck(_A, _L) -> no. -%% Check that usort/1 is stable and correct relative ukeysort/2. -ucheck_stability(L) -> - S = no_dups(lsort(L)), - U = lists:usort(L), - check_stab(L, U, S, "usort/1", "ukeysort/2"). - - %% Key merge two lists. keymerge(Config) when is_list(Config) -> @@ -1105,18 +1037,6 @@ keysort_1(Config) when is_list(Config) -> ok. -%% keysort should be stable -keysort_stable(Config) when is_list(Config) -> - ok = keysort_check(1, [{1,b},{1,c}], [{1,b},{1,c}]), - ok = keysort_check(1, [{1,c},{1,b}], [{1,c},{1,b}]), - ok = keysort_check(1, - [{1,c},{1,b},{2,x},{3,p},{2,a}], - [{1,c},{1,b},{2,x},{2,a},{3,p}]), - ok = keysort_check(1, - [{1,a},{1,b},{1,a},{1,a}], - [{1,a},{1,b},{1,a},{1,a}]), - ok. - %% keysort should exit when given bad arguments keysort_error(Config) when is_list(Config) -> {'EXIT', _} = (catch lists:keysort(0, [{1,b},{1,c}])), @@ -1373,27 +1293,6 @@ ukeysort_1(Config) when is_list(Config) -> ok. -%% ukeysort should keep the first duplicate. -ukeysort_stable(Config) when is_list(Config) -> - ok = ukeysort_check(1, [{1,b},{1,c}], [{1,b}]), - ok = ukeysort_check(1, [{1,c},{1,b}], [{1,c}]), - ok = ukeysort_check(1, - [{1,c},{1,b},{2,x},{3,p},{2,a}], - [{1,c},{2,x},{3,p}]), - - ok = ukeysort_check(1, [{1,a},{1,b},{1,b}], [{1,a}]), - ok = ukeysort_check(1, [{2,a},{1,b},{2,a}], [{1,b},{2,a}]), - - ok = ukeysort_check_stability(bigfunlist(3)), - ok = ukeysort_check_stability(bigfunlist(10)), - ok = ukeysort_check_stability(bigfunlist(100)), - ok = ukeysort_check_stability(bigfunlist(1000)), - case erlang:system_info(modified_timing_level) of - undefined -> ok = ukeysort_check_stability(bigfunlist(10000)); - _ -> ok - end, - ok. - %% ukeysort should exit when given bad arguments. ukeysort_error(Config) when is_list(Config) -> {'EXIT', _} = (catch lists:ukeysort(0, [{1,b},{1,c}])), @@ -1438,13 +1337,6 @@ gen_ukeysort_check(I, Input) -> erlang:error(gen_ukeysort_check) end. -%% Used for checking that the first copy is kept. -ukeysort_check_stability(L) -> - I = 1, - U = lists:ukeysort(I, L), - S = no_dups_keys(lkeysort(I, L), I), - check_stab(L, U, S, "ukeysort/2", "usort/2"). - %%% Uniquely keysort a list, check that the returned list is what we %%% expected, and that it is actually sorted. ukeysort_check(I, Input, Expected) -> @@ -1483,395 +1375,6 @@ ukeycompare(I, J, A, B) when A =/= B, element(J, A) =< element(J, B) -> ok. - - -%% Merge two lists using a fun. -funmerge(Config) when is_list(Config) -> - - Singleton = id([a, b, c]), - Two = [1,2], - Six = [1,2,3,4,5,6], - F = fun(X, Y) -> X =< Y end, - - %% 2-way merge - [] = lists:merge(F, [], []), - Two = lists:merge(F, Two, []), - Two = lists:merge(F, [], Two), - Six = lists:merge(F, [1,3,5], [2,4,6]), - Six = lists:merge(F, [2,4,6], [1,3,5]), - Six = lists:merge(F, [1,2,3], [4,5,6]), - Six = lists:merge(F, [4,5,6], [1,2,3]), - Six = lists:merge(F, [1,2,5],[3,4,6]), - [1,2,3,5,7] = lists:merge(F, [1,3,5,7], [2]), - [1,2,3,4,5,7] = lists:merge(F, [1,3,5,7], [2,4]), - [1,2,3,4,5,6,7] = lists:merge(F, [1,3,5,7], [2,4,6]), - [1,2,3,5,7] = lists:merge(F, [2], [1,3,5,7]), - [1,2,3,4,5,7] = lists:merge(F, [2,4], [1,3,5,7]), - [1,2,3,4,5,6,7] = lists:merge(F, [2,4,6], [1,3,5,7]), - - F2 = fun(X,Y) -> element(1,X) =< element(1,Y) end, - [{b,2},{c,11},{c,12},{c,21},{c,22},{e,5}] = - lists:merge(F2,[{c,11},{c,12},{e,5}], [{b,2},{c,21},{c,22}]), - - true = erts_debug:same(Singleton, lists:merge(F, Singleton, [])), - true = erts_debug:same(Singleton, lists:merge(F, [], Singleton)), - - {'EXIT', _} = (catch lists:merge(F, a, b)), - {'EXIT', _} = (catch lists:merge(F, a, [])), - {'EXIT', _} = (catch lists:merge(F, [], b)), - {'EXIT', _} = (catch lists:merge(F, a, [1, 2, 3])), - {'EXIT', _} = (catch lists:merge(F, [1, 2, 3], b)), - - ok. - -%% Reverse merge two lists using a fun. -rfunmerge(Config) when is_list(Config) -> - - Singleton = id([a, b, c]), - Two = [2,1], - Six = [6,5,4,3,2,1], - F = fun(X, Y) -> X =< Y end, - - %% 2-way reversed merge - [] = lists:rmerge(F, [], []), - Two = lists:rmerge(F, Two, []), - Two = lists:rmerge(F, [], Two), - Six = lists:rmerge(F, [5,3,1], [6,4,2]), - Six = lists:rmerge(F, [6,4,2], [5,3,1]), - Six = lists:rmerge(F, [3,2,1], [6,5,4]), - Six = lists:rmerge(F, [6,5,4], [3,2,1]), - Six = lists:rmerge(F, [4,3,2],[6,5,1]), - [7,6,5,3,1] = lists:rmerge(F, [7,5,3,1], [6]), - [7,6,5,4,3,1] = lists:rmerge(F, [7,5,3,1], [6,4]), - [7,6,5,4,3,2,1] = lists:rmerge(F, [7,5,3,1], [6,4,2]), - [7,5,3,2,1] = lists:rmerge(F, [2], [7,5,3,1]), - [7,5,4,3,2,1] = lists:rmerge(F, [4,2], [7,5,3,1]), - [7,6,5,4,3,2,1] = lists:rmerge(F, [6,4,2], [7,5,3,1]), - - F2 = fun(X,Y) -> element(1,X) =< element(1,Y) end, - L1 = [{c,11},{c,12},{e,5}], - L2 = [{b,2},{c,21},{c,22}], - true = - lists:merge(F2, L1, L2) == - lists:reverse(lists:rmerge(F2,lists:reverse(L1), lists:reverse(L2))), - - true = erts_debug:same(Singleton, lists:rmerge(F, Singleton, [])), - true = erts_debug:same(Singleton, lists:rmerge(F, [], Singleton)), - - {'EXIT', _} = (catch lists:rmerge(F, a, b)), - {'EXIT', _} = (catch lists:rmerge(F, a, [])), - {'EXIT', _} = (catch lists:rmerge(F, [], b)), - {'EXIT', _} = (catch lists:rmerge(F, a, [1, 2, 3])), - {'EXIT', _} = (catch lists:rmerge(F, [1, 2, 3], b)), - - ok. - - -funsort_1(Config) when is_list(Config) -> - ok = funsort_check(1, [], []), - ok = funsort_check(1, [{a,b}], [{a,b}]), - ok = funsort_check(1, [{a,b},{a,b}], [{a,b},{a,b}]), - ok = funsort_check(1, [{a,b},{b,c}], [{a,b},{b,c}]), - ok = funsort_check(1, [{b,c},{a,b}], [{a,b},{b,c}]), - ok = funsort_check(1, - [{1,e},{3,f},{2,y},{0,z},{x,14}], - [{0,z},{1,e},{2,y},{3,f},{x,14}]), - F = funsort_fun(1), - - [{b,1},{c,1}] = lists:sort(F, [{c,1},{b,1}]), - [{a,0},{b,2},{c,3},{d,4}] = - lists:sort(F, [{d,4},{c,3},{b,2},{a,0}]), - [{a,0},{b,1},{b,2},{c,1}] = - lists:sort(F, [{c,1},{b,1},{b,2},{a,0}]), - [{a,0},{b,1},{b,2},{c,1},{d,4}] = - lists:sort(F, [{c,1},{b,1},{b,2},{a,0},{d,4}]), - - SFun = fun(L) -> fun(X) -> funsort_check(1, X, L) end end, - L1 = [{1,a},{1,a},{2,b},{2,b},{3,c},{4,d},{5,e},{6,f}], - lists:foreach(SFun(L1), perms(L1)), - - ok. - -%% sort/2 should be stable. -funsort_stable(Config) when is_list(Config) -> - ok = funsort_check(1, [{1,b},{1,c}], [{1,b},{1,c}]), - ok = funsort_check(1, [{1,c},{1,b}], [{1,c},{1,b}]), - ok = funsort_check(1, - [{1,c},{1,b},{2,x},{3,p},{2,a}], - [{1,c},{1,b},{2,x},{2,a},{3,p}]), - ok. - -%% sort/2 should exit when given bad arguments. -funsort_error(Config) when is_list(Config) -> - {'EXIT', _} = (catch lists:sort(1, [{1,b} , {1,c}])), - {'EXIT', _} = (catch lists:sort(fun(X,Y) -> X =< Y end, - [{1,b} | {1,c}])), - ok. - -%% sort/2 on big randomized lists. -funsort_rand(Config) when is_list(Config) -> - ok = funsort_check3(1, biglist(10)), - ok = funsort_check3(1, biglist(100)), - ok = funsort_check3(1, biglist(1000)), - ok = funsort_check3(1, biglist(10000)), - ok. - -%% Do a keysort -funsort(I, L) -> - lists:sort(funsort_fun(I), L). - -funsort_check3(I, Input) -> - check_sorted(I, 3, Input, funsort(I, Input)). - -%%% Keysort a list, check that the returned list is what we expected, -%%% and that it is actually sorted. -funsort_check(I, Input, Expected) -> - Expected = funsort(I, Input), - check_sorted(I, Input, Expected). - - -%% Merge two lists while removing duplicates using a fun. -ufunmerge(Conf) when is_list(Conf) -> - - Singleton = id([a, b, c]), - Two = [1,2], - Six = [1,2,3,4,5,6], - F = fun(X, Y) -> X =< Y end, - - %% 2-way unique merge - [] = lists:umerge(F, [], []), - Two = lists:umerge(F, Two, []), - Two = lists:umerge(F, [], Two), - Six = lists:umerge(F, [1,3,5], [2,4,6]), - Six = lists:umerge(F, [2,4,6], [1,3,5]), - Six = lists:umerge(F, [1,2,3], [4,5,6]), - Six = lists:umerge(F, [4,5,6], [1,2,3]), - Six = lists:umerge(F, [1,2,5],[3,4,6]), - [1,2,3,5,7] = lists:umerge(F, [1,3,5,7], [2]), - [1,2,3,4,5,7] = lists:umerge(F, [1,3,5,7], [2,4]), - [1,2,3,4,5,6,7] = lists:umerge(F, [1,3,5,7], [2,4,6]), - [1,2,3,5,7] = lists:umerge(F, [2], [1,3,5,7]), - [1,2,3,4,5,7] = lists:umerge(F, [2,4], [1,3,5,7]), - [1,2,3,4,5,6,7] = lists:umerge(F, [2,4,6], [1,3,5,7]), - - [1,2,3,5,7] = lists:umerge(F, [1,2,3,5,7], [2]), - [1,2,3,4,5,7] = lists:umerge(F, [1,2,3,4,5,7], [2,4]), - [1,2,3,4,5,6,7] = lists:umerge(F, [1,3,5,6,7], [2,4,6]), - [1,2,3,5,7] = lists:umerge(F, [2], [1,2,3,5,7]), - [1,2,3,4,5,7] = lists:umerge(F, [2,4], [1,2,3,4,5,7]), - [1,2,3,4,5,6,7] = lists:umerge(F, [2,4,6], [1,2,3,4,5,6,7]), - - L1 = [{a,1},{a,3},{a,5},{a,7}], - L2 = [{b,1},{b,3},{b,5},{b,7}], - F2 = fun(X,Y) -> element(2,X) =< element(2,Y) end, - L1 = lists:umerge(F2, L1, L2), - [{b,2},{e,5},{c,11},{c,12},{c,21},{c,22}] = - lists:umerge(F2, [{e,5},{c,11},{c,12}], [{b,2},{c,21},{c,22}]), - - true = erts_debug:same(Singleton, lists:umerge(F, Singleton, [])), - true = erts_debug:same(Singleton, lists:umerge(F, [], Singleton)), - - {'EXIT', _} = (catch lists:umerge(F, a, b)), - {'EXIT', _} = (catch lists:umerge(F, a, [])), - {'EXIT', _} = (catch lists:umerge(F, [], b)), - {'EXIT', _} = (catch lists:umerge(F, a, [1, 2, 3])), - {'EXIT', _} = (catch lists:umerge(F, [1, 2, 3], b)), - - ok. - -%% Reverse merge two lists while removing duplicates using a fun. -rufunmerge(Conf) when is_list(Conf) -> - Singleton = id([a, b, c]), - Two = [2,1], - Six = [6,5,4,3,2,1], - F = fun(X, Y) -> X =< Y end, - - %% 2-way reversed unique merge - [] = lists:rumerge(F, [], []), - Two = lists:rumerge(F, Two, []), - Two = lists:rumerge(F, [], Two), - Six = lists:rumerge(F, [5,3,1], [6,4,2]), - Six = lists:rumerge(F, [6,4,2], [5,3,1]), - Six = lists:rumerge(F, [3,2,1], [6,5,4]), - Six = lists:rumerge(F, [6,5,4], [3,2,1]), - Six = lists:rumerge(F, [4,3,2],[6,5,1]), - [7,6,5,3,1] = lists:rumerge(F, [7,5,3,1], [6]), - [7,6,5,4,3,1] = lists:rumerge(F, [7,5,3,1], [6,4]), - [7,6,5,4,3,2,1] = lists:rumerge(F, [7,5,3,1], [6,4,2]), - [7,5,3,2,1] = lists:rumerge(F, [2], [7,5,3,1]), - [7,5,4,3,2,1] = lists:rumerge(F, [4,2], [7,5,3,1]), - [7,6,5,4,3,2,1] = lists:rumerge(F, [6,4,2], [7,5,3,1]), - - [7,6,5,3,1] = lists:rumerge(F, [7,6,5,3,1], [6]), - [7,6,5,4,3,1] = lists:rumerge(F, [7,6,5,4,3,1], [6,4]), - [7,6,5,4,3,2,1] = lists:rumerge(F, [7,6,5,4,3,2,1], [6,4,2]), - [7,5,3,2,1] = lists:rumerge(F, [2], [7,5,3,2,1]), - [7,5,4,3,2,1] = lists:rumerge(F, [4,2], [7,5,4,3,2,1]), - [7,6,5,4,3,2,1] = lists:rumerge(F, [6,4,2], [7,6,5,4,3,2,1]), - - F2 = fun(X,Y) -> element(1,X) =< element(1,Y) end, - L1 = [{1,a},{1,b},{1,a}], - L2 = [{1,a},{1,b},{1,a}], - true = lists:umerge(F2, L1, L2) == - lists:reverse(lists:rumerge(F, lists:reverse(L2), lists:reverse(L1))), - - L3 = [{c,11},{c,12},{e,5}], - L4 = [{b,2},{c,21},{c,22}], - true = - lists:umerge(F2, L3, L4) == - lists:reverse(lists:rumerge(F2,lists:reverse(L3), lists:reverse(L4))), - - true = erts_debug:same(Singleton, lists:rumerge(F, Singleton, [])), - true = erts_debug:same(Singleton, lists:rumerge(F, [], Singleton)), - - {'EXIT', _} = (catch lists:rumerge(F, a, b)), - {'EXIT', _} = (catch lists:rumerge(F, a, [])), - {'EXIT', _} = (catch lists:rumerge(F, [], b)), - {'EXIT', _} = (catch lists:rumerge(F, a, [1, 2, 3])), - {'EXIT', _} = (catch lists:rumerge(F, [1, 2, 3], b)), - - ok. - -ufunsort_1(Config) when is_list(Config) -> - ok = ufunsort_check(1, [], []), - ok = ufunsort_check(1, [{a,b}], [{a,b}]), - ok = ufunsort_check(1, [{a,b},{a,b}], [{a,b}]), - ok = ufunsort_check(1, [{a,b},{b,c}], [{a,b},{b,c}]), - ok = ufunsort_check(1, [{b,c},{a,b}], [{a,b},{b,c}]), - ok = ufunsort_check(1, - [{1,e},{3,f},{2,y},{0,z},{x,14}], - [{0,z},{1,e},{2,y},{3,f},{x,14}]), - ok = ufunsort_check(1, - [{1,a},{2,b},{3,c},{2,b},{1,a},{2,b},{3,c}, - {2,b},{1,a}], - [{1,a},{2,b},{3,c}]), - ok = ufunsort_check(1, - [{1,a},{1,a},{1,b},{1,b},{1,a},{2,a}], - [{1,a},{2,a}]), - - F = funsort_fun(1), - L1 = [{1,a},{1,b},{1,a}], - L2 = [{1,a},{1,b},{1,a}], - ok = ufunsort_check(1, lists:keymerge(1, L1, L2), - lists:umerge(F, lists:usort(F, L1), - lists:usort(F, L2))), - L3 = [{1,a},{1,b},{1,a},{2,a}], - ok = ufunsort_check(1, lists:keymerge(1, L3, L2), - lists:umerge(F, lists:usort(F, L3), - lists:usort(F, L2))), - L4 = [{1,b},{1,a}], - ok = ufunsort_check(1, lists:keymerge(1, L1, L4), - lists:umerge(F, lists:usort(F, L1), - lists:usort(F, L4))), - L5 = [{1,a},{1,b},{1,a},{2,a}], - ok = ufunsort_check(1, lists:keymerge(1, L5, []), - lists:umerge(F, lists:usort(F, L5), [])), - L6 = [{3,a}], - ok = ufunsort_check(1, lists:keymerge(1, L5, L6), - lists:umerge(F, lists:usort(F, L5), - lists:usort(F, L6))), - - [{b,1},{c,1}] = lists:usort(F, [{c,1},{c,1},{b,1}]), - [{a,0},{b,2},{c,3},{d,4}] = - lists:usort(F, [{d,4},{c,3},{b,2},{b,2},{a,0}]), - [{a,0},{b,1},{c,1}] = - lists:usort(F, [{c,1},{b,1},{b,1},{b,2},{b,2},{a,0}]), - [{a,0},{b,1},{c,1},{d,4}] = - lists:usort(F, [{c,1},{b,1},{b,2},{a,0},{a,0},{d,4},{d,4}]), - - SFun = fun(L) -> fun(X) -> ufunsort_check(1, X, L) end end, - PL = [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f}], - Ps = perms([{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{2,b},{1,a}]), - lists:foreach(SFun(PL), Ps), - - ok. - -%% usort/2 should be stable. -ufunsort_stable(Config) when is_list(Config) -> - ok = ufunsort_check(1, [{1,b},{1,c}], [{1,b}]), - ok = ufunsort_check(1, [{1,c},{1,b}], [{1,c}]), - ok = ufunsort_check(1, - [{1,c},{1,b},{2,x},{3,p},{2,a}], - [{1,c},{2,x},{3,p}]), - - ok = ufunsort_check_stability(bigfunlist(10)), - ok = ufunsort_check_stability(bigfunlist(100)), - ok = ufunsort_check_stability(bigfunlist(1000)), - case erlang:system_info(modified_timing_level) of - undefined -> ok = ufunsort_check_stability(bigfunlist(10000)); - _ -> ok - end, - ok. - -%% usort/2 should exit when given bad arguments. -ufunsort_error(Config) when is_list(Config) -> - {'EXIT', _} = (catch lists:usort(1, [{1,b} , {1,c}])), - {'EXIT', _} = (catch lists:usort(fun(X,Y) -> X =< Y end, - [{1,b} | {1,c}])), - ok. - -%% usort/2 on big randomized lists. -ufunsort_rand(Config) when is_list(Config) -> - ok = ufunsort_check3(1, biglist(10)), - ok = ufunsort_check3(1, biglist(100)), - ok = ufunsort_check3(1, biglist(1000)), - ok = ufunsort_check3(1, biglist(10000)), - - ok = gen_ufunsort_check(1, ubiglist(100)), - ok = gen_ufunsort_check(1, ubiglist(1000)), - ok = gen_ufunsort_check(1, ubiglist(10000)), - ok. - -%% Check that usort/2 is stable and correct relative sort/2. -gen_ufunsort_check(I, Input) -> - U = ufunsort(I, Input), - S = funsort(I, Input), - case U == no_dups_keys(S, I) of - true -> - ok; - false -> - io:format("~w~n", [Input]), - erlang:error(gen_ufunsort_check) - end. - -%% Used for checking that the first copy is kept. -ufunsort_check_stability(L) -> - I = 1, - U = ufunsort(I, L), - S = no_dups(funsort(I, L)), - check_stab(L, U, S, "usort/2", "sort/2"). - -ufunsort_check3(I, Input) -> - ucheck_sorted(I, 3, Input, ufunsort(I, Input)). - -%%% Keysort a list, check that the returned list is what we expected, -%%% and that it is actually sorted. -ufunsort_check(I, Input, Expected) -> - Expected = ufunsort(I, Input), - ucheck_sorted(I, Input, Expected). - -%% Do a keysort -ufunsort(I, L) -> - lists:usort(funsort_fun(I), L). - -funsort_fun(I) -> - fun(A, B) when tuple_size(A) >= I, tuple_size(B) >= I -> - element(I, A) =< element(I, B) - end. - -check_stab(L, U, S, US, SS) -> - UP = explicit_pid(U), - SP = explicit_pid(S), - case UP == SP of - true -> - ok; - false -> - io:format("In: ~w~n", [explicit_pid(L)]), - io:format("~s: ~w~n", [US, UP]), - io:format("~s: ~w~n", [SS, SP]), - erlang:error(unstable) - end. - %%%------------------------------------------------------------ %%% Generate lists of given length, containing 3-tuples with %%% random integer elements in the range 0..44 as elements 1 and 2. @@ -1908,50 +1411,6 @@ urandom_tuple(N, I) -> R2 = randint(I), {R1, R2}. -%%%------------------------------------------------------------ -%%% Generate lists of given length, containing 2-tuples with random -%%% integer elements in the range 0..10 as elements 1. All tuples have -%%% the same function as element 2, but every function is created in a -%%% unique process. ==/2 will return 'true' for any pair of functions, -%%% but erlang:fun_info(Fun, pid) can be used for distinguishing -%%% functions created in different processes. The pid acts like a -%%% sequence number. - -bigfunlist(N) -> - rand:seed(exsplus), - bigfunlist_1(N). - -bigfunlist_1(N) when N < 30000 -> % Now (R8) max 32000 different pids. - case catch bigfunlist(N, 0, []) of - {'EXIT', _} -> - bigfunlist_1(N); - Reply -> - Reply - end. - -bigfunlist(0, _P, L) -> - lists:reverse(L); -bigfunlist(N, P, L) -> - {E, NP} = random_funtuple(P, 11), - bigfunlist(N-1, NP, [E | L]). - -random_funtuple(P, N) -> - R = randint(N), - F = make_fun(), - NP = fun_pid(F), - true = NP > P, - {{R, F}, NP}. - -make_fun() -> - Pid = spawn(?MODULE, make_fun, [self()]), - receive {Pid, Fun} -> Fun end. - -make_fun(Pid) -> - Pid ! {self(), fun (X) -> {X, Pid} end}. - -fun_pid(Fun) -> - erlang:fun_info(Fun, pid). - random_tuple(N, Seq) -> R1 = randint(N), R2 = randint(N), @@ -1960,19 +1419,6 @@ random_tuple(N, Seq) -> randint(N) -> trunc(rand:uniform() * N). -%% The first "duplicate" is kept. -no_dups([]) -> - []; -no_dups([H | T]) -> - no_dups(H, T, []). - -no_dups(H, [H1 | T], L) when H == H1 -> - no_dups(H, T, L); -no_dups(H, [H1 | T], L) -> - no_dups(H1, T, [H | L]); -no_dups(H, [], L) -> - lists:reverse([H | L]). - %% The first "duplicate" is kept. no_dups_keys([], _I) -> []; @@ -1994,7 +1440,7 @@ perms(L) -> %%%------------------------------------------------------------ %%% Test the sort routines with randomly generated lists. --record(state, {sort = 0, usort = 0, stable = 0}). +-record(state, {sort = 0, usort = 0}). %% Run it interactively. 'stop' or 'info' recognized commands. sort_loop() -> @@ -2037,289 +1483,19 @@ sloop(N, S) -> BL = biglist(Len, []), ok = check(BL), ok = keysort_check3(1, BL), - ok = funsort_check3(1, BL), S#state{sort = S#state.sort + 1}; 1 -> BL = ubiglist(Len, []), ok = ucheck(BL), ok = gen_ukeysort_check(1, BL), - ok = gen_ufunsort_check(1, BL), - S#state{usort = S#state.usort + 1}; - 2 -> - BL = bigfunlist(Len), - %% ok = check_stability(BL), - ok = ucheck_stability(BL), - ok = ukeysort_check_stability(BL), - ok = ufunsort_check_stability(BL), - S#state{stable = S#state.stable + 1} + S#state{usort = S#state.usort + 1} end, sloop(N, NS) end. display_state(S) -> io:format("sort: ~p~n", [S#state.sort]), - io:format("usort: ~p~n", [S#state.usort]), - io:format("stable: ~p~n", [S#state.stable]). - -%% This version of sort/1 is really stable; the order of equal -%% elements is kept. It is used for checking the current -%% implementation of usort/1 etc. - -lsort([X, Y | L] = L0) when X =< Y -> - case L of - [] -> - L0; - [Z] when Y =< Z -> - L0; - [Z] when X =< Z -> - [X, Z, Y]; - [Z] -> - [Z, X, Y]; - _ -> - split_1(X, Y, L, [], []) - end; -lsort([X, Y | L]) -> - case L of - [] -> - [Y, X]; - [Z] when X =< Z -> - [Y, X | L]; - [Z] when Y =< Z -> - [Y, Z, X]; - [Z] -> - [Z, Y, X]; - _ -> - split_2(X, Y, L, [], []) - end; -lsort([_] = L) -> - L; -lsort([] = L) -> - L. - -split_1(X, Y, [Z | L], R, Rs) when Z >= Y -> - split_1(Y, Z, L, [X | R], Rs); -split_1(X, Y, [Z | L], R, Rs) when Z >= X -> - split_1(Z, Y, L, [X | R], Rs); -split_1(X, Y, [Z | L], [], Rs) -> - split_1(X, Y, L, [Z], Rs); -split_1(X, Y, [Z | L], R, Rs) -> - split_1_1(X, Y, L, R, Rs, Z); -split_1(X, Y, [], R, Rs) -> - rmergel([[Y, X | R] | Rs], [], asc). - -split_1_1(X, Y, [Z | L], R, Rs, S) when Z >= Y -> - split_1_1(Y, Z, L, [X | R], Rs, S); -split_1_1(X, Y, [Z | L], R, Rs, S) when Z >= X -> - split_1_1(Z, Y, L, [X | R], Rs, S); -split_1_1(X, Y, [Z | L], R, Rs, S) when S =< Z -> - split_1(S, Z, L, [], [[Y, X | R] | Rs]); -split_1_1(X, Y, [Z | L], R, Rs, S) -> - split_1(Z, S, L, [], [[Y, X | R] | Rs]); -split_1_1(X, Y, [], R, Rs, S) -> - rmergel([[S], [Y, X | R] | Rs], [], asc). - -split_2(X, Y, [Z | L], R, Rs) when Z < Y -> - split_2(Y, Z, L, [X | R], Rs); -split_2(X, Y, [Z | L], R, Rs) when Z < X -> - split_2(Z, Y, L, [X | R], Rs); -split_2(X, Y, [Z | L], [], Rs) -> - split_2(X, Y, L, [Z], Rs); -split_2(X, Y, [Z | L], R, Rs) -> - split_2_1(X, Y, L, R, Rs, Z); -split_2(X, Y, [], R, Rs) -> - mergel([[Y, X | R] | Rs], [], desc). - -split_2_1(X, Y, [Z | L], R, Rs, S) when Z < Y -> - split_2_1(Y, Z, L, [X | R], Rs, S); -split_2_1(X, Y, [Z | L], R, Rs, S) when Z < X -> - split_2_1(Z, Y, L, [X | R], Rs, S); -split_2_1(X, Y, [Z | L], R, Rs, S) when S > Z -> - split_2(S, Z, L, [], [[Y, X | R] | Rs]); -split_2_1(X, Y, [Z | L], R, Rs, S) -> - split_2(Z, S, L, [], [[Y, X | R] | Rs]); -split_2_1(X, Y, [], R, Rs, S) -> - mergel([[S], [Y, X | R] | Rs], [], desc). - -mergel([[] | L], Acc, O) -> - mergel(L, Acc, O); -mergel([T1, [H2 | T2] | L], Acc, asc) -> - mergel(L, [merge2_1(T1, H2, T2, []) | Acc], asc); -mergel([[H2 | T2], T1 | L], Acc, desc) -> - mergel(L, [merge2_1(T1, H2, T2, []) | Acc], desc); -mergel([L], [], _O) -> - L; -mergel([L], Acc, O) -> - rmergel([lists:reverse(L, []) | Acc], [], O); -mergel([], [], _O) -> - []; -mergel([], Acc, O) -> - rmergel(Acc, [], O); -mergel([A, [] | L], Acc, O) -> - mergel([A | L], Acc, O); -mergel([A, B, [] | L], Acc, O) -> - mergel([A, B | L], Acc, O). - -rmergel([[H2 | T2], T1 | L], Acc, asc) -> - rmergel(L, [rmerge2_1(T1, H2, T2, []) | Acc], asc); -rmergel([T1, [H2 | T2] | L], Acc, desc) -> - rmergel(L, [rmerge2_1(T1, H2, T2, []) | Acc], desc); -rmergel([L], Acc, O) -> - mergel([lists:reverse(L, []) | Acc], [], O); -rmergel([], Acc, O) -> - mergel(Acc, [], O). - -merge2_1([H1 | T1], H2, T2, M) when H1 =< H2 -> - merge2_1(T1, H2, T2, [H1 | M]); -merge2_1([H1 | T1], H2, T2, M) -> - merge2_2(T1, H1, T2, [H2 | M]); -merge2_1([], H2, T2, M) -> - lists:reverse(T2, [H2 | M]). - -merge2_2(T1, H1, [H2 | T2], M) when H1 =< H2 -> - merge2_1(T1, H2, T2, [H1 | M]); -merge2_2(T1, H1, [H2 | T2], M) -> - merge2_2(T1, H1, T2, [H2 | M]); -merge2_2(T1, H1, [], M) -> - lists:reverse(T1, [H1 | M]). - -rmerge2_1([H1 | T1], H2, T2, M) when H1 =< H2 -> - rmerge2_2(T1, H1, T2, [H2 | M]); -rmerge2_1([H1 | T1], H2, T2, M) -> - rmerge2_1(T1, H2, T2, [H1 | M]); -rmerge2_1([], H2, T2, M) -> - lists:reverse(T2, [H2 | M]). - -rmerge2_2(T1, H1, [H2 | T2], M) when H1 =< H2 -> - rmerge2_2(T1, H1, T2, [H2 | M]); -rmerge2_2(T1, H1, [H2 | T2], M) -> - rmerge2_1(T1, H2, T2, [H1 | M]); -rmerge2_2(T1, H1, [], M) -> - lists:reverse(T1, [H1 | M]). - - - -%% This version of keysort/2 is really stable; the order of equal -%% elements is kept. It is used for checking the current -%% implementation of ukeysort/2 etc. - -lkeysort(Index, L) when is_integer(Index), Index > 0 -> - case L of - [] -> L; - [_] -> L; - [X, Y | T] -> - EX = element(Index, X), - EY = element(Index, Y), - if - EX =< EY -> - keysplit_1(Index, X, EX, Y, EY, T, [], []); - true -> - keysplit_2(Index, Y, EY, T, [X]) - end - end. - -keysplit_1(I, X, EX, Y, EY, [Z | L], R, Rs) -> - EZ = element(I, Z), - if - EY =< EZ -> - keysplit_1(I, Y, EY, Z, EZ, L, [X | R], Rs); - EX =< EZ -> - keysplit_1(I, Z, EZ, Y, EY, L, [X | R], Rs); - true, R == [] -> - keysplit_1(I, X, EX, Y, EY, L, [Z], Rs); - true -> - keysplit_1_1(I, X, EX, Y, EY, L, R, Rs, Z, EZ) - end; -keysplit_1(I, X, _EX, Y, _EY, [], R, Rs) -> - rkeymergel(I, [[Y, X | R] | Rs], []). - -%% One out-of-order element, S. -keysplit_1_1(I, X, EX, Y, EY, [Z | L], R, Rs, S, ES) -> - EZ = element(I, Z), - if - EY =< EZ -> - keysplit_1_1(I, Y, EY, Z, EZ, L, [X | R], Rs, S, ES); - EX =< EZ -> - keysplit_1_1(I, Z, EZ, Y, EY, L, [X | R], Rs, S, ES); - ES =< EZ -> - keysplit_1(I, S, ES, Z, EZ, L, [], [[Y, X | R] | Rs]); - true -> - keysplit_1(I, Z, EZ, S, ES, L, [], [[Y, X | R] | Rs]) - end; -keysplit_1_1(I, X, _EX, Y, _EY, [], R, Rs, S, _ES) -> - rkeymergel(I, [[S], [Y, X | R] | Rs], []). - -%% Descending. -keysplit_2(I, Y, EY, [Z | L], R) -> - EZ = element(I, Z), - if - EY =< EZ -> - keysplit_1(I, Y, EY, Z, EZ, L, [], [lists:reverse(R, [])]); - true -> - keysplit_2(I, Z, EZ, L, [Y | R]) - end; -keysplit_2(_I, Y, _EY, [], R) -> - [Y | R]. - -keymergel(I, [T1, [H2 | T2] | L], Acc) -> - keymergel(I, L, [keymerge2_1(I, T1, element(I, H2), H2, T2, []) | Acc]); -keymergel(_I, [L], []) -> - L; -keymergel(I, [L], Acc) -> - rkeymergel(I, [lists:reverse(L, []) | Acc], []); -keymergel(I, [], Acc) -> - rkeymergel(I, Acc, []). - -rkeymergel(I, [[H2 | T2], T1 | L], Acc) -> - rkeymergel(I, L, [rkeymerge2_1(I, T1, element(I, H2), H2, T2, []) | Acc]); -rkeymergel(I, [L], Acc) -> - keymergel(I, [lists:reverse(L, []) | Acc], []); -rkeymergel(I, [], Acc) -> - keymergel(I, Acc, []). - -keymerge2_1(I, [H1 | T1], E2, H2, T2, M) -> - E1 = element(I, H1), - if - E1 =< E2 -> - keymerge2_1(I, T1, E2, H2, T2, [H1 | M]); - true -> - keymerge2_2(I, T1, E1, H1, T2, [H2 | M]) - end; -keymerge2_1(_I, [], _E2, H2, T2, M) -> - lists:reverse(T2, [H2 | M]). - -keymerge2_2(I, T1, E1, H1, [H2 | T2], M) -> - E2 = element(I, H2), - if - E1 =< E2 -> - keymerge2_1(I, T1, E2, H2, T2, [H1 | M]); - true -> - keymerge2_2(I, T1, E1, H1, T2, [H2 | M]) - end; -keymerge2_2(_I, T1, _E1, H1, [], M) -> - lists:reverse(T1, [H1 | M]). - -rkeymerge2_1(I, [H1 | T1], E2, H2, T2, M) -> - E1 = element(I, H1), - if - E1 =< E2 -> - rkeymerge2_2(I, T1, E1, T2, [H2 | M], H1); - true -> - rkeymerge2_1(I, T1, E2, H2, T2, [H1 | M]) - end; -rkeymerge2_1(_I, [], _E2, H2, T2, M) -> - lists:reverse(T2, [H2 | M]). - -rkeymerge2_2(I, T1, E1, [H2 | T2], M, H1) -> - E2 = element(I, H2), - if - E1 =< E2 -> - rkeymerge2_2(I, T1, E1, T2, [H2 | M], H1); - true -> - rkeymerge2_1(I, T1, E2, H2, T2, [H1 | M]) - end; -rkeymerge2_2(_I, T1, _E1, [], M, H1) -> - lists:reverse(T1, [H1 | M]). - + io:format("usort: ~p~n", [S#state.usort]). %%%------------------------------------------------------------ @@ -2543,7 +1719,6 @@ sublist_3_e(Config) when is_list(Config) -> -define(flatten_error1(X), {'EXIT', _} = (catch lists:flatten(X))). --define(flatten_error2(X,Y), {'EXIT', _} = (catch lists:flatten(X,Y))). %% Test lists:flatten/1,2 and lists:flatlength/1. flatten_1(Config) when is_list(Config) -> -- 2.35.3
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor