summaryrefslogtreecommitdiff
path: root/string.c
diff options
context:
space:
mode:
authorngoto <ngoto@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-07-05 10:45:23 +0000
committerngoto <ngoto@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-07-05 10:45:23 +0000
commit5eff15d1bdda4efcdd8aa59c91c804e345394a1c (patch)
treefa26cd007193abab898ffcd4cf16a9559705ebaf /string.c
parenta3ca2c7cd54e63cfac3f8d4e401da71407b5fc83 (diff)
* string.c (rb_str_change_terminator_length): New function to change
termlen and resize heap for the terminator. This is split from rb_str_fill_terminator (str_fill_term) because filling terminator and changing terminator length are different things. [Bug #12536] * internal.h: declaration for rb_str_change_terminator_length. * string.c (str_fill_term): Simplify only to zero-fill the terminator. For non-shared strings, it assumes that (capa + termlen) bytes of heap is allocated. This partially reverts r55557. * encoding.c (rb_enc_associate_index): rb_str_change_terminator_length is used, and it should be called whenever the termlen is changed. * string.c (str_capacity): New static function to return capacity of a string with the given termlen, because the termlen may sometimes be different from TERM_LEN(str) especially during changing termlen or filling terminator with specific termlen. * string.c (rb_str_capacity): Use str_capacity. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55575 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'string.c')
-rw-r--r--string.c67
1 files changed, 43 insertions, 24 deletions
diff --git a/string.c b/string.c
index dfdd3d1f4d..ff3792ffb2 100644
--- a/string.c
+++ b/string.c
@@ -646,11 +646,11 @@ str_mod_check(VALUE s, const char *p, long len)
}
}
-size_t
-rb_str_capacity(VALUE str)
+static size_t
+str_capacity(VALUE str, const int termlen)
{
if (STR_EMBED_P(str)) {
- return (RSTRING_EMBED_LEN_MAX + 1 - TERM_LEN(str));
+ return (RSTRING_EMBED_LEN_MAX + 1 - termlen);
}
else if (FL_TEST(str, STR_SHARED|STR_NOFREE)) {
return RSTRING(str)->as.heap.len;
@@ -660,6 +660,12 @@ rb_str_capacity(VALUE str)
}
}
+size_t
+rb_str_capacity(VALUE str)
+{
+ return str_capacity(str, TERM_LEN(str));
+}
+
static inline void
must_not_null(const char *ptr)
{
@@ -2021,42 +2027,55 @@ 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 = rb_str_capacity(str);
- /* This function could be called during the encoding changing procedure.
- * If so, the termlen may be different from current TERM_LEN(str).
+ long capa = str_capacity(str, termlen);
+
+ /* This function assumes that (capa + termlen) bytes of memory
+ * is allocated, like many other functions in this file.
*/
- const int oldtermlen = TERM_LEN(str);
- if (capa < len + termlen - 1) { /* assumes oldtermlen is 1 here */
+ if (capa < len) {
rb_check_lockedtmp(str);
str_make_independent_expand(str, len, 0L, termlen);
}
else if (str_dependent_p(str)) {
- if ((termlen > oldtermlen) || !zero_filled(s + len, termlen))
+ if (!zero_filled(s + len, termlen))
str_make_independent_expand(str, len, 0L, termlen);
}
else {
- if (termlen > oldtermlen) {
- if (!STR_EMBED_P(str)) {
- const int d = termlen - oldtermlen;
- if (capa > len + d) {
- /* decrease capa for the new termlen */
- capa -= d;
- assert(capa >= 1);
- assert(!FL_TEST((str), STR_SHARED));
- RSTRING(str)->as.heap.aux.capa = capa;
- } else {
- assert(capa >= len);
- RESIZE_CAPA_TERM(str, capa, termlen);
- }
- }
- }
TERM_FILL(s + len, termlen);
return s;
}
return RSTRING_PTR(str);
}
+void
+rb_str_change_terminator_length(VALUE str, const int oldtermlen, const int termlen)
+{
+ long capa = str_capacity(str, oldtermlen);
+ long len = RSTRING_LEN(str);
+
+ if (capa < len + termlen - oldtermlen) {
+ rb_check_lockedtmp(str);
+ str_make_independent_expand(str, len, 0L, termlen);
+ }
+ else if (str_dependent_p(str)) {
+ if (termlen > oldtermlen)
+ str_make_independent_expand(str, len, 0L, termlen);
+ }
+ else {
+ if (!STR_EMBED_P(str)) {
+ /* modify capa instead of realloc */
+ assert(!FL_TEST((str), STR_SHARED));
+ RSTRING(str)->as.heap.aux.capa = capa - (termlen - oldtermlen);
+ }
+ if (termlen > oldtermlen) {
+ TERM_FILL(RSTRING_PTR(str) + len, termlen);
+ }
+ }
+
+ return;
+}
+
char *
rb_string_value_cstr(volatile VALUE *ptr)
{