optimize rope

This commit is contained in:
Yuichi Nishiwaki 2016-02-27 01:55:49 +09:00
parent 8810d94259
commit d2167a87f9
1 changed files with 39 additions and 45 deletions

View File

@ -20,7 +20,7 @@ struct rope {
union { union {
struct { struct {
struct chunk *chunk; struct chunk *chunk;
int offset; const char *str;
} leaf; } leaf;
struct { struct {
struct rope *left, *right; struct rope *left, *right;
@ -80,7 +80,7 @@ make_chunk_lit(pic_state *pic, const char *str, int len)
c = pic_malloc(pic, offsetof(struct chunk, buf)); c = pic_malloc(pic, offsetof(struct chunk, buf));
c->refcnt = 1; c->refcnt = 1;
c->str = (char *)str; c->str = str;
c->len = len; c->len = len;
return c; return c;
@ -95,8 +95,8 @@ make_rope_leaf(pic_state *pic, struct chunk *c)
rope->refcnt = 1; rope->refcnt = 1;
rope->weight = c->len; rope->weight = c->len;
rope->isleaf = true; rope->isleaf = true;
rope->u.leaf.offset = 0; rope->u.leaf.chunk = c; /* delegate ownership */
rope->u.leaf.chunk = c; /* delegate ownership */ rope->u.leaf.str = c->str;
return rope; return rope;
} }
@ -106,11 +106,6 @@ make_rope_node(pic_state *pic, struct rope *left, struct rope *right)
{ {
struct rope *rope; struct rope *rope;
if (left == 0)
return pic_rope_incref(right);
if (right == 0)
return pic_rope_incref(left);
rope = pic_malloc(pic, sizeof(struct rope)); rope = pic_malloc(pic, sizeof(struct rope));
rope->refcnt = 1; rope->refcnt = 1;
rope->weight = left->weight + right->weight; rope->weight = left->weight + right->weight;
@ -135,29 +130,31 @@ make_str(pic_state *pic, struct rope *rope)
static struct rope * static struct rope *
merge(pic_state *pic, struct rope *left, struct rope *right) merge(pic_state *pic, struct rope *left, struct rope *right)
{ {
if (left == 0)
return pic_rope_incref(right);
if (right == 0)
return pic_rope_incref(left);
return make_rope_node(pic, left, right); return make_rope_node(pic, left, right);
} }
static struct rope * static struct rope *
slice(pic_state *pic, struct rope *rope, int i, int j) slice(pic_state *pic, struct rope *rope, int i, int j)
{ {
assert(i <= j);
assert(j <= rope->weight);
if (i == 0 && rope->weight == j) { if (i == 0 && rope->weight == j) {
return pic_rope_incref(rope); return pic_rope_incref(rope);
} }
if (rope->isleaf) { if (rope->isleaf) {
struct rope *y; struct rope *r;
y = make_rope_leaf(pic, rope->u.leaf.chunk); r = make_rope_leaf(pic, rope->u.leaf.chunk);
y->weight = j - i; r->weight = j - i;
y->u.leaf.offset = rope->u.leaf.offset + i; r->u.leaf.str += i;
CHUNK_INCREF(rope->u.leaf.chunk); CHUNK_INCREF(rope->u.leaf.chunk);
return y; return r;
} }
if (j <= rope->u.node.left->weight) { if (j <= rope->u.node.left->weight) {
@ -179,42 +176,27 @@ slice(pic_state *pic, struct rope *rope, int i, int j)
} }
static void static void
flatten(pic_state *pic, struct rope *rope, struct chunk *c, int offset) flatten(pic_state *pic, struct rope *rope, struct chunk *c, char *buf)
{ {
if (rope->isleaf) { if (rope->isleaf) {
memcpy(c->buf + offset, rope->u.leaf.chunk->str + rope->u.leaf.offset, rope->weight); memcpy(buf, rope->u.leaf.str, rope->weight);
} else {
flatten(pic, rope->u.node.left, c, buf);
flatten(pic, rope->u.node.right, c, buf + rope->u.node.left->weight);
}
if (rope->isleaf) {
CHUNK_DECREF(rope->u.leaf.chunk); CHUNK_DECREF(rope->u.leaf.chunk);
rope->u.leaf.chunk = c; rope->u.leaf.chunk = c;
rope->u.leaf.offset = offset; rope->u.leaf.str = buf;
CHUNK_INCREF(c);
} else { } else {
flatten(pic, rope->u.node.left, c, offset);
flatten(pic, rope->u.node.right, c, offset + rope->u.node.left->weight);
pic_rope_decref(pic, rope->u.node.left); pic_rope_decref(pic, rope->u.node.left);
pic_rope_decref(pic, rope->u.node.right); pic_rope_decref(pic, rope->u.node.right);
rope->isleaf = true; rope->isleaf = true;
rope->u.leaf.chunk = c; rope->u.leaf.chunk = c;
rope->u.leaf.offset = offset; rope->u.leaf.str = buf;
CHUNK_INCREF(c);
} }
} CHUNK_INCREF(c);
static const char *
rope_cstr(pic_state *pic, struct rope *rope)
{
struct chunk *c;
if (rope->isleaf && rope->u.leaf.offset == 0 && rope->weight == rope->u.leaf.chunk->len) {
return rope->u.leaf.chunk->str; /* reuse cached chunk */
}
c = make_chunk(pic, 0, rope->weight);
flatten(pic, rope, c, 0);
CHUNK_DECREF(c);
return c->str;
} }
static void static void
@ -284,7 +266,7 @@ pic_str_ref(pic_state *PIC_UNUSED(pic), pic_value str, int i)
while (i < rope->weight) { while (i < rope->weight) {
if (rope->isleaf) { if (rope->isleaf) {
return rope->u.leaf.chunk->str[rope->u.leaf.offset + i]; return rope->u.leaf.str[i];
} }
if (i < rope->u.node.left->weight) { if (i < rope->u.node.left->weight) {
rope = rope->u.node.left; rope = rope->u.node.left;
@ -330,7 +312,19 @@ pic_str_hash(pic_state *pic, pic_value str)
const char * const char *
pic_str(pic_state *pic, pic_value str) pic_str(pic_state *pic, pic_value str)
{ {
return rope_cstr(pic, pic_str_ptr(pic, str)->rope); struct rope *rope = pic_str_ptr(pic, str)->rope;
struct chunk *c;
if (rope->isleaf && rope->u.leaf.str + rope->weight == rope->u.leaf.chunk->str + rope->u.leaf.chunk->len) {
return rope->u.leaf.str; /* reuse cached chunk */
}
c = make_chunk(pic, 0, rope->weight);
flatten(pic, rope, c, c->buf);
CHUNK_DECREF(c);
return c->str;
} }
static pic_value static pic_value