[Lldb-commits] [lldb] r374916 - eliminate virtual methods from PythonDataObjects

Lawrence D'Anna via lldb-commits lldb-commits at lists.llvm.org
Tue Oct 15 10:12:49 PDT 2019


Author: lawrence_danna
Date: Tue Oct 15 10:12:49 2019
New Revision: 374916

URL: http://llvm.org/viewvc/llvm-project?rev=374916&view=rev
Log:
eliminate virtual methods from PythonDataObjects

Summary:
This patch eliminates a bunch of boilerplate from
PythonDataObjects, as well as the use of virtual methods.
In my opinion it also makes the Reset logic a lot more
clear and easy to follow.   The price is yet another
template.   I think it's worth it.

Reviewers: JDevlieghere, jasonmolenda, labath, zturner

Reviewed By: JDevlieghere, labath

Subscribers: lldb-commits

Tags: #lldb

Differential Revision: https://reviews.llvm.org/D68918

Modified:
    lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
    lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h

Modified: lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp?rev=374916&r1=374915&r2=374916&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp (original)
+++ lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp Tue Oct 15 10:12:49 2019
@@ -213,43 +213,19 @@ StructuredData::ObjectSP PythonObject::C
 }
 
 // PythonString
-PythonBytes::PythonBytes() : PythonObject() {}
 
-PythonBytes::PythonBytes(llvm::ArrayRef<uint8_t> bytes) : PythonObject() {
-  SetBytes(bytes);
-}
+PythonBytes::PythonBytes(llvm::ArrayRef<uint8_t> bytes) { SetBytes(bytes); }
 
-PythonBytes::PythonBytes(const uint8_t *bytes, size_t length) : PythonObject() {
+PythonBytes::PythonBytes(const uint8_t *bytes, size_t length) {
   SetBytes(llvm::ArrayRef<uint8_t>(bytes, length));
 }
 
-PythonBytes::PythonBytes(PyRefType type, PyObject *py_obj) : PythonObject() {
-  Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a string
-}
-
-PythonBytes::~PythonBytes() {}
-
 bool PythonBytes::Check(PyObject *py_obj) {
   if (!py_obj)
     return false;
   return PyBytes_Check(py_obj);
 }
 
-void PythonBytes::Reset(PyRefType type, PyObject *py_obj) {
-  // Grab the desired reference type so that if we end up rejecting `py_obj` it
-  // still gets decremented if necessary.
-  PythonObject result(type, py_obj);
-
-  if (!PythonBytes::Check(py_obj)) {
-    PythonObject::Reset();
-    return;
-  }
-
-  // Calling PythonObject::Reset(const PythonObject&) will lead to stack
-  // overflow since it calls back into the virtual implementation.
-  PythonObject::Reset(PyRefType::Borrowed, result.get());
-}
-
 llvm::ArrayRef<uint8_t> PythonBytes::GetBytes() const {
   if (!IsValid())
     return llvm::ArrayRef<uint8_t>();
@@ -290,36 +266,12 @@ PythonByteArray::PythonByteArray(const u
   Reset(PyRefType::Owned, PyByteArray_FromStringAndSize(str, length));
 }
 
-PythonByteArray::PythonByteArray(PyRefType type, PyObject *o) {
-  Reset(type, o);
-}
-
-PythonByteArray::PythonByteArray(const PythonBytes &object)
-    : PythonObject(object) {}
-
-PythonByteArray::~PythonByteArray() {}
-
 bool PythonByteArray::Check(PyObject *py_obj) {
   if (!py_obj)
     return false;
   return PyByteArray_Check(py_obj);
 }
 
-void PythonByteArray::Reset(PyRefType type, PyObject *py_obj) {
-  // Grab the desired reference type so that if we end up rejecting `py_obj` it
-  // still gets decremented if necessary.
-  PythonObject result(type, py_obj);
-
-  if (!PythonByteArray::Check(py_obj)) {
-    PythonObject::Reset();
-    return;
-  }
-
-  // Calling PythonObject::Reset(const PythonObject&) will lead to stack
-  // overflow since it calls back into the virtual implementation.
-  PythonObject::Reset(PyRefType::Borrowed, result.get());
-}
-
 llvm::ArrayRef<uint8_t> PythonByteArray::GetBytes() const {
   if (!IsValid())
     return llvm::ArrayRef<uint8_t>();
@@ -357,17 +309,7 @@ Expected<PythonString> PythonString::Fro
   return Take<PythonString>(str);
 }
 
-PythonString::PythonString(PyRefType type, PyObject *py_obj) : PythonObject() {
-  Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a string
-}
-
-PythonString::PythonString(llvm::StringRef string) : PythonObject() {
-  SetString(string);
-}
-
-PythonString::PythonString() : PythonObject() {}
-
-PythonString::~PythonString() {}
+PythonString::PythonString(llvm::StringRef string) { SetString(string); }
 
 bool PythonString::Check(PyObject *py_obj) {
   if (!py_obj)
@@ -382,29 +324,26 @@ bool PythonString::Check(PyObject *py_ob
   return false;
 }
 
-void PythonString::Reset(PyRefType type, PyObject *py_obj) {
-  // Grab the desired reference type so that if we end up rejecting `py_obj` it
-  // still gets decremented if necessary.
-  PythonObject result(type, py_obj);
-
-  if (!PythonString::Check(py_obj)) {
-    PythonObject::Reset();
-    return;
-  }
+void PythonString::Convert(PyRefType &type, PyObject *&py_obj) {
 #if PY_MAJOR_VERSION < 3
   // In Python 2, Don't store PyUnicode objects directly, because we need
   // access to their underlying character buffers which Python 2 doesn't
   // provide.
   if (PyUnicode_Check(py_obj)) {
-    PyObject *s = PyUnicode_AsUTF8String(result.get());
-    if (s == NULL)
+    PyObject *s = PyUnicode_AsUTF8String(py_obj);
+    if (s == nullptr) {
       PyErr_Clear();
-    result.Reset(PyRefType::Owned, s);
+      if (type == PyRefType::Owned)
+        Py_DECREF(py_obj);
+      return;
+    }
+    if (type == PyRefType::Owned)
+      Py_DECREF(py_obj);
+    else
+      type = PyRefType::Owned;
+    py_obj = s;
   }
 #endif
-  // Calling PythonObject::Reset(const PythonObject&) will lead to stack
-  // overflow since it calls back into the virtual implementation.
-  PythonObject::Reset(PyRefType::Borrowed, result.get());
 }
 
 llvm::StringRef PythonString::GetString() const {
@@ -468,18 +407,7 @@ StructuredData::StringSP PythonString::C
 
 // PythonInteger
 
-PythonInteger::PythonInteger() : PythonObject() {}
-
-PythonInteger::PythonInteger(PyRefType type, PyObject *py_obj)
-    : PythonObject() {
-  Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a integer type
-}
-
-PythonInteger::PythonInteger(int64_t value) : PythonObject() {
-  SetInteger(value);
-}
-
-PythonInteger::~PythonInteger() {}
+PythonInteger::PythonInteger(int64_t value) { SetInteger(value); }
 
 bool PythonInteger::Check(PyObject *py_obj) {
   if (!py_obj)
@@ -494,16 +422,7 @@ bool PythonInteger::Check(PyObject *py_o
 #endif
 }
 
-void PythonInteger::Reset(PyRefType type, PyObject *py_obj) {
-  // Grab the desired reference type so that if we end up rejecting `py_obj` it
-  // still gets decremented if necessary.
-  PythonObject result(type, py_obj);
-
-  if (!PythonInteger::Check(py_obj)) {
-    PythonObject::Reset();
-    return;
-  }
-
+void PythonInteger::Convert(PyRefType &type, PyObject *&py_obj) {
 #if PY_MAJOR_VERSION < 3
   // Always store this as a PyLong, which makes interoperability between Python
   // 2.x and Python 3.x easier.  This is only necessary in 2.x, since 3.x
@@ -512,16 +431,23 @@ void PythonInteger::Reset(PyRefType type
     // Since we converted the original object to a different type, the new
     // object is an owned object regardless of the ownership semantics
     // requested by the user.
-    result.Reset(PyRefType::Owned, PyLong_FromLongLong(PyInt_AsLong(py_obj)));
+    long long value = PyInt_AsLong(py_obj);
+    PyObject *l = nullptr;
+    if (!PyErr_Occurred())
+      l = PyLong_FromLongLong(value);
+    if (l == nullptr) {
+      PyErr_Clear();
+      if (type == PyRefType::Owned)
+        Py_DECREF(py_obj);
+      return;
+    }
+    if (type == PyRefType::Owned)
+      Py_DECREF(py_obj);
+    else
+      type = PyRefType::Owned;
+    py_obj = l;
   }
 #endif
-
-  assert(PyLong_Check(result.get()) &&
-         "Couldn't get a PyLong from this PyObject");
-
-  // Calling PythonObject::Reset(const PythonObject&) will lead to stack
-  // overflow since it calls back into the virtual implementation.
-  PythonObject::Reset(PyRefType::Borrowed, result.get());
 }
 
 int64_t PythonInteger::GetInteger() const {
@@ -555,11 +481,6 @@ StructuredData::IntegerSP PythonInteger:
 
 // PythonBoolean
 
-PythonBoolean::PythonBoolean(PyRefType type, PyObject *py_obj)
-    : PythonObject() {
-  Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a boolean type
-}
-
 PythonBoolean::PythonBoolean(bool value) {
   SetValue(value);
 }
@@ -568,21 +489,6 @@ bool PythonBoolean::Check(PyObject *py_o
   return py_obj ? PyBool_Check(py_obj) : false;
 }
 
-void PythonBoolean::Reset(PyRefType type, PyObject *py_obj) {
-  // Grab the desired reference type so that if we end up rejecting `py_obj` it
-  // still gets decremented if necessary.
-  PythonObject result(type, py_obj);
-
-  if (!PythonBoolean::Check(py_obj)) {
-    PythonObject::Reset();
-    return;
-  }
-
-  // Calling PythonObject::Reset(const PythonObject&) will lead to stack
-  // overflow since it calls back into the virtual implementation.
-  PythonObject::Reset(PyRefType::Borrowed, result.get());
-}
-
 bool PythonBoolean::GetValue() const {
   return m_py_obj ? PyObject_IsTrue(m_py_obj) : false;
 }
@@ -599,42 +505,21 @@ StructuredData::BooleanSP PythonBoolean:
 
 // PythonList
 
-PythonList::PythonList(PyInitialValue value) : PythonObject() {
+PythonList::PythonList(PyInitialValue value) {
   if (value == PyInitialValue::Empty)
     Reset(PyRefType::Owned, PyList_New(0));
 }
 
-PythonList::PythonList(int list_size) : PythonObject() {
+PythonList::PythonList(int list_size) {
   Reset(PyRefType::Owned, PyList_New(list_size));
 }
 
-PythonList::PythonList(PyRefType type, PyObject *py_obj) : PythonObject() {
-  Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a list
-}
-
-PythonList::~PythonList() {}
-
 bool PythonList::Check(PyObject *py_obj) {
   if (!py_obj)
     return false;
   return PyList_Check(py_obj);
 }
 
-void PythonList::Reset(PyRefType type, PyObject *py_obj) {
-  // Grab the desired reference type so that if we end up rejecting `py_obj` it
-  // still gets decremented if necessary.
-  PythonObject result(type, py_obj);
-
-  if (!PythonList::Check(py_obj)) {
-    PythonObject::Reset();
-    return;
-  }
-
-  // Calling PythonObject::Reset(const PythonObject&) will lead to stack
-  // overflow since it calls back into the virtual implementation.
-  PythonObject::Reset(PyRefType::Borrowed, result.get());
-}
-
 uint32_t PythonList::GetSize() const {
   if (IsValid())
     return PyList_GET_SIZE(m_py_obj);
@@ -676,19 +561,15 @@ StructuredData::ArraySP PythonList::Crea
 
 // PythonTuple
 
-PythonTuple::PythonTuple(PyInitialValue value) : PythonObject() {
+PythonTuple::PythonTuple(PyInitialValue value) {
   if (value == PyInitialValue::Empty)
     Reset(PyRefType::Owned, PyTuple_New(0));
 }
 
-PythonTuple::PythonTuple(int tuple_size) : PythonObject() {
+PythonTuple::PythonTuple(int tuple_size) {
   Reset(PyRefType::Owned, PyTuple_New(tuple_size));
 }
 
-PythonTuple::PythonTuple(PyRefType type, PyObject *py_obj) : PythonObject() {
-  Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a tuple
-}
-
 PythonTuple::PythonTuple(std::initializer_list<PythonObject> objects) {
   m_py_obj = PyTuple_New(objects.size());
 
@@ -712,29 +593,12 @@ PythonTuple::PythonTuple(std::initialize
   }
 }
 
-PythonTuple::~PythonTuple() {}
-
 bool PythonTuple::Check(PyObject *py_obj) {
   if (!py_obj)
     return false;
   return PyTuple_Check(py_obj);
 }
 
-void PythonTuple::Reset(PyRefType type, PyObject *py_obj) {
-  // Grab the desired reference type so that if we end up rejecting `py_obj` it
-  // still gets decremented if necessary.
-  PythonObject result(type, py_obj);
-
-  if (!PythonTuple::Check(py_obj)) {
-    PythonObject::Reset();
-    return;
-  }
-
-  // Calling PythonObject::Reset(const PythonObject&) will lead to stack
-  // overflow since it calls back into the virtual implementation.
-  PythonObject::Reset(PyRefType::Borrowed, result.get());
-}
-
 uint32_t PythonTuple::GetSize() const {
   if (IsValid())
     return PyTuple_GET_SIZE(m_py_obj);
@@ -768,18 +632,11 @@ StructuredData::ArraySP PythonTuple::Cre
 
 // PythonDictionary
 
-PythonDictionary::PythonDictionary(PyInitialValue value) : PythonObject() {
+PythonDictionary::PythonDictionary(PyInitialValue value) {
   if (value == PyInitialValue::Empty)
     Reset(PyRefType::Owned, PyDict_New());
 }
 
-PythonDictionary::PythonDictionary(PyRefType type, PyObject *py_obj)
-    : PythonObject() {
-  Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a dictionary
-}
-
-PythonDictionary::~PythonDictionary() {}
-
 bool PythonDictionary::Check(PyObject *py_obj) {
   if (!py_obj)
     return false;
@@ -787,21 +644,6 @@ bool PythonDictionary::Check(PyObject *p
   return PyDict_Check(py_obj);
 }
 
-void PythonDictionary::Reset(PyRefType type, PyObject *py_obj) {
-  // Grab the desired reference type so that if we end up rejecting `py_obj` it
-  // still gets decremented if necessary.
-  PythonObject result(type, py_obj);
-
-  if (!PythonDictionary::Check(py_obj)) {
-    PythonObject::Reset();
-    return;
-  }
-
-  // Calling PythonObject::Reset(const PythonObject&) will lead to stack
-  // overflow since it calls back into the virtual implementation.
-  PythonObject::Reset(PyRefType::Borrowed, result.get());
-}
-
 uint32_t PythonDictionary::GetSize() const {
   if (IsValid())
     return PyDict_Size(m_py_obj);
@@ -841,14 +683,6 @@ PythonDictionary::CreateStructuredDictio
   return result;
 }
 
-PythonModule::PythonModule() : PythonObject() {}
-
-PythonModule::PythonModule(PyRefType type, PyObject *py_obj) {
-  Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a module
-}
-
-PythonModule::~PythonModule() {}
-
 PythonModule PythonModule::BuiltinsModule() {
 #if PY_MAJOR_VERSION >= 3
   return AddModule("builtins");
@@ -890,33 +724,10 @@ bool PythonModule::Check(PyObject *py_ob
   return PyModule_Check(py_obj);
 }
 
-void PythonModule::Reset(PyRefType type, PyObject *py_obj) {
-  // Grab the desired reference type so that if we end up rejecting `py_obj` it
-  // still gets decremented if necessary.
-  PythonObject result(type, py_obj);
-
-  if (!PythonModule::Check(py_obj)) {
-    PythonObject::Reset();
-    return;
-  }
-
-  // Calling PythonObject::Reset(const PythonObject&) will lead to stack
-  // overflow since it calls back into the virtual implementation.
-  PythonObject::Reset(PyRefType::Borrowed, result.get());
-}
-
 PythonDictionary PythonModule::GetDictionary() const {
   return PythonDictionary(PyRefType::Borrowed, PyModule_GetDict(m_py_obj));
 }
 
-PythonCallable::PythonCallable() : PythonObject() {}
-
-PythonCallable::PythonCallable(PyRefType type, PyObject *py_obj) {
-  Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a callable
-}
-
-PythonCallable::~PythonCallable() {}
-
 bool PythonCallable::Check(PyObject *py_obj) {
   if (!py_obj)
     return false;
@@ -924,21 +735,6 @@ bool PythonCallable::Check(PyObject *py_
   return PyCallable_Check(py_obj);
 }
 
-void PythonCallable::Reset(PyRefType type, PyObject *py_obj) {
-  // Grab the desired reference type so that if we end up rejecting `py_obj` it
-  // still gets decremented if necessary.
-  PythonObject result(type, py_obj);
-
-  if (!PythonCallable::Check(py_obj)) {
-    PythonObject::Reset();
-    return;
-  }
-
-  // Calling PythonObject::Reset(const PythonObject&) will lead to stack
-  // overflow since it calls back into the virtual implementation.
-  PythonObject::Reset(PyRefType::Borrowed, result.get());
-}
-
 PythonCallable::ArgInfo PythonCallable::GetNumInitArguments() const {
   ArgInfo result = {0, false, false, false};
   if (!IsValid())
@@ -1011,12 +807,6 @@ operator()(std::initializer_list<PythonO
                       PyObject_CallObject(m_py_obj, arg_tuple.get()));
 }
 
-PythonFile::PythonFile() : PythonObject() {}
-
-PythonFile::PythonFile(PyRefType type, PyObject *o) { Reset(type, o); }
-
-PythonFile::~PythonFile() {}
-
 bool PythonFile::Check(PyObject *py_obj) {
   if (!py_obj)
     return false;
@@ -1047,21 +837,6 @@ bool PythonFile::Check(PyObject *py_obj)
 #endif
 }
 
-void PythonFile::Reset(PyRefType type, PyObject *py_obj) {
-  // Grab the desired reference type so that if we end up rejecting `py_obj` it
-  // still gets decremented if necessary.
-  PythonObject result(type, py_obj);
-
-  if (!PythonFile::Check(py_obj)) {
-    PythonObject::Reset();
-    return;
-  }
-
-  // Calling PythonObject::Reset(const PythonObject&) will lead to stack
-  // overflow since it calls back into the virtual implementation.
-  PythonObject::Reset(PyRefType::Borrowed, result.get());
-}
-
 FileUP PythonFile::GetUnderlyingFile() const {
   if (!IsValid())
     return nullptr;

Modified: lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h?rev=374916&r1=374915&r2=374916&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h (original)
+++ lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h Tue Oct 15 10:12:49 2019
@@ -25,6 +25,25 @@
 // Expected<> is considered deprecated and should not be
 // used in new code.  If you need to use it, fix it first.
 //
+//
+// TODOs for this file
+//
+// * Make all methods safe for exceptions.
+//
+// * Eliminate method signatures that must translate exceptions into
+//   empty objects or NULLs.   Almost everything here should return
+//   Expected<>.   It should be acceptable for certain operations that
+//   can never fail to assert instead, such as the creation of
+//   PythonString from a string literal.
+//
+// * Elimintate Reset(), and make all non-default constructors private.
+//   Python objects should be created with Retain<> or Take<>, and they
+//   should be assigned with operator=
+//
+// * Eliminate default constructors, make python objects always
+//   nonnull, and use optionals where necessary.
+//
+
 
 #ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONDATAOBJECTS_H
 #define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONDATAOBJECTS_H
@@ -170,20 +189,15 @@ public:
     rhs.m_py_obj = nullptr;
   }
 
-  virtual ~PythonObject() { Reset(); }
+  ~PythonObject() { Reset(); }
 
   void Reset() {
-    // Avoid calling the virtual method since it's not necessary
-    // to actually validate the type of the PyObject if we're
-    // just setting to null.
     if (m_py_obj && Py_IsInitialized())
       Py_DECREF(m_py_obj);
     m_py_obj = nullptr;
   }
 
   void Reset(const PythonObject &rhs) {
-    // Avoid calling the virtual method if it's not necessary
-    // to actually validate the type of the PyObject.
     if (!rhs.IsValid())
       Reset();
     else
@@ -196,9 +210,7 @@ public:
   // PyRefType doesn't make sense, and the copy constructor should be used.
   void Reset(PyRefType type, const PythonObject &ref) = delete;
 
-  // FIXME We shouldn't have virtual anything.  PythonObject should be a
-  // strictly pass-by-value type.
-  virtual void Reset(PyRefType type, PyObject *py_obj) {
+  void Reset(PyRefType type, PyObject *py_obj) {
     if (py_obj == m_py_obj)
       return;
 
@@ -376,21 +388,37 @@ llvm::Expected<long long> As<long long>(
 
 } // namespace python
 
-class PythonBytes : public PythonObject {
+template <class T> class TypedPythonObject : public PythonObject {
 public:
-  PythonBytes();
-  explicit PythonBytes(llvm::ArrayRef<uint8_t> bytes);
-  PythonBytes(const uint8_t *bytes, size_t length);
-  PythonBytes(PyRefType type, PyObject *o);
+  // override to perform implicit type conversions on Reset
+  // This can be eliminated once we drop python 2 support.
+  static void Convert(PyRefType &type, PyObject *&py_obj) {}
 
-  ~PythonBytes() override;
+  using PythonObject::Reset;
 
-  static bool Check(PyObject *py_obj);
+  void Reset(PyRefType type, PyObject *py_obj) {
+    Reset();
+    if (!py_obj)
+      return;
+    T::Convert(type, py_obj);
+    if (T::Check(py_obj))
+      PythonObject::Reset(type, py_obj);
+    else if (type == PyRefType::Owned)
+      Py_DECREF(py_obj);
+  }
 
-  // Bring in the no-argument base class version
-  using PythonObject::Reset;
+  TypedPythonObject(PyRefType type, PyObject *py_obj) { Reset(type, py_obj); }
+
+  TypedPythonObject() {}
+};
+
+class PythonBytes : public TypedPythonObject<PythonBytes> {
+public:
+  using TypedPythonObject::TypedPythonObject;
+  explicit PythonBytes(llvm::ArrayRef<uint8_t> bytes);
+  PythonBytes(const uint8_t *bytes, size_t length);
 
-  void Reset(PyRefType type, PyObject *py_obj) override;
+  static bool Check(PyObject *py_obj);
 
   llvm::ArrayRef<uint8_t> GetBytes() const;
 
@@ -401,23 +429,15 @@ public:
   StructuredData::StringSP CreateStructuredString() const;
 };
 
-class PythonByteArray : public PythonObject {
+class PythonByteArray : public TypedPythonObject<PythonByteArray> {
 public:
-  PythonByteArray();
+  using TypedPythonObject::TypedPythonObject;
   explicit PythonByteArray(llvm::ArrayRef<uint8_t> bytes);
   PythonByteArray(const uint8_t *bytes, size_t length);
-  PythonByteArray(PyRefType type, PyObject *o);
   PythonByteArray(const PythonBytes &object);
 
-  ~PythonByteArray() override;
-
   static bool Check(PyObject *py_obj);
 
-  // Bring in the no-argument base class version
-  using PythonObject::Reset;
-
-  void Reset(PyRefType type, PyObject *py_obj) override;
-
   llvm::ArrayRef<uint8_t> GetBytes() const;
 
   size_t GetSize() const;
@@ -427,22 +447,17 @@ public:
   StructuredData::StringSP CreateStructuredString() const;
 };
 
-class PythonString : public PythonObject {
+class PythonString : public TypedPythonObject<PythonString> {
 public:
+  using TypedPythonObject::TypedPythonObject;
   static llvm::Expected<PythonString> FromUTF8(llvm::StringRef string);
 
-  PythonString();
-  explicit PythonString(llvm::StringRef string); // safe, null on error
-  PythonString(PyRefType type, PyObject *o);
+  PythonString() : TypedPythonObject() {} // MSVC requires this for some reason
 
-  ~PythonString() override;
+  explicit PythonString(llvm::StringRef string); // safe, null on error
 
   static bool Check(PyObject *py_obj);
-
-  // Bring in the no-argument base class version
-  using PythonObject::Reset;
-
-  void Reset(PyRefType type, PyObject *py_obj) override;
+  static void Convert(PyRefType &type, PyObject *&py_obj);
 
   llvm::StringRef GetString() const; // safe, empty string on error
 
@@ -455,20 +470,16 @@ public:
   StructuredData::StringSP CreateStructuredString() const;
 };
 
-class PythonInteger : public PythonObject {
+class PythonInteger : public TypedPythonObject<PythonInteger> {
 public:
-  PythonInteger();
-  explicit PythonInteger(int64_t value);
-  PythonInteger(PyRefType type, PyObject *o);
+  using TypedPythonObject::TypedPythonObject;
 
-  ~PythonInteger() override;
+  PythonInteger() : TypedPythonObject() {} // MSVC requires this for some reason
 
-  static bool Check(PyObject *py_obj);
-
-  // Bring in the no-argument base class version
-  using PythonObject::Reset;
+  explicit PythonInteger(int64_t value);
 
-  void Reset(PyRefType type, PyObject *py_obj) override;
+  static bool Check(PyObject *py_obj);
+  static void Convert(PyRefType &type, PyObject *&py_obj);
 
   int64_t GetInteger() const;
 
@@ -477,21 +488,14 @@ public:
   StructuredData::IntegerSP CreateStructuredInteger() const;
 };
 
-class PythonBoolean : public PythonObject {
+class PythonBoolean : public TypedPythonObject<PythonBoolean> {
 public:
-  PythonBoolean() = default;
-  explicit PythonBoolean(bool value);
-  PythonBoolean(PyRefType type, PyObject *o);
+  using TypedPythonObject::TypedPythonObject;
 
-  ~PythonBoolean() override = default;
+  explicit PythonBoolean(bool value);
 
   static bool Check(PyObject *py_obj);
 
-  // Bring in the no-argument base class version
-  using PythonObject::Reset;
-
-  void Reset(PyRefType type, PyObject *py_obj) override;
-
   bool GetValue() const;
 
   void SetValue(bool value);
@@ -499,22 +503,17 @@ public:
   StructuredData::BooleanSP CreateStructuredBoolean() const;
 };
 
-class PythonList : public PythonObject {
+class PythonList : public TypedPythonObject<PythonList> {
 public:
-  PythonList() {}
+  using TypedPythonObject::TypedPythonObject;
+
+  PythonList() : TypedPythonObject() {} // MSVC requires this for some reason
+
   explicit PythonList(PyInitialValue value);
   explicit PythonList(int list_size);
-  PythonList(PyRefType type, PyObject *o);
-
-  ~PythonList() override;
 
   static bool Check(PyObject *py_obj);
 
-  // Bring in the no-argument base class version
-  using PythonObject::Reset;
-
-  void Reset(PyRefType type, PyObject *py_obj) override;
-
   uint32_t GetSize() const;
 
   PythonObject GetItemAtIndex(uint32_t index) const;
@@ -526,24 +525,17 @@ public:
   StructuredData::ArraySP CreateStructuredArray() const;
 };
 
-class PythonTuple : public PythonObject {
+class PythonTuple : public TypedPythonObject<PythonTuple> {
 public:
-  PythonTuple() {}
+  using TypedPythonObject::TypedPythonObject;
+
   explicit PythonTuple(PyInitialValue value);
   explicit PythonTuple(int tuple_size);
-  PythonTuple(PyRefType type, PyObject *o);
   PythonTuple(std::initializer_list<PythonObject> objects);
   PythonTuple(std::initializer_list<PyObject *> objects);
 
-  ~PythonTuple() override;
-
   static bool Check(PyObject *py_obj);
 
-  // Bring in the no-argument base class version
-  using PythonObject::Reset;
-
-  void Reset(PyRefType type, PyObject *py_obj) override;
-
   uint32_t GetSize() const;
 
   PythonObject GetItemAtIndex(uint32_t index) const;
@@ -553,20 +545,15 @@ public:
   StructuredData::ArraySP CreateStructuredArray() const;
 };
 
-class PythonDictionary : public PythonObject {
+class PythonDictionary : public TypedPythonObject<PythonDictionary> {
 public:
-  PythonDictionary() {}
-  explicit PythonDictionary(PyInitialValue value);
-  PythonDictionary(PyRefType type, PyObject *o);
+  using TypedPythonObject::TypedPythonObject;
 
-  ~PythonDictionary() override;
+  PythonDictionary() : TypedPythonObject() {} // MSVC requires this for some reason
 
-  static bool Check(PyObject *py_obj);
-
-  // Bring in the no-argument base class version
-  using PythonObject::Reset;
+  explicit PythonDictionary(PyInitialValue value);
 
-  void Reset(PyRefType type, PyObject *py_obj) override;
+  static bool Check(PyObject *py_obj);
 
   uint32_t GetSize() const;
 
@@ -578,12 +565,9 @@ public:
   StructuredData::DictionarySP CreateStructuredDictionary() const;
 };
 
-class PythonModule : public PythonObject {
+class PythonModule : public TypedPythonObject<PythonModule> {
 public:
-  PythonModule();
-  PythonModule(PyRefType type, PyObject *o);
-
-  ~PythonModule() override;
+  using TypedPythonObject::TypedPythonObject;
 
   static bool Check(PyObject *py_obj);
 
@@ -608,16 +592,13 @@ public:
 
   llvm::Expected<PythonObject> Get(const char *name);
 
-  // Bring in the no-argument base class version
-  using PythonObject::Reset;
-
-  void Reset(PyRefType type, PyObject *py_obj) override;
-
   PythonDictionary GetDictionary() const;
 };
 
-class PythonCallable : public PythonObject {
+class PythonCallable : public TypedPythonObject<PythonCallable> {
 public:
+  using TypedPythonObject::TypedPythonObject;
+
   struct ArgInfo {
     size_t count;
     bool is_bound_method : 1;
@@ -625,18 +606,8 @@ public:
     bool has_kwargs : 1;
   };
 
-  PythonCallable();
-  PythonCallable(PyRefType type, PyObject *o);
-
-  ~PythonCallable() override;
-
   static bool Check(PyObject *py_obj);
 
-  // Bring in the no-argument base class version
-  using PythonObject::Reset;
-
-  void Reset(PyRefType type, PyObject *py_obj) override;
-
   ArgInfo GetNumArguments() const;
 
   // If the callable is a Py_Class, then find the number of arguments
@@ -655,19 +626,14 @@ public:
   }
 };
 
-class PythonFile : public PythonObject {
+class PythonFile : public TypedPythonObject<PythonFile> {
 public:
-  PythonFile();
-  PythonFile(PyRefType type, PyObject *o);
+  using TypedPythonObject::TypedPythonObject;
 
-  ~PythonFile() override;
+  PythonFile() : TypedPythonObject() {} // MSVC requires this for some reason
 
   static bool Check(PyObject *py_obj);
 
-  using PythonObject::Reset;
-
-  void Reset(PyRefType type, PyObject *py_obj) override;
-
   static llvm::Expected<PythonFile> FromFile(File &file,
                                              const char *mode = nullptr);
 




More information about the lldb-commits mailing list