summaryrefslogtreecommitdiff
path: root/hash.c
diff options
context:
space:
mode:
authorAlexander Momchilov <alexandermomchilov@gmail.com>2023-12-18 03:17:44 -0500
committerPeter Zhu <peter@peterzhu.ca>2023-12-18 14:51:16 -0500
commitb5c6c0122f5b010cb5f43e7a236c4ba2b1d56a2a (patch)
treee8b9a2ae9202b92d03ba39336e9678b07be3e68e /hash.c
parent893fe30ef2b30525d932d6b1256f717cc60b3311 (diff)
compare_by_identity: remove alloc for empty Hash
For non-empty Hashes, this function needs to rehash all the stored values (using the new `compare` and `hash` functions from `identhash`). It does so by writing into a newly allocated `tmp` Hash, and then transferring ownership of its st table into `self`. For empty Hashes, we can skip allocating this `tmp`, because there's nothing to re-hash. We can just modify our new st table's `type` in-place.
Diffstat (limited to 'hash.c')
-rw-r--r--hash.c21
1 files changed, 14 insertions, 7 deletions
diff --git a/hash.c b/hash.c
index cf83675c70..f6525ba4a5 100644
--- a/hash.c
+++ b/hash.c
@@ -4380,15 +4380,22 @@ rb_hash_compare_by_id(VALUE hash)
ar_force_convert_table(hash, __FILE__, __LINE__);
HASH_ASSERT(RHASH_ST_TABLE_P(hash));
- tmp = hash_alloc(0);
- hash_st_table_init(tmp, &identhash, RHASH_SIZE(hash));
- identtable = RHASH_ST_TABLE(tmp);
+ if (RHASH_TABLE_EMPTY_P(hash)) {
+ // Fast path: There's nothing to rehash, so we don't need a `tmp` table.
+ RHASH_ST_TABLE(hash)->type = &identhash;
+ } else {
+ // Slow path: Need to rehash the members of `self` into a new
+ // `tmp` table using the new `identhash` compare/hash functions.
+ tmp = hash_alloc(0);
+ hash_st_table_init(tmp, &identhash, RHASH_SIZE(hash));
+ identtable = RHASH_ST_TABLE(tmp);
- rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp);
+ rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp);
- rb_hash_free(hash);
- RHASH_ST_TABLE_SET(hash, identtable);
- RHASH_ST_CLEAR(tmp);
+ rb_hash_free(hash);
+ RHASH_ST_TABLE_SET(hash, identtable);
+ RHASH_ST_CLEAR(tmp);
+ }
return hash;
}