diff --git a/ChangeLog b/ChangeLog index 9550be8e5d0ce0..bbd4c2ee7b5d9e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Wed Mar 3 18:35:55 2010 Yukihiro Matsumoto + + * hash.c (rb_hash_select_bang): add #select! and keep_if to Hash. + + * hash.c (env_select_bang): ..and to ENV. + Wed Mar 3 15:54:20 2010 Yukihiro Matsumoto * lib/matrix.rb (Vector#each2, collect2): small refactoring. diff --git a/hash.c b/hash.c index 51537e91b638e6..5eba21654ef7aa 100644 --- a/hash.c +++ b/hash.c @@ -989,6 +989,57 @@ rb_hash_select(VALUE hash) return result; } +static int +keep_if_i(VALUE key, VALUE value, VALUE hash) +{ + if (key == Qundef) return ST_CONTINUE; + if (!RTEST(rb_yield_values(2, key, value))) { + return ST_DELETE; + } + return ST_CONTINUE; +} + +/* + * call-seq: + * hsh.select! {| key, value | block } -> hsh or nil + * + * Equivalent to Hash#keep_if, but returns + * nil if no changes were made. + */ + +VALUE +rb_hash_select_bang(VALUE hash) +{ + st_index_t n; + + RETURN_ENUMERATOR(hash, 0, 0); + rb_hash_modify(hash); + if (!RHASH(hash)->ntbl) + return Qnil; + n = RHASH(hash)->ntbl->num_entries; + rb_hash_foreach(hash, keep_if_i, hash); + if (n == RHASH(hash)->ntbl->num_entries) return Qnil; + return hash; +} + +/* + * call-seq: + * hsh.keep_if {| key, value | block } -> hsh + * + * Deletes every key-value pair from hsh for which block + * evaluates to false. + * + */ + +VALUE +rb_hash_keep_if(VALUE hash) +{ + RETURN_ENUMERATOR(hash, 0, 0); + rb_hash_modify(hash); + rb_hash_foreach(hash, keep_if_i, hash); + return hash; +} + static int clear_i(VALUE key, VALUE value, VALUE dummy) { @@ -2367,6 +2418,37 @@ env_select(VALUE ehash) return result; } +static VALUE +env_select_bang(VALUE ehash) +{ + volatile VALUE keys; + long i; + int del = 0; + + RETURN_ENUMERATOR(ehash, 0, 0); + keys = env_keys(); /* rb_secure(4); */ + for (i=0; i2,3=>4,5=>6} + assert_equal({3=>4,5=>6}, h.keep_if {|k, v| k + v >= 7 }) + h = {1=>2,3=>4,5=>6} + assert_equal({1=>2,3=>4,5=>6}, h.keep_if{true}) + end + def test_dup for taint in [ false, true ] for untrust in [ false, true ] @@ -736,6 +743,14 @@ def test_select assert_equal({3=>4,5=>6}, {1=>2,3=>4,5=>6}.select {|k, v| k + v >= 7 }) end + def test_select! + h = {1=>2,3=>4,5=>6} + assert_equal(h, h.select! {|k, v| k + v >= 7 }) + assert_equal({3=>4,5=>6}, h) + h = {1=>2,3=>4,5=>6} + assert_equal(nil, h.select!{true}) + end + def test_clear2 assert_equal({}, {1=>2,3=>4,5=>6}.clear) h = {1=>2,3=>4,5=>6}