summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hawthorn <john@hawthorn.email>2019-09-11 09:02:22 -0700
committerAaron Patterson <tenderlove@github.com>2019-09-11 14:23:11 -0700
commit21994b7fd686f263544fcac1616ecf3189fb78b3 (patch)
tree6c8f94bed0dc5c37a3bee7578043aff75f407392
parent14e3731059246fcd093daa36fd0139d0287e633f (diff)
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.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/2452
-rw-r--r--hash.c24
1 files changed, 17 insertions, 7 deletions
diff --git a/hash.c b/hash.c
index b61784af3a..e9d994bf70 100644
--- a/hash.c
+++ b/hash.c
@@ -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;
}