summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam S Fulton <wsf@fultondesigns.co.uk>2016-08-23 18:15:35 +0100
committerWilliam S Fulton <wsf@fultondesigns.co.uk>2016-08-23 19:06:36 +0100
commit5b7c08c21449c407019f4484c91819a441e8bd9c (patch)
tree8d0da2e462920a194e09106b2b82656068e2a80e
parent253a39fdffc9b3c270ba815d6e60f416a4ee46a7 (diff)
downloadswig-builtin-hashable.tar.gz
Make Python builtin types hashable by defaultbuiltin-hashable
Default hash is the underlying C/C++ pointer. This matches up with testing for equivalence (Py_EQ in SwigPyObject_richcompare) which compares the pointers.
-rw-r--r--Examples/test-suite/python/python_builtin_runme.py11
-rw-r--r--Examples/test-suite/python_builtin.i14
-rw-r--r--Lib/python/builtin.swg40
-rw-r--r--Lib/python/pyhead.swg1
-rw-r--r--Source/Modules/python.cxx3
5 files changed, 53 insertions, 16 deletions
diff --git a/Examples/test-suite/python/python_builtin_runme.py b/Examples/test-suite/python/python_builtin_runme.py
index c41dfc0b1..70990cbfd 100644
--- a/Examples/test-suite/python/python_builtin_runme.py
+++ b/Examples/test-suite/python/python_builtin_runme.py
@@ -1,6 +1,17 @@
from python_builtin import *
if is_python_builtin():
+ # Test 0 for default tp_hash
+ vs = ValueStruct(1234)
+ h = hash(vs)
+ d = dict()
+ d[h] = "hi"
+ if h not in d:
+ raise RuntimeError("h should be in d")
+ h2 = hash(ValueStruct.inout(vs))
+ if h != h2:
+ raise RuntimeError("default tp_hash not working")
+
# Test 1 for tp_hash
if hash(SimpleValue(222)) != 222:
raise RuntimeError("tp_hash not working")
diff --git a/Examples/test-suite/python_builtin.i b/Examples/test-suite/python_builtin.i
index ac1ad9c2d..e2c453d54 100644
--- a/Examples/test-suite/python_builtin.i
+++ b/Examples/test-suite/python_builtin.i
@@ -10,6 +10,17 @@ bool is_python_builtin() { return false; }
#endif
%}
+// Test 0 for default tp_hash
+%inline %{
+struct ValueStruct {
+ int value;
+ ValueStruct(int value) : value(value) {}
+ static ValueStruct *inout(ValueStruct *v) {
+ return v;
+ }
+};
+%}
+
// Test 1 for tp_hash
#if defined(SWIGPYTHON_BUILTIN)
%feature("python:tp_hash") SimpleValue "SimpleValueHashFunction"
@@ -19,9 +30,6 @@ bool is_python_builtin() { return false; }
struct SimpleValue {
int value;
SimpleValue(int value) : value(value) {}
- static SimpleValue *inout(SimpleValue *sv) {
- return sv;
- }
};
%}
diff --git a/Lib/python/builtin.swg b/Lib/python/builtin.swg
index 3dd5bbf95..1244dbbcc 100644
--- a/Lib/python/builtin.swg
+++ b/Lib/python/builtin.swg
@@ -187,19 +187,14 @@ wrapper##_closure(PyObject *a) { \
}
#define SWIGPY_HASHFUNC_CLOSURE(wrapper) \
-SWIGINTERN long \
+SWIGINTERN Py_hash_t \
wrapper##_closure(PyObject *a) { \
PyObject *pyresult; \
- long result; \
+ Py_hash_t result; \
pyresult = wrapper(a, NULL); \
if (!pyresult) \
return -1; \
- if (!PyLong_Check(pyresult)) \
- PyErr_Format(PyExc_TypeError, "Wrong type for hash function");\
- else \
- result = PyLong_AsLong(pyresult); \
- if (PyErr_Occurred()) \
- result = -1; \
+ result = SWIG_PyNumber_AsPyHash(pyresult); \
Py_DECREF(pyresult); \
return result; \
}
@@ -227,14 +222,35 @@ SwigPyBuiltin_BadInit(PyObject *self, PyObject *SWIGUNUSEDPARM(args), PyObject *
}
SWIGINTERN void
-SwigPyBuiltin_BadDealloc(PyObject *pyobj) {
- SwigPyObject *sobj;
- sobj = (SwigPyObject *)pyobj;
+SwigPyBuiltin_BadDealloc(PyObject *obj) {
+ SwigPyObject *sobj = (SwigPyObject *)obj;
if (sobj->own) {
- PyErr_Format(PyExc_TypeError, "Swig detected a memory leak in type '%.300s': no callable destructor found.", pyobj->ob_type->tp_name);
+ PyErr_Format(PyExc_TypeError, "Swig detected a memory leak in type '%.300s': no callable destructor found.", obj->ob_type->tp_name);
}
}
+SWIGINTERN Py_hash_t
+SwigPyObject_hash(PyObject *obj) {
+ SwigPyObject *sobj = (SwigPyObject *)obj;
+ void *ptr = sobj->ptr;
+ return (Py_hash_t)ptr;
+}
+
+SWIGINTERN Py_hash_t
+SWIG_PyNumber_AsPyHash(PyObject *obj) {
+ Py_hash_t result = -1;
+#if PY_VERSION_HEX < 0x03020000
+ if (PyLong_Check(obj))
+ result = PyLong_AsLong(obj);
+#else
+ if (PyNumber_Check(obj))
+ result = PyNumber_AsSsize_t(obj, NULL);
+#endif
+ else
+ PyErr_Format(PyExc_TypeError, "Wrong type for hash function");
+ return result;
+}
+
typedef struct {
PyCFunction get;
PyCFunction set;
diff --git a/Lib/python/pyhead.swg b/Lib/python/pyhead.swg
index 63df684b6..55eb95a6d 100644
--- a/Lib/python/pyhead.swg
+++ b/Lib/python/pyhead.swg
@@ -211,4 +211,5 @@ typedef destructor freefunc;
#if PY_VERSION_HEX < 0x03020000
#define PyDescr_TYPE(x) (((PyDescrObject *)(x))->d_type)
#define PyDescr_NAME(x) (((PyDescrObject *)(x))->d_name)
+#define Py_hash_t long
#endif
diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx
index d31554071..40d3d9a8a 100644
--- a/Source/Modules/python.cxx
+++ b/Source/Modules/python.cxx
@@ -4057,6 +4057,7 @@ public:
static String *tp_basicsize = NewStringf("sizeof(SwigPyObject)");
static String *tp_dictoffset_default = NewString("offsetof(SwigPyObject, dict)");
static String *tp_new = NewString("PyType_GenericNew");
+ static String *tp_hash = NewString("SwigPyObject_hash");
String *tp_as_number = NewStringf("&%s_type.as_number", templ);
String *tp_as_sequence = NewStringf("&%s_type.as_sequence", templ);
String *tp_as_mapping = NewStringf("&%s_type.as_mapping", templ);
@@ -4088,7 +4089,7 @@ public:
printSlot(f, getSlot(n, "feature:python:tp_as_number", tp_as_number), "tp_as_number");
printSlot(f, getSlot(n, "feature:python:tp_as_sequence", tp_as_sequence), "tp_as_sequence");
printSlot(f, getSlot(n, "feature:python:tp_as_mapping", tp_as_mapping), "tp_as_mapping");
- printSlot(f, getSlot(n, "feature:python:tp_hash"), "tp_hash", "hashfunc");
+ printSlot(f, getSlot(n, "feature:python:tp_hash", tp_hash), "tp_hash", "hashfunc");
printSlot(f, getSlot(n, "feature:python:tp_call"), "tp_call", "ternaryfunc");
printSlot(f, getSlot(n, "feature:python:tp_str"), "tp_str", "reprfunc");
printSlot(f, getSlot(n, "feature:python:tp_getattro"), "tp_getattro", "getattrofunc");