mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Improve Hash table using variable sized segments.
This commit is contained in:
@@ -18,7 +18,7 @@ MRB_BEGIN_DECL
|
||||
struct RHash {
|
||||
MRB_OBJECT_HEADER;
|
||||
struct iv_tbl *iv;
|
||||
struct seglist *ht;
|
||||
struct htable *ht;
|
||||
};
|
||||
|
||||
#define mrb_hash_ptr(v) ((struct RHash*)(mrb_ptr(v)))
|
||||
|
||||
+161
-147
@@ -17,11 +17,12 @@ mrb_int mrb_float_id(mrb_float f);
|
||||
#endif
|
||||
|
||||
/* return non zero to break the loop */
|
||||
typedef int (sg_foreach_func)(mrb_state *mrb,mrb_value key, mrb_value val, void *data);
|
||||
typedef int (ht_foreach_func)(mrb_state *mrb,mrb_value key, mrb_value val, void *data);
|
||||
|
||||
#ifndef MRB_SG_SEGMENT_SIZE
|
||||
#define MRB_SG_SEGMENT_SIZE 5
|
||||
#ifndef MRB_HT_INIT_SIZE
|
||||
#define MRB_HT_INIT_SIZE 4
|
||||
#endif
|
||||
#define HT_SEG_INCREASE_RATIO 1.2
|
||||
|
||||
struct segkv {
|
||||
mrb_value key;
|
||||
@@ -29,8 +30,9 @@ struct segkv {
|
||||
};
|
||||
|
||||
typedef struct segment {
|
||||
uint16_t size;
|
||||
struct segment *next;
|
||||
struct segkv e[MRB_SG_SEGMENT_SIZE];
|
||||
struct segkv e[];
|
||||
} segment;
|
||||
|
||||
typedef struct segindex {
|
||||
@@ -40,16 +42,16 @@ typedef struct segindex {
|
||||
} segindex;
|
||||
|
||||
/* Instance variable table structure */
|
||||
typedef struct seglist {
|
||||
typedef struct htable {
|
||||
segment *rootseg;
|
||||
segment *lastseg;
|
||||
mrb_int size;
|
||||
mrb_int last_len;
|
||||
uint16_t last_len;
|
||||
segindex *index;
|
||||
} seglist;
|
||||
} htable;
|
||||
|
||||
static /* inline */ size_t
|
||||
sg_hash_func(mrb_state *mrb, seglist *t, mrb_value key)
|
||||
ht_hash_func(mrb_state *mrb, htable *t, mrb_value key)
|
||||
{
|
||||
enum mrb_vtype tt = mrb_type(key);
|
||||
mrb_value hv;
|
||||
@@ -84,7 +86,7 @@ sg_hash_func(mrb_state *mrb, seglist *t, mrb_value key)
|
||||
}
|
||||
|
||||
static inline mrb_bool
|
||||
sg_hash_equal(mrb_state *mrb, seglist *t, mrb_value a, mrb_value b)
|
||||
ht_hash_equal(mrb_state *mrb, htable *t, mrb_value a, mrb_value b)
|
||||
{
|
||||
enum mrb_vtype tt = mrb_type(a);
|
||||
|
||||
@@ -134,12 +136,12 @@ sg_hash_equal(mrb_state *mrb, seglist *t, mrb_value a, mrb_value b)
|
||||
}
|
||||
|
||||
/* Creates the instance variable table. */
|
||||
static seglist*
|
||||
sg_new(mrb_state *mrb)
|
||||
static htable*
|
||||
ht_new(mrb_state *mrb)
|
||||
{
|
||||
seglist *t;
|
||||
htable *t;
|
||||
|
||||
t = (seglist*)mrb_malloc(mrb, sizeof(seglist));
|
||||
t = (htable*)mrb_malloc(mrb, sizeof(htable));
|
||||
t->size = 0;
|
||||
t->rootseg = NULL;
|
||||
t->lastseg = NULL;
|
||||
@@ -163,11 +165,11 @@ sg_new(mrb_state *mrb)
|
||||
#define UPPER_BOUND(x) ((x)>>2|(x)>>1)
|
||||
#endif
|
||||
|
||||
#define SG_MASK(index) ((index->capa)-1)
|
||||
#define HT_MASK(index) ((index->capa)-1)
|
||||
|
||||
/* Build index for the segment list */
|
||||
/* Build index for the hash table */
|
||||
static void
|
||||
sg_index(mrb_state *mrb, seglist *t)
|
||||
ht_index(mrb_state *mrb, htable *t)
|
||||
{
|
||||
size_t size = (size_t)t->size;
|
||||
size_t mask;
|
||||
@@ -175,14 +177,6 @@ sg_index(mrb_state *mrb, seglist *t)
|
||||
segment *seg;
|
||||
size_t i;
|
||||
|
||||
if (size < MRB_SG_SEGMENT_SIZE) {
|
||||
if (index) {
|
||||
failed:
|
||||
mrb_free(mrb, index);
|
||||
t->index = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* allocate index table */
|
||||
if (index && index->size >= UPPER_BOUND(index->capa)) {
|
||||
size = index->capa+1;
|
||||
@@ -190,7 +184,11 @@ sg_index(mrb_state *mrb, seglist *t)
|
||||
power2(size);
|
||||
if (!index || index->capa < size) {
|
||||
index = (segindex*)mrb_realloc_simple(mrb, index, sizeof(segindex)+sizeof(struct segkv*)*size);
|
||||
if (index == NULL) goto failed;
|
||||
if (index == NULL) {
|
||||
mrb_free(mrb, index);
|
||||
t->index = NULL;
|
||||
return;
|
||||
}
|
||||
t->index = index;
|
||||
}
|
||||
index->size = t->size;
|
||||
@@ -200,10 +198,10 @@ sg_index(mrb_state *mrb, seglist *t)
|
||||
}
|
||||
|
||||
/* rebuld index */
|
||||
mask = SG_MASK(index);
|
||||
mask = HT_MASK(index);
|
||||
seg = t->rootseg;
|
||||
while (seg) {
|
||||
for (i=0; i<MRB_SG_SEGMENT_SIZE; i++) {
|
||||
for (i=0; i<seg->size; i++) {
|
||||
mrb_value key;
|
||||
size_t k, step = 0;
|
||||
|
||||
@@ -212,7 +210,7 @@ sg_index(mrb_state *mrb, seglist *t)
|
||||
}
|
||||
key = seg->e[i].key;
|
||||
if (mrb_undef_p(key)) continue;
|
||||
k = sg_hash_func(mrb, t, key) & mask;
|
||||
k = ht_hash_func(mrb, t, key) & mask;
|
||||
while (index->table[k]) {
|
||||
k = (k+(++step)) & mask;
|
||||
}
|
||||
@@ -222,9 +220,9 @@ sg_index(mrb_state *mrb, seglist *t)
|
||||
}
|
||||
}
|
||||
|
||||
/* Compacts the segment list removing deleted entries. */
|
||||
/* Compacts the hash table removing deleted entries. */
|
||||
static void
|
||||
sg_compact(mrb_state *mrb, seglist *t)
|
||||
ht_compact(mrb_state *mrb, htable *t)
|
||||
{
|
||||
segment *seg;
|
||||
mrb_int i;
|
||||
@@ -235,11 +233,11 @@ sg_compact(mrb_state *mrb, seglist *t)
|
||||
if (t == NULL) return;
|
||||
seg = t->rootseg;
|
||||
if (t->index && (size_t)t->size == t->index->size) {
|
||||
sg_index(mrb, t);
|
||||
ht_index(mrb, t);
|
||||
return;
|
||||
}
|
||||
while (seg) {
|
||||
for (i=0; i<MRB_SG_SEGMENT_SIZE; i++) {
|
||||
for (i=0; i<seg->size; i++) {
|
||||
mrb_value k = seg->e[i].key;
|
||||
|
||||
if (!seg->next && i >= t->last_len) {
|
||||
@@ -255,7 +253,7 @@ sg_compact(mrb_state *mrb, seglist *t)
|
||||
size++;
|
||||
if (seg2 != NULL) {
|
||||
seg2->e[i2++] = seg->e[i];
|
||||
if (i2 >= MRB_SG_SEGMENT_SIZE) {
|
||||
if (i2 >= seg2->size) {
|
||||
seg2 = seg2->next;
|
||||
i2 = 0;
|
||||
}
|
||||
@@ -279,13 +277,31 @@ sg_compact(mrb_state *mrb, seglist *t)
|
||||
}
|
||||
}
|
||||
if (t->index) {
|
||||
sg_index(mrb, t);
|
||||
ht_index(mrb, t);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the value for the key in the indexed segment list. */
|
||||
static segment*
|
||||
segment_alloc(mrb_state *mrb, segment *seg)
|
||||
{
|
||||
uint32_t size;
|
||||
|
||||
if (!seg) size = MRB_HT_INIT_SIZE;
|
||||
else {
|
||||
size = seg->size*HT_SEG_INCREASE_RATIO + 1;
|
||||
if (size > UINT16_MAX) size = UINT16_MAX;
|
||||
}
|
||||
|
||||
seg = (segment*)mrb_malloc(mrb, sizeof(segment)+sizeof(struct segkv)*size);
|
||||
seg->size = size;
|
||||
seg->next = NULL;
|
||||
|
||||
return seg;
|
||||
}
|
||||
|
||||
/* Set the value for the key in the indexed table. */
|
||||
static void
|
||||
sg_index_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val)
|
||||
ht_index_put(mrb_state *mrb, htable *t, mrb_value key, mrb_value val)
|
||||
{
|
||||
segindex *index = t->index;
|
||||
size_t k, sp, step = 0, mask;
|
||||
@@ -293,18 +309,18 @@ sg_index_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val)
|
||||
|
||||
if (index->size >= UPPER_BOUND(index->capa)) {
|
||||
/* need to expand table */
|
||||
sg_compact(mrb, t);
|
||||
ht_compact(mrb, t);
|
||||
index = t->index;
|
||||
}
|
||||
mask = SG_MASK(index);
|
||||
mask = HT_MASK(index);
|
||||
sp = index->capa;
|
||||
k = sg_hash_func(mrb, t, key) & mask;
|
||||
k = ht_hash_func(mrb, t, key) & mask;
|
||||
while (index->table[k]) {
|
||||
mrb_value key2 = index->table[k]->key;
|
||||
if (mrb_undef_p(key2)) {
|
||||
if (sp == index->capa) sp = k;
|
||||
}
|
||||
else if (sg_hash_equal(mrb, t, key, key2)) {
|
||||
else if (ht_hash_equal(mrb, t, key, key2)) {
|
||||
index->table[k]->val = val;
|
||||
return;
|
||||
}
|
||||
@@ -316,11 +332,11 @@ sg_index_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val)
|
||||
|
||||
/* put the value at the last */
|
||||
seg = t->lastseg;
|
||||
if (t->last_len < MRB_SG_SEGMENT_SIZE) {
|
||||
if (t->last_len < seg->size) {
|
||||
index->table[k] = &seg->e[t->last_len++];
|
||||
}
|
||||
else { /* append a new segment */
|
||||
seg->next = (segment*)mrb_malloc(mrb, sizeof(segment));
|
||||
seg->next = segment_alloc(mrb, seg);
|
||||
seg = seg->next;
|
||||
seg->next = NULL;
|
||||
t->lastseg = seg;
|
||||
@@ -333,21 +349,21 @@ sg_index_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val)
|
||||
t->size++;
|
||||
}
|
||||
|
||||
/* Set the value for the key in the segment list. */
|
||||
/* Set the value for the key in the table. */
|
||||
static void
|
||||
sg_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val)
|
||||
ht_put(mrb_state *mrb, htable *t, mrb_value key, mrb_value val)
|
||||
{
|
||||
segment *seg;
|
||||
mrb_int i, deleted = 0;
|
||||
|
||||
if (t == NULL) return;
|
||||
if (t->index) {
|
||||
sg_index_put(mrb, t, key, val);
|
||||
ht_index_put(mrb, t, key, val);
|
||||
return;
|
||||
}
|
||||
seg = t->rootseg;
|
||||
while (seg) {
|
||||
for (i=0; i<MRB_SG_SEGMENT_SIZE; i++) {
|
||||
for (i=0; i<seg->size; i++) {
|
||||
mrb_value k = seg->e[i].key;
|
||||
/* Found room in last segment after last_len */
|
||||
if (!seg->next && i >= t->last_len) {
|
||||
@@ -361,49 +377,58 @@ sg_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val)
|
||||
deleted++;
|
||||
continue;
|
||||
}
|
||||
if (sg_hash_equal(mrb, t, k, key)) {
|
||||
if (ht_hash_equal(mrb, t, k, key)) {
|
||||
seg->e[i].val = val;
|
||||
return;
|
||||
}
|
||||
}
|
||||
seg = seg->next;
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
if (deleted > MRB_SG_SEGMENT_SIZE) {
|
||||
sg_compact(mrb, t);
|
||||
|
||||
/* Compact if last segment has room */
|
||||
if (deleted > 0 && deleted > MRB_HT_INIT_SIZE) {
|
||||
ht_compact(mrb, t);
|
||||
}
|
||||
t->size++;
|
||||
|
||||
seg = (segment*)mrb_malloc(mrb, sizeof(segment));
|
||||
seg->next = NULL;
|
||||
seg->e[0].key = key;
|
||||
seg->e[0].val = val;
|
||||
t->last_len = 1;
|
||||
if (t->rootseg == NULL) {
|
||||
t->rootseg = seg;
|
||||
/* check if thre's room after compaction */
|
||||
if (t->lastseg && t->last_len < t->lastseg->size) {
|
||||
seg = t->lastseg;
|
||||
i = t->last_len;
|
||||
}
|
||||
else {
|
||||
t->lastseg->next = seg;
|
||||
/* append new segment */
|
||||
seg = segment_alloc(mrb, t->lastseg);
|
||||
i = 0;
|
||||
if (t->rootseg == NULL) {
|
||||
t->rootseg = seg;
|
||||
}
|
||||
else {
|
||||
t->lastseg->next = seg;
|
||||
}
|
||||
t->lastseg = seg;
|
||||
}
|
||||
t->lastseg = seg;
|
||||
if (t->index == NULL && t->size > MRB_SG_SEGMENT_SIZE*4) {
|
||||
sg_index(mrb, t);
|
||||
seg->e[i].key = key;
|
||||
seg->e[i].val = val;
|
||||
t->last_len = i+1;
|
||||
if (t->index == NULL && t->size > MRB_HT_INIT_SIZE*4) {
|
||||
ht_index(mrb, t);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get a value for a key from the indexed segment list. */
|
||||
/* Get a value for a key from the indexed table. */
|
||||
static mrb_bool
|
||||
sg_index_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp)
|
||||
ht_index_get(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp)
|
||||
{
|
||||
segindex *index = t->index;
|
||||
size_t mask = SG_MASK(index);
|
||||
size_t k = sg_hash_func(mrb, t, key) & mask;
|
||||
size_t mask = HT_MASK(index);
|
||||
size_t k = ht_hash_func(mrb, t, key) & mask;
|
||||
size_t step = 0;
|
||||
|
||||
while (index->table[k]) {
|
||||
mrb_value key2 = index->table[k]->key;
|
||||
if (!mrb_undef_p(key2) && sg_hash_equal(mrb, t, key, key2)) {
|
||||
if (!mrb_undef_p(key2) && ht_hash_equal(mrb, t, key, key2)) {
|
||||
if (vp) *vp = index->table[k]->val;
|
||||
return TRUE;
|
||||
}
|
||||
@@ -412,28 +437,28 @@ sg_index_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Get a value for a key from the segment list. */
|
||||
/* Get a value for a key from the hash table. */
|
||||
static mrb_bool
|
||||
sg_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp)
|
||||
ht_get(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp)
|
||||
{
|
||||
segment *seg;
|
||||
mrb_int i;
|
||||
|
||||
if (t == NULL) return FALSE;
|
||||
if (t->index) {
|
||||
return sg_index_get(mrb, t, key, vp);
|
||||
return ht_index_get(mrb, t, key, vp);
|
||||
}
|
||||
|
||||
seg = t->rootseg;
|
||||
while (seg) {
|
||||
for (i=0; i<MRB_SG_SEGMENT_SIZE; i++) {
|
||||
for (i=0; i<seg->size; i++) {
|
||||
mrb_value k = seg->e[i].key;
|
||||
|
||||
if (!seg->next && i >= t->last_len) {
|
||||
return FALSE;
|
||||
}
|
||||
if (mrb_undef_p(k)) continue;
|
||||
if (sg_hash_equal(mrb, t, k, key)) {
|
||||
if (ht_hash_equal(mrb, t, k, key)) {
|
||||
if (vp) *vp = seg->e[i].val;
|
||||
return TRUE;
|
||||
}
|
||||
@@ -446,7 +471,7 @@ sg_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp)
|
||||
/* Deletes the value for the symbol from the instance variable table. */
|
||||
/* Deletion is done by overwriting keys by `undef`. */
|
||||
static mrb_bool
|
||||
sg_del(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp)
|
||||
ht_del(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp)
|
||||
{
|
||||
segment *seg;
|
||||
mrb_int i;
|
||||
@@ -454,7 +479,7 @@ sg_del(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp)
|
||||
if (t == NULL) return FALSE;
|
||||
seg = t->rootseg;
|
||||
while (seg) {
|
||||
for (i=0; i<MRB_SG_SEGMENT_SIZE; i++) {
|
||||
for (i=0; i<seg->size; i++) {
|
||||
mrb_value key2;
|
||||
|
||||
if (!seg->next && i >= t->last_len) {
|
||||
@@ -462,7 +487,7 @@ sg_del(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp)
|
||||
return FALSE;
|
||||
}
|
||||
key2 = seg->e[i].key;
|
||||
if (!mrb_undef_p(key2) && sg_hash_equal(mrb, t, key, key2)) {
|
||||
if (!mrb_undef_p(key2) && ht_hash_equal(mrb, t, key, key2)) {
|
||||
if (vp) *vp = seg->e[i].val;
|
||||
seg->e[i].key = mrb_undef_value();
|
||||
t->size--;
|
||||
@@ -476,18 +501,15 @@ sg_del(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp)
|
||||
|
||||
/* Iterates over the instance variable table. */
|
||||
static void
|
||||
sg_foreach(mrb_state *mrb, seglist *t, sg_foreach_func *func, void *p)
|
||||
ht_foreach(mrb_state *mrb, htable *t, ht_foreach_func *func, void *p)
|
||||
{
|
||||
segment *seg;
|
||||
mrb_int i;
|
||||
|
||||
if (t == NULL) return;
|
||||
if (t->index && t->index->size-(size_t)t->size > MRB_SG_SEGMENT_SIZE) {
|
||||
sg_compact(mrb, t);
|
||||
}
|
||||
seg = t->rootseg;
|
||||
while (seg) {
|
||||
for (i=0; i<MRB_SG_SEGMENT_SIZE; i++) {
|
||||
for (i=0; i<seg->size; i++) {
|
||||
/* no value in last segment after last_len */
|
||||
if (!seg->next && i >= t->last_len) {
|
||||
return;
|
||||
@@ -500,34 +522,26 @@ sg_foreach(mrb_state *mrb, seglist *t, sg_foreach_func *func, void *p)
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the size of the instance variable table. */
|
||||
static mrb_int
|
||||
sg_size(mrb_state *mrb, seglist *t)
|
||||
{
|
||||
if (t == NULL) return 0;
|
||||
return t->size;
|
||||
}
|
||||
|
||||
/* Copy the instance variable table. */
|
||||
static seglist*
|
||||
sg_copy(mrb_state *mrb, seglist *t)
|
||||
static htable*
|
||||
ht_copy(mrb_state *mrb, htable *t)
|
||||
{
|
||||
segment *seg;
|
||||
seglist *t2;
|
||||
htable *t2;
|
||||
mrb_int i;
|
||||
|
||||
seg = t->rootseg;
|
||||
t2 = sg_new(mrb);
|
||||
t2 = ht_new(mrb);
|
||||
|
||||
while (seg != NULL) {
|
||||
for (i=0; i<MRB_SG_SEGMENT_SIZE; i++) {
|
||||
while (seg) {
|
||||
for (i=0; i<seg->size; i++) {
|
||||
mrb_value key = seg->e[i].key;
|
||||
mrb_value val = seg->e[i].val;
|
||||
|
||||
if ((seg->next == NULL) && (i >= t->last_len)) {
|
||||
return t2;
|
||||
}
|
||||
sg_put(mrb, t2, key, val);
|
||||
ht_put(mrb, t2, key, val);
|
||||
}
|
||||
seg = seg->next;
|
||||
}
|
||||
@@ -536,7 +550,7 @@ sg_copy(mrb_state *mrb, seglist *t)
|
||||
|
||||
/* Free memory of the instance variable table. */
|
||||
static void
|
||||
sg_free(mrb_state *mrb, seglist *t)
|
||||
ht_free(mrb_state *mrb, htable *t)
|
||||
{
|
||||
segment *seg;
|
||||
|
||||
@@ -576,20 +590,20 @@ hash_mark_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p)
|
||||
void
|
||||
mrb_gc_mark_hash(mrb_state *mrb, struct RHash *hash)
|
||||
{
|
||||
sg_foreach(mrb, hash->ht, hash_mark_i, NULL);
|
||||
ht_foreach(mrb, hash->ht, hash_mark_i, NULL);
|
||||
}
|
||||
|
||||
size_t
|
||||
mrb_gc_mark_hash_size(mrb_state *mrb, struct RHash *hash)
|
||||
{
|
||||
if (!hash->ht) return 0;
|
||||
return sg_size(mrb, hash->ht)*2;
|
||||
return hash->ht->size*2;
|
||||
}
|
||||
|
||||
void
|
||||
mrb_gc_free_hash(mrb_state *mrb, struct RHash *hash)
|
||||
{
|
||||
sg_free(mrb, hash->ht);
|
||||
ht_free(mrb, hash->ht);
|
||||
}
|
||||
|
||||
MRB_API mrb_value
|
||||
@@ -609,8 +623,8 @@ mrb_hash_new_capa(mrb_state *mrb, mrb_int capa)
|
||||
struct RHash *h;
|
||||
|
||||
h = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class);
|
||||
/* preallocate segment list */
|
||||
h->ht = sg_new(mrb);
|
||||
/* preallocate hash table */
|
||||
h->ht = ht_new(mrb);
|
||||
/* capacity ignored */
|
||||
h->iv = 0;
|
||||
return mrb_obj_value(h);
|
||||
@@ -624,7 +638,7 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_value orig;
|
||||
struct RHash* copy;
|
||||
seglist *orig_h;
|
||||
htable *orig_h;
|
||||
mrb_value ifnone, vret;
|
||||
|
||||
mrb_get_args(mrb, "o", &orig);
|
||||
@@ -635,7 +649,7 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self)
|
||||
|
||||
orig_h = RHASH_TBL(self);
|
||||
copy = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class);
|
||||
copy->ht = sg_copy(mrb, orig_h);
|
||||
copy->ht = ht_copy(mrb, orig_h);
|
||||
|
||||
if (MRB_RHASH_DEFAULT_P(self)) {
|
||||
copy->flags |= MRB_HASH_DEFAULT;
|
||||
@@ -663,22 +677,22 @@ check_kdict_i(mrb_state *mrb, mrb_value key, mrb_value val, void *data)
|
||||
void
|
||||
mrb_hash_check_kdict(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
seglist *sg;
|
||||
htable *t;
|
||||
|
||||
sg = RHASH_TBL(self);
|
||||
if (!sg || sg_size(mrb, sg) == 0) return;
|
||||
sg_foreach(mrb, sg, check_kdict_i, NULL);
|
||||
t = RHASH_TBL(self);
|
||||
if (!t || t->size == 0) return;
|
||||
ht_foreach(mrb, t, check_kdict_i, NULL);
|
||||
}
|
||||
|
||||
MRB_API mrb_value
|
||||
mrb_hash_dup(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
struct RHash* copy;
|
||||
seglist *orig_h;
|
||||
htable *orig_h;
|
||||
|
||||
orig_h = RHASH_TBL(self);
|
||||
copy = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class);
|
||||
copy->ht = orig_h ? sg_copy(mrb, orig_h) : NULL;
|
||||
copy->ht = orig_h ? ht_copy(mrb, orig_h) : NULL;
|
||||
return mrb_obj_value(copy);
|
||||
}
|
||||
|
||||
@@ -688,7 +702,7 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key)
|
||||
mrb_value val;
|
||||
mrb_sym mid;
|
||||
|
||||
if (sg_get(mrb, RHASH_TBL(hash), key, &val)) {
|
||||
if (ht_get(mrb, RHASH_TBL(hash), key, &val)) {
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -705,7 +719,7 @@ mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def)
|
||||
{
|
||||
mrb_value val;
|
||||
|
||||
if (sg_get(mrb, RHASH_TBL(hash), key, &val)) {
|
||||
if (ht_get(mrb, RHASH_TBL(hash), key, &val)) {
|
||||
return val;
|
||||
}
|
||||
/* not found */
|
||||
@@ -718,7 +732,7 @@ mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val)
|
||||
mrb_hash_modify(mrb, hash);
|
||||
|
||||
key = KEY(key);
|
||||
sg_put(mrb, RHASH_TBL(hash), key, val);
|
||||
ht_put(mrb, RHASH_TBL(hash), key, val);
|
||||
mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), key);
|
||||
mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), val);
|
||||
return;
|
||||
@@ -744,7 +758,7 @@ mrb_hash_modify(mrb_state *mrb, mrb_value hash)
|
||||
}
|
||||
|
||||
if (!RHASH_TBL(hash)) {
|
||||
RHASH_TBL(hash) = sg_new(mrb);
|
||||
RHASH_TBL(hash) = ht_new(mrb);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -985,10 +999,10 @@ mrb_hash_set_default_proc(mrb_state *mrb, mrb_value hash)
|
||||
MRB_API mrb_value
|
||||
mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key)
|
||||
{
|
||||
seglist *sg = RHASH_TBL(hash);
|
||||
htable *t = RHASH_TBL(hash);
|
||||
mrb_value del_val;
|
||||
|
||||
if (sg_del(mrb, sg, key, &del_val)) {
|
||||
if (ht_del(mrb, t, key, &del_val)) {
|
||||
return del_val;
|
||||
}
|
||||
|
||||
@@ -1006,15 +1020,15 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self)
|
||||
return mrb_hash_delete_key(mrb, self, key);
|
||||
}
|
||||
|
||||
/* find first element in segment list, and remove it. */
|
||||
/* find first element in a hash table, and remove it. */
|
||||
static void
|
||||
sg_shift(mrb_state *mrb, seglist *t, mrb_value *kp, mrb_value *vp)
|
||||
ht_shift(mrb_state *mrb, htable *t, mrb_value *kp, mrb_value *vp)
|
||||
{
|
||||
segment *seg = t->rootseg;
|
||||
mrb_int i;
|
||||
|
||||
while (seg) {
|
||||
for (i=0; i<MRB_SG_SEGMENT_SIZE; i++) {
|
||||
for (i=0; i<seg->size; i++) {
|
||||
mrb_value key;
|
||||
|
||||
if (!seg->next && i >= t->last_len) {
|
||||
@@ -1050,13 +1064,13 @@ sg_shift(mrb_state *mrb, seglist *t, mrb_value *kp, mrb_value *vp)
|
||||
static mrb_value
|
||||
mrb_hash_shift(mrb_state *mrb, mrb_value hash)
|
||||
{
|
||||
seglist *sg = RHASH_TBL(hash);
|
||||
htable *t = RHASH_TBL(hash);
|
||||
|
||||
mrb_hash_modify(mrb, hash);
|
||||
if (sg && sg_size(mrb, sg) > 0) {
|
||||
if (t && t->size > 0) {
|
||||
mrb_value del_key, del_val;
|
||||
|
||||
sg_shift(mrb, sg, &del_key, &del_val);
|
||||
ht_shift(mrb, t, &del_key, &del_val);
|
||||
mrb_gc_protect(mrb, del_key);
|
||||
mrb_gc_protect(mrb, del_val);
|
||||
return mrb_assoc_new(mrb, del_key, del_val);
|
||||
@@ -1088,11 +1102,11 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash)
|
||||
MRB_API mrb_value
|
||||
mrb_hash_clear(mrb_state *mrb, mrb_value hash)
|
||||
{
|
||||
seglist *sg = RHASH_TBL(hash);
|
||||
htable *t = RHASH_TBL(hash);
|
||||
|
||||
mrb_hash_modify(mrb, hash);
|
||||
if (sg) {
|
||||
sg_free(mrb, sg);
|
||||
if (t) {
|
||||
ht_free(mrb, t);
|
||||
RHASH_TBL(hash) = NULL;
|
||||
}
|
||||
return hash;
|
||||
@@ -1144,19 +1158,19 @@ mrb_hash_aset(mrb_state *mrb, mrb_value self)
|
||||
static mrb_value
|
||||
mrb_hash_size_m(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
seglist *sg = RHASH_TBL(self);
|
||||
htable *t = RHASH_TBL(self);
|
||||
|
||||
if (!sg) return mrb_fixnum_value(0);
|
||||
return mrb_fixnum_value(sg_size(mrb, sg));
|
||||
if (!t) return mrb_fixnum_value(0);
|
||||
return mrb_fixnum_value(t->size);
|
||||
}
|
||||
|
||||
MRB_API mrb_bool
|
||||
mrb_hash_empty_p(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
seglist *sg = RHASH_TBL(self);
|
||||
htable *t = RHASH_TBL(self);
|
||||
|
||||
if (!sg) return TRUE;
|
||||
return sg_size(mrb, sg) == 0;
|
||||
if (!t) return TRUE;
|
||||
return t->size == 0;
|
||||
}
|
||||
|
||||
/* 15.2.13.4.12 */
|
||||
@@ -1212,14 +1226,14 @@ hash_keys_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p)
|
||||
MRB_API mrb_value
|
||||
mrb_hash_keys(mrb_state *mrb, mrb_value hash)
|
||||
{
|
||||
seglist *sg = RHASH_TBL(hash);
|
||||
size_t size;
|
||||
htable *t = RHASH_TBL(hash);
|
||||
mrb_int size;
|
||||
mrb_value ary;
|
||||
|
||||
if (!sg || (size = sg_size(mrb, sg)) == 0)
|
||||
if (!t || (size = t->size) == 0)
|
||||
return mrb_ary_new(mrb);
|
||||
ary = mrb_ary_new_capa(mrb, size);
|
||||
sg_foreach(mrb, sg, hash_keys_i, (void*)&ary);
|
||||
ht_foreach(mrb, t, hash_keys_i, (void*)&ary);
|
||||
return ary;
|
||||
}
|
||||
|
||||
@@ -1246,14 +1260,14 @@ hash_vals_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p)
|
||||
MRB_API mrb_value
|
||||
mrb_hash_values(mrb_state *mrb, mrb_value hash)
|
||||
{
|
||||
seglist *sg = RHASH_TBL(hash);
|
||||
size_t size;
|
||||
htable *t = RHASH_TBL(hash);
|
||||
mrb_int size;
|
||||
mrb_value ary;
|
||||
|
||||
if (!sg || (size = sg_size(mrb, sg)) == 0)
|
||||
if (!t || (size = t->size) == 0)
|
||||
return mrb_ary_new(mrb);
|
||||
ary = mrb_ary_new_capa(mrb, size);
|
||||
sg_foreach(mrb, sg, hash_vals_i, (void*)&ary);
|
||||
ht_foreach(mrb, t, hash_vals_i, (void*)&ary);
|
||||
return ary;
|
||||
}
|
||||
|
||||
@@ -1279,10 +1293,10 @@ mrb_hash_values(mrb_state *mrb, mrb_value hash)
|
||||
MRB_API mrb_bool
|
||||
mrb_hash_key_p(mrb_state *mrb, mrb_value hash, mrb_value key)
|
||||
{
|
||||
seglist *sg;
|
||||
htable *t;
|
||||
|
||||
sg = RHASH_TBL(hash);
|
||||
if (sg_get(mrb, sg, key, NULL)) {
|
||||
t = RHASH_TBL(hash);
|
||||
if (ht_get(mrb, t, key, NULL)) {
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
@@ -1340,23 +1354,23 @@ mrb_hash_has_value(mrb_state *mrb, mrb_value hash)
|
||||
mrb_get_args(mrb, "o", &val);
|
||||
arg.found = FALSE;
|
||||
arg.val = val;
|
||||
sg_foreach(mrb, RHASH_TBL(hash), hash_has_value_i, &arg);
|
||||
ht_foreach(mrb, RHASH_TBL(hash), hash_has_value_i, &arg);
|
||||
return mrb_bool_value(arg.found);
|
||||
}
|
||||
|
||||
static int
|
||||
merge_i(mrb_state *mrb, mrb_value key, mrb_value val, void *data)
|
||||
{
|
||||
seglist *h1 = (seglist*)data;
|
||||
htable *h1 = (htable*)data;
|
||||
|
||||
sg_put(mrb, h1, key, val);
|
||||
ht_put(mrb, h1, key, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MRB_API void
|
||||
mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2)
|
||||
{
|
||||
seglist *h1, *h2;
|
||||
htable *h1, *h2;
|
||||
|
||||
mrb_hash_modify(mrb, hash1);
|
||||
hash2 = mrb_ensure_hash_type(mrb, hash2);
|
||||
@@ -1365,10 +1379,10 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2)
|
||||
|
||||
if (!h2) return;
|
||||
if (!h1) {
|
||||
RHASH_TBL(hash1) = sg_copy(mrb, h2);
|
||||
RHASH_TBL(hash1) = ht_copy(mrb, h2);
|
||||
return;
|
||||
}
|
||||
sg_foreach(mrb, h2, merge_i, h1);
|
||||
ht_foreach(mrb, h2, merge_i, h1);
|
||||
mrb_write_barrier(mrb, (struct RBasic*)RHASH(hash1));
|
||||
return;
|
||||
}
|
||||
@@ -1389,7 +1403,7 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2)
|
||||
static mrb_value
|
||||
mrb_hash_rehash(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
sg_compact(mrb, RHASH_TBL(self));
|
||||
ht_compact(mrb, RHASH_TBL(self));
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user