diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2019-02-13 06:27:33 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2019-02-13 06:27:33 -0800 |
commit | 5724a053262cc324515206180b6640ecde12addb (patch) | |
tree | 9cfa75ff02480515579afba90a1c2f7ef38d9488 /lib.c | |
parent | dabd00c6f02b73c43cdf8c4ec760092cc5a04268 (diff) | |
download | txr-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.c | 79 |
1 files changed, 79 insertions, 0 deletions
@@ -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); |