diff options
author | John Hawthorn <john@hawthorn.email> | 2019-09-11 09:02:22 -0700 |
---|---|---|
committer | Aaron Patterson <tenderlove@github.com> | 2019-09-11 14:23:11 -0700 |
commit | 21994b7fd686f263544fcac1616ecf3189fb78b3 (patch) | |
tree | 6c8f94bed0dc5c37a3bee7578043aff75f407392 /hash.c | |
parent | 14e3731059246fcd093daa36fd0139d0287e633f (diff) | |
download | ruby-21994b7fd686f263544fcac1616ecf3189fb78b3.tar.gz |
Avoid rehashing keys in transform_values
Previously, calling transform_values would call rb_hash_aset for each
key, needing to rehash it and look up its location.
Instead, we can use rb_hash_stlike_foreach_with_replace to replace the
values as we iterate without rehashing the keys.
Diffstat (limited to 'hash.c')
-rw-r--r-- | hash.c | 24 |
1 files changed, 17 insertions, 7 deletions
@@ -3129,10 +3129,16 @@ rb_hash_transform_keys_bang(VALUE hash) } static int -transform_values_i(VALUE key, VALUE value, VALUE result) +transform_values_foreach_func(st_data_t key, st_data_t value, st_data_t argp, int error) { - VALUE new_value = rb_yield(value); - rb_hash_aset(result, key, new_value); + return ST_REPLACE; +} + +static int +transform_values_foreach_replace(st_data_t *key, st_data_t *value, st_data_t argp, int existing) +{ + VALUE new_value = rb_yield((VALUE)*value); + *value = new_value; return ST_CONTINUE; } @@ -3159,9 +3165,10 @@ rb_hash_transform_values(VALUE hash) VALUE result; RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); - result = rb_hash_new_with_size(RHASH_SIZE(hash)); + result = hash_dup(hash, rb_cHash, 0); + if (!RHASH_EMPTY_P(hash)) { - rb_hash_foreach(hash, transform_values_i, result); + rb_hash_stlike_foreach_with_replace(result, transform_values_foreach_func, transform_values_foreach_replace, 0); } return result; @@ -3189,8 +3196,11 @@ rb_hash_transform_values_bang(VALUE hash) { RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); rb_hash_modify_check(hash); - if (!RHASH_TABLE_EMPTY_P(hash)) - rb_hash_foreach(hash, transform_values_i, hash); + + if (!RHASH_TABLE_EMPTY_P(hash)) { + rb_hash_stlike_foreach_with_replace(hash, transform_values_foreach_func, transform_values_foreach_replace, 0); + } + return hash; } |