Convert SWIG typemap string operations to PythonObjects.

llvm-svn: 250530
This commit is contained in:
Zachary Turner 2015-10-16 17:51:49 +00:00
parent a6760f98cf
commit 7d6d218e12
4 changed files with 100 additions and 37 deletions

View File

@ -63,34 +63,38 @@
int i;
len = 0;
while ($1[len]) len++;
lldb_private::PythonList list(len);
using namespace lldb_private;
PythonList list(len);
for (i = 0; i < len; i++)
list.SetItemAtIndex(i, lldb_private::PythonString($1[i]));
list.SetItemAtIndex(i, PythonString($1[i]));
$result = list.release();
}
%typemap(in) char const ** {
/* Check if is a list */
if (PyList_Check($input)) {
int size = PyList_Size($input);
int i = 0;
using namespace lldb_private;
if (PythonList::Check($input)) {
PythonList py_list(PyRefType::Borrowed, $input);
int size = py_list.GetSize();
$1 = (char**)malloc((size+1)*sizeof(char*));
for (i = 0; i < size; i++) {
PyObject *o = PyList_GetItem($input,i);
if (PyString_Check(o))
$1[i] = PyString_AsString(o);
else {
for (int i = 0; i < size; i++) {
PythonObject o = py_list.GetItemAtIndex(i);
if (!PythonString::Check(o.get())) {
PyErr_SetString(PyExc_TypeError,"list must contain strings");
free($1);
return NULL;
return nullptr;
}
auto py_str = o.AsType<PythonString>();
$1[i] = const_cast<char*>(py_str.GetString().data());
}
$1[i] = 0;
$1[size] = 0;
} else if ($input == Py_None) {
$1 = NULL;
$1 = nullptr;
} else {
PyErr_SetString(PyExc_TypeError,"not a list");
return NULL;
return nullptr;
}
}
@ -501,12 +505,13 @@
}
%typemap(in) FILE * {
using namespace lldb_private;
if ($input == Py_None)
$1 = NULL;
$1 = nullptr;
else if (!lldb_private::PythonFile::Check($input)) {
int fd = PyObject_AsFileDescriptor($input);
lldb_private::PythonString py_mode(lldb_private::PyRefType::Owned,
PyObject_GetAttrString($input, "mode"));
PythonObject py_input(PyRefType::Borrowed, $input);
PythonString py_mode = py_input.GetAttributeValue("mode").AsType<PythonString>();
if (-1 != fd && py_mode.IsValid()) {
FILE *f;
@ -521,8 +526,8 @@
}
else
{
lldb_private::File file;
lldb_private::PythonFile py_file(lldb_private::PyRefType::Borrowed, $input);
PythonFile py_file(PyRefType::Borrowed, $input);
File file;
if (!py_file.GetUnderlyingFile(file))
return nullptr;
@ -543,26 +548,34 @@
else // if (flags & __SRW)
mode[i++] = 'a';
#endif
lldb_private::File file($1, false);
lldb_private::PythonFile py_file(file, mode);
using namespace lldb_private;
File file($1, false);
PythonFile py_file(file, mode);
$result = py_file.release();
}
%typemap(in) (const char* string, int len) {
using namespace lldb_private;
if ($input == Py_None)
{
$1 = NULL;
$2 = 0;
}
else if (PyUnicode_Check($input))
else if (PythonString::Check($input))
{
$1 = PyString_AsString(PyUnicode_AsUTF8String($input));
$2 = strlen($1);
}
else if (PyString_Check($input))
{
$1 = PyString_AsString($input);
$2 = PyString_Size($input);
PythonString py_str(PyRefType::Borrowed, $input);
llvm::StringRef str = py_str.GetString();
$1 = const_cast<char*>(str.data());
$2 = str.size();
// In Python 2, if $input is a PyUnicode object then this
// will trigger a Unicode -> String conversion, in which
// case the `PythonString` will now own the PyString. Thus
// if it goes out of scope, the data will be deleted. The
// only way to avoid this is to leak the Python object in
// that case. Note that if there was no conversion, then
// releasing the string will not leak anything, since we
// created this as a borrowed reference.
py_str.release();
}
else
{

View File

@ -111,6 +111,20 @@ PythonObject::HasAttribute(llvm::StringRef attr) const
return !!PyObject_HasAttr(m_py_obj, py_attr.get());
}
PythonObject
PythonObject::GetAttributeValue(llvm::StringRef attr) const
{
if (!IsValid())
return PythonObject();
PythonString py_attr(attr);
if (!PyObject_HasAttr(m_py_obj, py_attr.get()))
return PythonObject();
return PythonObject(PyRefType::Owned,
PyObject_GetAttr(m_py_obj, py_attr.get()));
}
bool
PythonObject::IsNone() const
{
@ -191,11 +205,13 @@ PythonString::Check(PyObject *py_obj)
if (!py_obj)
return false;
#if PY_MAJOR_VERSION >= 3
return PyUnicode_Check(py_obj);
#else
return PyString_Check(py_obj);
if (PyUnicode_Check(py_obj))
return true;
#if PY_MAJOR_VERSION < 3
if (PyString_Check(py_obj))
return true;
#endif
return false;
}
void
@ -210,7 +226,13 @@ PythonString::Reset(PyRefType type, PyObject *py_obj)
PythonObject::Reset();
return;
}
#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))
result.Reset(PyRefType::Owned, PyUnicode_AsUTF8String(result.get()));
#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());
@ -271,6 +293,12 @@ PythonString::CreateStructuredString() const
// PythonInteger
//----------------------------------------------------------------------
PythonInteger::PythonInteger()
: PythonObject()
{
}
PythonInteger::PythonInteger(PyRefType type, PyObject *py_obj)
: PythonObject()
{

View File

@ -201,6 +201,9 @@ public:
bool
HasAttribute(llvm::StringRef attribute) const;
PythonObject
GetAttributeValue(llvm::StringRef attribute) const;
bool
IsValid() const;
@ -210,6 +213,14 @@ public:
bool
IsNone() const;
template<typename T>
T AsType() const
{
if (!T::Check(m_py_obj))
return T();
return T(PyRefType::Borrowed, m_py_obj);
}
StructuredData::ObjectSP CreateStructuredObject() const;
protected:

View File

@ -382,3 +382,14 @@ TEST_F(PythonDataObjectsTest, TestPythonFile)
PythonFile py_file(file, "r");
EXPECT_TRUE(PythonFile::Check(py_file.get()));
}
TEST_F(PythonDataObjectsTest, TestObjectAttributes)
{
PythonInteger py_int(42);
EXPECT_TRUE(py_int.HasAttribute("numerator"));
EXPECT_FALSE(py_int.HasAttribute("this_should_not_exist"));
PythonInteger numerator_attr = py_int.GetAttributeValue("numerator").AsType<PythonInteger>();
EXPECT_TRUE(numerator_attr.IsAllocated());
EXPECT_EQ(42, numerator_attr.GetInteger());
}