diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2013-04-28 02:47:22 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2013-04-28 02:47:22 +0900 |
| commit | 5c68195c88ed45164373b0ca435a7be2421dcc7c (patch) | |
| tree | c1e56af6ca069a0625ae86a25bc24b8bb409656a | |
| parent | 160eb71338205813b9b9c599249b4a5e2bec4217 (diff) | |
| download | mruby-5c68195c88ed45164373b0ca435a7be2421dcc7c.tar.gz mruby-5c68195c88ed45164373b0ca435a7be2421dcc7c.zip | |
mrb_str_new_static(): zero copy string creation
| -rw-r--r-- | include/mruby.h | 1 | ||||
| -rw-r--r-- | include/mruby/string.h | 3 | ||||
| -rw-r--r-- | src/gc.c | 2 | ||||
| -rw-r--r-- | src/string.c | 42 | ||||
| -rw-r--r-- | src/symbol.c | 14 |
5 files changed, 49 insertions, 13 deletions
diff --git a/include/mruby.h b/include/mruby.h index 8c811c58f..28eea6929 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -231,6 +231,7 @@ void *mrb_free(mrb_state*, void*); mrb_value mrb_str_new(mrb_state *mrb, const char *p, size_t len); mrb_value mrb_str_new_cstr(mrb_state*, const char*); +mrb_value mrb_str_new_static(mrb_state *mrb, const char *p, size_t len); mrb_state* mrb_open(void); mrb_state* mrb_open_allocf(mrb_allocf, void *ud); diff --git a/include/mruby/string.h b/include/mruby/string.h index c62d79563..a1b38d039 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -37,7 +37,8 @@ struct RString { #define RSTRING_LEN(s) (RSTRING(s)->len) #define RSTRING_CAPA(s) (RSTRING(s)->aux.capa) #define RSTRING_END(s) (RSTRING(s)->ptr + RSTRING(s)->len) -#define MRB_STR_SHARED 256 +#define MRB_STR_SHARED 1 +#define MRB_STR_STATIC (1<<1) void mrb_str_decref(mrb_state*, mrb_shared_string*); void mrb_str_modify(mrb_state*, struct RString*); @@ -531,7 +531,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj) case MRB_TT_STRING: if (obj->flags & MRB_STR_SHARED) mrb_str_decref(mrb, ((struct RString*)obj)->aux.shared); - else + else if ((obj->flags & MRB_STR_STATIC) == 0) mrb_free(mrb, ((struct RString*)obj)->ptr); break; diff --git a/src/string.c b/src/string.c index 371d3faf6..34769222a 100644 --- a/src/string.c +++ b/src/string.c @@ -34,6 +34,7 @@ static mrb_value mrb_str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_ void mrb_str_decref(mrb_state *mrb, mrb_shared_string *shared) { + if (shared->refcnt < 0) return; shared->refcnt--; if (shared->refcnt == 0) { mrb_free(mrb, shared->ptr); @@ -44,6 +45,18 @@ mrb_str_decref(mrb_state *mrb, mrb_shared_string *shared) void mrb_str_modify(mrb_state *mrb, struct RString *s) { + if (s->flags & MRB_STR_STATIC) { + char *p = s->ptr; + + s->ptr = (char *)mrb_malloc(mrb, (size_t)s->len+1); + if (p) { + memcpy(s->ptr, p, s->len); + } + s->ptr[s->len] = '\0'; + s->flags &= ~MRB_STR_STATIC; + return; + } + if (s->flags & MRB_STR_SHARED) { mrb_shared_string *shared = s->aux.shared; @@ -68,6 +81,7 @@ mrb_str_modify(mrb_state *mrb, struct RString *s) mrb_str_decref(mrb, shared); } s->flags &= ~MRB_STR_SHARED; + return; } } @@ -249,6 +263,19 @@ mrb_str_new_cstr(mrb_state *mrb, const char *p) return mrb_obj_value(s); } +mrb_value +mrb_str_new_static(mrb_state *mrb, const char *p, size_t len) +{ + struct RString *s; + + s = mrb_obj_alloc_string(mrb); + s->len = len; + s->aux.capa = len; + s->ptr = (char *)p; + s->flags |= MRB_STR_STATIC; + return mrb_obj_value(s); +} + char * mrb_str_to_cstr(mrb_state *mrb, mrb_value str0) { @@ -271,12 +298,19 @@ str_make_shared(mrb_state *mrb, struct RString *s) if (!(s->flags & MRB_STR_SHARED)) { mrb_shared_string *shared = (mrb_shared_string *)mrb_malloc(mrb, sizeof(mrb_shared_string)); - shared->refcnt = 1; - if (s->aux.capa > s->len) { - s->ptr = shared->ptr = (char *)mrb_realloc(mrb, s->ptr, s->len+1); + if (s->flags & MRB_STR_STATIC) { + shared->refcnt = -1; /* should never be freed */ + shared->ptr = s->ptr; + s->flags &= ~MRB_STR_STATIC; } else { - shared->ptr = s->ptr; + shared->refcnt = 1; + if (s->aux.capa > s->len) { + s->ptr = shared->ptr = (char *)mrb_realloc(mrb, s->ptr, s->len+1); + } + else { + shared->ptr = s->ptr; + } } shared->len = s->len; s->aux.shared = shared; diff --git a/src/symbol.c b/src/symbol.c index 24db3a4b6..e913f95c8 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -213,7 +213,7 @@ mrb_sym_to_s(mrb_state *mrb, mrb_value sym) size_t len; p = mrb_sym2name_len(mrb, id, &len); - return mrb_str_new(mrb, p, len); + return mrb_str_new_static(mrb, p, len); } /* 15.2.11.3.4 */ @@ -381,14 +381,14 @@ mrb_sym2str(mrb_state *mrb, mrb_sym sym) { size_t len; const char *name = mrb_sym2name_len(mrb, sym, &len); - + mrb_value str; + if (!name) return mrb_undef_value(); /* can't happen */ + str = mrb_str_new_static(mrb, name, len); if (symname_p(name) && strlen(name) == len) { - return mrb_str_new(mrb, name, len); - } - else { - return mrb_str_dump(mrb, mrb_str_new(mrb, name, len)); + return str; } + return mrb_str_dump(mrb, str); } const char* @@ -402,7 +402,7 @@ mrb_sym2name(mrb_state *mrb, mrb_sym sym) return name; } else { - mrb_value str = mrb_str_dump(mrb, mrb_str_new(mrb, name, len)); + mrb_value str = mrb_str_dump(mrb, mrb_str_new_static(mrb, name, len)); return RSTRING(str)->ptr; } } |
