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