2#include "proxsuite-nlp/python/fwd.hpp"
3#include "proxsuite-nlp/third-party/polymorphic_cxx14.hpp"
6#include <eigenpy/utils/traits.hpp>
8#include <boost/core/demangle.hpp>
14namespace boost::python {
15template <
class T,
class A>
struct pointee<xyz::polymorphic<T, A>> {
20namespace proxsuite::nlp {
26 using X =
typename bp::pointee<Poly>::type;
27 bp::objects::class_value_wrapper<
28 Poly, bp::objects::make_ptr_instance<
29 X, bp::objects::pointer_holder<Poly, X>>>();
73template <
class Base,
class A>
75 : bp::def_visitor<PolymorphicVisitor<xyz::polymorphic<Base, A>>> {
76 using Poly = xyz::polymorphic<Base, A>;
77 static_assert(std::is_polymorphic_v<Base>,
"Type should be polymorphic!");
79 template <
class PyClass>
void visit(PyClass &cl)
const {
80 using T =
typename PyClass::wrapped_type;
81 using meta =
typename PyClass::metadata;
82 using held =
typename meta::held_type;
83 typedef bp::converter::implicit<held, Poly> functions;
86 PROXSUITE_NLP_COMPILER_DIAGNOSTIC_IGNORED_DELETE_NON_ABSTRACT_NON_VIRTUAL_DTOR
87 bp::converter::registry::insert(
88 &functions::convertible, &functions::construct, bp::type_id<Poly>(),
89 &bp::converter::expected_from_python_type_direct<T>::get_pytype);
90 PROXSUITE_NLP_COMPILER_DIAGNOSTIC_POP
97 if constexpr (std::is_base_of_v<boost::python::wrapper<Base>,
98 typename PyClass::wrapped_type>) {
99 cl.enable_pickling_(
true);
107template <
typename Value>
108struct OwningNonOwningHolder : boost::python::instance_holder {
109 typedef Value held_type;
110 typedef Value value_type;
114 Value *operator()(Value &v) {
return &v; };
115 Value *operator()(Value *v) {
return v; };
118 Value *get_ptr() {
return std::visit(PtrGetter(), m_held); }
121 template <
typename... Args>
122 OwningNonOwningHolder(PyObject *self, Args... args)
123 : m_held(Value(boost::python::objects::do_unforward(
124 std::forward<Args>(args), 0)...)) {
125 boost::python::detail::initialize_wrapper(self, get_ptr());
129 void *holds(boost::python::type_info dst_t,
bool) {
130 if (
void *wrapped = holds_wrapped(dst_t, get_ptr(), get_ptr()))
133 boost::python::type_info src_t = boost::python::type_id<Value>();
134 return src_t == dst_t ? get_ptr()
135 : boost::python::objects::find_static_type(
136 get_ptr(), src_t, dst_t);
140 inline void *holds_wrapped(boost::python::type_info dst_t,
141 boost::python::wrapper<T> *,
T *p) {
142 return boost::python::type_id<T>() == dst_t ? p : 0;
145 inline void *holds_wrapped(boost::python::type_info, ...) {
return 0; }
148 std::variant<Value, Value *> m_held;
175template <
typename _PyBase,
typename _Base>
176struct PolymorphicWrapper : boost::python::wrapper<_Base> {
177 using PyBase = _PyBase;
180 PolymorphicWrapper() =
default;
181 PolymorphicWrapper(
const PolymorphicWrapper &o) : bp::wrapper<Base>(o) {
184 PolymorphicWrapper(PolymorphicWrapper &&o) =
default;
186 PolymorphicWrapper &operator=(
const PolymorphicWrapper &o) {
190 bp::wrapper<Base>::operator=(o);
194 PolymorphicWrapper &operator=(PolymorphicWrapper &&o) =
default;
197 void deepcopy_owner() {
198 namespace bp = boost::python;
199 if (PyObject *owner_ptr = bp::detail::wrapper_base_::get_owner(*
this)) {
200 bp::object copy = bp::import(
"copy");
201 bp::object deepcopy = copy.attr(
"deepcopy");
206 bp::object owner{bp::handle<>(bp::borrowed(owner_ptr))};
212 copied_owner = deepcopy(owner);
213 PyObject *copied_owner_ptr = copied_owner.ptr();
222 bp::objects::instance<> *inst =
223 ((bp::objects::instance<> *)copied_owner_ptr);
227 std::ostringstream error_msg;
228 error_msg <<
"OwningNonOwningHolder should be setup for "
229 << boost::core::demangle(
typeid(PyBase).name()) <<
" type"
231 throw std::logic_error(error_msg.str());
233 value_holder->m_held =
static_cast<PyBase *
>(
this);
235 bp::detail::initialize_wrapper(copied_owner_ptr,
this);
240 bp::object copied_owner;
250template <
class poly_ref,
class MakeHolder>
struct ToPythonIndirectPoly {
251 using poly_type = boost::remove_cv_ref_t<poly_ref>;
253 template <
class U> PyObject *operator()(U
const &x)
const {
254 return execute(
const_cast<U &
>(x));
256#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
257 PyTypeObject
const *get_pytype() {
258 return boost::python::converter::registered_pytype<poly_type>::get_pytype();
263 template <
class T,
class A>
264 static PyObject *execute(
const xyz::polymorphic<T, A> &p) {
265 if (p.valueless_after_move())
266 return bp::detail::none();
267 T *q =
const_cast<T *
>(boost::get_pointer(p));
269 return bp::to_python_indirect<const T &, MakeHolder>{}(q);
280template <
class T,
class A,
class MakeHolder>
281struct to_python_indirect<xyz::polymorphic<T, A> &, MakeHolder>
282 : proxsuite::nlp::python::internal::ToPythonIndirectPoly<
283 xyz::polymorphic<T, A> &, MakeHolder> {};
285template <
class T,
class A,
class MakeHolder>
286struct to_python_indirect<const xyz::polymorphic<T, A> &, MakeHolder>
287 : proxsuite::nlp::python::internal::ToPythonIndirectPoly<
288 const xyz::polymorphic<T, A> &, MakeHolder> {};
#define PROXSUITE_NLP_COMPILER_DIAGNOSTIC_PUSH
macros for pragma push/pop/ignore deprecated warnings
void register_polymorphic_to_python()
Expose a polymorphic value type, e.g. xyz::polymorphic<T, A>.