1 /******************************************************************************
2  *
3  * MantaFlow fluid solver framework
4  * Copyright 2011-2014 Tobias Pfaff, Nils Thuerey
5  *
6  * This program is free software, distributed under the terms of the
7  * Apache License, Version 2.0
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Auto python registry
11  *
12  ******************************************************************************/
13 
14 #include <string.h>
15 #include "pythonInclude.h"
16 #include "structmember.h"
17 #include "manta.h"
18 
19 using namespace std;
20 
21 const string gDefaultModuleName = "manta";
22 
23 namespace Pb {
24 
25 //******************************************************************************
26 // Custom object definition
27 
28 struct Method {
MethodPb::Method29   Method(const string &n, const string &d, GenericFunction f) : name(n), doc(d), func(f)
30   {
31   }
32   string name, doc;
33   GenericFunction func;
34 
defPb::Method35   PyMethodDef def()
36   {
37     PyMethodDef def = {&name[0], (PyCFunction)func, METH_VARARGS | METH_KEYWORDS, &doc[0]};
38     return def;
39   }
40 };
41 struct GetSet {
GetSetPb::GetSet42   GetSet() : getter(0), setter(0)
43   {
44   }
GetSetPb::GetSet45   GetSet(const string &n, const string &d, Getter g, Setter s)
46       : name(n), doc(d), getter(g), setter(s)
47   {
48   }
49   string name, doc;
50   Getter getter;
51   Setter setter;
52 
defPb::GetSet53   PyGetSetDef def()
54   {
55     PyGetSetDef def = {&name[0], getter, setter, &doc[0], NULL};
56     return def;
57   }
58 };
59 
60 struct ClassData {
61   string cName, pyName;
62   string cPureName, cTemplate;
63   InitFunc init;
64   PyTypeObject typeInfo;
65   PyNumberMethods numInfo;
66   // PySequenceMethods seqInfo;
67   vector<Method> methods;
68   map<string, GetSet> getset;
69   map<string, OperatorFunction> ops;
70   ClassData *baseclass;
71   string baseclassName;
72   Constructor constructor;
73 
74   vector<PyMethodDef> genMethods;
75   vector<PyGetSetDef> genGetSet;
76 };
77 
78 struct PbObject {
79   PyObject_HEAD Manta::PbClass *instance;
80   ClassData *classdef;
81 };
82 
83 //******************************************************
84 // Internal wrapper class
85 
86 //! Registers all classes and methods exposed to Python.
87 /*! This class is only used internally by Pb:: framwork.
88  *  Please use the functionality of PbClass to lookup and translate pointers. */
89 class WrapperRegistry {
90  public:
91   static WrapperRegistry &instance();
92   void addClass(const std::string &name,
93                 const std::string &internalName,
94                 const std::string &baseclass);
95   void addEnumEntry(const std::string &name, int value);
96   void addExternalInitializer(InitFunc func);
97   void addMethod(const std::string &classname,
98                  const std::string &methodname,
99                  GenericFunction method);
100   void addOperator(const std::string &classname,
101                    const std::string &methodname,
102                    OperatorFunction method);
103   void addConstructor(const std::string &classname, Constructor method);
104   void addGetSet(const std::string &classname,
105                  const std::string &property,
106                  Getter getfunc,
107                  Setter setfunc);
108   void addPythonPath(const std::string &path);
109   void addPythonCode(const std::string &file, const std::string &code);
110   PyObject *createPyObject(const std::string &classname,
111                            const std::string &name,
112                            Manta::PbArgs &args,
113                            Manta::PbClass *parent);
114   void construct(const std::string &scriptname, const vector<string> &args);
115   void cleanup();
116   void renameObjects();
117   void runPreInit();
118   PyObject *initModule();
119   ClassData *lookup(const std::string &name);
120   bool canConvert(ClassData *from, ClassData *to);
121 
122  private:
123   ClassData *getOrConstructClass(const string &name);
124   void registerBaseclasses();
125   void registerDummyTypes();
126   void registerMeta();
127   void addConstants(PyObject *module);
128   void registerOperators(ClassData *cls);
129   void addParentMethods(ClassData *cls, ClassData *base);
130   WrapperRegistry();
131   ~WrapperRegistry();
132   std::map<std::string, ClassData *> mClasses;
133   std::vector<ClassData *> mClassList;
134   std::vector<InitFunc> mExtInitializers;
135   std::vector<std::string> mPaths;
136   std::string mCode, mScriptName;
137   std::vector<std::string> args;
138   std::map<std::string, int> mEnumValues;
139 };
140 
141 //******************************************************************************
142 // Callback functions
143 
cbGetClass(PbObject * self,void * cl)144 PyObject *cbGetClass(PbObject *self, void *cl)
145 {
146   return Manta::toPy(self->classdef->cPureName);
147 }
148 
cbGetTemplate(PbObject * self,void * cl)149 PyObject *cbGetTemplate(PbObject *self, void *cl)
150 {
151   return Manta::toPy(self->classdef->cTemplate);
152 }
153 
cbGetCName(PbObject * self,void * cl)154 PyObject *cbGetCName(PbObject *self, void *cl)
155 {
156   return Manta::toPy(self->classdef->cName);
157 }
158 
cbDealloc(PbObject * self)159 void cbDealloc(PbObject *self)
160 {
161   // cout << "dealloc " << self->instance->getName() << " " << self->classdef->cName << endl;
162   if (self->instance) {
163 #ifndef BLENDER
164     // don't delete top-level objects
165     if (self->instance->getParent() != self->instance)
166       delete self->instance;
167 #else
168     // in Blender we *have* to delete all objects
169     delete self->instance;
170 #endif
171   }
172   Py_TYPE(self)->tp_free((PyObject *)self);
173 }
174 
cbNew(PyTypeObject * type,PyObject * args,PyObject * kwds)175 PyObject *cbNew(PyTypeObject *type, PyObject *args, PyObject *kwds)
176 {
177   PbObject *self = (PbObject *)type->tp_alloc(type, 0);
178   if (self != NULL) {
179     // lookup and link classdef
180     self->classdef = WrapperRegistry::instance().lookup(type->tp_name);
181     self->instance = NULL;
182     // cout << "creating " << self->classdef->cName << endl;
183   }
184   else
185     errMsg("can't allocate new python class object");
186   return (PyObject *)self;
187 }
188 
cbDisableConstructor(PyObject * self,PyObject * args,PyObject * kwds)189 int cbDisableConstructor(PyObject *self, PyObject *args, PyObject *kwds)
190 {
191   errMsg("Can't instantiate a class template without template arguments");
192   return -1;
193 }
194 
PyInit_manta_main(void)195 PyMODINIT_FUNC PyInit_manta_main(void)
196 {
197   MantaEnsureRegistration();
198 #if PY_MAJOR_VERSION >= 3
199   return WrapperRegistry::instance().initModule();
200 #else
201   WrapperRegistry::instance().initModule();
202 #endif
203 }
204 
205 //******************************************************
206 // WrapperRegistry
207 
WrapperRegistry()208 WrapperRegistry::WrapperRegistry()
209 {
210   addClass("__modclass__", "__modclass__", "");
211   addClass("PbClass", "PbClass", "");
212 }
213 
~WrapperRegistry()214 WrapperRegistry::~WrapperRegistry()
215 {
216   // Some static constructions may have called WrapperRegistry.instance() and added
217   // own classes, functions, etc. Ensure everything is cleaned up properly.
218   cleanup();
219 }
220 
getOrConstructClass(const string & classname)221 ClassData *WrapperRegistry::getOrConstructClass(const string &classname)
222 {
223   map<string, ClassData *>::iterator it = mClasses.find(classname);
224 
225   if (it != mClasses.end())
226     return it->second;
227   ClassData *data = new ClassData;
228   data->cName = classname;
229   data->cPureName = classname;
230   data->cTemplate = "";
231   size_t tplIdx = classname.find('<');
232   if (tplIdx != string::npos) {
233     data->cPureName = classname.substr(0, tplIdx);
234     data->cTemplate = classname.substr(tplIdx + 1, classname.find('>') - tplIdx - 1);
235   }
236   data->baseclass = NULL;
237   data->constructor = cbDisableConstructor;
238   mClasses[classname] = data;
239   mClassList.push_back(data);
240   return data;
241 }
242 
replaceAll(string & source,string const & find,string const & replace)243 void replaceAll(string &source, string const &find, string const &replace)
244 {
245   for (string::size_type i = 0; (i = source.find(find, i)) != std::string::npos;) {
246     source.replace(i, find.length(), replace);
247     i += replace.length() - find.length() + 1;
248   }
249 }
250 
addClass(const string & pyName,const string & internalName,const string & baseclass)251 void WrapperRegistry::addClass(const string &pyName,
252                                const string &internalName,
253                                const string &baseclass)
254 {
255   ClassData *data = getOrConstructClass(internalName);
256 
257   // regularize python name
258   string pythonName = pyName;
259   replaceAll(pythonName, "<", "_");
260   replaceAll(pythonName, ">", "");
261   replaceAll(pythonName, ",", "_");
262 
263   if (data->pyName.empty())
264     data->pyName = pythonName;
265   mClasses[pythonName] = data;
266   if (!baseclass.empty())
267     data->baseclassName = baseclass;
268 }
269 
addEnumEntry(const string & name,int value)270 void WrapperRegistry::addEnumEntry(const string &name, int value)
271 {
272   /// Gather static definitions to add them as static python objects afterwards
273   if (mEnumValues.insert(std::make_pair(name, value)).second == false) {
274     errMsg("Enum entry '" + name + "' already existing...");
275   }
276 }
277 
addExternalInitializer(InitFunc func)278 void WrapperRegistry::addExternalInitializer(InitFunc func)
279 {
280   mExtInitializers.push_back(func);
281 }
282 
addPythonPath(const string & path)283 void WrapperRegistry::addPythonPath(const string &path)
284 {
285   mPaths.push_back(path);
286 }
287 
addPythonCode(const string & file,const string & code)288 void WrapperRegistry::addPythonCode(const string &file, const string &code)
289 {
290   mCode += code + "\n";
291 }
292 
addGetSet(const string & classname,const string & property,Getter getfunc,Setter setfunc)293 void WrapperRegistry::addGetSet(const string &classname,
294                                 const string &property,
295                                 Getter getfunc,
296                                 Setter setfunc)
297 {
298   ClassData *classdef = getOrConstructClass(classname);
299   GetSet &def = classdef->getset[property];
300   if (def.name.empty()) {
301     def.name = property;
302     def.doc = property;
303   }
304   if (getfunc)
305     def.getter = getfunc;
306   if (setfunc)
307     def.setter = setfunc;
308 }
309 
addMethod(const string & classname,const string & methodname,GenericFunction func)310 void WrapperRegistry::addMethod(const string &classname,
311                                 const string &methodname,
312                                 GenericFunction func)
313 {
314   string aclass = classname;
315   if (aclass.empty())
316     aclass = "__modclass__";
317 
318   ClassData *classdef = getOrConstructClass(aclass);
319   for (int i = 0; i < (int)classdef->methods.size(); i++)
320     if (classdef->methods[i].name == methodname)
321       return;  // avoid duplicates
322   classdef->methods.push_back(Method(methodname, methodname, func));
323 }
324 
addOperator(const string & classname,const string & methodname,OperatorFunction func)325 void WrapperRegistry::addOperator(const string &classname,
326                                   const string &methodname,
327                                   OperatorFunction func)
328 {
329   if (classname.empty())
330     errMsg("PYTHON operators have to be defined within classes.");
331 
332   string op = methodname.substr(8);
333   ClassData *classdef = getOrConstructClass(classname);
334   classdef->ops[op] = func;
335 }
336 
addConstructor(const string & classname,Constructor func)337 void WrapperRegistry::addConstructor(const string &classname, Constructor func)
338 {
339   ClassData *classdef = getOrConstructClass(classname);
340   classdef->constructor = func;
341 }
342 
addParentMethods(ClassData * cur,ClassData * base)343 void WrapperRegistry::addParentMethods(ClassData *cur, ClassData *base)
344 {
345   if (base == 0)
346     return;
347 
348   for (vector<Method>::iterator it = base->methods.begin(); it != base->methods.end(); ++it)
349     addMethod(cur->cName, it->name, it->func);
350 
351   for (map<string, GetSet>::iterator it = base->getset.begin(); it != base->getset.end(); ++it)
352     addGetSet(cur->cName, it->first, it->second.getter, it->second.setter);
353 
354   for (map<string, OperatorFunction>::iterator it = base->ops.begin(); it != base->ops.end(); ++it)
355     cur->ops[it->first] = it->second;
356 
357   addParentMethods(cur, base->baseclass);
358 }
359 
registerBaseclasses()360 void WrapperRegistry::registerBaseclasses()
361 {
362   for (int i = 0; i < (int)mClassList.size(); i++) {
363     string bname = mClassList[i]->baseclassName;
364     if (!bname.empty()) {
365       mClassList[i]->baseclass = lookup(bname);
366       if (!mClassList[i]->baseclass)
367         errMsg("Registering class '" + mClassList[i]->cName + "' : Base class '" + bname +
368                "' not found");
369     }
370   }
371 
372   for (int i = 0; i < (int)mClassList.size(); i++) {
373     addParentMethods(mClassList[i], mClassList[i]->baseclass);
374   }
375 }
376 
registerMeta()377 void WrapperRegistry::registerMeta()
378 {
379   for (int i = 0; i < (int)mClassList.size(); i++) {
380     mClassList[i]->getset["_class"] = GetSet("_class", "C class name", (Getter)cbGetClass, 0);
381     mClassList[i]->getset["_cname"] = GetSet("_cname", "Full C name", (Getter)cbGetCName, 0);
382     mClassList[i]->getset["_T"] = GetSet("_T", "C template argument", (Getter)cbGetTemplate, 0);
383   }
384 }
385 
registerOperators(ClassData * cls)386 void WrapperRegistry::registerOperators(ClassData *cls)
387 {
388   PyNumberMethods &num = cls->numInfo;
389   for (map<string, OperatorFunction>::iterator it = cls->ops.begin(); it != cls->ops.end(); it++) {
390     const string &op = it->first;
391     OperatorFunction func = it->second;
392     if (op == "+=")
393       num.nb_inplace_add = func;
394     else if (op == "-=")
395       num.nb_inplace_subtract = func;
396     else if (op == "*=")
397       num.nb_inplace_multiply = func;
398     else if (op == "+")
399       num.nb_add = func;
400     else if (op == "-")
401       num.nb_subtract = func;
402     else if (op == "*")
403       num.nb_multiply = func;
404 #if PY_MAJOR_VERSION < 3
405     else if (op == "/=")
406       num.nb_inplace_divide = func;
407     else if (op == "/")
408       num.nb_divide = func;
409 #else
410     else if (op == "/=")
411       num.nb_inplace_true_divide = func;
412     else if (op == "/")
413       num.nb_true_divide = func;
414 #endif
415     else
416       errMsg("PYTHON operator " + op + " not supported");
417   }
418 }
419 
registerDummyTypes()420 void WrapperRegistry::registerDummyTypes()
421 {
422   vector<string> add;
423   for (vector<ClassData *>::iterator it = mClassList.begin(); it != mClassList.end(); ++it) {
424     string cName = (*it)->cName;
425     if (cName.find('<') != string::npos)
426       add.push_back(cName.substr(0, cName.find('<')));
427   }
428   for (int i = 0; i < (int)add.size(); i++)
429     addClass(add[i], add[i], "");
430 }
431 
lookup(const string & name)432 ClassData *WrapperRegistry::lookup(const string &name)
433 {
434   for (map<string, ClassData *>::iterator it = mClasses.begin(); it != mClasses.end(); ++it) {
435     if (it->first == name || it->second->cName == name)
436       return it->second;
437   }
438   return NULL;
439 }
440 
cleanup()441 void WrapperRegistry::cleanup()
442 {
443   for (vector<ClassData *>::iterator it = mClassList.begin(); it != mClassList.end(); ++it) {
444     delete *it;
445   }
446   mClasses.clear();
447   mClassList.clear();
448 }
449 
instance()450 WrapperRegistry &WrapperRegistry::instance()
451 {
452   static WrapperRegistry inst;
453   return inst;
454 }
455 
canConvert(ClassData * from,ClassData * to)456 bool WrapperRegistry::canConvert(ClassData *from, ClassData *to)
457 {
458   if (from == to)
459     return true;
460   if (from->baseclass)
461     return canConvert(from->baseclass, to);
462   return false;
463 }
464 
addConstants(PyObject * module)465 void WrapperRegistry::addConstants(PyObject *module)
466 {
467   // expose arguments
468   PyObject *list = PyList_New(args.size());
469   for (int i = 0; i < (int)args.size(); i++)
470     PyList_SET_ITEM(list, i, Manta::toPy(args[i]));
471   PyModule_AddObject(module, "args", list);
472   PyModule_AddObject(module, "SCENEFILE", Manta::toPy(mScriptName));
473 
474   // expose compile flags
475 #ifdef DEBUG
476   PyModule_AddObject(module, "DEBUG", Manta::toPy<bool>(true));
477 #else
478   PyModule_AddObject(module, "DEBUG", Manta::toPy<bool>(false));
479 #endif
480 #ifdef MANTA_MT
481   PyModule_AddObject(module, "MT", Manta::toPy<bool>(true));
482 #else
483   PyModule_AddObject(module, "MT", Manta::toPy<bool>(false));
484 #endif
485 #ifdef GUI
486   PyModule_AddObject(module, "GUI", Manta::toPy<bool>(true));
487 #else
488   PyModule_AddObject(module, "GUI", Manta::toPy<bool>(false));
489 #endif
490 #if FLOATINGPOINT_PRECISION == 2
491   PyModule_AddObject(module, "DOUBLEPRECISION", Manta::toPy<bool>(true));
492 #else
493   PyModule_AddObject(module, "DOUBLEPRECISION", Manta::toPy<bool>(false));
494 #endif
495   // cuda off for now
496   PyModule_AddObject(module, "CUDA", Manta::toPy<bool>(false));
497 
498   // expose enum entries
499   std::map<std::string, int>::iterator it;
500   for (it = mEnumValues.begin(); it != mEnumValues.end(); it++) {
501     PyModule_AddObject(module, it->first.c_str(), Manta::toPy(it->second));
502     // Alternative would be:
503     // e.g. PyModule_AddIntConstant(module, "FlagFluid", 1);
504   }
505 }
506 
runPreInit()507 void WrapperRegistry::runPreInit()
508 {
509   // add python directories to path
510   PyObject *sys_path = PySys_GetObject((char *)"path");
511   for (size_t i = 0; i < mPaths.size(); i++) {
512     PyObject *path = Manta::toPy(mPaths[i]);
513     if (sys_path == NULL || path == NULL || PyList_Append(sys_path, path) < 0) {
514       errMsg("unable to set python path");
515     }
516     Py_DECREF(path);
517   }
518   if (!mCode.empty()) {
519     mCode = "from manta import *\n" + mCode;
520     PyRun_SimpleString(mCode.c_str());
521   }
522 }
523 
createPyObject(const string & classname,const string & name,Manta::PbArgs & args,Manta::PbClass * parent)524 PyObject *WrapperRegistry::createPyObject(const string &classname,
525                                           const string &name,
526                                           Manta::PbArgs &args,
527                                           Manta::PbClass *parent)
528 {
529   ClassData *classdef = lookup(classname);
530   if (!classdef)
531     errMsg("Class " + classname + " doesn't exist.");
532 
533   // create object
534   PyObject *obj = cbNew(&classdef->typeInfo, NULL, NULL);
535   PbObject *self = (PbObject *)obj;
536   PyObject *nkw = 0;
537 
538   if (args.kwds())
539     nkw = PyDict_Copy(args.kwds());
540   else
541     nkw = PyDict_New();
542 
543   PyObject *nocheck = Py_BuildValue("s", "yes");
544   PyDict_SetItemString(nkw, "nocheck", nocheck);
545   if (parent)
546     PyDict_SetItemString(nkw, "parent", parent->getPyObject());
547 
548   // create instance
549   if (self->classdef->constructor(obj, args.linArgs(), nkw) < 0)
550     errMsg("error raised in constructor");  // assume condition is already set
551 
552   Py_DECREF(nkw);
553   Py_DECREF(nocheck);
554   self->instance->setName(name);
555 
556   return obj;
557 }
558 
559 // prepare typeinfo and register python module
construct(const string & scriptname,const vector<string> & args)560 void WrapperRegistry::construct(const string &scriptname, const vector<string> &args)
561 {
562   mScriptName = scriptname;
563   this->args = args;
564 
565   registerBaseclasses();
566   registerMeta();
567   registerDummyTypes();
568 
569   // work around for certain gcc versions, cast to char*
570   PyImport_AppendInittab((char *)gDefaultModuleName.c_str(), PyInit_manta_main);
571 }
572 
castPy(PyTypeObject * p)573 inline PyObject *castPy(PyTypeObject *p)
574 {
575   return reinterpret_cast<PyObject *>(static_cast<void *>(p));
576 }
577 
initModule()578 PyObject *WrapperRegistry::initModule()
579 {
580   // generate and terminate all method lists
581   PyMethodDef sentinelFunc = {NULL, NULL, 0, NULL};
582   PyGetSetDef sentinelGetSet = {NULL, NULL, NULL, NULL, NULL};
583   for (int i = 0; i < (int)mClassList.size(); i++) {
584     ClassData *cls = mClassList[i];
585     cls->genMethods.clear();
586     cls->genGetSet.clear();
587     for (vector<Method>::iterator i2 = cls->methods.begin(); i2 != cls->methods.end(); ++i2)
588       cls->genMethods.push_back(i2->def());
589     for (map<string, GetSet>::iterator i2 = cls->getset.begin(); i2 != cls->getset.end(); ++i2)
590       cls->genGetSet.push_back(i2->second.def());
591 
592     cls->genMethods.push_back(sentinelFunc);
593     cls->genGetSet.push_back(sentinelGetSet);
594   }
595 
596   // prepare module info
597 #if PY_MAJOR_VERSION >= 3
598   static PyModuleDef MainModule = {PyModuleDef_HEAD_INIT,
599                                    gDefaultModuleName.c_str(),
600                                    "Bridge module to the C++ solver",
601                                    -1,
602                                    NULL,
603                                    NULL,
604                                    NULL,
605                                    NULL,
606                                    NULL};
607   // get generic methods (plugin functions)
608   MainModule.m_methods = &mClasses["__modclass__"]->genMethods[0];
609 
610   // create module
611   PyObject *module = PyModule_Create(&MainModule);
612 #else
613   PyObject *module = Py_InitModule(gDefaultModuleName.c_str(),
614                                    &mClasses["__modclass__"]->genMethods[0]);
615 #endif
616   if (module == NULL)
617     return NULL;
618 
619   // load classes
620   for (vector<ClassData *>::iterator it = mClassList.begin(); it != mClassList.end(); ++it) {
621     ClassData &data = **it;
622     char *nameptr = (char *)data.pyName.c_str();
623 
624     // define numeric substruct
625     PyNumberMethods *num = 0;
626     if (!data.ops.empty()) {
627       num = &data.numInfo;
628       memset(num, 0, sizeof(PyNumberMethods));
629       registerOperators(&data);
630     }
631 
632     // define python classinfo
633     PyTypeObject t = {
634         PyVarObject_HEAD_INIT(NULL, 0)(char *) data.pyName.c_str(),  // tp_name
635         sizeof(PbObject),                                            // tp_basicsize
636         0,                                                           // tp_itemsize
637         (destructor)cbDealloc,                                       // tp_dealloc
638         0,                                                           // tp_print
639         0,                                                           // tp_getattr
640         0,                                                           // tp_setattr
641         0,                                                           // tp_reserved
642         0,                                                           // tp_repr
643         num,                                                         // tp_as_number
644         0,                                                           // tp_as_sequence
645         0,                                                           // tp_as_mapping
646         0,                                                           // tp_hash
647         0,                                                           // tp_call
648         0,                                                           // tp_str
649         0,                                                           // tp_getattro
650         0,                                                           // tp_setattro
651         0,                                                           // tp_as_buffer
652         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,                    // tp_flags
653         nameptr,                                                     // tp_doc
654         0,                                                           // tp_traverse
655         0,                                                           // tp_clear
656         0,                                                           // tp_richcompare
657         0,                                                           // tp_weaklistoffset
658         0,                                                           // tp_iter
659         0,                                                           // tp_iternext
660         &data.genMethods[0],                                         // tp_methods
661         0,                                                           // tp_members
662         &data.genGetSet[0],                                          // tp_getset
663         0,                                                           // tp_base
664         0,                                                           // tp_dict
665         0,                                                           // tp_descr_get
666         0,                                                           // tp_descr_set
667         0,                                                           // tp_dictoffset
668         (initproc)(data.constructor),                                // tp_init
669         0,                                                           // tp_alloc
670         cbNew                                                        // tp_new
671     };
672     data.typeInfo = t;
673 
674     if (PyType_Ready(&data.typeInfo) < 0)
675       continue;
676 
677     for (map<string, ClassData *>::iterator i2 = mClasses.begin(); i2 != mClasses.end(); ++i2) {
678       if (*it != i2->second)
679         continue;
680       // register all aliases
681       Py_INCREF(castPy(&data.typeInfo));
682       PyModule_AddObject(module, (char *)i2->first.c_str(), (PyObject *)&data.typeInfo);
683     }
684   }
685 
686   // externals
687   for (vector<InitFunc>::iterator it = mExtInitializers.begin(); it != mExtInitializers.end();
688        ++it) {
689     (*it)(module);
690   }
691 
692   addConstants(module);
693 
694   return module;
695 }
696 
697 //******************************************************
698 // Register members and exposed functions
699 
setup(const std::string & filename,const std::vector<std::string> & args)700 void setup(const std::string &filename, const std::vector<std::string> &args)
701 {
702   WrapperRegistry::instance().construct(filename, args);
703   Py_Initialize();
704   WrapperRegistry::instance().runPreInit();
705 }
706 
finalize()707 void finalize()
708 {
709   Py_Finalize();
710   WrapperRegistry::instance().cleanup();
711 }
712 
canConvert(PyObject * obj,const string & classname)713 bool canConvert(PyObject *obj, const string &classname)
714 {
715   ClassData *from = ((PbObject *)obj)->classdef;
716   ClassData *dest = WrapperRegistry::instance().lookup(classname);
717   if (!dest)
718     errMsg("Classname '" + classname + "' is not registered.");
719   return WrapperRegistry::instance().canConvert(from, dest);
720 }
721 
objFromPy(PyObject * obj)722 Manta::PbClass *objFromPy(PyObject *obj)
723 {
724   if (Py_TYPE(obj)->tp_dealloc != (destructor)cbDealloc)  // not a manta object
725     return NULL;
726 
727   return ((PbObject *)obj)->instance;
728 }
729 
copyObject(Manta::PbClass * cls,const string & classname)730 PyObject *copyObject(Manta::PbClass *cls, const string &classname)
731 {
732   ClassData *classdef = WrapperRegistry::instance().lookup(classname);
733   assertMsg(classdef, "python class " + classname + " does not exist.");
734 
735   // allocate new object
736   PbObject *obj = (PbObject *)classdef->typeInfo.tp_alloc(&(classdef->typeInfo), 0);
737   assertMsg(obj, "cannot allocate new python object");
738 
739   obj->classdef = classdef;
740   cls->registerObject((PyObject *)obj, 0);
741 
742   return cls->getPyObject();
743 }
744 
createPy(const std::string & classname,const std::string & name,Manta::PbArgs & args,Manta::PbClass * parent)745 Manta::PbClass *createPy(const std::string &classname,
746                          const std::string &name,
747                          Manta::PbArgs &args,
748                          Manta::PbClass *parent)
749 {
750   PyObject *obj = WrapperRegistry::instance().createPyObject(classname, name, args, parent);
751   return ((PbObject *)obj)->instance;
752 }
753 
setReference(Manta::PbClass * cls,PyObject * obj)754 void setReference(Manta::PbClass *cls, PyObject *obj)
755 {
756   ((PbObject *)obj)->instance = cls;
757 }
758 
Register(const string & className,const string & funcName,GenericFunction func)759 Register::Register(const string &className, const string &funcName, GenericFunction func)
760 {
761   WrapperRegistry::instance().addMethod(className, funcName, func);
762 }
Register(const string & className,const string & funcName,OperatorFunction func)763 Register::Register(const string &className, const string &funcName, OperatorFunction func)
764 {
765   WrapperRegistry::instance().addOperator(className, funcName, func);
766 }
Register(const string & className,const string & funcName,Constructor func)767 Register::Register(const string &className, const string &funcName, Constructor func)
768 {
769   WrapperRegistry::instance().addConstructor(className, func);
770 }
Register(const string & className,const string & property,Getter getter,Setter setter)771 Register::Register(const string &className, const string &property, Getter getter, Setter setter)
772 {
773   WrapperRegistry::instance().addGetSet(className, property, getter, setter);
774 }
Register(const string & className,const string & pyName,const string & baseClass)775 Register::Register(const string &className, const string &pyName, const string &baseClass)
776 {
777   WrapperRegistry::instance().addClass(pyName, className, baseClass);
778 }
Register(const string & name,const int value)779 Register::Register(const string &name, const int value)
780 {
781   WrapperRegistry::instance().addEnumEntry(name, value);
782 }
Register(const string & file,const string & pythonCode)783 Register::Register(const string &file, const string &pythonCode)
784 {
785   WrapperRegistry::instance().addPythonCode(file, pythonCode);
786 }
Register(InitFunc func)787 Register::Register(InitFunc func)
788 {
789   WrapperRegistry::instance().addExternalInitializer(func);
790 }
791 
792 }  // namespace Pb
793