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.
This commit is contained in:
Alexander Momchilov 2023-12-18 03:17:44 -05:00 committed by Peter Zhu
parent 893fe30ef2
commit b5c6c0122f

21
hash.c
View File

@ -4380,15 +4380,22 @@ rb_hash_compare_by_id(VALUE hash)
ar_force_convert_table(hash, __FILE__, __LINE__); ar_force_convert_table(hash, __FILE__, __LINE__);
HASH_ASSERT(RHASH_ST_TABLE_P(hash)); HASH_ASSERT(RHASH_ST_TABLE_P(hash));
tmp = hash_alloc(0); if (RHASH_TABLE_EMPTY_P(hash)) {
hash_st_table_init(tmp, &identhash, RHASH_SIZE(hash)); // Fast path: There's nothing to rehash, so we don't need a `tmp` table.
identtable = RHASH_ST_TABLE(tmp); 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); rb_hash_free(hash);
RHASH_ST_TABLE_SET(hash, identtable); RHASH_ST_TABLE_SET(hash, identtable);
RHASH_ST_CLEAR(tmp); RHASH_ST_CLEAR(tmp);
}
return hash; return hash;
} }