@@ -685,6 +685,31 @@ gc_collect(void)
685
685
}
686
686
687
687
688
+ static PyObject *
689
+ func_varargs (PyObject * Py_UNUSED (module ), PyObject * args , PyObject * kwargs )
690
+ {
691
+ if (kwargs != NULL ) {
692
+ return PyTuple_Pack (2 , args , kwargs );
693
+ }
694
+ else {
695
+ return PyTuple_Pack (1 , args );
696
+ }
697
+ }
698
+
699
+
700
+ static void
701
+ check_int (PyObject * obj , int value )
702
+ {
703
+ #ifdef PYTHON3
704
+ assert (PyLong_Check (obj ));
705
+ assert (PyLong_AsLong (obj ) == value );
706
+ #else
707
+ assert (PyInt_Check (obj ));
708
+ assert (PyInt_AsLong (obj ) == value );
709
+ #endif
710
+ }
711
+
712
+
688
713
static PyObject *
689
714
test_weakref (PyObject * Py_UNUSED (module ), PyObject * Py_UNUSED (args ))
690
715
{
@@ -743,7 +768,164 @@ test_weakref(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
743
768
#endif
744
769
745
770
Py_DECREF (weakref );
771
+ Py_RETURN_NONE ;
772
+ }
773
+
774
+
775
+ static void
776
+ test_vectorcall_noargs (PyObject * func_varargs )
777
+ {
778
+ PyObject * res = PyObject_Vectorcall (func_varargs , NULL , 0 , NULL );
779
+ assert (res != NULL );
780
+
781
+ assert (PyTuple_Check (res ));
782
+ assert (PyTuple_GET_SIZE (res ) == 1 );
783
+ PyObject * posargs = PyTuple_GET_ITEM (res , 0 );
784
+
785
+ assert (PyTuple_Check (posargs ));
786
+ assert (PyTuple_GET_SIZE (posargs ) == 0 );
787
+
788
+ Py_DECREF (res );
789
+ }
790
+
791
+
792
+ static void
793
+ test_vectorcall_args (PyObject * func_varargs )
794
+ {
795
+ PyObject * args_tuple = Py_BuildValue ("ii" , 1 , 2 );
796
+ assert (args_tuple != NULL );
797
+ size_t nargs = (size_t )PyTuple_GET_SIZE (args_tuple );
798
+ PyObject * * args = & PyTuple_GET_ITEM (args_tuple , 0 );
799
+
800
+ PyObject * res = PyObject_Vectorcall (func_varargs , args , nargs , NULL );
801
+ Py_DECREF (args_tuple );
802
+ assert (res != NULL );
803
+
804
+ assert (PyTuple_Check (res ));
805
+ assert (PyTuple_GET_SIZE (res ) == 1 );
806
+ PyObject * posargs = PyTuple_GET_ITEM (res , 0 );
807
+
808
+ assert (PyTuple_Check (posargs ));
809
+ assert (PyTuple_GET_SIZE (posargs ) == 2 );
810
+ check_int (PyTuple_GET_ITEM (posargs , 0 ), 1 );
811
+ check_int (PyTuple_GET_ITEM (posargs , 1 ), 2 );
812
+
813
+ Py_DECREF (res );
814
+ }
815
+
816
+
817
+ static void
818
+ test_vectorcall_args_offset (PyObject * func_varargs )
819
+ {
820
+ // args contains 3 values, but only pass 2 last values
821
+ PyObject * args_tuple = Py_BuildValue ("iii" , 1 , 2 , 3 );
822
+ assert (args_tuple != NULL );
823
+ size_t nargs = 2 | PY_VECTORCALL_ARGUMENTS_OFFSET ;
824
+ PyObject * * args = & PyTuple_GET_ITEM (args_tuple , 1 );
825
+ PyObject * arg0 = PyTuple_GET_ITEM (args_tuple , 0 );
826
+
827
+ PyObject * res = PyObject_Vectorcall (func_varargs , args , nargs , NULL );
828
+ assert (PyTuple_GET_ITEM (args_tuple , 0 ) == arg0 );
829
+ Py_DECREF (args_tuple );
830
+ assert (res != NULL );
831
+
832
+ assert (PyTuple_Check (res ));
833
+ assert (PyTuple_GET_SIZE (res ) == 1 );
834
+ PyObject * posargs = PyTuple_GET_ITEM (res , 0 );
835
+
836
+ assert (PyTuple_Check (posargs ));
837
+ assert (PyTuple_GET_SIZE (posargs ) == 2 );
838
+ check_int (PyTuple_GET_ITEM (posargs , 0 ), 2 );
839
+ check_int (PyTuple_GET_ITEM (posargs , 1 ), 3 );
840
+
841
+ Py_DECREF (res );
842
+ }
843
+
844
+
845
+ static void
846
+ test_vectorcall_args_kwnames (PyObject * func_varargs )
847
+ {
848
+ PyObject * args_tuple = Py_BuildValue ("iiiii" , 1 , 2 , 3 , 4 , 5 );
849
+ assert (args_tuple != NULL );
850
+ PyObject * * args = & PyTuple_GET_ITEM (args_tuple , 0 );
851
+
852
+ #ifdef PYTHON3
853
+ PyObject * key1 = PyUnicode_FromString ("key1" );
854
+ PyObject * key2 = PyUnicode_FromString ("key2" );
855
+ #else
856
+ PyObject * key1 = PyString_FromString ("key1" );
857
+ PyObject * key2 = PyString_FromString ("key2" );
858
+ #endif
859
+ assert (key1 != NULL );
860
+ assert (key2 != NULL );
861
+ PyObject * kwnames = PyTuple_Pack (2 , key1 , key2 );
862
+ assert (kwnames != NULL );
863
+ size_t nargs = (size_t )(PyTuple_GET_SIZE (args_tuple ) - PyTuple_GET_SIZE (kwnames ));
864
+
865
+ PyObject * res = PyObject_Vectorcall (func_varargs , args , nargs , kwnames );
866
+ Py_DECREF (args_tuple );
867
+ Py_DECREF (kwnames );
868
+ assert (res != NULL );
869
+
870
+ assert (PyTuple_Check (res ));
871
+ assert (PyTuple_GET_SIZE (res ) == 2 );
872
+ PyObject * posargs = PyTuple_GET_ITEM (res , 0 );
873
+ PyObject * kwargs = PyTuple_GET_ITEM (res , 1 );
874
+
875
+ assert (PyTuple_Check (posargs ));
876
+ assert (PyTuple_GET_SIZE (posargs ) == 3 );
877
+ check_int (PyTuple_GET_ITEM (posargs , 0 ), 1 );
878
+ check_int (PyTuple_GET_ITEM (posargs , 1 ), 2 );
879
+ check_int (PyTuple_GET_ITEM (posargs , 2 ), 3 );
880
+
881
+ assert (PyDict_Check (kwargs ));
882
+ assert (PyDict_Size (kwargs ) == 2 );
883
+
884
+ Py_ssize_t pos = 0 ;
885
+ PyObject * key , * value ;
886
+ while (PyDict_Next (kwargs , & pos , & key , & value )) {
887
+ #ifdef PYTHON3
888
+ assert (PyUnicode_Check (key ));
889
+ #else
890
+ assert (PyString_Check (key ));
891
+ #endif
892
+ if (PyObject_RichCompareBool (key , key1 , Py_EQ )) {
893
+ check_int (value , 4 );
894
+ }
895
+ else {
896
+ assert (PyObject_RichCompareBool (key , key2 , Py_EQ ));
897
+ check_int (value , 5 );
898
+ }
899
+ }
900
+
901
+ Py_DECREF (res );
902
+ Py_DECREF (key1 );
903
+ Py_DECREF (key2 );
904
+ }
905
+
906
+
907
+ static PyObject *
908
+ test_vectorcall (PyObject * module , PyObject * Py_UNUSED (args ))
909
+ {
910
+ #ifndef PYTHON3
911
+ module = PyImport_ImportModule (MODULE_NAME_STR );
912
+ assert (module != NULL );
913
+ #endif
914
+ PyObject * func_varargs = PyObject_GetAttrString (module , "func_varargs" );
915
+ #ifndef PYTHON3
916
+ Py_DECREF (module );
917
+ #endif
918
+ if (func_varargs == NULL ) {
919
+ return NULL ;
920
+ }
921
+
922
+ // test PyObject_Vectorcall()
923
+ test_vectorcall_noargs (func_varargs );
924
+ test_vectorcall_args (func_varargs );
925
+ test_vectorcall_args_offset (func_varargs );
926
+ test_vectorcall_args_kwnames (func_varargs );
746
927
928
+ Py_DECREF (func_varargs );
747
929
Py_RETURN_NONE ;
748
930
}
749
931
@@ -768,6 +950,8 @@ static struct PyMethodDef methods[] = {
768
950
{"test_api_casts" , test_api_casts , METH_NOARGS , _Py_NULL },
769
951
{"test_import" , test_import , METH_NOARGS , _Py_NULL },
770
952
{"test_weakref" , test_weakref , METH_NOARGS , _Py_NULL },
953
+ {"func_varargs" , (PyCFunction )(void * )func_varargs , METH_VARARGS | METH_KEYWORDS , _Py_NULL },
954
+ {"test_vectorcall" , test_vectorcall , METH_NOARGS , _Py_NULL },
771
955
{_Py_NULL , _Py_NULL , 0 , _Py_NULL }
772
956
};
773
957
0 commit comments