Commit 4987d73d authored by Julien Michel's avatar Julien Michel

ENH: Also support functors of the form void ()(Out&, const In&...)

parent 490d8c35
...@@ -200,6 +200,32 @@ template <typename C, typename R, typename... T> struct FunctorFilterSuperclassH ...@@ -200,6 +200,32 @@ template <typename C, typename R, typename... T> struct FunctorFilterSuperclassH
using InputHasNeighborhood = std::tuple<typename IsNeighborhood<T>::ValueType...>; using InputHasNeighborhood = std::tuple<typename IsNeighborhood<T>::ValueType...>;
}; };
/// Partial specialisation for void(*)(R &,T...)
template <typename R, typename... T> struct FunctorFilterSuperclassHelper<void(*)(R&, T...)>
{
using OutputImageType = typename ImageTypeDeduction<R>::ImageType;
using FilterType = VariadicInputsImageFilter<OutputImageType,typename ImageTypeDeduction<typename PixelTypeDeduction<T>::PixelType>::ImageType...>;
using InputHasNeighborhood = std::tuple<typename IsNeighborhood<T>::ValueType...>;
};
/// Partial specialisation for void(C::*)(R&,T...) const
template <typename C, typename R, typename... T> struct FunctorFilterSuperclassHelper<void(C::*)(R&,T...) const>
{
using OutputImageType = typename ImageTypeDeduction<R>::ImageType;
using FilterType = VariadicInputsImageFilter<OutputImageType,typename ImageTypeDeduction<typename PixelTypeDeduction<T>::PixelType>::ImageType...>;
using InputHasNeighborhood = std::tuple<typename IsNeighborhood<T>::ValueType...>;
};
/// Partial specialisation for void(C::*)(R&,T...)
template <typename C, typename R, typename... T> struct FunctorFilterSuperclassHelper<void(C::*)(R&,T...)>
{
using OutputImageType = typename ImageTypeDeduction<R>::ImageType;
using FilterType = VariadicInputsImageFilter<OutputImageType,typename ImageTypeDeduction<typename PixelTypeDeduction<T>::PixelType>::ImageType...>;
using InputHasNeighborhood = std::tuple<typename IsNeighborhood<T>::ValueType...>;
};
/** /**
* \brief This helper method builds a fully functional FunctorImageFilter from a functor instance * \brief This helper method builds a fully functional FunctorImageFilter from a functor instance
* *
......
...@@ -138,16 +138,67 @@ template <typename T> struct GetProxy<itk::ConstNeighborhoodIterator<T> > ...@@ -138,16 +138,67 @@ template <typename T> struct GetProxy<itk::ConstNeighborhoodIterator<T> >
} }
}; };
template <class Oper> struct OperProxy : public OperProxy<decltype(&Oper::operator())> {};
template<class Out, class ... In> struct OperProxy<Out(*)(In...)>
{
template <class Oper> static void Compute(Oper& oper, Out& out, const In& ... in)
{
out = oper(in...);
}
};
template<class C, class Out, class ... In> struct OperProxy<Out(C::*)(In...)>
{
template<class Oper> static void Compute(Oper& oper, Out& out, const In& ... in)
{
out = oper(in...);
}
};
template<class C, class Out, class ... In> struct OperProxy<Out(C::*)(In...) const>
{
template<class Oper> static void Compute(Oper& oper, Out& out, const In& ... in)
{
out = oper(in...);
}
};
template<class Out, class ... In> struct OperProxy<void(*)(Out&, In...)>
{
template<class Oper> static void Compute(Oper& oper, Out& out, const In& ... in)
{
oper(out,in...);
}
};
template<class C, class Out, class ... In> struct OperProxy<void(C::*)(Out&, In...)>
{
template<class Oper> static void Compute(Oper& oper, Out& out, const In& ... in)
{
oper(out,in...);
}
};
template<class C, class Out, class ... In> struct OperProxy<void(C::*)(Out&, In...) const>
{
template template<class Oper> static void Compute(Oper& oper, Out& out, const In& ... in)
{
oper(out,in...);
}
};
// Will be easier to write in c++17 with std::apply and fold expressions // Will be easier to write in c++17 with std::apply and fold expressions
template <class Tuple, class Oper, size_t...Is> auto CallOperatorImpl(Tuple& t, const Oper & oper,std::index_sequence<Is...>) template <class Tuple, class Out, class Oper, size_t...Is> auto CallOperatorImpl(Tuple& t, Out & out, const Oper & oper,std::index_sequence<Is...>)
{ {
return oper(GetProxy<typename std::remove_reference<decltype(std::get<Is>(t))>::type>::Get(std::get<Is>(t))...); OperProxy<Oper>::Compute(oper,out,GetProxy<typename std::remove_reference<decltype(std::get<Is>(t))>::type>::Get(std::get<Is>(t))...);
} }
// Will be easier to write in c++17 with std::apply and fold expressions // Will be easier to write in c++17 with std::apply and fold expressions
template <class Oper, typename ... Args> auto CallOperator(const Oper& oper, std::tuple<Args...> & t) template <class Out, class Oper, typename ... Args> auto CallOperator(Out & out, const Oper& oper, std::tuple<Args...> & t)
{ {
return CallOperatorImpl(t,oper,std::make_index_sequence<sizeof...(Args)>{}); CallOperatorImpl(t,out,oper,std::make_index_sequence<sizeof...(Args)>{});
} }
// Variadic move of iterators // Variadic move of iterators
...@@ -229,12 +280,17 @@ FunctorImageFilter<TFunction> ...@@ -229,12 +280,17 @@ FunctorImageFilter<TFunction>
itk::ProgressReporter p(this,threadId,outputRegionForThread.GetNumberOfPixels()); itk::ProgressReporter p(this,threadId,outputRegionForThread.GetNumberOfPixels());
auto inputIterators = functor_filter_details::MakeIterators(this->GetVariadicInputs(),outputRegionForThread, m_Radius,InputHasNeighborhood{}); auto inputIterators = functor_filter_details::MakeIterators(this->GetVariadicInputs(),outputRegionForThread, m_Radius,InputHasNeighborhood{});
// Build a default value
typename OutputImageType::PixelType outputValueHolder;
itk::NumericTraits<typename OutputImageType::PixelType>::SetLength(outputValueHolder,this->GetOutput()->GetNumberOfComponentsPerPixel());
while(!outIt.IsAtEnd()) while(!outIt.IsAtEnd())
{ {
for(;!outIt.IsAtEndOfLine();++outIt,functor_filter_details::MoveIterators(inputIterators)) for(;!outIt.IsAtEndOfLine();++outIt,functor_filter_details::MoveIterators(inputIterators))
{ {
outIt.Set(functor_filter_details::CallOperator(m_Functor,inputIterators)); functor_filter_details::CallOperator(outputValueHolder,m_Functor,inputIterators);
outIt.Set(outputValueHolder);
// Update progress // Update progress
p.CompletedPixel(); p.CompletedPixel();
} }
......
...@@ -90,7 +90,20 @@ template <typename T> struct TypesCheck ...@@ -90,7 +90,20 @@ template <typename T> struct TypesCheck
} }
}; };
template <typename TOut,typename TIn> struct TestOperatorVoidReturn
{
void operator()(TOut& out,const TIn&) const
{
out = TOut(OutputSize());
}
constexpr size_t OutputSize(...) const
{
return 1;
}
};
template <typename TOut, typename TIn> void TestFilter() template <typename TOut, typename TIn> void TestFilter()
{ {
// Deduce types // Deduce types
...@@ -119,6 +132,19 @@ template <typename T> struct TypesCheck ...@@ -119,6 +132,19 @@ template <typename T> struct TypesCheck
filter->template SetVariadicInput<0>(in); // template keyword to avoid C++ parse ambiguity filter->template SetVariadicInput<0>(in); // template keyword to avoid C++ parse ambiguity
filter->Update(); filter->Update();
// Test with void return
auto functorWithVoidReturn = TestOperatorVoidReturn<TOut,TIn>{};
auto filterWithVoidReturn = NewFunctorFilter(functorWithVoidReturn);
using FilterWithVoidReturnType = typename decltype(filter)::ObjectType;
static_assert(FilterWithVoidReturnType::NumberOfInputs == 1,"");
static_assert(std::is_same<typename FilterWithVoidReturnType::template InputImageType<0>, InputImageType>::value, "");
filterWithVoidReturn->SetVariadicInputs(in);
filterWithVoidReturn->SetInput1(in);
filterWithVoidReturn->template SetVariadicInput<0>(in); // template keyword to avoid C++ parse ambiguity
filterWithVoidReturn->Update();
// Test with simple lambda // Test with simple lambda
auto lambda = [] (const TIn &) auto lambda = [] (const TIn &)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment