diff options
author | shyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-08-22 03:42:36 +0000 |
---|---|---|
committer | shyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-08-22 03:42:36 +0000 |
commit | cb0bb993f245a39fd91a5bb358b7cbb6a56099ea (patch) | |
tree | 75a9d468cad52783c609b29bdf1bb9d703d53490 /hash.c | |
parent | e66f118a9bf4e727ed63003af56a028779429482 (diff) |
* hash.c (rb_hash_delete_key): delete the entry without calling block.
* hash.c (rb_hash_shift): should consider iter_lev too.
* hash.c (delete_if_i): use rb_hash_delete_key() so that the block
isn't called twice. [ruby-core:11556]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8_6@13224 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'hash.c')
-rw-r--r-- | hash.c | 61 |
1 files changed, 46 insertions, 15 deletions
@@ -590,6 +590,23 @@ index_i(key, value, args) return ST_CONTINUE; } +static VALUE +rb_hash_delete_key(hash, key) + VALUE hash, key; +{ + st_data_t ktmp = (st_data_t)key, val; + + if (RHASH(hash)->iter_lev > 0) { + if (st_delete_safe(RHASH(hash)->tbl, &ktmp, &val, Qundef)) { + FL_SET(hash, HASH_DELETED); + return (VALUE)val; + } + } + else if (st_delete(RHASH(hash)->tbl, &ktmp, &val)) + return (VALUE)val; + return Qundef; +} + /* * call-seq: * hsh.index(value) => key @@ -669,14 +686,8 @@ rb_hash_delete(hash, key) VALUE val; rb_hash_modify(hash); - if (RHASH(hash)->iter_lev > 0) { - if (st_delete_safe(RHASH(hash)->tbl, (st_data_t*)&key, &val, Qundef)) { - FL_SET(hash, HASH_DELETED); - return val; - } - } - else if (st_delete(RHASH(hash)->tbl, (st_data_t*)&key, &val)) - return val; + val = rb_hash_delete_key(hash, key); + if (val != Qundef) return val; if (rb_block_given_p()) { return rb_yield(key); } @@ -684,7 +695,6 @@ rb_hash_delete(hash, key) } struct shift_var { - int stop; VALUE key; VALUE val; }; @@ -695,13 +705,23 @@ shift_i(key, value, var) struct shift_var *var; { if (key == Qundef) return ST_CONTINUE; - if (var->stop) return ST_STOP; - var->stop = 1; + if (var->key != Qundef) return ST_STOP; var->key = key; var->val = value; return ST_DELETE; } +static int +shift_i_safe(key, value, var) + VALUE key, value; + struct shift_var *var; +{ + if (key == Qundef) return ST_CONTINUE; + var->key = key; + var->val = value; + return ST_STOP; +} + /* * call-seq: * hsh.shift -> anArray or obj @@ -722,10 +742,21 @@ rb_hash_shift(hash) struct shift_var var; rb_hash_modify(hash); - var.stop = 0; - rb_hash_foreach(hash, shift_i, (st_data_t)&var); + var.key = Qundef; + if (RHASH(hash)->iter_lev > 0) { + rb_hash_foreach(hash, shift_i_safe, (st_data_t)&var); + if (var.key != Qundef) { + st_data_t key = var.key; + if (st_delete_safe(RHASH(hash)->tbl, &key, 0, Qundef)) { + FL_SET(hash, HASH_DELETED); + } + } + } + else { + rb_hash_foreach(hash, shift_i, (st_data_t)&var); + } - if (var.stop) { + if (var.key != Qundef) { return rb_assoc_new(var.key, var.val); } else if (FL_TEST(hash, HASH_PROC_DEFAULT)) { @@ -742,7 +773,7 @@ delete_if_i(key, value, hash) { if (key == Qundef) return ST_CONTINUE; if (RTEST(rb_yield_values(2, key, value))) { - rb_hash_delete(hash, key); + rb_hash_delete_key(hash, key); } return ST_CONTINUE; } |