8#ifndef PXR_BASE_TF_MAKE_PY_CONSTRUCTOR_H
9#define PXR_BASE_TF_MAKE_PY_CONSTRUCTOR_H
16# define TF_MAX_ARITY 7
21#include "pxr/base/tf/api.h"
22#include "pxr/base/tf/functionTraits.h"
26#include "pxr/base/tf/pyError.h"
27#include "pxr/base/tf/pyIdentity.h"
33#include "pxr/external/boost/python/def_visitor.hpp"
34#include "pxr/external/boost/python/dict.hpp"
35#include "pxr/external/boost/python/errors.hpp"
36#include "pxr/external/boost/python/list.hpp"
37#include "pxr/external/boost/python/object/iterator.hpp"
38#include "pxr/external/boost/python/raw_function.hpp"
39#include "pxr/external/boost/python/tuple.hpp"
40#include "pxr/external/boost/python/type_id.hpp"
47PXR_NAMESPACE_OPEN_SCOPE
85namespace Tf_MakePyConstructor {
87namespace bp = pxr_boost::python;
89template <
typename CTOR>
90struct InitVisitor : bp::def_visitor<InitVisitor<CTOR> > {
91 friend class bp::def_visitor_access;
92 const std::string _doc;
93 InitVisitor(
const std::string &doc = std::string()) : _doc(doc) {}
95 template <
typename CLS>
96 void visit(CLS &c)
const {
97 c.def(
"__init__", CTOR::template init_callable<CLS>(), _doc.c_str());
100 template <
class CLS,
class Options>
101 void visit(CLS &c,
char const* name, Options& options)
const {
103 c.def(name, CTOR::template init_callable<CLS>(options), _doc.c_str());
109bp::object _DummyInit(bp::tuple
const & ,
112template <
typename CTOR>
113struct NewVisitor : bp::def_visitor<NewVisitor<CTOR> > {
114 friend class bp::def_visitor_access;
115 const std::string _doc;
116 NewVisitor(
const std::string &doc = std::string()) : _doc(doc) {}
118 template <
typename CLS>
119 void visit(CLS &c)
const {
132 if (PyObject_HasAttrString(c.ptr(),
"__new__"))
133 c.attr(
"__new__") = c.attr(
"__new__");
134 c.def(
"__new__", CTOR::template __new__<CLS>, _doc.c_str());
135 c.staticmethod(
"__new__");
138 c.def(
"__init__", bp::raw_function(_DummyInit));
141 template <
class CLS,
class Options>
142 void visit(CLS &c,
char const* name, Options& options)
const {
155 if (PyObject_HasAttrString(c.ptr(),
"__new__"))
156 c.attr(
"__new__") = c.attr(
"__new__");
157 c.def(
"__new__", CTOR::template __new__<CLS>,
163 c.staticmethod(
"__new__");
166 c.def(
"__init__", bp::raw_function(_DummyInit));
172typedef bp::object object;
175struct InstallPolicy {
176 static void PostInstall(
object const &self, T
const &t,
183 static_assert(Tf_SupportsUniqueChanged<T>::Value,
184 "Type T must support refcount unique changed notification.");
185 static void PostInstall(
object const &self,
TfRefPtr<T> const &ptr,
186 const void *uniqueId) {
190 Tf_PyAddPythonOwnership(ptr, uniqueId, self.ptr());
194template <
typename CLS,
typename T>
195void Install(
object const &self, T
const &t,
TfErrorMark const &m) {
198 typedef typename CLS::metadata::holder Holder;
199 typedef typename bp::objects::instance<Holder> instance_t;
200 typedef InstallPolicy<T> Policy;
201 typedef typename CLS::metadata::held_type HeldType;
204 void *memory = Holder::
206 allocate(self.ptr(), offsetof(instance_t, storage),
sizeof(Holder));
209 Holder *holder = (
new (memory) Holder(held));
211 if (TfPyConvertTfErrorsToPythonException(m))
212 bp::throw_error_already_set();
218 bp::detail::initialize_wrapper(self.ptr(), &(*(held.operator->())));
219 holder->install(self.ptr());
222 Tf_PySetPythonIdentity(held, self.ptr());
224 Policy::PostInstall(self, t, held.GetUniqueIdentifier());
227 Holder::deallocate(self.ptr(), memory);
throw;
233template <
typename WeakPtr,
typename P>
234struct _RefPtrFactoryConverter {
235 typedef std::remove_reference_t<P> Ptr;
236 bool convertible()
const {
243 PyObject *operator()(Ptr
const &p)
const {
244 typedef InstallPolicy<Ptr> Policy;
245 WeakPtr ptr(
static_cast<typename WeakPtr::DataType *
>
250 return bp::incref(Py_None);
255 Policy::PostInstall(result, p, ptr.GetUniqueIdentifier());
256 return bp::incref(result.ptr());
260 PyTypeObject
const *get_pytype()
const {
261 return pxr_boost::python::objects::registered_class_object(
262 pxr_boost::python::type_id<typename WeakPtr::DataType>()).get();
266template <
typename WeakPtr =
void>
267struct RefPtrFactory {
268 template <
typename FactoryResultPtr>
270 using WeakPtrType = std::conditional_t<
271 std::is_same<WeakPtr, void>::value,
274 typedef _RefPtrFactoryConverter<WeakPtrType, FactoryResultPtr> type;
283template <
typename SIG,
size_t EXTRA_ARITY = 0>
286 using Traits = TfFunctionTraits<SIG*>;
287 static_assert(Traits::Arity <= (TF_MAX_ARITY + EXTRA_ARITY));
290 static void SetFunc(Sig *func) {
296 "Duplicate will be ignored.",
303template <
typename SIG,
size_t EXTRA_ARITY>
304SIG *CtorBase<SIG, EXTRA_ARITY>::_func =
nullptr;
306template <
typename SIG>
struct InitCtor;
307template <
typename SIG>
struct InitCtorWithBackReference;
308template <
typename SIG>
struct InitCtorWithVarArgs;
309template <
typename SIG>
struct NewCtor;
310template <
typename SIG>
struct NewCtorWithClassReference;
316Tf_MakePyConstructor::InitVisitor
317<
typename Tf_MakePyConstructor::InitCtor<T> >
318TfMakePyConstructor(T *func,
const std::string &doc = std::string()) {
320 Tf_MakePyConstructor::InitCtor<T> Ctor(func);
321 return Tf_MakePyConstructor::InitVisitor
322 <Tf_MakePyConstructor::InitCtor<T> >(doc);
326Tf_MakePyConstructor::InitVisitor
327<
typename Tf_MakePyConstructor::InitCtorWithBackReference<T> >
328TfMakePyConstructorWithBackReference(T *func,
const std::string &doc = std::string()) {
330 Tf_MakePyConstructor::InitCtorWithBackReference<T> Ctor(func);
331 return Tf_MakePyConstructor::InitVisitor
332 <Tf_MakePyConstructor::InitCtorWithBackReference<T> >(doc);
336Tf_MakePyConstructor::InitVisitor
337<
typename Tf_MakePyConstructor::InitCtorWithVarArgs<T> >
338TfMakePyConstructorWithVarArgs(T *func,
const std::string &doc = std::string()) {
340 Tf_MakePyConstructor::InitCtorWithVarArgs<T> Ctor(func);
341 return Tf_MakePyConstructor::InitVisitor
342 <Tf_MakePyConstructor::InitCtorWithVarArgs<T> >(doc);
346Tf_MakePyConstructor::NewVisitor
347<
typename Tf_MakePyConstructor::NewCtor<T> >
348TfMakePyNew(T *func,
const std::string &doc = std::string()) {
350 Tf_MakePyConstructor::NewCtor<T> Ctor(func);
351 return Tf_MakePyConstructor::NewVisitor
352 <Tf_MakePyConstructor::NewCtor<T> >(doc);
356Tf_MakePyConstructor::NewVisitor
357<
typename Tf_MakePyConstructor::NewCtorWithClassReference<T> >
358TfMakePyNewWithClassReference(T *func,
const std::string &doc = std::string()) {
360 Tf_MakePyConstructor::NewCtorWithClassReference<T> Ctor(func);
361 return Tf_MakePyConstructor::NewVisitor
362 <Tf_MakePyConstructor::NewCtorWithClassReference<T> >(doc);
366template <
typename T =
void>
367struct TfPyRefPtrFactory :
public Tf_MakePyConstructor::RefPtrFactory<T> {};
369template <
typename T>
struct Tf_PySequenceToListConverterRefPtrFactory;
374 template <
typename T>
376 typedef Tf_PySequenceToListConverterRefPtrFactory<T> type;
382struct Tf_PySequenceToListConverterRefPtrFactory {
383 typedef std::remove_reference_t<T> SeqType;
384 bool convertible()
const {
387 PyObject *operator()(T seq)
const {
388 using namespace pxr_boost::python;
390 typedef typename Tf_MakePyConstructor::RefPtrFactory<>::
391 apply<typename SeqType::value_type>::type RefPtrFactory;
393 pxr_boost::python::list l;
394 for (
typename SeqType::const_iterator i = seq.begin();
395 i != seq.end(); ++i) {
396 l.append(
object(handle<>(RefPtrFactory()(*i))));
398 return pxr_boost::python::incref(l.ptr());
402 PyTypeObject
const *get_pytype()
const {
407namespace Tf_MakePyConstructor {
409template <
typename R,
typename... Args>
410struct InitCtor<R(Args...)> : CtorBase<R(Args...)> {
411 typedef CtorBase<R(Args...)> Base;
412 typedef typename Base::Sig Sig;
414 InitCtor(Sig* func) { Base::SetFunc(func); }
416 template <
typename CLS>
417 static bp::object init_callable() {
418 return bp::make_function(__init__<CLS>);
421 template <
typename CLS,
typename Options>
422 static bp::object init_callable(Options& o) {
423 return bp::make_function(__init__<CLS>, o.policies(), o.keywords()) ;
426 template <
typename CLS>
427 static void __init__(
object &self, Args... args) {
429 Install<CLS>(self, Base::_func(args...), m);
433template <
typename R,
typename... Args>
434struct NewCtor<R(Args...)> : CtorBase<R(Args...)> {
435 typedef CtorBase<R(Args...)> Base;
436 typedef typename Base::Sig Sig;
437 NewCtor(Sig *func) { Base::SetFunc(func); }
440 static bp::object __new__(
object &cls, Args... args) {
441 typedef typename CLS::metadata::held_type HeldType;
443 R r((Base::_func(args...)));
445 if (TfPyConvertTfErrorsToPythonException(m))
446 bp::throw_error_already_set();
452 bp::detail::initialize_wrapper(ret.ptr(), get_pointer(h));
454 bp::setattr(ret,
"__class__", cls);
456 InstallPolicy<R>::PostInstall(ret, r, h.GetUniqueIdentifier());
461template <
typename R,
typename... Args>
462struct InitCtorWithVarArgs<R(Args...)> :
464 CtorBase<R(Args...), 2> {
465 typedef CtorBase<R(Args...), 2> Base;
466 typedef typename Base::Sig Sig;
471 using Arity = TfMetaLength<Args...>;
473 InitCtorWithVarArgs(Sig *func) { Base::SetFunc(func); }
475 static_assert((Arity::value >= 2) &&
478 typename Base::Traits::template NthArg<(Arity::value-2)>>) &&
481 typename Base::Traits::template NthArg<(Arity::value-1)>>),
482 "InitCtorWithVarArgs requires a function of form "
483 "(..., const tuple&, const dict&)");
485 template <
typename CLS>
486 static bp::object init_callable() {
490 return bp::raw_function(__init__<CLS>, 1);
493 template <
typename CLS,
typename Options>
494 static bp::object init_callable(Options& options) {
497 return bp::raw_function(
498 bp::make_function(__init__<CLS>, options.policies()),
502 template <
typename CLS,
size_t... I>
503 static bp::object __init__impl(
const bp::tuple& args,
504 const bp::dict& kwargs,
505 std::index_sequence<I...>) {
510 const unsigned int expectedNamedArgs = Arity::value - 2;
512 const unsigned int positionalArgs = bp::len(args) - 1;
513 if (positionalArgs < expectedNamedArgs) {
514 std::array<std::string, Arity::value - 2>
515 positionalArgTypes = {{
516 (bp::type_id<typename Base::Traits::template NthArg<I>>().name())...
519 std::begin(positionalArgTypes),
520 std::end(positionalArgTypes),
", "
522 if (!joinedTypes.empty()) {
529 "Arguments to __init__ did not match C++ signature:\n"
530 "\t__init__(%s...)", joinedTypes.c_str()
541 std::remove_reference_t<
542 typename Base::Traits::template NthArg<I>>>(args[I + 1])...,
543 bp::tuple(args.slice(expectedNamedArgs + 1, bp::len(args))), kwargs),
549 template <
typename CLS>
550 static bp::object __init__(
const bp::tuple& args,
551 const bp::dict& kwargs) {
552 return __init__impl<CLS>(
553 args, kwargs, std::make_index_sequence<Arity::value - 2>());
563template <
typename R,
typename SelfRef,
typename... Args>
564struct InitCtorWithBackReference<R(SelfRef, Args...)> :
565 CtorBase<R(SelfRef, Args...)> {
566 typedef CtorBase<R(SelfRef, Args...)> Base;
567 typedef typename Base::Sig Sig;
568 InitCtorWithBackReference(Sig *func) { Base::SetFunc(func); }
570 template <
typename CLS>
571 static bp::object init_callable() {
572 return bp::make_function(__init__<CLS>);
575 template <
typename CLS,
typename Options>
576 static bp::object init_callable(Options& o) {
577 return bp::make_function(__init__<CLS>, o.policies(), o.keywords());
580 template <
typename CLS>
581 static void __init__(SelfRef self, Args... args) {
583 Install<CLS>(self, Base::_func(self, args...), m);
587template <
typename R,
typename ClsRef,
typename... Args>
588struct NewCtorWithClassReference<R(ClsRef, Args...)> :
589 CtorBase<R(ClsRef, Args...)> {
590 typedef CtorBase<R(ClsRef, Args...)> Base;
591 typedef typename Base::Sig Sig;
592 NewCtorWithClassReference(Sig *func) { Base::SetFunc(func); }
595 static bp::object __new__(ClsRef cls, Args... args) {
596 typedef typename CLS::metadata::held_type HeldType;
598 R r(Base::_func(cls, args...));
600 if (TfPyConvertTfErrorsToPythonException(m))
601 bp::throw_error_already_set();
607 bp::detail::initialize_wrapper(ret.ptr(), get_pointer(h));
609 bp::setattr(ret,
"__class__", cls);
611 InstallPolicy<R>::PostInstall(ret, r, h.GetUniqueIdentifier());
617PXR_NAMESPACE_CLOSE_SCOPE
Low-level utilities for informing users of various internal and external diagnostic conditions.
Miscellaneous Utilities for dealing with script.
TF_API void TfPyThrowRuntimeError(const char *msg)
Raises a Python RuntimeError with the given error msg and throws a pxr_boost::python::error_already_s...
TF_API bool TfPyIsNone(pxr_boost::python::object const &obj)
Return true iff obj is None.
pxr_boost::python::object TfPyObject(T const &t, bool complainOnFailure=true)
Return a python object for the given C++ object, loading the appropriate wrapper code if necessary.
TF_API void TfPyThrowTypeError(const char *msg)
Raises a Python TypeError with the given error msg and throws a pxr_boost::python::error_already_set ...
Class used to record the end of the error-list.
Reference-counted smart pointer utility class.
Pointer storage with deletion detection.
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.
std::string TfStringJoin(ForwardIterator begin, ForwardIterator end, const char *separator=" ")
Concatenates the strings (begin, end), with default separator.
TF_API std::string TfStringPrintf(const char *fmt,...)
Returns a string formed by a printf()-like specification.
A pxr_boost::python result converter generator which converts standard library sequences to lists of ...
Definitions of basic string utilities in tf.
Pointer storage with deletion detection.