Panda3D

Loading...
Searching...
No Matches
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// Extract the PyTypeObject pointer corresponding to a Dtool_PyTypedObject.
165#define Dtool_GetPyTypeObject(type) (&(type)->_PyType)
166
167// Use DtoolInstance_Check to check whether a PyObject* is a DtoolInstance.
168#define DtoolInstance_Check(obj) \
169 (Py_TYPE(obj)->tp_basicsize >= (int)sizeof(Dtool_PyInstDef) && \
170 ((Dtool_PyInstDef *)obj)->_signature == PY_PANDA_SIGNATURE)
171
172// These macros access the DtoolInstance without error checking.
173#define DtoolInstance_TYPE(obj) (((Dtool_PyInstDef *)obj)->_My_Type)
174#define DtoolInstance_IS_CONST(obj) (((Dtool_PyInstDef *)obj)->_is_const)
175#define DtoolInstance_VOID_PTR(obj) (((Dtool_PyInstDef *)obj)->_ptr_to_object)
176#define DtoolInstance_INIT_PTR(obj, ptr) { ((Dtool_PyInstDef *)obj)->_ptr_to_object = (void*)(ptr); }
177#define DtoolInstance_UPCAST(obj, type) (((Dtool_PyInstDef *)(obj))->_My_Type->_Dtool_UpcastInterface((obj), &(type)))
178
179// ** HACK ** allert.. Need to keep a runtime type dictionary ... that is
180// forward declared of typed object. We rely on the fact that typed objects
181// are uniquly defined by an integer.
182
183 typedef std::map<std::string, Dtool_PyTypedObject *> Dtool_TypeMap;
184
185EXPCL_PYPANDA Dtool_TypeMap *Dtool_GetGlobalTypeMap();
186
187/**
188
189 */
190EXPCL_PYPANDA void DTOOL_Call_ExtractThisPointerForType(PyObject *self, Dtool_PyTypedObject *classdef, void **answer);
191
192EXPCL_PYPANDA void *DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef, int param, const std::string &function_name, bool const_ok, bool report_errors);
193
194EXPCL_PYPANDA bool Dtool_Call_ExtractThisPointer(PyObject *self, Dtool_PyTypedObject &classdef, void **answer);
195
196EXPCL_PYPANDA bool Dtool_Call_ExtractThisPointer_NonConst(PyObject *self, Dtool_PyTypedObject &classdef,
197 void **answer, const char *method_name);
198
199 template<class T> INLINE bool DtoolInstance_GetPointer(PyObject *self, T *&into);
200 template<class T> INLINE bool DtoolInstance_GetPointer(PyObject *self, T *&into, Dtool_PyTypedObject &classdef);
201
202INLINE Py_hash_t DtoolInstance_HashPointer(PyObject *self);
203INLINE int DtoolInstance_ComparePointers(PyObject *v1, PyObject *v2);
204INLINE PyObject *DtoolInstance_RichComparePointers(PyObject *v1, PyObject *v2, int op);
205
206// Functions related to error reporting.
207EXPCL_PYPANDA bool _Dtool_CheckErrorOccurred();
208
209#ifdef NDEBUG
210#define Dtool_CheckErrorOccurred() (UNLIKELY(_PyErr_OCCURRED() != nullptr))
211#else
212#define Dtool_CheckErrorOccurred() (UNLIKELY(_Dtool_CheckErrorOccurred()))
213#endif
214
215EXPCL_PYPANDA PyObject *Dtool_Raise_AssertionError();
216EXPCL_PYPANDA PyObject *Dtool_Raise_TypeError(const char *message);
217EXPCL_PYPANDA PyObject *Dtool_Raise_ArgTypeError(PyObject *obj, int param, const char *function_name, const char *type_name);
218EXPCL_PYPANDA PyObject *Dtool_Raise_AttributeError(PyObject *obj, const char *attribute);
219
220EXPCL_PYPANDA PyObject *_Dtool_Raise_BadArgumentsError();
221#ifdef NDEBUG
222// Define it to a function that just prints a generic message.
223#define Dtool_Raise_BadArgumentsError(x) _Dtool_Raise_BadArgumentsError()
224#else
225// Expand this to a TypeError listing all of the overloads.
226#define Dtool_Raise_BadArgumentsError(x) Dtool_Raise_TypeError("Arguments must match:\n" x)
227#endif
228
229// These functions are similar to Dtool_WrapValue, except that they also
230// contain code for checking assertions and exceptions when compiling with
231// NDEBUG mode on.
232EXPCL_PYPANDA PyObject *_Dtool_Return_None();
233EXPCL_PYPANDA PyObject *Dtool_Return_Bool(bool value);
234EXPCL_PYPANDA PyObject *_Dtool_Return(PyObject *value);
235
236#ifdef NDEBUG
237#define Dtool_Return_None() (LIKELY(_PyErr_OCCURRED() == nullptr) ? (Py_INCREF(Py_None), Py_None) : nullptr)
238#define Dtool_Return(value) (LIKELY(_PyErr_OCCURRED() == nullptr) ? value : nullptr)
239#else
240#define Dtool_Return_None() _Dtool_Return_None()
241#define Dtool_Return(value) _Dtool_Return(value)
242#endif
243
244ALWAYS_INLINE void Dtool_Assign_PyObject(PyObject *&ptr, PyObject *value);
245
246/**
247 * Wrapper around Python 3.4's enum library, which does not have a C API.
248 */
249EXPCL_PYPANDA PyTypeObject *Dtool_EnumType_Create(const char *name, PyObject *names,
250 const char *module = nullptr);
251INLINE long Dtool_EnumValue_AsLong(PyObject *value);
252
253
254/**
255
256 */
257EXPCL_PYPANDA PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject &known_class_type, bool memory_rules, bool is_const, int RunTimeType);
258
259// DTool_CreatePyInstance .. wrapper function to finalize the existance of a
260// general dtool py instance..
261EXPCL_PYPANDA PyObject *DTool_CreatePyInstance(void *local_this, Dtool_PyTypedObject &in_classdef, bool memory_rules, bool is_const);
262
263// These template methods allow use when the Dtool_PyTypedObject is not known.
264// They require a get_class_type() to be defined for the class.
265 template<class T> INLINE PyObject *DTool_CreatePyInstance(const T *obj, bool memory_rules);
266 template<class T> INLINE PyObject *DTool_CreatePyInstance(T *obj, bool memory_rules);
267 template<class T> INLINE PyObject *DTool_CreatePyInstanceTyped(const T *obj, bool memory_rules);
268 template<class T> INLINE PyObject *DTool_CreatePyInstanceTyped(T *obj, bool memory_rules);
269
270// Macro(s) class definition .. Used to allocate storage and init some values
271// for a Dtool Py Type object.
272
273// struct Dtool_PyTypedObject Dtool_##CLASS_NAME;
274
275#define Define_Module_Class_Internal(MODULE_NAME,CLASS_NAME,CNAME)\
276 extern struct Dtool_PyTypedObject Dtool_##CLASS_NAME;\
277 static int Dtool_Init_##CLASS_NAME(PyObject *self, PyObject *args, PyObject *kwds);\
278 static PyObject *Dtool_new_##CLASS_NAME(PyTypeObject *type, PyObject *args, PyObject *kwds);
279
280#define Define_Module_Class(MODULE_NAME,CLASS_NAME,CNAME,PUBLIC_NAME)\
281 Define_Module_Class_Internal(MODULE_NAME,CLASS_NAME,CNAME)\
282 Define_Dtool_new(CLASS_NAME,CNAME)\
283 Define_Dtool_FreeInstance(CLASS_NAME,CNAME)\
284 Define_Dtool_Class(MODULE_NAME,CLASS_NAME,PUBLIC_NAME)
285
286#define Define_Module_Class_Private(MODULE_NAME,CLASS_NAME,CNAME,PUBLIC_NAME)\
287 Define_Module_Class_Internal(MODULE_NAME,CLASS_NAME,CNAME)\
288 Define_Dtool_new(CLASS_NAME,CNAME)\
289 Define_Dtool_FreeInstance_Private(CLASS_NAME,CNAME)\
290 Define_Dtool_Class(MODULE_NAME,CLASS_NAME,PUBLIC_NAME)
291
292#define Define_Module_ClassRef_Private(MODULE_NAME,CLASS_NAME,CNAME,PUBLIC_NAME)\
293 Define_Module_Class_Internal(MODULE_NAME,CLASS_NAME,CNAME)\
294 Define_Dtool_new(CLASS_NAME,CNAME)\
295 Define_Dtool_FreeInstanceRef_Private(CLASS_NAME,CNAME)\
296 Define_Dtool_Class(MODULE_NAME,CLASS_NAME,PUBLIC_NAME)
297
298#define Define_Module_ClassRef(MODULE_NAME,CLASS_NAME,CNAME,PUBLIC_NAME)\
299 Define_Module_Class_Internal(MODULE_NAME,CLASS_NAME,CNAME)\
300 Define_Dtool_new(CLASS_NAME,CNAME)\
301 Define_Dtool_FreeInstanceRef(CLASS_NAME,CNAME)\
302 Define_Dtool_Class(MODULE_NAME,CLASS_NAME,PUBLIC_NAME)
303
304// The finalizer for simple instances.
305INLINE int DTool_PyInit_Finalize(PyObject *self, void *This, Dtool_PyTypedObject *type, bool memory_rules, bool is_const);
306
307// A heler function to glu methed definition together .. that can not be done
308// at code generation time becouse of multiple generation passes in
309// interigate..
310 typedef std::map<std::string, PyMethodDef *> MethodDefmap;
311
312// We need a way to runtime merge compile units into a python "Module" .. this
313// is done with the fallowing structors and code.. along with the support of
314// interigate_module
315
316 struct Dtool_TypeDef {
317 const char *const name;
318 Dtool_PyTypedObject *type;
319};
320
321 struct LibraryDef {
322 PyMethodDef *const _methods;
323 const Dtool_TypeDef *const _types;
324 Dtool_TypeDef *const _external_types;
325};
326
327#if PY_MAJOR_VERSION >= 3
328EXPCL_PYPANDA PyObject *Dtool_PyModuleInitHelper(const LibraryDef *defs[], PyModuleDef *module_def);
329#else
330EXPCL_PYPANDA PyObject *Dtool_PyModuleInitHelper(const LibraryDef *defs[], const char *modulename);
331#endif
332
333// HACK.... Be carefull Dtool_BorrowThisReference This function can be used to
334// grab the "THIS" pointer from an object and use it Required to support fom
335// historical inharatence in the for of "is this instance of"..
336EXPCL_PYPANDA PyObject *Dtool_BorrowThisReference(PyObject *self, PyObject *args);
337
338#define DTOOL_PyObject_HashPointer DtoolInstance_HashPointer
339#define DTOOL_PyObject_ComparePointers DtoolInstance_ComparePointers
340
341EXPCL_PYPANDA PyObject *
342copy_from_make_copy(PyObject *self, PyObject *noargs);
343
344EXPCL_PYPANDA PyObject *
345copy_from_copy_constructor(PyObject *self, PyObject *noargs);
346
347EXPCL_PYPANDA PyObject *
348map_deepcopy_to_copy(PyObject *self, PyObject *args);
349
350/**
351 * These functions check whether the arguments passed to a function conform to
352 * certain expectations.
353 */
354ALWAYS_INLINE bool Dtool_CheckNoArgs(PyObject *args);
355ALWAYS_INLINE bool Dtool_CheckNoArgs(PyObject *args, PyObject *kwds);
356EXPCL_PYPANDA bool Dtool_ExtractArg(PyObject **result, PyObject *args,
357 PyObject *kwds, const char *keyword);
358EXPCL_PYPANDA bool Dtool_ExtractArg(PyObject **result, PyObject *args,
359 PyObject *kwds);
360EXPCL_PYPANDA bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args,
361 PyObject *kwds, const char *keyword);
362EXPCL_PYPANDA bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args,
363 PyObject *kwds);
364
365/**
366 * These functions convert a C++ value into the corresponding Python object.
367 * This used to be generated by the code generator, but it seems more reliable
368 * and maintainable to define these as overloads and have the compiler sort
369 * it out.
370 */
371ALWAYS_INLINE PyObject *Dtool_WrapValue(int value);
372ALWAYS_INLINE PyObject *Dtool_WrapValue(unsigned int value);
373ALWAYS_INLINE PyObject *Dtool_WrapValue(long value);
374ALWAYS_INLINE PyObject *Dtool_WrapValue(unsigned long value);
375ALWAYS_INLINE PyObject *Dtool_WrapValue(long long value);
376ALWAYS_INLINE PyObject *Dtool_WrapValue(unsigned long long value);
377ALWAYS_INLINE PyObject *Dtool_WrapValue(bool value);
378ALWAYS_INLINE PyObject *Dtool_WrapValue(double value);
379ALWAYS_INLINE PyObject *Dtool_WrapValue(const char *value);
380ALWAYS_INLINE PyObject *Dtool_WrapValue(const wchar_t *value);
381ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::string &value);
382ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::wstring &value);
383ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::string *value);
384ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::wstring *value);
385ALWAYS_INLINE PyObject *Dtool_WrapValue(char value);
386ALWAYS_INLINE PyObject *Dtool_WrapValue(wchar_t value);
387ALWAYS_INLINE PyObject *Dtool_WrapValue(std::nullptr_t);
388ALWAYS_INLINE PyObject *Dtool_WrapValue(PyObject *value);
389ALWAYS_INLINE PyObject *Dtool_WrapValue(const vector_uchar &value);
390
391#if PY_MAJOR_VERSION >= 0x02060000
392ALWAYS_INLINE PyObject *Dtool_WrapValue(Py_buffer *value);
393#endif
394
395 template<class T1, class T2>
396ALWAYS_INLINE PyObject *Dtool_WrapValue(const std::pair<T1, T2> &value);
397
398EXPCL_PYPANDA Dtool_PyTypedObject *Dtool_GetSuperBase();
399
400#include "py_panda.I"
401
402#include "py_wrappers.h"
403
404#endif // HAVE_PYTHON && !CPPPARSER
405
406#endif // PY_PANDA_H_
std
STL namespace.
pnotify.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
py_compat.h
py_panda.I
Dtool_CheckNoArgs
bool Dtool_CheckNoArgs(PyObject *args)
Checks that the tuple is empty.
Definition py_panda.I:167
DtoolInstance_ComparePointers
int DtoolInstance_ComparePointers(PyObject *v1, PyObject *v2)
Python 2-style comparison function that compares objects by pointer.
Definition py_panda.I:75
Dtool_WrapValue
PyObject * Dtool_WrapValue(int value)
The following functions wrap an arbitrary C++ value into a PyObject.
Definition py_panda.I:183
DTool_PyInit_Finalize
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:155
Dtool_EnumValue_AsLong
long Dtool_EnumValue_AsLong(PyObject *value)
Converts the enum value to a C long.
Definition py_panda.I:109
Dtool_Assign_PyObject
void Dtool_Assign_PyObject(PyObject *&ptr, PyObject *value)
Utility function for assigning a PyObject pointer while managing refcounts.
Definition py_panda.I:97
DTool_CreatePyInstance
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:124
DtoolInstance_RichComparePointers
PyObject * DtoolInstance_RichComparePointers(PyObject *v1, PyObject *v2, int op)
Rich comparison function that compares objects by pointer.
Definition py_panda.I:88
DtoolInstance_GetPointer
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
DtoolInstance_HashPointer
Py_hash_t DtoolInstance_HashPointer(PyObject *self)
Function to create a hash from a wrapped Python object.
Definition py_panda.I:65
py_wrappers.h
register_type.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
vector_uchar.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.