@@ -400,7 +400,7 @@ set_empty_to_minsize(PySetObject *so)
400400 FT_ATOMIC_STORE_SSIZE_RELAXED (so -> used , 0 );
401401 so -> mask = PySet_MINSIZE - 1 ;
402402 so -> table = so -> smalltable ;
403- so -> hash = -1 ;
403+ FT_ATOMIC_STORE_SSIZE_RELAXED ( so -> hash , -1 ) ;
404404}
405405
406406static int
@@ -718,18 +718,15 @@ _shuffle_bits(Py_uhash_t h)
718718 large primes with "interesting bit patterns" and that passed tests
719719 for good collision statistics on a variety of problematic datasets
720720 including powersets and graph structures (such as David Eppstein's
721- graph recipes in Lib/test/test_set.py) */
721+ graph recipes in Lib/test/test_set.py). */
722722
723723static Py_hash_t
724- frozenset_hash (PyObject * self )
724+ frozenset_hash_impl (PyObject * self )
725725{
726- PySetObject * so = ( PySetObject * ) self ;
726+ PySetObject * so = _PySet_CAST ( self ) ;
727727 Py_uhash_t hash = 0 ;
728728 setentry * entry ;
729729
730- if (so -> hash != -1 )
731- return so -> hash ;
732-
733730 /* Xor-in shuffled bits from every entry's hash field because xor is
734731 commutative and a frozenset hash should be independent of order.
735732
@@ -762,7 +759,21 @@ frozenset_hash(PyObject *self)
762759 if (hash == (Py_uhash_t )- 1 )
763760 hash = 590923713UL ;
764761
765- so -> hash = hash ;
762+ return (Py_hash_t )hash ;
763+ }
764+
765+ static Py_hash_t
766+ frozenset_hash (PyObject * self )
767+ {
768+ PySetObject * so = _PySet_CAST (self );
769+ Py_uhash_t hash ;
770+
771+ if (FT_ATOMIC_LOAD_SSIZE_RELAXED (so -> hash ) != -1 ) {
772+ return FT_ATOMIC_LOAD_SSIZE_RELAXED (so -> hash );
773+ }
774+
775+ hash = frozenset_hash_impl (self );
776+ FT_ATOMIC_STORE_SSIZE_RELAXED (so -> hash , hash );
766777 return hash ;
767778}
768779
@@ -1202,10 +1213,12 @@ set_swap_bodies(PySetObject *a, PySetObject *b)
12021213
12031214 if (PyType_IsSubtype (Py_TYPE (a ), & PyFrozenSet_Type ) &&
12041215 PyType_IsSubtype (Py_TYPE (b ), & PyFrozenSet_Type )) {
1205- h = a -> hash ; a -> hash = b -> hash ; b -> hash = h ;
1216+ h = FT_ATOMIC_LOAD_SSIZE_RELAXED (a -> hash );
1217+ FT_ATOMIC_STORE_SSIZE_RELAXED (a -> hash , FT_ATOMIC_LOAD_SSIZE_RELAXED (b -> hash ));
1218+ FT_ATOMIC_STORE_SSIZE_RELAXED (b -> hash , h );
12061219 } else {
1207- a -> hash = -1 ;
1208- b -> hash = -1 ;
1220+ FT_ATOMIC_STORE_SSIZE_RELAXED ( a -> hash , -1 ) ;
1221+ FT_ATOMIC_STORE_SSIZE_RELAXED ( b -> hash , -1 ) ;
12091222 }
12101223}
12111224
@@ -2086,9 +2099,9 @@ set_richcompare(PySetObject *v, PyObject *w, int op)
20862099 case Py_EQ :
20872100 if (PySet_GET_SIZE (v ) != PySet_GET_SIZE (w ))
20882101 Py_RETURN_FALSE ;
2089- if (v -> hash != -1 &&
2090- (( PySetObject * )w )-> hash != -1 &&
2091- v -> hash != (( PySetObject * ) w ) -> hash )
2102+ Py_hash_t v_hash = FT_ATOMIC_LOAD_SSIZE_RELAXED (v -> hash );
2103+ Py_hash_t w_hash = FT_ATOMIC_LOAD_SSIZE_RELAXED ((( PySetObject * )w )-> hash );
2104+ if ( v_hash != -1 && w_hash != -1 && v_hash != w_hash )
20922105 Py_RETURN_FALSE ;
20932106 return set_issubset (v , w );
20942107 case Py_NE :
0 commit comments