interrogate: clean up py_panda.h a bit more

Inching towards reducing code in py_panda and eventually having no Python-specific code in interrogatedb anymore.
This commit is contained in:
rdb 2018-06-11 13:39:45 +02:00
parent bc596797a3
commit 3cc88cd304
8 changed files with 105 additions and 184 deletions

View File

@ -2536,7 +2536,7 @@ write_module_class(ostream &out, Object *obj) {
} }
} }
if (NeedsARichCompareFunction(obj->_itype)) { if (NeedsARichCompareFunction(obj->_itype) || slots.count("tp_compare")) {
out << "//////////////////\n"; out << "//////////////////\n";
out << "// A rich comparison function\n"; out << "// A rich comparison function\n";
out << "// " << ClassName << "\n"; out << "// " << ClassName << "\n";
@ -2547,7 +2547,6 @@ write_module_class(ostream &out, Object *obj) {
out << " return nullptr;\n"; out << " return nullptr;\n";
out << " }\n\n"; out << " }\n\n";
out << " switch (op) {\n";
for (fi = obj->_methods.begin(); fi != obj->_methods.end(); ++fi) { for (fi = obj->_methods.begin(); fi != obj->_methods.end(); ++fi) {
std::set<FunctionRemap*> remaps; std::set<FunctionRemap*> remaps;
Function *func = (*fi); Function *func = (*fi);
@ -2564,21 +2563,28 @@ write_module_class(ostream &out, Object *obj) {
} }
} }
const string &fname = func->_ifunc.get_name(); const string &fname = func->_ifunc.get_name();
const char *op_type;
if (fname == "operator <") { if (fname == "operator <") {
out << " case Py_LT:\n"; op_type = "Py_LT";
} else if (fname == "operator <=") { } else if (fname == "operator <=") {
out << " case Py_LE:\n"; op_type = "Py_LE";
} else if (fname == "operator ==") { } else if (fname == "operator ==") {
out << " case Py_EQ:\n"; op_type = "Py_EQ";
} else if (fname == "operator !=") { } else if (fname == "operator !=") {
out << " case Py_NE:\n"; op_type = "Py_NE";
} else if (fname == "operator >") { } else if (fname == "operator >") {
out << " case Py_GT:\n"; op_type = "Py_GT";
} else if (fname == "operator >=") { } else if (fname == "operator >=") {
out << " case Py_GE:\n"; op_type = "Py_GE";
} else { } else {
continue; continue;
} }
if (!has_local_richcompare) {
out << " switch (op) {\n";
has_local_richcompare = true;
}
out << " case " << op_type << ":\n";
out << " {\n"; out << " {\n";
string expected_params; string expected_params;
@ -2587,14 +2593,15 @@ write_module_class(ostream &out, Object *obj) {
out << " break;\n"; out << " break;\n";
out << " }\n"; out << " }\n";
has_local_richcompare = true;
} }
out << " }\n\n"; if (has_local_richcompare) {
// End of switch block
out << " if (_PyErr_OCCURRED()) {\n"; out << " }\n\n";
out << " PyErr_Clear();\n"; out << " if (_PyErr_OCCURRED()) {\n";
out << " }\n\n"; out << " PyErr_Clear();\n";
out << " }\n\n";
}
if (slots.count("tp_compare")) { if (slots.count("tp_compare")) {
// A lot of Panda code depends on comparisons being done via the // A lot of Panda code depends on comparisons being done via the
@ -2624,6 +2631,7 @@ write_module_class(ostream &out, Object *obj) {
out << " case Py_GE:\n"; out << " case Py_GE:\n";
out << " return PyBool_FromLong(cmpval >= 0);\n"; out << " return PyBool_FromLong(cmpval >= 0);\n";
out << " }\n"; out << " }\n";
has_local_richcompare = true;
} }
out << " Py_INCREF(Py_NotImplemented);\n"; out << " Py_INCREF(Py_NotImplemented);\n";
@ -2850,7 +2858,7 @@ write_module_class(ostream &out, Object *obj) {
out << "#else\n"; out << "#else\n";
if (has_hash_compare) { if (has_hash_compare) {
write_function_slot(out, 4, slots, "tp_compare", write_function_slot(out, 4, slots, "tp_compare",
"&DTOOL_PyObject_ComparePointers"); "&DtoolInstance_ComparePointers");
} else { } else {
out << " nullptr, // tp_compare\n"; out << " nullptr, // tp_compare\n";
} }
@ -2880,7 +2888,7 @@ write_module_class(ostream &out, Object *obj) {
// hashfunc tp_hash; // hashfunc tp_hash;
if (has_hash_compare) { if (has_hash_compare) {
write_function_slot(out, 4, slots, "tp_hash", "&DTOOL_PyObject_HashPointer"); write_function_slot(out, 4, slots, "tp_hash", "&DtoolInstance_HashPointer");
} else { } else {
out << " nullptr, // tp_hash\n"; out << " nullptr, // tp_hash\n";
} }
@ -2951,7 +2959,7 @@ write_module_class(ostream &out, Object *obj) {
} else if (has_hash_compare) { } else if (has_hash_compare) {
// All hashable types need to be comparable. // All hashable types need to be comparable.
out << "#if PY_MAJOR_VERSION >= 3\n"; out << "#if PY_MAJOR_VERSION >= 3\n";
out << " &DTOOL_PyObject_RichCompare,\n"; out << " &DtoolInstance_RichComparePointers,\n";
out << "#else\n"; out << "#else\n";
out << " nullptr, // tp_richcompare\n"; out << " nullptr, // tp_richcompare\n";
out << "#endif\n"; out << "#endif\n";

View File

@ -79,13 +79,13 @@ EXPORT_THIS Dtool_PyTypedObject Dtool_DTOOL_SUPER_BASE = {
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
nullptr, // tp_compare nullptr, // tp_compare
#else #else
&DTOOL_PyObject_ComparePointers, &DtoolInstance_ComparePointers,
#endif #endif
nullptr, // tp_repr nullptr, // tp_repr
nullptr, // tp_as_number nullptr, // tp_as_number
nullptr, // tp_as_sequence nullptr, // tp_as_sequence
nullptr, // tp_as_mapping nullptr, // tp_as_mapping
&DTOOL_PyObject_HashPointer, &DtoolInstance_HashPointer,
nullptr, // tp_call nullptr, // tp_call
nullptr, // tp_str nullptr, // tp_str
PyObject_GenericGetAttr, PyObject_GenericGetAttr,
@ -96,7 +96,7 @@ EXPORT_THIS Dtool_PyTypedObject Dtool_DTOOL_SUPER_BASE = {
nullptr, // tp_traverse nullptr, // tp_traverse
nullptr, // tp_clear nullptr, // tp_clear
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
&DTOOL_PyObject_RichCompare, &DtoolInstance_RichComparePointers,
#else #else
nullptr, // tp_richcompare nullptr, // tp_richcompare
#endif #endif

View File

@ -16,8 +16,6 @@
#ifdef HAVE_PYTHON #ifdef HAVE_PYTHON
PyTupleObject Dtool_EmptyTuple = {PyVarObject_HEAD_INIT(nullptr, 0)};
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
/** /**
* Given a long or int, returns a size_t, or raises an OverflowError if it is * Given a long or int, returns a size_t, or raises an OverflowError if it is

View File

@ -138,11 +138,29 @@ typedef long Py_hash_t;
/* Python 3.6 */ /* Python 3.6 */
// Used to implement _PyObject_CallNoArg
extern EXPCL_INTERROGATEDB PyTupleObject Dtool_EmptyTuple;
#ifndef _PyObject_CallNoArg #ifndef _PyObject_CallNoArg
# define _PyObject_CallNoArg(func) PyObject_Call((func), (PyObject *)&Dtool_EmptyTuple, nullptr) INLINE PyObject *_PyObject_CallNoArg(PyObject *func) {
static PyTupleObject empty_tuple = {PyVarObject_HEAD_INIT(nullptr, 0)};
#ifdef Py_TRACE_REFS
_Py_AddToAllObjects((PyObject *)&empty_tuple, 0);
#endif
return PyObject_Call(func, (PyObject *)&empty_tuple, nullptr);
}
# define _PyObject_CallNoArg _PyObject_CallNoArg
#endif
#ifndef _PyObject_FastCall
INLINE PyObject *_PyObject_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs) {
PyObject *tuple = PyTuple_New(nargs);
for (Py_ssize_t i = 0; i < nargs; ++i) {
PyTuple_SET_ITEM(tuple, i, args[i]);
Py_INCREF(args[i]);
}
PyObject *result = PyObject_Call(func, tuple, nullptr);
Py_DECREF(tuple);
return result;
}
# define _PyObject_FastCall _PyObject_FastCall
#endif #endif
// Python versions before 3.6 didn't require longlong support to be enabled. // Python versions before 3.6 didn't require longlong support to be enabled.
@ -161,6 +179,21 @@ extern EXPCL_INTERROGATEDB PyTupleObject Dtool_EmptyTuple;
# define PyDict_GET_SIZE(mp) (((PyDictObject *)mp)->ma_used) # define PyDict_GET_SIZE(mp) (((PyDictObject *)mp)->ma_used)
#endif #endif
#ifndef Py_RETURN_RICHCOMPARE
# define Py_RETURN_RICHCOMPARE(val1, val2, op) \
do { \
switch (op) { \
NODEFAULT \
case Py_EQ: if ((val1) == (val2)) Py_RETURN_TRUE; Py_RETURN_FALSE; \
case Py_NE: if ((val1) != (val2)) Py_RETURN_TRUE; Py_RETURN_FALSE; \
case Py_LT: if ((val1) < (val2)) Py_RETURN_TRUE; Py_RETURN_FALSE; \
case Py_GT: if ((val1) > (val2)) Py_RETURN_TRUE; Py_RETURN_FALSE; \
case Py_LE: if ((val1) <= (val2)) Py_RETURN_TRUE; Py_RETURN_FALSE; \
case Py_GE: if ((val1) >= (val2)) Py_RETURN_TRUE; Py_RETURN_FALSE; \
} \
} while (0)
#endif
/* Other Python implementations */ /* Other Python implementations */
// _PyErr_OCCURRED is an undocumented macro version of PyErr_Occurred. // _PyErr_OCCURRED is an undocumented macro version of PyErr_Occurred.

View File

@ -62,6 +62,37 @@ DtoolInstance_GetPointer(PyObject *self, T *&into, Dtool_PyTypedObject &target_c
return false; return false;
} }
/**
* Function to create a hash from a wrapped Python object.
*/
INLINE Py_hash_t DtoolInstance_HashPointer(PyObject *self) {
if (self != nullptr && DtoolInstance_Check(self)) {
return (Py_hash_t)(intptr_t)DtoolInstance_VOID_PTR(self);
}
return -1;
}
/**
* Python 2-style comparison function that compares objects by pointer.
*/
INLINE int DtoolInstance_ComparePointers(PyObject *v1, PyObject *v2) {
void *v1_this = DtoolInstance_Check(v1) ? DtoolInstance_VOID_PTR(v1) : nullptr;
void *v2_this = DtoolInstance_Check(v2) ? DtoolInstance_VOID_PTR(v2) : nullptr;
if (v1_this != nullptr && v2_this != nullptr) {
return (v1_this > v2_this) - (v1_this < v2_this);
} else {
return (v1 > v2) - (v1 < v2);
}
}
/**
* Rich comparison function that compares objects by pointer.
*/
INLINE PyObject *DtoolInstance_RichComparePointers(PyObject *v1, PyObject *v2, int op) {
int cmpval = DtoolInstance_ComparePointers(v1, v2);
Py_RETURN_RICHCOMPARE(cmpval, 0, op);
}
/** /**
* These functions wrap a pointer for a class that defines get_type_handle(). * These functions wrap a pointer for a class that defines get_type_handle().
*/ */

View File

@ -143,13 +143,6 @@ DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef,
return nullptr; return nullptr;
} }
void *DTOOL_Call_GetPointerThis(PyObject *self) {
if (self != nullptr && DtoolInstance_Check(self)) {
return DtoolInstance_VOID_PTR(self);
}
return nullptr;
}
/** /**
* This is similar to a PyErr_Occurred() check, except that it also checks * This is similar to a PyErr_Occurred() check, except that it also checks
* Notify to see if an assertion has occurred. If that is the case, then it * Notify to see if an assertion has occurred. If that is the case, then it
@ -588,10 +581,6 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) {
return Dtool_Raise_TypeError("PyType_Ready(Dtool_StaticProperty_Type)"); return Dtool_Raise_TypeError("PyType_Ready(Dtool_StaticProperty_Type)");
} }
#ifdef Py_TRACE_REFS
_Py_AddToAllObjects((PyObject *)&Dtool_EmptyTuple, 0);
#endif
// Initialize the base class of everything. // Initialize the base class of everything.
Dtool_PyModuleClassInit_DTOOL_SUPER_BASE(nullptr); Dtool_PyModuleClassInit_DTOOL_SUPER_BASE(nullptr);
} }
@ -734,127 +723,6 @@ PyObject *Dtool_AddToDictionary(PyObject *self1, PyObject *args) {
return Py_None; return Py_None;
} }
Py_hash_t DTOOL_PyObject_HashPointer(PyObject *self) {
if (self != nullptr && DtoolInstance_Check(self)) {
return (Py_hash_t)(intptr_t)DtoolInstance_VOID_PTR(self);
}
return -1;
}
/* Compare v to w. Return
-1 if v < w or exception (PyErr_Occurred() true in latter case).
0 if v == w.
1 if v > w.
XXX The docs (C API manual) say the return value is undefined in case
XXX of error.
*/
int DTOOL_PyObject_ComparePointers(PyObject *v1, PyObject *v2) {
// try this compare
void *v1_this = DTOOL_Call_GetPointerThis(v1);
void *v2_this = DTOOL_Call_GetPointerThis(v2);
if (v1_this != nullptr && v2_this != nullptr) { // both are our types...
if (v1_this < v2_this) {
return -1;
}
if (v1_this > v2_this) {
return 1;
}
return 0;
}
// ok self compare...
if (v1 < v2) {
return -1;
}
if (v1 > v2) {
return 1;
}
return 0;
}
int DTOOL_PyObject_Compare(PyObject *v1, PyObject *v2) {
// First try compareTo function..
PyObject * func = PyObject_GetAttrString(v1, "compare_to");
if (func == nullptr) {
PyErr_Clear();
} else {
#if PY_VERSION_HEX >= 0x03060000
PyObject *res = _PyObject_FastCall(func, &v2, 1);
#else
PyObject *res = nullptr;
PyObject *args = PyTuple_Pack(1, v2);
if (args != nullptr) {
res = PyObject_Call(func, args, nullptr);
Py_DECREF(args);
}
#endif
Py_DECREF(func);
PyErr_Clear(); // just in case the function threw an error
// only use if the function returns an INT... hmm
if (res != nullptr) {
if (PyLong_Check(res)) {
long answer = PyLong_AsLong(res);
Py_DECREF(res);
// Python really wants us to return strictly -1, 0, or 1.
if (answer < 0) {
return -1;
} else if (answer > 0) {
return 1;
} else {
return 0;
}
}
#if PY_MAJOR_VERSION < 3
else if (PyInt_Check(res)) {
long answer = PyInt_AsLong(res);
Py_DECREF(res);
// Python really wants us to return strictly -1, 0, or 1.
if (answer < 0) {
return -1;
} else if (answer > 0) {
return 1;
} else {
return 0;
}
}
#endif
Py_DECREF(res);
}
}
return DTOOL_PyObject_ComparePointers(v1, v2);
}
PyObject *DTOOL_PyObject_RichCompare(PyObject *v1, PyObject *v2, int op) {
int cmpval = DTOOL_PyObject_Compare(v1, v2);
bool result;
switch (op) {
NODEFAULT
case Py_LT:
result = (cmpval < 0);
break;
case Py_LE:
result = (cmpval <= 0);
break;
case Py_EQ:
result = (cmpval == 0);
break;
case Py_NE:
result = (cmpval != 0);
break;
case Py_GT:
result = (cmpval > 0);
break;
case Py_GE:
result = (cmpval >= 0);
break;
}
return PyBool_FromLong(result);
}
/** /**
* This is a support function for a synthesized __copy__() method from a C++ * This is a support function for a synthesized __copy__() method from a C++
* make_copy() method. * make_copy() method.
@ -875,15 +743,7 @@ PyObject *copy_from_make_copy(PyObject *self, PyObject *noargs) {
*/ */
PyObject *copy_from_copy_constructor(PyObject *self, PyObject *noargs) { PyObject *copy_from_copy_constructor(PyObject *self, PyObject *noargs) {
PyObject *callable = (PyObject *)Py_TYPE(self); PyObject *callable = (PyObject *)Py_TYPE(self);
return _PyObject_FastCall(callable, &self, 1);
#if PY_VERSION_HEX >= 0x03060000
PyObject *result = _PyObject_FastCall(callable, &self, 1);
#else
PyObject *args = PyTuple_Pack(1, self);
PyObject *result = PyObject_Call(callable, args, nullptr);
Py_DECREF(args);
#endif
return result;
} }
/** /**

View File

@ -195,8 +195,6 @@ EXPCL_INTERROGATEDB void DTOOL_Call_ExtractThisPointerForType(PyObject *self, Dt
EXPCL_INTERROGATEDB void *DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef, int param, const std::string &function_name, bool const_ok, bool report_errors); EXPCL_INTERROGATEDB void *DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef, int param, const std::string &function_name, bool const_ok, bool report_errors);
EXPCL_INTERROGATEDB void *DTOOL_Call_GetPointerThis(PyObject *self);
EXPCL_INTERROGATEDB bool Dtool_Call_ExtractThisPointer(PyObject *self, Dtool_PyTypedObject &classdef, void **answer); EXPCL_INTERROGATEDB bool Dtool_Call_ExtractThisPointer(PyObject *self, Dtool_PyTypedObject &classdef, void **answer);
EXPCL_INTERROGATEDB bool Dtool_Call_ExtractThisPointer_NonConst(PyObject *self, Dtool_PyTypedObject &classdef, EXPCL_INTERROGATEDB bool Dtool_Call_ExtractThisPointer_NonConst(PyObject *self, Dtool_PyTypedObject &classdef,
@ -205,6 +203,10 @@ EXPCL_INTERROGATEDB bool Dtool_Call_ExtractThisPointer_NonConst(PyObject *self,
template<class T> INLINE bool DtoolInstance_GetPointer(PyObject *self, T *&into); template<class T> INLINE bool DtoolInstance_GetPointer(PyObject *self, T *&into);
template<class T> INLINE bool DtoolInstance_GetPointer(PyObject *self, T *&into, Dtool_PyTypedObject &classdef); template<class T> INLINE bool DtoolInstance_GetPointer(PyObject *self, T *&into, Dtool_PyTypedObject &classdef);
INLINE Py_hash_t DtoolInstance_HashPointer(PyObject *self);
INLINE int DtoolInstance_ComparePointers(PyObject *v1, PyObject *v2);
INLINE PyObject *DtoolInstance_RichComparePointers(PyObject *v1, PyObject *v2, int op);
// Functions related to error reporting. // Functions related to error reporting.
EXPCL_INTERROGATEDB bool _Dtool_CheckErrorOccurred(); EXPCL_INTERROGATEDB bool _Dtool_CheckErrorOccurred();
@ -331,21 +333,8 @@ EXPCL_INTERROGATEDB PyObject *Dtool_BorrowThisReference(PyObject *self, PyObject
// some point.. // some point..
EXPCL_INTERROGATEDB PyObject *Dtool_AddToDictionary(PyObject *self1, PyObject *args); EXPCL_INTERROGATEDB PyObject *Dtool_AddToDictionary(PyObject *self1, PyObject *args);
#define DTOOL_PyObject_HashPointer DtoolInstance_HashPointer
EXPCL_INTERROGATEDB Py_hash_t DTOOL_PyObject_HashPointer(PyObject *obj); #define DTOOL_PyObject_ComparePointers DtoolInstance_ComparePointers
/* Compare v to w. Return
-1 if v < w or exception (PyErr_Occurred() true in latter case).
0 if v == w.
1 if v > w.
XXX The docs (C API manual) say the return value is undefined in case
XXX of error.
*/
EXPCL_INTERROGATEDB int DTOOL_PyObject_ComparePointers(PyObject *v1, PyObject *v2);
EXPCL_INTERROGATEDB int DTOOL_PyObject_Compare(PyObject *v1, PyObject *v2);
EXPCL_INTERROGATEDB PyObject *DTOOL_PyObject_RichCompare(PyObject *v1, PyObject *v2, int op);
EXPCL_INTERROGATEDB PyObject * EXPCL_INTERROGATEDB PyObject *
copy_from_make_copy(PyObject *self, PyObject *noargs); copy_from_make_copy(PyObject *self, PyObject *noargs);

View File

@ -192,6 +192,7 @@ extern "C" {
EXPCL_PYSTUB int _PyArg_Parse_SizeT(...); EXPCL_PYSTUB int _PyArg_Parse_SizeT(...);
EXPCL_PYSTUB int _PyErr_BadInternalCall(...); EXPCL_PYSTUB int _PyErr_BadInternalCall(...);
EXPCL_PYSTUB int _PyLong_AsByteArray(...); EXPCL_PYSTUB int _PyLong_AsByteArray(...);
EXPCL_PYSTUB int _PyLong_Sign(...);
EXPCL_PYSTUB int _PyObject_CallFunction_SizeT(...); EXPCL_PYSTUB int _PyObject_CallFunction_SizeT(...);
EXPCL_PYSTUB int _PyObject_CallMethod_SizeT(...); EXPCL_PYSTUB int _PyObject_CallMethod_SizeT(...);
EXPCL_PYSTUB int _PyObject_DebugFree(...); EXPCL_PYSTUB int _PyObject_DebugFree(...);
@ -421,6 +422,7 @@ int _PyArg_ParseTupleAndKeywords_SizeT(...) { return 0; };
int _PyArg_Parse_SizeT(...) { return 0; }; int _PyArg_Parse_SizeT(...) { return 0; };
int _PyErr_BadInternalCall(...) { return 0; }; int _PyErr_BadInternalCall(...) { return 0; };
int _PyLong_AsByteArray(...) { return 0; }; int _PyLong_AsByteArray(...) { return 0; };
int _PyLong_Sign(...) { return 0; };
int _PyObject_CallFunction_SizeT(...) { return 0; }; int _PyObject_CallFunction_SizeT(...) { return 0; };
int _PyObject_CallMethod_SizeT(...) { return 0; }; int _PyObject_CallMethod_SizeT(...) { return 0; };
int _PyObject_DebugFree(...) { return 0; }; int _PyObject_DebugFree(...) { return 0; };