Python -builtin __contains__ fix for map and set like containers.

Fix when using -builtin and wrapping std::map, std::set, std::unordered_map or
std::unordered_set to ensure __contains__ is called. This is a wrapper for the STL
container's find method. Without it, Python will do its own slower sequence search.
This commit is contained in:
William S Fulton 2018-09-21 08:40:55 +01:00
commit 4715a4e72c
8 changed files with 76 additions and 2 deletions

View file

@ -7,6 +7,11 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.0.0 (in progress)
===========================
2018-09-21: wsfulton
[Python] Fix when using -builtin and wrapping std::map, std::set, std::unordered_map or
std::unordered_set to ensure __contains__ is called. This is a wrapper for the STL
container's find method. Without it, Python will do its own slower sequence search.
2018-09-19: wsfulton
[Python] Fix functors (wrapped as __call__) when using -builtin -modern -fastunpack.

View file

@ -69,6 +69,15 @@ for k in map:
if map[k] != imap[k]:
raise RuntimeError, "bad map"
# Test __contains__ (required for 'x in y' to work)
if not imap.__contains__('hello'):
raise RuntimeError("hello imap.__contains__")
if 'hello' not in imap:
raise RuntimeError("hello not in imap")
if imap.__contains__('oops'):
raise RuntimeError("oops imap.__contains__")
if 'oops' in imap:
raise RuntimeError("oops in imap")
mapc = {}
c1 = std_containers.C()
@ -114,3 +123,14 @@ for i in s:
if i != j:
raise RuntimeError
j = j + 1
# Test __contains__ (required for 'x in y' to work)
if not s.__contains__(3):
raise RuntimeError("3 s.__contains__")
if 3 not in s:
raise RuntimeError("3 not in s")
if s.__contains__(-1):
raise RuntimeError("-1 s.__contains__")
if -1 in s:
raise RuntimeError("-1 in s")

View file

@ -635,6 +635,42 @@ SwigPyBuiltin_ssizeobjargproc_closure(SwigPyWrapperFunction wrapper, PyObject *a
return result;
}
#define SWIGPY_OBJOBJPROC_CLOSURE(wrapper) \
SWIGINTERN int \
wrapper##_objobjproc_closure(PyObject *a, PyObject *b) { \
return SwigPyBuiltin_objobjproc_closure(wrapper, a, b); \
}
SWIGINTERN int
SwigPyBuiltin_objobjproc_closure(SwigPyWrapperFunction wrapper, PyObject *a, PyObject *b) {
int result;
PyObject *pyresult;
PyObject *tuple;
tuple = PyTuple_New(1);
assert(tuple);
PyTuple_SET_ITEM(tuple, 0, b);
Py_XINCREF(b);
pyresult = wrapper(a, tuple);
result = pyresult ? (PyObject_IsTrue(pyresult) ? 1 : 0) : -1;
Py_XDECREF(pyresult);
Py_DECREF(tuple);
return result;
}
#define SWIGPY_FUNPACK_OBJOBJPROC_CLOSURE(wrapper) \
SWIGINTERN int \
wrapper##_objobjproc_closure(PyObject *a, PyObject *b) { \
return SwigPyBuiltin_funpack_objobjproc_closure(wrapper, a, b); \
}
SWIGINTERN int
SwigPyBuiltin_funpack_objobjproc_closure(SwigPyWrapperFunction wrapper, PyObject *a, PyObject *b) {
int result;
PyObject *pyresult;
pyresult = wrapper(a, b);
result = pyresult ? (PyObject_IsTrue(pyresult) ? 1 : 0) : -1;
Py_XDECREF(pyresult);
return result;
}
#define SWIGPY_OBJOBJARGPROC_CLOSURE(wrapper) \
SWIGINTERN int \
wrapper##_objobjargproc_closure(PyObject *a, PyObject *b, PyObject *c) { \

View file

@ -156,6 +156,7 @@
%feature("python:slot", "mp_length", functype="lenfunc") __len__;
%feature("python:slot", "mp_subscript", functype="binaryfunc") __getitem__;
%feature("python:slot", "tp_iter", functype="getiterfunc") key_iterator;
%feature("python:slot", "sq_contains", functype="objobjproc") __contains__;
%extend {
%newobject iterkeys(PyObject **PYTHON_SELF);
@ -263,7 +264,6 @@
return itemList;
}
// Python 2.2 methods
bool __contains__(const key_type& key) {
return self->find(key) != self->end();
}

View file

@ -36,6 +36,10 @@
%swig_sequence_iterator(set);
%swig_container_methods(set);
#if defined(SWIGPYTHON_BUILTIN)
%feature("python:slot", "sq_contains", functype="objobjproc") __contains__;
#endif
%extend {
void append(value_type x) {
self->insert(x);

View file

@ -131,6 +131,10 @@
%swig_sequence_forward_iterator(Map);
%swig_container_methods(Map)
#if defined(SWIGPYTHON_BUILTIN)
%feature("python:slot", "sq_contains", functype="objobjproc") __contains__;
#endif
%extend {
mapped_type __getitem__(const key_type& key) const throw (std::out_of_range) {
Map::const_iterator i = self->find(key);
@ -204,7 +208,6 @@
return itemList;
}
// Python 2.2 methods
bool __contains__(const key_type& key) {
return self->find(key) != self->end();
}

View file

@ -43,6 +43,10 @@
%swig_sequence_forward_iterator(unordered_set);
%swig_container_methods(unordered_set);
#if defined(SWIGPYTHON_BUILTIN)
%feature("python:slot", "sq_contains", functype="objobjproc") __contains__;
#endif
%extend {
void append(value_type x) {
self->insert(x);

View file

@ -210,6 +210,7 @@ static String *getClosure(String *functype, String *wrapper, int funpack = 0) {
"ssizessizeargfunc", "SWIGPY_SSIZESSIZEARGFUNC_CLOSURE",
"ssizeobjargproc", "SWIGPY_SSIZEOBJARGPROC_CLOSURE",
"ssizessizeobjargproc", "SWIGPY_SSIZESSIZEOBJARGPROC_CLOSURE",
"objobjproc", "SWIGPY_OBJOBJPROC_CLOSURE",
"objobjargproc", "SWIGPY_OBJOBJARGPROC_CLOSURE",
"reprfunc", "SWIGPY_REPRFUNC_CLOSURE",
"hashfunc", "SWIGPY_HASHFUNC_CLOSURE",
@ -229,6 +230,7 @@ static String *getClosure(String *functype, String *wrapper, int funpack = 0) {
"ssizessizeargfunc", "SWIGPY_SSIZESSIZEARGFUNC_CLOSURE",
"ssizeobjargproc", "SWIGPY_SSIZEOBJARGPROC_CLOSURE",
"ssizessizeobjargproc", "SWIGPY_SSIZESSIZEOBJARGPROC_CLOSURE",
"objobjproc", "SWIGPY_FUNPACK_OBJOBJPROC_CLOSURE",
"objobjargproc", "SWIGPY_OBJOBJARGPROC_CLOSURE",
"reprfunc", "SWIGPY_REPRFUNC_CLOSURE",
"hashfunc", "SWIGPY_HASHFUNC_CLOSURE",