vspline 1.1.0
Generic C++11 Code for Uniform B-Splines
|
interface definition for unary functors More...
Go to the source code of this file.
Classes | |
struct | vspline::unary_functor_tag< _vsize > |
we derive all vspline::unary_functors from this empty class, to have a common base type for all of them. This enables us to easily check if a type is a vspline::unary_functor without having to wrangle with unary_functor's template arguments. More... | |
struct | vspline::unary_functor< IN, OUT, _vsize > |
class unary_functor provides a functor object which offers a system of types for concrete unary functors derived from it. If vectorization isn't used, this is trivial, but with vectorization in use, we get vectorized types derived from plain IN and OUT via query of vspline::vector_traits. More... | |
struct | vspline::callable< derived_type, IN, OUT, vsize > |
mixin 'callable' is used with CRTP: it serves as additional base to unary functors which are meant to provide operator() and takes the derived class as it's first template argument, followed be the argument types and vectorization width, so that the parameter and return type for operator() and - if vsize is greater than 1 - it's vectorized overload can be produced. This formulation has the advantage of not having to rely on the 'out_type_of' mechanism I was using before and provides precisely the operator() overload(s) which are appropriate. More... | |
struct | vspline::broadcast< derived_type, IN, OUT, _vsize > |
struct broadcast is a mixin providing an 'eval' method to a functor which can process vectorized arguments. This mixin is inherited by the functor missing that capability, using CRTP. Because here, in the providing class, nothing is known (or, even, knowable) about the functor, we need to pass additional template arguments to establish the usual vspline unary functor frame of reference, namely in_type, out_type, vsize etc. The resulting 'vectorized' eval may not be efficient: it has to build individual 'in_type' values from the vectorized input, process them with the derived functor's eval routine, then insert the resulting out_type in the vectorized output. But it's a quick way of getting vectorized evaluation capability without writing the vector code. This is particularly useful when the functor's unvectorized eval() is complex (like, calling into legacy code or even into opaque binary) and 'proper' vectorization is hard to do. And with a bit of luck, the optimizer 'recognizes' what's going on and produces SIMD code anyway. Note that the derived class needs a using declaration for the vectorized eval overload inherited from this base class - see broadcast_type (below) for an example of using this mixin. More... | |
struct | vspline::broadcast_type< I, O, S > |
struct | vspline::chain_type< T1, T2 > |
class chain_type is a helper class to pass one unary functor's result as argument to another one. We rely on T1 and T2 to provide a few of the standard types used in unary functors. Typically, T1 and T2 will both be vspline::unary_functors, but the type requirements could also be fulfilled 'manually'. More... | |
struct | vspline::grok_type< IN, OUT, _vsize > |
class grok_type is a helper class wrapping a vspline::unary_functor so that it's type becomes opaque - a technique called 'type erasure', here applied to vspline::unary_functors with their specific capability of providing both vectorized and unvectorized operation in one common object. More... | |
struct | vspline::grok_type< IN, OUT, 1 > |
specialization of grok_type for _vsize == 1 this is the only possible specialization if vectorization is not used. here we don't use _v_ev but only the unvectorized evaluation. More... | |
struct | vspline::amplify_type< _in_type, _out_type, _math_type, _vsize > |
amplify_type amplifies it's input with a factor. If the data are multi-channel, the factor is multi-channel as well and the channels are amplified by the corresponding elements of the factor. I added this class to make work with integer-valued splines more comfortable - if these splines are prefiltered with 'boost', the effect of the boost has to be reversed at some point, and amplify_type does just that when you use 1/boost as the 'factor'. More... | |
struct | vspline::flip< _in_type, _vsize > |
flip functor produces it's input with component order reversed. This can be used to deal with situations where coordinates in the 'wrong' order have to be fed to a functor expecting the opposite order and should be a fast way of doing so, since the compiler can likely optimize it well. I added this class to provide simple handling of incoming NumPy coordinates, which are normally in reverse order of vigra coordinates More... | |
struct | vspline::yield_type< crd_t, data_t, _vsize, enable > |
at times we require reading access to an nD array at given coordinates, as a functor which, receiving the coordinates, produces the values from the array. In the scalar case, this is trivial: if the coordinate is integral, we have a simple indexed access, and if it is real, we can use std::round to produce a nearby discrete coordinate. But for the vectorized case we need a bit more effort: We need to translate the access with a vector of coordinates into a gather operation. We start out with a generalized template class 'yield-type': More... | |
struct | vspline::yield_type< crd_t, data_t, _vsize, typename std::enable_if< crd_integral< crd_t > ::value > ::type > |
struct | vspline::yield_type< crd_t, data_t, _vsize, typename std::enable_if< ! crd_integral< crd_t > ::value > ::type > |
Next, we specialize for real coordinates. More... | |
struct | vspline::sink_functor_tag< _vsize > |
while 'normal' unary_functors are all derived from unary_functor_tag, sink functors will be derived from sink_functor_tag. More... | |
struct | vspline::sink_functor< IN, _vsize > |
sink_functor is used for functors without an output - e.g. reductors which are used for analytic purposes on data sets. They use the same system of input types, but omit the output types. More... | |
Namespaces | |
namespace | vspline |
Typedefs | |
template<typename T > | |
using | vspline::crd_integral = typename std::conditional< std::is_fundamental< T >::value, std::is_integral< T >, std::is_integral< typename T::value_type > > ::type |
First, we specialize for integral coordinates. More... | |
Functions | |
template<class IN , class OUT > | |
std::function< void(const IN &, OUT &) > | vspline::eval_wrap (std::function< OUT(const IN &) > f) |
eval_wrap is a helper function template, wrapping an 'ordinary' function which returns some value given some input in a void function taking input as const reference and writing output to a reference, which is the signature used for evaluation in vspline::unary_functors. More... | |
template<class T1 , class T2 > | |
vspline::chain_type< T1, T2 > | vspline::chain (const T1 &t1, const T2 &t2) |
chain is a factory function yielding the result of chaining two unary_functors. More... | |
template<typename T1 , typename T2 , typename enable = typename std::enable_if < std::is_base_of < vspline::unary_functor_tag < T2::vsize > , T1 > :: value && std::is_base_of < vspline::unary_functor_tag < T1::vsize > , T2 > :: value > :: type> | |
vspline::chain_type< T1, T2 > | vspline::operator+ (const T1 &t1, const T2 &t2) |
using operator overloading, we can exploit operator+'s semantics to chain several unary functors. We need to specifically enable this for types derived from unary_functor_tag to avoid a catch-all situation. More... | |
template<class grokkee_type > | |
vspline::grok_type< typename grokkee_type::in_type, typename grokkee_type::out_type, grokkee_type::vsize > | vspline::grok (const grokkee_type &grokkee) |
grok() is the corresponding factory function, wrapping grokkee in a vspline::grok_type. More... | |
interface definition for unary functors
vspline's evaluation and remapping code relies on a unary functor template which is used as the base for vspline::evaluator and also constitutes the type of object accepted by most of the functions in transform.h.
This template produces functors which are meant to yield a single output for a single input, where both the input and output types may be single types or vigra::TinyVectors, and their elementary types may be vectorized. The functors are expected to provide methods named eval() which are capable of performing the required functionality. These eval routines take both their input and output by reference - the input is taken by const &, and the output as plain &. The result type of the eval routines is void. While such unary functors can be hand-coded, the class template 'unary_functor' provides services to create such functors in a uniform way, with a specifc system of associated types and some convenience code. Using unary_functor is meant to facilitate the creation of the unary functors used in vspline.
Using unary_functor generates objects which can be easily combined into more complex unary functors, a typical use would be to 'chain' two unary_functors, see class template 'chain_type' below, which also provides an example for the use of unary_functor.
class unary_functor takes three template arguments:
The vectorized argument and result type are deduced from IN, OUT and _vsize by querying vspline::vector_traits. When using Vc (-DUSE_VC), these types will be Vc::SimdArrays if the elementary type can be used to form a SimdArray. Otherwise vspline provides a fallback type emulating vectorization: vspline::simd_type. This fallback type emulates just enough of SimdArray's capabilities to function as a replacement inside vspline's body of code.
So where is eval() or operator()? Not in class unary_functor. The actual functionality is provided by the derived class. There is deliberately no code concerning evaluation in class unary_functor. My initial implementation had pure virtual functions to define the interface for evaluation, but this required explicitly providing the overloads in the derived class. Simply omitting any reference to evaluation allows the derived class to accomplish evaluation with a template if the code is syntactically the same for vectorized and unvectorized operation. To users of concrete functors inheriting from unary_functor this makes no difference. The only drawback is that it's not possible to perform evaluation via a base class pointer or reference. But this is best avoided anyway because it degrades performance. If the need arises to have several unary_functors with the same template signature share a common type, there's a mechanism to make the internals opaque by 'grokking'. grokking provides a wrapper around a unary_functor which hides it's type, vspline::grok_type directly inherits from unary_functor and the only template arguments are IN, OUT and _vsize. This hurts performance a little - just as calling via a base class pointer/reference would, but the code is outside class unary_functor and therefore only activated when needed.
Class vspline::evaluator is itself coded as a vspline::unary_functor and can serve as another example for the use of the code in this file.
Before the introduction of vspline::simd_type, vectorization was done with Vc or not at all. Now vspline::vector_traits will produce Vc types if possible and vspline::simd_type otherwise. This breaks code relying on the fallback to scalar without Vc, and it also breaks code that assumes that Vc is the sole method of vectorization.
Extant code written for use with Vc should function as before as long as USE_VC is defined. It may be possible now to use such code even without Vc. This depends on how much of Vc::SimdArray's functionality is used. If such code runs without Vc, it may still not perform well and possibly even worse than scalar code.
Definition in file unary_functor.h.