Commit 283e2b71 authored by David Gobbi's avatar David Gobbi Committed by Marcus D. Hanwell
Browse files

ENH: Add an optional hash function for python special types.

Python mapping objects require their keys to be hashable.  So, unless
a special object has a hash function, it cannot be stored in a map.
For vtkObjectBase-derived objects, the hash is done on the memory address,
but for special objects, the hash must be computed based on the value.
parent 3257075e
......@@ -138,11 +138,23 @@ static void PyVTKSpecialObject_PyDelete(PyVTKSpecialObject *self)
//--------------------------------------------------------------------
static long PyVTKSpecialObject_PyHash(PyVTKSpecialObject *self)
{
// self->vtk_hash must never be set to anything but -1 for mutable objects
if (self->vtk_hash != -1)
{
return self->vtk_hash;
}
if (self->vtk_ptr && self->vtk_info->hash_func)
{
long val = self->vtk_info->hash_func(self->vtk_ptr);
int imm = 0;
long val = self->vtk_info->hash_func(self->vtk_ptr, &imm);
if (val != -1)
{
if (imm)
{
// cache the hash for immutable objects
self->vtk_hash = val;
}
return val;
}
}
......@@ -250,6 +262,7 @@ PyObject *PyVTKSpecialObject_New(char *classname, void *ptr, int copy)
}
self->vtk_ptr = ptr;
self->vtk_hash = -1;
self->vtk_info = info;
return (PyObject *)self;
......
......@@ -33,8 +33,9 @@ typedef void (*PyVTKSpecialPrintFunc)(ostream& os, void *);
// Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE
// return "-1" if the comparison is impossible
typedef int (*PyVTKSpecialCompareFunc)(void *, void *, int);
// return a hash from the value of the object, or -1 if error
typedef long (*PyVTKSpecialHashFunc)(void *);
// return a hash from the value of the object, or -1 if error,
// set second arg to '1' if the object is immutable
typedef long (*PyVTKSpecialHashFunc)(void *, int *);
// Struct to hold special methods, the first three are mandatory
// and the rest are optional.
......@@ -79,6 +80,7 @@ public:
struct PyVTKSpecialObject {
PyObject_HEAD
void *vtk_ptr;
long vtk_hash;
PyVTKSpecialType *vtk_info;
};
......
......@@ -19,6 +19,7 @@
#include "vtkObject.h"
#include "vtkSmartPointerBase.h"
#include "vtkVariant.h"
#include "vtkWindows.h"
#include <vtksys/ios/sstream>
......@@ -1613,6 +1614,52 @@ int vtkPythonUtil::CheckArray(PyObject *args, int i, unsigned __int64 *a, int n)
}
#endif
//--------------------------------------------------------------------
long vtkPythonUtil::VariantHash(vtkVariant *v)
{
long h = -1;
// This uses the same rules as the vtkVariant "==" operator.
// All types except for vtkObject are converted to strings.
// Quite inefficient, but it gets the job done. Fortunately,
// the python vtkVariant is immutable, so its hash can be cached.
switch (v->GetType())
{
case VTK_OBJECT:
{
h = _Py_HashPointer(v->ToVTKObject());
break;
}
case VTK_UNICODE_STRING:
{
vtkUnicodeString u = v->ToUnicodeString();
const char *s = u.utf8_str();
PyObject *tmp = PyUnicode_DecodeUTF8(s, strlen(s), "strict");
if (tmp == 0)
{
PyErr_Clear();
return 0;
}
h = PyObject_Hash(tmp);
Py_DECREF(tmp);
break;
}
default:
{
vtkStdString s = v->ToString();
PyObject *tmp = PyString_FromString(s.c_str());
h = PyObject_Hash(tmp);
Py_DECREF(tmp);
break;
}
}
return h;
}
//--------------------------------------------------------------------
void vtkPythonVoidFunc(void *arg)
{
......
......@@ -23,6 +23,7 @@
class vtkPythonObjectMap;
class vtkPythonClassMap;
class vtkPythonSpecialTypeMap;
class vtkVariant;
extern "C" void vtkPythonUtilDelete();
......@@ -147,7 +148,7 @@ public:
static void *UnmanglePointer(char *ptrText, int *len, const char *type);
// Description:
// check array arguments sent through the wrappers to see if the
// Check array arguments sent through the wrappers to see if the
// underlying C++ method changed the values, and attempt to modify
// the original python sequence (list or tuple) if so.
static int CheckArray(PyObject *args, int i, bool *a, int n);
......@@ -171,6 +172,10 @@ public:
static int CheckArray(PyObject *args, int i, unsigned __int64 *a, int n);
#endif
// Description:
// Compute a hash for a vtkVariant.
static long VariantHash(vtkVariant *variant);
private:
vtkPythonUtil();
~vtkPythonUtil();
......
......@@ -2443,6 +2443,7 @@ void vtkParseOutput(FILE *fp, FileInfo *data)
static char *compare_tokens[6] = {
"<", "<=", "==", "!=", ">", ">=" };
int compare_ops = 0;
int has_hash = 0;
int class_has_new = 0;
int i;
......@@ -2816,6 +2817,40 @@ void vtkParseOutput(FILE *fp, FileInfo *data)
"\n");
}
/* the hash function for vtkTimeStamp */
if (strcmp(data->ClassName, "vtkTimeStamp") == 0)
{
has_hash = 1;
fprintf(fp,
"static long vtkSpecial_%sHash(void *self, int *immutable)\n"
"{\n"
" unsigned long mtime = *((vtkTimeStamp *)self);\n"
" long h = (long)mtime;\n"
" *immutable = 0;\n"
" if (h != -1) { return h; };\n"
" return -1;\n"
"}\n"
"\n",
data->ClassName);
}
/* the hash function for vtkVariant */
if (strcmp(data->ClassName, "vtkVariant") == 0)
{
has_hash = 1;
fprintf(fp,
"static long vtkSpecial_%sHash(void *self, int *immutable)\n"
"{\n"
" long h = vtkPythonUtil::VariantHash((vtkVariant *)self);\n"
" *immutable = 1;\n"
" return h;\n"
"}\n"
"\n",
data->ClassName);
}
/* the table to hold these special methods */
fprintf(fp,
"static PyVTKSpecialMethods vtkSpecial_%sSpecialMethods =\n"
......@@ -2837,8 +2872,20 @@ void vtkParseOutput(FILE *fp, FileInfo *data)
fprintf(fp,
" 0,\n");
}
if (has_hash)
{
fprintf(fp,
" &vtkSpecial_%sHash,\n",
data->ClassName);
}
else
{
fprintf(fp,
" 0,\n");
}
fprintf(fp,
" 0,\n"
"};\n"
"\n");
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment