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 /lib.c | |
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.
Diffstat (limited to 'lib.c')
-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)); } } |