summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-08-17 21:53:10 -0700
committerKaz Kylheku <kaz@kylheku.com>2017-08-17 21:53:10 -0700
commit25a3e10e7aed58c8745fdadc87b3b26e8b51523e (patch)
tree1cbe9b70c318f8406c4dbe92c4213218f24487a0
parent49fa1df6a448459279cfcaa98f26f9d0d584a8ff (diff)
downloadtxr-25a3e10e7aed58c8745fdadc87b3b26e8b51523e.tar.gz
txr-25a3e10e7aed58c8745fdadc87b3b26e8b51523e.tar.bz2
txr-25a3e10e7aed58c8745fdadc87b3b26e8b51523e.zip
Rewriting string-extend.
* lib.c (string_extend): Restructure internals with these goals: no loop: calculate needed space in one step; if the allocation needs to grow, then grow it by 25% or step it up to exactly the needed size, whichever of the two is larger. Overflow check against INT_PTR_MAX, since len and alloc fields of string are not fixnums but integers extracted with c_num.
-rw-r--r--lib.c51
1 files changed, 25 insertions, 26 deletions
diff --git a/lib.c b/lib.c
index b9fb4210..f76c08bd 100644
--- a/lib.c
+++ b/lib.c
@@ -3522,45 +3522,44 @@ val string_extend(val str, val tail)
{
type_check(str, STR);
{
+ val self = lit("string-extend");
cnum len = c_num(length_str(str));
cnum oalloc = c_num(str->st.alloc), alloc = oalloc;
- val needed;
- val room = zero;
+ cnum delta, needed;
if (stringp(tail))
- needed = length_str(tail);
+ delta = c_num(length_str(tail));
else if (chrp(tail))
- needed = one;
- else if (fixnump(tail))
- needed = tail;
+ delta = 1;
+ else if (integerp(tail))
+ delta = c_num(tail);
else
- uw_throwf(error_s, lit("string-extend: tail ~s bad type"), str, nao);
+ uw_throwf(error_s, lit("~s: tail ~s bad type"), self, str, nao);
- room = num(alloc - len - 1);
+ if (INT_PTR_MAX - delta - 1 < len)
+ uw_throwf(error_s, lit("~s: overflow"), self, nao);
- while (gt(needed, room) && alloc < NUM_MAX) {
- if (alloc > NUM_MAX / 2) {
- alloc = NUM_MAX;
- } else {
- alloc *= 2;
- }
- room = num(alloc - len - 1);
- }
+ needed = len + delta + 1;
- if (gt(needed, room))
- uw_throw(error_s, lit("string-extend: overflow"));
-
- if (alloc != oalloc) {
- str->st.str = coerce(wchar_t *, chk_grow_vec(coerce(mem_t *, str->st.str),
- oalloc, alloc,
- sizeof *str->st.str));
- set(mkloc(str->st.alloc, str), num(alloc));
+ if (needed > alloc) {
+ if (alloc >= (INT_PTR_MAX - INT_PTR_MAX / 5))
+ alloc = INT_PTR_MAX;
+ else
+ alloc = max(alloc + alloc / 4, needed);
+
+ if (alloc != oalloc) {
+ str->st.str = coerce(wchar_t *,
+ chk_grow_vec(coerce(mem_t *, str->st.str),
+ oalloc, alloc,
+ sizeof *str->st.str));
+ set(mkloc(str->st.alloc, str), num_fast(alloc));
+ }
}
- set(mkloc(str->st.len, str), plus(str->st.len, needed));
+ set(mkloc(str->st.len, str), num_fast(len + delta));
if (stringp(tail)) {
- wmemcpy(str->st.str + len, c_str(tail), c_num(needed) + 1);
+ wmemcpy(str->st.str + len, c_str(tail), delta + 1);
} else if (chrp(tail)) {
str->st.str[len] = c_chr(tail);
str->st.str[len + 1] = 0;