diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2017-08-17 21:53:10 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2017-08-17 21:53:10 -0700 |
commit | 25a3e10e7aed58c8745fdadc87b3b26e8b51523e (patch) | |
tree | 1cbe9b70c318f8406c4dbe92c4213218f24487a0 | |
parent | 49fa1df6a448459279cfcaa98f26f9d0d584a8ff (diff) | |
download | txr-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.c | 51 |
1 files changed, 25 insertions, 26 deletions
@@ -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; |