Project

General

Profile

Feature #9970 ยป hash-map-keys-and-map-values.diff

seantheprogrammer (Sean Griffin), 06/21/2014 09:34 PM

View differences:

hash.c (working copy)
return Qfalse;
}
VALUE
map_hash(VALUE hash, int (*func)(ANYARGS))
{
VALUE result;
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
result = rb_hash_new();
if (!RHASH_EMPTY_P(hash)) {
rb_hash_foreach(hash, func, result);
}
return result;
}
static int
map_keys_i(VALUE key, VALUE value, VALUE result)
{
rb_hash_aset(result, rb_yield(key), value);
return ST_CONTINUE;
}
/*
* call-seq:
* hsh.map_keys {| key | block } -> a_hash
* hsh.map_keys -> an_enumerator
*
* Returns a new hash, with the keys computed from running <code>block<code>
* once for each key in the hash, and the values unchanged.
*
* If no block is given, an enumerator is returned instead.
*
* h = { "a" => 100, "b" => 200 }
* h.map_keys { |key| key + '!' } #=> { "a!" => 100, "b!" => 200 }
*
*/
VALUE
rb_hash_map_keys(VALUE hash)
{
return map_hash(hash, map_keys_i);
}
/*
* call-seq:
* hsh.map_keys! {| key | block } -> hsh or nil
* hsh.map_keys! -> an_enumerator
*
* Replaces every key in the hash with the result of calling <code>block</code>
* once for each key in the hash. Returns <code>nil</code> if no changes were made.
*
* If no block is given, an enumerator is returned instead.
*
* h = { "a" => 100, "b" => 200 }
* h.map_keys! { |key| key + '!' } #=> { "a!" => 100, "b!" => 200 }
*
*/
VALUE
rb_hash_map_keys_bang(VALUE hash)
{
st_index_t n;
VALUE keys;
long i;
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
rb_hash_modify(hash);
n = RHASH_SIZE(hash);
if (!n) return Qnil;
keys = rb_hash_keys(hash);
for (i = 0; i < RARRAY_LEN(keys); i++) {
VALUE key = RARRAY_AREF(keys, i);
rb_hash_aset(hash, rb_yield(key), rb_hash_delete(hash, key));
}
return hash;
}
static int
map_values_i(VALUE key, VALUE value, VALUE result)
{
rb_hash_aset(result, key, rb_yield(value));
return ST_CONTINUE;
}
/*
* call-seq:
* hsh.map_values {| value | block } -> a_hash
* hsh.map_values -> an_enumerator
*
* Returns a new hash, with the values computed from running <code>block<code>
* once for each value in the hash, and the values unchanged.
*
* If no block is given, an enumerator is returned instead.
*
* h = { "a" => 100, "b" => 200 }
* h.map_values { |value| value * 2 } #=> { "a" => 200, "b" => 400 }
*
*/
VALUE
rb_hash_map_values(VALUE hash)
{
return map_hash(hash, map_values_i);
}
/*
* call-seq:
* hsh.map_values! {| value | block } -> hsh or nil
* hsh.map_values! -> an_enumerator
*
* Replaces every value in the hash with the result of calling <code>block</code>
* once for each value in the hash, and the keys unchanged.
*
* If no block is given, an enumerator is returned instead.
*
* h = { "a" => 100, "b" => 200 }
* h.map_values! { |value| value * 2 } #=> { "a" => 200, "b" => 400 }
*
*/
VALUE
rb_hash_map_values_bang(VALUE hash)
{
st_index_t n;
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
n = RHASH_SIZE(hash);
if (!n) return Qnil;
rb_hash_foreach(hash, map_values_i, hash);
return hash;
}
static int path_tainted = -1;
static char **origenviron;
......
rb_define_method(rb_cHash, "assoc", rb_hash_assoc, 1);
rb_define_method(rb_cHash, "rassoc", rb_hash_rassoc, 1);
rb_define_method(rb_cHash, "flatten", rb_hash_flatten, -1);
rb_define_method(rb_cHash, "map_keys", rb_hash_map_keys, 0);
rb_define_method(rb_cHash, "map_keys!", rb_hash_map_keys_bang, 0);
rb_define_method(rb_cHash, "map_values", rb_hash_map_values, 0);
rb_define_method(rb_cHash, "map_values!", rb_hash_map_values_bang, 0);
rb_define_method(rb_cHash,"include?", rb_hash_has_key, 1);
rb_define_method(rb_cHash,"member?", rb_hash_has_key, 1);
test/ruby/test_hash.rb (working copy)
assert_equal(bug9381, hash[wrapper.new(5)])
end
def test_map_keys
original = { 'a' => 'a', 'b' => 'b' }
mapped = original.map_keys { |key| key + '!' }
assert_equal({ 'a' => 'a', 'b' => 'b' }, original)
assert_equal({ 'a!' => 'a', 'b!' => 'b' }, mapped)
end
def test_map_keys_bang
original = { 'a' => 'a', 'b' => 'b' }
mapped = original.map_keys! { |key| key + '!' }
assert_equal({ 'a!' => 'a', 'b!' => 'b' }, original)
assert_equal({ 'a!' => 'a', 'b!' => 'b' }, mapped)
end
def test_map_keys_bang_on_empty_hash
original = {}
mapped = original.map_keys! { |key| key + '!' }
assert_equal({}, original)
assert_nil mapped
end
def test_map_values
original = { 'a' => 'a', 'b' => 'b' }
mapped = original.map_values { |value| value + '!' }
assert_equal({ 'a' => 'a', 'b' => 'b' }, original)
assert_equal({ 'a' => 'a!', 'b' => 'b!' }, mapped)
end
def test_map_values_bang
original = { 'a' => 'a', 'b' => 'b' }
mapped = original.map_values! { |value| value + '!' }
assert_equal({ 'a' => 'a!', 'b' => 'b!' }, original)
assert_equal({ 'a' => 'a!', 'b' => 'b!' }, mapped)
end
def test_map_values_bang_on_empty_hash
original = {}
mapped = original.map_values! { |value| value + '!' }
assert_equal({}, original)
assert_nil mapped
end
class TestSubHash < TestHash
class SubHash < Hash
def reject(*)
    (1-1/1)