diff options
-rw-r--r-- | eval.c | 1 | ||||
-rw-r--r-- | lib.c | 64 | ||||
-rw-r--r-- | lib.h | 2 | ||||
-rw-r--r-- | tests/012/iter.tl | 5 | ||||
-rw-r--r-- | txr.1 | 57 |
5 files changed, 129 insertions, 0 deletions
@@ -7824,6 +7824,7 @@ void eval_init(void) reg_fun(intern(lit("iter-item"), user_package), func_n1(iter_item)); reg_fun(intern(lit("iter-step"), user_package), func_n1(iter_step)); reg_fun(intern(lit("iter-reset"), user_package), func_n2(iter_reset)); + reg_fun(intern(lit("iter-cat"), user_package), func_n0v(iter_catv)); reg_fun(intern(lit("rcons"), user_package), func_n2(rcons)); reg_fun(intern(lit("rangep"), user_package), func_n1(rangep)); @@ -869,6 +869,47 @@ static void seq_iter_rewind(seq_iter_t *it) } } +static int seq_iter_get_cat(seq_iter_t *it, val *pval) +{ + val dargs = it->ul.dargs; + cnum index = it->ui.index; + varg args = dargs->a.args; + val iter = dargs->a.car; + + for (;;) { + if (iter_more(iter)) { + *pval = iter_item(iter); + set(mkloc(dargs->a.car, dargs), iter_step(iter)); + return 1; + } + if (!args_more(args, index)) + return 0; + iter = iter_begin(args_get(args, &index)); + it->ui.index = index; + set(mkloc(dargs->a.car, dargs), iter); + } +} + +static int seq_iter_peek_cat(seq_iter_t *it, val *pval) +{ + val dargs = it->ul.dargs; + cnum index = it->ui.index; + varg args = dargs->a.args; + val iter = dargs->a.car; + + for (;;) { + if (iter_more(iter)) { + *pval = iter_item(iter); + return 1; + } + if (!args_more(args, index)) + return 0; + iter = iter_begin(args_get(args, &index)); + it->ui.index = index; + set(mkloc(dargs->a.car, dargs), iter); + } +} + static void seq_iter_mark_op(struct seq_iter *it) { gc_mark(it->ui.iter); @@ -933,6 +974,9 @@ struct seq_iter_ops si_oop_ops = seq_iter_ops_init(seq_iter_get_oop, struct seq_iter_ops si_fast_oop_ops = seq_iter_ops_init(seq_iter_get_fast_oop, seq_iter_peek_fast_oop); +struct seq_iter_ops si_cat_ops = seq_iter_ops_init(seq_iter_get_cat, + seq_iter_peek_cat); + void seq_iter_init_with_info(val self, seq_iter_t *it, seq_info_t si, int support_rewind) { @@ -1406,6 +1450,26 @@ val iter_reset(val iter, val obj) } } +val iter_catv(varg iters) +{ + cnum index = 0; + if (args_more(iters, index)) { + val iter0 = iter_begin(args_get(iters, &index)); + val dargs = dyn_args(iters, iter0, nil); + val si_obj, iter; + struct seq_iter *si = coerce(struct seq_iter *, chk_calloc(1, sizeof *si)); + si->inf.type = DARG; + si->inf.obj = dargs; + si->ui.index = index; + si->ul.dargs = dargs; + si->ops = &si_cat_ops; + si_obj = cobj(coerce(mem_t *, si), seq_iter_cls, &seq_iter_ops); + gc_hint(iter); + return si_obj; + } + return nil; +} + static void seq_build_generic_pend(seq_build_t *bu, val seq) { seq_iter_t it; @@ -456,6 +456,7 @@ typedef struct seq_iter { val vbound; cnum cbound; val next; + val dargs; } ul; struct seq_iter_ops *ops; } seq_iter_t; @@ -766,6 +767,7 @@ val iter_more(val iter); val iter_item(val iter); val iter_step(val iter); val iter_reset(val iter, val obj); +val iter_catv(varg iters); void seq_build_init(val self, seq_build_t *bu, val likeobj); void seq_add(seq_build_t *bu, val item); void seq_pend(seq_build_t *bu, val items); diff --git a/tests/012/iter.tl b/tests/012/iter.tl index 1b1bfd1e..0823849e 100644 --- a/tests/012/iter.tl +++ b/tests/012/iter.tl @@ -90,3 +90,8 @@ 115792089237316195423570985008687907853269984665640564039457584007913129639934 115792089237316195423570985008687907853269984665640564039457584007913129639933)) +(mtest + (str-seq (iter-cat "abc" "def" "ghi" #\j..(succ #\z))) + "abcdefghijklmnopqrstuvwxyz" + (iter-cat) nil + (list-seq (iter-cat nil)) nil) @@ -39990,6 +39990,63 @@ is invoked on .meta seq and the result is returned. +.coNP Function @ iter-cat +.synb +.mets (iter-cat << seq *) +.syne +.desc +The +.code iter-cat +function produces a catenated iterator: an object suitable for traversing +the abstract sequence formed by the catenation of the +.meta seq +arguments. This is accomplished without actually catenating the argument +sequences. + +If no arguments are given to +.code iter-cat +then it returns +.codn nil . +Otherwise, the abstract semantics of the catenated iterator is as follows. +The iterator retains all of the +.meta seq +objects. It converts the first +.meta seq +object to an iterator as if by +.code iter-begin +on it. This is referred to as the individual iterator. When that iterator is +exhausted of items, +.code iter-begin +is called on the next +.meta seq +object to produce the next individual iterator. + +Note: under this semantics, the catenated iterator's +.code iter-more +operation does not simply report the value returned by the +.code iter-more +call on the individual iterator. When the individual iterator's +.code iter-more +function returns +.codn nil , +the catenated operator then switches to the individual iterator of the next +.meta seq +object in the argument sequence. This is repeated as many times as necessary +until an iterator is found for which +The +.code iter-item +function, when applied to a catenated iterator, similarly potentially +searches through the argument space. +.code iter-more +yields true, or the arguments are exhausted. + +.TP* Examples: + +.verb + ;; Create an iterator that produces 0, 1, ... 9, 20, 21, ... 29 + (iter-cat 0..10 20..30) +.brev + .coNP Function @ seq-begin .synb .mets (seq-begin << object ) |