summaryrefslogtreecommitdiffstats
path: root/lib.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2020-05-24 22:05:09 -0700
committerKaz Kylheku <kaz@kylheku.com>2020-05-24 22:05:09 -0700
commit5c7a7732e8938b5d127b677f0d42d3a774103112 (patch)
treeb5d1aeac179df52e717a1fac483637ec601b1116 /lib.c
parent19e36297b54f684becbebe54637c5a0c9bd18cd7 (diff)
downloadtxr-5c7a7732e8938b5d127b677f0d42d3a774103112.tar.gz
txr-5c7a7732e8938b5d127b677f0d42d3a774103112.tar.bz2
txr-5c7a7732e8938b5d127b677f0d42d3a774103112.zip
lib: combine cat_str and vscat implementations.
The vscat function is white-box copy of cat_str, with just the iteration over the inputs done differently, and without the support for separators that are characters instead of strings (which was added to cat_str after vscat was forked. In this patch, the common logic underlying both functions is factored out into a small ad-hoc "struct cat_str" object which maintains the state and provides the operations to measure the pieces of the string, allocate the space, copy the pieces together and produce the resulting object. The motivation here isn't just to reduce duplication. I would like a more efficient function for catenating strings which takes a "struct args *", not requiring a list to be consed up. * lib.c (struct cat_str): New struct type. (cat_str_init, cat_str_measure, cat_str_alloc, cat_str_append, cat_str_get): New static functions. (cat_str, vscat): Considerably shorten by using the above functions.
Diffstat (limited to 'lib.c')
-rw-r--r--lib.c196
1 files changed, 91 insertions, 105 deletions
diff --git a/lib.c b/lib.c
index 99720212..65bee46b 100644
--- a/lib.c
+++ b/lib.c
@@ -4049,152 +4049,138 @@ val replace_str(val str_in, val items, val from, val to)
return str_in;
}
-val cat_str(val list, val sep)
-{
- size_t total = 1;
- val iter;
- wchar_t *str, *ptr;
- wchar_t onech[] = wini(" ");
+struct cat_str {
+ val sep;
cnum len_sep;
+ size_t total;
+ wchar_t *str, *ptr;
+};
+
+static void cat_str_init(struct cat_str *cs, val sep, wchar_t *onech)
+{
+ cs->sep = sep;
+ cs->total = 1;
+ cs->str = cs->ptr = 0;
if (null_or_missing_p(sep)) {
- len_sep = 0;
+ cs->len_sep = 0;
} else if (chrp(sep)) {
onech[0] = c_chr(sep);
- len_sep = 1;
- sep = auto_str(coerce(const wchli_t *, wref(onech)));
+ cs->len_sep = 1;
+ cs->sep = auto_str(coerce(const wchli_t *, wref(onech)));
} else {
- len_sep = c_num(length_str(sep));
+ cs->len_sep = c_num(length_str(cs->sep));
}
+}
- for (iter = list; iter != nil; iter = cdr(iter)) {
- val item = car(iter);
- if (!item)
- continue;
- if (stringp(item)) {
- size_t ntotal = total + c_num(length_str(item));
-
- if (len_sep && cdr(iter))
- ntotal += len_sep;
-
- if (ntotal < total)
- goto oflow;
-
- total = ntotal;
-
- continue;
- }
- if (chrp(item)) {
- size_t ntotal = total + 1;
+static void cat_str_measure(struct cat_str *cs, val item, val more_p)
+{
+ if (!item)
+ return;
- if (len_sep && cdr(iter))
- ntotal += len_sep;
+ if (stringp(item)) {
+ size_t ntotal = cs->total + c_num(length_str(item));
- if (ntotal < total)
- goto oflow;
+ if (cs->len_sep && more_p)
+ ntotal += cs->len_sep;
- total = ntotal;
+ if (ntotal < cs->total)
+ goto oflow;
- continue;
- }
- uw_throwf(error_s, lit("cat-str: ~s is not a character or string"),
- item, nao);
+ cs->total = ntotal;
+ return;
}
- str = chk_wmalloc(total);
+ if (chrp(item)) {
+ size_t ntotal = cs->total + 1;
- for (ptr = str, iter = list; iter != nil; iter = cdr(iter)) {
- val item = car(iter);
+ if (cs->len_sep && more_p)
+ ntotal += cs->len_sep;
- if (!item)
- continue;
- if (stringp(item)) {
- cnum len = c_num(length_str(item));
- wmemcpy(ptr, c_str(item), len);
- ptr += len;
- } else {
- *ptr++ = c_chr(item);
- }
+ if (ntotal < cs->total)
+ goto oflow;
- if (len_sep && cdr(iter)) {
- wmemcpy(ptr, c_str(sep), len_sep);
- ptr += len_sep;
- }
+ cs->total = ntotal;
+ return;
}
- *ptr = 0;
-
- return string_own(str);
+ uw_throwf(error_s, lit("cat-str: ~s is not a character or string"),
+ item, nao);
oflow:
uw_throwf(error_s, lit("cat-str: string length overflow"), nao);
}
-static val vscat(val sep, va_list vl1, va_list vl2)
+static void cat_str_alloc(struct cat_str *cs)
{
- size_t total = 1;
- val item, next;
- wchar_t *str, *ptr;
- cnum len_sep = (!null_or_missing_p(sep)) ? c_num(length_str(sep)) : 0;
+ cs->ptr = cs->str = chk_wmalloc(cs->total);
+}
- for (item = va_arg(vl1, val); item != nao; item = next)
- {
- next = va_arg(vl1, val);
+static void cat_str_append(struct cat_str *cs, val item, val more_p)
+{
+ if (!item)
+ return;
+ if (stringp(item)) {
+ cnum len = c_num(length_str(item));
+ wmemcpy(cs->ptr, c_str(item), len);
+ cs->ptr += len;
+ } else {
+ *cs->ptr++ = c_chr(item);
+ }
- if (stringp(item)) {
- size_t ntotal = total + c_num(length_str(item));
+ if (cs->len_sep && more_p) {
+ wmemcpy(cs->ptr, c_str(cs->sep), cs->len_sep);
+ cs->ptr += cs->len_sep;
+ }
+}
- if (len_sep && next != nao)
- ntotal += len_sep;
+static val cat_str_get(struct cat_str *cs)
+{
+ *cs->ptr = 0;
+ return string_own(cs->str);
+}
- if (ntotal < total)
- goto oflow;
+val cat_str(val list, val sep)
+{
+ val iter;
+ struct cat_str cs;
+ wchar_t onech[] = wini(" ");
- total = ntotal;
+ cat_str_init(&cs, sep, onech);
- continue;
- }
- if (chrp(item)) {
- size_t ntotal = total + 1;
+ for (iter = list; iter != nil; iter = cdr(iter))
+ cat_str_measure(&cs, car(iter), cdr(iter));
- if (len_sep && next != nao)
- ntotal += len_sep;
+ cat_str_alloc(&cs);
- if (ntotal < total)
- goto oflow;
+ for (iter = list; iter != nil; iter = cdr(iter))
+ cat_str_append(&cs, car(iter), cdr(iter));
- total = ntotal;
+ return cat_str_get(&cs);
+}
- continue;
- }
- uw_throwf(error_s, lit("scat: ~s is not a character or string"),
- item, nao);
- }
+static val vscat(val sep, va_list vl1, va_list vl2)
+{
+ val item, next;
+ struct cat_str cs;
+ wchar_t onech[] = wini(" ");
- str = chk_wmalloc(total);
+ cat_str_init(&cs, sep, onech);
- for (ptr = str, item = va_arg(vl2, val); item != nao; item = next)
+ for (item = va_arg(vl1, val); item != nao; item = next)
{
- next = va_arg(vl2, val);
+ next = va_arg(vl1, val);
+ cat_str_measure(&cs, item, tnil(next != nao));
+ }
- if (stringp(item)) {
- cnum len = c_num(length_str(item));
- wmemcpy(ptr, c_str(item), len);
- ptr += len;
- } else {
- *ptr++ = c_chr(item);
- }
+ cat_str_alloc(&cs);
- if (len_sep && next != nao) {
- wmemcpy(ptr, c_str(sep), len_sep);
- ptr += len_sep;
- }
+ for (item = va_arg(vl2, val); item != nao; item = next)
+ {
+ next = va_arg(vl2, val);
+ cat_str_append(&cs, item, tnil(next != nao));
}
- *ptr = 0;
- return string_own(str);
-
-oflow:
- uw_throwf(error_s, lit("scat: string length overflow"), nao);
+ return cat_str_get(&cs);
}
val scat(val sep, ...)