Panda3D
py_panda.h
Go to the documentation of this file.
1 /**
2  * @file py_panda.h
3  */
4 
5 #ifndef PY_PANDA_H_
6 #define PY_PANDA_H_
7 
8 #include <set>
9 #include <map>
10 #include <string>
11 
12 #ifdef USE_DEBUG_PYTHON
13 #define Py_DEBUG
14 #endif
15 
16 #include "pnotify.h"
17 #include "vector_uchar.h"
18 #include "register_type.h"
19 
20 #if defined(HAVE_PYTHON) && !defined(CPPPARSER)
21 
22 // py_compat.h includes Python.h.
23 #include "py_compat.h"
24 #include <structmember.h>
25 
26 using namespace std;
27 
28 // this is tempory .. untill this is glued better into the panda build system
29 
30 #if defined(_WIN32) && !defined(LINK_ALL_STATIC)
31 #define EXPORT_THIS __declspec(dllexport)
32 #define IMPORT_THIS extern __declspec(dllimport)
33 #else
34 #define EXPORT_THIS
35 #define IMPORT_THIS extern
36 #endif
37 
38 struct Dtool_PyTypedObject;
39 
40 // used to stamp dtool instance..
41 #define PY_PANDA_SIGNATURE 0xbeaf
42 typedef void *(*UpcastFunction)(PyObject *,Dtool_PyTypedObject *);
43 typedef void *(*DowncastFunction)(void *, Dtool_PyTypedObject *);
44 typedef void *(*CoerceFunction)(PyObject *, void *);
45 typedef void (*ModuleClassInitFunction)(PyObject *module);
46 
47 // INSTANCE CONTAINER FOR ALL panda py objects....
48 struct Dtool_PyInstDef {
49  PyObject_HEAD
50 
51  // This is a pointer to the Dtool_PyTypedObject type. It's tempting not to
52  // store this and to instead use PY_TYPE(self) and upcast that, but that
53  // breaks when someone inherits from our class in Python.
54  struct Dtool_PyTypedObject *_My_Type;
55 
56  // Pointer to the underlying C++ object.
57  void *_ptr_to_object;
58 
59  // This is always set to PY_PANDA_SIGNATURE, so that we can quickly detect
60  // whether an object is a Panda object.
61  unsigned short _signature;
62 
63  // True if we own the pointer and should delete it or unref it.
64  bool _memory_rules;
65 
66  // True if this is a "const" pointer.
67  bool _is_const;
68 };
69 
70 // The Class Definition Structor For a Dtool python type.
71 struct Dtool_PyTypedObject {
72  // Standard Python Features..
73  PyTypeObject _PyType;
74 
75  // May be TypeHandle::none() to indicate a non-TypedObject class.
76  TypeHandle _type;
77 
78  ModuleClassInitFunction _Dtool_ModuleClassInit;
79 
80  UpcastFunction _Dtool_UpcastInterface; // The Upcast Function By Slot
81  DowncastFunction _Dtool_DowncastInterface; // The Downcast Function By Slot
82 
83  CoerceFunction _Dtool_ConstCoerce;
84  CoerceFunction _Dtool_Coerce;
85 };
86 
87 // This is now simply a forward declaration. The actual definition is created
88 // by the code generator.
89 #define Define_Dtool_Class(MODULE_NAME, CLASS_NAME, PUBLIC_NAME) \
90  extern Dtool_PyTypedObject Dtool_##CLASS_NAME;
91 
92 // More Macro(s) to Implement class functions.. Usually used if C++ needs type
93 // information
94 #define Define_Dtool_new(CLASS_NAME,CNAME)\
95 static PyObject *Dtool_new_##CLASS_NAME(PyTypeObject *type, PyObject *args, PyObject *kwds) {\
96  (void) args; (void) kwds;\
97  PyObject *self = type->tp_alloc(type, 0);\
98  ((Dtool_PyInstDef *)self)->_signature = PY_PANDA_SIGNATURE;\
99  ((Dtool_PyInstDef *)self)->_My_Type = &Dtool_##CLASS_NAME;\
100  return self;\
101 }
102 
103 // The following used to be in the above macro, but it doesn't seem to be
104 // necessary as tp_alloc memsets the object to 0.
105 // ((Dtool_PyInstDef *)self)->_ptr_to_object = NULL;
106 // ((Dtool_PyInstDef *)self)->_memory_rules = false;
107 // ((Dtool_PyInstDef *)self)->_is_const = false;
108 
109 // Delete functions..
110 #ifdef NDEBUG
111 #define Define_Dtool_FreeInstance_Private(CLASS_NAME,CNAME)\
112 static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\
113  Py_TYPE(self)->tp_free(self);\
114 }
115 #else // NDEBUG
116 #define Define_Dtool_FreeInstance_Private(CLASS_NAME,CNAME)\
117 static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\
118  if (DtoolInstance_VOID_PTR(self) != nullptr) {\
119  if (((Dtool_PyInstDef *)self)->_memory_rules) {\
120  std::cerr << "Detected leak for " << #CLASS_NAME \
121  << " which interrogate cannot delete.\n"; \
122  }\
123  }\
124  Py_TYPE(self)->tp_free(self);\
125 }
126 #endif // NDEBUG
127 
128 #define Define_Dtool_FreeInstance(CLASS_NAME,CNAME)\
129 static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\
130  if (DtoolInstance_VOID_PTR(self) != nullptr) {\
131  if (((Dtool_PyInstDef *)self)->_memory_rules) {\
132  delete (CNAME *)DtoolInstance_VOID_PTR(self);\
133  }\
134  }\
135  Py_TYPE(self)->tp_free(self);\
136 }
137 
138 #define Define_Dtool_FreeInstanceRef(CLASS_NAME,CNAME)\
139 static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\
140  if (DtoolInstance_VOID_PTR(self) != nullptr) {\
141  if (((Dtool_PyInstDef *)self)->_memory_rules) {\
142  unref_delete((CNAME *)DtoolInstance_VOID_PTR(self));\
143  }\
144  }\
145  Py_TYPE(self)->tp_free(self);\
146 }
147 
148 #define Define_Dtool_FreeInstanceRef_Private(CLASS_NAME,CNAME)\
149 static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\
150  if (DtoolInstance_VOID_PTR(self) != nullptr) {\
151  if (((Dtool_PyInstDef *)self)->_memory_rules) {\
152  unref_delete((ReferenceCount *)(CNAME *)DtoolInstance_VOID_PTR(self));\
153  }\
154  }\
155  Py_TYPE(self)->tp_free(self);\
156 }
157 
158 #define Define_Dtool_Simple_FreeInstance(CLASS_NAME, CNAME)\
159 static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\
160  ((Dtool_InstDef_##CLASS_NAME *)self)->_value.~##CLASS_NAME();\
161  Py_TYPE(self)->tp_free(self);\
162 }
163 
164 // Use DtoolInstance_Check to check whether a PyObject* is a DtoolInstance.
165 #define DtoolInstance_Check(obj) \
166  (Py_TYPE(obj)->tp_basicsize >= (int)sizeof(Dtool_PyInstDef) && \
167  ((Dtool_PyInstDef *)obj)->_signature == PY_PANDA_SIGNATURE)
168 
169 // These macros access the DtoolInstance without error checking.
170 #define DtoolInstance_TYPE(obj) (((Dtool_PyInstDef *)obj)->_My_Type)
171 #define DtoolInstance_IS_CONST(obj) (((Dtool_PyInstDef *)obj)->_is_const)
172 #define DtoolInstance_VOID_PTR(obj) (((Dtool_PyInstDef *)obj)->_ptr_to_object)
173 #define DtoolInstance_INIT_PTR(obj, ptr) { ((Dtool_PyInstDef *)obj)->_ptr_to_object = (void*)(ptr); }
174 #define DtoolInstance_UPCAST(obj, type) (((Dtool_PyInstDef *)(obj))->_My_Type->_Dtool_UpcastInterface((obj), &(type)))
175 
176 // ** HACK ** allert.. Need to keep a runtime type dictionary ... that is
177 // forward declared of typed object. We rely on the fact that typed objects
178 // are uniquly defined by an integer.
179 
180 typedef std::map<std::string, Dtool_PyTypedObject *> Dtool_TypeMap;
181 
182 EXPCL_PYPANDA Dtool_TypeMap *Dtool_GetGlobalTypeMap();
183 
184 /**
185 
186  */
187 EXPCL_PYPANDA void DTOOL_Call_ExtractThisPointerForType(PyObject *self, Dtool_PyTypedObject *classdef, void **answer);
188 
189 EXPCL_PYPANDA void *DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef, int param, const std::string &function_name, bool const_ok, bool report_errors);
190 
191 EXPCL_PYPANDA bool Dtool_Call_ExtractThisPointer(PyObject *self, Dtool_PyTypedObject &classdef, void **answer);
192 
193 EXPCL_PYPANDA bool Dtool_Call_ExtractThisPointer_NonConst(PyObject *self, Dtool_PyTypedObject &classdef,
194  void **answer, const char *method_name);
195 
196 template<class T> INLINE bool DtoolInstance_GetPointer(PyObject *self, T *&into);
197 template<class T> INLINE bool DtoolInstance_GetPointer(PyObject *self, T *&into, Dtool_PyTypedObject &classdef);
198 
199 INLINE Py_hash_t DtoolInstance_HashPointer(PyObject *self);
200 INLINE int DtoolInstance_ComparePointers(PyObject *v1, PyObject *v2);
201 INLINE PyObject *DtoolInstance_RichComparePointers(PyObject *v1, PyObject *v2, int op);
202 
203 // Functions related to error reporting.
204 EXPCL_PYPANDA bool _Dtool_CheckErrorOccurred();
205 
206 #ifdef NDEBUG
207 #define Dtool_CheckErrorOccurred() (UNLIKELY(_PyErr_OCCURRED() != nullptr))
208 #else
209 #define Dtool_CheckErrorOccurred() (UNLIKELY(_Dtool_CheckErrorOccurred()))
210 #endif
211 
212 EXPCL_PYPANDA PyObject *Dtool_Raise_AssertionError();
213 EXPCL_PYPANDA PyObject *Dtool_Raise_TypeError(const char *message);
214 EXPCL_PYPANDA PyObject *Dtool_Raise_ArgTypeError(PyObject *obj, int param, const char *function_name, const char *type_name);
215 EXPCL_PYPANDA PyObject *Dtool_Raise_AttributeError(PyObject *obj, const char *attribute);
216 
217 EXPCL_PYPANDA PyObject *_Dtool_Raise_BadArgumentsError();
218 #ifdef NDEBUG
219 // Define it to a function that just prints a generic message.
220 #define Dtool_Raise_BadArgumentsError(x) _Dtool_Raise_BadArgumentsError()
221 #else
222 // Expand this to a TypeError listing all of the overloads.
223 #define Dtool_Raise_BadArgumentsError(x) Dtool_Raise_TypeError("Arguments must match:\n" x)
224 #endif
225 
226 // These functions are similar to Dtool_WrapValue, except that they also
227 // contain code for checking assertions and exceptions when compiling with
228 // NDEBUG mode on.
229 EXPCL_PYPANDA PyObject *_Dtool_Return_None();
230 EXPCL_PYPANDA PyObject *Dtool_Return_Bool(bool value);
231 EXPCL_PYPANDA PyObject *_Dtool_Return(PyObject *value);
232 
233 #ifdef NDEBUG
234 #define Dtool_Return_None() (LIKELY(_PyErr_OCCURRED() == nullptr) ? (Py_INCREF(Py_None), Py_None) : nullptr)
235 #define Dtool_Return(value) (LIKELY(_PyErr_OCCURRED() == nullptr) ? value : nullptr)
236 #else
237 #define Dtool_Return_None() _Dtool_Return_None()
238 #define Dtool_Return(value) _Dtool_Return(value)
239 #endif
240 
241 /**
242  * Wrapper around Python 3.4's enum library, which does not have a C API.
243  */
244 EXPCL_PYPANDA PyTypeObject *Dtool_EnumType_Create(const char *name, PyObject *names,
245  const char *module = nullptr);
246 INLINE long Dtool_EnumValue_AsLong(PyObject *value);
247 
248 
249 /**
250 
251  */
252 EXPCL_PYPANDA PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject &known_class_type, bool memory_rules, bool is_const, int RunTimeType);
253 
254 // DTool_CreatePyInstance .. wrapper function to finalize the existance of a
255 // general dtool py instance..
256 EXPCL_PYPANDA PyObject *DTool_CreatePyInstance(void *local_this, Dtool_PyTypedObject &in_classdef, bool memory_rules, bool is_const);
257 
258 // These template methods allow use when the Dtool_PyTypedObject is not known.
259 // They require a get_class_type() to be defined for the class.
260 template<class T> INLINE PyObject *DTool_CreatePyInstance(const T *obj, bool memory_rules);
261 template<class T> INLINE PyObject *DTool_CreatePyInstance(T *obj, bool memory_rules);
262 template<class T> INLINE PyObject *DTool_CreatePyInstanceTyped(const T *obj, bool memory_rules);
263 template<class T> INLINE PyObject *DTool_CreatePyInstanceTyped(T *obj, bool memory_rules);
264 
265 // Macro(s) class definition .. Used to allocate storage and init some values
266 // for a Dtool Py Type object.
267 
268 // struct Dtool_PyTypedObject Dtool_##CLASS_NAME;
269 
270 #define Define_Module_Class_Internal(MODULE_NAME,CLASS_NAME,CNAME)\
271 extern struct Dtool_PyTypedObject Dtool_##CLASS_NAME;\
272 static int Dtool_Init_##CLASS_NAME(PyObject *self, PyObject *args, PyObject *kwds);\
273 static PyObject *Dtool_new_##CLASS_NAME(PyTypeObject *type, PyObject *args, PyObject *kwds);
274 
275 #define Define_Module_Class(MODULE_NAME,CLASS_NAME,CNAME,PUBLIC_NAME)\
276 Define_Module_Class_Internal(MODULE_NAME,CLASS_NAME,CNAME)\
277 Define_Dtool_new(CLASS_NAME,CNAME)\
278 Define_Dtool_FreeInstance(CLASS_NAME,CNAME)\
279 Define_Dtool_Class(MODULE_NAME,CLASS_NAME,PUBLIC_NAME)
280 
281 #define Define_Module_Class_Private(MODULE_NAME,CLASS_NAME,CNAME,PUBLIC_NAME)\
282 Define_Module_Class_Internal(MODULE_NAME,CLASS_NAME,CNAME)\
283 Define_Dtool_new(CLASS_NAME,CNAME)\
284 Define_Dtool_FreeInstance_Private(CLASS_NAME,CNAME)\
285 Define_Dtool_Class(MODULE_NAME,CLASS_NAME,PUBLIC_NAME)
286 
287 #define Define_Module_ClassRef_Private(MODULE_NAME,CLASS_NAME,CNAME,PUBLIC_NAME)\
288 Define_Module_Class_Internal(MODULE_NAME,CLASS_NAME,CNAME)\
289 Define_Dtool_new(CLASS_NAME,CNAME)\
290 Define_Dtool_FreeInstanceRef_Private(CLASS_NAME,CNAME)\
291 Define_Dtool_Class(MODULE_NAME,CLASS_NAME,PUBLIC_NAME)
292 
293 #define Define_Module_ClassRef(MODULE_NAME,CLASS_NAME,CNAME,PUBLIC_NAME)\
294 Define_Module_Class_Internal(MODULE_NAME,CLASS_NAME,CNAME)\
295 Define_Dtool_new(CLASS_NAME,CNAME)\
296 Define_Dtool_FreeInstanceRef(CLASS_NAME,CNAME)\
297 Define_Dtool_Class(MODULE_NAME,CLASS_NAME,PUBLIC_NAME)
298 
299 // The finalizer for simple instances.
300 INLINE int DTool_PyInit_Finalize(PyObject *self, void *This, Dtool_PyTypedObject *type, bool memory_rules, bool is_const);
301 
302 // A heler function to glu methed definition together .. that can not be done
303 // at code generation time becouse of multiple generation passes in
304 // interigate..
305 typedef std::map<std::string, PyMethodDef *> MethodDefmap;
306 
307 // We need a way to runtime merge compile units into a python "Module" .. this
308 // is done with the fallowing structors and code.. along with the support of
309 // interigate_module
310 
311 struct Dtool_TypeDef {
312  const char *const name;
313  Dtool_PyTypedObject *type;
314 };
315 
316 struct LibraryDef {
317  PyMethodDef *const _methods;
318  const Dtool_TypeDef *const _types;
319  Dtool_TypeDef *const _external_types;
320 };
321 
322 #if PY_MAJOR_VERSION >= 3
323 EXPCL_PYPANDA PyObject *Dtool_PyModuleInitHelper(const LibraryDef *defs[], PyModuleDef *module_def);
324 #else
325 EXPCL_PYPANDA PyObject *Dtool_PyModuleInitHelper(const LibraryDef *defs[], const char *modulename);
326 #endif
327 
328 // HACK.... Be carefull Dtool_BorrowThisReference This function can be used to
329 // grab the "THIS" pointer from an object and use it Required to support fom
330 // historical inharatence in the for of "is this instance of"..
331 EXPCL_PYPANDA PyObject *Dtool_BorrowThisReference(PyObject *self, PyObject *args);
332 
333 #define DTOOL_PyObject_HashPointer DtoolInstance_HashPointer
334 #define DTOOL_PyObject_ComparePointers DtoolInstance_ComparePointers
335 
336 EXPCL_PYPANDA PyObject *
337 copy_from_make_copy(PyObject *self, PyObject *noargs);
338 
339 EXPCL_PYPANDA PyObject *
340 copy_from_copy_constructor(PyObject *self, PyObject *noargs);
341 
342 EXPCL_PYPANDA PyObject *
343 map_deepcopy_to_copy(PyObject *self, PyObject *args);
344 
345 /**
346  * These functions check whether the arguments passed to a function conform to
347  * certain expectations.
348  */
349 ALWAYS_INLINE bool Dtool_CheckNoArgs(PyObject *args);
350 ALWAYS_INLINE bool Dtool_CheckNoArgs(PyObject *args, PyObject *kwds);
351 EXPCL_PYPANDA bool Dtool_ExtractArg(PyObject **result, PyObject *args,
352  PyObject *kwds, const char *keyword);
353 EXPCL_PYPANDA bool Dtool_ExtractArg(PyObject **result, PyObject *args,
354  PyObject *kwds);
355 EXPCL_PYPANDA bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args,
356  PyObject *kwds, const char *keyword);
357 EXPCL_PYPANDA bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args,
358  PyObject *kwds);
359 
360 /**
361  * These functions convert a C++ value into the corresponding Python object.
362  * This used to be generated by the code generator, but it seems more reliable
363  * and maintainable to define these as overloads and have the compiler sort
364  * it out.
365  */
366 ALWAYS_INLINE PyObject *Dtool_WrapValue(int value);
367 ALWAYS_INLINE PyObject *Dtool_WrapValue(unsigned int value);
368 ALWAYS_INLINE PyObject *Dtool_WrapValue(long value);
369 ALWAYS_INLINE PyObject *Dtool_WrapValue(unsigned long value);
370 ALWAYS_INLINE PyObject *Dtool_WrapValue(long long value);
371 ALWAYS_INLINE PyObject *Dtool_WrapValue(unsigned long long value);
372 ALWAYS_INLINE PyObject *Dtool_WrapValue(bool value);
373 ALWAYS_INLINE PyObject *Dtool_WrapValue(double value);
374 ALWAYS_INLINE PyObject *Dtool_WrapValue(const char *value);
375 ALWAYS_INLINE PyObject *Dtool_WrapValue(const wchar_t *value);
376 ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::string &value);
377 ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::wstring &value);
378 ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::string *value);
379 ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::wstring *value);
380 ALWAYS_INLINE PyObject *Dtool_WrapValue(char value);
381 ALWAYS_INLINE PyObject *Dtool_WrapValue(wchar_t value);
382 ALWAYS_INLINE PyObject *Dtool_WrapValue(std::nullptr_t);
383 ALWAYS_INLINE PyObject *Dtool_WrapValue(PyObject *value);
384 ALWAYS_INLINE PyObject *Dtool_WrapValue(const vector_uchar &value);
385 
386 #if PY_MAJOR_VERSION >= 0x02060000
387 ALWAYS_INLINE PyObject *Dtool_WrapValue(Py_buffer *value);
388 #endif
389 
390 template<class T1, class T2>
391 ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::pair<T1, T2> &value);
392 
393 EXPCL_PYPANDA Dtool_PyTypedObject *Dtool_GetSuperBase();
394 
395 #include "py_panda.I"
396 
397 #include "py_wrappers.h"
398 
399 #endif // HAVE_PYTHON && !CPPPARSER
400 
401 #endif // PY_PANDA_H_
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Py_hash_t DtoolInstance_HashPointer(PyObject *self)
Function to create a hash from a wrapped Python object.
Definition: py_panda.I:65
bool Dtool_CheckNoArgs(PyObject *args)
Checks that the tuple is empty.
Definition: py_panda.I:154
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
long Dtool_EnumValue_AsLong(PyObject *value)
Converts the enum value to a C long.
Definition: py_panda.I:96
PyObject * DtoolInstance_RichComparePointers(PyObject *v1, PyObject *v2, int op)
Rich comparison function that compares objects by pointer.
Definition: py_panda.I:88
PyObject * Dtool_WrapValue(int value)
The following functions wrap an arbitrary C++ value into a PyObject.
Definition: py_panda.I:170
PyObject * DTool_CreatePyInstance(const T *obj, bool memory_rules)
These functions wrap a pointer for a class that defines get_type_handle().
Definition: py_panda.I:111
int DtoolInstance_ComparePointers(PyObject *v1, PyObject *v2)
Python 2-style comparison function that compares objects by pointer.
Definition: py_panda.I:75
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int DTool_PyInit_Finalize(PyObject *self, void *local_this, Dtool_PyTypedObject *type, bool memory_rules, bool is_const)
Finishes initializing the Dtool_PyInstDef.
Definition: py_panda.I:142
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
bool DtoolInstance_GetPointer(PyObject *self, T *&into)
Template function that can be used to extract any TypedObject pointer from a wrapped Python object.
Definition: py_panda.I:20