diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2025-03-07 07:08:29 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2025-03-07 07:08:29 -0800 |
commit | 26f1f25a07a2b85b5481f0f5f1612c64bc76d910 (patch) | |
tree | 2563d5325552ba994520b3f0d064be3076316bb4 /lib.c | |
parent | 07e40c025d65beeced5ac83485eb13dab9b7d2ae (diff) | |
download | txr-26f1f25a07a2b85b5481f0f5f1612c64bc76d910.tar.gz txr-26f1f25a07a2b85b5481f0f5f1612c64bc76d910.tar.bz2 txr-26f1f25a07a2b85b5481f0f5f1612c64bc76d910.zip |
New feature: range iteration with skip.
The notation X..Y..Z now denotes an iterable range,
if X..Y is a valid iterable range on its own, and Z is a
positive integer. Z gives a step size: 1 takes every
element, 2 every other and so on.
* lib.c (seq_iter_get_skip, set_iter_peek_skip): New static
functions.
(si_skip_ops): New static structure.
(iter_dynamic): Function relocated earlier in file to avoid
forward declaration.
(seq_iter_init_with_info): When the iterated object is a
range, check for the to element itself being a range.
If so, it is potentially a skip iteration. Validate it
and implement via a skip iterator referencing a dynamic
range iterator.
* lib.h (struct seq_iter): New sub-union member, ul.skip.
We could use an existing member of type cnum;
this is for naming clarity.
* tests/012/iter.tl: New tests.
* txr.1: Documented.
Diffstat (limited to 'lib.c')
-rw-r--r-- | lib.c | 71 |
1 files changed, 63 insertions, 8 deletions
@@ -859,6 +859,34 @@ static int seq_iter_peek_cat(seq_iter_t *it, val *pval) } } +static int seq_iter_get_skip(seq_iter_t *it, val *pval) +{ + val iter = it->ui.iter; + cnum skip = it->ul.skip; + + if (iter_more(iter)) { + cnum i; + *pval = iter_item(iter); + for (i = 0; i < skip; i++) + iter = iter_step(iter); + return 1; + } + + return 0; +} + +static int seq_iter_peek_skip(seq_iter_t *it, val *pval) +{ + val iter = it->ui.iter; + + if (iter_more(iter)) { + *pval = iter_item(iter); + return 1; + } + + return 0; +} + static void seq_iter_mark_cat(struct seq_iter *it) { gc_mark(it->ul.dargs); @@ -941,6 +969,9 @@ struct seq_iter_ops si_cat_ops = seq_iter_ops_init_mark(seq_iter_get_cat, seq_iter_peek_cat, seq_iter_mark_cat); +struct seq_iter_ops si_skip_ops = seq_iter_ops_init(seq_iter_get_skip, + seq_iter_peek_skip); + static void seq_iter_clone(seq_iter_t *dit, const seq_iter_t *sit) { if (sit->ops->clone) @@ -949,6 +980,14 @@ static void seq_iter_clone(seq_iter_t *dit, const seq_iter_t *sit) *dit = *sit; } +static val iter_dynamic(struct seq_iter *si_orig) +{ + struct seq_iter *si = coerce(struct seq_iter *, + chk_copy_obj(coerce(mem_t *, si_orig), + sizeof *si)); + return cobj(coerce(mem_t *, si), seq_iter_cls, &seq_iter_cobj_ops); +} + void seq_iter_init_with_info(val self, seq_iter_t *it, seq_info_t si) { it->inf = si; @@ -964,6 +1003,30 @@ void seq_iter_init_with_info(val self, seq_iter_t *it, seq_info_t si) break; } + if (rangep(rt)) { + val rtf = from(rt); + val rtt = to(rt); + + if (!integerp(rtt) || !plusp(rtt)) { + uw_throwf(type_error_s, + lit("~a: skip amount ~s in ~s..~s..~s " + "must be positive integer"), + self, rtt, rf, rtf, rtt, nao); + } else if (rtt == one) { + rt = rtf; + } else { + val rng = rcons(rf, rtf); + seq_iter_t lower_iter; + + seq_iter_init_with_info(self, &lower_iter, seq_info(rng)); + + it->ui.iter = iter_dynamic(&lower_iter); + it->ul.skip = c_num(rtt, self); + it->ops = &si_skip_ops; + return; + } + } + if (less(rf, rt)) switch (type(rf)) { case NUM: num_range_fwd: @@ -1277,14 +1340,6 @@ val iter_begin(val obj) } } -static val iter_dynamic(struct seq_iter *si_orig) -{ - struct seq_iter *si = coerce(struct seq_iter *, - chk_copy_obj(coerce(mem_t *, si_orig), - sizeof *si)); - return cobj(coerce(mem_t *, si), seq_iter_cls, &seq_iter_cobj_ops); -} - val iter_more(val iter) { val self = lit("iter-more"); |