LTL  2.0.x
Files | Classes | Macros | Functions
MArray Expression Template Internals

Files

file  expr_base.h
 This file defines the base class for all operands in expression templates.
 

Classes

class  ltl::ExprNode< A, N >
 Node in the expression parse tree. Every expression in ultimately represented by this class. More...
 
class  ltl::ExprBinopNode< A, B, Op, N >
 Binary operation node in the expression parse tree. More...
 
class  ltl::ExprUnopNode< A, Op, N >
 Unary operation node in the expression parse tree. More...
 
class  ltl::ExprLiteralNode< T >
 Node in the expression parse tree representing a literal number. More...
 
struct  ltl::ExprBase< Derived_T, N_Dims >
 

Macros

#define BINOP_AA(operator, op)
 Define the global binary functions/operators for ltl::MArray expressions, version for 2 MArray operands, overloaded versions below. More...
 
#define UNOP_E(operator, op)
 Define the global unary operators, overloaded versions for marray operand. More...
 
#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. More...
 
#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. More...
 
#define DECLARE_BINARY_FUNC(function, ret_type)
 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. More...
 
#define DECLARE_UNARY_FUNC(function, ret_type)
 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. More...
 

Functions

template<typename A , typename B >
const Shape< A::dims > * ltl::_expr_getshape (const A &a, const B &)
 Determine the shape of an expression by returning the ltl::Shape objects on one of the ltl::MArray operatnds. More...
 
template<typename A , typename B >
int ltl::_expr_getalign (const A &a, const B &)
 Determine the alignment (w.r.t. natural vector boundaries) of the operands in an expression. More...
 
#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. More...
 
#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. More...
 

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::__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>
*

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.

Macro Definition 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 ); \
#define MAKE_BINAP_FUNC(classname, ret_type, func)
Definition: applicops.h:104
#define DECLARE_BINARY_FUNC_(function)
Make any binary function available to expression templates.This macro declares all necessary overload...
Definition: expr.h:1290

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 ); \
#define DECLARE_UNARY_FUNC_(function)
Make any unary function available to expression templates.This macro declares all necessary overloade...
Definition: expr.h:1319
#define MAKE_UNAP_FUNC(classname, ret_type, op)
Definition: applicops.h:132

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.