@@ -3381,19 +3381,18 @@ dict_dealloc(PyObject *self)
33813381
33823382
33833383static PyObject *
3384- dict_repr_lock_held (PyObject * self )
3384+ anydict_repr_impl (PyObject * self )
33853385{
33863386 PyDictObject * mp = (PyDictObject * )self ;
33873387 PyObject * key = NULL , * value = NULL ;
3388- ASSERT_DICT_LOCKED (mp );
33893388
3390- int res = Py_ReprEnter (( PyObject * ) mp );
3389+ int res = Py_ReprEnter (self );
33913390 if (res != 0 ) {
33923391 return (res > 0 ? PyUnicode_FromString ("{...}" ) : NULL );
33933392 }
33943393
33953394 if (mp -> ma_used == 0 ) {
3396- Py_ReprLeave (( PyObject * ) mp );
3395+ Py_ReprLeave (self );
33973396 return PyUnicode_FromString ("{}" );
33983397 }
33993398
@@ -3412,7 +3411,7 @@ dict_repr_lock_held(PyObject *self)
34123411 Note that repr may mutate the dict. */
34133412 Py_ssize_t i = 0 ;
34143413 int first = 1 ;
3415- while (_PyDict_Next (( PyObject * ) mp , & i , & key , & value , NULL )) {
3414+ while (_PyDict_Next (self , & i , & key , & value , NULL )) {
34163415 // Prevent repr from deleting key or value during key format.
34173416 Py_INCREF (key );
34183417 Py_INCREF (value );
@@ -3454,18 +3453,25 @@ dict_repr_lock_held(PyObject *self)
34543453 goto error ;
34553454 }
34563455
3457- Py_ReprLeave (( PyObject * ) mp );
3456+ Py_ReprLeave (self );
34583457
34593458 return PyUnicodeWriter_Finish (writer );
34603459
34613460error :
3462- Py_ReprLeave (( PyObject * ) mp );
3461+ Py_ReprLeave (self );
34633462 PyUnicodeWriter_Discard (writer );
34643463 Py_XDECREF (key );
34653464 Py_XDECREF (value );
34663465 return NULL ;
34673466}
34683467
3468+ static PyObject *
3469+ dict_repr_lock_held (PyObject * self )
3470+ {
3471+ ASSERT_DICT_LOCKED ((PyDictObject * )self );
3472+ return anydict_repr_impl (self );
3473+ }
3474+
34693475static PyObject *
34703476dict_repr (PyObject * self )
34713477{
@@ -3482,6 +3488,12 @@ dict_length(PyObject *self)
34823488 return GET_USED (_PyAnyDict_CAST (self ));
34833489}
34843490
3491+ static Py_ssize_t
3492+ frozendict_length (PyObject * self )
3493+ {
3494+ return _PyAnyDict_CAST (self )-> ma_used ;
3495+ }
3496+
34853497static PyObject *
34863498dict_subscript (PyObject * self , PyObject * key )
34873499{
@@ -7833,7 +7845,7 @@ static PyNumberMethods frozendict_as_number = {
78337845};
78347846
78357847static PyMappingMethods frozendict_as_mapping = {
7836- .mp_length = dict_length ,
7848+ .mp_length = frozendict_length ,
78377849 .mp_subscript = dict_subscript ,
78387850};
78397851
@@ -7856,7 +7868,12 @@ static PyMethodDef frozendict_methods[] = {
78567868static PyObject *
78577869frozendict_repr (PyObject * self )
78587870{
7859- PyObject * repr = dict_repr (self );
7871+ PyDictObject * mp = _PyAnyDict_CAST (self );
7872+ if (mp -> ma_used == 0 ) {
7873+ return PyUnicode_FromFormat ("%s()" , Py_TYPE (self )-> tp_name );
7874+ }
7875+
7876+ PyObject * repr = anydict_repr_impl (self );
78607877 if (repr == NULL ) {
78617878 return NULL ;
78627879 }
@@ -7869,33 +7886,55 @@ frozendict_repr(PyObject *self)
78697886 return res ;
78707887}
78717888
7889+ static Py_uhash_t
7890+ _shuffle_bits (Py_uhash_t h )
7891+ {
7892+ return ((h ^ 89869747UL ) ^ (h << 16 )) * 3644798167UL ;
7893+ }
7894+
7895+ // Code copied from frozenset_hash()
78727896static Py_hash_t
78737897frozendict_hash (PyObject * op )
78747898{
78757899 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 ;
7900+ Py_hash_t shash = FT_ATOMIC_LOAD_SSIZE_RELAXED (self -> ma_hash );
7901+ if (shash != -1 ) {
7902+ return shash ;
78797903 }
78807904
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 ;
7905+ PyDictObject * mp = _PyAnyDict_CAST (op );
7906+ Py_uhash_t hash = 0 ;
7907+
7908+ PyObject * key , * value ; // borrowed refs
7909+ Py_ssize_t pos = 0 ;
7910+ while (PyDict_Next (op , & pos , & key , & value )) {
7911+ Py_hash_t key_hash = PyObject_Hash (key );
7912+ if (key_hash == -1 ) {
7913+ return -1 ;
7914+ }
7915+ hash ^= _shuffle_bits (key_hash );
7916+
7917+ Py_hash_t value_hash = PyObject_Hash (value );
7918+ if (value_hash == -1 ) {
7919+ return -1 ;
7920+ }
7921+ hash ^= _shuffle_bits (value_hash );
78897922 }
78907923
7891- hash = PyObject_Hash (frozenset );
7892- Py_DECREF (frozenset );
7893- if (hash == -1 ) {
7894- return -1 ;
7924+ /* Factor in the number of active entries */
7925+ hash ^= ((Py_uhash_t )mp -> ma_used + 1 ) * 1927868237UL ;
7926+
7927+ /* Disperse patterns arising in nested frozendicts */
7928+ hash ^= (hash >> 11 ) ^ (hash >> 25 );
7929+ hash = hash * 69069U + 907133923UL ;
7930+
7931+ /* -1 is reserved as an error code */
7932+ if (hash == (Py_uhash_t )- 1 ) {
7933+ hash = 590923713UL ;
78957934 }
78967935
7897- FT_ATOMIC_STORE_SSIZE_RELAXED (self -> ma_hash , hash );
7898- return hash ;
7936+ FT_ATOMIC_STORE_SSIZE_RELAXED (self -> ma_hash , ( Py_hash_t ) hash );
7937+ return ( Py_hash_t ) hash ;
78997938}
79007939
79017940
0 commit comments