From 4987d73dfca2b0d3cda1687d7747e329713e7cb7 Mon Sep 17 00:00:00 2001 From: Julien Michel <julien.michel@cnes.fr> Date: Fri, 16 Nov 2018 17:35:34 +0100 Subject: [PATCH] ENH: Also support functors of the form void ()(Out&, const In&...) --- .../Functor/include/otbFunctorImageFilter.h | 26 ++++++++ .../Functor/include/otbFunctorImageFilter.hxx | 66 +++++++++++++++++-- .../Functor/test/otbFunctorImageFilter.cxx | 26 ++++++++ 3 files changed, 113 insertions(+), 5 deletions(-) diff --git a/Modules/Core/Functor/include/otbFunctorImageFilter.h b/Modules/Core/Functor/include/otbFunctorImageFilter.h index 2b2be20a40..d52b4fa36d 100644 --- a/Modules/Core/Functor/include/otbFunctorImageFilter.h +++ b/Modules/Core/Functor/include/otbFunctorImageFilter.h @@ -200,6 +200,32 @@ template <typename C, typename R, typename... T> struct FunctorFilterSuperclassH 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 * diff --git a/Modules/Core/Functor/include/otbFunctorImageFilter.hxx b/Modules/Core/Functor/include/otbFunctorImageFilter.hxx index f0a1dc9100..cbc94cb762 100644 --- a/Modules/Core/Functor/include/otbFunctorImageFilter.hxx +++ b/Modules/Core/Functor/include/otbFunctorImageFilter.hxx @@ -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 -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 -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 @@ -229,12 +280,17 @@ FunctorImageFilter<TFunction> itk::ProgressReporter p(this,threadId,outputRegionForThread.GetNumberOfPixels()); 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()) { 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 p.CompletedPixel(); } diff --git a/Modules/Core/Functor/test/otbFunctorImageFilter.cxx b/Modules/Core/Functor/test/otbFunctorImageFilter.cxx index 44fe64ea55..b662d72482 100644 --- a/Modules/Core/Functor/test/otbFunctorImageFilter.cxx +++ b/Modules/Core/Functor/test/otbFunctorImageFilter.cxx @@ -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() { // Deduce types @@ -119,6 +132,19 @@ template <typename T> struct TypesCheck filter->template SetVariadicInput<0>(in); // template keyword to avoid C++ parse ambiguity 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 auto lambda = [] (const TIn &) { -- GitLab