HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
pyIdentity.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_BASE_TF_PY_IDENTITY_H
8 #define PXR_BASE_TF_PY_IDENTITY_H
9 
10 #include "pxr/pxr.h"
11 
12 #include "pxr/base/tf/api.h"
13 #include "pxr/base/tf/pyLock.h"
14 #include "pxr/base/tf/pyUtils.h"
15 
16 #include "pxr/base/arch/demangle.h"
17 #include "pxr/base/tf/diagnostic.h"
18 #include "pxr/base/tf/refPtr.h"
21 #include "pxr/base/tf/weakPtr.h"
22 
23 #include "pxr/external/boost/python/handle.hpp"
24 
25 #include "pxr/base/tf/hashmap.h"
26 
27 // Specializations for pxr_boost::python::pointee and get_pointer for TfRefPtr and
28 // TfWeakPtr.
29 namespace PXR_BOOST_NAMESPACE { namespace python {
30 
31 // TfWeakPtrFacade
32 template <template <class> class X, class Y>
33 struct pointee< PXR_NS::TfWeakPtrFacade<X, Y> > {
34  typedef Y type;
35 };
36 
37 // TfRefPtr
38 template <typename T>
39 struct pointee< PXR_NS::TfRefPtr<T> > {
40  typedef T type;
41 };
42 
43 }}
44 
46 
48 {
49  // Set the identity of ptr (which derives from TfPtrBase) to be the
50  // python object \a obj.
51  TF_API
52  static void Set(void const *id, PyObject *obj);
53 
54  // Return a new reference to the python object associated with ptr. If
55  // there is none, return 0.
56  TF_API
57  static PyObject *Get(void const *id);
58 
59  TF_API
60  static void Erase(void const *id);
61 
62  // Acquire a reference to the python object associated with ptrBase
63  // if not already acquired.
64  TF_API
65  static void Acquire(void const *id);
66 
67  // Release a reference to the python object associated with ptrBase
68  // if we own a reference.
69  TF_API
70  static void Release(void const *id);
71 
72 };
73 
74 template <class Ptr>
75 void Tf_PyReleasePythonIdentity(Ptr const &ptr, PyObject *obj)
76 {
77  Tf_PySetPythonIdentity(ptr, obj);
78  Tf_PyIdentityHelper::Release(ptr.GetUniqueIdentifier());
79 }
80 
82  bool isNowUnique);
83 
85 {
88  TF_API
89  static void Insert(TfRefBase *refBase, void const *uniqueId);
90  TF_API
91  static void const *Lookup(TfRefBase const *refBase);
92  TF_API
93  static void Erase(TfRefBase *refBase);
94  private:
95  static _CacheType _cache;
96 };
97 
98 
99 // Doxygen generates files whose names are mangled typenames. This is fine
100 // except when the filenames get longer than 256 characters. This is one case
101 // of that, so we'll just disable doxygen. There's no actual doxygen doc here,
102 // so this is fine. If/when this gets solved for real, we can remove this
103 // (6/06)
104 #ifndef doxygen
105 
106 
107 template <class Ptr, typename Enable = void>
109  template <typename U>
110  static void Add(U const &, const void *, PyObject *) {}
111  template <typename U>
112  static void Remove(U const &, PyObject *) {}
113 };
114 
115 template <typename Ptr>
117  std::enable_if_t<
118  std::is_same<TfRefPtr<typename Ptr::DataType>, Ptr>::value &&
119  std::is_base_of<TfRefBase, typename Ptr::DataType>::value>>
120 {
121  static void Add(Ptr ptr, const void *uniqueId, PyObject *self) {
122 
123  TfPyLock pyLock;
124 
125  // Create a capsule to hold on to a heap-allocated instance of
126  // Ptr. We'll set this as an attribute on the Python object so
127  // it keeps the C++ object alive.
128  pxr_boost::python::handle<> capsule(
129  PyCapsule_New(
130  new Ptr(ptr), "refptr",
131  +[](PyObject* capsule) {
132  void* heldPtr = PyCapsule_GetPointer(capsule, "refptr");
133  delete static_cast<Ptr*>(heldPtr);
134  }));
135 
136  int ret = PyObject_SetAttrString(self, "__owner", capsule.get());
137  if (ret == -1) {
138  // CODE_COVERAGE_OFF
139  TF_WARN("Could not set __owner attribute on python object!");
140  PyErr_Clear();
141  return;
142  // CODE_COVERAGE_ON
143  }
144  TfRefBase *refBase =
145  static_cast<TfRefBase *>(get_pointer(ptr));
146  Tf_PyOwnershipPtrMap::Insert(refBase, uniqueId);
147  }
148 
149  static void Remove(Ptr ptr, PyObject *obj) {
150  TfPyLock pyLock;
151 
152  if (!ptr) {
153  // CODE_COVERAGE_OFF Can only happen if there's a bug.
154  TF_CODING_ERROR("Removing ownership from null/expired ptr!");
155  return;
156  // CODE_COVERAGE_ON
157  }
158 
159  if (PyObject_HasAttrString(obj, "__owner")) {
160  // We are guaranteed that ptr is not unique at this point,
161  // as __owner has a reference and ptr is itself a
162  // reference. This also guarantees us that the object owns
163  // a reference to its python object, so we don't need to
164  // explicitly acquire a reference here.
165  TF_AXIOM(!ptr->IsUnique());
166  // Remove this object from the cache of refbase to uniqueId
167  // that we use for python-owned things.
169  // Remove the __owner attribute.
170  if (PyObject_DelAttrString(obj, "__owner") == -1) {
171  // CODE_COVERAGE_OFF It's hard to make this occur.
172  TF_WARN("Undeletable __owner attribute on python object!");
173  PyErr_Clear();
174  // CODE_COVERAGE_ON
175  }
176  }
177  }
178 };
179 
180 #endif // doxygen -- see comment above.
181 
182 
183 template <typename Ptr>
185  static const bool value = false;
186 };
187 
188 template <typename T>
190  static const bool value = true;
191 };
192 
193 
194 template <class Ptr>
196 Tf_PySetPythonIdentity(Ptr const &, PyObject *)
197 {
198 }
199 
200 template <class Ptr>
202 Tf_PySetPythonIdentity(Ptr const &ptr, PyObject *obj)
203 {
204  if (ptr.GetUniqueIdentifier()) {
205  Tf_PyIdentityHelper::Set(ptr.GetUniqueIdentifier(), obj);
206  // Make sure we hear about it when this weak base dies so we can remove
207  // it from the map.
208  ptr.EnableExtraNotification();
209  }
210 }
211 
212 template <class Ptr>
213 PyObject *Tf_PyGetPythonIdentity(Ptr const &ptr)
214 {
215  PyObject *ret = Tf_PyIdentityHelper::Get(ptr.GetUniqueIdentifier());
216  return ret;
217 }
218 
219 template <class Ptr>
220 void Tf_PyRemovePythonOwnership(Ptr const &t, PyObject *obj)
221 {
223 }
224 
225 template <class Ptr>
226 void Tf_PyAddPythonOwnership(Ptr const &t, const void *uniqueId, PyObject *obj)
227 {
228  Tf_PyOwnershipHelper<Ptr>::Add(t, uniqueId, obj);
229 }
230 
232 
233 #endif // PXR_BASE_TF_PY_IDENTITY_H
typename std::enable_if< B, T >::type enable_if_t
Define Imath::enable_if_t to be std for C++14, equivalent for C++11.
#define TF_API
Definition: api.h:23
Y
Definition: ImathEuler.h:184
static void Add(U const &, const void *, PyObject *)
Definition: pyIdentity.h:110
GLsizei const GLfloat * value
Definition: glcorearb.h:824
static TF_API void const * Lookup(TfRefBase const *refBase)
#define TF_CODING_ERROR
X
Definition: ImathEuler.h:183
static TF_API void Release(void const *id)
Y * get_pointer(TfWeakPtrFacade< X, Y > const &p)
Definition: weakPtrFacade.h:63
static TF_API void Erase(TfRefBase *refBase)
#define PXR_NS
Definition: pxr.h:54
TfHashMap< TfRefBase const *, void const *, TfHash > _CacheType
Definition: pyIdentity.h:87
#define TF_WARN
GLdouble t
Definition: glad.h:2397
void Tf_PyRemovePythonOwnership(Ptr const &t, PyObject *obj)
Definition: pyIdentity.h:220
#define TF_AXIOM(cond)
std::enable_if_t< Tf_PyIsRefPtr< Ptr >::value > Tf_PySetPythonIdentity(Ptr const &, PyObject *)
Definition: pyIdentity.h:196
static TF_API void Acquire(void const *id)
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
static void Remove(U const &, PyObject *)
Definition: pyIdentity.h:112
void Tf_PyReleasePythonIdentity(Ptr const &ptr, PyObject *obj)
Definition: pyIdentity.h:75
void Tf_PyAddPythonOwnership(Ptr const &t, const void *uniqueId, PyObject *obj)
Definition: pyIdentity.h:226
auto ptr(T p) -> const void *
Definition: format.h:4331
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
static TF_API void Set(void const *id, PyObject *obj)
static TF_API void Erase(void const *id)
PyObject * Tf_PyGetPythonIdentity(Ptr const &ptr)
Definition: pyIdentity.h:213
void Tf_PyOwnershipRefBaseUniqueChanged(TfRefBase const *refBase, bool isNowUnique)
static TF_API PyObject * Get(void const *id)
static TF_API void Insert(TfRefBase *refBase, void const *uniqueId)