12c1f46dcSZachary Turner //===-- PythonDataObjects.cpp ------------------------------------*- C++ -*-===// 22c1f46dcSZachary Turner // 32c1f46dcSZachary Turner // The LLVM Compiler Infrastructure 42c1f46dcSZachary Turner // 52c1f46dcSZachary Turner // This file is distributed under the University of Illinois Open Source 62c1f46dcSZachary Turner // License. See LICENSE.TXT for details. 72c1f46dcSZachary Turner // 82c1f46dcSZachary Turner //===----------------------------------------------------------------------===// 92c1f46dcSZachary Turner 102c1f46dcSZachary Turner #ifdef LLDB_DISABLE_PYTHON 112c1f46dcSZachary Turner 122c1f46dcSZachary Turner // Python is disabled in this build 132c1f46dcSZachary Turner 142c1f46dcSZachary Turner #else 152c1f46dcSZachary Turner 162c1f46dcSZachary Turner #include "lldb-python.h" 172c1f46dcSZachary Turner #include "PythonDataObjects.h" 182c1f46dcSZachary Turner #include "ScriptInterpreterPython.h" 192c1f46dcSZachary Turner 202c1f46dcSZachary Turner #include "lldb/Core/Stream.h" 212c1f46dcSZachary Turner #include "lldb/Host/File.h" 222c1f46dcSZachary Turner #include "lldb/Interpreter/ScriptInterpreter.h" 232c1f46dcSZachary Turner 242c1f46dcSZachary Turner #include <stdio.h> 252c1f46dcSZachary Turner 262c1f46dcSZachary Turner using namespace lldb_private; 272c1f46dcSZachary Turner using namespace lldb; 282c1f46dcSZachary Turner 292c1f46dcSZachary Turner void 302c1f46dcSZachary Turner StructuredPythonObject::Dump(Stream &s) const 312c1f46dcSZachary Turner { 322c1f46dcSZachary Turner s << "Python Obj: 0x" << GetValue(); 332c1f46dcSZachary Turner } 342c1f46dcSZachary Turner 352c1f46dcSZachary Turner //---------------------------------------------------------------------- 362c1f46dcSZachary Turner // PythonObject 372c1f46dcSZachary Turner //---------------------------------------------------------------------- 382c1f46dcSZachary Turner 392c1f46dcSZachary Turner void 402c1f46dcSZachary Turner PythonObject::Dump(Stream &strm) const 412c1f46dcSZachary Turner { 422c1f46dcSZachary Turner if (m_py_obj) 432c1f46dcSZachary Turner { 442c1f46dcSZachary Turner FILE *file = ::tmpfile(); 452c1f46dcSZachary Turner if (file) 462c1f46dcSZachary Turner { 472c1f46dcSZachary Turner ::PyObject_Print (m_py_obj, file, 0); 482c1f46dcSZachary Turner const long length = ftell (file); 492c1f46dcSZachary Turner if (length) 502c1f46dcSZachary Turner { 512c1f46dcSZachary Turner ::rewind(file); 522c1f46dcSZachary Turner std::vector<char> file_contents (length,'\0'); 532c1f46dcSZachary Turner const size_t length_read = ::fread (file_contents.data(), 1, file_contents.size(), file); 542c1f46dcSZachary Turner if (length_read > 0) 552c1f46dcSZachary Turner strm.Write (file_contents.data(), length_read); 562c1f46dcSZachary Turner } 572c1f46dcSZachary Turner ::fclose (file); 582c1f46dcSZachary Turner } 592c1f46dcSZachary Turner } 602c1f46dcSZachary Turner else 612c1f46dcSZachary Turner strm.PutCString ("NULL"); 622c1f46dcSZachary Turner } 632c1f46dcSZachary Turner 642c1f46dcSZachary Turner PyObjectType 652c1f46dcSZachary Turner PythonObject::GetObjectType() const 662c1f46dcSZachary Turner { 67*f8b22f8fSZachary Turner if (!IsAllocated()) 682c1f46dcSZachary Turner return PyObjectType::None; 692c1f46dcSZachary Turner 702c1f46dcSZachary Turner if (PyList_Check(m_py_obj)) 712c1f46dcSZachary Turner return PyObjectType::List; 722c1f46dcSZachary Turner if (PyDict_Check(m_py_obj)) 732c1f46dcSZachary Turner return PyObjectType::Dictionary; 7422c8efcdSZachary Turner if (PyUnicode_Check(m_py_obj)) 7522c8efcdSZachary Turner return PyObjectType::String; 7622c8efcdSZachary Turner if (PyLong_Check(m_py_obj)) 7722c8efcdSZachary Turner return PyObjectType::Integer; 7822c8efcdSZachary Turner #if PY_MAJOR_VERSION < 3 7922c8efcdSZachary Turner // These functions don't exist in Python 3.x. PyString is PyUnicode 8022c8efcdSZachary Turner // and PyInt is PyLong. 812c1f46dcSZachary Turner if (PyString_Check(m_py_obj)) 822c1f46dcSZachary Turner return PyObjectType::String; 8322c8efcdSZachary Turner if (PyInt_Check(m_py_obj)) 842c1f46dcSZachary Turner return PyObjectType::Integer; 8522c8efcdSZachary Turner #endif 862c1f46dcSZachary Turner return PyObjectType::Unknown; 872c1f46dcSZachary Turner } 882c1f46dcSZachary Turner 892c1f46dcSZachary Turner PythonString 902c1f46dcSZachary Turner PythonObject::Repr() 912c1f46dcSZachary Turner { 922c1f46dcSZachary Turner if (!m_py_obj) 932c1f46dcSZachary Turner return PythonString(); 942c1f46dcSZachary Turner PyObject *repr = PyObject_Repr(m_py_obj); 952c1f46dcSZachary Turner if (!repr) 962c1f46dcSZachary Turner return PythonString(); 97*f8b22f8fSZachary Turner return PythonString(PyRefType::Owned, repr); 982c1f46dcSZachary Turner } 992c1f46dcSZachary Turner 1002c1f46dcSZachary Turner PythonString 1012c1f46dcSZachary Turner PythonObject::Str() 1022c1f46dcSZachary Turner { 1032c1f46dcSZachary Turner if (!m_py_obj) 1042c1f46dcSZachary Turner return PythonString(); 1052c1f46dcSZachary Turner PyObject *str = PyObject_Str(m_py_obj); 1062c1f46dcSZachary Turner if (!str) 1072c1f46dcSZachary Turner return PythonString(); 108*f8b22f8fSZachary Turner return PythonString(PyRefType::Owned, str); 1092c1f46dcSZachary Turner } 1102c1f46dcSZachary Turner 1112c1f46dcSZachary Turner bool 112*f8b22f8fSZachary Turner PythonObject::IsNone() const 1132c1f46dcSZachary Turner { 114*f8b22f8fSZachary Turner return m_py_obj == Py_None; 115*f8b22f8fSZachary Turner } 116*f8b22f8fSZachary Turner 117*f8b22f8fSZachary Turner bool 118*f8b22f8fSZachary Turner PythonObject::IsValid() const 119*f8b22f8fSZachary Turner { 120*f8b22f8fSZachary Turner return m_py_obj != nullptr; 121*f8b22f8fSZachary Turner } 122*f8b22f8fSZachary Turner 123*f8b22f8fSZachary Turner bool 124*f8b22f8fSZachary Turner PythonObject::IsAllocated() const 125*f8b22f8fSZachary Turner { 126*f8b22f8fSZachary Turner return IsValid() && !IsNone(); 1272c1f46dcSZachary Turner } 1282c1f46dcSZachary Turner 1292c1f46dcSZachary Turner StructuredData::ObjectSP 1302c1f46dcSZachary Turner PythonObject::CreateStructuredObject() const 1312c1f46dcSZachary Turner { 1322c1f46dcSZachary Turner switch (GetObjectType()) 1332c1f46dcSZachary Turner { 1342c1f46dcSZachary Turner case PyObjectType::Dictionary: 135*f8b22f8fSZachary Turner return PythonDictionary(PyRefType::Borrowed, m_py_obj).CreateStructuredDictionary(); 1362c1f46dcSZachary Turner case PyObjectType::Integer: 137*f8b22f8fSZachary Turner return PythonInteger(PyRefType::Borrowed, m_py_obj).CreateStructuredInteger(); 1382c1f46dcSZachary Turner case PyObjectType::List: 139*f8b22f8fSZachary Turner return PythonList(PyRefType::Borrowed, m_py_obj).CreateStructuredArray(); 1402c1f46dcSZachary Turner case PyObjectType::String: 141*f8b22f8fSZachary Turner return PythonString(PyRefType::Borrowed, m_py_obj).CreateStructuredString(); 1422c1f46dcSZachary Turner case PyObjectType::None: 1432c1f46dcSZachary Turner return StructuredData::ObjectSP(); 1442c1f46dcSZachary Turner default: 1452c1f46dcSZachary Turner return StructuredData::ObjectSP(new StructuredPythonObject(m_py_obj)); 1462c1f46dcSZachary Turner } 1472c1f46dcSZachary Turner } 1482c1f46dcSZachary Turner 1492c1f46dcSZachary Turner //---------------------------------------------------------------------- 1502c1f46dcSZachary Turner // PythonString 1512c1f46dcSZachary Turner //---------------------------------------------------------------------- 1522c1f46dcSZachary Turner 153*f8b22f8fSZachary Turner PythonString::PythonString(PyRefType type, PyObject *py_obj) 154*f8b22f8fSZachary Turner : PythonObject() 1552c1f46dcSZachary Turner { 156*f8b22f8fSZachary Turner Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a string 1572c1f46dcSZachary Turner } 1582c1f46dcSZachary Turner 159*f8b22f8fSZachary Turner PythonString::PythonString(const PythonString &object) 160*f8b22f8fSZachary Turner : PythonObject(object) 1612c1f46dcSZachary Turner { 1622c1f46dcSZachary Turner } 1632c1f46dcSZachary Turner 16422c8efcdSZachary Turner PythonString::PythonString(llvm::StringRef string) 16522c8efcdSZachary Turner : PythonObject() 1662c1f46dcSZachary Turner { 16722c8efcdSZachary Turner SetString(string); 1682c1f46dcSZachary Turner } 1692c1f46dcSZachary Turner 17022c8efcdSZachary Turner PythonString::PythonString(const char *string) 17122c8efcdSZachary Turner : PythonObject() 1722c1f46dcSZachary Turner { 17322c8efcdSZachary Turner SetString(llvm::StringRef(string)); 1742c1f46dcSZachary Turner } 1752c1f46dcSZachary Turner 176*f8b22f8fSZachary Turner PythonString::PythonString() 177*f8b22f8fSZachary Turner : PythonObject() 1782c1f46dcSZachary Turner { 1792c1f46dcSZachary Turner } 1802c1f46dcSZachary Turner 1812c1f46dcSZachary Turner PythonString::~PythonString () 1822c1f46dcSZachary Turner { 1832c1f46dcSZachary Turner } 1842c1f46dcSZachary Turner 1852c1f46dcSZachary Turner bool 18622c8efcdSZachary Turner PythonString::Check(PyObject *py_obj) 18722c8efcdSZachary Turner { 18822c8efcdSZachary Turner if (!py_obj) 18922c8efcdSZachary Turner return false; 19022c8efcdSZachary Turner #if PY_MAJOR_VERSION >= 3 19122c8efcdSZachary Turner // Python 3 does not have PyString objects, only PyUnicode. 19222c8efcdSZachary Turner return PyUnicode_Check(py_obj); 19322c8efcdSZachary Turner #else 19422c8efcdSZachary Turner return PyUnicode_Check(py_obj) || PyString_Check(py_obj); 19522c8efcdSZachary Turner #endif 19622c8efcdSZachary Turner } 19722c8efcdSZachary Turner 198*f8b22f8fSZachary Turner void 199*f8b22f8fSZachary Turner PythonString::Reset(PyRefType type, PyObject *py_obj) 2002c1f46dcSZachary Turner { 201*f8b22f8fSZachary Turner // Grab the desired reference type so that if we end up rejecting 202*f8b22f8fSZachary Turner // `py_obj` it still gets decremented if necessary. 203*f8b22f8fSZachary Turner PythonObject result(type, py_obj); 204*f8b22f8fSZachary Turner 20522c8efcdSZachary Turner if (!PythonString::Check(py_obj)) 20622c8efcdSZachary Turner { 207*f8b22f8fSZachary Turner PythonObject::Reset(); 208*f8b22f8fSZachary Turner return; 20922c8efcdSZachary Turner } 21022c8efcdSZachary Turner 21122c8efcdSZachary Turner // Convert this to a PyBytes object, and only store the PyBytes. Note that in 21222c8efcdSZachary Turner // Python 2.x, PyString and PyUnicode are interchangeable, and PyBytes is an alias 21322c8efcdSZachary Turner // of PyString. So on 2.x, if we get into this branch, we already have a PyBytes. 21422c8efcdSZachary Turner if (PyUnicode_Check(py_obj)) 21522c8efcdSZachary Turner { 216*f8b22f8fSZachary Turner // Since we're converting this to a different object, we assume ownership of the 217*f8b22f8fSZachary Turner // new object regardless of the value of `type`. 218*f8b22f8fSZachary Turner result.Reset(PyRefType::Owned, PyUnicode_AsUTF8String(py_obj)); 21922c8efcdSZachary Turner } 22022c8efcdSZachary Turner 221*f8b22f8fSZachary Turner assert(PyBytes_Check(result.get()) && "PythonString::Reset received a non-string"); 222*f8b22f8fSZachary Turner 223*f8b22f8fSZachary Turner // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls 224*f8b22f8fSZachary Turner // back into the virtual implementation. 225*f8b22f8fSZachary Turner PythonObject::Reset(PyRefType::Borrowed, result.get()); 2262c1f46dcSZachary Turner } 2272c1f46dcSZachary Turner 2282c1f46dcSZachary Turner llvm::StringRef 2292c1f46dcSZachary Turner PythonString::GetString() const 2302c1f46dcSZachary Turner { 231*f8b22f8fSZachary Turner if (IsValid()) 23222c8efcdSZachary Turner { 23322c8efcdSZachary Turner Py_ssize_t size; 23422c8efcdSZachary Turner char *c; 23522c8efcdSZachary Turner PyBytes_AsStringAndSize(m_py_obj, &c, &size); 23622c8efcdSZachary Turner return llvm::StringRef(c, size); 23722c8efcdSZachary Turner } 2382c1f46dcSZachary Turner return llvm::StringRef(); 2392c1f46dcSZachary Turner } 2402c1f46dcSZachary Turner 2412c1f46dcSZachary Turner size_t 2422c1f46dcSZachary Turner PythonString::GetSize() const 2432c1f46dcSZachary Turner { 244*f8b22f8fSZachary Turner if (IsValid()) 24522c8efcdSZachary Turner return PyBytes_Size(m_py_obj); 2462c1f46dcSZachary Turner return 0; 2472c1f46dcSZachary Turner } 2482c1f46dcSZachary Turner 2492c1f46dcSZachary Turner void 2502c1f46dcSZachary Turner PythonString::SetString (llvm::StringRef string) 2512c1f46dcSZachary Turner { 25222c8efcdSZachary Turner #if PY_MAJOR_VERSION >= 3 25322c8efcdSZachary Turner PyObject *unicode = PyUnicode_FromStringAndSize(string.data(), string.size()); 25422c8efcdSZachary Turner PyObject *bytes = PyUnicode_AsUTF8String(unicode); 255*f8b22f8fSZachary Turner PythonObject::Reset(PyRefType::Owned, bytes); 256*f8b22f8fSZachary Turner Py_DECREF(unicode); 25722c8efcdSZachary Turner #else 258*f8b22f8fSZachary Turner PythonObject::Reset(PyRefType::Owned, PyString_FromStringAndSize(string.data(), string.size())); 25922c8efcdSZachary Turner #endif 2602c1f46dcSZachary Turner } 2612c1f46dcSZachary Turner 2622c1f46dcSZachary Turner StructuredData::StringSP 2632c1f46dcSZachary Turner PythonString::CreateStructuredString() const 2642c1f46dcSZachary Turner { 2652c1f46dcSZachary Turner StructuredData::StringSP result(new StructuredData::String); 2662c1f46dcSZachary Turner result->SetValue(GetString()); 2672c1f46dcSZachary Turner return result; 2682c1f46dcSZachary Turner } 2692c1f46dcSZachary Turner 2702c1f46dcSZachary Turner //---------------------------------------------------------------------- 2712c1f46dcSZachary Turner // PythonInteger 2722c1f46dcSZachary Turner //---------------------------------------------------------------------- 2732c1f46dcSZachary Turner 274*f8b22f8fSZachary Turner PythonInteger::PythonInteger(PyRefType type, PyObject *py_obj) 275*f8b22f8fSZachary Turner : PythonObject() 2762c1f46dcSZachary Turner { 277*f8b22f8fSZachary Turner Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a integer type 2782c1f46dcSZachary Turner } 2792c1f46dcSZachary Turner 280*f8b22f8fSZachary Turner PythonInteger::PythonInteger(const PythonInteger &object) 281*f8b22f8fSZachary Turner : PythonObject(object) 2822c1f46dcSZachary Turner { 2832c1f46dcSZachary Turner } 2842c1f46dcSZachary Turner 285*f8b22f8fSZachary Turner PythonInteger::PythonInteger(int64_t value) 286*f8b22f8fSZachary Turner : PythonObject() 2872c1f46dcSZachary Turner { 2882c1f46dcSZachary Turner SetInteger(value); 2892c1f46dcSZachary Turner } 2902c1f46dcSZachary Turner 2912c1f46dcSZachary Turner 2922c1f46dcSZachary Turner PythonInteger::~PythonInteger () 2932c1f46dcSZachary Turner { 2942c1f46dcSZachary Turner } 2952c1f46dcSZachary Turner 2962c1f46dcSZachary Turner bool 29722c8efcdSZachary Turner PythonInteger::Check(PyObject *py_obj) 2982c1f46dcSZachary Turner { 29922c8efcdSZachary Turner if (!py_obj) 30022c8efcdSZachary Turner return false; 30122c8efcdSZachary Turner 30222c8efcdSZachary Turner #if PY_MAJOR_VERSION >= 3 30322c8efcdSZachary Turner // Python 3 does not have PyInt_Check. There is only one type of 30422c8efcdSZachary Turner // integral value, long. 30522c8efcdSZachary Turner return PyLong_Check(py_obj); 30622c8efcdSZachary Turner #else 30722c8efcdSZachary Turner return PyLong_Check(py_obj) || PyInt_Check(py_obj); 30822c8efcdSZachary Turner #endif 3092c1f46dcSZachary Turner } 3102c1f46dcSZachary Turner 311*f8b22f8fSZachary Turner void 312*f8b22f8fSZachary Turner PythonInteger::Reset(PyRefType type, PyObject *py_obj) 31322c8efcdSZachary Turner { 314*f8b22f8fSZachary Turner // Grab the desired reference type so that if we end up rejecting 315*f8b22f8fSZachary Turner // `py_obj` it still gets decremented if necessary. 316*f8b22f8fSZachary Turner PythonObject result(type, py_obj); 317*f8b22f8fSZachary Turner 31822c8efcdSZachary Turner if (!PythonInteger::Check(py_obj)) 31922c8efcdSZachary Turner { 320*f8b22f8fSZachary Turner PythonObject::Reset(); 321*f8b22f8fSZachary Turner return; 32222c8efcdSZachary Turner } 32322c8efcdSZachary Turner 32422c8efcdSZachary Turner #if PY_MAJOR_VERSION < 3 32522c8efcdSZachary Turner // Always store this as a PyLong, which makes interoperability between 32622c8efcdSZachary Turner // Python 2.x and Python 3.x easier. This is only necessary in 2.x, 32722c8efcdSZachary Turner // since 3.x doesn't even have a PyInt. 32822c8efcdSZachary Turner if (PyInt_Check(py_obj)) 32922c8efcdSZachary Turner { 330*f8b22f8fSZachary Turner // Since we converted the original object to a different type, the new 331*f8b22f8fSZachary Turner // object is an owned object regardless of the ownership semantics requested 332*f8b22f8fSZachary Turner // by the user. 333*f8b22f8fSZachary Turner result.Reset(PyRefType::Owned, PyLong_FromLongLong(PyInt_AsLong(py_obj))); 33422c8efcdSZachary Turner } 33522c8efcdSZachary Turner #endif 33622c8efcdSZachary Turner 337*f8b22f8fSZachary Turner assert(PyLong_Check(result.get()) && "Couldn't get a PyLong from this PyObject"); 33822c8efcdSZachary Turner 339*f8b22f8fSZachary Turner // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls 340*f8b22f8fSZachary Turner // back into the virtual implementation. 341*f8b22f8fSZachary Turner PythonObject::Reset(PyRefType::Borrowed, result.get()); 3422c1f46dcSZachary Turner } 3432c1f46dcSZachary Turner 3442c1f46dcSZachary Turner int64_t 3452c1f46dcSZachary Turner PythonInteger::GetInteger() const 3462c1f46dcSZachary Turner { 3472c1f46dcSZachary Turner if (m_py_obj) 3482c1f46dcSZachary Turner { 34922c8efcdSZachary Turner assert(PyLong_Check(m_py_obj) && "PythonInteger::GetInteger has a PyObject that isn't a PyLong"); 35022c8efcdSZachary Turner 3512c1f46dcSZachary Turner return PyLong_AsLongLong(m_py_obj); 3522c1f46dcSZachary Turner } 3532c1f46dcSZachary Turner return UINT64_MAX; 3542c1f46dcSZachary Turner } 3552c1f46dcSZachary Turner 3562c1f46dcSZachary Turner void 3572c1f46dcSZachary Turner PythonInteger::SetInteger(int64_t value) 3582c1f46dcSZachary Turner { 359*f8b22f8fSZachary Turner PythonObject::Reset(PyRefType::Owned, PyLong_FromLongLong(value)); 3602c1f46dcSZachary Turner } 3612c1f46dcSZachary Turner 3622c1f46dcSZachary Turner StructuredData::IntegerSP 3632c1f46dcSZachary Turner PythonInteger::CreateStructuredInteger() const 3642c1f46dcSZachary Turner { 3652c1f46dcSZachary Turner StructuredData::IntegerSP result(new StructuredData::Integer); 3662c1f46dcSZachary Turner result->SetValue(GetInteger()); 3672c1f46dcSZachary Turner return result; 3682c1f46dcSZachary Turner } 3692c1f46dcSZachary Turner 3702c1f46dcSZachary Turner //---------------------------------------------------------------------- 3712c1f46dcSZachary Turner // PythonList 3722c1f46dcSZachary Turner //---------------------------------------------------------------------- 3732c1f46dcSZachary Turner 374*f8b22f8fSZachary Turner PythonList::PythonList(PyInitialValue value) 375*f8b22f8fSZachary Turner : PythonObject() 3762c1f46dcSZachary Turner { 377*f8b22f8fSZachary Turner if (value == PyInitialValue::Empty) 378*f8b22f8fSZachary Turner Reset(PyRefType::Owned, PyList_New(0)); 3792c1f46dcSZachary Turner } 3802c1f46dcSZachary Turner 381*f8b22f8fSZachary Turner PythonList::PythonList(PyRefType type, PyObject *py_obj) 382*f8b22f8fSZachary Turner : PythonObject() 3832c1f46dcSZachary Turner { 384*f8b22f8fSZachary Turner Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a list 3852c1f46dcSZachary Turner } 3862c1f46dcSZachary Turner 387*f8b22f8fSZachary Turner PythonList::PythonList(const PythonList &list) 388*f8b22f8fSZachary Turner : PythonObject(list) 3892c1f46dcSZachary Turner { 3902c1f46dcSZachary Turner } 3912c1f46dcSZachary Turner 3922c1f46dcSZachary Turner PythonList::~PythonList () 3932c1f46dcSZachary Turner { 3942c1f46dcSZachary Turner } 3952c1f46dcSZachary Turner 3962c1f46dcSZachary Turner bool 39722c8efcdSZachary Turner PythonList::Check(PyObject *py_obj) 39822c8efcdSZachary Turner { 39922c8efcdSZachary Turner if (!py_obj) 40022c8efcdSZachary Turner return false; 40122c8efcdSZachary Turner return PyList_Check(py_obj); 40222c8efcdSZachary Turner } 40322c8efcdSZachary Turner 404*f8b22f8fSZachary Turner void 405*f8b22f8fSZachary Turner PythonList::Reset(PyRefType type, PyObject *py_obj) 4062c1f46dcSZachary Turner { 407*f8b22f8fSZachary Turner // Grab the desired reference type so that if we end up rejecting 408*f8b22f8fSZachary Turner // `py_obj` it still gets decremented if necessary. 409*f8b22f8fSZachary Turner PythonObject result(type, py_obj); 410*f8b22f8fSZachary Turner 41122c8efcdSZachary Turner if (!PythonList::Check(py_obj)) 41222c8efcdSZachary Turner { 413*f8b22f8fSZachary Turner PythonObject::Reset(); 414*f8b22f8fSZachary Turner return; 41522c8efcdSZachary Turner } 41622c8efcdSZachary Turner 417*f8b22f8fSZachary Turner // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls 418*f8b22f8fSZachary Turner // back into the virtual implementation. 419*f8b22f8fSZachary Turner PythonObject::Reset(PyRefType::Borrowed, result.get()); 4202c1f46dcSZachary Turner } 4212c1f46dcSZachary Turner 4222c1f46dcSZachary Turner uint32_t 4232c1f46dcSZachary Turner PythonList::GetSize() const 4242c1f46dcSZachary Turner { 425*f8b22f8fSZachary Turner if (IsValid()) 4262c1f46dcSZachary Turner return PyList_GET_SIZE(m_py_obj); 4272c1f46dcSZachary Turner return 0; 4282c1f46dcSZachary Turner } 4292c1f46dcSZachary Turner 4302c1f46dcSZachary Turner PythonObject 4312c1f46dcSZachary Turner PythonList::GetItemAtIndex(uint32_t index) const 4322c1f46dcSZachary Turner { 433*f8b22f8fSZachary Turner if (IsValid()) 434*f8b22f8fSZachary Turner return PythonObject(PyRefType::Borrowed, PyList_GetItem(m_py_obj, index)); 4352c1f46dcSZachary Turner return PythonObject(); 4362c1f46dcSZachary Turner } 4372c1f46dcSZachary Turner 4382c1f46dcSZachary Turner void 4392c1f46dcSZachary Turner PythonList::SetItemAtIndex(uint32_t index, const PythonObject &object) 4402c1f46dcSZachary Turner { 441*f8b22f8fSZachary Turner if (IsAllocated() && object.IsValid()) 442*f8b22f8fSZachary Turner { 443*f8b22f8fSZachary Turner // PyList_SetItem is documented to "steal" a reference, so we need to 444*f8b22f8fSZachary Turner // convert it to an owned reference by incrementing it. 445*f8b22f8fSZachary Turner Py_INCREF(object.get()); 4462c1f46dcSZachary Turner PyList_SetItem(m_py_obj, index, object.get()); 4472c1f46dcSZachary Turner } 448*f8b22f8fSZachary Turner } 4492c1f46dcSZachary Turner 4502c1f46dcSZachary Turner void 4512c1f46dcSZachary Turner PythonList::AppendItem(const PythonObject &object) 4522c1f46dcSZachary Turner { 453*f8b22f8fSZachary Turner if (IsAllocated() && object.IsValid()) 454*f8b22f8fSZachary Turner { 455*f8b22f8fSZachary Turner // `PyList_Append` does *not* steal a reference, so do not call `Py_INCREF` 456*f8b22f8fSZachary Turner // here like we do with `PyList_SetItem`. 4572c1f46dcSZachary Turner PyList_Append(m_py_obj, object.get()); 4582c1f46dcSZachary Turner } 459*f8b22f8fSZachary Turner } 4602c1f46dcSZachary Turner 4612c1f46dcSZachary Turner StructuredData::ArraySP 4622c1f46dcSZachary Turner PythonList::CreateStructuredArray() const 4632c1f46dcSZachary Turner { 4642c1f46dcSZachary Turner StructuredData::ArraySP result(new StructuredData::Array); 4652c1f46dcSZachary Turner uint32_t count = GetSize(); 4662c1f46dcSZachary Turner for (uint32_t i = 0; i < count; ++i) 4672c1f46dcSZachary Turner { 4682c1f46dcSZachary Turner PythonObject obj = GetItemAtIndex(i); 4692c1f46dcSZachary Turner result->AddItem(obj.CreateStructuredObject()); 4702c1f46dcSZachary Turner } 4712c1f46dcSZachary Turner return result; 4722c1f46dcSZachary Turner } 4732c1f46dcSZachary Turner 4742c1f46dcSZachary Turner //---------------------------------------------------------------------- 4752c1f46dcSZachary Turner // PythonDictionary 4762c1f46dcSZachary Turner //---------------------------------------------------------------------- 4772c1f46dcSZachary Turner 478*f8b22f8fSZachary Turner PythonDictionary::PythonDictionary(PyInitialValue value) 479*f8b22f8fSZachary Turner : PythonObject() 4802c1f46dcSZachary Turner { 481*f8b22f8fSZachary Turner if (value == PyInitialValue::Empty) 482*f8b22f8fSZachary Turner Reset(PyRefType::Owned, PyDict_New()); 4832c1f46dcSZachary Turner } 4842c1f46dcSZachary Turner 485*f8b22f8fSZachary Turner PythonDictionary::PythonDictionary(PyRefType type, PyObject *py_obj) 486*f8b22f8fSZachary Turner : PythonObject() 4872c1f46dcSZachary Turner { 488*f8b22f8fSZachary Turner Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a dictionary 4892c1f46dcSZachary Turner } 4902c1f46dcSZachary Turner 491*f8b22f8fSZachary Turner PythonDictionary::PythonDictionary(const PythonDictionary &object) 492*f8b22f8fSZachary Turner : PythonObject(object) 4932c1f46dcSZachary Turner { 4942c1f46dcSZachary Turner } 4952c1f46dcSZachary Turner 4962c1f46dcSZachary Turner PythonDictionary::~PythonDictionary () 4972c1f46dcSZachary Turner { 4982c1f46dcSZachary Turner } 4992c1f46dcSZachary Turner 5002c1f46dcSZachary Turner bool 50122c8efcdSZachary Turner PythonDictionary::Check(PyObject *py_obj) 50222c8efcdSZachary Turner { 50322c8efcdSZachary Turner if (!py_obj) 50422c8efcdSZachary Turner return false; 50522c8efcdSZachary Turner 50622c8efcdSZachary Turner return PyDict_Check(py_obj); 50722c8efcdSZachary Turner } 50822c8efcdSZachary Turner 509*f8b22f8fSZachary Turner void 510*f8b22f8fSZachary Turner PythonDictionary::Reset(PyRefType type, PyObject *py_obj) 5112c1f46dcSZachary Turner { 512*f8b22f8fSZachary Turner // Grab the desired reference type so that if we end up rejecting 513*f8b22f8fSZachary Turner // `py_obj` it still gets decremented if necessary. 514*f8b22f8fSZachary Turner PythonObject result(type, py_obj); 515*f8b22f8fSZachary Turner 51622c8efcdSZachary Turner if (!PythonDictionary::Check(py_obj)) 51722c8efcdSZachary Turner { 518*f8b22f8fSZachary Turner PythonObject::Reset(); 519*f8b22f8fSZachary Turner return; 52022c8efcdSZachary Turner } 52122c8efcdSZachary Turner 522*f8b22f8fSZachary Turner // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls 523*f8b22f8fSZachary Turner // back into the virtual implementation. 524*f8b22f8fSZachary Turner PythonObject::Reset(PyRefType::Borrowed, result.get()); 5252c1f46dcSZachary Turner } 5262c1f46dcSZachary Turner 5272c1f46dcSZachary Turner uint32_t 5282c1f46dcSZachary Turner PythonDictionary::GetSize() const 5292c1f46dcSZachary Turner { 530*f8b22f8fSZachary Turner if (IsValid()) 5312c1f46dcSZachary Turner return PyDict_Size(m_py_obj); 5322c1f46dcSZachary Turner return 0; 5332c1f46dcSZachary Turner } 5342c1f46dcSZachary Turner 5352c1f46dcSZachary Turner PythonList 5362c1f46dcSZachary Turner PythonDictionary::GetKeys() const 5372c1f46dcSZachary Turner { 538*f8b22f8fSZachary Turner if (IsValid()) 539*f8b22f8fSZachary Turner return PythonList(PyRefType::Owned, PyDict_Keys(m_py_obj)); 540*f8b22f8fSZachary Turner return PythonList(PyInitialValue::Invalid); 5412c1f46dcSZachary Turner } 5422c1f46dcSZachary Turner 5432c1f46dcSZachary Turner PythonObject 544*f8b22f8fSZachary Turner PythonDictionary::GetItemForKey(const PythonObject &key) const 5452c1f46dcSZachary Turner { 546*f8b22f8fSZachary Turner if (IsAllocated() && key.IsValid()) 547*f8b22f8fSZachary Turner return PythonObject(PyRefType::Borrowed, PyDict_GetItem(m_py_obj, key.get())); 5482c1f46dcSZachary Turner return PythonObject(); 5492c1f46dcSZachary Turner } 5502c1f46dcSZachary Turner 5512c1f46dcSZachary Turner void 552*f8b22f8fSZachary Turner PythonDictionary::SetItemForKey(const PythonObject &key, const PythonObject &value) 5532c1f46dcSZachary Turner { 554*f8b22f8fSZachary Turner if (IsAllocated() && key.IsValid() && value.IsValid()) 5552c1f46dcSZachary Turner PyDict_SetItem(m_py_obj, key.get(), value.get()); 5562c1f46dcSZachary Turner } 5572c1f46dcSZachary Turner 5582c1f46dcSZachary Turner StructuredData::DictionarySP 5592c1f46dcSZachary Turner PythonDictionary::CreateStructuredDictionary() const 5602c1f46dcSZachary Turner { 5612c1f46dcSZachary Turner StructuredData::DictionarySP result(new StructuredData::Dictionary); 5622c1f46dcSZachary Turner PythonList keys(GetKeys()); 5632c1f46dcSZachary Turner uint32_t num_keys = keys.GetSize(); 5642c1f46dcSZachary Turner for (uint32_t i = 0; i < num_keys; ++i) 5652c1f46dcSZachary Turner { 5662c1f46dcSZachary Turner PythonObject key = keys.GetItemAtIndex(i); 5672c1f46dcSZachary Turner PythonObject value = GetItemForKey(key); 5682c1f46dcSZachary Turner StructuredData::ObjectSP structured_value = value.CreateStructuredObject(); 569*f8b22f8fSZachary Turner result->AddItem(key.Str().GetString(), structured_value); 5702c1f46dcSZachary Turner } 5712c1f46dcSZachary Turner return result; 5722c1f46dcSZachary Turner } 5732c1f46dcSZachary Turner 5742c1f46dcSZachary Turner #endif 575