From a6399f2c25b7c94216862ef488f53676dcfc99be Mon Sep 17 00:00:00 2001
From: Julien Michel <julien.michel@cnes.fr>
Date: Tue, 2 Oct 2018 13:28:29 +0200
Subject: [PATCH] ENH: experiment with variadic types (WIP)

---
 Modules/Core/ImageBase/test/CMakeLists.txt    |   2 +-
 .../ImageBase/test/otbFunctorImageFilter.cxx  | 203 ++++++++++++++++++
 .../ImageBase/test/otbImageBaseTestDriver.cxx |   1 +
 3 files changed, 205 insertions(+), 1 deletion(-)
 create mode 100644 Modules/Core/ImageBase/test/otbFunctorImageFilter.cxx

diff --git a/Modules/Core/ImageBase/test/CMakeLists.txt b/Modules/Core/ImageBase/test/CMakeLists.txt
index b2ac501075..ad4522d2e0 100644
--- a/Modules/Core/ImageBase/test/CMakeLists.txt
+++ b/Modules/Core/ImageBase/test/CMakeLists.txt
@@ -40,7 +40,7 @@ set(OTBImageBaseTests
   otbImageTest.cxx
   otbImageFunctionAdaptor.cxx
   otbMetaImageFunction.cxx
-
+  otbFunctorImageFilter.cxx
   )
 
 add_executable(otbImageBaseTestDriver ${OTBImageBaseTests})
