@@ -1008,6 +1008,89 @@ static PyType_Spec HeapCTypeSetattr_spec = {
10081008 HeapCTypeSetattr_slots
10091009};
10101010
1011+ /*
1012+ * The code below is for a test that uses PyType_FromSpec API to create a heap
1013+ * type that simultaneously exposes
1014+ *
1015+ * - A regular __new__ / __init__ constructor pair
1016+ * - A vector call handler in the type object
1017+ *
1018+ * A general requirement of vector call implementations is that they should
1019+ * behave identically (except being potentially faster). The example below
1020+ * deviates from this rule by initializing the instance with a different value.
1021+ * This is only done here only so that we can see which path was taken and is
1022+ * strongly discouraged in other cases.
1023+ */
1024+
1025+ typedef struct {
1026+ PyObject_HEAD
1027+ long value ;
1028+ } HeapCTypeVectorcallObject ;
1029+
1030+ static PyObject * heapctype_vectorcall_vectorcall (PyObject * self ,
1031+ PyObject * const * args_in ,
1032+ size_t nargsf ,
1033+ PyObject * kwargs_in )
1034+ {
1035+ if (kwargs_in || PyVectorcall_NARGS (nargsf )) {
1036+ return PyErr_Format (PyExc_IndexError , "HeapCTypeVectorcall() takes no arguments!" );
1037+ }
1038+
1039+ HeapCTypeVectorcallObject * r =
1040+ PyObject_New (HeapCTypeVectorcallObject , (PyTypeObject * ) self );
1041+
1042+ if (!r ) {
1043+ return NULL ;
1044+ }
1045+
1046+ r -> value = 1 ;
1047+
1048+ return (PyObject * ) r ;
1049+ }
1050+
1051+ static PyObject *
1052+ heapctype_vectorcall_new (PyTypeObject * type , PyObject * args , PyObject * kwargs )
1053+ {
1054+ if (PyTuple_GET_SIZE (args ) || kwargs ) {
1055+ return PyErr_Format (PyExc_IndexError , "HeapCTypeVectorcall() takes no arguments!" );
1056+ }
1057+
1058+ return (PyObject * ) PyObject_New (HeapCTypeVectorcallObject , type );
1059+ }
1060+
1061+ static int
1062+ heapctype_vectorcall_init (PyObject * self , PyObject * args , PyObject * kwargs ) {
1063+ if (PyTuple_GET_SIZE (args ) || kwargs ) {
1064+ PyErr_Format (PyExc_IndexError , "HeapCTypeVectorcall() takes no arguments!" );
1065+ return -1 ;
1066+ }
1067+
1068+ HeapCTypeVectorcallObject * o = (HeapCTypeVectorcallObject * ) self ;
1069+ o -> value = 2 ;
1070+ return 0 ;
1071+ }
1072+
1073+ static struct PyMemberDef heapctype_vectorcall_members [] = {
1074+ {"value" , Py_T_LONG , offsetof(HeapCTypeVectorcallObject , value ), 0 , NULL },
1075+ {NULL }
1076+ };
1077+
1078+ static PyType_Slot HeapCTypeVectorcall_slots [] = {
1079+ {Py_tp_new , heapctype_vectorcall_new },
1080+ {Py_tp_init , heapctype_vectorcall_init },
1081+ {Py_tp_vectorcall , heapctype_vectorcall_vectorcall },
1082+ {Py_tp_members , heapctype_vectorcall_members },
1083+ {0 , 0 },
1084+ };
1085+
1086+ static PyType_Spec HeapCTypeVectorcall_spec = {
1087+ "_testcapi.HeapCTypeVectorcall" ,
1088+ sizeof (HeapCTypeVectorcallObject ),
1089+ 0 ,
1090+ Py_TPFLAGS_DEFAULT ,
1091+ HeapCTypeVectorcall_slots
1092+ };
1093+
10111094PyDoc_STRVAR (HeapCCollection_doc ,
10121095"Tuple-like heap type that uses PyObject_GetItemData for items." );
10131096
@@ -1180,6 +1263,9 @@ _PyTestCapi_Init_Heaptype(PyObject *m) {
11801263 PyObject * HeapCTypeSetattr = PyType_FromSpec (& HeapCTypeSetattr_spec );
11811264 ADD ("HeapCTypeSetattr" , HeapCTypeSetattr );
11821265
1266+ PyObject * HeapCTypeVectorcall = PyType_FromSpec (& HeapCTypeVectorcall_spec );
1267+ ADD ("HeapCTypeVectorcall" , HeapCTypeVectorcall );
1268+
11831269 PyObject * subclass_with_finalizer_bases = PyTuple_Pack (1 , HeapCTypeSubclass );
11841270 if (subclass_with_finalizer_bases == NULL ) {
11851271 return -1 ;
0 commit comments