summaryrefslogtreecommitdiff
path: root/hash.c
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-08-29 23:12:21 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-08-29 23:12:21 +0000
commit2a4c4f7b0c147585119036c43c1d04f73621e510 (patch)
treea25d27ffdd53b0b5912e6746131b97a245a3732d /hash.c
parent3d7f8c2320d13fcc0c12e8910d70a812dab2f681 (diff)
* include/ruby/intern.h: declare rb_hash_tbl.
* include/ruby/ruby.h (RHash): delay st_table allocation. rename tbl field to ntbl to detect direct reference to the st_table as a compile error. (RHASH_TBL): abstract accessor defined. (RHASH_ITER_LEV): ditto. (RHASH_IFNONE): ditto. (RHASH_SIZE): ditto. (RHASH_EMPTY_P): ditto. * hash.c: delay st_table allocation. * gc.c: replace tbl by ntbl. * array.c: replace direct field accessor by abstract field accessor such as RHASH(hash)->tbl to RHASH_TBL(hash). * marshal.c: ditto. * insns.def: ditto. * ext/iconv/iconv.c: ditto. * ext/json/ext/generator/generator.c: ditto. * ext/json/ext/parser/parser.c: ditto. * ext/syck/rubyext.c: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13309 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'hash.c')
-rw-r--r--hash.c108
1 files changed, 72 insertions, 36 deletions
diff --git a/hash.c b/hash.c
index 27c0c5bdfc..8fbc7b9416 100644
--- a/hash.c
+++ b/hash.c
@@ -147,10 +147,10 @@ hash_foreach_iter(VALUE key, VALUE value, struct hash_foreach_arg *arg)
int status;
st_table *tbl;
- tbl = RHASH(arg->hash)->tbl;
+ tbl = RHASH(arg->hash)->ntbl;
if (key == Qundef) return ST_CONTINUE;
status = (*arg->func)(key, value, arg->arg);
- if (RHASH(arg->hash)->tbl != tbl) {
+ if (RHASH(arg->hash)->ntbl != tbl) {
rb_raise(rb_eRuntimeError, "rehash occurred during iteration");
}
switch (status) {
@@ -172,7 +172,7 @@ hash_foreach_ensure(VALUE hash)
if (RHASH(hash)->iter_lev == 0) {
if (FL_TEST(hash, HASH_DELETED)) {
- st_cleanup_safe(RHASH(hash)->tbl, Qundef);
+ st_cleanup_safe(RHASH(hash)->ntbl, Qundef);
FL_UNSET(hash, HASH_DELETED);
}
}
@@ -182,7 +182,7 @@ hash_foreach_ensure(VALUE hash)
static VALUE
hash_foreach_call(struct hash_foreach_arg *arg)
{
- if (st_foreach(RHASH(arg->hash)->tbl, hash_foreach_iter, (st_data_t)arg)) {
+ if (st_foreach(RHASH(arg->hash)->ntbl, hash_foreach_iter, (st_data_t)arg)) {
rb_raise(rb_eRuntimeError, "hash modified during iteration");
}
return Qnil;
@@ -193,6 +193,8 @@ rb_hash_foreach(VALUE hash, int (*func)(ANYARGS), VALUE farg)
{
struct hash_foreach_arg arg;
+ if (!RHASH(hash)->ntbl)
+ return;
RHASH(hash)->iter_lev++;
arg.hash = hash;
arg.func = (rb_foreach_func *)func;
@@ -216,7 +218,7 @@ hash_alloc(VALUE klass)
{
VALUE hash = hash_alloc0(klass);
- RHASH(hash)->tbl = st_init_table(&objhash);
+ RHASH(hash)->ntbl = 0;
return hash;
}
@@ -228,14 +230,29 @@ rb_hash_new(void)
}
static void
-rb_hash_modify(VALUE hash)
+rb_hash_modify_check(VALUE hash)
{
- if (!RHASH(hash)->tbl) rb_raise(rb_eTypeError, "uninitialized Hash");
if (OBJ_FROZEN(hash)) rb_error_frozen("hash");
if (!OBJ_TAINTED(hash) && rb_safe_level() >= 4)
rb_raise(rb_eSecurityError, "Insecure: can't modify hash");
}
+struct st_table *
+rb_hash_tbl(VALUE hash)
+{
+ if (!RHASH(hash)->ntbl) {
+ RHASH(hash)->ntbl = st_init_table(&objhash);
+ }
+ return RHASH(hash)->ntbl;
+}
+
+static void
+rb_hash_modify(VALUE hash)
+{
+ rb_hash_modify_check(hash);
+ rb_hash_tbl(hash);
+}
+
/*
* call-seq:
* Hash.new => hash
@@ -313,7 +330,9 @@ rb_hash_s_create(int argc, VALUE *argv, VALUE klass)
if (argc == 1 && TYPE(argv[0]) == T_HASH) {
hash = hash_alloc0(klass);
- RHASH(hash)->tbl = st_copy(RHASH(argv[0])->tbl);
+ if (RHASH(argv[0])->ntbl) {
+ RHASH(hash)->ntbl = st_copy(RHASH(argv[0])->ntbl);
+ }
return hash;
}
@@ -388,11 +407,13 @@ rb_hash_rehash(VALUE hash)
if (RHASH(hash)->iter_lev > 0) {
rb_raise(rb_eRuntimeError, "rehash during iteration");
}
- rb_hash_modify(hash);
- tbl = st_init_table_with_size(RHASH(hash)->tbl->type, RHASH(hash)->tbl->num_entries);
+ rb_hash_modify_check(hash);
+ if (!RHASH(hash)->ntbl)
+ return hash;
+ tbl = st_init_table_with_size(RHASH(hash)->ntbl->type, RHASH(hash)->ntbl->num_entries);
rb_hash_foreach(hash, rb_hash_rehash_i, (st_data_t)tbl);
- st_free_table(RHASH(hash)->tbl);
- RHASH(hash)->tbl = tbl;
+ st_free_table(RHASH(hash)->ntbl);
+ RHASH(hash)->ntbl = tbl;
return hash;
}
@@ -416,7 +437,7 @@ rb_hash_aref(VALUE hash, VALUE key)
{
VALUE val;
- if (!st_lookup(RHASH(hash)->tbl, key, &val)) {
+ if (!RHASH(hash)->ntbl || !st_lookup(RHASH(hash)->ntbl, key, &val)) {
return rb_funcall(hash, id_default, 1, key);
}
return val;
@@ -427,7 +448,7 @@ rb_hash_lookup(VALUE hash, VALUE key)
{
VALUE val;
- if (!st_lookup(RHASH(hash)->tbl, key, &val)) {
+ if (!RHASH(hash)->ntbl || !st_lookup(RHASH(hash)->ntbl, key, &val)) {
return Qnil; /* without Hash#default */
}
return val;
@@ -475,7 +496,7 @@ rb_hash_fetch(int argc, VALUE *argv, VALUE hash)
if (block_given && argc == 2) {
rb_warn("block supersedes default value argument");
}
- if (!st_lookup(RHASH(hash)->tbl, key, &val)) {
+ if (!RHASH(hash)->ntbl || !st_lookup(RHASH(hash)->ntbl, key, &val)) {
if (block_given) return rb_yield(key);
if (argc == 1) {
rb_raise(rb_eKeyError, "key not found");
@@ -620,13 +641,15 @@ rb_hash_delete_key(VALUE hash, VALUE key)
{
st_data_t ktmp = (st_data_t)key, val;
+ if (!RHASH(hash)->ntbl)
+ return Qundef;
if (RHASH(hash)->iter_lev > 0) {
- if (st_delete_safe(RHASH(hash)->tbl, &ktmp, &val, Qundef)) {
+ if (st_delete_safe(RHASH(hash)->ntbl, &ktmp, &val, Qundef)) {
FL_SET(hash, HASH_DELETED);
return (VALUE)val;
}
}
- else if (st_delete(RHASH(hash)->tbl, &ktmp, &val))
+ else if (st_delete(RHASH(hash)->ntbl, &ktmp, &val))
return (VALUE)val;
return Qundef;
}
@@ -765,9 +788,12 @@ rb_hash_delete_if(VALUE hash)
VALUE
rb_hash_reject_bang(VALUE hash)
{
- int n = RHASH(hash)->tbl->num_entries;
+ int n;
+ if (!RHASH(hash)->ntbl)
+ return Qnil;
+ n = RHASH(hash)->ntbl->num_entries;
rb_hash_delete_if(hash);
- if (n == RHASH(hash)->tbl->num_entries) return Qnil;
+ if (n == RHASH(hash)->ntbl->num_entries) return Qnil;
return hash;
}
@@ -861,12 +887,14 @@ clear_i(VALUE key, VALUE value, VALUE dummy)
static VALUE
rb_hash_clear(VALUE hash)
{
- rb_hash_modify(hash);
- if (RHASH(hash)->tbl->num_entries > 0) {
+ rb_hash_modify_check(hash);
+ if (!RHASH(hash)->ntbl)
+ return hash;
+ if (RHASH(hash)->ntbl->num_entries > 0) {
if (RHASH(hash)->iter_lev > 0)
rb_hash_foreach(hash, clear_i, 0);
else
- st_clear(RHASH(hash)->tbl);
+ st_clear(RHASH(hash)->ntbl);
}
return hash;
@@ -894,11 +922,11 @@ VALUE
rb_hash_aset(VALUE hash, VALUE key, VALUE val)
{
rb_hash_modify(hash);
- if (TYPE(key) != T_STRING || st_lookup(RHASH(hash)->tbl, key, 0)) {
- st_insert(RHASH(hash)->tbl, key, val);
+ if (TYPE(key) != T_STRING || st_lookup(RHASH(hash)->ntbl, key, 0)) {
+ st_insert(RHASH(hash)->ntbl, key, val);
}
else {
- st_add_direct(RHASH(hash)->tbl, rb_str_new4(key), val);
+ st_add_direct(RHASH(hash)->ntbl, rb_str_new4(key), val);
}
return val;
}
@@ -959,7 +987,9 @@ rb_hash_replace(VALUE hash, VALUE hash2)
static VALUE
rb_hash_size(VALUE hash)
{
- return INT2FIX(RHASH(hash)->tbl->num_entries);
+ if (!RHASH(hash)->ntbl)
+ return INT2FIX(0);
+ return INT2FIX(RHASH(hash)->ntbl->num_entries);
}
@@ -976,9 +1006,7 @@ rb_hash_size(VALUE hash)
static VALUE
rb_hash_empty_p(VALUE hash)
{
- if (RHASH(hash)->tbl->num_entries == 0)
- return Qtrue;
- return Qfalse;
+ return RHASH_EMPTY_P(hash) ? Qtrue : Qfalse;
}
static int
@@ -1190,7 +1218,7 @@ inspect_hash(VALUE hash, VALUE dummy, int recur)
static VALUE
rb_hash_inspect(VALUE hash)
{
- if (RHASH(hash)->tbl == 0 || RHASH(hash)->tbl->num_entries == 0)
+ if (RHASH_EMPTY_P(hash))
return rb_str_new2("{}");
return rb_exec_recursive(inspect_hash, hash, 0);
}
@@ -1288,7 +1316,9 @@ rb_hash_values(VALUE hash)
static VALUE
rb_hash_has_key(VALUE hash, VALUE key)
{
- if (st_lookup(RHASH(hash)->tbl, key, 0)) {
+ if (!RHASH(hash)->ntbl)
+ return Qfalse;
+ if (st_lookup(RHASH(hash)->ntbl, key, 0)) {
return Qtrue;
}
return Qfalse;
@@ -1380,15 +1410,17 @@ hash_equal(VALUE hash1, VALUE hash2, int eql)
}
return rb_equal(hash2, hash1);
}
- if (RHASH(hash1)->tbl->num_entries != RHASH(hash2)->tbl->num_entries)
+ if (RHASH_SIZE(hash1) != RHASH_SIZE(hash2))
return Qfalse;
+ if (!RHASH(hash1)->ntbl || !RHASH(hash2)->ntbl)
+ return Qtrue;
#if 0
if (!(rb_equal(RHASH(hash1)->ifnone, RHASH(hash2)->ifnone) &&
FL_TEST(hash1, HASH_PROC_DEFAULT) == FL_TEST(hash2, HASH_PROC_DEFAULT)))
return Qfalse;
#endif
- data.tbl = RHASH(hash2)->tbl;
+ data.tbl = RHASH(hash2)->ntbl;
data.result = Qtrue;
rb_hash_foreach(hash1, eql ? eql_i : equal_i, (st_data_t)&data);
@@ -1451,7 +1483,9 @@ recursive_hash(VALUE hash, VALUE dummy, int recur)
if (recur) {
return LONG2FIX(0);
}
- hval = RHASH(hash)->tbl->num_entries;
+ if (!RHASH(hash)->ntbl)
+ return LONG2FIX(0);
+ hval = RHASH(hash)->ntbl->num_entries;
rb_hash_foreach(hash, hash_i, (st_data_t)&hval);
return INT2FIX(hval);
}
@@ -1695,7 +1729,7 @@ static VALUE
rb_hash_compare_by_id(VALUE hash)
{
rb_hash_modify(hash);
- RHASH(hash)->tbl->type = &identhash;
+ RHASH(hash)->ntbl->type = &identhash;
rb_hash_rehash(hash);
return hash;
}
@@ -1712,7 +1746,9 @@ rb_hash_compare_by_id(VALUE hash)
static VALUE
rb_hash_compare_by_id_p(VALUE hash)
{
- if (RHASH(hash)->tbl->type == &identhash) {
+ if (!RHASH(hash)->ntbl)
+ return Qfalse;
+ if (RHASH(hash)->ntbl->type == &identhash) {
return Qtrue;
}
return Qfalse;