Browse Source

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.
rdb 7 năm trước cách đây
mục cha
commit
3cc88cd304

+ 25 - 17
dtool/src/interrogate/interfaceMakerPythonNative.cxx

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

+ 3 - 3
dtool/src/interrogatedb/dtool_super_base.cxx

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

+ 0 - 2
dtool/src/interrogatedb/py_compat.cxx

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

+ 37 - 4
dtool/src/interrogatedb/py_compat.h

@@ -138,11 +138,29 @@ typedef long Py_hash_t;
 
 /* Python 3.6 */
 
-// Used to implement _PyObject_CallNoArg
-extern EXPCL_INTERROGATEDB PyTupleObject Dtool_EmptyTuple;
-
 #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
 
 // 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)
 #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 */
 
 // _PyErr_OCCURRED is an undocumented macro version of PyErr_Occurred.

+ 31 - 0
dtool/src/interrogatedb/py_panda.I

@@ -62,6 +62,37 @@ DtoolInstance_GetPointer(PyObject *self, T *&into, Dtool_PyTypedObject &target_c
   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().
  */

+ 1 - 141
dtool/src/interrogatedb/py_panda.cxx

@@ -143,13 +143,6 @@ DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef,
   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
  * 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)");
     }
 
-#ifdef Py_TRACE_REFS
-    _Py_AddToAllObjects((PyObject *)&Dtool_EmptyTuple, 0);
-#endif
-
     // Initialize the base class of everything.
     Dtool_PyModuleClassInit_DTOOL_SUPER_BASE(nullptr);
   }
@@ -734,127 +723,6 @@ PyObject *Dtool_AddToDictionary(PyObject *self1, PyObject *args) {
   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++
  * 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 *callable = (PyObject *)Py_TYPE(self);
-
-#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;
+  return _PyObject_FastCall(callable, &self, 1);
 }
 
 /**

+ 6 - 17
dtool/src/interrogatedb/py_panda.h

@@ -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_GetPointerThis(PyObject *self);
-
 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,
@@ -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, 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.
 EXPCL_INTERROGATEDB bool _Dtool_CheckErrorOccurred();
 
@@ -331,21 +333,8 @@ EXPCL_INTERROGATEDB PyObject *Dtool_BorrowThisReference(PyObject *self, PyObject
 // some point..
 EXPCL_INTERROGATEDB PyObject *Dtool_AddToDictionary(PyObject *self1, PyObject *args);
 
-
-EXPCL_INTERROGATEDB Py_hash_t DTOOL_PyObject_HashPointer(PyObject *obj);
-
-/* 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);
+#define DTOOL_PyObject_HashPointer DtoolInstance_HashPointer
+#define DTOOL_PyObject_ComparePointers DtoolInstance_ComparePointers
 
 EXPCL_INTERROGATEDB PyObject *
 copy_from_make_copy(PyObject *self, PyObject *noargs);

+ 2 - 0
dtool/src/pystub/pystub.cxx

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