More flexible python builtin slots

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 */
This commit is contained in:
William S Fulton 2016-09-22 08:12:46 +01:00
commit 848628ae91
5 changed files with 140 additions and 24 deletions

View file

@ -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.

View file

@ -79,3 +79,16 @@ if is_python_builtin():
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")

View file

@ -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 <exception.i>
%include <std_except.i>
%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<size; ++x)
numbers[x] = x*10;
}
Py_ssize_t __len__() {
return size;
}
int __getitem__(Py_ssize_t n) throw (std::out_of_range) {
if (n >= (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; x<size; ++x)
n.numbers[x] = numbers[x+ii];
return n;
}
}
};
%}

View file

@ -1,12 +1,12 @@
#define SWIGPY_UNARYFUNC_CLOSURE(wrapper) \
SWIGINTERN PyObject * \
wrapper##_closure(PyObject *a) { \
wrapper##_unaryfunc_closure(PyObject *a) { \
return wrapper(a, NULL); \
}
#define SWIGPY_DESTRUCTOR_CLOSURE(wrapper) \
SWIGINTERN void \
wrapper##_closure(PyObject *a) { \
wrapper##_destructor_closure(PyObject *a) { \
SwigPyObject *sobj; \
sobj = (SwigPyObject *)a; \
Py_XDECREF(sobj->dict); \
@ -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

View file

@ -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 @@ public:
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 @@ public:
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 @@ public:
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) {