Merge branch 'MemberFunctionWrapper' into 'master'
Member function wrapper See merge request OpenMesh/OpenMesh!286
This commit is contained in:
@@ -428,27 +428,10 @@ struct SmartRangeT
|
|||||||
* @param f Functor that needs to be evaluated to true if the element should not be skipped.
|
* @param f Functor that needs to be evaluated to true if the element should not be skipped.
|
||||||
*/
|
*/
|
||||||
template <typename Functor>
|
template <typename Functor>
|
||||||
auto filtered(Functor&& f) -> FilteredSmartRangeT<SmartRange, Handle, typename std::decay<Functor>::type>
|
auto filtered(Functor&& f) -> FilteredSmartRangeT<SmartRange, Handle, Functor>
|
||||||
{
|
{
|
||||||
auto range = static_cast<const RangeT*>(this);
|
auto range = static_cast<const RangeT*>(this);
|
||||||
auto b = (*range).begin();
|
return FilteredSmartRangeT<SmartRange, Handle, Functor>(std::forward<Functor>(f), (*range).begin(), (*range).end());
|
||||||
auto e = (*range).end();
|
|
||||||
return FilteredSmartRangeT<SmartRange, Handle, typename std::decay<Functor>::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 <typename Functor>
|
|
||||||
auto filtered(Functor& f) -> FilteredSmartRangeT<SmartRange, Handle, const typename std::decay<Functor>::type&>
|
|
||||||
{
|
|
||||||
auto range = static_cast<const RangeT*>(this);
|
|
||||||
auto b = (*range).begin();
|
|
||||||
auto e = (*range).end();
|
|
||||||
return FilteredSmartRangeT<SmartRange, Handle, const typename std::decay<Functor>::type&>(f, b, e);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -488,11 +471,12 @@ struct FilteredSmartRangeT : public SmartRangeT<FilteredSmartRangeT<RangeT, Hand
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Functor f_;
|
Functor f_; // Should iterators always get a reference to filter stored in range?
|
||||||
|
// Should iterators stay valid after range goes out of scope?
|
||||||
BaseIterator end_;
|
BaseIterator end_;
|
||||||
};
|
};
|
||||||
|
|
||||||
FilteredSmartRangeT(Functor f, BaseIterator begin, BaseIterator end) : f_(f), begin_(begin), end_(end){}
|
FilteredSmartRangeT(Functor&& f, BaseIterator begin, BaseIterator end) : f_(std::forward<Functor>(f)), begin_(std::move(begin)), end_(std::move(end)){}
|
||||||
FilteredIterator begin() const { return FilteredIterator(f_, begin_, end_); }
|
FilteredIterator begin() const { return FilteredIterator(f_, begin_, end_); }
|
||||||
FilteredIterator end() const { return FilteredIterator(f_, end_, end_); }
|
FilteredIterator end() const { return FilteredIterator(f_, end_, end_); }
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
//== NAMESPACES ===============================================================
|
//== NAMESPACES ===============================================================
|
||||||
|
|
||||||
@@ -250,6 +251,39 @@ using RegularQuad = Regular<4,3>;
|
|||||||
using RegularTri = Regular<6,4>;
|
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 <typename T, typename MF>
|
||||||
|
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 <typename O>
|
||||||
|
auto operator()(const O& _o) -> decltype ((t_.*mf_)(_o))
|
||||||
|
{
|
||||||
|
return (t_.*mf_)(_o);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Helper to create a MemberFunctionWrapper without explicitely naming the types
|
||||||
|
template <typename T, typename MF>
|
||||||
|
MemberFunctionWrapper<T,MF> make_member_function_wrapper(T&& _t, MF _mf)
|
||||||
|
{
|
||||||
|
return MemberFunctionWrapper<T,MF>(std::forward<T>(_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<decltype(*this)>::type::member_function)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
} // namespace Predicates
|
} // namespace Predicates
|
||||||
|
|
||||||
|
|||||||
@@ -856,5 +856,59 @@ TEST_F(OpenMeshSmartRanges, Predicate)
|
|||||||
test_make_predicate<FaceHandle>(mesh_);
|
test_make_predicate<FaceHandle>(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user