summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eval.c1
-rw-r--r--lib.c64
-rw-r--r--lib.h2
-rw-r--r--tests/012/iter.tl5
-rw-r--r--txr.157
5 files changed, 129 insertions, 0 deletions
diff --git a/eval.c b/eval.c
index 4125d33a..c7e281a7 100644
--- a/eval.c
+++ b/eval.c
@@ -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));
diff --git a/lib.c b/lib.c
index 4ee9cd59..832d704b 100644
--- a/lib.c
+++ b/lib.c
@@ -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;
diff --git a/lib.h b/lib.h
index 9378ce02..dfa23c6e 100644
--- a/lib.h
+++ b/lib.h
@@ -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)
diff --git a/txr.1 b/txr.1
index b5cffeea..d951e459 100644
--- a/txr.1
+++ b/txr.1
@@ -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 )