summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--combi.c91
-rw-r--r--combi.h1
-rw-r--r--eval.c1
-rw-r--r--lib.c23
-rw-r--r--lib.h11
5 files changed, 117 insertions, 10 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);
diff --git a/combi.h b/combi.h
index 9302029a..907aec87 100644
--- a/combi.h
+++ b/combi.h
@@ -27,6 +27,7 @@
*/
val perm(val seq, val k);
+val permi(val seq, val k);
val rperm(val seq, val k);
val comb(val seq, val k);
val rcomb(val seq, val k);
diff --git a/eval.c b/eval.c
index 1e6e48d5..815d488f 100644
--- a/eval.c
+++ b/eval.c
@@ -7898,6 +7898,7 @@ void eval_init(void)
reg_fun(intern(lit("promisep"), user_package), func_n1(promisep));
reg_fun(intern(lit("rperm"), user_package), func_n2(rperm));
reg_fun(intern(lit("perm"), user_package), func_n2o(perm, 1));
+ reg_fun(intern(lit("permi"), user_package), func_n2o(permi, 1));
reg_fun(intern(lit("comb"), user_package), func_n2(comb));
reg_fun(intern(lit("rcomb"), user_package), func_n2(rcomb));
diff --git a/lib.c b/lib.c
index b4f44a01..d3b829ee 100644
--- a/lib.c
+++ b/lib.c
@@ -910,7 +910,7 @@ static int seq_iter_peek_cat(seq_iter_t *it, val *pval)
}
}
-static void seq_iter_mark_op(struct seq_iter *it)
+void seq_iter_mark_op(struct seq_iter *it)
{
gc_mark(it->ui.iter);
}
@@ -977,6 +977,14 @@ struct seq_iter_ops si_fast_oop_ops = seq_iter_ops_init(seq_iter_get_fast_oop,
struct seq_iter_ops si_cat_ops = seq_iter_ops_init(seq_iter_get_cat,
seq_iter_peek_cat);
+static void seq_iter_clone(seq_iter_t *dit, const seq_iter_t *sit)
+{
+ if (sit->ops->clone)
+ sit->ops->clone(sit, dit);
+ else
+ *dit = *sit;
+}
+
void seq_iter_init_with_info(val self, seq_iter_t *it,
seq_info_t si, int support_rewind)
{
@@ -1128,7 +1136,7 @@ void seq_iter_init_with_info(val self, seq_iter_t *it,
}
if (it->inf.obj->co.cls == seq_iter_cls)
{
- *it = *coerce(struct seq_iter *, it->inf.obj->co.handle);
+ seq_iter_clone(it, coerce(struct seq_iter *, it->inf.obj->co.handle));
break;
}
if (it->inf.obj->co.cls == tree_iter_cls)
@@ -1224,12 +1232,11 @@ static void seq_iter_mark(val seq_iter)
si->ops->mark(si);
}
-static struct cobj_ops
- seq_iter_cobj_ops = cobj_ops_init(eq,
- cobj_print_op,
- cobj_destroy_free_op,
- seq_iter_mark,
- cobj_eq_hash_op);
+struct cobj_ops seq_iter_cobj_ops = cobj_ops_init(eq,
+ cobj_print_op,
+ cobj_destroy_free_op,
+ seq_iter_mark,
+ cobj_eq_hash_op);
val seq_begin(val obj)
{
diff --git a/lib.h b/lib.h
index 07c37b9f..04e4f725 100644
--- a/lib.h
+++ b/lib.h
@@ -465,10 +465,13 @@ struct seq_iter_ops {
int (*get)(struct seq_iter *, val *pval);
int (*peek)(struct seq_iter *, val *pval);
void (*mark)(struct seq_iter *);
+ void (*clone)(const struct seq_iter *, struct seq_iter *);
};
-#define seq_iter_ops_init(get, peek) { get, peek, seq_iter_mark_op }
-#define seq_iter_ops_init_nomark(get, peek) { get, peek, 0 }
+#define seq_iter_ops_init(get, peek) { get, peek, seq_iter_mark_op, 0 }
+#define seq_iter_ops_init_nomark(get, peek) { get, peek, 0, 0 }
+#define seq_iter_ops_init_clone(get, peek, clone) \
+ { get, peek, seq_iter_mark_op, clone }
typedef struct seq_build {
val obj;
@@ -745,12 +748,16 @@ typedef unsigned long alloc_bytes_t;
extern alloc_bytes_t malloc_bytes;
extern alloc_bytes_t gc_bytes;
+extern struct cobj_class *seq_iter_cls;
+extern struct cobj_ops seq_iter_cobj_ops;
+
val identity(val obj);
val built_in_type_p(val sym);
val typeof(val obj);
val subtypep(val sub, val sup);
val typep(val obj, val type);
seq_info_t seq_info(val cobj);
+void seq_iter_mark_op(struct seq_iter *it);
void seq_iter_init_with_info(val self, seq_iter_t *it,
seq_info_t si, int support_rewind);
void seq_iter_init(val self, seq_iter_t *it, val obj);