5#ifndef __eigenpy_utils_variant_hpp__ 6#define __eigenpy_utils_variant_hpp__ 8#include "eigenpy/fwd.hpp" 9#include "eigenpy/utils/traits.hpp" 10#include "eigenpy/utils/python-compat.hpp" 12#include <boost/python.hpp> 13#include <boost/variant.hpp> 14#include <boost/mpl/for_each.hpp> 15#include <boost/mpl/vector.hpp> 19#ifdef EIGENPY_WITH_CXX17_SUPPORT 28template <
typename ResultType,
typename Variant>
32template <
typename Variant>
35template <
typename Variant>
41#ifdef EIGENPY_WITH_CXX17_SUPPORT 44template <
typename ResultType,
typename... Alternatives>
46 typedef std::variant<Alternatives...> variant_type;
47 typedef ResultType result_type;
49 template <
typename Visitor,
typename Visitable>
50 static result_type visit(Visitor&& visitor, Visitable&& v) {
51 return std::visit(std::forward<Visitor>(visitor),
52 std::forward<Visitable>(v));
55 result_type operator()(std::monostate)
const {
56 return bp::incref(bp::object().ptr());
60template <
typename... Alternatives>
62 typedef boost::mpl::vector<Alternatives...> types;
65template <
typename... Alternatives>
67 typedef std::monostate type;
76template <
typename ResultType,
typename... Alternatives>
78 : boost::static_visitor<ResultType> {
79 typedef boost::variant<Alternatives...> variant_type;
80 typedef ResultType result_type;
82 template <
typename Visitor,
typename Visitable>
83 static result_type visit(Visitor&& visitor, Visitable&& visitable) {
84 return std::forward<Visitable>(visitable).apply_visitor(visitor);
87 result_type operator()(boost::blank)
const {
88 return bp::incref(bp::object().ptr());
92template <
typename... Alternatives>
94 typedef typename boost::variant<Alternatives...>::types types;
97template <
typename... Alternatives>
99 typedef boost::blank type;
107template <
typename Variant>
109 static void registration() {
110 bp::converter::registry::push_back(convertible, construct,
111 bp::type_id<Variant>());
115 static void* convertible(PyObject* obj) {
116 return (obj == Py_None) ? obj :
nullptr;
120 static void construct(PyObject*,
121 bp::converter::rvalue_from_python_stage1_data* data) {
123 reinterpret_cast<bp::converter::rvalue_from_python_storage<Variant>*
>(
127 data->convertible = storage;
132template <
typename T,
class Enable =
void>
137 T, typename std::enable_if<std::is_same<T, bool>::value>
::type> {
138 static void* convertible(PyObject* obj) {
139 return PyBool_Check(obj) ? obj :
nullptr;
142 static PyTypeObject
const* expected_pytype() {
return &PyBool_Type; }
147 T, typename std::enable_if<!std::is_same<T, bool>::value &&
148 std::is_integral<T>::value>::type> {
149 static void* convertible(PyObject* obj) {
151 return (PyInt_Check(obj) && !PyBool_Check(obj)) ? obj :
nullptr;
154 static PyTypeObject
const* expected_pytype() {
return &PyLong_Type; }
159 T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
160 static void* convertible(PyObject* obj) {
161 return PyFloat_Check(obj) ? obj :
nullptr;
164 static PyTypeObject
const* expected_pytype() {
return &PyFloat_Type; }
168template <
typename T,
typename Variant>
170 static void registration() {
171 bp::converter::registry::push_back(
172 &convertible, &bp::converter::implicit<T, Variant>::construct,
173 bp::type_id<Variant>()
174#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
181 static void* convertible(PyObject* obj) {
184 static PyTypeObject
const* expected_pytype() {
191template <
typename Variant>
194 typedef typename Base::result_type result_type;
195 typedef typename Base::variant_type variant_type;
197 static result_type convert(
const variant_type& v) {
201 template <
typename T>
202 result_type operator()(T& t)
const {
203 return bp::incref(bp::object(t).ptr());
206 using Base::operator();
213template <
typename Variant>
216 typedef typename Base::result_type result_type;
217 typedef typename Base::variant_type variant_type;
219 static result_type convert(
const variant_type& v) {
223 template <
typename T,
224 typename std::enable_if<is_python_primitive_type<T>::value,
226 result_type operator()(T t)
const {
227 return bp::incref(bp::object(t).ptr());
230 template <
typename T,
231 typename std::enable_if<!is_python_primitive_type<T>::value,
233 result_type operator()(T& t)
const {
234 return bp::detail::make_reference_holder::execute(&t);
238 using Base::operator();
245template <
typename Variant>
247 typedef Variant variant_type;
252 PyObject* operator()(
const variant_type& v)
const {
253 return VariantRefToObject<variant_type>::convert(v);
256#ifndef BOOST_PYTHON_NO_PY_SIGNATURES 257 PyTypeObject
const* get_pytype()
const {
258 return bp::converter::registered_pytype<variant_type>::get_pytype();
266template <
typename Variant>
268 typedef Variant variant_type;
270 template <class T, typename std::enable_if<is_empty_variant<T>::value,
273 EmptyConvertible<variant_type>::registration();
276 template <class T, typename std::enable_if<!is_empty_variant<T>::value &&
277 std::is_arithmetic<T>::value,
280 NumericConvertible<T, variant_type>::registration();
283 template <class T, typename std::enable_if<!is_empty_variant<T>::value &&
284 !std::is_arithmetic<T>::value,
287 bp::implicitly_convertible<T, variant_type>();
296template <
typename Variant>
298 typedef Variant variant_type;
302 template <
class ArgumentPackage>
303 static PyObject* postcall(ArgumentPackage
const& args_, PyObject* result) {
305 if (PyInt_Check(result) || PyBool_Check(result) || PyFloat_Check(result) ||
306 PyStr_Check(result) || PyComplex_Check(result)) {
309 return bp::return_internal_reference<>::postcall(args_, result);
336template <
typename Variant>
338 typedef Variant variant_type;
341 static void registration() {
345 bp::to_python_converter<variant_type, variant_to_value>();
Implement convertible and expected_pytype for bool, integer and float.
Convert numeric type to Variant without ambiguity.
Allow to get all alternatives in a boost::mpl vector.
Convert an Alternative type to a Variant.
Allow to use std::variant and boost::variant with the same API.