diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2024-06-15 15:01:16 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2024-06-15 15:01:16 -0700 |
commit | 38a76d820decec3c703185b12a0f89bedec7716c (patch) | |
tree | b4a0dea1deb5004adbbf6d1cc88f90a550c2d4d7 /combi.c | |
parent | 08eef02fb98856550fdd6a2cdccfdb65dc0cfec8 (diff) | |
download | txr-38a76d820decec3c703185b12a0f89bedec7716c.tar.gz txr-38a76d820decec3c703185b12a0f89bedec7716c.tar.bz2 txr-38a76d820decec3c703185b12a0f89bedec7716c.zip |
New permi: iterator version of perm.
* eval.c (eval_init): Register permi intrinsic.
* combi.c (permi_get, permi_peek, permi_clone): New static
functions.
(permi_ops): New static structure.
(permi_iter): New static function.
(permi): New function.
* combi.h (permi): Declared.
* lib.h (struct seq_iter_ops): New function pointer, clone.
(seq_iter_ops_init, seq_iter_ops_init_nomark): Initialize
new member.
(seq_iter_ops_init_clone): New macro.
(seq_iter_cls): Existing external name declared.
(seq_iter_cobj_ops, seq_iter_mark_op): Previously internal
names declared external.
* lib.c (seq_iter_mark_op, seq_iter_cobj_ops): Static variables
become extern.
(seq_iter_clone): New static function.
(seq_iter_init_with_info): Use seq_iter_clone instead of assuming
we can trivially clone an iterator state bitwise.
Diffstat (limited to 'combi.c')
-rw-r--r-- | combi.c | 91 |
1 files changed, 91 insertions, 0 deletions
@@ -35,6 +35,7 @@ #include "unwind.h" #include "eval.h" #include "hash.h" +#include "gc.h" #include "combi.h" static void check_k(val k, val self) @@ -266,6 +267,96 @@ val perm(val seq, val k) } } +static int permi_get(struct seq_iter *it, val *pval) +{ + val state = it->inf.obj; + + if (it->ul.next) { + if (it->ui.iter || perm_while_fun(state)) { + it->ui.iter = nil; + *pval = perm_seq_gen_fun(state); + return 1; + } + } + + it->ul.next = nil; + return 0; +} + +static int permi_peek(struct seq_iter *it, val *pval) +{ + val state = it->inf.obj; + + if (it->ul.next) { + if (it->ui.iter || perm_while_fun(state)) { + it->ui.iter = t; + *pval = state; + *pval = perm_seq_gen_fun(state); + return 1; + } + } + + it->ul.next = nil; + return 0; +} + +static void permi_clone(const struct seq_iter *sit, struct seq_iter *dit) +{ + val state = sit->inf.obj; + val c = vecref(state, two); + val state_copy = copy_vec(state); + + *dit = *sit; + dit->inf.obj = state_copy; + set(vecref_l(state_copy, two), copy_vec(c)); +} + +struct seq_iter_ops permi_ops = seq_iter_ops_init_clone(permi_get, + permi_peek, + permi_clone); + +static val permi_iter(val state) +{ + val obj; + struct seq_iter *it = coerce(struct seq_iter *, chk_calloc(1, sizeof *it)); + + it->inf.obj = state; + it->inf.type = NIL; + it->inf.kind = SEQ_NOTSEQ; + + it->ui.iter = nil; + it->ul.next = t; + it->ops = &permi_ops; + + obj = cobj(coerce(mem_t *, it), seq_iter_cls, &seq_iter_cobj_ops); + + gc_hint(obj); + gc_hint(state); + + return obj; +} + +val permi(val seq, val k) +{ + val self = lit("permi"); + + if (null_or_missing_p(k)) { + k = nil; + } else { + check_k(k, self); + } + + if (k == zero) { + return cons(make_like(nil, seq), nil); + } else { + val vec = vec_seq(seq); + val state = perm_init(vec, k, seq); + if (!state) + return nil; + return permi_iter(state); + } +} + static val rperm_init(val list, val k, val extra) { val vec = vector(k, list); |