summaryrefslogtreecommitdiffstats
path: root/lib.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2019-02-13 06:27:33 -0800
committerKaz Kylheku <kaz@kylheku.com>2019-02-13 06:27:33 -0800
commit5724a053262cc324515206180b6640ecde12addb (patch)
tree9cfa75ff02480515579afba90a1c2f7ef38d9488 /lib.c
parentdabd00c6f02b73c43cdf8c4ec760092cc5a04268 (diff)
downloadtxr-5724a053262cc324515206180b6640ecde12addb.tar.gz
txr-5724a053262cc324515206180b6640ecde12addb.tar.bz2
txr-5724a053262cc324515206180b6640ecde12addb.zip
Framework for iterating over sequences.
This has been needed for a while. While we have seq_info for classifying sequences to nicely dispatch code into various cases, those cases duplicate code. The code base could benefit from generic traversal. * lib.c (seq_iter_get_nil, seq_iter_get_list, seq_iter_get_vec, set_iter_get_hash): New static functions. (seq_iter_rewind, seq_iter_init): New functions. * lib.h (struct seq_iter, seq_iter_t): New struct type and its typedef name. (seq_iter_init, seq_iter_rewind): Declared. (seq_get): New inline function.
Diffstat (limited to 'lib.c')
-rw-r--r--lib.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/lib.c b/lib.c
index 5da925e9..e837939b 100644
--- a/lib.c
+++ b/lib.c
@@ -323,6 +323,85 @@ static void noreturn unsup_obj(val self, val obj)
abort();
}
+static int seq_iter_get_nil(seq_iter_t *it, val *pval)
+{
+ return 0;
+}
+
+static int seq_iter_get_list(seq_iter_t *it, val *pval)
+{
+ if (!it->ui.iter)
+ return 0;
+ *pval = car(it->ui.iter);
+ it->ui.iter = cdr(it->ui.iter);
+ return 1;
+}
+
+static int seq_iter_get_vec(seq_iter_t *it, val *pval)
+{
+ if (it->ui.index < it->ul.len) {
+ *pval = ref(it->inf.obj, num(it->ui.index++));
+ return 1;
+ }
+ return 0;
+}
+
+static int seq_iter_get_hash(seq_iter_t *it, val *pval)
+{
+ *pval = hash_next(it->ui.iter);
+ return *pval != nil;
+}
+
+void seq_iter_rewind(val self, seq_iter_t *it)
+{
+ switch (it->inf.kind) {
+ case SEQ_NIL:
+ it->ui.iter = nil;
+ break;
+ case SEQ_LISTLIKE:
+ it->ui.iter = it->inf.obj;
+ break;
+ case SEQ_VECLIKE:
+ it->ui.index = 0;
+ break;
+ case SEQ_HASHLIKE:
+ it->ui.iter = hash_begin(it->inf.obj);
+ break;
+ default:
+ break;
+ }
+}
+
+void seq_iter_init(val self, seq_iter_t *it, val obj)
+{
+ it->inf = seq_info(obj);
+
+ switch (it->inf.kind) {
+ case SEQ_NIL:
+ it->ui.iter = nil;
+ it->ul.len = 0;
+ it->get = seq_iter_get_nil;
+ break;
+ case SEQ_LISTLIKE:
+ it->ui.iter = it->inf.obj;
+ it->ul.len = 0;
+ it->get = seq_iter_get_list;
+ break;
+ case SEQ_VECLIKE:
+ it->ui.index = 0;
+ it->ul.len = c_num(length(it->inf.obj));
+ it->get = seq_iter_get_vec;
+ break;
+ case SEQ_HASHLIKE:
+ it->ui.iter = hash_begin(it->inf.obj);
+ it->ul.len = 0;
+ it->get = seq_iter_get_hash;
+ break;
+ default:
+ unsup_obj(self, obj);
+ }
+}
+
val throw_mismatch(val self, val obj, type_t t)
{
type_mismatch(lit("~a: ~s is not of type ~s"), self, obj, code2type(t), nao);