Commit d05c3374 authored by Jordi Inglada's avatar Jordi Inglada

ADD: draft FunctorImageFilter

parent 8d4e8f1b
//--------------------------------------
// utils/traits: Additional type traits
//--------------------------------------
//
// Copyright kennytm (auraHT Ltd.) 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file doc/LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
/**
``<utils/traits.hpp>`` --- Additional type traits
=================================================
This module provides additional type traits and related functions, missing from
the standard library.
*/
#ifndef TRAITS_HPP_9ALQFEFX7TO
#define TRAITS_HPP_9ALQFEFX7TO 1
#include <cstdlib>
#include <tuple>
#include <functional>
#include <type_traits>
namespace FunctionTraits {
/**
.. macro:: DECLARE_HAS_TYPE_MEMBER(member_name)
This macro declares a template ``has_member_name`` which will check whether
a type member ``member_name`` exists in a particular type.
Example::
DECLARE_HAS_TYPE_MEMBER(result_type)
...
printf("%d\n", has_result_type< std::plus<int> >::value);
// ^ prints '1' (true)
printf("%d\n", has_result_type< double(*)() >::value);
// ^ prints '0' (false)
*/
#define DECLARE_HAS_TYPE_MEMBER(member_name) \
template <typename, typename = void> \
struct has_##member_name \
{ enum { value = false }; }; \
template <typename T> \
struct has_##member_name<T, typename std::enable_if<sizeof(typename T::member_name)||true>::type> \
{ enum { value = true }; };
/**
.. type:: struct utils::function_traits<F>
Obtain compile-time information about a function object *F*.
This template currently supports the following types:
* Normal function types (``R(T...)``), function pointers (``R(*)(T...)``)
and function references (``R(&)(T...)`` and ``R(&&)(T...)``).
* Member functions (``R(C::*)(T...)``)
* ``std::function<F>``
* Type of lambda functions, and any other types that has a unique
``operator()``.
* Type of ``std::mem_fn`` (only for GCC's libstdc++ and LLVM's libc++).
Following the C++ spec, the first argument will be a raw pointer.
*/
template <typename T>
struct function_traits
: public function_traits<decltype(&T::operator())>
{};
namespace xx_impl
{
template <typename C, typename R, typename... A>
struct memfn_type
{
typedef typename std::conditional<
std::is_const<C>::value,
typename std::conditional<
std::is_volatile<C>::value,
R (C::*)(A...) const volatile,
R (C::*)(A...) const
>::type,
typename std::conditional<
std::is_volatile<C>::value,
R (C::*)(A...) volatile,
R (C::*)(A...)
>::type
>::type type;
};
}
template <typename ReturnType, typename... Args>
struct function_traits<ReturnType(Args...)>
{
/**
.. type:: type result_type
The type returned by calling an instance of the function object type *F*.
*/
typedef ReturnType result_type;
/**
.. type:: type function_type
The function type (``R(T...)``).
*/
typedef ReturnType function_type(Args...);
/**
.. type:: type member_function_type<OwnerType>
The member function type for an *OwnerType* (``R(OwnerType::*)(T...)``).
*/
template <typename OwnerType>
using member_function_type = typename xx_impl::memfn_type<
typename std::remove_pointer<typename std::remove_reference<OwnerType>::type>::type,
ReturnType, Args...
>::type;
/**
.. data:: static const size_t arity
Number of arguments the function object will take.
*/
enum { arity = sizeof...(Args) };
/**
.. type:: type arg<n>::type
The type of the *n*-th argument.
*/
template <size_t i>
struct arg
{
typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
};
};
template <typename ReturnType, typename... Args>
struct function_traits<ReturnType(*)(Args...)>
: public function_traits<ReturnType(Args...)>
{};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...)>
: public function_traits<ReturnType(Args...)>
{
typedef ClassType& owner_type;
};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
: public function_traits<ReturnType(Args...)>
{
typedef const ClassType& owner_type;
};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) volatile>
: public function_traits<ReturnType(Args...)>
{
typedef volatile ClassType& owner_type;
};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const volatile>
: public function_traits<ReturnType(Args...)>
{
typedef const volatile ClassType& owner_type;
};
template <typename FunctionType>
struct function_traits<std::function<FunctionType>>
: public function_traits<FunctionType>
{};
#if defined(_GLIBCXX_FUNCTIONAL)
#define MEM_FN_SYMBOL_XX0SL7G4Z0J std::_Mem_fn
#elif defined(_LIBCPP_FUNCTIONAL)
#define MEM_FN_SYMBOL_XX0SL7G4Z0J std::__mem_fn
#endif
#ifdef MEM_FN_SYMBOL_XX0SL7G4Z0J
template <typename R, typename C>
struct function_traits<MEM_FN_SYMBOL_XX0SL7G4Z0J<R C::*>>
: public function_traits<R(C*)>
{};
template <typename R, typename C, typename... A>
struct function_traits<MEM_FN_SYMBOL_XX0SL7G4Z0J<R(C::*)(A...)>>
: public function_traits<R(C*, A...)>
{};
template <typename R, typename C, typename... A>
struct function_traits<MEM_FN_SYMBOL_XX0SL7G4Z0J<R(C::*)(A...) const>>
: public function_traits<R(const C*, A...)>
{};
template <typename R, typename C, typename... A>
struct function_traits<MEM_FN_SYMBOL_XX0SL7G4Z0J<R(C::*)(A...) volatile>>
: public function_traits<R(volatile C*, A...)>
{};
template <typename R, typename C, typename... A>
struct function_traits<MEM_FN_SYMBOL_XX0SL7G4Z0J<R(C::*)(A...) const volatile>>
: public function_traits<R(const volatile C*, A...)>
{};
#undef MEM_FN_SYMBOL_XX0SL7G4Z0J
#endif
template <typename T>
struct function_traits<T&> : public function_traits<T> {};
template <typename T>
struct function_traits<const T&> : public function_traits<T> {};
template <typename T>
struct function_traits<volatile T&> : public function_traits<T> {};
template <typename T>
struct function_traits<const volatile T&> : public function_traits<T> {};
template <typename T>
struct function_traits<T&&> : public function_traits<T> {};
template <typename T>
struct function_traits<const T&&> : public function_traits<T> {};
template <typename T>
struct function_traits<volatile T&&> : public function_traits<T> {};
template <typename T>
struct function_traits<const volatile T&&> : public function_traits<T> {};
#define FORWARD_RES_8QR485JMSBT \
typename std::conditional< \
std::is_lvalue_reference<R>::value, \
T&, \
typename std::remove_reference<T>::type&& \
>::type
/**
.. function:: auto utils::forward_like<Like, T>(T&& t) noexcept
Forward the reference *t* like the type of *Like*. That means, if *Like* is
an lvalue (reference), this function will return an lvalue reference of *t*.
Otherwise, if *Like* is an rvalue, this function will return an rvalue
reference of *t*.
This is mainly used to propagate the expression category (lvalue/rvalue) of
a member of *Like*, generalizing ``std::forward``.
*/
template <typename R, typename T>
FORWARD_RES_8QR485JMSBT forward_like(T&& input) noexcept
{
return static_cast<FORWARD_RES_8QR485JMSBT>(input);
}
#undef FORWARD_RES_8QR485JMSBT
/**
.. type:: struct utils::copy_cv<From, To>
Copy the CV qualifier between the two types. For example,
``utils::copy_cv<const int, double>::type`` will become ``const double``.
*/
template <typename From, typename To>
struct copy_cv
{
private:
typedef typename std::remove_cv<To>::type raw_To;
typedef typename std::conditional<std::is_const<From>::value,
const raw_To, raw_To>::type const_raw_To;
public:
/**
.. type:: type type
Result of cv-copying.
*/
typedef typename std::conditional<std::is_volatile<From>::value,
volatile const_raw_To, const_raw_To>::type type;
};
/**
.. type:: struct utils::pointee<T>
Returns the type by derefering an instance of *T*. This is a generalization
of ``std::remove_pointer``, that it also works with iterators.
*/
template <typename T>
struct pointee
{
/**
.. type:: type type
Result of dereferencing.
*/
typedef typename std::remove_reference<decltype(*std::declval<T>())>::type type;
};
/**
.. function:: std::add_rvalue_reference<T>::type utils::rt_val<T>() noexcept
Returns a value of type *T*. It is guaranteed to do nothing and will not
throw a compile-time error, but using the returned result will cause
undefined behavior.
*/
template <typename T>
typename std::add_rvalue_reference<T>::type rt_val() noexcept
{
return std::move(*static_cast<T*>(nullptr));
}
}
#endif
......@@ -27,6 +27,7 @@
#include "itkConstNeighborhoodIterator.h"
#include "itkProcessObject.h"
#include <type_traits>
#include "otbFunctionTraits.h"
namespace otb
{
......@@ -34,15 +35,16 @@ namespace otb
template<typename TOutput>
struct ImageFunctorBase
{
using OutputImageType = typename std::conditional<std::is_scalar<TOutput>::value,
otb::Image<TOutput>,
otb::VectorImage<TOutput>>::type;
void SetRadius(size_t r)
{
m_Radius = r;
}
unsigned int GetNumberOfOutputBands() const
{
return 1;
}
protected:
size_t m_Radius = 0;
......@@ -65,6 +67,60 @@ struct ImageFunctor<typename itk::ConstNeighborhoodIterator<TInput>,
using InputImageType = TInput;
};
template<typename T>
using FTraits = typename FunctionTraits::function_traits<T>;
template<typename T>
using FResultType = typename FTraits<T>::result_type;
template<typename T, size_t i>
using ArgType = typename FTraits<T>::template arg<i>::type;
template<typename T>
using InputArgumentType = ArgType<T, 0>;
template<class T, class R = void>
struct enable_if_type { typedef R type; };
template<class T, class Enable = void>
struct IsNeighborhood : std::false_type {};
template<class T>
struct IsNeighborhood<T, typename enable_if_type<typename T::NeighborhoodType>::type> : std::true_type
{};
template<typename TFunction, bool B = true>
struct TII
{
using type = typename InputArgumentType<TFunction>::ImageType;
};
template<typename TFunction>
struct TII<TFunction, !IsNeighborhood<InputArgumentType<TFunction>>::value>
{
using InputArgument = InputArgumentType<TFunction>;
using type = typename std::conditional<std::is_scalar<InputArgument>::value,
typename otb::Image<InputArgument>,
typename otb::VectorImage<InputArgument>
>::type ;
};
template<typename TFunction>
using TInputImage = typename TII<TFunction>::type;
// OutputImageType: if the result of the
// functor is a scalar -> otb::Image,
// otherwise, otb::VectorImage
template<typename TFunction, typename ResultType = FResultType<TFunction>>
using TOutputImage =
typename std::conditional< std::is_scalar<ResultType>::value,
typename otb::Image<ResultType>,
typename otb::VectorImage<ResultType>
>::type;
/** \class FunctorImageFilter
* \brief Implements
*
......@@ -75,22 +131,24 @@ struct ImageFunctor<typename itk::ConstNeighborhoodIterator<TInput>,
* \ingroup OTBImageManipulation
*/
template <class TFunction>
class ITK_EXPORT FunctorImageFilter
: public itk::ImageToImageFilter<typename TFunction::InputImageType,
typename TFunction::OutputImageType>
class ITK_EXPORT FunctorImageFilter
: public itk::ImageToImageFilter<TInputImage<TFunction>, TOutputImage<TFunction>>
{
public:
using Self = FunctorImageFilter;
using FunctorType = TFunction;
using Pointer = itk::SmartPointer<Self>;
using ConstPointer = itk::SmartPointer<const Self>;
using InputImageType = typename FunctorType::InputImageType;
using InputImageType = TInputImage<TFunction>;
using InputImagePointer = typename InputImageType::ConstPointer;
using InputImageRegionType = typename InputImageType::RegionType;
using InputImagePixelType = typename InputImageType::PixelType;
using InputImageSizeType = typename InputImageType::SizeType;
using InputImageIndexType = typename InputImageType::IndexType;
using OutputImageType = typename FunctorType::OutputImageType;
using OutputImageType = TOutputImage<TFunction>;
using OutputImagePointer = typename OutputImageType::Pointer;
using OutputImageRegionType = typename OutputImageType::RegionType;
using OutputImagePixelType = typename OutputImageType::PixelType;
......@@ -98,32 +156,33 @@ public:
OutputImageType>;
using ProcessObjectType = itk::ProcessObject;
/** Method for creation by passing the filter type. */
itkNewMacro(Self);
/** Method for creation by passing the filter type. */
static Pointer New(const FunctorType& f) ;
/** Run-time type information (and related methods). */
itkTypeMacro(FunctorImageFilter, ImageToImageFilter);
itkTypeMacro(FunctorImageFilter, ImageToImageFilter);
/** Get the functor object. The functor is returned by reference.
* (Functors do not have to derive from itk::LightObject, so they do
* not necessarily have a reference count. So we cannot return a
* SmartPointer.) */
FunctorType& GetFunctor()
{
this->Modified();
return m_Functor;
}
FunctorType& GetFunctor()
{
this->Modified();
return m_Functor;
}
/** Get the functor object. The functor is returned by reference.
* (Functors do not have to derive from itk::LightObject, so they do
* not necessarily have a reference count. So we cannot return a
* SmartPointer.) */
const FunctorType& GetFunctor() const
{
return m_Functor;
}
const FunctorType& GetFunctor() const
{
return m_Functor;
}
/** Set the functor object. This replaces the current Functor with a
* copy of the specified Functor. This allows the user to specify a
......@@ -138,7 +197,8 @@ void SetFunctor(const FunctorType& functor)
}
private:
FunctorImageFilter(){} ;
FunctorImageFilter();
FunctorImageFilter(const FunctorType& f) : m_Functor(f) {};
FunctorImageFilter(const Self &) ;
void operator =(const Self&) ;
~FunctorImageFilter() override {}
......
......@@ -28,6 +28,21 @@
namespace otb
{
template <class TFunction>
FunctorImageFilter<TFunction>::FunctorImageFilter()
{
// this->SetNumberOfRequiredInputs(m_Functor.GetNumberOfInputs());
// this->InPlaceOff();
}
template <class TFunction>
typename FunctorImageFilter<TFunction>::Pointer
FunctorImageFilter<TFunction>::New(const TFunction& f)
{
Pointer p = new FunctorImageFilter<TFunction>(f);
return p;
}
template <class TFunction>
void
FunctorImageFilter<TFunction>
......
......@@ -71,7 +71,7 @@ otbImageToNoDataMaskFilter.cxx
otbChangeInformationImageFilter.cxx
otbGridResampleImageFilter.cxx
otbMaskedIteratorDecorator.cxx
otbFunctorFilter.cxx
otbFunctorImageFilter.cxx
)
add_executable(otbImageManipulationTestDriver ${OTBImageManipulationTests})
......@@ -623,6 +623,6 @@ otb_add_test(NAME bfTvMaskedIteratorDecoratorExtended COMMAND otbImageManipulati
otbMaskedIteratorDecoratorExtended
)
otb_add_test(NAME bfTvFunctorFilter COMMAND otbImageManipulationTestDriver
otbFunctorFilter
otb_add_test(NAME bfTvFunctorImageFilter COMMAND otbImageManipulationTestDriver
otbFunctorImageFilter
)
......@@ -49,12 +49,26 @@ struct Funct3 : otb::ImageFunctor<IntImageNeighborhood,
}
};
auto Lambda1 = [](double p)
{
return p;
};
int otbFunctorFilter(int itkNotUsed(argc), char * itkNotUsed(argv) [])
using OImage = typename otb::Image<int>;
using Neig = typename itk::ConstNeighborhoodIterator<OImage>;
static_assert(otb::IsNeighborhood<Neig>::value, "err");
static_assert(!otb::IsNeighborhood<OImage>::value, "err");
static_assert(!otb::IsNeighborhood<double>::value, "err");
int otbFunctorImageFilter(int itkNotUsed(argc), char * itkNotUsed(argv) [])
{
auto filter1 = otb::FunctorImageFilter<Funct1>::New();
auto filter2 = otb::FunctorImageFilter<Funct2>::New();
auto filter3 = otb::FunctorImageFilter<Funct3>::New();
return EXIT_SUCCESS;
auto filter1 = otb::FunctorImageFilter<Funct1>::New(Funct1{});
auto filter2 = otb::FunctorImageFilter<Funct2>::New(Funct2{});
auto filter3 = otb::FunctorImageFilter<Funct3>::New(Funct3{});
auto filter4 = otb::FunctorImageFilter<decltype(Lambda1)>::New(Lambda1);
return EXIT_SUCCESS;
}
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