Commit 3e100545 authored by David Gobbi's avatar David Gobbi

Avoid creating duplicate wrapped namespaces.

In C++, the contents of a single namespace can be defined in more
than one header.  We must allow for this when wrapping namespaces
in python, by checking if the namespace has already been created.

Change-Id: Ib64d0fad648cf597c59f3a67edcb9a165594fbf6
parent d5cb2382
......@@ -9,6 +9,7 @@ set(Module_SRCS
vtkSmartPyObject.cxx
PyVTKClass.cxx
PyVTKMutableObject.cxx
PyVTKNamespace.cxx
PyVTKObject.cxx
PyVTKSpecialObject.cxx
PyVTKTemplate.cxx
......
/*=========================================================================
Program: Visualization Toolkit
Module: PyVTKNamespace.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
/*-----------------------------------------------------------------------
The PyVTKNamespace was created in Nov 2014 by David Gobbi.
This is a PyModule subclass for wrapping C++ namespaces.
-----------------------------------------------------------------------*/
#include "PyVTKNamespace.h"
#include "vtkPythonUtil.h"
// Silence warning like
// "dereferencing type-punned pointer will break strict-aliasing rules"
// it happens because this kind of expression: (long *)&ptr
// pragma GCC diagnostic is available since gcc>=4.2
#if defined(__GNUC__) && (__GNUC__>4) || (__GNUC__==4 && __GNUC_MINOR__>=2)
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
//--------------------------------------------------------------------
const char *PyVTKNamespace_Doc =
"A python module that wraps a C++ namespace.\n";
//--------------------------------------------------------------------
static void PyVTKNamespace_Delete(PyObject *op)
{
// remove from the map so that there is no dangling reference
vtkPythonUtil::RemoveNamespaceFromMap(op);
// call the superclass destructor
PyVTKNamespace_Type.tp_base->tp_dealloc(op);
}
//--------------------------------------------------------------------
PyTypeObject PyVTKNamespace_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
(char*)"vtk.namespace", // tp_name
0, // tp_basicsize
0, // tp_itemsize
PyVTKNamespace_Delete, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
0, // tp_compare
0, // tp_repr
0, // tp_as_number
0, // tp_as_sequence
0, // tp_as_mapping
0, // tp_hash
0, // tp_call
0, // tp_string
0, // tp_getattro
0, // tp_setattro
0, // tp_as_buffer
Py_TPFLAGS_DEFAULT, // tp_flags
(char*)PyVTKNamespace_Doc, // tp_doc
0, // tp_traverse
0, // tp_clear
0, // tp_richcompare
0, // tp_weaklistoffset
0, // tp_iter
0, // tp_iternext
0, // tp_methods
0, // tp_members
0, // tp_getset
&PyModule_Type, // tp_base
0, // tp_dict
0, // tp_descr_get
0, // tp_descr_set
0, // tp_dictoffset
0, // tp_init
0, // tp_alloc
0, // tp_new
0, // tp_free
0, // tp_is_gc
0, // tp_bases
0, // tp_mro
0, // tp_cache
0, // tp_subclasses
0, // tp_weaklist
VTK_WRAP_PYTHON_SUPRESS_UNINITIALIZED
};
//--------------------------------------------------------------------
PyObject *PyVTKNamespace_New(const char *name)
{
// first check to see if this namespace exists
PyObject *self = vtkPythonUtil::FindNamespace(name);
if (self)
{
Py_INCREF(self);
}
else
{
// make sure python has readied the type object
PyType_Ready(&PyVTKNamespace_Type);
// call the allocator provided by python for this type
self = PyVTKNamespace_Type.tp_alloc(&PyVTKNamespace_Type, 0);
// call the superclass init function
PyObject *args = PyTuple_New(1);
PyTuple_SET_ITEM(args, 0, PyString_FromString(name));
PyVTKNamespace_Type.tp_base->tp_init(self, args, 0);
Py_DECREF(args);
// remember the object for later reference
vtkPythonUtil::AddNamespaceToMap(self);
}
return self;
}
//--------------------------------------------------------------------
PyObject *PyVTKNamespace_GetDict(PyObject *self)
{
return PyModule_GetDict(self);
}
//--------------------------------------------------------------------
const char *PyVTKNamespace_GetName(PyObject *self)
{
return PyModule_GetName(self);
}
/*=========================================================================
Program: Visualization Toolkit
Module: PyVTKNamespace.h
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
/*-----------------------------------------------------------------------
The PyVTKNamespace was created in Nov 2014 by David Gobbi.
This is a PyModule subclass for wrapping C++ namespaces.
-----------------------------------------------------------------------*/
#ifndef __PyVTKNamespace_h
#define __PyVTKNamespace_h
#include "vtkWrappingPythonCoreModule.h" // For export macro
#include "vtkPython.h"
#include "vtkSystemIncludes.h"
extern VTKWRAPPINGPYTHONCORE_EXPORT PyTypeObject PyVTKNamespace_Type;
#define PyVTKNamespace_Check(obj) ((obj)->ob_type == &PyVTKNamespace_Type)
extern "C"
{
VTKWRAPPINGPYTHONCORE_EXPORT
PyObject *PyVTKNamespace_New(const char *name);
VTKWRAPPINGPYTHONCORE_EXPORT
PyObject *PyVTKNamespace_GetDict(PyObject *self);
VTKWRAPPINGPYTHONCORE_EXPORT
const char *PyVTKNamespace_GetName(PyObject *self);
}
#endif
......@@ -59,7 +59,7 @@ public:
};
//--------------------------------------------------------------------
// There are five maps associated with the Python wrappers
// There are six maps associated with the Python wrappers
// Map VTK objects to python objects (this is also the cornerstone
// of the vtk/python garbage collection system, because it contains
......@@ -105,6 +105,12 @@ class vtkPythonSpecialTypeMap
{
};
// Keep track of all the C++ namespaces that have been wrapped.
class vtkPythonNamespaceMap
: public std::map<std::string, PyObject*>
{
};
// Keep track of all vtkPythonCommand instances.
class vtkPythonCommandList
: public std::vector<vtkWeakPointer<vtkPythonCommand> >
......@@ -157,6 +163,7 @@ vtkPythonUtil::vtkPythonUtil()
this->GhostMap = new vtkPythonGhostMap;
this->ClassMap = new vtkPythonClassMap;
this->SpecialTypeMap = new vtkPythonSpecialTypeMap;
this->NamespaceMap = new vtkPythonNamespaceMap;
this->PythonCommandList = new vtkPythonCommandList;
}
......@@ -167,6 +174,7 @@ vtkPythonUtil::~vtkPythonUtil()
delete this->GhostMap;
delete this->ClassMap;
delete this->SpecialTypeMap;
delete this->NamespaceMap;
delete this->PythonCommandList;
}
......@@ -804,6 +812,67 @@ void *vtkPythonUtil::GetPointerFromSpecialObject(
return NULL;
}
//--------------------------------------------------------------------
void vtkPythonUtil::AddNamespaceToMap(PyObject *module)
{
if (!PyVTKNamespace_Check(module))
{
return;
}
if (vtkPythonMap == NULL)
{
vtkPythonMap = new vtkPythonUtil();
Py_AtExit(vtkPythonUtilDelete);
}
const char *name = PyVTKNamespace_GetName(module);
// let's make sure it isn't already there
vtkPythonNamespaceMap::iterator i =
vtkPythonMap->NamespaceMap->find(name);
if (i != vtkPythonMap->NamespaceMap->end())
{
return;
}
(*vtkPythonMap->NamespaceMap)[name] = module;
}
//--------------------------------------------------------------------
// This method is called
void vtkPythonUtil::RemoveNamespaceFromMap(PyObject *obj)
{
if (vtkPythonMap && PyVTKNamespace_Check(obj))
{
const char *name = PyVTKNamespace_GetName(obj);
vtkPythonNamespaceMap::iterator it =
vtkPythonMap->NamespaceMap->find(name);
if (it != vtkPythonMap->NamespaceMap->end() &&
it->second == obj)
{
// The map has a pointer to the object, but does not hold a
// reference, therefore there is no decref.
vtkPythonMap->NamespaceMap->erase(it);
}
}
}
//--------------------------------------------------------------------
PyObject *vtkPythonUtil::FindNamespace(const char *name)
{
if (vtkPythonMap)
{
vtkPythonNamespaceMap::iterator it =
vtkPythonMap->NamespaceMap->find(name);
if (it != vtkPythonMap->NamespaceMap->end())
{
return it->second;
}
}
return NULL;
}
//--------------------------------------------------------------------
// mangle a void pointer into a SWIG-style string
char *vtkPythonUtil::ManglePointer(const void *ptr, const char *type)
......
......@@ -21,6 +21,7 @@
#include "vtkPython.h"
#include "PyVTKClass.h"
#include "PyVTKMutableObject.h"
#include "PyVTKNamespace.h"
#include "PyVTKObject.h"
#include "PyVTKSpecialObject.h"
......@@ -30,6 +31,7 @@ class vtkPythonCommandList;
class vtkPythonGhostMap;
class vtkPythonObjectMap;
class vtkPythonSpecialTypeMap;
class vtkPythonNamespaceMap;
class vtkStdString;
class vtkUnicodeString;
class vtkVariant;
......@@ -126,6 +128,20 @@ public:
static void *GetPointerFromSpecialObject(
PyObject *obj, const char *result_type, PyObject **newobj);
// Description:
// Add a wrapped C++ namespace as a python module object. This allows
// the namespace to be retrieved and added to as necessary.
static void AddNamespaceToMap(PyObject *o);
// Description:
// Remove a wrapped C++ namespace from consideration. This is called
// from the namespace destructor.
static void RemoveNamespaceFromMap(PyObject *o);
// Description:
// Return an existing namespace, or NULL if it doesn't exist.
static PyObject *FindNamespace(const char *name);
// Description:
// Utility function to build a docstring by concatenating a series
// of strings until a null string is found.
......@@ -161,6 +177,7 @@ private:
vtkPythonGhostMap *GhostMap;
vtkPythonClassMap *ClassMap;
vtkPythonSpecialTypeMap *SpecialTypeMap;
vtkPythonNamespaceMap *NamespaceMap;
vtkPythonCommandList *PythonCommandList;
friend void vtkPythonUtilDelete();
......
......@@ -41,7 +41,7 @@ int vtkWrapPython_WrapNamespace(FILE *fp, NamespaceInfo *data)
fprintf(fp,
"static PyObject *PyVTKNamespace_%s()\n"
"{\n"
" PyObject *m = PyModule_New(\"%s\");\n"
" PyObject *m = PyVTKNamespace_New(\"%s\");\n"
"\n",
data->Name, data->Name);
......@@ -49,7 +49,7 @@ int vtkWrapPython_WrapNamespace(FILE *fp, NamespaceInfo *data)
data->NumberOfConstants)
{
fprintf(fp,
" PyObject *d = PyModule_GetDict(m);\n"
" PyObject *d = PyVTKNamespace_GetDict(m);\n"
" PyObject *o;\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