diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2020-07-07 06:46:22 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2020-07-07 06:46:22 -0700 |
commit | 623ce6c9829d9352d05f6dae3204c1705be95702 (patch) | |
tree | 383bc7d6127762ced11d2e80b0dfea7c3b91054d /lib.c | |
parent | 91b24fc71e53a0b356ef97708f467b9da37fbb6b (diff) | |
download | txr-623ce6c9829d9352d05f6dae3204c1705be95702.tar.gz txr-623ce6c9829d9352d05f6dae3204c1705be95702.tar.bz2 txr-623ce6c9829d9352d05f6dae3204c1705be95702.zip |
New: protocol for iteration with structs.
* lib.c (seq_iterable): Return t if argument is a structure
supporting the iter-begin method.
(seq_iter_get_oop, seq_iter_peek_oop, seq_iter_get_fast_oop,
seq_iter_peek_fast_oop): New static functions.
(seq_iter_init_with_info): Handle COBJ case. If the COBJ is a
structure which suports the iter-begin method, then retrieve
the iterator object by calling it, and then prepare the
iterator structure for either the fast or the canonical
protocol based on whether the iterator supports iter-more.
(seq_iter_mark): Mark the iter member if the iterator is a
struct object.
(iter_begin): Rearrange tests here to check object type first
before sequence kind. If the object is a structure supporting
the iter-begin method, then call it and return its value.
(iter_more, iter_step): Check for struct object with
corresponding special methods and return.
(iter_reset): Similar change like in iter_begin. We check for
the iter-reset special method and try to use it, otherwise
fall back on the regular iter_begin logic.
* lib.h (struct seq_iter): New member next of the ul union
for caching the result of a peek operation.
* struct.c (iter_begin_s, iter_more_s, iter_item_s,
iter_step_s, iter_reset_s): New symbol variables;
(special_sym): Pointers to new symbol variables added to
array.
(struct_init): New symbol variables initialized.
(get_special_required_slot): New function.
* struct.h (iter_begin_s, iter_more_s, iter_item_s,
iter_step_s, iter_reset_s): Declared.
(enum special_slot): New enum members iter_begin_m,
iter_more_m, iter_item_m, iter_step_m, iter_reset_m.
(get_special_required_slot): Declared.
* txr.1: Documented.
* tests/012/oop-seq.expected: New file.
* tests/012/oop-seq.tl: New file.
Diffstat (limited to 'lib.c')
-rw-r--r-- | lib.c | 197 |
1 files changed, 171 insertions, 26 deletions
@@ -353,6 +353,10 @@ static val seq_iterable(seq_info_t si) case BGNUM: case FLNUM: return t; + case COBJ: + if (get_special_slot(si.obj, iter_begin_m)) + return t; + break; default: break; } @@ -568,6 +572,94 @@ static int seq_iter_peek_num(seq_iter_t *it, val *pval) return 1; } +static int seq_iter_get_oop(seq_iter_t *it, val *pval) +{ + val iter = it->ui.iter; + + if (it->ul.next != nao) { + val iter_step_meth = get_special_required_slot(iter, iter_step_m); + *pval = it->ul.next; + it->ui.iter = funcall1(iter_step_meth, iter); + it->ul.next = nao; + return 1; + } else { + val iter_more_meth = get_special_required_slot(iter, iter_more_m); + + if (!funcall1(iter_more_meth, iter)) { + return 0; + } else { + val iter_item_meth = get_special_required_slot(iter, iter_item_m); + val iter_step_meth = get_special_required_slot(iter, iter_step_m); + *pval = funcall1(iter_item_meth, iter); + it->ui.iter = funcall1(iter_step_meth, iter); + it->ul.next = nao; + return 1; + } + } +} + +static int seq_iter_peek_oop(seq_iter_t *it, val *pval) +{ + val iter = it->ui.iter; + + if (it->ul.next != nao) { + *pval = it->ul.next; + return 1; + } else { + val iter_more_meth = get_special_required_slot(iter, iter_more_m); + + if (funcall1(iter_more_meth, iter)) { + val iter_item_meth = get_special_required_slot(iter, iter_item_m); + it->ul.next = *pval = funcall1(iter_item_meth, iter); + } + + return 1; + } + + return 0; +} + +static int seq_iter_get_fast_oop(seq_iter_t *it, val *pval) +{ + val iter = it->ui.iter; + + if (iter) { + val item = it->ul.next; + val iter_step_meth = get_special_required_slot(iter, iter_step_m); + + if (item == nao) { + val iter_item_meth = get_special_required_slot(iter, iter_item_m); + *pval = funcall1(iter_item_meth, iter); + } else { + *pval = item; + } + + it->ui.iter = funcall1(iter_step_meth, iter); + it->ul.next = nao; + return 1; + } + + return 0; +} + +static int seq_iter_peek_fast_oop(seq_iter_t *it, val *pval) +{ + val iter = it->ui.iter; + + if (it->ul.next != nao) { + *pval = it->ul.next; + return 1; + } + + if (iter) { + val iter_item_meth = get_special_required_slot(iter, iter_item_m); + it->ul.next = *pval = funcall1(iter_item_meth, iter); + return 1; + } + + return 0; +} + val seq_geti(seq_iter_t *it) { val v = nil; @@ -703,6 +795,35 @@ static void seq_iter_init_with_info(val self, seq_iter_t *it, it->get = seq_iter_get_num; it->peek = seq_iter_peek_num; break; + case COBJ: + if (obj_struct_p(it->inf.obj)) { + val iter_begin_meth = get_special_slot(it->inf.obj, iter_begin_m); + if (iter_begin_meth) { + val iter = funcall1(iter_begin_meth, it->inf.obj); + if (iter == nil) { + it->ui.iter = nil; + it->ul.len = 0; + it->get = seq_iter_get_nil; + it->peek = seq_iter_peek_nil; + break; + } else { + val iter_more_meth = get_special_slot(iter, iter_more_m); + if (iter_more_meth) { + it->ui.iter = iter; + it->ul.next = nao; + it->get = seq_iter_get_oop; + it->peek = seq_iter_peek_oop; + } else { + it->ui.iter = iter; + it->ul.next = nao; + it->get = seq_iter_get_fast_oop; + it->peek = seq_iter_peek_fast_oop; + } + break; + } + } + } + /* fallthrough */ default: switch (it->inf.kind) { case SEQ_NIL: @@ -787,6 +908,8 @@ static void seq_iter_mark(val seq_iter) gc_mark(si->ui.iter); break; default: + if (cobjp(seq_iter) && obj_struct_p(seq_iter)) + gc_mark(si->ui.iter); break; } } @@ -830,16 +953,23 @@ val iter_begin(val obj) val self = lit("iter-begin"); seq_info_t sinf = seq_info(obj); - switch (sinf.kind) { - case SEQ_NIL: - case SEQ_LISTLIKE: - return sinf.obj; + switch (sinf.type) { + case CHR: + case NUM: + case BGNUM: + return obj; + case COBJ: + if (obj_struct_p(obj)) { + val iter_begin_meth = get_special_slot(obj, iter_begin_m); + if (iter_begin_meth) + return funcall1(iter_begin_meth, obj); + } + /* fallthrough */ default: - switch (sinf.type) { - case CHR: - case NUM: - case BGNUM: - return obj; + switch (sinf.kind) { + case SEQ_NIL: + case SEQ_LISTLIKE: + return sinf.obj; default: { val si_obj; @@ -870,6 +1000,11 @@ val iter_more(val iter) val item = nil; return if2(seq_peek(si, &item), t); } + if (obj_struct_p(iter)) { + val iter_more_meth = get_special_slot(iter, iter_more_m); + if (iter_more_meth) + return funcall1(iter_more_meth, iter); + } /* fallthrough */ default: return t; @@ -915,6 +1050,11 @@ val iter_step(val iter) (void) seq_get(si, &item); return iter; } + if (obj_struct_p(iter)) { + val iter_step_meth = get_special_slot(iter, iter_step_m); + if (iter_step_meth) + return funcall1(iter_step_meth, iter); + } /* fallthrough */ default: return cdr(iter); @@ -926,24 +1066,29 @@ val iter_reset(val iter, val obj) val self = lit("iter-reset"); seq_info_t sinf = seq_info(obj); - switch (sinf.kind) { - case SEQ_NIL: - case SEQ_LISTLIKE: - return sinf.obj; + switch (type(iter)) { + case CHR: + case NUM: + case BGNUM: + return obj; + case COBJ: + if (iter->co.cls == seq_iter_s) + { + struct seq_iter *si = coerce(struct seq_iter *, iter->co.handle); + seq_iter_init_with_info(self, si, sinf, 0); + return iter; + } + /* fallthrough */ default: - switch (type(iter)) { - case CHR: - case NUM: - case BGNUM: - return obj; - case COBJ: - if (iter->co.cls == seq_iter_s) - { - struct seq_iter *si = coerce(struct seq_iter *, iter->co.handle); - seq_iter_init_with_info(self, si, sinf, 0); - return iter; - } - /* fallthrough */ + if (cobjp(obj) && obj_struct_p(obj)) { + val iter_reset_meth = get_special_slot(obj, iter_reset_m); + if (iter_reset_meth) + return funcall2(iter_reset_meth, obj, iter); + } + switch (sinf.kind) { + case SEQ_NIL: + case SEQ_LISTLIKE: + return sinf.obj; default: return iter_begin(obj); } |