8000 Refcounting Smart Pointers by insertinterestingnamehere · Pull Request #702 · libdynd/dynd-python · GitHub
[go: up one dir, main page]

Skip to content

Refcounting Smart Pointers #702

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
d7ac59e
Add smart pointer classes for managing pyobject pointers.
insertinterestingnamehere May 24, 2016
844d532
Update dynd-python codebase to use new py_ref class.
insertinterestingnamehere May 24, 2016
3658354
Fix MSVC compilation error.
insertinterestingnamehere Jun 3, 2016
acca45b
Rewrite smart pointers that encapsulate Python references.
insertinterestingnamehere Jun 4, 2016
ecc96d3
Add RAII class to release the GIL.
insertinterestingnamehere Jun 6, 2016
fb7d0eb
Add explicit syntax for borrowing a reference from a wrapped PyObject*.
insertinterestingnamehere Jun 9, 2016
791696a
Add convenience function for null-checking a smart pointer wrapping a
insertinterestingnamehere Jun 9, 2016
24d4a32
Add a convenience function to aid in casting from a possibly null
insertinterestingnamehere Jun 9, 2016
4d0d38e
Add a series of assert statements to ensure that wrapped references
insertinterestingnamehere Jun 9, 2016
ebeb883
Make release method for py_ref return an owned or borrowed reference
insertinterestingnamehere Jun 9, 2016
059e012
Move the release method of pydynd::py_ref_tmpl to be a function that …
insertinterestingnamehere Jun 9, 2016
7f2eaba
Rename py_ref_tmpl to py_ref_t.
insertinterestingnamehere Jun 9, 2016
495faf4
Add a method to get an owned reference from a given reference.
insertinterestingnamehere Jun 9, 2016
a1aa405
Add method to py_ref_t to create a new owned reference from a given
insertinterestingnamehere Jun 9, 2016
7962d97
Add method to py_ref_t to copy the current reference.
insertinterestingnamehere Jun 9, 2016
fc522f4
Fix typo in disallow_null where release was not correctly used.
insertinterestingnamehere Jun 10, 2016
9e8bf42
Close a reference leak in smart pointers for managing PyObject pointers.
insertinterestingnamehere Jun 22, 2016
4d9ec89
Add more commenting to the new py_ref classes.
insertinterestingnamehere Aug 3, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Rename py_ref_tmpl to py_ref_t.
  • Loading branch information
insertinterestingnamehere committed Jul 1, 2016
commit 7f2eaba4988284ffd7bf3325ef147f31250c59ec
58 changes: 29 additions & 29 deletions dynd/include/utility_functions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,15 @@ inline void decref_if_owned<false, false>(PyObject *obj) noexcept
}

template <bool owns_ref = true, bool not_null = true>
class py_ref_tmpl {
class py_ref_t {
PyObject *o;

public:
// All versions default-initialize to null.
// This allows the smart pointer class to be moved from.
// Whether or not the class is allowed to be null only changes
// when zerochecks/exceptions may occur and when assertions are used.
py_ref_tmpl() noexcept : o(nullptr){};
py_ref_t() noexcept : o(nullptr){};

// First define an accessor to get the PyObject pointer from
// the wrapper class.
Expand All @@ -151,11 +151,11 @@ class py_ref_tmpl {
/* If:
* This type allows null or the input type does not,
* Then:
* Conversions from the other py_ref_tmpl type to this type do not raise exceptions.
* Conversions from the other py_ref_t type to this type do not raise exceptions.
*/
template <bool other_owns_ref, bool other_not_null,
typename std::enable_if_t<other_not_null || !not_null> * = nullptr>
py_ref_tmpl(const py_ref_tmpl<other_owns_ref, other_not_null> &other) noexcept
py_ref_t(const py_ref_t<other_owns_ref, other_not_null> &other) noexcept
{
// If the input is not null, assert that it isn't.
PYDYND_ASSERT_IF(other_not_null, other.o != nullptr);
Expand All @@ -175,7 +175,7 @@ class py_ref_tmpl {
*/
template <bool other_owns_ref, bool other_not_null,
typename std::enable_if_t<!other_not_null && not_null> * = nullptr>
py_ref_tmpl(const py_ref_tmpl<other_owns_ref, other_not_null> &other)
py_ref_t(const py_ref_t<other_owns_ref, other_not_null> &other)
{
if (other.o != nullptr) {
// Assert that the input reference is valid.
Expand All @@ -199,7 +199,7 @@ class py_ref_tmpl {
* a move operation is defined and will not raise an exception.
*/
template <bool other_not_null, typename std::enable_if_t<other_not_null || !not_null> * = nullptr>
py_ref_tmpl(py_ref_tmpl<true, other_not_null> &&other) noexcept
py_ref_t(py_ref_t<true, other_not_null> &&other) noexcept
{
// If this type is a non-null type, the assigned value should not be null.
// If the other type is a non-null type, the provided value should not be null,
Expand Down Expand Up @@ -227,7 +227,7 @@ class py_ref_tmpl {
* a move may be performed, but may also raise an exception.
*/
template <bool other_not_null, typename std::enable_if_t<!other_not_null && not_null> * = nullptr>
py_ref_tmpl(py_ref_tmpl<true, other_not_null> &&other)
py_ref_t(py_ref_t<true, other_not_null> &&other)
{
if (other.o != nullptr) {
// Assert that the input reference is valid.
Expand Down Expand Up @@ -256,7 +256,7 @@ class py_ref_tmpl {
* specify `consume_ref` as false regardless of whether or not you
* own the reference represented in the PyObject* you pass in.
*/
explicit py_ref_tmpl(PyObject *obj, bool consume_ref) noexcept
explicit py_ref_t(PyObject *obj, bool consume_ref) noexcept
{
o = obj;
if (consume_ref) {
Expand All @@ -270,7 +270,7 @@ class py_ref_tmpl {
PYDYND_ASSERT_IF(obj != nullptr, Py_REFCNT(obj) > 0);
}

~py_ref_tmpl()
~py_ref_t()
{
// A smart pointer wrapping a PyObject* still needs to be safe to
// destruct after it has been moved from.
Expand All @@ -288,11 +288,11 @@ class py_ref_tmpl {
/* If:
* This type allows null or the input type does not,
* Then:
* Assignment from the other py_ref_tmpl type to this type may not raise an exception.
* Assignment from the other py_ref_t type to this type may not raise an exception.
*/
template <bool other_owns_ref, bool other_not_null,
typename std::enable_if_t<other_not_null || !not_null> * = nullptr>
py_ref_tmpl<owns_ref, not_null> &operator=(const py_ref_tmpl<other_owns_ref, other_not_null> &other) noexcept
py_ref_t<owns_ref, not_null> &operator=(const py_ref_t<other_owns_ref, other_not_null> &other) noexcept
{
// Assert that the input reference is not null if the input type does not allow nulls.
PYDYND_ASSERT_IF(other_not_null, other.o != nullptr);
Expand All @@ -310,11 +310,11 @@ class py_ref_tmpl {
* this type does not allow null,
* and the other type does,
* Then:
* Assignment from the other py_ref_tmpl type to this type may raise an exception.
* Assignment from the other py_ref_t type to this type may raise an exception.
*/
template <bool other_owns_ref, bool other_not_null,
typename std::enable_if_t<!other_not_null && not_null> * = nullptr>
py_ref_tmpl<owns_ref, not_null> &operator=(const py_ref_tmpl<other_owns_ref, other_not_null> &other) noexcept
py_ref_t<owns_ref, not_null> &operator=(const py_ref_t<other_owns_ref, other_not_null> &other) noexcept
{
if (other.o != nullptr) {
// Assert that the input reference is valid.
Expand All @@ -339,11 +339,11 @@ class py_ref_tmpl {
* this type doesn't allow null
* and the input type doesn't allow null,
* Then:
* Assignment from the other py_ref_tmpl type to this type may not raise an exception.
* Assignment from the other py_ref_t type to this type may not raise an exception.
*/
template <bool other_owns_ref, bool other_not_null,
typename std::enable_if_t<other_not_null || !not_null> * = nullptr>
py_ref_tmpl<owns_ref, not_null> &operator=(py_ref_tmpl<other_owns_ref, other_not_null> &&other) noexcept
py_ref_t<owns_ref, not_null> &operator=(py_ref_t<other_owns_ref, other_not_null> &&other) noexcept
{
// If the input reference should not be null, assert that that is the case.
PYDYND_ASSERT_IF(other_not_null, other.o != nullptr);
Expand All @@ -362,11 +362,11 @@ class py_ref_tmpl {
* this type does not allow null,
* and the other type does,
* Then:
* Assignment from the other py_ref_tmpl type to this type may raise an exception.
* Assignment from the other py_ref_t type to this type may raise an exception.
*/
template <bool other_owns_ref, bool other_not_null,
typename std::enable_if_t<!other_not_null && not_null> * = nullptr>
py_ref_tmpl<owns_ref, not_null> &operator=(py_ref_tmpl<other_owns_ref, other_not_null> &&other) noexcept
py_ref_t<owns_ref, not_null> &operator=(py_ref_t<other_owns_ref, other_not_null> &&other) noexcept
{
if (other.o != nullptr) {
// Assert that the input reference is valid.
Expand All @@ -384,13 +384,13 @@ class py_ref_tmpl {
}
}

py_ref_tmpl<false, not_null> borrow() noexcept { return py_ref<false, not_null>(o, false); }
py_ref_t<false, not_null> borrow() noexcept { return py_ref<false, not_null>(o, false); }

// Return a reference to the encapsulated PyObject as a raw pointer.
// Set the encapsulated pointer to NULL.
// If this is a type that owns its reference, an owned reference is returned.
// If this is a type that wraps a borrowed reference, a borrowed reference is returned.
static PyObject *release(py_ref_tmpl<owns_ref, not_null> &&ref) noexcept
static PyObject *release(py_ref_t<owns_ref, not_null> &&ref) noexcept
{
// If the contained reference should not be null, assert that it isn't.
PYDYND_ASSERT_IF(not_null, ref.o != nullptr);
Expand All @@ -404,18 +404,18 @@ class py_ref_tmpl {

// Convenience aliases for the templated smart pointer classes.

using py_ref = py_ref_tmpl<true, true>;
using py_ref = py_ref_t<true, true>;

using py_ref_with_null = py_ref_tmpl<true, false>;
using py_ref_with_null = py_ref_t<true, false>;

using py_borref = py_ref_tmpl<false, true>;
using py_borref = py_ref_t<false, true>;

using py_borref_with_null = py_ref_tmpl<false, false>;
using py_borref_with_null = py_ref_t<false, false>;

template <bool owns_ref, bool not_null>
PyObject *release(py_ref_tmpl<owns_ref, not_null> &&ref)
PyObject *release(py_ref_t<owns_ref, not_null> &&ref)
{
return py_ref_tmpl<owns_ref, not_null>::release(std::forward<py_ref_tmpl<owns_ref, not_null>>(ref));
return py_ref_t<owns_ref, not_null>::release(std::forward<py_ref_t<owns_ref, not_null>>(ref));
}

/* Capture a new reference if it is not null.
Expand All @@ -435,10 +435,10 @@ inline py_ref capture_if_not_null(PyObject *o)
* only checks for via an assert statement in debug builds.
*/
template <bool owns_ref, bool not_null>
inline py_ref_tmpl<owns_ref, true> nullcheck(py_ref_tmpl<owns_ref, not_null> &&obj) noexcept(not_null)
inline py_ref_t<owns_ref, true> nullcheck(py_ref_t<owns_ref, not_null> &&obj) noexcept(not_null)
{
// Route this through the assignment operator since the semantics are the same.
py_ref_tmpl<owns_ref, true> out = obj;
py_ref_t<owns_ref, true> out = obj;
return out;
}

Expand All @@ -447,13 +447,13 @@ inline py_ref_tmpl<owns_ref, true> nullcheck(py_ref_tmpl<owns_ref, not_null> &&o
* This should be used when the pointer is already known to not be null.
*/
template <bool owns_ref, bool not_null>
inline py_ref_tmpl<owns_ref, true> disallow_null(py_ref_tmpl<owns_ref, not_null> &&obj) noexcept
inline py_ref_t<owns_ref, true> disallow_null(py_ref_t<owns_ref, not_null> &&obj) noexcept
{
// Assert that the wrapped pointer is actually not null.
assert(obj.get() != nullptr);
// Assert that the wrapped reference is valid if it is not null.
PYDYND_ASSERT_IF(obj.get() != nullptr, Py_REFCNT(obj.get()) > 0);
return py_ref_tmpl<owns_ref, true>(obj.release(), owns_ref);
return py_ref_t<owns_ref, true>(obj.release(), owns_ref);
}

// RAII class to acquire GIL.
Expand Down
0