@@ -7869,33 +7869,55 @@ frozendict_repr(PyObject *self)
78697869 return res ;
78707870}
78717871
7872+ static Py_uhash_t
7873+ _shuffle_bits (Py_uhash_t h )
7874+ {
7875+ return ((h ^ 89869747UL ) ^ (h << 16 )) * 3644798167UL ;
7876+ }
7877+
7878+ // Code copied from frozenset_hash()
78727879static Py_hash_t
78737880frozendict_hash (PyObject * op )
78747881{
78757882 PyFrozenDictObject * self = _PyFrozenDictObject_CAST (op );
7876- Py_hash_t hash = FT_ATOMIC_LOAD_SSIZE_RELAXED (self -> ma_hash );
7877- if (hash != -1 ) {
7878- return hash ;
7883+ Py_hash_t shash = FT_ATOMIC_LOAD_SSIZE_RELAXED (self -> ma_hash );
7884+ if (shash != -1 ) {
7885+ return shash ;
78797886 }
78807887
7881- PyObject * items = _PyDictView_New (op , & PyDictItems_Type );
7882- if (items == NULL ) {
7883- return -1 ;
7884- }
7885- PyObject * frozenset = PyFrozenSet_New (items );
7886- Py_DECREF (items );
7887- if (frozenset == NULL ) {
7888- return -1 ;
7888+ PyDictObject * mp = _PyAnyDict_CAST (op );
7889+ Py_uhash_t hash = 0 ;
7890+
7891+ PyObject * key , * value ; // borrowed refs
7892+ Py_ssize_t pos = 0 ;
7893+ while (PyDict_Next (op , & pos , & key , & value )) {
7894+ Py_hash_t key_hash = PyObject_Hash (key );
7895+ if (key_hash == -1 ) {
7896+ return -1 ;
7897+ }
7898+ hash ^= _shuffle_bits (key_hash );
7899+
7900+ Py_hash_t value_hash = PyObject_Hash (value );
7901+ if (value_hash == -1 ) {
7902+ return -1 ;
7903+ }
7904+ hash ^= _shuffle_bits (value_hash );
78897905 }
78907906
7891- hash = PyObject_Hash (frozenset );
7892- Py_DECREF (frozenset );
7893- if (hash == -1 ) {
7894- return -1 ;
7907+ /* Factor in the number of active entries */
7908+ hash ^= ((Py_uhash_t )mp -> ma_used + 1 ) * 1927868237UL ;
7909+
7910+ /* Disperse patterns arising in nested frozensets */
7911+ hash ^= (hash >> 11 ) ^ (hash >> 25 );
7912+ hash = hash * 69069U + 907133923UL ;
7913+
7914+ /* -1 is reserved as an error code */
7915+ if (hash == (Py_uhash_t )- 1 ) {
7916+ hash = 590923713UL ;
78957917 }
78967918
7897- FT_ATOMIC_STORE_SSIZE_RELAXED (self -> ma_hash , hash );
7898- return hash ;
7919+ FT_ATOMIC_STORE_SSIZE_RELAXED (self -> ma_hash , ( Py_hash_t ) hash );
7920+ return ( Py_hash_t ) hash ;
78997921}
79007922
79017923
0 commit comments