diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2019-06-14 07:21:56 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2019-06-14 07:21:56 -0700 |
commit | dc0f9b2d38c58f7058d44e07ae04fde94356473b (patch) | |
tree | a22f7696eebfb7a94552792c334f729064ac0036 | |
parent | fdbd49a83ce4a567824c2830e202735d59b55a84 (diff) | |
download | txr-dc0f9b2d38c58f7058d44e07ae04fde94356473b.tar.gz txr-dc0f9b2d38c58f7058d44e07ae04fde94356473b.tar.bz2 txr-dc0f9b2d38c58f7058d44e07ae04fde94356473b.zip |
select: maintenance.
* lib.c (sel): Function converted to seq_info and iterators.
Negative indices handled in list case. Self-name corrected
to select; the C function is called sel just to avoid
clashing with POSIX select.
* txr.1: Documentation updated.
-rw-r--r-- | lib.c | 72 | ||||
-rw-r--r-- | txr.1 | 25 |
2 files changed, 56 insertions, 41 deletions
@@ -10479,66 +10479,72 @@ val where(val func, val seq) } } -val sel(val seq_in, val where_in) +val sel(val seq, val where_in) { - val self = lit("sel"); + val self = lit("select"); list_collect_decl (out, ptail); - val seq = nullify(seq_in); val where = if3(functionp(where_in), funcall1(where_in, seq), - nullify(where_in)); + where_in); + seq_info_t si = seq_info(seq); + seq_iter_t wh_iter; + val wh; - switch (type(seq)) { - case NIL: + seq_iter_init(self, &wh_iter, where); + + switch (si.kind) { + case SEQ_NIL: return nil; - case COBJ: - if (hashp(seq)) + case SEQ_HASHLIKE: { - val newhash = make_similar_hash(seq); - - for (; where; where = cdr(where)) { - val key = car(where); - val found = gethash_e(self, seq, key); + val newhash = make_similar_hash(si.obj); + while (seq_get(&wh_iter, &wh)) { + val found = gethash_e(self, seq, wh); if (found) - sethash(newhash, key, cdr(found)); + sethash(newhash, wh, cdr(found)); } return newhash; } - if (seq->co.cls == carray_s) - goto carray; - /* fallthrough */ - case CONS: - case LCONS: + case SEQ_LISTLIKE: { val idx = zero; + val iter = si.obj; + val len = nil; + + while (iter && seq_peek(&wh_iter, &wh)) { + if (minusp(wh)) + wh = plus(wh, len ? len : (len = length(seq))); + if (lt(wh, idx)) { + seq_geti(&wh_iter); + continue; + } else if (eql(wh, idx)) { + ptail = list_collect(ptail, car(iter)); + seq_geti(&wh_iter); + } - for (; seq && where; seq = cdr(seq), idx = plus(idx, one)) { - val wh = nil; - - for (; where && lt(wh = car(where), idx); where = cdr(where)) - ; /* empty */ - - if (eql(wh, idx)) - ptail = list_collect (ptail, car(seq)); + iter = cdr(iter); + idx = plus(idx, one); } } break; - carray: - default: + case SEQ_VECLIKE: { val len = length(seq); - for (; where; where = cdr(where)) { - val wh = car(where); + + while (seq_get(&wh_iter, &wh)) { if (ge(wh, len)) break; - ptail = list_collect (ptail, ref(seq, car(where))); + ptail = list_collect(ptail, ref(si.obj, wh)); } } break; + case SEQ_NOTSEQ: + type_mismatch(lit("~a: ~s is not a sequence"), self, seq, nao); } - return make_like(out, seq_in); + + return make_like(out, seq); } static val do_relate(val env, val arg) @@ -28469,14 +28469,16 @@ If is a sequence, then .meta index-list consists of numeric -indices. The -.code select -function stops processing -.meta object -upon encountering an -index inside +indices. The length of the sequence, as reported by the +.code length +function, is added to every .meta index-list -which is out of range. (Rationale: without +value which is negative. +The +.code select +function stops collecting values upon encountering an index value which is +greater than or equal to the length of the sequence. +(Rationale: without this strict behavior, .code select would not be able to terminate if @@ -28485,7 +28487,7 @@ is infinite.) If .meta object -is a list, then +is, more specifically, a list-like sequence, then .meta index-list must contain monotonically increasing numeric values, even if no value is out of range, since the @@ -28493,6 +28495,12 @@ numeric values, even if no value is out of range, since the function makes a single pass through the list based on the assumption that indices are ordered. (Rationale: optimization.) +This requirement for monotonicity applies to the values which +result after negative indices are displaced by the sequence length +Also, in this list-like sequence case, values taken from +.meta index-list +which are still negative after being displaced by the sequence length are +ignored. If .meta object @@ -28509,6 +28517,7 @@ All of is processed, even if it contains keys which are not in .metn object . +The nonexistent keys are ignored. The .code select |