@@ -1475,74 +1475,68 @@ copy_small_table(setentry *dest, setentry *src)
14751475}
14761476#endif
14771477
1478- /* set_swap_bodies() switches the contents of any two sets by moving their
1479- internal data pointers and, if needed, copying the internal smalltables.
1480- Semantically equivalent to:
1478+ /* set_replace_body() replaces the contents of dst with those of src,
1479+ moving dst's old contents into src for proper cleanup on Py_DECREF.
14811480
1482- t=set(a); a.clear(); a.update(b); b.clear(); b.update(t); del t
1481+ The caller guarantees that src is a uniquely-referenced temporary set
1482+ that will be discarded immediately afterward. This allows us to skip
1483+ atomic operations and shared-marking on src's fields, and to skip the
1484+ frozenset hash swap (neither argument is ever a frozenset here).
14831485
14841486 The function always succeeds and it leaves both objects in a stable state.
1485- Useful for operations that update in-place (by allowing an intermediate
1486- result to be swapped into one of the original inputs).
14871487*/
14881488
14891489static void
1490- set_swap_bodies (PySetObject * a , PySetObject * b )
1490+ set_replace_body (PySetObject * dst , PySetObject * src )
14911491{
14921492 Py_ssize_t t ;
14931493 setentry * u ;
14941494 setentry tab [PySet_MINSIZE ];
1495- Py_hash_t h ;
1496-
1497- setentry * a_table = a -> table ;
1498- setentry * b_table = b -> table ;
1499- FT_ATOMIC_STORE_PTR_RELEASE (a -> table , NULL );
1500- FT_ATOMIC_STORE_PTR_RELEASE (b -> table , NULL );
1501-
1502- t = a -> fill ; a -> fill = b -> fill ; b -> fill = t ;
1503- t = a -> used ;
1504- FT_ATOMIC_STORE_SSIZE_RELAXED (a -> used , b -> used );
1505- FT_ATOMIC_STORE_SSIZE_RELAXED (b -> used , t );
1506- t = a -> mask ;
1507- FT_ATOMIC_STORE_SSIZE_RELEASE (a -> mask , b -> mask );
1508- FT_ATOMIC_STORE_SSIZE_RELEASE (b -> mask , t );
1509-
1510- u = a_table ;
1511- if (a_table == a -> smalltable )
1512- u = b -> smalltable ;
1513- a_table = b_table ;
1514- if (b_table == b -> smalltable )
1515- a_table = a -> smalltable ;
1516- b_table = u ;
1517-
1518- if (a_table == a -> smalltable || b_table == b -> smalltable ) {
1519- memcpy (tab , a -> smalltable , sizeof (tab ));
1495+
1496+ assert (!PyType_IsSubtype (Py_TYPE (dst ), & PyFrozenSet_Type ));
1497+ assert (!PyType_IsSubtype (Py_TYPE (src ), & PyFrozenSet_Type ));
1498+ assert (Py_REFCNT (src ) == 1 );
1499+
1500+ setentry * dst_table = dst -> table ;
1501+ setentry * src_table = src -> table ;
1502+ FT_ATOMIC_STORE_PTR_RELEASE (dst -> table , NULL );
1503+ src -> table = NULL ;
1504+
1505+ t = dst -> fill ; dst -> fill = src -> fill ; src -> fill = t ;
1506+ t = dst -> used ;
1507+ FT_ATOMIC_STORE_SSIZE_RELAXED (dst -> used , src -> used );
1508+ src -> used = t ;
1509+ t = dst -> mask ;
1510+ FT_ATOMIC_STORE_SSIZE_RELEASE (dst -> mask , src -> mask );
1511+ src -> mask = t ;
1512+
1513+ u = dst_table ;
1514+ if (dst_table == dst -> smalltable )
1515+ u = src -> smalltable ;
1516+ dst_table = src_table ;
1517+ if (src_table == src -> smalltable )
1518+ dst_table = dst -> smalltable ;
1519+ src_table = u ;
1520+
1521+ if (dst_table == dst -> smalltable || src_table == src -> smalltable ) {
1522+ memcpy (tab , dst -> smalltable , sizeof (tab ));
15201523#ifndef Py_GIL_DISABLED
1521- memcpy (a -> smalltable , b -> smalltable , sizeof (tab ));
1522- memcpy (b -> smalltable , tab , sizeof (tab ));
1524+ memcpy (dst -> smalltable , src -> smalltable , sizeof (tab ));
1525+ memcpy (src -> smalltable , tab , sizeof (tab ));
15231526#else
1524- copy_small_table (a -> smalltable , b -> smalltable );
1525- copy_small_table ( b -> smalltable , tab );
1527+ copy_small_table (dst -> smalltable , src -> smalltable );
1528+ memcpy ( src -> smalltable , tab , sizeof ( tab ) );
15261529#endif
15271530 }
15281531
1529- if (PyType_IsSubtype (Py_TYPE (a ), & PyFrozenSet_Type ) &&
1530- PyType_IsSubtype (Py_TYPE (b ), & PyFrozenSet_Type )) {
1531- h = FT_ATOMIC_LOAD_SSIZE_RELAXED (a -> hash );
1532- FT_ATOMIC_STORE_SSIZE_RELAXED (a -> hash , FT_ATOMIC_LOAD_SSIZE_RELAXED (b -> hash ));
1533- FT_ATOMIC_STORE_SSIZE_RELAXED (b -> hash , h );
1534- } else {
1535- FT_ATOMIC_STORE_SSIZE_RELAXED (a -> hash , -1 );
1536- FT_ATOMIC_STORE_SSIZE_RELAXED (b -> hash , -1 );
1537- }
1538- if (!SET_IS_SHARED (b ) && SET_IS_SHARED (a )) {
1539- SET_MARK_SHARED (b );
1540- }
1541- if (!SET_IS_SHARED (a ) && SET_IS_SHARED (b )) {
1542- SET_MARK_SHARED (a );
1532+ FT_ATOMIC_STORE_SSIZE_RELAXED (dst -> hash , -1 );
1533+
1534+ if (SET_IS_SHARED (dst )) {
1535+ SET_MARK_SHARED (src );
15431536 }
1544- FT_ATOMIC_STORE_PTR_RELEASE (a -> table , a_table );
1545- FT_ATOMIC_STORE_PTR_RELEASE (b -> table , b_table );
1537+
1538+ FT_ATOMIC_STORE_PTR_RELEASE (dst -> table , dst_table );
1539+ src -> table = src_table ;
15461540}
15471541
15481542/*[clinic input]
@@ -1797,7 +1791,7 @@ set_intersection_update(PySetObject *so, PyObject *other)
17971791 tmp = set_intersection (so , other );
17981792 if (tmp == NULL )
17991793 return NULL ;
1800- set_swap_bodies (so , (PySetObject * )tmp );
1794+ set_replace_body (so , (PySetObject * )tmp );
18011795 Py_DECREF (tmp );
18021796 Py_RETURN_NONE ;
18031797}
@@ -1821,7 +1815,7 @@ set_intersection_update_multi_impl(PySetObject *so, PyObject * const *others,
18211815 if (tmp == NULL )
18221816 return NULL ;
18231817 Py_BEGIN_CRITICAL_SECTION (so );
1824- set_swap_bodies (so , (PySetObject * )tmp );
1818+ set_replace_body (so , (PySetObject * )tmp );
18251819 Py_END_CRITICAL_SECTION ();
18261820 Py_DECREF (tmp );
18271821 Py_RETURN_NONE ;
0 commit comments