diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2024-06-20 00:09:25 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2024-06-20 00:09:25 -0700 |
commit | 6bd0f5494990a18352de716987460914858d2f82 (patch) | |
tree | 8e36724451ab2f6199e387cdfc0daaba75a14b13 | |
parent | 635aa6b2b6395a1f7c20cd4182f7be261f98b36e (diff) | |
download | txr-6bd0f5494990a18352de716987460914858d2f82.tar.gz txr-6bd0f5494990a18352de716987460914858d2f82.tar.bz2 txr-6bd0f5494990a18352de716987460914858d2f82.zip |
length: support string ranges.
For calculating the length of a range, we can't just do
numeric subtractions because it fails for string ranges.
* lib.c (length_str_range, length_rng): New static functions.
(length): Use length_rng for ranges.
-rw-r--r-- | lib.c | 40 |
1 files changed, 39 insertions, 1 deletions
@@ -553,6 +553,29 @@ static int seq_iter_peek_range_number(seq_iter_t *it, val *pval) return 0; } +static val length_str_range(val from, val to) +{ + val self = lit("length"); + + if (eql(length_str(from), length_str(to))) { + const wchar_t *fs = c_str(from, self); + const wchar_t *ts = c_str(to, self); + val out = one; + cnum i; + + for (i = 0; fs[i]; i++) + out = mul(out, num(labs(ts[i] - fs[i]) + 1)); + + gc_hint(from); + gc_hint(to); + + return out; + } else { + uw_throwf(type_error_s, lit("~a: ~s..~s are of unequal length"), + self, from, to, nao); + } +} + static int seq_iter_get_range_str(seq_iter_t *it, val *pval) { if (it->ui.vn) { @@ -13348,6 +13371,21 @@ val copy(val seq) } } +static val length_rng(val rng) +{ + val fv = from(rng); + val tv = to(rng); + + if (stringp(fv)) { + if (!stringp(tv)) + type_mismatch(lit("length: both fields of ~s must be strings"), + rng, nao); + return length_str_range(fv, tv); + } + + return minus(to(rng), from(rng)); +} + val length(val seq) { switch (type(seq)) { @@ -13363,7 +13401,7 @@ val length(val seq) case VEC: return length_vec(seq); case RNG: - return minus(to(seq), from(seq)); + return length_rng(seq); case BUF: return length_buf(seq); case COBJ: |