diff --git a/CHANGES.current b/CHANGES.current index 8483273d164..eeeb08dfdd3 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -11,6 +11,24 @@ Version 3.0.11 (in progress) we checked an uninitialised value instead. Fixes #627. Based on patch from Sergey Seroshtan. +2016-09-22: wsfulton + [Python] More flexible python builtin slots for overloaded C++ function. + + The closure names used for builtin slots are mangled with their functype so + that overloaded C++ method names can be used for multiple slots. + For example: + + %feature("python:slot", "mp_subscript", functype="binaryfunc") SimpleArray::__getitem__; + %feature("python:slot", "sq_item", functype="ssizeargfunc") SimpleArray::__getitem__(Py_ssize_t n); + + will generate closures: + + SWIGPY_SSIZEARGFUNC_CLOSURE(_wrap_SimpleArray___getitem__) /* defines _wrap_SimpleArray___getitem___ssizeargfunc_closure */ + SWIGPY_BINARYFUNC_CLOSURE(_wrap_SimpleArray___getitem__) /* defines _wrap_SimpleArray___getitem___binaryfunc_closure */ + + Previously only one name was defined: _wrap_SimpleArray___getitem___closure. + Hence the overloaded __getitem__ method can be used to support both mp_subscript and sq_item slots. + 2016-09-17: wsfulton [Python] Fix iterators for containers of NULL pointers (or Python None) when using -builtin. Previously iteration would stop at the first element that was NULL. diff --git a/Examples/test-suite/python/python_builtin_runme.py b/Examples/test-suite/python/python_builtin_runme.py index 70990cbfde3..dc46b63f531 100644 --- a/Examples/test-suite/python/python_builtin_runme.py +++ b/Examples/test-suite/python/python_builtin_runme.py @@ -79,3 +79,16 @@ if MyClass.less_than_counts != 6: raise RuntimeError("python:compare feature not working") +sa = SimpleArray(5) +elements = [x for x in sa] +if elements != [0, 10, 20, 30, 40]: + raise RuntimeError("Iteration not working") +if len(sa) != 5: + raise RuntimeError("len not working") +for i in range(5): + if sa[i] != i*10: + raise RuntimeError("indexing not working") +subslice = sa[1:3] +elements = [x for x in subslice] +if elements != [10, 20]: + raise RuntimeError("slice not working") diff --git a/Examples/test-suite/python_builtin.i b/Examples/test-suite/python_builtin.i index e2c453d5456..45654a01474 100644 --- a/Examples/test-suite/python_builtin.i +++ b/Examples/test-suite/python_builtin.i @@ -136,3 +136,66 @@ void Dealloc2Destroyer(PyObject *v) { }; int MyClass::less_than_counts = 0; %} + +// Test 6 add in container __getitem__ to support basic sequence protocol +// Tests overloaded functions being used for more than one slot (mp_subscript and sq_item) +%include +%include +%apply int {Py_ssize_t} +%typemap(in) PySliceObject * { + if (!PySlice_Check($input)) + SWIG_exception(SWIG_TypeError, "in method '$symname', argument $argnum of type '$type'"); + $1 = (PySliceObject *)$input; +} +%typemap(typecheck,precedence=300) PySliceObject* { + $1 = PySlice_Check($input); +} + +%feature("python:slot", "mp_subscript", functype="binaryfunc") SimpleArray::__getitem__(PySliceObject *slice); +%feature("python:slot", "sq_item", functype="ssizeargfunc") SimpleArray::__getitem__(Py_ssize_t n); +%feature("python:slot", "sq_length", functype="lenfunc") SimpleArray::__len__; +%inline %{ + class SimpleArray { + size_t size; + int numbers[5]; + public: + SimpleArray(size_t size) : size(size) { + for (size_t x = 0; x= (int)size) + throw std::out_of_range("Index too large"); + return numbers[n]; + } + + SimpleArray __getitem__(PySliceObject *slice) throw (std::out_of_range, std::invalid_argument) { + if (!PySlice_Check(slice)) + throw std::invalid_argument("Slice object expected"); + Py_ssize_t i, j, step; +#if PY_VERSION_HEX >= 0x03020000 + PySlice_GetIndices((PyObject *)slice, size, &i, &j, &step); +#else + PySlice_GetIndices((PySliceObject *)slice, size, &i, &j, &step); +#endif + if (step != 1) + throw std::invalid_argument("Only a step size of 1 is implemented"); + + { + Py_ssize_t ii = i<0 ? 0 : i>=size ? size-1 : i; + Py_ssize_t jj = j<0 ? 0 : j>=size ? size-1 : j; + if (ii > jj) + throw std::invalid_argument("getitem i should not be larger than j"); + SimpleArray n(jj-ii); + for (size_t x = 0; xdict); \ @@ -32,7 +32,7 @@ wrapper##_closure(PyObject *a) { \ #define SWIGPY_INQUIRY_CLOSURE(wrapper) \ SWIGINTERN int \ -wrapper##_closure(PyObject *a) { \ +wrapper##_inquiry_closure(PyObject *a) { \ PyObject *pyresult; \ int result; \ pyresult = wrapper(a, NULL); \ @@ -41,9 +41,15 @@ wrapper##_closure(PyObject *a) { \ return result; \ } +#define SWIGPY_GETITERFUNC_CLOSURE(wrapper) \ +SWIGINTERN PyObject * \ +wrapper##_getiterfunc_closure(PyObject *a) { \ + return wrapper(a, NULL); \ +} + #define SWIGPY_BINARYFUNC_CLOSURE(wrapper) \ SWIGINTERN PyObject * \ -wrapper##_closure(PyObject *a, PyObject *b) { \ +wrapper##_binaryfunc_closure(PyObject *a, PyObject *b) { \ PyObject *tuple, *result; \ tuple = PyTuple_New(1); \ assert(tuple); \ @@ -58,7 +64,7 @@ typedef ternaryfunc ternarycallfunc; #define SWIGPY_TERNARYFUNC_CLOSURE(wrapper) \ SWIGINTERN PyObject * \ -wrapper##_closure(PyObject *a, PyObject *b, PyObject *c) { \ +wrapper##_ternaryfunc_closure(PyObject *a, PyObject *b, PyObject *c) { \ PyObject *tuple, *result; \ tuple = PyTuple_New(2); \ assert(tuple); \ @@ -73,13 +79,13 @@ wrapper##_closure(PyObject *a, PyObject *b, PyObject *c) { \ #define SWIGPY_TERNARYCALLFUNC_CLOSURE(wrapper) \ SWIGINTERN PyObject * \ -wrapper##_closure(PyObject *callable_object, PyObject *args, PyObject *) { \ +wrapper##_ternarycallfunc_closure(PyObject *callable_object, PyObject *args, PyObject *) { \ return wrapper(callable_object, args); \ } #define SWIGPY_LENFUNC_CLOSURE(wrapper) \ SWIGINTERN Py_ssize_t \ -wrapper##_closure(PyObject *a) { \ +wrapper##_lenfunc_closure(PyObject *a) { \ PyObject *resultobj; \ Py_ssize_t result; \ resultobj = wrapper(a, NULL); \ @@ -90,7 +96,7 @@ wrapper##_closure(PyObject *a) { \ #define SWIGPY_SSIZESSIZEARGFUNC_CLOSURE(wrapper) \ SWIGINTERN PyObject * \ -wrapper##_closure(PyObject *a, Py_ssize_t b, Py_ssize_t c) { \ +wrapper##_ssizessizeargfunc_closure(PyObject *a, Py_ssize_t b, Py_ssize_t c) { \ PyObject *tuple, *result; \ tuple = PyTuple_New(2); \ assert(tuple); \ @@ -103,7 +109,7 @@ wrapper##_closure(PyObject *a, Py_ssize_t b, Py_ssize_t c) { \ #define SWIGPY_SSIZESSIZEOBJARGPROC_CLOSURE(wrapper) \ SWIGINTERN int \ -wrapper##_closure(PyObject *a, Py_ssize_t b, Py_ssize_t c, PyObject *d) { \ +wrapper##_ssizessizeobjargproc_closure(PyObject *a, Py_ssize_t b, Py_ssize_t c, PyObject *d) { \ PyObject *tuple, *resultobj; \ int result; \ tuple = PyTuple_New(d ? 3 : 2); \ @@ -123,7 +129,7 @@ wrapper##_closure(PyObject *a, Py_ssize_t b, Py_ssize_t c, PyObject *d) { \ #define SWIGPY_SSIZEARGFUNC_CLOSURE(wrapper) \ SWIGINTERN PyObject * \ -wrapper##_closure(PyObject *a, Py_ssize_t b) { \ +wrapper##_ssizeargfunc_closure(PyObject *a, Py_ssize_t b) { \ PyObject *tuple, *result; \ tuple = PyTuple_New(1); \ assert(tuple); \ @@ -135,7 +141,7 @@ wrapper##_closure(PyObject *a, Py_ssize_t b) { \ #define SWIGPY_FUNPACK_SSIZEARGFUNC_CLOSURE(wrapper) \ SWIGINTERN PyObject * \ -wrapper##_closure(PyObject *a, Py_ssize_t b) { \ +wrapper##_ssizeargfunc_closure(PyObject *a, Py_ssize_t b) { \ PyObject *arg, *result; \ arg = _PyLong_FromSsize_t(b); \ result = wrapper(a, arg); \ @@ -145,7 +151,7 @@ wrapper##_closure(PyObject *a, Py_ssize_t b) { \ #define SWIGPY_SSIZEOBJARGPROC_CLOSURE(wrapper) \ SWIGINTERN int \ -wrapper##_closure(PyObject *a, Py_ssize_t b, PyObject *c) { \ +wrapper##_ssizeobjargproc_closure(PyObject *a, Py_ssize_t b, PyObject *c) { \ PyObject *tuple, *resultobj; \ int result; \ tuple = PyTuple_New(2); \ @@ -162,7 +168,7 @@ wrapper##_closure(PyObject *a, Py_ssize_t b, PyObject *c) { \ #define SWIGPY_OBJOBJARGPROC_CLOSURE(wrapper) \ SWIGINTERN int \ -wrapper##_closure(PyObject *a, PyObject *b, PyObject *c) { \ +wrapper##_objobjargproc_closure(PyObject *a, PyObject *b, PyObject *c) { \ PyObject *tuple, *resultobj; \ int result; \ tuple = PyTuple_New(c ? 2 : 1); \ @@ -182,13 +188,13 @@ wrapper##_closure(PyObject *a, PyObject *b, PyObject *c) { \ #define SWIGPY_REPRFUNC_CLOSURE(wrapper) \ SWIGINTERN PyObject * \ -wrapper##_closure(PyObject *a) { \ +wrapper##_reprfunc_closure(PyObject *a) { \ return wrapper(a, NULL); \ } #define SWIGPY_HASHFUNC_CLOSURE(wrapper) \ SWIGINTERN Py_hash_t \ -wrapper##_closure(PyObject *a) { \ +wrapper##_hashfunc_closure(PyObject *a) { \ PyObject *pyresult; \ Py_hash_t result; \ pyresult = wrapper(a, NULL); \ @@ -199,6 +205,12 @@ wrapper##_closure(PyObject *a) { \ return result; \ } +#define SWIGPY_ITERNEXTFUNC_CLOSURE(wrapper) \ +SWIGINTERN PyObject * \ +wrapper##_iternextfunc_closure(PyObject *a) { \ + return wrapper(a, NULL); \ +} + #ifdef __cplusplus extern "C" { #endif diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx index 1a3b886abe2..380cd98d53b 100644 --- a/Source/Modules/python.cxx +++ b/Source/Modules/python.cxx @@ -47,11 +47,13 @@ static Hash *f_shadow_imports = 0; static String *f_shadow_builtin_imports = 0; static String *f_shadow_stubs = 0; static Hash *builtin_getset = 0; +static Hash *builtin_closures = 0; static Hash *class_members = 0; static File *f_builtins = 0; static String *builtin_tp_init = 0; static String *builtin_methods = 0; static String *builtin_default_unref = 0; +static String *builtin_closures_code = 0; static String *methods; static String *class_name; @@ -188,7 +190,7 @@ static String *getClosure(String *functype, String *wrapper, int funpack = 0) { "unaryfunc", "SWIGPY_UNARYFUNC_CLOSURE", "destructor", "SWIGPY_DESTRUCTOR_CLOSURE", "inquiry", "SWIGPY_INQUIRY_CLOSURE", - "getiterfunc", "SWIGPY_UNARYFUNC_CLOSURE", + "getiterfunc", "SWIGPY_GETITERFUNC_CLOSURE", "binaryfunc", "SWIGPY_BINARYFUNC_CLOSURE", "ternaryfunc", "SWIGPY_TERNARYFUNC_CLOSURE", "ternarycallfunc", "SWIGPY_TERNARYCALLFUNC_CLOSURE", @@ -200,7 +202,7 @@ static String *getClosure(String *functype, String *wrapper, int funpack = 0) { "objobjargproc", "SWIGPY_OBJOBJARGPROC_CLOSURE", "reprfunc", "SWIGPY_REPRFUNC_CLOSURE", "hashfunc", "SWIGPY_HASHFUNC_CLOSURE", - "iternextfunc", "SWIGPY_UNARYFUNC_CLOSURE", + "iternextfunc", "SWIGPY_ITERNEXTFUNC_CLOSURE", NULL }; @@ -208,7 +210,7 @@ static String *getClosure(String *functype, String *wrapper, int funpack = 0) { "unaryfunc", "SWIGPY_UNARYFUNC_CLOSURE", "destructor", "SWIGPY_DESTRUCTOR_CLOSURE", "inquiry", "SWIGPY_INQUIRY_CLOSURE", - "getiterfunc", "SWIGPY_UNARYFUNC_CLOSURE", + "getiterfunc", "SWIGPY_GETITERFUNC_CLOSURE", "ternaryfunc", "SWIGPY_TERNARYFUNC_CLOSURE", "ternarycallfunc", "SWIGPY_TERNARYCALLFUNC_CLOSURE", "lenfunc", "SWIGPY_LENFUNC_CLOSURE", @@ -219,7 +221,7 @@ static String *getClosure(String *functype, String *wrapper, int funpack = 0) { "objobjargproc", "SWIGPY_OBJOBJARGPROC_CLOSURE", "reprfunc", "SWIGPY_REPRFUNC_CLOSURE", "hashfunc", "SWIGPY_HASHFUNC_CLOSURE", - "iternextfunc", "SWIGPY_UNARYFUNC_CLOSURE", + "iternextfunc", "SWIGPY_ITERNEXTFUNC_CLOSURE", NULL }; @@ -626,6 +628,8 @@ class PYTHON:public Language { f_directors_h = NewString(""); f_directors = NewString(""); builtin_getset = NewHash(); + builtin_closures = NewHash(); + builtin_closures_code = NewString(""); class_members = NewHash(); builtin_methods = NewString(""); builtin_default_unref = NewString("delete $self;"); @@ -3328,11 +3332,12 @@ class PYTHON:public Language { String *func_type = Getattr(n, "feature:python:slot:functype"); String *closure_decl = getClosure(func_type, wrapper_name, overname ? 0 : funpack); String *feature_name = NewStringf("feature:python:%s", slot); - String *closure_name = Copy(wrapper_name); + String *closure_name = 0; if (closure_decl) { - Append(closure_name, "_closure"); - if (!Getattr(n, "sym:overloaded") || !Getattr(n, "sym:nextSibling")) - Printf(f_wrappers, "%s /* defines %s */\n\n", closure_decl, closure_name); + closure_name = NewStringf("%s_%s_closure", wrapper_name, func_type); + if (!GetFlag(builtin_closures, closure_name)) + Printf(builtin_closures_code, "%s /* defines %s */\n\n", closure_decl, closure_name); + SetFlag(builtin_closures, closure_name); Delete(closure_decl); } if (func_type) { @@ -4511,7 +4516,12 @@ class PYTHON:public Language { SwigType *realct = Copy(real_classname); SwigType_add_pointer(realct); SwigType_remember(realct); - if (!builtin) { + if (builtin) { + Printv(f_wrappers, builtin_closures_code, NIL); + Delete(builtin_closures_code); + builtin_closures_code = NewString(""); + Clear(builtin_closures); + } else { Printv(f_wrappers, "SWIGINTERN PyObject *", class_name, "_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {\n", NIL); Printv(f_wrappers, " PyObject *obj;\n", NIL); if (modernargs) {