MArray Expression Template Internals
[The Class MArray]

Classes

Files

Defines

Functions


Detailed Description

This documentation explains the internal expression template mechanism. It should not be necessary to understand all this to use the LTL.

The anatomy of expression templates:

Expressions like the right-hand side of

     A = A + B*C;

(with A, B, and C being of type ltl::MArray<float,1>) are represented by nested templated data types that capture the parse tree of the expression.

In this example, the expression A + B*C is represented by the type (simplified for readability)

     ltl::ExprBinopNode<ltl::MArrayIterConst<float, 1>,
                        ltl::ExprNode<ltl::ExprBinopNode<ltl::MArrayIterConst<float, 1>,
                                                         ltl::MArrayIterConst<float, 1>,
                                                         ltl::__ltl_TMul<float, float>,
                                                         1>,
                                      1>,
                        ltl::__ltl_TAdd<float, float>,
                        1>

In real code, we'd want all possible parse tree nodes to be of one single type so that any expression argument can be caught by a single templated type. Therefore, each of the parse tree nodes is wrapped in a template class ExprNode<>, which forwards all calls to the parse tree node it wraps.

The class ExprNode<> defines an iterator-like interface that all parse tree nodes (and ultimately the iterators that parse tree nodes hold) implement. This way, a whole expression, and every sub-expression presents an iterator interface to the outside world.

For this to function we define

Ultimately, the expression is evaluated by

    template<typename E>
    ltl::MArray<float,1>::operator=( ExprNode<E,1> ).

which uses the iterator-like interface of the expression to loop over each element of the underlying (multidimensional) array structure.

TODO: properly document the new ET mechanism, and also all types derived from ExprBase, e.g. MergeExpr, ... and how to add user-defined expressions.


Define Documentation

#define BINOP_AA ( operator,
op   ) 

Define the global binary functions/operators for ltl::MArray expressions, version for 2 MArray operands, overloaded versions below.

Each binary function/operator takes opjects derived from ExprBase (MArray, ExprNode), or literals as arguments and returns a parse-tree node for the operation it represents:

    ExprNode <ExprBinopNode <A, B, Operation, NDim> > function( A& rhs, B& lhs )

where LHS and RHS are of type ExprBase or (scalar) literals.

There are 8 combination of argument types for binary ops, namely:

array op array,
array op scalar,
scalar op array,
expr op array,
array op expr,
expr op expr,
scalar op expr, and
expr op scalar.

An overloaded function/operator template is generated by these macros for each of these cases. The literal type is assumed to be of the same type as the elements of the expr (or be type-castable to that type).

This might seem like it could be reduced to 3 cases by unifying the overloaded functions for array and expr to take ExprBase objects as arguments. However, this causes ambiguous overloads with the cases taking an arbitrary type (a scalar).

#define UNOP_E ( operator,
op   ) 

Define the global unary operators, overloaded versions for marray operand.

Each unary function/operator takes objects derived from ExprBase (ltl::MArray, ltl::ExprNode) as arguments and returns a parse-tree node for the operation it represents:

    ExprNode <ExprUnopNode <A, Operation, NDim> > function( A& operand )

where operand is of type ExprBase.

#define DECLARE_BINOP ( operation,
opname   ) 

Make a binary (built-in) operator available to expression templates.This macro declares all necessary overloaded operators to build the parse tree for a given binary operator operation. The return type is the standard C type-promoted result of the operation on built in scalar types.

It is assumed that the name of the applicative template for the same operator is called ltl::__ltl_opname and that this template is defined elsewhere (misc/applicops.h for built-in operators).

#define DECLARE_UNOP ( operation,
opname   ) 

Make a unary (built-in) operator available to expression templates.This macro declares all necessary overloaded operators to build the parse tree for a given unary operator operation. The return type is the standard C type-promoted result of the operation on built in scalar types.

It is assumed that the name of the applicative template for the same operator is called ltl::__ltl_opname and that this template is defined elsewhere (misc/applicops.h for built-in operators).

#define DECLARE_BINARY_FUNC_ ( function   ) 

Make any binary function available to expression templates.This macro declares all necessary overloaded operators to build the parse tree for a given binary function function. The return type may be different than the operand type.

It is assumed that the name of the applicative template for the same function is called ltl::__ltl_function and that this template is defined elsewhere. (misc/applicops.h for standard functions).

The function itself has to be implemented with the signature

    template <typename T>
    T function( const T& a, const T& b );
#define DECLARE_UNARY_FUNC_ ( function   ) 

Make any unary function available to expression templates.This macro declares all necessary overloaded operators to build the parse tree for a given unary function function. The return type may be different than the operand type.

It is assumed that the name of the applicative template for the same function is called ltl::__ltl_function and that this template is defined elsewhere (misc/applicops.h for standard functions).

The function itself has to be implemented with the signature

    template <typename T>
    T function( const T& a );
#define DECLARE_BINARY_FUNC ( function,
ret_type   ) 
Value:
MAKE_BINAP_FUNC( __ltl_##function, ret_type, function );     \
DECLARE_BINARY_FUNC_(function)

Make any user-defined binary function available to expression templates.This macro declares all necessary overloaded operators to build the parse tree for a given binary function function. The return type may be different than the operand type.

This macro also declares and defines the applicative templates for this function. It is the only macro that needs to be called by users to make user-defined functions available to expression templates.

Assume you have a function like this:

    template <typename T>
    ret_type function( const T& a, const T& b );

Then using

    DECLARE_BINARY_FUNC(function, ret_type);

This function will be usable in expression templates.

#define DECLARE_UNARY_FUNC ( function,
ret_type   ) 
Value:
MAKE_UNAP_FUNC( __ltl_##function, ret_type, function );       \
DECLARE_UNARY_FUNC_(function)

Make any user-defined unary function available to expression templates.This macro declares all necessary overloaded operators to build the parse tree for a given unary function function. The return type may be different than the operand type.

This macro also declares and defines the applicative templates for this function. It is the only macro that needs to be called by users to make user-defined functions available to expression templates.

Assume you have a function like this:

    template <typename T>
    ret_type function( const T& a );

Then using

    DECLARE_BINARY_FUNC(function, ret_type);

This function will be usable in expression templates.


Function Documentation

template<typename A , typename B >
const Shape<A::dims>* ltl::_expr_getshape ( const A &  a,
const B &   
) [inline]

Determine the shape of an expression by returning the ltl::Shape objects on one of the ltl::MArray operatnds.

Determine the shape of an expression

When determining the shape of an expression it is sufficient to return any one shape object from any one of the MArrays in the expression since we know they will all be the conformable. However, we must make sure that we do not ask e.g. a literal constant for a shape ...

In the general case, just use the LHS Shape ... We will provide partial specializations for the cases where one of the operands does not have a shape and return the other instead.

Referenced by ltl::ExprBinopNode< A, B, Op, N >::shape().

template<typename A , typename B >
int ltl::_expr_getalign ( const A &  a,
const B &   
) [inline]

Determine the alignment (w.r.t. natural vector boundaries) of the operands in an expression.

When determining the alignment of an expression it is sufficient to return any one of the alignments from any one of the MArrays in the expression since we only vectorize if we know the alignments are the same. However, we must make sure that we do not ask e.g. a literal constant for a it's alignment ...

In the general case, just use the LHS's alignment ... We will provide partial specializations for the cases where one of the operands does not have an alignment and return the other's instead.


Generated on 19 Feb 2015 for LTL by  doxygen 1.6.1