pyobjectholder.h 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. // Copyright (C) 2024 The Qt Company Ltd.
  2. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
  3. #ifndef PYOBJECTHOLDER_H
  4. #define PYOBJECTHOLDER_H
  5. #include "sbkpython.h"
  6. #include <cassert>
  7. #include <utility>
  8. namespace Shiboken
  9. {
  10. /// PyObjectHolder holds a PyObject pointer, keeping a reference decrementing
  11. /// its reference counter when destroyed. It makes sure to hold the GIL when
  12. /// releasing. It implements copy/move semantics and is mainly intended as a
  13. /// base class for functors holding a callable which can be passed around and
  14. /// stored in containers or moved from freely.
  15. /// For one-shot functors, release() can be invoked after the call.
  16. class PyObjectHolder
  17. {
  18. public:
  19. PyObjectHolder() noexcept = default;
  20. /// PyObjectHolder constructor.
  21. /// \param pyobj A reference to a Python object
  22. explicit PyObjectHolder(PyObject *pyObj) noexcept : m_pyObj(pyObj)
  23. {
  24. assert(pyObj != nullptr);
  25. Py_INCREF(m_pyObj);
  26. }
  27. PyObjectHolder(const PyObjectHolder &o) noexcept : m_pyObj(o.m_pyObj)
  28. {
  29. Py_XINCREF(m_pyObj);
  30. }
  31. PyObjectHolder &operator=(const PyObjectHolder &o) noexcept
  32. {
  33. if (this != &o) {
  34. m_pyObj = o.m_pyObj;
  35. Py_XINCREF(m_pyObj);
  36. }
  37. return *this;
  38. }
  39. PyObjectHolder(PyObjectHolder &&o) noexcept : m_pyObj{std::exchange(o.m_pyObj, nullptr)} {}
  40. PyObjectHolder &operator=(PyObjectHolder &&o) noexcept
  41. {
  42. m_pyObj = std::exchange(o.m_pyObj, nullptr);
  43. return *this;
  44. }
  45. /// Decref the python reference
  46. ~PyObjectHolder() { release(); }
  47. [[nodiscard]] bool isNull() const { return m_pyObj == nullptr; }
  48. [[nodiscard]] operator bool() const { return m_pyObj != nullptr; }
  49. /// Returns the pointer of the Python object being held.
  50. [[nodiscard]] PyObject *object() const { return m_pyObj; }
  51. [[nodiscard]] operator PyObject *() const { return m_pyObj; }
  52. [[nodiscard]] PyObject *operator->() { return m_pyObj; }
  53. protected:
  54. void release()
  55. {
  56. if (m_pyObj != nullptr) {
  57. assert(Py_IsInitialized());
  58. auto gstate = PyGILState_Ensure();
  59. Py_DECREF(m_pyObj);
  60. PyGILState_Release(gstate);
  61. m_pyObj = nullptr;
  62. }
  63. }
  64. private:
  65. PyObject *m_pyObj = nullptr;
  66. };
  67. } // namespace Shiboken
  68. #endif // PYOBJECTHOLDER_H