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 { 67f8b22f8fSZachary 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(); 97f8b22f8fSZachary 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(); 108f8b22f8fSZachary Turner return PythonString(PyRefType::Owned, str); 1092c1f46dcSZachary Turner } 1102c1f46dcSZachary Turner 1112c1f46dcSZachary Turner bool 112f8b22f8fSZachary Turner PythonObject::IsNone() const 1132c1f46dcSZachary Turner { 114f8b22f8fSZachary Turner return m_py_obj == Py_None; 115f8b22f8fSZachary Turner } 116f8b22f8fSZachary Turner 117f8b22f8fSZachary Turner bool 118f8b22f8fSZachary Turner PythonObject::IsValid() const 119f8b22f8fSZachary Turner { 120f8b22f8fSZachary Turner return m_py_obj != nullptr; 121f8b22f8fSZachary Turner } 122f8b22f8fSZachary Turner 123f8b22f8fSZachary Turner bool 124f8b22f8fSZachary Turner PythonObject::IsAllocated() const 125f8b22f8fSZachary Turner { 126f8b22f8fSZachary 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: 135f8b22f8fSZachary Turner return PythonDictionary(PyRefType::Borrowed, m_py_obj).CreateStructuredDictionary(); 1362c1f46dcSZachary Turner case PyObjectType::Integer: 137f8b22f8fSZachary Turner return PythonInteger(PyRefType::Borrowed, m_py_obj).CreateStructuredInteger(); 1382c1f46dcSZachary Turner case PyObjectType::List: 139f8b22f8fSZachary Turner return PythonList(PyRefType::Borrowed, m_py_obj).CreateStructuredArray(); 1402c1f46dcSZachary Turner case PyObjectType::String: 141f8b22f8fSZachary 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 153f8b22f8fSZachary Turner PythonString::PythonString(PyRefType type, PyObject *py_obj) 154f8b22f8fSZachary Turner : PythonObject() 1552c1f46dcSZachary Turner { 156f8b22f8fSZachary Turner Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a string 1572c1f46dcSZachary Turner } 1582c1f46dcSZachary Turner 159f8b22f8fSZachary Turner PythonString::PythonString(const PythonString &object) 160f8b22f8fSZachary 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 176f8b22f8fSZachary Turner PythonString::PythonString() 177f8b22f8fSZachary 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 198f8b22f8fSZachary Turner void 199f8b22f8fSZachary Turner PythonString::Reset(PyRefType type, PyObject *py_obj) 2002c1f46dcSZachary Turner { 201f8b22f8fSZachary Turner // Grab the desired reference type so that if we end up rejecting 202f8b22f8fSZachary Turner // `py_obj` it still gets decremented if necessary. 203f8b22f8fSZachary Turner PythonObject result(type, py_obj); 204f8b22f8fSZachary Turner 20522c8efcdSZachary Turner if (!PythonString::Check(py_obj)) 20622c8efcdSZachary Turner { 207f8b22f8fSZachary Turner PythonObject::Reset(); 208f8b22f8fSZachary 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 { 216f8b22f8fSZachary Turner // Since we're converting this to a different object, we assume ownership of the 217f8b22f8fSZachary Turner // new object regardless of the value of `type`. 218f8b22f8fSZachary Turner result.Reset(PyRefType::Owned, PyUnicode_AsUTF8String(py_obj)); 21922c8efcdSZachary Turner } 22022c8efcdSZachary Turner 221f8b22f8fSZachary Turner assert(PyBytes_Check(result.get()) && "PythonString::Reset received a non-string"); 222f8b22f8fSZachary Turner 223f8b22f8fSZachary Turner // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls 224f8b22f8fSZachary Turner // back into the virtual implementation. 225f8b22f8fSZachary Turner PythonObject::Reset(PyRefType::Borrowed, result.get()); 2262c1f46dcSZachary Turner } 2272c1f46dcSZachary Turner 2282c1f46dcSZachary Turner llvm::StringRef 2292c1f46dcSZachary Turner PythonString::GetString() const 2302c1f46dcSZachary Turner { 231f8b22f8fSZachary 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 { 244f8b22f8fSZachary 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); 255f8b22f8fSZachary Turner PythonObject::Reset(PyRefType::Owned, bytes); 256f8b22f8fSZachary Turner Py_DECREF(unicode); 25722c8efcdSZachary Turner #else 258f8b22f8fSZachary 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 274f8b22f8fSZachary Turner PythonInteger::PythonInteger(PyRefType type, PyObject *py_obj) 275f8b22f8fSZachary Turner : PythonObject() 2762c1f46dcSZachary Turner { 277f8b22f8fSZachary Turner Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a integer type 2782c1f46dcSZachary Turner } 2792c1f46dcSZachary Turner 280f8b22f8fSZachary Turner PythonInteger::PythonInteger(const PythonInteger &object) 281f8b22f8fSZachary Turner : PythonObject(object) 2822c1f46dcSZachary Turner { 2832c1f46dcSZachary Turner } 2842c1f46dcSZachary Turner 285f8b22f8fSZachary Turner PythonInteger::PythonInteger(int64_t value) 286f8b22f8fSZachary 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 311f8b22f8fSZachary Turner void 312f8b22f8fSZachary Turner PythonInteger::Reset(PyRefType type, PyObject *py_obj) 31322c8efcdSZachary Turner { 314f8b22f8fSZachary Turner // Grab the desired reference type so that if we end up rejecting 315f8b22f8fSZachary Turner // `py_obj` it still gets decremented if necessary. 316f8b22f8fSZachary Turner PythonObject result(type, py_obj); 317f8b22f8fSZachary Turner 31822c8efcdSZachary Turner if (!PythonInteger::Check(py_obj)) 31922c8efcdSZachary Turner { 320f8b22f8fSZachary Turner PythonObject::Reset(); 321f8b22f8fSZachary 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 { 330f8b22f8fSZachary Turner // Since we converted the original object to a different type, the new 331f8b22f8fSZachary Turner // object is an owned object regardless of the ownership semantics requested 332f8b22f8fSZachary Turner // by the user. 333f8b22f8fSZachary Turner result.Reset(PyRefType::Owned, PyLong_FromLongLong(PyInt_AsLong(py_obj))); 33422c8efcdSZachary Turner } 33522c8efcdSZachary Turner #endif 33622c8efcdSZachary Turner 337f8b22f8fSZachary Turner assert(PyLong_Check(result.get()) && "Couldn't get a PyLong from this PyObject"); 33822c8efcdSZachary Turner 339f8b22f8fSZachary Turner // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls 340f8b22f8fSZachary Turner // back into the virtual implementation. 341f8b22f8fSZachary 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 { 359f8b22f8fSZachary 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 374f8b22f8fSZachary Turner PythonList::PythonList(PyInitialValue value) 375f8b22f8fSZachary Turner : PythonObject() 3762c1f46dcSZachary Turner { 377f8b22f8fSZachary Turner if (value == PyInitialValue::Empty) 378f8b22f8fSZachary Turner Reset(PyRefType::Owned, PyList_New(0)); 3792c1f46dcSZachary Turner } 3802c1f46dcSZachary Turner 381*87f47729SZachary Turner PythonList::PythonList(int list_size) 382*87f47729SZachary Turner : PythonObject() 383*87f47729SZachary Turner { 384*87f47729SZachary Turner Reset(PyRefType::Owned, PyList_New(list_size)); 385*87f47729SZachary Turner } 386*87f47729SZachary Turner 387f8b22f8fSZachary Turner PythonList::PythonList(PyRefType type, PyObject *py_obj) 388f8b22f8fSZachary Turner : PythonObject() 3892c1f46dcSZachary Turner { 390f8b22f8fSZachary Turner Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a list 3912c1f46dcSZachary Turner } 3922c1f46dcSZachary Turner 393f8b22f8fSZachary Turner PythonList::PythonList(const PythonList &list) 394f8b22f8fSZachary Turner : PythonObject(list) 3952c1f46dcSZachary Turner { 3962c1f46dcSZachary Turner } 3972c1f46dcSZachary Turner 3982c1f46dcSZachary Turner PythonList::~PythonList () 3992c1f46dcSZachary Turner { 4002c1f46dcSZachary Turner } 4012c1f46dcSZachary Turner 4022c1f46dcSZachary Turner bool 40322c8efcdSZachary Turner PythonList::Check(PyObject *py_obj) 40422c8efcdSZachary Turner { 40522c8efcdSZachary Turner if (!py_obj) 40622c8efcdSZachary Turner return false; 40722c8efcdSZachary Turner return PyList_Check(py_obj); 40822c8efcdSZachary Turner } 40922c8efcdSZachary Turner 410f8b22f8fSZachary Turner void 411f8b22f8fSZachary Turner PythonList::Reset(PyRefType type, PyObject *py_obj) 4122c1f46dcSZachary Turner { 413f8b22f8fSZachary Turner // Grab the desired reference type so that if we end up rejecting 414f8b22f8fSZachary Turner // `py_obj` it still gets decremented if necessary. 415f8b22f8fSZachary Turner PythonObject result(type, py_obj); 416f8b22f8fSZachary Turner 41722c8efcdSZachary Turner if (!PythonList::Check(py_obj)) 41822c8efcdSZachary Turner { 419f8b22f8fSZachary Turner PythonObject::Reset(); 420f8b22f8fSZachary Turner return; 42122c8efcdSZachary Turner } 42222c8efcdSZachary Turner 423f8b22f8fSZachary Turner // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls 424f8b22f8fSZachary Turner // back into the virtual implementation. 425f8b22f8fSZachary Turner PythonObject::Reset(PyRefType::Borrowed, result.get()); 4262c1f46dcSZachary Turner } 4272c1f46dcSZachary Turner 4282c1f46dcSZachary Turner uint32_t 4292c1f46dcSZachary Turner PythonList::GetSize() const 4302c1f46dcSZachary Turner { 431f8b22f8fSZachary Turner if (IsValid()) 4322c1f46dcSZachary Turner return PyList_GET_SIZE(m_py_obj); 4332c1f46dcSZachary Turner return 0; 4342c1f46dcSZachary Turner } 4352c1f46dcSZachary Turner 4362c1f46dcSZachary Turner PythonObject 4372c1f46dcSZachary Turner PythonList::GetItemAtIndex(uint32_t index) const 4382c1f46dcSZachary Turner { 439f8b22f8fSZachary Turner if (IsValid()) 440f8b22f8fSZachary Turner return PythonObject(PyRefType::Borrowed, PyList_GetItem(m_py_obj, index)); 4412c1f46dcSZachary Turner return PythonObject(); 4422c1f46dcSZachary Turner } 4432c1f46dcSZachary Turner 4442c1f46dcSZachary Turner void 4452c1f46dcSZachary Turner PythonList::SetItemAtIndex(uint32_t index, const PythonObject &object) 4462c1f46dcSZachary Turner { 447f8b22f8fSZachary Turner if (IsAllocated() && object.IsValid()) 448f8b22f8fSZachary Turner { 449f8b22f8fSZachary Turner // PyList_SetItem is documented to "steal" a reference, so we need to 450f8b22f8fSZachary Turner // convert it to an owned reference by incrementing it. 451f8b22f8fSZachary Turner Py_INCREF(object.get()); 4522c1f46dcSZachary Turner PyList_SetItem(m_py_obj, index, object.get()); 4532c1f46dcSZachary Turner } 454f8b22f8fSZachary Turner } 4552c1f46dcSZachary Turner 4562c1f46dcSZachary Turner void 4572c1f46dcSZachary Turner PythonList::AppendItem(const PythonObject &object) 4582c1f46dcSZachary Turner { 459f8b22f8fSZachary Turner if (IsAllocated() && object.IsValid()) 460f8b22f8fSZachary Turner { 461f8b22f8fSZachary Turner // `PyList_Append` does *not* steal a reference, so do not call `Py_INCREF` 462f8b22f8fSZachary Turner // here like we do with `PyList_SetItem`. 4632c1f46dcSZachary Turner PyList_Append(m_py_obj, object.get()); 4642c1f46dcSZachary Turner } 465f8b22f8fSZachary Turner } 4662c1f46dcSZachary Turner 4672c1f46dcSZachary Turner StructuredData::ArraySP 4682c1f46dcSZachary Turner PythonList::CreateStructuredArray() const 4692c1f46dcSZachary Turner { 4702c1f46dcSZachary Turner StructuredData::ArraySP result(new StructuredData::Array); 4712c1f46dcSZachary Turner uint32_t count = GetSize(); 4722c1f46dcSZachary Turner for (uint32_t i = 0; i < count; ++i) 4732c1f46dcSZachary Turner { 4742c1f46dcSZachary Turner PythonObject obj = GetItemAtIndex(i); 4752c1f46dcSZachary Turner result->AddItem(obj.CreateStructuredObject()); 4762c1f46dcSZachary Turner } 4772c1f46dcSZachary Turner return result; 4782c1f46dcSZachary Turner } 4792c1f46dcSZachary Turner 4802c1f46dcSZachary Turner //---------------------------------------------------------------------- 4812c1f46dcSZachary Turner // PythonDictionary 4822c1f46dcSZachary Turner //---------------------------------------------------------------------- 4832c1f46dcSZachary Turner 484f8b22f8fSZachary Turner PythonDictionary::PythonDictionary(PyInitialValue value) 485f8b22f8fSZachary Turner : PythonObject() 4862c1f46dcSZachary Turner { 487f8b22f8fSZachary Turner if (value == PyInitialValue::Empty) 488f8b22f8fSZachary Turner Reset(PyRefType::Owned, PyDict_New()); 4892c1f46dcSZachary Turner } 4902c1f46dcSZachary Turner 491f8b22f8fSZachary Turner PythonDictionary::PythonDictionary(PyRefType type, PyObject *py_obj) 492f8b22f8fSZachary Turner : PythonObject() 4932c1f46dcSZachary Turner { 494f8b22f8fSZachary Turner Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a dictionary 4952c1f46dcSZachary Turner } 4962c1f46dcSZachary Turner 497f8b22f8fSZachary Turner PythonDictionary::PythonDictionary(const PythonDictionary &object) 498f8b22f8fSZachary Turner : PythonObject(object) 4992c1f46dcSZachary Turner { 5002c1f46dcSZachary Turner } 5012c1f46dcSZachary Turner 5022c1f46dcSZachary Turner PythonDictionary::~PythonDictionary () 5032c1f46dcSZachary Turner { 5042c1f46dcSZachary Turner } 5052c1f46dcSZachary Turner 5062c1f46dcSZachary Turner bool 50722c8efcdSZachary Turner PythonDictionary::Check(PyObject *py_obj) 50822c8efcdSZachary Turner { 50922c8efcdSZachary Turner if (!py_obj) 51022c8efcdSZachary Turner return false; 51122c8efcdSZachary Turner 51222c8efcdSZachary Turner return PyDict_Check(py_obj); 51322c8efcdSZachary Turner } 51422c8efcdSZachary Turner 515f8b22f8fSZachary Turner void 516f8b22f8fSZachary Turner PythonDictionary::Reset(PyRefType type, PyObject *py_obj) 5172c1f46dcSZachary Turner { 518f8b22f8fSZachary Turner // Grab the desired reference type so that if we end up rejecting 519f8b22f8fSZachary Turner // `py_obj` it still gets decremented if necessary. 520f8b22f8fSZachary Turner PythonObject result(type, py_obj); 521f8b22f8fSZachary Turner 52222c8efcdSZachary Turner if (!PythonDictionary::Check(py_obj)) 52322c8efcdSZachary Turner { 524f8b22f8fSZachary Turner PythonObject::Reset(); 525f8b22f8fSZachary Turner return; 52622c8efcdSZachary Turner } 52722c8efcdSZachary Turner 528f8b22f8fSZachary Turner // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls 529f8b22f8fSZachary Turner // back into the virtual implementation. 530f8b22f8fSZachary Turner PythonObject::Reset(PyRefType::Borrowed, result.get()); 5312c1f46dcSZachary Turner } 5322c1f46dcSZachary Turner 5332c1f46dcSZachary Turner uint32_t 5342c1f46dcSZachary Turner PythonDictionary::GetSize() const 5352c1f46dcSZachary Turner { 536f8b22f8fSZachary Turner if (IsValid()) 5372c1f46dcSZachary Turner return PyDict_Size(m_py_obj); 5382c1f46dcSZachary Turner return 0; 5392c1f46dcSZachary Turner } 5402c1f46dcSZachary Turner 5412c1f46dcSZachary Turner PythonList 5422c1f46dcSZachary Turner PythonDictionary::GetKeys() const 5432c1f46dcSZachary Turner { 544f8b22f8fSZachary Turner if (IsValid()) 545f8b22f8fSZachary Turner return PythonList(PyRefType::Owned, PyDict_Keys(m_py_obj)); 546f8b22f8fSZachary Turner return PythonList(PyInitialValue::Invalid); 5472c1f46dcSZachary Turner } 5482c1f46dcSZachary Turner 5492c1f46dcSZachary Turner PythonObject 550f8b22f8fSZachary Turner PythonDictionary::GetItemForKey(const PythonObject &key) const 5512c1f46dcSZachary Turner { 552f8b22f8fSZachary Turner if (IsAllocated() && key.IsValid()) 553f8b22f8fSZachary Turner return PythonObject(PyRefType::Borrowed, PyDict_GetItem(m_py_obj, key.get())); 5542c1f46dcSZachary Turner return PythonObject(); 5552c1f46dcSZachary Turner } 5562c1f46dcSZachary Turner 5572c1f46dcSZachary Turner void 558f8b22f8fSZachary Turner PythonDictionary::SetItemForKey(const PythonObject &key, const PythonObject &value) 5592c1f46dcSZachary Turner { 560f8b22f8fSZachary Turner if (IsAllocated() && key.IsValid() && value.IsValid()) 5612c1f46dcSZachary Turner PyDict_SetItem(m_py_obj, key.get(), value.get()); 5622c1f46dcSZachary Turner } 5632c1f46dcSZachary Turner 5642c1f46dcSZachary Turner StructuredData::DictionarySP 5652c1f46dcSZachary Turner PythonDictionary::CreateStructuredDictionary() const 5662c1f46dcSZachary Turner { 5672c1f46dcSZachary Turner StructuredData::DictionarySP result(new StructuredData::Dictionary); 5682c1f46dcSZachary Turner PythonList keys(GetKeys()); 5692c1f46dcSZachary Turner uint32_t num_keys = keys.GetSize(); 5702c1f46dcSZachary Turner for (uint32_t i = 0; i < num_keys; ++i) 5712c1f46dcSZachary Turner { 5722c1f46dcSZachary Turner PythonObject key = keys.GetItemAtIndex(i); 5732c1f46dcSZachary Turner PythonObject value = GetItemForKey(key); 5742c1f46dcSZachary Turner StructuredData::ObjectSP structured_value = value.CreateStructuredObject(); 575f8b22f8fSZachary Turner result->AddItem(key.Str().GetString(), structured_value); 5762c1f46dcSZachary Turner } 5772c1f46dcSZachary Turner return result; 5782c1f46dcSZachary Turner } 5792c1f46dcSZachary Turner 5802c1f46dcSZachary Turner #endif 581