From 68ddbfb634809be74722e9252993c6089a0c4d7a Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Tue, 21 Nov 2017 19:25:54 -0800 Subject: bugfix: two issues in mappend* and append*. Two bugs in these functions, both attributable to the lazy_appendv implementation: They destructively catenate the input lists, much like nconc, even though documented as non-destructive. If any input list is infinite, other than the last input list, that list is forced, resulting in an infinite loop. * lib.c (lazy_appendv_func): Rewritten to use a different algorithm which earnestly allocates a new lazy cons for each element of the output sequence, except for the tail part corresponding to the last list. (lazy_appendv): Set up the lazy cons according to the new representation and just return it. No searching for the tail of the nonempty list, and no destructive manipulation. --- lib.c | 52 +++++++++++++++++++++++----------------------------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/lib.c b/lib.c index 18ba967f..97d0eece 100644 --- a/lib.c +++ b/lib.c @@ -1357,34 +1357,31 @@ val replace_list(val list, val items, val from, val to) static val lazy_appendv_func(val env, val lcons) { - cons_bind (last, lists, env); - val nonempty = nil; - - while (lists) { - nonempty = nullify(pop(&lists)); - if (nonempty) - break; - } + cons_bind (fl, rl, env); + cons_bind (fe, re, fl); - rplaca(lcons, last); + rplaca(lcons, fe); - if (nilp(lists)) { - rplacd(lcons, nonempty); - return nil; + if (re) { + rplaca(env, re); + rplacd(lcons, make_lazy_cons(lcons_fun(lcons))); + } else if (rl) { + do { + fl = car(rl); + rl = cdr(rl); + } while (!fl && rl); + + if (fl) { + if (rl) { + rplaca(env, fl); + rplacd(env, rl); + rplacd(lcons, make_lazy_cons(lcons_fun(lcons))); + } else { + rplacd(lcons, fl); + } + } } - if (atom(nonempty)) - uw_throwf(error_s, lit("append*: cannot append to atom ~s"), - nonempty, nao); - - rplacd(env, lists); - - { - loc ptail = ltail(mkcloc(nonempty)); - rplaca(env, car(deref(ptail))); - set(ptail, make_lazy_cons(lcons_fun(lcons))); - rplacd(lcons, nonempty); - } return nil; } @@ -1407,11 +1404,8 @@ val lazy_appendv(struct args *args) nonempty, nao); { - loc ptail = ltail(mkcloc(nonempty)); - set(ptail, make_lazy_cons(func_f1(cons(car(deref(ptail)), - args_get_rest(args, index)), - lazy_appendv_func))); - return nonempty; + return make_lazy_cons(func_f1(cons(nonempty, args_get_rest(args, index)), + lazy_appendv_func)); } } -- cgit v1.2.3