diff --git a/Modules/Core/ImageBase/test/otbFunctorImageFilter.cxx b/Modules/Core/ImageBase/test/otbFunctorImageFilter.cxx
new file mode 100644
index 0000000000..9867264535
--- /dev/null
+++ b/Modules/Core/ImageBase/test/otbFunctorImageFilter.cxx
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
+ *
+ * This file is part of Orfeo Toolbox
+ *
+ *     https://www.orfeo-toolbox.org/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#include "otbFunctor.h"
+//#include "otbFunctorImageFilter.h"
+
+#include "otbImage.h"
+#include "otbVectorImage.h"
+#include "itkNeighborhood.h"
+#include "itkImageRegionIterator.h"
+#include "itkImageSource.h"
+#include <tuple>
+
+
+// Proxy to switch image type from T (Jordi has better code for that)
+template <typename T> struct ImageTypeProxy
+{
+  using ImageType = otb::Image<T>;
+};
+
+template <typename T> struct ImageTypeProxy<itk::VariableLengthVector<T> >
+{
+  using ImageType = otb::VectorImage<T>;
+};
+
+
+// Variadic creation of iterator tuple
+template <class T> auto MakeIterator(itk::SmartPointer<T> img)
+{
+  itk::ImageRegionConstIterator<T> it(img,img->GetLargestPossibleRegion());
+  return it;
+}
+
+
+template<class... T>  auto MakeIterators(itk::SmartPointer<T>... args)
+  {
+    return std::make_tuple(MakeIterator(args)...);
+  }
+
+// Variadic call of operator from iterator tuple
+template <class Tuple, class Oper, size_t...Is> auto CallOperatorImpl(Tuple& t, const Oper & oper,std::index_sequence<Is...>)
+{
+  return oper(std::get<Is>(t).Get()...);
+}
+
+template <class Oper, typename ... Args> auto CallOperator(const Oper& oper, std::tuple<Args...> & t)
+{
+  return CallOperatorImpl(t,oper,std::make_index_sequence<sizeof...(Args)>{});
+}
+
+// Variadic move of iterators
+template<class Tuple,size_t...Is> auto MoveIteratorsImpl(Tuple & t, std::index_sequence<Is...>)
+{
+  return std::make_tuple(++(std::get<Is>(t) )...);
+}
+
+template<typename ... Args> void MoveIterators(std::tuple<Args...> & t)
+{
+  MoveIteratorsImpl(t,std::make_index_sequence<sizeof...(Args)>{});
+}
+
+
+// Variadic functor class (will disapear)
+template <typename Out, typename... T> class VariadicFunctor
+{  
+public:  
+  Out operator()(const T&...) const
+    {
+    return Out();
+    }
+
+  unsigned int GetNumberOfVariadicArgs() const
+  {
+    const unsigned int nbArgs = sizeof...(T);
+    return nbArgs;
+  }
+};
+
+// Example of functor
+template<typename Out, typename In1, typename In2> class AddFunctor : public VariadicFunctor<Out,In1,In2>
+{
+public:
+  Out operator()(const In1 & in1, const In2 & in2)
+  {
+    return static_cast<Out>(in1+in2);
+  }
+};
+
+
+template <typename ... Args> void Ignore(Args ...)
+{}
+
+template<class TOuptut, class ... TInputs> class VariadicInputsImageFilter : public itk::ImageSource<TOuptut>
+{
+public:
+  using Self = VariadicInputsImageFilter<TOuptut, TInputs...>;
+  using Pointer =  itk::SmartPointer<Self>;
+  using ConstPointer = itk::SmartPointer<const Self>;
+  using Superclass = itk::ImageSource<TOuptut>;
+
+  using InputTypesTupleType = std::tuple<TInputs...>;
+
+  itkNewMacro(Self);
+  
+  template <std::size_t I> void SetVInput(typename std::tuple_element<I,InputTypesTupleType>::type * inputPtr)
+  {
+    this->SetNthInput(I,inputPtr);
+  }
+
+  template <std::size_t I> const typename std::tuple_element<I,InputTypesTupleType>::type * GetVInput()
+  {
+    using ImageType = typename std::tuple_element<I,InputTypesTupleType>::type;
+    return dynamic_cast<const ImageType *>(this->GetInput(I));
+  }
+
+  void SetVInputs(TInputs*... inputs)
+  {
+    auto inTuple = std::make_tuple(inputs...);
+    SetInputsImpl(inTuple,std::make_index_sequence<sizeof...(inputs)>{});
+  }
+
+protected:
+  VariadicInputsImageFilter()
+  {
+    this->SetNumberOfRequiredInputs(sizeof...(TInputs));
+  };
+  
+  ~VariadicInputsImageFilter() = default;
+  
+private:
+  template<class Tuple, size_t...Is> auto SetInputsImpl(Tuple& t, std::index_sequence<Is...>)
+  {
+    return std::initializer_list<int>{(this->SetVInput<Is>(std::get<Is>(t)),0)...};
+  }
+  
+  VariadicInputsImageFilter(const Self&) = delete;
+  void operator=(const Self&) = delete;
+};
+
+
+using namespace otb;
+
+int otbFunctorImageFilter(int, char ** )
+{
+  using VectorImageType = VectorImage<double>;
+  using ImageType       = Image<unsigned int>;
+  using RegionType      = typename ImageType::RegionType;
+  using SizeType        = typename RegionType::SizeType;
+  using IndexType       = typename RegionType::IndexType;
+  
+  using NeighborhoodType = itk::Neighborhood<double,2>;
+  using VectorPixelType  = typename VectorImageType::PixelType;
+
+  auto vimage = VectorImageType::New();
+  auto image  = ImageType::New();
+
+  SizeType size({200,200});
+  
+  vimage->SetRegions(size);
+  image->SetRegions(size);
+
+  auto f1 = VariadicFunctor<double,itk::VariableLengthVector<double>,double>();
+  std::cout<<"Nb variadic args: "<<f1.GetNumberOfVariadicArgs();
+
+  auto iterators = MakeIterators(vimage,image);
+
+  MoveIterators(iterators);
+
+  auto res = CallOperator(f1,iterators);
+ 
+
+  // auto it = MakeIterator(image,image->GetLargestPossibleRegion(),3, no_radius_tag());
+  // auto vit = MakeIterator(vimage,vimage->GetLargestPossibleRegion(),3,radius_tag());
+
+
+  auto filter = VariadicInputsImageFilter<VectorImageType,VectorImageType,ImageType>::New();
+
+  filter->SetVInput<0>(vimage);
+  filter->SetVInput<1>(image);
+
+  filter->SetVInputs(vimage,image);
+
+  std::cout<<filter->GetVInput<0>()<< filter->GetVInput<1>()<<std::endl;
+  
+  return EXIT_SUCCESS;
+}
diff --git a/Modules/Core/ImageBase/test/otbImageBaseTestDriver.cxx b/Modules/Core/ImageBase/test/otbImageBaseTestDriver.cxx
index 991c0dc859..933b9c5a5b 100644
--- a/Modules/Core/ImageBase/test/otbImageBaseTestDriver.cxx
+++ b/Modules/Core/ImageBase/test/otbImageBaseTestDriver.cxx
@@ -41,4 +41,5 @@ void RegisterTests()
   REGISTER_TEST(otbImageTest);
   REGISTER_TEST(otbImageFunctionAdaptor);
   REGISTER_TEST(otbMetaImageFunction);
+  REGISTER_TEST(otbFunctorImageFilter);
 }
-- 
GitLab