Make Python builtin types hashable by default
Default hash is the underlying C/C++ pointer. This matches up with testing for equivalence (Py_EQ in SwigPyObject_richcompare) which compares the pointers.
This commit is contained in:
parent
253a39fdff
commit
5b7c08c214
5 changed files with 53 additions and 16 deletions
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
%}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue