24#ifndef PXR_BASE_TF_PY_PTR_HELPERS_H
25#define PXR_BASE_TF_PY_PTR_HELPERS_H
32#include "pxr/base/tf/pyIdentity.h"
33#include "pxr/base/tf/pyObjectFinder.h"
34#include "pxr/base/tf/wrapTypeHelpers.h"
43#include <boost/python/class.hpp>
44#include <boost/python/converter/from_python.hpp>
45#include <boost/python/converter/registered.hpp>
46#include <boost/python/converter/registrations.hpp>
47#include <boost/python/converter/registry.hpp>
48#include <boost/python/converter/rvalue_from_python_data.hpp>
49#include <boost/python/converter/to_python_function_type.hpp>
50#include <boost/python/def_visitor.hpp>
51#include <boost/python/handle.hpp>
52#include <boost/python/implicit.hpp>
53#include <boost/python/to_python_converter.hpp>
58PXR_NAMESPACE_OPEN_SCOPE
77template <
typename Ptr>
79 typedef typename Ptr::DataType Pointee;
80 typedef boost::python::objects::pointer_holder<Ptr, Pointee> Holder;
81 typedef std::pair<PyObject*, bool> Result;
86 static Result Execute(Ptr
const& p)
89 if (!p.GetUniqueIdentifier())
90 return Result(boost::python::detail::none(),
false);
98 if (PyObject *
id = Tf_PyGetPythonIdentity(p))
99 return Result(
id,
false);
103 PyObject *res = boost::python::objects::make_ptr_instance
104 <Pointee, Holder>::execute(p);
107 return Result(res, res != Py_None);
111namespace Tf_PyDefHelpers {
113using namespace boost::python;
115template <
typename Ptr>
116struct _PtrInterface {
117 typedef typename Ptr::DataType Pointee;
118 using ConstPointee = std::add_const_t<Pointee>;
119 using NonConstPointee = std::remove_const_t<Pointee>;
121 template <
typename U>
123 typedef typename Ptr::template Rebind<U>::Type Type;
126 typedef typename Rebind<ConstPointee>::Type ConstPtr;
127 typedef typename Rebind<NonConstPointee>::Type NonConstPtr;
131template <
typename PtrType>
132bool _IsPtrExpired(
object const &self) {
134 PtrType p = extract<PtrType>(self);
136 }
catch (boost::python::error_already_set
const &) {
142template <
typename PtrType>
143bool _IsPtrValid(
object const &self) {
144 return !_IsPtrExpired<PtrType>(self);
147template <
typename PtrType>
148bool _ArePtrsEqual(PtrType
const &self,
149 PtrType
const &other) {
return self == other; }
150template <
typename PtrType>
151bool _ArePtrsNotEqual(PtrType
const &self,
152 PtrType
const &other) {
return self != other; }
153template <
typename PtrType>
154bool _ArePtrsLessThan(PtrType
const &self,
155 PtrType
const &other) {
return self < other; }
159template <
class PtrType>
160struct _PtrFromPythonConversionPolicy {
161 static void Apply(PtrType
const &, PyObject *) { }
167struct _PtrFromPythonConversionPolicy<
TfRefPtr<T> > {
168 static void Apply(
TfRefPtr<T> const &p, PyObject *obj) {
169 Tf_PyRemovePythonOwnership(p, obj);
174struct _PtrFromPython {
175 typedef typename _PtrInterface<Ptr>::Pointee Pointee;
177 converter::registry::insert(&convertible, &construct,
181 static void *convertible(PyObject *p) {
184 void *result = converter::get_lvalue_from_python
185 (p, converter::registered<Pointee>::converters);
189 static void construct(PyObject* source, converter::
190 rvalue_from_python_stage1_data* data) {
191 void*
const storage = ((converter::rvalue_from_python_storage<Ptr>*)
192 data)->storage.bytes;
194 if (data->convertible == source)
197 Ptr ptr(
static_cast<Pointee*
>(data->convertible));
198 new (storage) Ptr(ptr);
199 _PtrFromPythonConversionPolicy<Ptr>::Apply(ptr, source);
202 Tf_PySetPythonIdentity(ptr, source);
204 data->convertible = storage;
211template <
typename PtrType>
212struct _AnyWeakPtrFromPython {
214 _AnyWeakPtrFromPython() {
215 converter::registry::insert(&convertible, &construct,
216 type_id<TfAnyWeakPtr>());
219 static void *convertible(PyObject *p) {
222 void *result = converter::get_lvalue_from_python
223 (p, converter::registered
224 <
typename _PtrInterface<PtrType>::Pointee>::converters);
228 static void construct(PyObject* source, converter::
229 rvalue_from_python_stage1_data* data) {
230 void*
const storage = ((converter::rvalue_from_python_storage
233 if (data->convertible == source)
236 typedef typename _PtrInterface<PtrType>::Pointee T;
237 T *ptr =
static_cast<T*
>(data->convertible);
238 PtrType smartPtr(ptr);
242 data->convertible = storage;
246template <
typename Ptr>
247struct _ConstPtrToPython {
248 typedef typename _PtrInterface<Ptr>::ConstPtr ConstPtr;
249 typedef typename _PtrInterface<Ptr>::NonConstPtr NonConstPtr;
250 _ConstPtrToPython() {
251 to_python_converter<ConstPtr, _ConstPtrToPython<Ptr> >();
253 static PyObject *convert(ConstPtr
const &p) {
254 return incref(
object(TfConst_cast<NonConstPtr>(p)).ptr());
258template <
typename Ptr>
261 to_python_converter<Ptr, _PtrToPython<Ptr> >();
263 static PyObject *convert(Ptr
const &p) {
264 std::pair<PyObject*, bool> ret = TfMakePyPtr<Ptr>::Execute(p);
266 Tf_PySetPythonIdentity(p, ret.first);
272template <
typename SrcPtr,
typename DstPtr>
273struct _ConvertPtrToPython {
274 _ConvertPtrToPython() {
275 to_python_converter<SrcPtr, _ConvertPtrToPython<SrcPtr, DstPtr> >();
277 static PyObject *convert(SrcPtr
const &p) {
279 return incref(
object(dst).ptr());
283template <
typename Ptr>
284struct _PtrToPythonWrapper {
289 static converter::to_python_function_t _originalConverter;
292 static PyObject *Convert(
void const *x) {
294 Ptr
const &p = *
static_cast<Ptr
const *
>(x);
296 std::pair<PyObject*, bool> ret = TfMakePyPtr<Ptr>::Execute(p);
297 if (ret.first == Py_None) {
299 Py_DECREF(ret.first);
300 ret.first = _originalConverter(x);
303 Tf_PySetPythonIdentity(p, ret.first);
309converter::to_python_function_t
310_PtrToPythonWrapper<T>::_originalConverter = 0;
312struct WeakPtr : def_visitor<WeakPtr> {
313 friend class def_visitor_access;
315 template <
typename WrapperPtrType,
typename Wrapper,
typename T>
316 static void _RegisterConversions(Wrapper *, T *) {
317 _RegisterConversionsHelper<WrapperPtrType, Wrapper, T>();
320 template <
typename WrapperPtrType,
typename Wrapper,
typename T>
321 static void _RegisterConversionsHelper() {
323 static_assert(std::is_same<
324 typename _PtrInterface<WrapperPtrType>::Pointee,
326 "Pointee must be same type as Wrapper.");
329 _PtrInterface<WrapperPtrType>::template Rebind<T>::Type PtrType;
332 _PtrFromPython<PtrType>();
335 _AnyWeakPtrFromPython<PtrType>();
338 implicitly_convertible<PtrType,
339 typename _PtrInterface<PtrType>::ConstPtr >();
342 _ConstPtrToPython<PtrType>();
352 converter::registration *r =
const_cast<converter::registration *
>
353 (converter::registry::query(type_id<WrapperPtrType>()));
355 _PtrToPythonWrapper<WrapperPtrType>::
356 _originalConverter = r->m_to_python;
357 r->m_to_python = _PtrToPythonWrapper<WrapperPtrType>::Convert;
365 if (!std::is_same<Wrapper, T>::value)
366 _PtrToPython<PtrType>();
370 template <
typename PtrType,
typename CLS,
typename Wrapper,
typename T>
371 static void _AddAPI(CLS &c, Wrapper *, T *) {
373 _PtrInterface<PtrType>::template Rebind<T>::Type UnwrappedPtrType;
375 c.add_property(
"expired", _IsPtrExpired<UnwrappedPtrType>,
377 "True if this object has expired, False otherwise.");
378 c.def(
"__bool__", _IsPtrValid<UnwrappedPtrType>,
380 "True if this object has not expired. False otherwise.");
381 c.def(
"__eq__", _ArePtrsEqual<UnwrappedPtrType>,
382 "Equality operator: x == y");
383 c.def(
"__ne__", _ArePtrsNotEqual<UnwrappedPtrType>,
384 "Non-equality operator: x != y");
385 c.def(
"__lt__", _ArePtrsLessThan<UnwrappedPtrType>,
386 "Less than operator: x < y");
390 template <
typename CLS>
391 void visit(CLS &c)
const {
392 typedef typename CLS::wrapped_type Type;
393 typedef typename CLS::metadata::held_type_arg PtrType;
394 static_assert(TF_SUPPORTS_WEAKPTR(Type),
395 "Type must support TfWeakPtr.");
397 _RegisterConversions<PtrType>
398 ((Type *)0, detail::unwrap_wrapper((Type *)0));
401 Tf_RegisterPythonObjectFinder<Type, PtrType>();
404 _AddAPI<PtrType>(c, (Type *)0, detail::unwrap_wrapper((Type *)0));
408struct RefAndWeakPtr : def_visitor<RefAndWeakPtr> {
409 friend class def_visitor_access;
411 template <
typename CLS,
typename Wrapper,
typename T>
412 static void _AddAPI(Wrapper *, T *) {
413 _PtrFromPython<TfRefPtr<T> >();
415 _PtrInterface<typename CLS::metadata::held_type>::template
416 Rebind<T>::Type PtrType;
417 _ConvertPtrToPython<TfRefPtr<T>, PtrType>();
420 template <
typename CLS>
421 void visit(CLS &c)
const {
422 typedef typename CLS::wrapped_type Type;
423 static_assert(TF_SUPPORTS_REFPTR(Type),
424 "Type must support TfRefPtr.");
427 _AddAPI<CLS>((Type *)0, detail::unwrap_wrapper((Type *)0));
433struct TfPyWeakPtr : Tf_PyDefHelpers::WeakPtr {};
434struct TfPyRefAndWeakPtr : Tf_PyDefHelpers::RefAndWeakPtr {};
436PXR_NAMESPACE_CLOSE_SCOPE
Type independent WeakPtr holder class.
Low-level utilities for informing users of various internal and external diagnostic conditions.
Provides the ability to hold an arbitrary TfWeakPtr in a non-type-specific manner in order to observe...
Reference-counted smart pointer utility class.
Demangle C++ typenames generated by the typeid() facility.
std::string ArchGetDemangled()
Return demangled RTTI generated-type name.
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definitions of basic string utilities in tf.
A boost.python visitor that associates the Python class object created by the wrapping with the TfTyp...
Pointer storage with deletion detection.