@@ -1697,6 +1697,13 @@ static PySequenceMethods set_as_sequence = {
16971697
16981698/* set object ********************************************************/
16991699
1700+ #ifdef Py_DEBUG
1701+ static PyObject * test_c_api (PySetObject * so );
1702+
1703+ PyDoc_STRVAR (test_c_api_doc , "Exercises C API. Returns True.\n\
1704+ All is well if assertions don't fail." );
1705+ #endif
1706+
17001707static PyMethodDef set_methods [] = {
17011708 {"add" , (PyCFunction )set_add , METH_O ,
17021709 add_doc },
@@ -1730,6 +1737,10 @@ static PyMethodDef set_methods[] = {
17301737 symmetric_difference_doc },
17311738 {"symmetric_difference_update" ,(PyCFunction )set_symmetric_difference_update , METH_O ,
17321739 symmetric_difference_update_doc },
1740+ #ifdef Py_DEBUG
1741+ {"test_c_api" , (PyCFunction )test_c_api , METH_NOARGS ,
1742+ test_c_api_doc },
1743+ #endif
17331744 {"union" , (PyCFunction )set_union , METH_O ,
17341745 union_doc },
17351746 {"update" , (PyCFunction )set_update , METH_O ,
@@ -1931,18 +1942,29 @@ PySet_New(PyObject *iterable)
19311942PyObject *
19321943PyFrozenSet_New (PyObject * iterable )
19331944{
1934- PyObject * args = NULL , * result ;
1945+ PyObject * args , * result ;
19351946
1936- if (iterable != NULL ) {
1947+ if (iterable == NULL )
1948+ args = PyTuple_New (0 );
1949+ else
19371950 args = PyTuple_Pack (1 , iterable );
1938- if (args == NULL )
1939- return NULL ;
1940- }
1951+ if (args == NULL )
1952+ return NULL ;
19411953 result = frozenset_new (& PyFrozenSet_Type , args , NULL );
1942- Py_XDECREF (args );
1954+ Py_DECREF (args );
19431955 return result ;
19441956}
19451957
1958+ int
1959+ PySet_Size (PyObject * anyset )
1960+ {
1961+ if (!PyAnySet_Check (anyset )) {
1962+ PyErr_BadInternalCall ();
1963+ return -1 ;
1964+ }
1965+ return ((PySetObject * )anyset )-> used ;
1966+ }
1967+
19461968int
19471969PySet_Contains (PyObject * anyset , PyObject * key )
19481970{
@@ -1954,13 +1976,13 @@ PySet_Contains(PyObject *anyset, PyObject *key)
19541976}
19551977
19561978int
1957- PySet_Discard (PyObject * anyset , PyObject * key )
1979+ PySet_Discard (PyObject * set , PyObject * key )
19581980{
1959- if (!PyAnySet_Check ( anyset )) {
1981+ if (!PyType_IsSubtype ( set -> ob_type , & PySet_Type )) {
19601982 PyErr_BadInternalCall ();
19611983 return -1 ;
19621984 }
1963- return set_discard_key ((PySetObject * )anyset , key );
1985+ return set_discard_key ((PySetObject * )set , key );
19641986}
19651987
19661988int
@@ -1982,3 +2004,92 @@ PySet_Pop(PyObject *set)
19822004 }
19832005 return set_pop ((PySetObject * )set );
19842006}
2007+
2008+
2009+ #ifdef Py_DEBUG
2010+
2011+ /* Test code to be called with any three element set.
2012+ Returns True and original set is restored. */
2013+
2014+ #define assertRaises (call_return_value , exception ) \
2015+ do { \
2016+ assert(call_return_value); \
2017+ assert(PyErr_ExceptionMatches(exception)); \
2018+ PyErr_Clear(); \
2019+ } while(0)
2020+
2021+ static PyObject *
2022+ test_c_api (PySetObject * so )
2023+ {
2024+ PyObject * elem , * dup , * t , * f , * ob = (PyObject * )so ;
2025+
2026+ /* Verify preconditions and exercise type/size checks */
2027+ assert (PyAnySet_Check (ob ));
2028+ assert (PyAnySet_CheckExact (ob ));
2029+ assert (!PyFrozenSet_CheckExact (ob ));
2030+ assert (PySet_Size (ob ) == 3 );
2031+ assert (PySet_GET_SIZE (ob ) == 3 );
2032+
2033+ /* Raise TypeError for non-iterable constructor arguments */
2034+ assertRaises (PySet_New (Py_None ) == NULL , PyExc_TypeError );
2035+ assertRaises (PyFrozenSet_New (Py_None ) == NULL , PyExc_TypeError );
2036+
2037+ /* Raise TypeError for unhashable key */
2038+ dup = PySet_New (ob );
2039+ assertRaises (PySet_Discard (ob , dup ) == -1 , PyExc_TypeError );
2040+ assertRaises (PySet_Contains (ob , dup ) == -1 , PyExc_TypeError );
2041+ assertRaises (PySet_Add (ob , dup ) == -1 , PyExc_TypeError );
2042+
2043+ /* Exercise successful pop, contains, add, and discard */
2044+ elem = PySet_Pop (ob );
2045+ assert (PySet_Contains (ob , elem ) == 0 );
2046+ assert (PySet_GET_SIZE (ob ) == 2 );
2047+ assert (PySet_Add (ob , elem ) == 0 );
2048+ assert (PySet_Contains (ob , elem ) == 1 );
2049+ assert (PySet_GET_SIZE (ob ) == 3 );
2050+ assert (PySet_Discard (ob , elem ) == 1 );
2051+ assert (PySet_GET_SIZE (ob ) == 2 );
2052+ assert (PySet_Discard (ob , elem ) == 0 );
2053+ assert (PySet_GET_SIZE (ob ) == 2 );
2054+
2055+ /* Raise SystemError when self argument is not a set or frozenset. */
2056+ t = PyTuple_New (0 );
2057+ assertRaises (PySet_Size (t ) == -1 , PyExc_SystemError );
2058+ assertRaises (PySet_Contains (t , elem ) == -1 , PyExc_SystemError );
2059+ Py_DECREF (t );
2060+
2061+ /* Raise SystemError when self argument is not a set. */
2062+ f = PyFrozenSet_New (dup );
2063+ assert (PySet_Size (f ) == 3 );
2064+ assert (PyFrozenSet_CheckExact (f ));
2065+ assertRaises (PySet_Add (f , elem ) == -1 , PyExc_SystemError );
2066+ assertRaises (PySet_Discard (f , elem ) == -1 , PyExc_SystemError );
2067+ assertRaises (PySet_Pop (f ) == NULL , PyExc_SystemError );
2068+ Py_DECREF (f );
2069+
2070+ /* Raise KeyError when popping from an empty set */
2071+ set_clear_internal (so );
2072+ assert (PySet_GET_SIZE (ob ) == 0 );
2073+ assertRaises (PySet_Pop (ob ) == NULL , PyExc_KeyError );
2074+
2075+ /* Restore the set from the copy and use the abstract API */
2076+ assert (PyObject_CallMethod (ob , "update" , "O" , dup ) == Py_None );
2077+ Py_DECREF (Py_None );
2078+
2079+ /* Verify constructors accept NULL arguments */
2080+ f = PySet_New (NULL );
2081+ assert (f != NULL );
2082+ assert (PySet_GET_SIZE (f ) == 0 );
2083+ Py_DECREF (f );
2084+ f = PyFrozenSet_New (NULL );
2085+ assert (f != NULL );
2086+ assert (PyFrozenSet_CheckExact (f ));
2087+ assert (PySet_GET_SIZE (f ) == 0 );
2088+ Py_DECREF (f );
2089+
2090+ Py_DECREF (elem );
2091+ Py_DECREF (dup );
2092+ Py_RETURN_TRUE ;
2093+ }
2094+
2095+ #endif
0 commit comments