optimize rope
This commit is contained in:
parent
8810d94259
commit
d2167a87f9
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue