From 339d70f77b8f09c85039302134ce1cfbbb0bb827 Mon Sep 17 00:00:00 2001 From: Joris Vaillant Date: Tue, 30 Jan 2024 17:04:46 +0100 Subject: [PATCH] Add blank/monostate support --- include/eigenpy/variant.hpp | 13 ++++++++++++ unittest/python/test_variant.py.in | 22 ++++++++++++++++++++ unittest/variant.cpp.in | 33 ++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/include/eigenpy/variant.hpp b/include/eigenpy/variant.hpp index 8d7b708c..7c3fc50b 100644 --- a/include/eigenpy/variant.hpp +++ b/include/eigenpy/variant.hpp @@ -41,6 +41,10 @@ struct VariantVisitorType > { return std::visit(std::forward(visitor), std::forward(v)); } + + result_type operator()(std::monostate) const { + return boost::python::incref(boost::python::object().ptr()); // None + } }; template @@ -61,6 +65,10 @@ struct VariantVisitorType > static result_type visit(Visitor&& visitor, Visitable&& visitable) { return std::forward(visitable).apply_visitor(visitor); } + + result_type operator()(boost::blank) const { + return boost::python::incref(boost::python::object().ptr()); // None + } }; template @@ -84,6 +92,8 @@ struct VariantValueToObject : VariantVisitorType { result_type operator()(T& t) const { return boost::python::incref(boost::python::object(t).ptr()); } + + using Base::operator(); }; /// Convert {boost,std}::variant alternative reference to a Python @@ -104,6 +114,9 @@ struct VariantRefToObject : VariantVisitorType { result_type operator()(T& t) const { return boost::python::detail::make_reference_holder::execute(&t); } + + /// Copy the object when it's None + using Base::operator(); }; /// Converter used in \see ReturnInternalVariant. diff --git a/unittest/python/test_variant.py.in b/unittest/python/test_variant.py.in index df375b1b..761188f7 100644 --- a/unittest/python/test_variant.py.in +++ b/unittest/python/test_variant.py.in @@ -4,7 +4,9 @@ variant_module = importlib.import_module("@MODNAME@") V1 = variant_module.V1 V2 = variant_module.V2 VariantHolder = variant_module.VariantHolder +VariantNoneHolder = variant_module.VariantNoneHolder make_variant = variant_module.make_variant +make_variant_none = variant_module.make_variant_none variant = make_variant() assert isinstance(variant, V1) @@ -40,3 +42,23 @@ assert v1.v == 1000 variant_holder.variant = v2 assert isinstance(variant_holder.variant, V2) assert variant_holder.variant.v == v2.v + +# Test variant that hold a None value +v_none = make_variant_none() +assert v_none is None +v_none = 1 +assert v_none == 1 +v_none = None +assert v_none is None + +variant_none_holder = VariantNoneHolder() +v_none = variant_none_holder.variant +assert v_none is None + +v1 = V1() +v1.v = 1 +variant_none_holder.variant = v1 +assert variant_none_holder.variant.v == 1 +v1 = variant_none_holder.variant +v1.v = 10 +assert variant_none_holder.variant.v == 10 diff --git a/unittest/variant.cpp.in b/unittest/variant.cpp.in index ee339cc3..3c085361 100644 --- a/unittest/variant.cpp.in +++ b/unittest/variant.cpp.in @@ -17,12 +17,35 @@ struct V2 { }; typedef VARIANT MyVariant; +template +struct MyVariantNoneHelper {}; + +template +struct MyVariantNoneHelper > { + typedef VARIANT type; +}; + +#ifdef EIGENPY_WITH_CXX17_SUPPORT +template +struct MyVariantNoneHelper > { + typedef VARIANT type; +}; +#endif + +typedef typename MyVariantNoneHelper >::type MyVariantNone; + MyVariant make_variant() { return V1(); } +MyVariantNone make_variant_none() { return MyVariantNone(); } + struct VariantHolder { MyVariant variant; }; +struct VariantNoneHolder { + MyVariantNone variant; +}; + BOOST_PYTHON_MODULE(@MODNAME@) { using namespace eigenpy; @@ -41,4 +64,14 @@ BOOST_PYTHON_MODULE(@MODNAME@) { bp::make_getter(&VariantHolder::variant, Converter::return_internal_reference()), bp::make_setter(&VariantHolder::variant)); + + typedef eigenpy::VariantConverter ConverterNone; + ConverterNone::registration(); + bp::def("make_variant_none", make_variant_none); + + boost::python::class_("VariantNoneHolder", bp::init<>()) + .add_property("variant", + bp::make_getter(&VariantNoneHolder::variant, + ConverterNone::return_internal_reference()), + bp::make_setter(&VariantNoneHolder::variant)); }