diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2017-11-21 19:25:54 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2017-11-21 19:25:54 -0800 |
commit | 68ddbfb634809be74722e9252993c6089a0c4d7a (patch) | |
tree | 7f324cecd2a447703d6548c678dc835d9198e5c1 | |
parent | 368b33e560b541b20a9a28e6ba307a22a813049e (diff) | |
download | txr-68ddbfb634809be74722e9252993c6089a0c4d7a.tar.gz txr-68ddbfb634809be74722e9252993c6089a0c4d7a.tar.bz2 txr-68ddbfb634809be74722e9252993c6089a0c4d7a.zip |
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.
-rw-r--r-- | lib.c | 52 |
1 files changed, 23 insertions, 29 deletions
@@ -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)); } } |