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 70*18426935SZachary Turner if (PythonList::Check(m_py_obj)) 712c1f46dcSZachary Turner return PyObjectType::List; 72*18426935SZachary Turner if (PythonDictionary::Check(m_py_obj)) 732c1f46dcSZachary Turner return PyObjectType::Dictionary; 74*18426935SZachary Turner if (PythonString::Check(m_py_obj)) 7522c8efcdSZachary Turner return PyObjectType::String; 76*18426935SZachary Turner if (PythonInteger::Check(m_py_obj)) 7722c8efcdSZachary Turner return PyObjectType::Integer; 782c1f46dcSZachary Turner return PyObjectType::Unknown; 792c1f46dcSZachary Turner } 802c1f46dcSZachary Turner 812c1f46dcSZachary Turner PythonString 822c1f46dcSZachary Turner PythonObject::Repr() 832c1f46dcSZachary Turner { 842c1f46dcSZachary Turner if (!m_py_obj) 852c1f46dcSZachary Turner return PythonString(); 862c1f46dcSZachary Turner PyObject *repr = PyObject_Repr(m_py_obj); 872c1f46dcSZachary Turner if (!repr) 882c1f46dcSZachary Turner return PythonString(); 89f8b22f8fSZachary Turner return PythonString(PyRefType::Owned, repr); 902c1f46dcSZachary Turner } 912c1f46dcSZachary Turner 922c1f46dcSZachary Turner PythonString 932c1f46dcSZachary Turner PythonObject::Str() 942c1f46dcSZachary Turner { 952c1f46dcSZachary Turner if (!m_py_obj) 962c1f46dcSZachary Turner return PythonString(); 972c1f46dcSZachary Turner PyObject *str = PyObject_Str(m_py_obj); 982c1f46dcSZachary Turner if (!str) 992c1f46dcSZachary Turner return PythonString(); 100f8b22f8fSZachary Turner return PythonString(PyRefType::Owned, str); 1012c1f46dcSZachary Turner } 1022c1f46dcSZachary Turner 1032c1f46dcSZachary Turner bool 104f8b22f8fSZachary Turner PythonObject::IsNone() const 1052c1f46dcSZachary Turner { 106f8b22f8fSZachary Turner return m_py_obj == Py_None; 107f8b22f8fSZachary Turner } 108f8b22f8fSZachary Turner 109f8b22f8fSZachary Turner bool 110f8b22f8fSZachary Turner PythonObject::IsValid() const 111f8b22f8fSZachary Turner { 112f8b22f8fSZachary Turner return m_py_obj != nullptr; 113f8b22f8fSZachary Turner } 114f8b22f8fSZachary Turner 115f8b22f8fSZachary Turner bool 116f8b22f8fSZachary Turner PythonObject::IsAllocated() const 117f8b22f8fSZachary Turner { 118f8b22f8fSZachary Turner return IsValid() && !IsNone(); 1192c1f46dcSZachary Turner } 1202c1f46dcSZachary Turner 1212c1f46dcSZachary Turner StructuredData::ObjectSP 1222c1f46dcSZachary Turner PythonObject::CreateStructuredObject() const 1232c1f46dcSZachary Turner { 1242c1f46dcSZachary Turner switch (GetObjectType()) 1252c1f46dcSZachary Turner { 1262c1f46dcSZachary Turner case PyObjectType::Dictionary: 127f8b22f8fSZachary Turner return PythonDictionary(PyRefType::Borrowed, m_py_obj).CreateStructuredDictionary(); 1282c1f46dcSZachary Turner case PyObjectType::Integer: 129f8b22f8fSZachary Turner return PythonInteger(PyRefType::Borrowed, m_py_obj).CreateStructuredInteger(); 1302c1f46dcSZachary Turner case PyObjectType::List: 131f8b22f8fSZachary Turner return PythonList(PyRefType::Borrowed, m_py_obj).CreateStructuredArray(); 1322c1f46dcSZachary Turner case PyObjectType::String: 133f8b22f8fSZachary Turner return PythonString(PyRefType::Borrowed, m_py_obj).CreateStructuredString(); 1342c1f46dcSZachary Turner case PyObjectType::None: 1352c1f46dcSZachary Turner return StructuredData::ObjectSP(); 1362c1f46dcSZachary Turner default: 1372c1f46dcSZachary Turner return StructuredData::ObjectSP(new StructuredPythonObject(m_py_obj)); 1382c1f46dcSZachary Turner } 1392c1f46dcSZachary Turner } 1402c1f46dcSZachary Turner 1412c1f46dcSZachary Turner //---------------------------------------------------------------------- 1422c1f46dcSZachary Turner // PythonString 1432c1f46dcSZachary Turner //---------------------------------------------------------------------- 1442c1f46dcSZachary Turner 145f8b22f8fSZachary Turner PythonString::PythonString(PyRefType type, PyObject *py_obj) 146f8b22f8fSZachary Turner : PythonObject() 1472c1f46dcSZachary Turner { 148f8b22f8fSZachary Turner Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a string 1492c1f46dcSZachary Turner } 1502c1f46dcSZachary Turner 151f8b22f8fSZachary Turner PythonString::PythonString(const PythonString &object) 152f8b22f8fSZachary Turner : PythonObject(object) 1532c1f46dcSZachary Turner { 1542c1f46dcSZachary Turner } 1552c1f46dcSZachary Turner 15622c8efcdSZachary Turner PythonString::PythonString(llvm::StringRef string) 15722c8efcdSZachary Turner : PythonObject() 1582c1f46dcSZachary Turner { 15922c8efcdSZachary Turner SetString(string); 1602c1f46dcSZachary Turner } 1612c1f46dcSZachary Turner 16222c8efcdSZachary Turner PythonString::PythonString(const char *string) 16322c8efcdSZachary Turner : PythonObject() 1642c1f46dcSZachary Turner { 16522c8efcdSZachary Turner SetString(llvm::StringRef(string)); 1662c1f46dcSZachary Turner } 1672c1f46dcSZachary Turner 168f8b22f8fSZachary Turner PythonString::PythonString() 169f8b22f8fSZachary Turner : PythonObject() 1702c1f46dcSZachary Turner { 1712c1f46dcSZachary Turner } 1722c1f46dcSZachary Turner 1732c1f46dcSZachary Turner PythonString::~PythonString () 1742c1f46dcSZachary Turner { 1752c1f46dcSZachary Turner } 1762c1f46dcSZachary Turner 1772c1f46dcSZachary Turner bool 17822c8efcdSZachary Turner PythonString::Check(PyObject *py_obj) 17922c8efcdSZachary Turner { 18022c8efcdSZachary Turner if (!py_obj) 18122c8efcdSZachary Turner return false; 182*18426935SZachary Turner 18322c8efcdSZachary Turner #if PY_MAJOR_VERSION >= 3 18422c8efcdSZachary Turner return PyUnicode_Check(py_obj); 18522c8efcdSZachary Turner #else 186*18426935SZachary Turner return PyString_Check(py_obj); 18722c8efcdSZachary Turner #endif 18822c8efcdSZachary Turner } 18922c8efcdSZachary Turner 190f8b22f8fSZachary Turner void 191f8b22f8fSZachary Turner PythonString::Reset(PyRefType type, PyObject *py_obj) 1922c1f46dcSZachary Turner { 193f8b22f8fSZachary Turner // Grab the desired reference type so that if we end up rejecting 194f8b22f8fSZachary Turner // `py_obj` it still gets decremented if necessary. 195f8b22f8fSZachary Turner PythonObject result(type, py_obj); 196f8b22f8fSZachary Turner 19722c8efcdSZachary Turner if (!PythonString::Check(py_obj)) 19822c8efcdSZachary Turner { 199f8b22f8fSZachary Turner PythonObject::Reset(); 200f8b22f8fSZachary Turner return; 20122c8efcdSZachary Turner } 20222c8efcdSZachary Turner 203f8b22f8fSZachary Turner // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls 204f8b22f8fSZachary Turner // back into the virtual implementation. 205f8b22f8fSZachary Turner PythonObject::Reset(PyRefType::Borrowed, result.get()); 2062c1f46dcSZachary Turner } 2072c1f46dcSZachary Turner 2082c1f46dcSZachary Turner llvm::StringRef 2092c1f46dcSZachary Turner PythonString::GetString() const 2102c1f46dcSZachary Turner { 211*18426935SZachary Turner if (!IsValid()) 212*18426935SZachary Turner return llvm::StringRef(); 213*18426935SZachary Turner 21422c8efcdSZachary Turner Py_ssize_t size; 21522c8efcdSZachary Turner char *c; 216*18426935SZachary Turner 217*18426935SZachary Turner #if PY_MAJOR_VERSION >= 3 218*18426935SZachary Turner c = PyUnicode_AsUTF8AndSize(m_py_obj, &size); 219*18426935SZachary Turner #else 220*18426935SZachary Turner PyString_AsStringAndSize(m_py_obj, &c, &size); 221*18426935SZachary Turner #endif 22222c8efcdSZachary Turner return llvm::StringRef(c, size); 22322c8efcdSZachary Turner } 2242c1f46dcSZachary Turner 2252c1f46dcSZachary Turner size_t 2262c1f46dcSZachary Turner PythonString::GetSize() const 2272c1f46dcSZachary Turner { 228f8b22f8fSZachary Turner if (IsValid()) 229*18426935SZachary Turner { 230*18426935SZachary Turner #if PY_MAJOR_VERSION >= 3 231*18426935SZachary Turner return PyUnicode_GetSize(m_py_obj); 232*18426935SZachary Turner #else 233*18426935SZachary Turner return PyString_Size(m_py_obj); 234*18426935SZachary Turner #endif 235*18426935SZachary Turner } 2362c1f46dcSZachary Turner return 0; 2372c1f46dcSZachary Turner } 2382c1f46dcSZachary Turner 2392c1f46dcSZachary Turner void 2402c1f46dcSZachary Turner PythonString::SetString (llvm::StringRef string) 2412c1f46dcSZachary Turner { 24222c8efcdSZachary Turner #if PY_MAJOR_VERSION >= 3 24322c8efcdSZachary Turner PyObject *unicode = PyUnicode_FromStringAndSize(string.data(), string.size()); 244*18426935SZachary Turner PythonObject::Reset(PyRefType::Owned, unicode); 24522c8efcdSZachary Turner #else 246*18426935SZachary Turner PyObject *str = PyString_FromStringAndSize(string.data(), string.size()); 247*18426935SZachary Turner PythonObject::Reset(PyRefType::Owned, str); 24822c8efcdSZachary Turner #endif 2492c1f46dcSZachary Turner } 2502c1f46dcSZachary Turner 2512c1f46dcSZachary Turner StructuredData::StringSP 2522c1f46dcSZachary Turner PythonString::CreateStructuredString() const 2532c1f46dcSZachary Turner { 2542c1f46dcSZachary Turner StructuredData::StringSP result(new StructuredData::String); 2552c1f46dcSZachary Turner result->SetValue(GetString()); 2562c1f46dcSZachary Turner return result; 2572c1f46dcSZachary Turner } 2582c1f46dcSZachary Turner 2592c1f46dcSZachary Turner //---------------------------------------------------------------------- 2602c1f46dcSZachary Turner // PythonInteger 2612c1f46dcSZachary Turner //---------------------------------------------------------------------- 2622c1f46dcSZachary Turner 263f8b22f8fSZachary Turner PythonInteger::PythonInteger(PyRefType type, PyObject *py_obj) 264f8b22f8fSZachary Turner : PythonObject() 2652c1f46dcSZachary Turner { 266f8b22f8fSZachary Turner Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a integer type 2672c1f46dcSZachary Turner } 2682c1f46dcSZachary Turner 269f8b22f8fSZachary Turner PythonInteger::PythonInteger(const PythonInteger &object) 270f8b22f8fSZachary Turner : PythonObject(object) 2712c1f46dcSZachary Turner { 2722c1f46dcSZachary Turner } 2732c1f46dcSZachary Turner 274f8b22f8fSZachary Turner PythonInteger::PythonInteger(int64_t value) 275f8b22f8fSZachary Turner : PythonObject() 2762c1f46dcSZachary Turner { 2772c1f46dcSZachary Turner SetInteger(value); 2782c1f46dcSZachary Turner } 2792c1f46dcSZachary Turner 2802c1f46dcSZachary Turner 2812c1f46dcSZachary Turner PythonInteger::~PythonInteger () 2822c1f46dcSZachary Turner { 2832c1f46dcSZachary Turner } 2842c1f46dcSZachary Turner 2852c1f46dcSZachary Turner bool 28622c8efcdSZachary Turner PythonInteger::Check(PyObject *py_obj) 2872c1f46dcSZachary Turner { 28822c8efcdSZachary Turner if (!py_obj) 28922c8efcdSZachary Turner return false; 29022c8efcdSZachary Turner 29122c8efcdSZachary Turner #if PY_MAJOR_VERSION >= 3 29222c8efcdSZachary Turner // Python 3 does not have PyInt_Check. There is only one type of 29322c8efcdSZachary Turner // integral value, long. 29422c8efcdSZachary Turner return PyLong_Check(py_obj); 29522c8efcdSZachary Turner #else 29622c8efcdSZachary Turner return PyLong_Check(py_obj) || PyInt_Check(py_obj); 29722c8efcdSZachary Turner #endif 2982c1f46dcSZachary Turner } 2992c1f46dcSZachary Turner 300f8b22f8fSZachary Turner void 301f8b22f8fSZachary Turner PythonInteger::Reset(PyRefType type, PyObject *py_obj) 30222c8efcdSZachary Turner { 303f8b22f8fSZachary Turner // Grab the desired reference type so that if we end up rejecting 304f8b22f8fSZachary Turner // `py_obj` it still gets decremented if necessary. 305f8b22f8fSZachary Turner PythonObject result(type, py_obj); 306f8b22f8fSZachary Turner 30722c8efcdSZachary Turner if (!PythonInteger::Check(py_obj)) 30822c8efcdSZachary Turner { 309f8b22f8fSZachary Turner PythonObject::Reset(); 310f8b22f8fSZachary Turner return; 31122c8efcdSZachary Turner } 31222c8efcdSZachary Turner 31322c8efcdSZachary Turner #if PY_MAJOR_VERSION < 3 31422c8efcdSZachary Turner // Always store this as a PyLong, which makes interoperability between 31522c8efcdSZachary Turner // Python 2.x and Python 3.x easier. This is only necessary in 2.x, 31622c8efcdSZachary Turner // since 3.x doesn't even have a PyInt. 31722c8efcdSZachary Turner if (PyInt_Check(py_obj)) 31822c8efcdSZachary Turner { 319f8b22f8fSZachary Turner // Since we converted the original object to a different type, the new 320f8b22f8fSZachary Turner // object is an owned object regardless of the ownership semantics requested 321f8b22f8fSZachary Turner // by the user. 322f8b22f8fSZachary Turner result.Reset(PyRefType::Owned, PyLong_FromLongLong(PyInt_AsLong(py_obj))); 32322c8efcdSZachary Turner } 32422c8efcdSZachary Turner #endif 32522c8efcdSZachary Turner 326f8b22f8fSZachary Turner assert(PyLong_Check(result.get()) && "Couldn't get a PyLong from this PyObject"); 32722c8efcdSZachary Turner 328f8b22f8fSZachary Turner // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls 329f8b22f8fSZachary Turner // back into the virtual implementation. 330f8b22f8fSZachary Turner PythonObject::Reset(PyRefType::Borrowed, result.get()); 3312c1f46dcSZachary Turner } 3322c1f46dcSZachary Turner 3332c1f46dcSZachary Turner int64_t 3342c1f46dcSZachary Turner PythonInteger::GetInteger() const 3352c1f46dcSZachary Turner { 3362c1f46dcSZachary Turner if (m_py_obj) 3372c1f46dcSZachary Turner { 33822c8efcdSZachary Turner assert(PyLong_Check(m_py_obj) && "PythonInteger::GetInteger has a PyObject that isn't a PyLong"); 33922c8efcdSZachary Turner 3402c1f46dcSZachary Turner return PyLong_AsLongLong(m_py_obj); 3412c1f46dcSZachary Turner } 3422c1f46dcSZachary Turner return UINT64_MAX; 3432c1f46dcSZachary Turner } 3442c1f46dcSZachary Turner 3452c1f46dcSZachary Turner void 3462c1f46dcSZachary Turner PythonInteger::SetInteger(int64_t value) 3472c1f46dcSZachary Turner { 348f8b22f8fSZachary Turner PythonObject::Reset(PyRefType::Owned, PyLong_FromLongLong(value)); 3492c1f46dcSZachary Turner } 3502c1f46dcSZachary Turner 3512c1f46dcSZachary Turner StructuredData::IntegerSP 3522c1f46dcSZachary Turner PythonInteger::CreateStructuredInteger() const 3532c1f46dcSZachary Turner { 3542c1f46dcSZachary Turner StructuredData::IntegerSP result(new StructuredData::Integer); 3552c1f46dcSZachary Turner result->SetValue(GetInteger()); 3562c1f46dcSZachary Turner return result; 3572c1f46dcSZachary Turner } 3582c1f46dcSZachary Turner 3592c1f46dcSZachary Turner //---------------------------------------------------------------------- 3602c1f46dcSZachary Turner // PythonList 3612c1f46dcSZachary Turner //---------------------------------------------------------------------- 3622c1f46dcSZachary Turner 363f8b22f8fSZachary Turner PythonList::PythonList(PyInitialValue value) 364f8b22f8fSZachary Turner : PythonObject() 3652c1f46dcSZachary Turner { 366f8b22f8fSZachary Turner if (value == PyInitialValue::Empty) 367f8b22f8fSZachary Turner Reset(PyRefType::Owned, PyList_New(0)); 3682c1f46dcSZachary Turner } 3692c1f46dcSZachary Turner 37087f47729SZachary Turner PythonList::PythonList(int list_size) 37187f47729SZachary Turner : PythonObject() 37287f47729SZachary Turner { 37387f47729SZachary Turner Reset(PyRefType::Owned, PyList_New(list_size)); 37487f47729SZachary Turner } 37587f47729SZachary Turner 376f8b22f8fSZachary Turner PythonList::PythonList(PyRefType type, PyObject *py_obj) 377f8b22f8fSZachary Turner : PythonObject() 3782c1f46dcSZachary Turner { 379f8b22f8fSZachary Turner Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a list 3802c1f46dcSZachary Turner } 3812c1f46dcSZachary Turner 382f8b22f8fSZachary Turner PythonList::PythonList(const PythonList &list) 383f8b22f8fSZachary Turner : PythonObject(list) 3842c1f46dcSZachary Turner { 3852c1f46dcSZachary Turner } 3862c1f46dcSZachary Turner 3872c1f46dcSZachary Turner PythonList::~PythonList () 3882c1f46dcSZachary Turner { 3892c1f46dcSZachary Turner } 3902c1f46dcSZachary Turner 3912c1f46dcSZachary Turner bool 39222c8efcdSZachary Turner PythonList::Check(PyObject *py_obj) 39322c8efcdSZachary Turner { 39422c8efcdSZachary Turner if (!py_obj) 39522c8efcdSZachary Turner return false; 39622c8efcdSZachary Turner return PyList_Check(py_obj); 39722c8efcdSZachary Turner } 39822c8efcdSZachary Turner 399f8b22f8fSZachary Turner void 400f8b22f8fSZachary Turner PythonList::Reset(PyRefType type, PyObject *py_obj) 4012c1f46dcSZachary Turner { 402f8b22f8fSZachary Turner // Grab the desired reference type so that if we end up rejecting 403f8b22f8fSZachary Turner // `py_obj` it still gets decremented if necessary. 404f8b22f8fSZachary Turner PythonObject result(type, py_obj); 405f8b22f8fSZachary Turner 40622c8efcdSZachary Turner if (!PythonList::Check(py_obj)) 40722c8efcdSZachary Turner { 408f8b22f8fSZachary Turner PythonObject::Reset(); 409f8b22f8fSZachary Turner return; 41022c8efcdSZachary Turner } 41122c8efcdSZachary Turner 412f8b22f8fSZachary Turner // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls 413f8b22f8fSZachary Turner // back into the virtual implementation. 414f8b22f8fSZachary Turner PythonObject::Reset(PyRefType::Borrowed, result.get()); 4152c1f46dcSZachary Turner } 4162c1f46dcSZachary Turner 4172c1f46dcSZachary Turner uint32_t 4182c1f46dcSZachary Turner PythonList::GetSize() const 4192c1f46dcSZachary Turner { 420f8b22f8fSZachary Turner if (IsValid()) 4212c1f46dcSZachary Turner return PyList_GET_SIZE(m_py_obj); 4222c1f46dcSZachary Turner return 0; 4232c1f46dcSZachary Turner } 4242c1f46dcSZachary Turner 4252c1f46dcSZachary Turner PythonObject 4262c1f46dcSZachary Turner PythonList::GetItemAtIndex(uint32_t index) const 4272c1f46dcSZachary Turner { 428f8b22f8fSZachary Turner if (IsValid()) 429f8b22f8fSZachary Turner return PythonObject(PyRefType::Borrowed, PyList_GetItem(m_py_obj, index)); 4302c1f46dcSZachary Turner return PythonObject(); 4312c1f46dcSZachary Turner } 4322c1f46dcSZachary Turner 4332c1f46dcSZachary Turner void 4342c1f46dcSZachary Turner PythonList::SetItemAtIndex(uint32_t index, const PythonObject &object) 4352c1f46dcSZachary Turner { 436f8b22f8fSZachary Turner if (IsAllocated() && object.IsValid()) 437f8b22f8fSZachary Turner { 438f8b22f8fSZachary Turner // PyList_SetItem is documented to "steal" a reference, so we need to 439f8b22f8fSZachary Turner // convert it to an owned reference by incrementing it. 440f8b22f8fSZachary Turner Py_INCREF(object.get()); 4412c1f46dcSZachary Turner PyList_SetItem(m_py_obj, index, object.get()); 4422c1f46dcSZachary Turner } 443f8b22f8fSZachary Turner } 4442c1f46dcSZachary Turner 4452c1f46dcSZachary Turner void 4462c1f46dcSZachary Turner PythonList::AppendItem(const PythonObject &object) 4472c1f46dcSZachary Turner { 448f8b22f8fSZachary Turner if (IsAllocated() && object.IsValid()) 449f8b22f8fSZachary Turner { 450f8b22f8fSZachary Turner // `PyList_Append` does *not* steal a reference, so do not call `Py_INCREF` 451f8b22f8fSZachary Turner // here like we do with `PyList_SetItem`. 4522c1f46dcSZachary Turner PyList_Append(m_py_obj, object.get()); 4532c1f46dcSZachary Turner } 454f8b22f8fSZachary Turner } 4552c1f46dcSZachary Turner 4562c1f46dcSZachary Turner StructuredData::ArraySP 4572c1f46dcSZachary Turner PythonList::CreateStructuredArray() const 4582c1f46dcSZachary Turner { 4592c1f46dcSZachary Turner StructuredData::ArraySP result(new StructuredData::Array); 4602c1f46dcSZachary Turner uint32_t count = GetSize(); 4612c1f46dcSZachary Turner for (uint32_t i = 0; i < count; ++i) 4622c1f46dcSZachary Turner { 4632c1f46dcSZachary Turner PythonObject obj = GetItemAtIndex(i); 4642c1f46dcSZachary Turner result->AddItem(obj.CreateStructuredObject()); 4652c1f46dcSZachary Turner } 4662c1f46dcSZachary Turner return result; 4672c1f46dcSZachary Turner } 4682c1f46dcSZachary Turner 4692c1f46dcSZachary Turner //---------------------------------------------------------------------- 4702c1f46dcSZachary Turner // PythonDictionary 4712c1f46dcSZachary Turner //---------------------------------------------------------------------- 4722c1f46dcSZachary Turner 473f8b22f8fSZachary Turner PythonDictionary::PythonDictionary(PyInitialValue value) 474f8b22f8fSZachary Turner : PythonObject() 4752c1f46dcSZachary Turner { 476f8b22f8fSZachary Turner if (value == PyInitialValue::Empty) 477f8b22f8fSZachary Turner Reset(PyRefType::Owned, PyDict_New()); 4782c1f46dcSZachary Turner } 4792c1f46dcSZachary Turner 480f8b22f8fSZachary Turner PythonDictionary::PythonDictionary(PyRefType type, PyObject *py_obj) 481f8b22f8fSZachary Turner : PythonObject() 4822c1f46dcSZachary Turner { 483f8b22f8fSZachary Turner Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a dictionary 4842c1f46dcSZachary Turner } 4852c1f46dcSZachary Turner 486f8b22f8fSZachary Turner PythonDictionary::PythonDictionary(const PythonDictionary &object) 487f8b22f8fSZachary Turner : PythonObject(object) 4882c1f46dcSZachary Turner { 4892c1f46dcSZachary Turner } 4902c1f46dcSZachary Turner 4912c1f46dcSZachary Turner PythonDictionary::~PythonDictionary () 4922c1f46dcSZachary Turner { 4932c1f46dcSZachary Turner } 4942c1f46dcSZachary Turner 4952c1f46dcSZachary Turner bool 49622c8efcdSZachary Turner PythonDictionary::Check(PyObject *py_obj) 49722c8efcdSZachary Turner { 49822c8efcdSZachary Turner if (!py_obj) 49922c8efcdSZachary Turner return false; 50022c8efcdSZachary Turner 50122c8efcdSZachary Turner return PyDict_Check(py_obj); 50222c8efcdSZachary Turner } 50322c8efcdSZachary Turner 504f8b22f8fSZachary Turner void 505f8b22f8fSZachary Turner PythonDictionary::Reset(PyRefType type, PyObject *py_obj) 5062c1f46dcSZachary Turner { 507f8b22f8fSZachary Turner // Grab the desired reference type so that if we end up rejecting 508f8b22f8fSZachary Turner // `py_obj` it still gets decremented if necessary. 509f8b22f8fSZachary Turner PythonObject result(type, py_obj); 510f8b22f8fSZachary Turner 51122c8efcdSZachary Turner if (!PythonDictionary::Check(py_obj)) 51222c8efcdSZachary Turner { 513f8b22f8fSZachary Turner PythonObject::Reset(); 514f8b22f8fSZachary Turner return; 51522c8efcdSZachary Turner } 51622c8efcdSZachary Turner 517f8b22f8fSZachary Turner // Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls 518f8b22f8fSZachary Turner // back into the virtual implementation. 519f8b22f8fSZachary Turner PythonObject::Reset(PyRefType::Borrowed, result.get()); 5202c1f46dcSZachary Turner } 5212c1f46dcSZachary Turner 5222c1f46dcSZachary Turner uint32_t 5232c1f46dcSZachary Turner PythonDictionary::GetSize() const 5242c1f46dcSZachary Turner { 525f8b22f8fSZachary Turner if (IsValid()) 5262c1f46dcSZachary Turner return PyDict_Size(m_py_obj); 5272c1f46dcSZachary Turner return 0; 5282c1f46dcSZachary Turner } 5292c1f46dcSZachary Turner 5302c1f46dcSZachary Turner PythonList 5312c1f46dcSZachary Turner PythonDictionary::GetKeys() const 5322c1f46dcSZachary Turner { 533f8b22f8fSZachary Turner if (IsValid()) 534f8b22f8fSZachary Turner return PythonList(PyRefType::Owned, PyDict_Keys(m_py_obj)); 535f8b22f8fSZachary Turner return PythonList(PyInitialValue::Invalid); 5362c1f46dcSZachary Turner } 5372c1f46dcSZachary Turner 5382c1f46dcSZachary Turner PythonObject 539f8b22f8fSZachary Turner PythonDictionary::GetItemForKey(const PythonObject &key) const 5402c1f46dcSZachary Turner { 541f8b22f8fSZachary Turner if (IsAllocated() && key.IsValid()) 542f8b22f8fSZachary Turner return PythonObject(PyRefType::Borrowed, PyDict_GetItem(m_py_obj, key.get())); 5432c1f46dcSZachary Turner return PythonObject(); 5442c1f46dcSZachary Turner } 5452c1f46dcSZachary Turner 5462c1f46dcSZachary Turner void 547f8b22f8fSZachary Turner PythonDictionary::SetItemForKey(const PythonObject &key, const PythonObject &value) 5482c1f46dcSZachary Turner { 549f8b22f8fSZachary Turner if (IsAllocated() && key.IsValid() && value.IsValid()) 5502c1f46dcSZachary Turner PyDict_SetItem(m_py_obj, key.get(), value.get()); 5512c1f46dcSZachary Turner } 5522c1f46dcSZachary Turner 5532c1f46dcSZachary Turner StructuredData::DictionarySP 5542c1f46dcSZachary Turner PythonDictionary::CreateStructuredDictionary() const 5552c1f46dcSZachary Turner { 5562c1f46dcSZachary Turner StructuredData::DictionarySP result(new StructuredData::Dictionary); 5572c1f46dcSZachary Turner PythonList keys(GetKeys()); 5582c1f46dcSZachary Turner uint32_t num_keys = keys.GetSize(); 5592c1f46dcSZachary Turner for (uint32_t i = 0; i < num_keys; ++i) 5602c1f46dcSZachary Turner { 5612c1f46dcSZachary Turner PythonObject key = keys.GetItemAtIndex(i); 5622c1f46dcSZachary Turner PythonObject value = GetItemForKey(key); 5632c1f46dcSZachary Turner StructuredData::ObjectSP structured_value = value.CreateStructuredObject(); 564f8b22f8fSZachary Turner result->AddItem(key.Str().GetString(), structured_value); 5652c1f46dcSZachary Turner } 5662c1f46dcSZachary Turner return result; 5672c1f46dcSZachary Turner } 5682c1f46dcSZachary Turner 5692c1f46dcSZachary Turner #endif 570