remove struct chunk

This commit is contained in:
Yuichi Nishiwaki 2016-02-29 16:48:38 +09:00
parent d2167a87f9
commit ae88bed481
1 changed files with 81 additions and 90 deletions

View File

@ -6,38 +6,22 @@
#include "picrin/extra.h" #include "picrin/extra.h"
#include "picrin/private/object.h" #include "picrin/private/object.h"
struct chunk {
int refcnt;
const char *str;
int len;
char buf[1];
};
struct rope { struct rope {
int refcnt; int refcnt;
int weight; int weight;
bool isleaf; bool isleaf;
union { union {
struct { struct {
struct chunk *chunk; struct rope *owner;
const char *str; const char *str; /* always points to zero-term'd buf */
} leaf; } leaf;
struct { struct {
struct rope *left, *right; struct rope *left, *right;
} node; } node;
} u; } u;
char buf[1];
}; };
#define CHUNK_INCREF(c) do { \
(c)->refcnt++; \
} while (0)
#define CHUNK_DECREF(c) do { \
if (! --(c)->refcnt) { \
pic_free(pic, (c)); \
} \
} while (0)
struct rope * struct rope *
pic_rope_incref(struct rope *rope) { pic_rope_incref(struct rope *rope) {
rope->refcnt++; rope->refcnt++;
@ -48,7 +32,9 @@ void
pic_rope_decref(pic_state *pic, struct rope *rope) { pic_rope_decref(pic_state *pic, struct rope *rope) {
if (! --rope->refcnt) { if (! --rope->refcnt) {
if (rope->isleaf) { if (rope->isleaf) {
CHUNK_DECREF(rope->u.leaf.chunk); if (rope->u.leaf.owner) {
pic_rope_decref(pic, rope->u.leaf.owner);
}
} else { } else {
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);
@ -57,46 +43,59 @@ pic_rope_decref(pic_state *pic, struct rope *rope) {
} }
} }
static struct chunk *
make_chunk(pic_state *pic, const char *str, int len)
{
struct chunk *c;
c = pic_malloc(pic, offsetof(struct chunk, buf) + len + 1);
c->refcnt = 1;
c->str = c->buf;
c->len = len;
c->buf[len] = 0;
if (str) {
memcpy(c->buf, str, len);
}
return c;
}
static struct chunk *
make_chunk_lit(pic_state *pic, const char *str, int len)
{
struct chunk *c;
c = pic_malloc(pic, offsetof(struct chunk, buf));
c->refcnt = 1;
c->str = str;
c->len = len;
return c;
}
static struct rope * static struct rope *
make_rope_leaf(pic_state *pic, struct chunk *c) make_rope_leaf(pic_state *pic, const char *str, int len)
{ {
struct rope *rope; struct rope *rope;
rope = pic_malloc(pic, sizeof(struct rope)); rope = pic_malloc(pic, offsetof(struct rope, buf) + len + 1);
rope->refcnt = 1; rope->refcnt = 1;
rope->weight = c->len; rope->weight = len;
rope->isleaf = true; rope->isleaf = true;
rope->u.leaf.chunk = c; /* delegate ownership */ rope->u.leaf.owner = NULL;
rope->u.leaf.str = c->str; rope->u.leaf.str = rope->buf;
rope->buf[len] = 0;
if (str) {
memcpy(rope->buf, str, len);
}
return rope;
}
static struct rope *
make_rope_lit(pic_state *pic, const char *str, int len)
{
struct rope *rope;
rope = pic_malloc(pic, offsetof(struct rope, buf));
rope->refcnt = 1;
rope->weight = len;
rope->isleaf = true;
rope->u.leaf.owner = NULL;
rope->u.leaf.str = str;
return rope;
}
static struct rope *
make_rope_slice(pic_state *pic, struct rope *owner, int i, int j)
{
struct rope *rope;
assert(owner->isleaf);
if (owner->u.leaf.owner != NULL) {
owner = owner->u.leaf.owner;
}
rope = pic_malloc(pic, offsetof(struct rope, buf));
rope->refcnt = 1;
rope->weight = j - i;
rope->isleaf = true;
rope->u.leaf.owner = owner;
rope->u.leaf.str = owner->u.leaf.str + i;
pic_rope_incref(owner);
return rope; return rope;
} }
@ -141,31 +140,27 @@ merge(pic_state *pic, struct rope *left, struct rope *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)
{ {
int lweight;
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 *r; return make_rope_slice(pic, rope, i, j);
r = make_rope_leaf(pic, rope->u.leaf.chunk);
r->weight = j - i;
r->u.leaf.str += i;
CHUNK_INCREF(rope->u.leaf.chunk);
return r;
} }
if (j <= rope->u.node.left->weight) { lweight = rope->u.node.left->weight;
if (j <= lweight) {
return slice(pic, rope->u.node.left, i, j); return slice(pic, rope->u.node.left, i, j);
} else if (rope->u.node.left->weight <= i) { } else if (lweight <= i) {
return slice(pic, rope->u.node.right, i - rope->u.node.left->weight, j - rope->u.node.left->weight); return slice(pic, rope->u.node.right, i - lweight, j - lweight);
} else { } else {
struct rope *r, *l; struct rope *r, *l;
l = slice(pic, rope->u.node.left, i, rope->u.node.left->weight); l = slice(pic, rope->u.node.left, i, lweight);
r = slice(pic, rope->u.node.right, 0, j - rope->u.node.left->weight); r = slice(pic, rope->u.node.right, 0, j - lweight);
rope = merge(pic, l, r); rope = merge(pic, l, r);
pic_rope_decref(pic, l); pic_rope_decref(pic, l);
@ -176,27 +171,25 @@ 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, char *buf) flatten(pic_state *pic, struct rope *rope, struct rope *owner, char *buf)
{ {
if (rope->isleaf) { if (rope->isleaf) {
memcpy(buf, rope->u.leaf.str, rope->weight); memcpy(buf, rope->u.leaf.str, rope->weight);
} else { } else {
flatten(pic, rope->u.node.left, c, buf); flatten(pic, rope->u.node.left, owner, buf);
flatten(pic, rope->u.node.right, c, buf + rope->u.node.left->weight); flatten(pic, rope->u.node.right, owner, buf + rope->u.node.left->weight);
} }
if (rope->isleaf) { /* path compression */
CHUNK_DECREF(rope->u.leaf.chunk);
rope->u.leaf.chunk = c; if (! rope->isleaf) {
rope->u.leaf.str = buf; pic_rope_incref(owner);
} else {
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.owner = owner;
rope->u.leaf.str = buf; rope->u.leaf.str = buf;
} }
CHUNK_INCREF(c);
} }
static void static void
@ -210,17 +203,17 @@ str_update(pic_state *pic, pic_value dst, pic_value src)
pic_value pic_value
pic_str_value(pic_state *pic, const char *str, int len) pic_str_value(pic_state *pic, const char *str, int len)
{ {
struct chunk *c; struct rope *r;
if (len > 0) { if (len > 0) {
c = make_chunk(pic, str, len); r = make_rope_leaf(pic, str, len);
} else { } else {
if (len == 0) { if (len == 0) {
str = ""; str = "";
} }
c = make_chunk_lit(pic, str, -len); r = make_rope_lit(pic, str, -len);
} }
return make_str(pic, make_rope_leaf(pic, c)); return make_str(pic, r);
} }
pic_value pic_value
@ -312,19 +305,17 @@ 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)
{ {
struct rope *rope = pic_str_ptr(pic, str)->rope; struct rope *rope = pic_str_ptr(pic, str)->rope, *r;
struct chunk *c;
if (rope->isleaf && rope->u.leaf.str + rope->weight == rope->u.leaf.chunk->str + rope->u.leaf.chunk->len) { if (rope->isleaf && rope->u.leaf.str[rope->weight] == '\0') {
return rope->u.leaf.str; /* reuse cached chunk */ return rope->u.leaf.str;
} }
c = make_chunk(pic, 0, rope->weight); r = make_rope_leaf(pic, 0, rope->weight);
flatten(pic, rope, c, c->buf); flatten(pic, rope, r, r->buf);
CHUNK_DECREF(c); return r->u.leaf.str;
return c->str;
} }
static pic_value static pic_value