Commit ac8d04fb authored by Yukihiro "Matz" Matsumoto's avatar Yukihiro "Matz" Matsumoto

Merge pull request #1820 from ksss/string-embed

Embed small string
parents 035898c7 4bc19d5f
......@@ -15,25 +15,51 @@ extern "C" {
extern const char mrb_digitmap[];
/* (sizeof(mrb_int)*2+sizeof(char*))/sizeof(char)-1 */
#if defined(MRB_INT16)
# define RSTRING_EMBED_LEN_MAX 9
#elif defined(MRB_INT64)
# define RSTRING_EMBED_LEN_MAX 15
#else
# define RSTRING_EMBED_LEN_MAX 11
#endif
struct RString {
MRB_OBJECT_HEADER;
mrb_int len;
union {
mrb_int capa;
struct mrb_shared_string *shared;
} aux;
char *ptr;
struct {
mrb_int len;
union {
mrb_int capa;
struct mrb_shared_string *shared;
} aux;
char *ptr;
} heap;
char ary[RSTRING_EMBED_LEN_MAX + 1];
} as;
};
#define mrb_str_ptr(s) ((struct RString*)(mrb_ptr(s)))
#define RSTRING(s) ((struct RString*)(mrb_ptr(s)))
#define RSTRING_PTR(s) (RSTRING(s)->ptr)
#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 RSTRING_PTR(s)\
((RSTRING(s)->flags & MRB_STR_EMBED) ?\
RSTRING(s)->as.ary :\
RSTRING(s)->as.heap.ptr)
#define RSTRING_LEN(s)\
((RSTRING(s)->flags & MRB_STR_EMBED) ?\
(mrb_int)((RSTRING(s)->flags & MRB_STR_EMBED_LEN_MASK) >> MRB_STR_EMBED_LEN_SHIFT) :\
RSTRING(s)->as.heap.len)
#define RSTRING_CAPA(s)\
((RSTRING(s)->flags & MRB_STR_EMBED) ?\
RSTRING_EMBED_LEN_MAX :\
RSTRING(s)->as.heap.aux.capa)
#define RSTRING_END(s) (RSTRING_PTR(s) + RSTRING_LEN(s))
#define MRB_STR_SHARED 1
#define MRB_STR_NOFREE 2
#define MRB_STR_EMBED 4
#define MRB_STR_EMBED_LEN_MASK 120
#define MRB_STR_EMBED_LEN_SHIFT 3
void mrb_gc_free_str(mrb_state*, struct RString*);
void mrb_str_modify(mrb_state*, struct RString*);
......
......@@ -5,14 +5,12 @@
static void
printstr(mrb_state *mrb, mrb_value obj)
{
struct RString *str;
char *s;
int len;
if (mrb_string_p(obj)) {
str = mrb_str_ptr(obj);
s = str->ptr;
len = str->len;
s = RSTRING_PTR(obj);
len = RSTRING_LEN(obj);
fwrite(s, len, 1, stdout);
}
}
......
......@@ -712,7 +712,13 @@ retry:
if (*p == 'p') arg = mrb_inspect(mrb, arg);
str = mrb_obj_as_string(mrb, arg);
len = RSTRING_LEN(str);
RSTRING_LEN(result) = blen;
if (RSTRING(result)->flags & MRB_STR_EMBED) {
int tmp_n = len;
RSTRING(result)->flags &= ~MRB_STR_EMBED_LEN_MASK;
RSTRING(result)->flags |= tmp_n << MRB_STR_EMBED_LEN_SHIFT;
} else {
RSTRING(result)->as.heap.len = blen;
}
if (flags&(FPREC|FWIDTH)) {
slen = RSTRING_LEN(str);
if (slen < 0) {
......
......@@ -33,8 +33,8 @@ mrb_str_swapcase_bang(mrb_state *mrb, mrb_value str)
struct RString *s = mrb_str_ptr(str);
mrb_str_modify(mrb, s);
p = s->ptr;
pend = s->ptr + s->len;
p = RSTRING_PTR(str);
pend = RSTRING_PTR(str) + RSTRING_LEN(str);
while (p < pend) {
if (ISUPPER(*p)) {
*p = TOLOWER(*p);
......
......@@ -511,7 +511,6 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
case 's':
{
mrb_value ss;
struct RString *s;
char **ps = 0;
int *pl = 0;
......@@ -519,9 +518,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
pl = va_arg(ap, int*);
if (i < argc) {
ss = to_str(mrb, *sp++);
s = mrb_str_ptr(ss);
*ps = s->ptr;
*pl = s->len;
*ps = RSTRING_PTR(ss);
*pl = RSTRING_LEN(ss);
i++;
}
}
......@@ -537,14 +535,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
if (i < argc) {
ss = to_str(mrb, *sp++);
s = mrb_str_ptr(ss);
len = (mrb_int)strlen(s->ptr);
if (len < s->len) {
len = (mrb_int)strlen(RSTRING_PTR(ss));
if (len < RSTRING_LEN(ss)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte");
}
else if (len > s->len) {
else if (len > RSTRING_LEN(ss)) {
mrb_str_modify(mrb, s);
}
*ps = s->ptr;
*ps = RSTRING_PTR(ss);
i++;
}
}
......@@ -1298,7 +1296,7 @@ mrb_class_name(mrb_state *mrb, struct RClass* c)
mrb_str_concat(mrb, path, mrb_ptr_to_str(mrb, c));
mrb_str_cat_lit(mrb, path, ">");
}
return mrb_str_ptr(path)->ptr;
return RSTRING_PTR(path);
}
const char*
......
......@@ -390,7 +390,6 @@ void
mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t)
{
const struct types *type = builtin_types;
struct RString *s;
enum mrb_vtype xt;
xt = mrb_type(x);
......@@ -409,8 +408,7 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t)
etype = "Symbol";
}
else if (mrb_special_const_p(x)) {
s = mrb_str_ptr(mrb_obj_as_string(mrb, x));
etype = s->ptr;
etype = RSTRING_PTR(mrb_obj_as_string(mrb, x));
}
else {
etype = mrb_obj_classname(mrb, x);
......
......@@ -12,14 +12,12 @@ static void
printstr(mrb_state *mrb, mrb_value obj)
{
#ifdef ENABLE_STDIO
struct RString *str;
char *s;
int len;
if (mrb_string_p(obj)) {
str = mrb_str_ptr(obj);
s = str->ptr;
len = str->len;
s = RSTRING_PTR(obj);
len = RSTRING_LEN(obj);
fwrite(s, len, 1, stdout);
}
#endif
......@@ -44,8 +42,7 @@ mrb_print_error(mrb_state *mrb)
mrb_print_backtrace(mrb);
s = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0);
if (mrb_string_p(s)) {
struct RString *str = mrb_str_ptr(s);
fwrite(str->ptr, str->len, 1, stderr);
fwrite(RSTRING_PTR(s), RSTRING_LEN(s), 1, stderr);
putc('\n', stderr);
}
#endif
......
......@@ -135,8 +135,8 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep)
mrb_free(mrb, irep->iseq);
for (i=0; i<irep->plen; i++) {
if (mrb_type(irep->pool[i]) == MRB_TT_STRING) {
if ((mrb_str_ptr(irep->pool[i])->flags & MRB_STR_NOFREE) == 0) {
mrb_free(mrb, mrb_str_ptr(irep->pool[i])->ptr);
if ((mrb_str_ptr(irep->pool[i])->flags & (MRB_STR_NOFREE|MRB_STR_EMBED)) == 0) {
mrb_free(mrb, RSTRING_PTR(irep->pool[i]));
}
mrb_free(mrb, mrb_obj_ptr(irep->pool[i]));
}
......@@ -163,25 +163,30 @@ mrb_str_pool(mrb_state *mrb, mrb_value str)
{
struct RString *s = mrb_str_ptr(str);
struct RString *ns;
char *ptr;
mrb_int len;
ns = (struct RString *)mrb_malloc(mrb, sizeof(struct RString));
ns->tt = MRB_TT_STRING;
ns->c = mrb->string_class;
len = s->len;
ns->len = len;
if (s->flags & MRB_STR_EMBED)
len = (mrb_int)((s->flags & MRB_STR_EMBED_LEN_MASK) >> MRB_STR_EMBED_LEN_SHIFT);
else
len = s->as.heap.len;
ns->as.heap.len = len;
if (s->flags & MRB_STR_NOFREE) {
ns->ptr = s->ptr;
ns->as.heap.ptr = s->as.heap.ptr;
ns->flags = MRB_STR_NOFREE;
}
else {
ns->flags = 0;
ns->ptr = (char *)mrb_malloc(mrb, (size_t)len+1);
if (s->ptr) {
memcpy(ns->ptr, s->ptr, len);
ns->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)len+1);
ptr = (s->flags & MRB_STR_EMBED) ? s->as.ary : s->as.heap.ptr;
if (ptr) {
memcpy(ns->as.heap.ptr, ptr, len);
}
ns->ptr[len] = '\0';
ns->as.heap.ptr[len] = '\0';
}
return mrb_obj_value(ns);
}
......
This diff is collapsed.
......@@ -397,11 +397,11 @@ sym_inspect(mrb_state *mrb, mrb_value sym)
name = mrb_sym2name_len(mrb, id, &len);
str = mrb_str_new(mrb, 0, len+1);
RSTRING(str)->ptr[0] = ':';
memcpy(RSTRING(str)->ptr+1, name, len);
RSTRING_PTR(str)[0] = ':';
memcpy(RSTRING_PTR(str)+1, name, len);
if (!symname_p(name) || strlen(name) != len) {
str = mrb_str_dump(mrb, str);
memcpy(RSTRING(str)->ptr, ":\"", 2);
memcpy(RSTRING_PTR(str), ":\"", 2);
}
return str;
}
......@@ -428,7 +428,7 @@ mrb_sym2name(mrb_state *mrb, mrb_sym sym)
}
else {
mrb_value str = mrb_str_dump(mrb, mrb_str_new_static(mrb, name, len));
return RSTRING(str)->ptr;
return RSTRING_PTR(str);
}
}
......
......@@ -61,14 +61,12 @@ eval_test(mrb_state *mrb)
static void
t_printstr(mrb_state *mrb, mrb_value obj)
{
struct RString *str;
char *s;
int len;
if (mrb_string_p(obj)) {
str = mrb_str_ptr(obj);
s = str->ptr;
len = str->len;
s = RSTRING_PTR(obj);
len = RSTRING_LEN(obj);
fwrite(s, len, 1, stdout);
}
}
......
......@@ -86,6 +86,7 @@ assert('String#[] with Range') do
g1 = 'abc'[-2..3]
h1 = 'abc'[3..4]
i1 = 'abc'[4..5]
j1 = 'abcdefghijklmnopqrstuvwxyz'[1..3]
a2 = 'abc'[1...0]
b2 = 'abc'[1...1]
c2 = 'abc'[1...2]
......@@ -95,6 +96,7 @@ assert('String#[] with Range') do
g2 = 'abc'[-2...3]
h2 = 'abc'[3...4]
i2 = 'abc'[4...5]
j2 = 'abcdefghijklmnopqrstuvwxyz'[1...3]
assert_equal '', a1
assert_equal 'b', b1
......@@ -105,6 +107,7 @@ assert('String#[] with Range') do
assert_equal 'bc', g1
assert_equal '', h1
assert_nil i2
assert_equal 'bcd', j1
assert_equal '', a2
assert_equal '', b2
assert_equal 'b', c2
......@@ -114,6 +117,7 @@ assert('String#[] with Range') do
assert_equal 'bc', g2
assert_equal '', h2
assert_nil i2
assert_equal 'bc', j2
end
assert('String#capitalize', '15.2.10.5.7') do
......@@ -281,8 +285,10 @@ end
assert('String#initialize', '15.2.10.5.23') do
a = ''
a.initialize('abc')
assert_equal 'abc', a
a.initialize('abcdefghijklmnopqrstuvwxyz')
assert_equal 'abcdefghijklmnopqrstuvwxyz', a
end
assert('String#initialize_copy', '15.2.10.5.24') do
......@@ -307,6 +313,13 @@ assert('String#replace', '15.2.10.5.28') do
a.replace('abc')
assert_equal 'abc', a
assert_equal 'abc', 'cba'.replace(a)
b = 'abc' * 10
c = ('cba' * 10).dup
b.replace(c);
c.replace(b);
assert_equal c, b
end
assert('String#reverse', '15.2.10.5.29') do
......@@ -452,6 +465,12 @@ assert('String#upcase!', '15.2.10.5.43') do
assert_equal 'ABC', a
assert_equal nil, 'ABC'.upcase!
a = 'abcdefghijklmnopqrstuvwxyz'
b = a.dup
a.upcase!
b.upcase!
assert_equal 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', b
end
# Not ISO specified
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment