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

llvm-svn: 374916
This commit is contained in:
Lawrence D'Anna
2019-10-15 17:12:49 +00:00
parent e409f12131
commit d3bd5b3d71
2 changed files with 121 additions and 380 deletions

View File

@@ -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,22 +388,38 @@ llvm::Expected<long long> As<long long>(llvm::Expected<PythonObject> &&obj);
} // namespace python
class PythonBytes : public PythonObject {
template <class T> class TypedPythonObject : public PythonObject {
public:
PythonBytes();
// 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) {}
using PythonObject::Reset;
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);
}
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);
PythonBytes(PyRefType type, PyObject *o);
~PythonBytes() 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;
@@ -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
explicit PythonInteger(int64_t 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;
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,21 +545,16 @@ 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
explicit PythonDictionary(PyInitialValue 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;
uint32_t GetSize() const;
PythonList GetKeys() 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);