aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2016-09-14 18:10:28 +0900
committerKazuki Yamaguchi <k@rhe.jp>2016-09-14 18:10:28 +0900
commit586664517e7eb93c7c794e21787baddef3f3cb2e (patch)
treea6b6ce1996ba78803a64751ac87782ee9e7b0564
parentefcd67c5f7b63c25825b8f3c8090db3e0fe9f05f (diff)
downloadruby-wip-topic/2-power-string-length.tar.gz
-rw-r--r--string.c143
1 files changed, 76 insertions, 67 deletions
diff --git a/string.c b/string.c
index 98364a8278..668199e095 100644
--- a/string.c
+++ b/string.c
@@ -1893,35 +1893,74 @@ str_independent(VALUE str)
return !str_dependent_p(str);
}
+static inline size_t
+aligned_newsize(long len, int termlen)
+{
+ size_t total = 128;
+
+ if (len >= LONG_MAX / 2 - termlen) {
+ if (LONG_MAX - len - termlen >= 4095)
+ return ((size_t)len + termlen + 4095) / 4096 * 4096;
+ return (size_t)len + termlen;
+ }
+
+ while (total < (size_t)len + termlen)
+ total *= 2;
+
+ return total;
+}
+
static void
str_make_independent_expand(VALUE str, long len, long expand, const int termlen)
{
- char *ptr;
- const char *oldptr;
- long capa = len + expand;
+ long newlen;
+ size_t total;
+ int independent = !str_dependent_p(str);
+ char *ptr, *oldptr;
- if (len > capa) len = capa;
+ newlen = len + expand;
+ if (expand < 0) {
+ /* avoid out-of-bound access */
+ len = newlen;
+ }
- if (!STR_EMBED_P(str) && STR_EMBEDDABLE_P(capa, termlen)) {
- ptr = RSTRING(str)->as.heap.ptr;
- STR_SET_EMBED(str);
- memcpy(RSTRING(str)->as.ary, ptr, len);
- TERM_FILL(RSTRING(str)->as.ary + len, termlen);
- STR_SET_EMBED_LEN(str, len);
+ if (STR_EMBEDDABLE_P(newlen, termlen)) {
+ if (!STR_EMBED_P(str)) {
+ oldptr = RSTRING_PTR(str);
+ STR_SET_EMBED(str);
+ if (len) memcpy(RSTRING(str)->as.ary, oldptr, len);
+ if (independent) ruby_xfree(oldptr);
+ }
+ TERM_FILL(RSTRING(str)->as.ary + newlen, termlen);
+ STR_SET_EMBED_LEN(str, newlen);
return;
}
- ptr = ALLOC_N(char, (size_t)capa + termlen);
- oldptr = RSTRING_PTR(str);
- if (oldptr) {
- memcpy(ptr, oldptr, len);
+ total = aligned_newsize(newlen, termlen);
+ if (independent && !STR_EMBED_P(str)) {
+ REALLOC_N(RSTRING(str)->as.heap.ptr, char, total);
+ }
+ else {
+ oldptr = RSTRING_PTR(str);
+ ptr = ALLOC_N(char, total);
+ if (len) memcpy(ptr, oldptr, len);
+ STR_SET_NOEMBED(str);
+ FL_UNSET(str, STR_SHARED|STR_NOFREE);
+ RSTRING(str)->as.heap.ptr = ptr;
+ }
+ RSTRING(str)->as.heap.len = newlen;
+ RSTRING(str)->as.heap.aux.capa = (long)(total - termlen);
+ TERM_FILL(RSTRING(str)->as.heap.ptr + newlen, termlen);
+}
+
+static inline void
+str_expand_if_necessary(VALUE str, long expand, int termlen)
+{
+ long len = RSTRING_LEN(str);
+
+ if (str_capacity(str, termlen) < (size_t)len + expand) {
+ str_make_independent_expand(str, len, expand, termlen);
}
- STR_SET_NOEMBED(str);
- FL_UNSET(str, STR_SHARED|STR_NOFREE);
- TERM_FILL(ptr + len, termlen);
- RSTRING(str)->as.heap.ptr = ptr;
- RSTRING(str)->as.heap.len = len;
- RSTRING(str)->as.heap.aux.capa = capa;
}
void
@@ -1945,12 +1984,9 @@ rb_str_modify_expand(VALUE str, long expand)
rb_raise(rb_eArgError, "string size too big");
}
- if (!str_independent(str)) {
+ if (!str_independent(str) || expand > 0) {
str_make_independent_expand(str, len, expand, termlen);
}
- else if (expand > 0) {
- RESIZE_CAPA_TERM(str, len + expand, termlen);
- }
ENC_CODERANGE_CLEAR(str);
}
@@ -2026,17 +2062,11 @@ str_null_char(const char *s, long len, const int minlen, rb_encoding *enc)
static char *
str_fill_term(VALUE str, char *s, long len, int termlen)
{
- long capa = str_capacity(str, termlen);
-
/* This function assumes that (capa + termlen) bytes of memory
- * is allocated, like many other functions in this file.
+ * is allocated, like all other functions in this file.
*/
- if (capa < len) {
- rb_check_lockedtmp(str);
- str_make_independent_expand(str, len, 0L, termlen);
- }
- else if (str_dependent_p(str)) {
+ if (str_dependent_p(str)) {
if (!zero_filled(s + len, termlen))
str_make_independent_expand(str, len, 0L, termlen);
}
@@ -2510,51 +2540,30 @@ VALUE
rb_str_resize(VALUE str, long len)
{
long slen;
- int independent;
+ int termlen;
if (len < 0) {
rb_raise(rb_eArgError, "negative string size (or size too big)");
}
- independent = str_independent(str);
+ str_modifiable(str);
ENC_CODERANGE_CLEAR(str);
slen = RSTRING_LEN(str);
+ termlen = TERM_LEN(str);
- {
- long capa;
- const int termlen = TERM_LEN(str);
+ if (str_dependent_p(str) || str_capacity(str, termlen) < (size_t)len) {
+ str_make_independent_expand(str, slen, len - slen, termlen);
+ }
+ else if (len != slen) {
if (STR_EMBED_P(str)) {
- if (len == slen) return str;
- if (STR_EMBEDDABLE_P(len, termlen)) {
- STR_SET_EMBED_LEN(str, len);
- TERM_FILL(RSTRING(str)->as.ary + len, termlen);
- return str;
- }
- str_make_independent_expand(str, slen, len - slen, termlen);
- }
- else if (STR_EMBEDDABLE_P(len, termlen)) {
- char *ptr = STR_HEAP_PTR(str);
- STR_SET_EMBED(str);
- if (slen > len) slen = len;
- if (slen > 0) MEMCPY(RSTRING(str)->as.ary, ptr, char, slen);
- TERM_FILL(RSTRING(str)->as.ary + len, termlen);
STR_SET_EMBED_LEN(str, len);
- if (independent) ruby_xfree(ptr);
- return str;
}
- else if (!independent) {
- if (len == slen) return str;
- str_make_independent_expand(str, slen, len - slen, termlen);
- }
- else if ((capa = RSTRING(str)->as.heap.aux.capa) < len ||
- (capa - len) > (len < 1024 ? len : 1024)) {
- REALLOC_N(RSTRING(str)->as.heap.ptr, char, (size_t)len + termlen);
- RSTRING(str)->as.heap.aux.capa = len;
+ else {
+ STR_SET_LEN(str, len);
}
- else if (len == slen) return str;
- RSTRING(str)->as.heap.len = len;
- TERM_FILL(RSTRING(str)->as.heap.ptr + len, termlen); /* sentinel */
+ TERM_FILL(RSTRING_PTR(str) + len, termlen);
}
+
return str;
}
@@ -3858,7 +3867,7 @@ str_succ(VALUE str)
carry_pos = s - sbeg;
}
}
- RESIZE_CAPA(str, slen + carry_len);
+ str_expand_if_necessary(str, carry_len, TERM_LEN(str));
sbeg = RSTRING_PTR(str);
s = sbeg + carry_pos;
memmove(s + carry_len, s, slen - carry_pos);
@@ -4259,7 +4268,7 @@ rb_str_splice_0(VALUE str, long beg, long len, VALUE val)
RSTRING_GETMEM(str, sptr, slen);
if (len < vlen) {
/* expand string */
- RESIZE_CAPA(str, slen + vlen - len);
+ str_expand_if_necessary(str, vlen - len, TERM_LEN(str));
sptr = RSTRING_PTR(str);
}
@@ -4699,7 +4708,7 @@ rb_str_sub_bang(int argc, VALUE *argv, VALUE str)
rp = RSTRING_PTR(repl); rlen = RSTRING_LEN(repl);
len = RSTRING_LEN(str);
if (rlen > plen) {
- RESIZE_CAPA(str, len + rlen - plen);
+ str_expand_if_necessary(str, rlen - plen, TERM_LEN(str));
}
p = RSTRING_PTR(str);
if (rlen != plen) {