summaryrefslogtreecommitdiffstats
path: root/combi.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2024-06-15 15:01:16 -0700
committerKaz Kylheku <kaz@kylheku.com>2024-06-15 15:01:16 -0700
commit38a76d820decec3c703185b12a0f89bedec7716c (patch)
treeb4a0dea1deb5004adbbf6d1cc88f90a550c2d4d7 /combi.c
parent08eef02fb98856550fdd6a2cdccfdb65dc0cfec8 (diff)
downloadtxr-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.c91
1 files changed, 91 insertions, 0 deletions
diff --git a/combi.c b/combi.c
index 82442af8..746f7910 100644
--- a/combi.c
+++ b/combi.c
@@ -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);