diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2019-06-12 23:28:52 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2019-06-12 23:28:52 -0700 |
commit | 8f72f80a49eeefc27d6790acec0d706d3852ed04 (patch) | |
tree | 2861e41915d34f08f435c53ca126191bb26d7862 | |
parent | 07f19fe31673b1d04fd6d8a2b44adac9355f7efe (diff) | |
download | txr-8f72f80a49eeefc27d6790acec0d706d3852ed04.tar.gz txr-8f72f80a49eeefc27d6790acec0d706d3852ed04.tar.bz2 txr-8f72f80a49eeefc27d6790acec0d706d3852ed04.zip |
buffers: replace operation.
* buf.c (replace_buf): New function.
* buf.h (replace_buf): Declared.
* lib.c (replace): Wire in.
-rw-r--r-- | buf.c | 89 | ||||
-rw-r--r-- | buf.h | 1 | ||||
-rw-r--r-- | lib.c | 2 |
3 files changed, 91 insertions, 1 deletions
@@ -271,6 +271,95 @@ val sub_buf(val buf, val from, val to) } } +val replace_buf(val buf, val items, val from, val to) +{ + val self = lit("replace"); + val len = length_buf(buf); + + if (missingp(from)) { + from = zero; + } else if (from == t) { + from = len; + } else if (!integerp(from)) { + seq_iter_t wh_iter, item_iter; + val wh, item; + seq_iter_init(self, &wh_iter, from); + seq_iter_init(self, &item_iter, items); + + if (!missingp(to)) + uw_throwf(error_s, + lit("~a: to-arg not applicable when from-arg is a list"), + self, nao); + + while (seq_get(&wh_iter, &wh) && seq_get(&item_iter, &item)) { + if (ge(wh, len)) + break; + buf_put_uchar(buf, wh, item); + } + + return buf; + } else if (lt(from, zero)) { + from = plus(from, len); + if (to == zero) + to = len; + } + + if (null_or_missing_p(to) || to == t) + to = len; + else if (lt(to, zero)) + to = plus(to, len); + + from = max2(zero, min2(from, len)); + to = max2(zero, min2(to, len)); + + { + val len_rep = minus(to, from); + val len_it = length(items); + + if (gt(len_rep, len_it)) { + val len_diff = minus(len_rep, len_it); + cnum t = c_num(to); + cnum l = c_num(len); + + memmove(buf->b.data + t - c_num(len_diff), + buf->b.data + t, + l - t); + + buf_set_length(buf, minus(len, len_diff), zero); + to = plus(from, len_it); + } else if (lt(len_rep, len_it)) { + val len_diff = minus(len_it, len_rep); + cnum t = c_num(to); + cnum l = c_num(len); + + buf_set_length(buf, plus(len, len_diff), zero); + + memmove(buf->b.data + t + c_num(len_diff), + buf->b.data + t, + l - t); + to = plus(from, len_it); + } + + if (zerop(len_it)) + return buf; + if (bufp(items)) { + memcpy(buf->b.data + c_num(from), items->b.data, c_num(len_it)); + } else { + seq_iter_t item_iter; + seq_iter_init(self, &item_iter, items); + cnum f = c_num(from); + cnum t = c_num(to); + + for (; f != t; f++) { + val item = seq_geti(&item_iter); + buf_put_uchar(buf, num(f), item); + } + } + } + + return buf; +} + static void buf_put_bytes(val buf, val pos, mem_t *ptr, cnum size, val self) { struct buf *b = buf_handle(buf, self); @@ -38,6 +38,7 @@ val buf_alloc_size(val buf); mem_t *buf_get(val buf, val self); void buf_fill(val buf, mem_t *src, val self); val sub_buf(val seq, val from, val to); +val replace_buf(val buf, val items, val from, val to); #if HAVE_I8 val buf_put_i8(val buf, val pos, val num); @@ -10089,7 +10089,7 @@ val replace(val seq, val items, val from, val to) return replace_obj(seq, items, from, to); /* fallthrough */ case BUF: - type_mismatch(lit("~a: operation doesn't support buf type"), self, nao); + return replace_buf(seq, items, from, to); default: type_mismatch(lit("~a: ~s is not a sequence"), self, seq, nao); } |