[PATCH 4/4] Convert frapy_richcompare to safety API

Tom Tromey <[email protected]>
Newsgroups gmane.comp.gdb.patches
Message-ID <[email protected]>
This converts frapy_richcompare to the Python safety API.  A new
wrap_richcompare template function is added.  As 'richcompare' can
return three results (or throw), the wrapped method returns a
std::optional<bool>; this is documented by the wrapper.

I considered a specialization of wrap_richcompare that automatically
ensures that the compared-to value is of the same class as 'this' --
this would be useful in a few (but not all) spots in gdb.  However
this seemed like a refinement that could easily be added later.

This also removes a part of a comment that I think is incorrect.
---
 gdb/python/py-frame.c  | 24 +++++++++++-------------
 gdb/python/py-safety.h | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 13 deletions(-)

diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index 4dd174cf5ae..4aedd7db563 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -141,6 +141,9 @@ struct frame_object : public PyObject
   /* The static link for this frame.  */
   gdbpy_ref<> static_link ();
 
+  /* Implementation of the Python richcompare API.  */
+  std::optional<bool> richcompare (gdbpy_borrowed_ref<> other, int op);
+
   static PyTypeObject *corresponding_object_type;
 };
 
@@ -482,30 +485,25 @@ gdbpy_frame_stop_reason_string (gdbpy_borrowed_ref<> args,
   return unwind_stop_reason_to_string ((enum unwind_stop_reason) reason);
 }
 
-/* Implements the equality comparison for Frame objects.
-   All other comparison operators will throw a TypeError Python exception,
-   as they aren't valid for frames.  */
+/* Implements the equality comparison for Frame objects.  */
 
-static PyObject *
-frapy_richcompare (PyObject *self, PyObject *other, int op)
+std::optional<bool>
+frame_object::richcompare (gdbpy_borrowed_ref<> other, int op)
 {
   int result;
 
   if (!PyObject_TypeCheck (other, &frame_object_type)
       || (op != Py_EQ && op != Py_NE))
-    return py_notimplemented ().release ();
+    return std::nullopt;
 
-  frame_object *self_frame = (frame_object *) self;
-  frame_object *other_frame = (frame_object *) other;
+  frame_object *other_frame = other;
 
-  if (self_frame->frame_id == other_frame->frame_id)
+  if (frame_id == other_frame->frame_id)
     result = Py_EQ;
   else
     result = Py_NE;
 
-  if (op == result)
-    return py_true ().release ();
-  return py_false ().release ();
+  return op == result;
 }
 
 PyTypeObject *frame_object::corresponding_object_type = &frame_object_type;
@@ -623,7 +621,7 @@ PyTypeObject frame_object_type = {
   "GDB frame object",		  /* tp_doc */
   0,				  /* tp_traverse */
   0,				  /* tp_clear */
-  frapy_richcompare,		  /* tp_richcompare */
+  wrap_richcompare<frame_object, &frame_object::richcompare>, /* tp_richcompare */
   0,				  /* tp_weaklistoffset */
   0,				  /* tp_iter */
   0,				  /* tp_iternext */
diff --git a/gdb/python/py-safety.h b/gdb/python/py-safety.h
index 06324868817..e2cd8bc3f30 100644
--- a/gdb/python/py-safety.h
+++ b/gdb/python/py-safety.h
@@ -364,4 +364,36 @@ wrap_setter (PyObject *arg, PyObject *value, void *closure)
   return 0;
 }
 
+/* A function that wraps a richcompare method.
+
+   A Python tp_richcompare function can either raise an exception,
+   return True or False, or return "not implemented".  The wrapped
+   method must return a std::optional<bool>, which allows all these
+   results: exceptions are simply thrown, true and false are ordinary
+   returns, and the return of an empty optional means "not
+   implemented".  */
+template<typename C, std::optional<bool> (C::*M) (gdbpy_borrowed_ref<>, int)>
+PyObject *
+wrap_richcompare (PyObject *arg, PyObject *value, int op)
+{
+  using namespace safety_details;
+  try
+    {
+      C *self = static_cast<C *> (arg);
+      std::optional<bool> result = (self->*M) (value, op);
+      if (result.has_value ())
+	return to_python (*result);
+      return py_notimplemented ().release ();
+    }
+  catch (const gdb_python_exception &pye)
+    {
+      gdb_assert (PyErr_Occurred () != nullptr);
+      return nullptr;
+    }
+  catch (const gdb_exception &exc)
+    {
+      return gdbpy_handle_gdb_exception (nullptr, exc);
+    }
+}
+
 #endif /* GDB_PYTHON_PY_SAFETY_H */

-- 
2.49.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.