Skip to content

Commit 3c32a6e

Browse files
committed
core: Fix postcall for primitive type
1 parent 0075690 commit 3c32a6e

File tree

3 files changed

+70
-17
lines changed

3 files changed

+70
-17
lines changed

include/eigenpy/variant.hpp

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,15 @@ struct VariantValueToObject : VariantVisitorType<PyObject*, Variant> {
9898
using Base::operator();
9999
};
100100

101+
template <typename T>
102+
struct is_class_or_union
103+
: std::integral_constant<bool, std::is_class<T>::value ||
104+
std::is_union<T>::value> {};
105+
template <typename T>
106+
struct is_class_or_union_remove_cvref
107+
: is_class_or_union<typename std::remove_cv<
108+
typename std::remove_reference<T>::type>::type> {};
109+
101110
/// Convert {boost,std}::variant<class...> alternative reference to a Python
102111
/// object. This converter return the alternative reference. The code that
103112
/// create the reference holder is taken from \see
@@ -113,19 +122,15 @@ struct VariantRefToObject : VariantVisitorType<PyObject*, Variant> {
113122
}
114123

115124
template <typename T,
116-
typename std::enable_if<
117-
std::is_arithmetic<typename std::remove_cv<
118-
typename std::remove_reference<T>::type>::type>::value,
119-
bool>::type = true>
125+
typename std::enable_if<!is_class_or_union_remove_cvref<T>::value,
126+
bool>::type = true>
120127
result_type operator()(T t) const {
121128
return boost::python::incref(boost::python::object(t).ptr());
122129
}
123130

124131
template <typename T,
125-
typename std::enable_if<
126-
!std::is_arithmetic<typename std::remove_cv<
127-
typename std::remove_reference<T>::type>::type>::value,
128-
bool>::type = true>
132+
typename std::enable_if<is_class_or_union_remove_cvref<T>::value,
133+
bool>::type = true>
129134
result_type operator()(T& t) const {
130135
return boost::python::detail::make_reference_holder::execute(&t);
131136
}
@@ -180,6 +185,15 @@ struct ReturnInternalVariant : boost::python::return_internal_reference<> {
180185
typedef Variant variant_type;
181186

182187
typedef details::VariantConverter<variant_type> result_converter;
188+
189+
template <class ArgumentPackage>
190+
static PyObject* postcall(ArgumentPackage const& args_, PyObject* result) {
191+
// Don't run return_internal_reference postcall on primitive type
192+
if (PyLong_Check(result) || PyBool_Check(result) || PyFloat_Check(result)) {
193+
return result;
194+
}
195+
return boost::python::return_internal_reference<>::postcall(args_, result);
196+
}
183197
};
184198

185199
/// Define a defaults converter to convert a {boost,std}::variant alternative to

unittest/python/test_variant.py.in

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ V2 = variant_module.V2
66
VariantHolder = variant_module.VariantHolder
77
VariantNoneHolder = variant_module.VariantNoneHolder
88
VariantArithmeticHolder = variant_module.VariantArithmeticHolder
9+
VariantBoolHolder = variant_module.VariantBoolHolder
910
make_variant = variant_module.make_variant
1011
make_variant_none = variant_module.make_variant_none
1112
make_variant_arithmetic = variant_module.make_variant_arithmetic
13+
make_variant_bool = variant_module.make_variant_bool
1214

1315
variant = make_variant()
1416
assert isinstance(variant, V1)
@@ -60,19 +62,35 @@ assert variant_none_holder.variant.v == 1
6062
v1 = variant_none_holder.variant
6163
v1.v = 10
6264
assert variant_none_holder.variant.v == 10
65+
# TODO make this work
6366
# variant_none_holder.variant = None
6467

6568

6669
# Test variant that hold base type
6770
v_arithmetic = make_variant_arithmetic()
6871
assert isinstance(v_arithmetic, int)
6972

70-
variant_arithemtic_holder = VariantArithmeticHolder()
71-
assert isinstance(variant_arithemtic_holder.variant, int)
72-
variant_arithemtic_holder.variant = 2.0
73-
assert variant_arithemtic_holder.variant == 2
74-
assert isinstance(variant_arithemtic_holder.variant, float)
75-
# Arithmetic type doesn't support reference
76-
v1 = variant_arithemtic_holder.variant
77-
v1 = 3
78-
assert variant_arithemtic_holder.variant != v1
73+
variant_arithmetic_holder = VariantArithmeticHolder()
74+
assert isinstance(variant_arithmetic_holder.variant, int)
75+
variant_arithmetic_holder.variant = 2
76+
# Raise an exception if return_internal_postcall is called
77+
assert variant_arithmetic_holder.variant == 2
78+
79+
variant_arithmetic_holder.variant = 2.0
80+
assert isinstance(variant_arithmetic_holder.variant, float)
81+
# Raise an exception if return_internal_postcall is called
82+
assert variant_arithmetic_holder.variant == 2.0
83+
84+
v_bool = make_variant_bool()
85+
assert isinstance(v_bool, bool)
86+
87+
variant_bool_holder = VariantBoolHolder()
88+
assert isinstance(variant_bool_holder.variant, bool)
89+
variant_bool_holder.variant = False
90+
# Raise an exception if return_internal_postcall is called
91+
assert not variant_bool_holder.variant
92+
93+
variant_bool_holder.variant = 2.0
94+
assert isinstance(variant_bool_holder.variant, float)
95+
# Raise an exception if return_internal_postcall is called
96+
assert variant_bool_holder.variant == 2.0

unittest/variant.cpp.in

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,17 @@ typedef typename MyVariantNoneHelper<VARIANT<V1> >::type MyVariantNone;
3636

3737
typedef VARIANT<int, double> MyVariantArithmetic;
3838

39+
// There is a conversion conflict between int and bool
40+
typedef VARIANT<bool, double> MyVariantBool;
41+
3942
MyVariant make_variant() { return V1(); }
4043

4144
MyVariantNone make_variant_none() { return MyVariantNone(); }
4245

4346
MyVariantArithmetic make_variant_arithmetic() { return MyVariantArithmetic(); }
4447

48+
MyVariantBool make_variant_bool() { return MyVariantBool(); }
49+
4550
struct VariantHolder {
4651
MyVariant variant;
4752
};
@@ -54,6 +59,10 @@ struct VariantArithmeticHolder {
5459
MyVariantArithmetic variant;
5560
};
5661

62+
struct VariantBoolHolder {
63+
MyVariantBool variant;
64+
};
65+
5766
BOOST_PYTHON_MODULE(@MODNAME@) {
5867
using namespace eigenpy;
5968

@@ -94,4 +103,16 @@ BOOST_PYTHON_MODULE(@MODNAME@) {
94103
bp::make_getter(&VariantArithmeticHolder::variant,
95104
ConverterArithmetic::return_internal_reference()),
96105
bp::make_setter(&VariantArithmeticHolder::variant));
106+
107+
typedef eigenpy::VariantConverter<MyVariantBool> ConverterBool;
108+
ConverterBool::registration();
109+
bp::def("make_variant_bool", make_variant_bool);
110+
111+
boost::python::class_<VariantBoolHolder>("VariantBoolHolder",
112+
bp::init<>())
113+
.add_property(
114+
"variant",
115+
bp::make_getter(&VariantBoolHolder::variant,
116+
ConverterBool::return_internal_reference()),
117+
bp::make_setter(&VariantBoolHolder::variant));
97118
}

0 commit comments

Comments
 (0)