From 4e234a91cdae81a28bd4a05ae72d286f64eb5e20 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Thu, 29 Oct 2020 10:34:12 +0100 Subject: [PATCH 1/4] fix/simplify FilteredSmartRange --- src/OpenMesh/Core/Mesh/SmartRange.hh | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/src/OpenMesh/Core/Mesh/SmartRange.hh b/src/OpenMesh/Core/Mesh/SmartRange.hh index c3fba9f0..6524042c 100644 --- a/src/OpenMesh/Core/Mesh/SmartRange.hh +++ b/src/OpenMesh/Core/Mesh/SmartRange.hh @@ -428,27 +428,10 @@ struct SmartRangeT * @param f Functor that needs to be evaluated to true if the element should not be skipped. */ template - auto filtered(Functor&& f) -> FilteredSmartRangeT::type> + auto filtered(Functor&& f) -> FilteredSmartRangeT { auto range = static_cast(this); - auto b = (*range).begin(); - auto e = (*range).end(); - return FilteredSmartRangeT::type>(f, b, e); - } - - /** @brief Only iterate over a subset of elements - * - * Returns a smart range which skips all elements that do not satisfy functor \p f - * - * @param f Functor that needs to be evaluated to true if the element should not be skipped. - */ - template - auto filtered(Functor& f) -> FilteredSmartRangeT::type&> - { - auto range = static_cast(this); - auto b = (*range).begin(); - auto e = (*range).end(); - return FilteredSmartRangeT::type&>(f, b, e); + return FilteredSmartRangeT(std::forward(f), (*range).begin(), (*range).end()); } }; @@ -488,11 +471,12 @@ struct FilteredSmartRangeT : public SmartRangeT(f)), begin_(std::move(begin)), end_(std::move(end)){} FilteredIterator begin() const { return FilteredIterator(f_, begin_, end_); } FilteredIterator end() const { return FilteredIterator(f_, end_, end_); } From e7148d0dda729284be68f31f86841a8d49bdff17 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Thu, 29 Oct 2020 10:52:34 +0100 Subject: [PATCH 2/4] add MemberFunctionWrapper to conveniently use member functions as predicates --- src/OpenMesh/Core/Utils/Predicates.hh | 33 +++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/OpenMesh/Core/Utils/Predicates.hh b/src/OpenMesh/Core/Utils/Predicates.hh index 332b488a..3bb85a08 100644 --- a/src/OpenMesh/Core/Utils/Predicates.hh +++ b/src/OpenMesh/Core/Utils/Predicates.hh @@ -250,6 +250,39 @@ using RegularQuad = Regular<4,3>; using RegularTri = Regular<6,4>; +/// Wrapper object to hold an object and a member function pointer, +/// and provides operator() to call that member function for that object with one argument +template +struct MemberFunctionWrapper +{ + T t_; // Objects whose member function we want to call + MF mf_; // pointer to member function + + MemberFunctionWrapper(T _t, MF _mf) + : + t_(_t), + mf_(_mf) + {} + + template + auto operator()(const O& _o) -> decltype ((t_.*mf_)(_o)) + { + return (t_.*mf_)(_o); + } +}; + +/// Helper to create a MemberFunctionWrapper without explicitely naming the types +template +MemberFunctionWrapper make_member_function_wrapper(T&& _t, MF _mf) +{ + return MemberFunctionWrapper(std::forward(_t), _mf); +} + +/// Convenience macro to create a MemberFunctionWrapper for *this object +#define OM_MFW(member_function) OpenMesh::Predicates::make_member_function_wrapper(*this, &std::decay::type::member_function) + + + //============================================================================= } // namespace Predicates From ad7f7eccad50ce8d13804e813c2d7b1ecafc436f Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Thu, 29 Oct 2020 11:05:18 +0100 Subject: [PATCH 3/4] add missing include --- src/OpenMesh/Core/Utils/Predicates.hh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/OpenMesh/Core/Utils/Predicates.hh b/src/OpenMesh/Core/Utils/Predicates.hh index 3bb85a08..2880eb5a 100644 --- a/src/OpenMesh/Core/Utils/Predicates.hh +++ b/src/OpenMesh/Core/Utils/Predicates.hh @@ -49,6 +49,7 @@ #include #include #include +#include //== NAMESPACES =============================================================== From 68d408cf411c960b1876022337608aee6fc90dbe Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Thu, 29 Oct 2020 11:05:40 +0100 Subject: [PATCH 4/4] add test for member function wrappper --- src/Unittests/unittests_smart_ranges.cc | 54 +++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/Unittests/unittests_smart_ranges.cc b/src/Unittests/unittests_smart_ranges.cc index ea2d97c9..a547686d 100644 --- a/src/Unittests/unittests_smart_ranges.cc +++ b/src/Unittests/unittests_smart_ranges.cc @@ -856,5 +856,59 @@ TEST_F(OpenMeshSmartRanges, Predicate) test_make_predicate(mesh_); } +struct MemberFunctionWrapperTestStruct +{ + MemberFunctionWrapperTestStruct(int _i) + : + i_(_i) + { + } + + int get_i(const OpenMesh::SmartEdgeHandle& /*_eh*/) const + { + return i_; + } + + bool id_divisible_by_2(const OpenMesh::SmartEdgeHandle& _eh) const + { + return _eh.idx() % 2 == 0; + } + + int valence_times_i(const OpenMesh::SmartVertexHandle& vh) + { + return vh.edges().sum(OM_MFW(get_i)); + } + + int i_; +}; + +TEST_F(OpenMeshSmartRanges, MemberFunctionFunctor) +{ + using namespace OpenMesh::Predicates; + + EXPECT_TRUE(mesh_.n_vertices() > 0) << "Mesh has no vertices"; + EXPECT_TRUE(mesh_.n_edges() > 0) << "Mesh has no edges"; + + int factor = 3; + MemberFunctionWrapperTestStruct test_object(factor); + + // Test using a MemberFunctionWrapper as Functor + EXPECT_EQ(mesh_.n_edges() / 2, mesh_.edges().count_if(make_member_function_wrapper(test_object, &MemberFunctionWrapperTestStruct::id_divisible_by_2))); + + + // Test using a MemberFunctionWrapper as Functor that is created using the convenience macro from inside the struct + for (auto vh : mesh_.vertices()) + EXPECT_EQ(test_object.valence_times_i(vh), vh.valence() * factor); + + factor = 4; + test_object.i_ = factor; + for (auto vh : mesh_.vertices()) + { + EXPECT_EQ(test_object.valence_times_i(vh), vh.valence() * factor); + } + + + +} }