forked from bartvdbraak/blender
4ff7c5eed6
Includes preprocessed Mantaflow source files for both OpenMP and TBB (if OpenMP is not present, TBB files will be used instead). These files come directly from the Mantaflow repository. Future updates to the core fluid solver will take place by updating the files. Reviewed By: sergey, mont29 Maniphest Tasks: T59995 Differential Revision: https://developer.blender.org/D3850
785 lines
25 KiB
C++
785 lines
25 KiB
C++
/******************************************************************************
|
|
*
|
|
* MantaFlow fluid solver framework
|
|
* Copyright 2011-2014 Tobias Pfaff, Nils Thuerey
|
|
*
|
|
* This program is free software, distributed under the terms of the
|
|
* Apache License, Version 2.0
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Auto python registry
|
|
*
|
|
******************************************************************************/
|
|
|
|
#include <string.h>
|
|
#include "pythonInclude.h"
|
|
#include "structmember.h"
|
|
#include "manta.h"
|
|
|
|
using namespace std;
|
|
|
|
const string gDefaultModuleName = "manta";
|
|
|
|
namespace Pb {
|
|
|
|
//******************************************************************************
|
|
// Custom object definition
|
|
|
|
struct Method {
|
|
Method(const string &n, const string &d, GenericFunction f) : name(n), doc(d), func(f)
|
|
{
|
|
}
|
|
string name, doc;
|
|
GenericFunction func;
|
|
|
|
PyMethodDef def()
|
|
{
|
|
PyMethodDef def = {&name[0], (PyCFunction)func, METH_VARARGS | METH_KEYWORDS, &doc[0]};
|
|
return def;
|
|
}
|
|
};
|
|
struct GetSet {
|
|
GetSet() : getter(0), setter(0)
|
|
{
|
|
}
|
|
GetSet(const string &n, const string &d, Getter g, Setter s)
|
|
: name(n), doc(d), getter(g), setter(s)
|
|
{
|
|
}
|
|
string name, doc;
|
|
Getter getter;
|
|
Setter setter;
|
|
|
|
PyGetSetDef def()
|
|
{
|
|
PyGetSetDef def = {&name[0], getter, setter, &doc[0], NULL};
|
|
return def;
|
|
}
|
|
};
|
|
|
|
struct ClassData {
|
|
string cName, pyName;
|
|
string cPureName, cTemplate;
|
|
InitFunc init;
|
|
PyTypeObject typeInfo;
|
|
PyNumberMethods numInfo;
|
|
// PySequenceMethods seqInfo;
|
|
vector<Method> methods;
|
|
map<string, GetSet> getset;
|
|
map<string, OperatorFunction> ops;
|
|
ClassData *baseclass;
|
|
string baseclassName;
|
|
Constructor constructor;
|
|
|
|
vector<PyMethodDef> genMethods;
|
|
vector<PyGetSetDef> genGetSet;
|
|
};
|
|
|
|
struct PbObject {
|
|
PyObject_HEAD Manta::PbClass *instance;
|
|
ClassData *classdef;
|
|
};
|
|
|
|
//******************************************************
|
|
// Internal wrapper class
|
|
|
|
//! Registers all classes and methods exposed to Python.
|
|
/*! This class is only used internally by Pb:: framwork.
|
|
* Please use the functionality of PbClass to lookup and translate pointers. */
|
|
class WrapperRegistry {
|
|
public:
|
|
static WrapperRegistry &instance();
|
|
void addClass(const std::string &name,
|
|
const std::string &internalName,
|
|
const std::string &baseclass);
|
|
void addEnumEntry(const std::string &name, int value);
|
|
void addExternalInitializer(InitFunc func);
|
|
void addMethod(const std::string &classname,
|
|
const std::string &methodname,
|
|
GenericFunction method);
|
|
void addOperator(const std::string &classname,
|
|
const std::string &methodname,
|
|
OperatorFunction method);
|
|
void addConstructor(const std::string &classname, Constructor method);
|
|
void addGetSet(const std::string &classname,
|
|
const std::string &property,
|
|
Getter getfunc,
|
|
Setter setfunc);
|
|
void addPythonPath(const std::string &path);
|
|
void addPythonCode(const std::string &file, const std::string &code);
|
|
PyObject *createPyObject(const std::string &classname,
|
|
const std::string &name,
|
|
Manta::PbArgs &args,
|
|
Manta::PbClass *parent);
|
|
void construct(const std::string &scriptname, const vector<string> &args);
|
|
void cleanup();
|
|
void renameObjects();
|
|
void runPreInit();
|
|
PyObject *initModule();
|
|
ClassData *lookup(const std::string &name);
|
|
bool canConvert(ClassData *from, ClassData *to);
|
|
|
|
private:
|
|
ClassData *getOrConstructClass(const string &name);
|
|
void registerBaseclasses();
|
|
void registerDummyTypes();
|
|
void registerMeta();
|
|
void addConstants(PyObject *module);
|
|
void registerOperators(ClassData *cls);
|
|
void addParentMethods(ClassData *cls, ClassData *base);
|
|
WrapperRegistry();
|
|
std::map<std::string, ClassData *> mClasses;
|
|
std::vector<ClassData *> mClassList;
|
|
std::vector<InitFunc> mExtInitializers;
|
|
std::vector<std::string> mPaths;
|
|
std::string mCode, mScriptName;
|
|
std::vector<std::string> args;
|
|
std::map<std::string, int> mEnumValues;
|
|
};
|
|
|
|
//******************************************************************************
|
|
// Callback functions
|
|
|
|
PyObject *cbGetClass(PbObject *self, void *cl)
|
|
{
|
|
return Manta::toPy(self->classdef->cPureName);
|
|
}
|
|
|
|
PyObject *cbGetTemplate(PbObject *self, void *cl)
|
|
{
|
|
return Manta::toPy(self->classdef->cTemplate);
|
|
}
|
|
|
|
PyObject *cbGetCName(PbObject *self, void *cl)
|
|
{
|
|
return Manta::toPy(self->classdef->cName);
|
|
}
|
|
|
|
void cbDealloc(PbObject *self)
|
|
{
|
|
// cout << "dealloc " << self->instance->getName() << " " << self->classdef->cName << endl;
|
|
if (self->instance) {
|
|
#ifndef BLENDER
|
|
// don't delete top-level objects
|
|
if (self->instance->getParent() != self->instance)
|
|
delete self->instance;
|
|
#else
|
|
// in Blender we *have* to delete all objects
|
|
delete self->instance;
|
|
#endif
|
|
}
|
|
Py_TYPE(self)->tp_free((PyObject *)self);
|
|
}
|
|
|
|
PyObject *cbNew(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
{
|
|
PbObject *self = (PbObject *)type->tp_alloc(type, 0);
|
|
if (self != NULL) {
|
|
// lookup and link classdef
|
|
self->classdef = WrapperRegistry::instance().lookup(type->tp_name);
|
|
self->instance = NULL;
|
|
// cout << "creating " << self->classdef->cName << endl;
|
|
}
|
|
else
|
|
errMsg("can't allocate new python class object");
|
|
return (PyObject *)self;
|
|
}
|
|
|
|
int cbDisableConstructor(PyObject *self, PyObject *args, PyObject *kwds)
|
|
{
|
|
errMsg("Can't instantiate a class template without template arguments");
|
|
return -1;
|
|
}
|
|
|
|
PyMODINIT_FUNC PyInit_Main(void)
|
|
{
|
|
MantaEnsureRegistration();
|
|
#if PY_MAJOR_VERSION >= 3
|
|
return WrapperRegistry::instance().initModule();
|
|
#else
|
|
WrapperRegistry::instance().initModule();
|
|
#endif
|
|
}
|
|
|
|
//******************************************************
|
|
// WrapperRegistry
|
|
|
|
WrapperRegistry::WrapperRegistry()
|
|
{
|
|
addClass("__modclass__", "__modclass__", "");
|
|
addClass("PbClass", "PbClass", "");
|
|
}
|
|
|
|
ClassData *WrapperRegistry::getOrConstructClass(const string &classname)
|
|
{
|
|
map<string, ClassData *>::iterator it = mClasses.find(classname);
|
|
|
|
if (it != mClasses.end())
|
|
return it->second;
|
|
ClassData *data = new ClassData;
|
|
data->cName = classname;
|
|
data->cPureName = classname;
|
|
data->cTemplate = "";
|
|
size_t tplIdx = classname.find('<');
|
|
if (tplIdx != string::npos) {
|
|
data->cPureName = classname.substr(0, tplIdx);
|
|
data->cTemplate = classname.substr(tplIdx + 1, classname.find('>') - tplIdx - 1);
|
|
}
|
|
data->baseclass = NULL;
|
|
data->constructor = cbDisableConstructor;
|
|
mClasses[classname] = data;
|
|
mClassList.push_back(data);
|
|
return data;
|
|
}
|
|
|
|
void replaceAll(string &source, string const &find, string const &replace)
|
|
{
|
|
for (string::size_type i = 0; (i = source.find(find, i)) != std::string::npos;) {
|
|
source.replace(i, find.length(), replace);
|
|
i += replace.length() - find.length() + 1;
|
|
}
|
|
}
|
|
|
|
void WrapperRegistry::addClass(const string &pyName,
|
|
const string &internalName,
|
|
const string &baseclass)
|
|
{
|
|
ClassData *data = getOrConstructClass(internalName);
|
|
|
|
// regularize python name
|
|
string pythonName = pyName;
|
|
replaceAll(pythonName, "<", "_");
|
|
replaceAll(pythonName, ">", "");
|
|
replaceAll(pythonName, ",", "_");
|
|
|
|
if (data->pyName.empty())
|
|
data->pyName = pythonName;
|
|
mClasses[pythonName] = data;
|
|
if (!baseclass.empty())
|
|
data->baseclassName = baseclass;
|
|
}
|
|
|
|
void WrapperRegistry::addEnumEntry(const string &name, int value)
|
|
{
|
|
/// Gather static definitions to add them as static python objects afterwards
|
|
if (mEnumValues.insert(std::make_pair(name, value)).second == false) {
|
|
errMsg("Enum entry '" + name + "' already existing...");
|
|
}
|
|
}
|
|
|
|
void WrapperRegistry::addExternalInitializer(InitFunc func)
|
|
{
|
|
mExtInitializers.push_back(func);
|
|
}
|
|
|
|
void WrapperRegistry::addPythonPath(const string &path)
|
|
{
|
|
mPaths.push_back(path);
|
|
}
|
|
|
|
void WrapperRegistry::addPythonCode(const string &file, const string &code)
|
|
{
|
|
mCode += code + "\n";
|
|
}
|
|
|
|
void WrapperRegistry::addGetSet(const string &classname,
|
|
const string &property,
|
|
Getter getfunc,
|
|
Setter setfunc)
|
|
{
|
|
ClassData *classdef = getOrConstructClass(classname);
|
|
GetSet &def = classdef->getset[property];
|
|
if (def.name.empty()) {
|
|
def.name = property;
|
|
def.doc = property;
|
|
}
|
|
if (getfunc)
|
|
def.getter = getfunc;
|
|
if (setfunc)
|
|
def.setter = setfunc;
|
|
}
|
|
|
|
void WrapperRegistry::addMethod(const string &classname,
|
|
const string &methodname,
|
|
GenericFunction func)
|
|
{
|
|
string aclass = classname;
|
|
if (aclass.empty())
|
|
aclass = "__modclass__";
|
|
|
|
ClassData *classdef = getOrConstructClass(aclass);
|
|
for (int i = 0; i < (int)classdef->methods.size(); i++)
|
|
if (classdef->methods[i].name == methodname)
|
|
return; // avoid duplicates
|
|
classdef->methods.push_back(Method(methodname, methodname, func));
|
|
}
|
|
|
|
void WrapperRegistry::addOperator(const string &classname,
|
|
const string &methodname,
|
|
OperatorFunction func)
|
|
{
|
|
if (classname.empty())
|
|
errMsg("PYTHON operators have to be defined within classes.");
|
|
|
|
string op = methodname.substr(8);
|
|
ClassData *classdef = getOrConstructClass(classname);
|
|
classdef->ops[op] = func;
|
|
}
|
|
|
|
void WrapperRegistry::addConstructor(const string &classname, Constructor func)
|
|
{
|
|
ClassData *classdef = getOrConstructClass(classname);
|
|
classdef->constructor = func;
|
|
}
|
|
|
|
void WrapperRegistry::addParentMethods(ClassData *cur, ClassData *base)
|
|
{
|
|
if (base == 0)
|
|
return;
|
|
|
|
for (vector<Method>::iterator it = base->methods.begin(); it != base->methods.end(); ++it)
|
|
addMethod(cur->cName, it->name, it->func);
|
|
|
|
for (map<string, GetSet>::iterator it = base->getset.begin(); it != base->getset.end(); ++it)
|
|
addGetSet(cur->cName, it->first, it->second.getter, it->second.setter);
|
|
|
|
for (map<string, OperatorFunction>::iterator it = base->ops.begin(); it != base->ops.end(); ++it)
|
|
cur->ops[it->first] = it->second;
|
|
|
|
addParentMethods(cur, base->baseclass);
|
|
}
|
|
|
|
void WrapperRegistry::registerBaseclasses()
|
|
{
|
|
for (int i = 0; i < (int)mClassList.size(); i++) {
|
|
string bname = mClassList[i]->baseclassName;
|
|
if (!bname.empty()) {
|
|
mClassList[i]->baseclass = lookup(bname);
|
|
if (!mClassList[i]->baseclass)
|
|
errMsg("Registering class '" + mClassList[i]->cName + "' : Base class '" + bname +
|
|
"' not found");
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < (int)mClassList.size(); i++) {
|
|
addParentMethods(mClassList[i], mClassList[i]->baseclass);
|
|
}
|
|
}
|
|
|
|
void WrapperRegistry::registerMeta()
|
|
{
|
|
for (int i = 0; i < (int)mClassList.size(); i++) {
|
|
mClassList[i]->getset["_class"] = GetSet("_class", "C class name", (Getter)cbGetClass, 0);
|
|
mClassList[i]->getset["_cname"] = GetSet("_cname", "Full C name", (Getter)cbGetCName, 0);
|
|
mClassList[i]->getset["_T"] = GetSet("_T", "C template argument", (Getter)cbGetTemplate, 0);
|
|
}
|
|
}
|
|
|
|
void WrapperRegistry::registerOperators(ClassData *cls)
|
|
{
|
|
PyNumberMethods &num = cls->numInfo;
|
|
for (map<string, OperatorFunction>::iterator it = cls->ops.begin(); it != cls->ops.end(); it++) {
|
|
const string &op = it->first;
|
|
OperatorFunction func = it->second;
|
|
if (op == "+=")
|
|
num.nb_inplace_add = func;
|
|
else if (op == "-=")
|
|
num.nb_inplace_subtract = func;
|
|
else if (op == "*=")
|
|
num.nb_inplace_multiply = func;
|
|
else if (op == "+")
|
|
num.nb_add = func;
|
|
else if (op == "-")
|
|
num.nb_subtract = func;
|
|
else if (op == "*")
|
|
num.nb_multiply = func;
|
|
#if PY_MAJOR_VERSION < 3
|
|
else if (op == "/=")
|
|
num.nb_inplace_divide = func;
|
|
else if (op == "/")
|
|
num.nb_divide = func;
|
|
#else
|
|
else if (op == "/=")
|
|
num.nb_inplace_true_divide = func;
|
|
else if (op == "/")
|
|
num.nb_true_divide = func;
|
|
#endif
|
|
else
|
|
errMsg("PYTHON operator " + op + " not supported");
|
|
}
|
|
}
|
|
|
|
void WrapperRegistry::registerDummyTypes()
|
|
{
|
|
vector<string> add;
|
|
for (vector<ClassData *>::iterator it = mClassList.begin(); it != mClassList.end(); ++it) {
|
|
string cName = (*it)->cName;
|
|
if (cName.find('<') != string::npos)
|
|
add.push_back(cName.substr(0, cName.find('<')));
|
|
}
|
|
for (int i = 0; i < (int)add.size(); i++)
|
|
addClass(add[i], add[i], "");
|
|
}
|
|
|
|
ClassData *WrapperRegistry::lookup(const string &name)
|
|
{
|
|
for (map<string, ClassData *>::iterator it = mClasses.begin(); it != mClasses.end(); ++it) {
|
|
if (it->first == name || it->second->cName == name)
|
|
return it->second;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void WrapperRegistry::cleanup()
|
|
{
|
|
for (vector<ClassData *>::iterator it = mClassList.begin(); it != mClassList.end(); ++it) {
|
|
delete *it;
|
|
}
|
|
mClasses.clear();
|
|
mClassList.clear();
|
|
}
|
|
|
|
WrapperRegistry &WrapperRegistry::instance()
|
|
{
|
|
static WrapperRegistry inst;
|
|
return inst;
|
|
}
|
|
|
|
bool WrapperRegistry::canConvert(ClassData *from, ClassData *to)
|
|
{
|
|
if (from == to)
|
|
return true;
|
|
if (from->baseclass)
|
|
return canConvert(from->baseclass, to);
|
|
return false;
|
|
}
|
|
|
|
void WrapperRegistry::addConstants(PyObject *module)
|
|
{
|
|
// expose arguments
|
|
PyObject *list = PyList_New(args.size());
|
|
for (int i = 0; i < (int)args.size(); i++)
|
|
PyList_SET_ITEM(list, i, Manta::toPy(args[i]));
|
|
PyModule_AddObject(module, "args", list);
|
|
PyModule_AddObject(module, "SCENEFILE", Manta::toPy(mScriptName));
|
|
|
|
// expose compile flags
|
|
#ifdef DEBUG
|
|
PyModule_AddObject(module, "DEBUG", Manta::toPy<bool>(true));
|
|
#else
|
|
PyModule_AddObject(module, "DEBUG", Manta::toPy<bool>(false));
|
|
#endif
|
|
#ifdef MANTA_MT
|
|
PyModule_AddObject(module, "MT", Manta::toPy<bool>(true));
|
|
#else
|
|
PyModule_AddObject(module, "MT", Manta::toPy<bool>(false));
|
|
#endif
|
|
#ifdef GUI
|
|
PyModule_AddObject(module, "GUI", Manta::toPy<bool>(true));
|
|
#else
|
|
PyModule_AddObject(module, "GUI", Manta::toPy<bool>(false));
|
|
#endif
|
|
#if FLOATINGPOINT_PRECISION == 2
|
|
PyModule_AddObject(module, "DOUBLEPRECISION", Manta::toPy<bool>(true));
|
|
#else
|
|
PyModule_AddObject(module, "DOUBLEPRECISION", Manta::toPy<bool>(false));
|
|
#endif
|
|
// cuda off for now
|
|
PyModule_AddObject(module, "CUDA", Manta::toPy<bool>(false));
|
|
|
|
// expose enum entries
|
|
std::map<std::string, int>::iterator it;
|
|
for (it = mEnumValues.begin(); it != mEnumValues.end(); it++) {
|
|
PyModule_AddObject(module, it->first.c_str(), Manta::toPy(it->second));
|
|
// Alternative would be:
|
|
// e.g. PyModule_AddIntConstant(module, "FlagFluid", 1);
|
|
}
|
|
}
|
|
|
|
void WrapperRegistry::runPreInit()
|
|
{
|
|
// add python directories to path
|
|
PyObject *sys_path = PySys_GetObject((char *)"path");
|
|
for (size_t i = 0; i < mPaths.size(); i++) {
|
|
PyObject *path = Manta::toPy(mPaths[i]);
|
|
if (sys_path == NULL || path == NULL || PyList_Append(sys_path, path) < 0) {
|
|
errMsg("unable to set python path");
|
|
}
|
|
Py_DECREF(path);
|
|
}
|
|
if (!mCode.empty()) {
|
|
mCode = "from manta import *\n" + mCode;
|
|
PyRun_SimpleString(mCode.c_str());
|
|
}
|
|
}
|
|
|
|
PyObject *WrapperRegistry::createPyObject(const string &classname,
|
|
const string &name,
|
|
Manta::PbArgs &args,
|
|
Manta::PbClass *parent)
|
|
{
|
|
ClassData *classdef = lookup(classname);
|
|
if (!classdef)
|
|
errMsg("Class " + classname + " doesn't exist.");
|
|
|
|
// create object
|
|
PyObject *obj = cbNew(&classdef->typeInfo, NULL, NULL);
|
|
PbObject *self = (PbObject *)obj;
|
|
PyObject *nkw = 0;
|
|
|
|
if (args.kwds())
|
|
nkw = PyDict_Copy(args.kwds());
|
|
else
|
|
nkw = PyDict_New();
|
|
|
|
PyObject *nocheck = Py_BuildValue("s", "yes");
|
|
PyDict_SetItemString(nkw, "nocheck", nocheck);
|
|
if (parent)
|
|
PyDict_SetItemString(nkw, "parent", parent->getPyObject());
|
|
|
|
// create instance
|
|
if (self->classdef->constructor(obj, args.linArgs(), nkw) < 0)
|
|
errMsg("error raised in constructor"); // assume condition is already set
|
|
|
|
Py_DECREF(nkw);
|
|
Py_DECREF(nocheck);
|
|
self->instance->setName(name);
|
|
|
|
return obj;
|
|
}
|
|
|
|
// prepare typeinfo and register python module
|
|
void WrapperRegistry::construct(const string &scriptname, const vector<string> &args)
|
|
{
|
|
mScriptName = scriptname;
|
|
this->args = args;
|
|
|
|
registerBaseclasses();
|
|
registerMeta();
|
|
registerDummyTypes();
|
|
|
|
// work around for certain gcc versions, cast to char*
|
|
PyImport_AppendInittab((char *)gDefaultModuleName.c_str(), PyInit_Main);
|
|
}
|
|
|
|
inline PyObject *castPy(PyTypeObject *p)
|
|
{
|
|
return reinterpret_cast<PyObject *>(static_cast<void *>(p));
|
|
}
|
|
|
|
PyObject *WrapperRegistry::initModule()
|
|
{
|
|
// generate and terminate all method lists
|
|
PyMethodDef sentinelFunc = {NULL, NULL, 0, NULL};
|
|
PyGetSetDef sentinelGetSet = {NULL, NULL, NULL, NULL, NULL};
|
|
for (int i = 0; i < (int)mClassList.size(); i++) {
|
|
ClassData *cls = mClassList[i];
|
|
cls->genMethods.clear();
|
|
cls->genGetSet.clear();
|
|
for (vector<Method>::iterator i2 = cls->methods.begin(); i2 != cls->methods.end(); ++i2)
|
|
cls->genMethods.push_back(i2->def());
|
|
for (map<string, GetSet>::iterator i2 = cls->getset.begin(); i2 != cls->getset.end(); ++i2)
|
|
cls->genGetSet.push_back(i2->second.def());
|
|
|
|
cls->genMethods.push_back(sentinelFunc);
|
|
cls->genGetSet.push_back(sentinelGetSet);
|
|
}
|
|
|
|
// prepare module info
|
|
#if PY_MAJOR_VERSION >= 3
|
|
static PyModuleDef MainModule = {PyModuleDef_HEAD_INIT,
|
|
gDefaultModuleName.c_str(),
|
|
"Bridge module to the C++ solver",
|
|
-1,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL};
|
|
// get generic methods (plugin functions)
|
|
MainModule.m_methods = &mClasses["__modclass__"]->genMethods[0];
|
|
|
|
// create module
|
|
PyObject *module = PyModule_Create(&MainModule);
|
|
#else
|
|
PyObject *module = Py_InitModule(gDefaultModuleName.c_str(),
|
|
&mClasses["__modclass__"]->genMethods[0]);
|
|
#endif
|
|
if (module == NULL)
|
|
return NULL;
|
|
|
|
// load classes
|
|
for (vector<ClassData *>::iterator it = mClassList.begin(); it != mClassList.end(); ++it) {
|
|
ClassData &data = **it;
|
|
char *nameptr = (char *)data.pyName.c_str();
|
|
|
|
// define numeric substruct
|
|
PyNumberMethods *num = 0;
|
|
if (!data.ops.empty()) {
|
|
num = &data.numInfo;
|
|
memset(num, 0, sizeof(PyNumberMethods));
|
|
registerOperators(&data);
|
|
}
|
|
|
|
// define python classinfo
|
|
PyTypeObject t = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)(char *) data.pyName.c_str(), // tp_name
|
|
sizeof(PbObject), // tp_basicsize
|
|
0, // tp_itemsize
|
|
(destructor)cbDealloc, // tp_dealloc
|
|
0, // tp_print
|
|
0, // tp_getattr
|
|
0, // tp_setattr
|
|
0, // tp_reserved
|
|
0, // tp_repr
|
|
num, // tp_as_number
|
|
0, // tp_as_sequence
|
|
0, // tp_as_mapping
|
|
0, // tp_hash
|
|
0, // tp_call
|
|
0, // tp_str
|
|
0, // tp_getattro
|
|
0, // tp_setattro
|
|
0, // tp_as_buffer
|
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
|
|
nameptr, // tp_doc
|
|
0, // tp_traverse
|
|
0, // tp_clear
|
|
0, // tp_richcompare
|
|
0, // tp_weaklistoffset
|
|
0, // tp_iter
|
|
0, // tp_iternext
|
|
&data.genMethods[0], // tp_methods
|
|
0, // tp_members
|
|
&data.genGetSet[0], // tp_getset
|
|
0, // tp_base
|
|
0, // tp_dict
|
|
0, // tp_descr_get
|
|
0, // tp_descr_set
|
|
0, // tp_dictoffset
|
|
(initproc)(data.constructor), // tp_init
|
|
0, // tp_alloc
|
|
cbNew // tp_new
|
|
};
|
|
data.typeInfo = t;
|
|
|
|
if (PyType_Ready(&data.typeInfo) < 0)
|
|
continue;
|
|
|
|
for (map<string, ClassData *>::iterator i2 = mClasses.begin(); i2 != mClasses.end(); ++i2) {
|
|
if (*it != i2->second)
|
|
continue;
|
|
// register all aliases
|
|
Py_INCREF(castPy(&data.typeInfo));
|
|
PyModule_AddObject(module, (char *)i2->first.c_str(), (PyObject *)&data.typeInfo);
|
|
}
|
|
}
|
|
|
|
// externals
|
|
for (vector<InitFunc>::iterator it = mExtInitializers.begin(); it != mExtInitializers.end();
|
|
++it) {
|
|
(*it)(module);
|
|
}
|
|
|
|
addConstants(module);
|
|
|
|
return module;
|
|
}
|
|
|
|
//******************************************************
|
|
// Register members and exposed functions
|
|
|
|
void setup(const std::string &filename, const std::vector<std::string> &args)
|
|
{
|
|
WrapperRegistry::instance().construct(filename, args);
|
|
Py_Initialize();
|
|
WrapperRegistry::instance().runPreInit();
|
|
}
|
|
|
|
void finalize()
|
|
{
|
|
Py_Finalize();
|
|
WrapperRegistry::instance().cleanup();
|
|
}
|
|
|
|
bool canConvert(PyObject *obj, const string &classname)
|
|
{
|
|
ClassData *from = ((PbObject *)obj)->classdef;
|
|
ClassData *dest = WrapperRegistry::instance().lookup(classname);
|
|
if (!dest)
|
|
errMsg("Classname '" + classname + "' is not registered.");
|
|
return WrapperRegistry::instance().canConvert(from, dest);
|
|
}
|
|
|
|
Manta::PbClass *objFromPy(PyObject *obj)
|
|
{
|
|
if (Py_TYPE(obj)->tp_dealloc != (destructor)cbDealloc) // not a manta object
|
|
return NULL;
|
|
|
|
return ((PbObject *)obj)->instance;
|
|
}
|
|
|
|
PyObject *copyObject(Manta::PbClass *cls, const string &classname)
|
|
{
|
|
ClassData *classdef = WrapperRegistry::instance().lookup(classname);
|
|
assertMsg(classdef, "python class " + classname + " does not exist.");
|
|
|
|
// allocate new object
|
|
PbObject *obj = (PbObject *)classdef->typeInfo.tp_alloc(&(classdef->typeInfo), 0);
|
|
assertMsg(obj, "cannot allocate new python object");
|
|
|
|
obj->classdef = classdef;
|
|
cls->registerObject((PyObject *)obj, 0);
|
|
|
|
return cls->getPyObject();
|
|
}
|
|
|
|
Manta::PbClass *createPy(const std::string &classname,
|
|
const std::string &name,
|
|
Manta::PbArgs &args,
|
|
Manta::PbClass *parent)
|
|
{
|
|
PyObject *obj = WrapperRegistry::instance().createPyObject(classname, name, args, parent);
|
|
return ((PbObject *)obj)->instance;
|
|
}
|
|
|
|
void setReference(Manta::PbClass *cls, PyObject *obj)
|
|
{
|
|
((PbObject *)obj)->instance = cls;
|
|
}
|
|
|
|
Register::Register(const string &className, const string &funcName, GenericFunction func)
|
|
{
|
|
WrapperRegistry::instance().addMethod(className, funcName, func);
|
|
}
|
|
Register::Register(const string &className, const string &funcName, OperatorFunction func)
|
|
{
|
|
WrapperRegistry::instance().addOperator(className, funcName, func);
|
|
}
|
|
Register::Register(const string &className, const string &funcName, Constructor func)
|
|
{
|
|
WrapperRegistry::instance().addConstructor(className, func);
|
|
}
|
|
Register::Register(const string &className, const string &property, Getter getter, Setter setter)
|
|
{
|
|
WrapperRegistry::instance().addGetSet(className, property, getter, setter);
|
|
}
|
|
Register::Register(const string &className, const string &pyName, const string &baseClass)
|
|
{
|
|
WrapperRegistry::instance().addClass(pyName, className, baseClass);
|
|
}
|
|
Register::Register(const string &name, const int value)
|
|
{
|
|
WrapperRegistry::instance().addEnumEntry(name, value);
|
|
}
|
|
Register::Register(const string &file, const string &pythonCode)
|
|
{
|
|
WrapperRegistry::instance().addPythonCode(file, pythonCode);
|
|
}
|
|
Register::Register(InitFunc func)
|
|
{
|
|
WrapperRegistry::instance().addExternalInitializer(func);
|
|
}
|
|
|
|
} // namespace Pb
|