src/PETE/PETE.h

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 /***************************************************************************
00003  *
00004  * The IPPL Framework
00005  * 
00006  *
00007  * Visit http://people.web.psi.ch/adelmann/ for more details
00008  *
00009  ***************************************************************************/
00010 
00011 
00013 //
00014 // FILE NAME
00015 //    PETE.h
00016 //
00017 // CREATED
00018 //    July 11, 1997
00019 //
00020 // DESCRIPTION
00021 //    PETE: Portable Expression Template Engine.
00022 //
00023 //    This header file defines the objects and operators necessary to use
00024 //    expression templates for a fairly large class of problems.
00025 //
00026 //    It defines template functions for the standard unary, binary and 
00027 //    trinary operators.  Each of them is defined for only certain types to 
00028 //    prevent clashes with global operator+.
00029 //
00031 
00032 #ifndef PETE_H
00033 #define PETE_H
00034 
00035 
00036 // include files
00037 #include "PETE/TypeComputations.h"
00038 #include "Utility/PAssert.h"
00039 
00040 #include <stdlib.h>
00041 #ifndef __MWERKS__
00042 #include <memory.h>
00043 #endif
00044 
00045 
00046 //=========================================================================
00047 //
00048 // PETE BASE CLASS DEFINITIONS
00049 //
00050 //=========================================================================
00051 
00053 //
00054 // CLASS NAME
00055 //    PETE_Expr<W>
00056 //
00057 // DESCRIPTION
00058 //    The base class for all objects that will participate in expressions
00059 //    All this wrapper class needs to do is let you convert back to 
00060 //    the type W.
00061 //
00062 //    The intended use for PETE_Expr is as a base class for
00063 //    a class you want to be able to enter into PETE expressions.
00064 //    You construct a PETE aware class by saying:
00065 //
00066 //    class W : public PETE_Expr<W>
00067 //    {
00068 //       ...
00069 //    };
00070 //
00071 //    Then a function that will recognize PETE expressions can do:
00072 //
00073 //    template<class W>
00074 //    void foo(const PETE_Expr<W>& wrapped_expr)
00075 //    {
00076 //      const W& expr = wrapped_expr.PETE_unwrap();
00077 //      ... do stuff with expr ...
00078 //    }
00079 // 
00081 
00082 template<class WrappedExpr>
00083 class PETE_Expr 
00084 {
00085 public:
00086 
00087   typedef WrappedExpr Wrapped;
00088 
00089   WrappedExpr& PETE_unwrap() 
00090   { 
00091     return static_cast<WrappedExpr&>(*this);
00092   }
00093   const WrappedExpr& PETE_unwrap() const 
00094   { 
00095     return static_cast<const WrappedExpr&>(*this);
00096   }
00097 
00098 };
00099 
00100 
00102 //
00103 // CLASS NAME
00104 //    PETE_Scalar<T>
00105 //
00106 // DESCRIPTION
00107 //    A wrapper around a scalar to be used in PETE expressions.
00108 //
00109 //    This is a simple illustration of how one makes a class PETE-aware.
00110 //    First, notice that PETE_Scalar<T> inherits publically from 
00111 //    PETE_Expr< PETE_Scalar<T> >. In addition, a PETE-aware class must
00112 //    provide two typedefs:
00113 //
00114 //      PETE_Expr_t: this is the actual class that will be used to
00115 //        compute an expression. Many simple classes act as both
00116 //        containers and cursor-like classes, so, often, this
00117 //        will simply be the class itself. However, classes with
00118 //        an STL-like iterator should use the iterator as PETE_Expr_t.
00119 //      PETE_Return_t: this is the type returned by evaluating the
00120 //        expression. Typically, this is the element-type of a container.
00121 //        For PETE_Scalar, this is the type of scalar.
00122 //
00123 //   Classes need to supply a member function of the form:
00124 //
00125 //      PETE_Expr_t MakeExpression() const { ... }
00126 //
00127 //   This function should construct and return an appropriate object of
00128 //   type PETE_Expr_t.
00129 //
00130 //   Finally, PETE really does its work by applying Functors recursively
00131 //   through the tree that represents an expression. At the leaves of the
00132 //   tree, these Functors encounter user classes like PETE_Scalar. There
00133 //   are three Functors that all user classes should support:
00134 //
00135 //      EvalFunctor_0: returns a value for the leaf part of the expression.
00136 //        This Functor has no arguments so most containers will need to
00137 //        supply a cursor-like class that returns the current container value.
00138 //        The cursor is bumped using another Functor, PETE_Increment. 
00139 //      PETE_Increment: moves the cursor to the next element.
00140 //      PETE_CountElems: returns the number of elements in the container.
00141 //        Used for testing conformance, for example.
00142 //
00143 //   The actual code for evaluating these Functors for a particular user class
00144 //   is contained in a global function named 'for_each'. Users classes need
00145 //   to define a different 'for_each' for each Functor.
00146 // 
00148 
00149 template<class T>
00150 class PETE_Scalar : public PETE_Expr< PETE_Scalar<T> >
00151 {
00152 public:
00153 
00154   // Required PETE typedefs and expression creation function.
00155   
00156   typedef PETE_Scalar<T> PETE_Expr_t;
00157   typedef T PETE_Return_t;
00158 
00159   PETE_Expr_t MakeExpression() const { return *this; }
00160 
00161   // Default constructor takes no action.
00162 
00163   PETE_Scalar() { }
00164 
00165   // Constructor from a single value.
00166 
00167   PETE_Scalar(const T& t) : scalar(t) { }
00168 
00169 #ifdef IPPL_PURIFY
00170   // Copy constructor.
00171 
00172   PETE_Scalar(const PETE_Scalar<T>& model) : scalar(model.scalar) { }
00173 
00174   // Assignment operator
00175 
00176   PETE_Scalar<T>&
00177   operator=(const PETE_Scalar<T>& rhs)
00178   {
00179     scalar = rhs.scalar;
00180     return *this; 
00181   }
00182 #endif
00183 
00184   // Conversion to a type T.
00185 
00186   operator T() const { return scalar; }
00187 
00188 private:
00189 
00190   T scalar;
00191 
00192 };
00193 
00194 //=========================================================================
00195 //
00196 // BASIC FUNCTORS AND for_each FUNCTIONS FOR PETE_Scalar
00197 //
00198 //=========================================================================
00199 
00200 // Evaluation functor, no offsets.
00201 
00202 struct EvalFunctor_0
00203 {
00204 #ifdef IPPL_PURIFY
00205   EvalFunctor_0() {}
00206   EvalFunctor_0(const EvalFunctor_0 &) {}
00207   EvalFunctor_0& operator=(const EvalFunctor_0 &) { return *this; }
00208 #endif
00209 };
00210 
00211 // Increment functor
00212 
00213 struct PETE_Increment
00214 {
00215   typedef int PETE_Return_t;
00216 #ifdef IPPL_PURIFY
00217   PETE_Increment() {}
00218   PETE_Increment(const PETE_Increment &) {}
00219   PETE_Increment& operator=(const PETE_Increment &) { return *this; }
00220 #endif
00221 };
00222 
00223 // Element count functor.
00224 
00225 struct PETE_CountElems
00226 {
00227   typedef int PETE_Return_t;
00228 #ifdef IPPL_PURIFY
00229   PETE_CountElems() {}
00230   PETE_CountElems(const PETE_CountElems &) {}
00231   PETE_CountElems& operator=(const PETE_CountElems &) { return *this; }
00232 #endif
00233 };
00234 
00235 // Behavior of basic Functors for PETE_Scalar:
00236 
00237 // Evaluate a scalar.
00238 
00239 template<class T>
00240 inline T
00241 for_each(const PETE_Scalar<T>& p, EvalFunctor_0)
00242 {
00243 #ifdef IPPL_SGI_PRAGMAS
00244 #pragma inline here
00245 #endif
00246   return T(p);
00247 }
00248 
00249 // Cursor increment, ignored by scalar.
00250 
00251 template<class T, class C>
00252 inline int
00253 for_each(PETE_Scalar<T>&, PETE_Increment, C)
00254 {
00255   return 0;
00256 }
00257 
00258 // Count elements, scalar returns code value -1.
00259 
00260 template<class T, class C>
00261 inline int
00262 for_each(const PETE_Scalar<T>&, PETE_CountElems, C)
00263 {
00264   return -1;
00265 }
00266 
00267 
00268 //=========================================================================
00269 //
00270 // PETE TREE CLASSES
00271 //
00272 //=========================================================================
00273 
00275 //
00276 // CLASS NAME
00277 //    PETE_TUTree<Value_t, Child_t>
00278 //
00279 // DESCRIPTION
00280 //    A tree node for representing unary expressions. The node holds a
00281 //    Child (of type Child_t), which is the type of the expression sub tree,
00282 //    a Value (of type Value_t), which is typically the operation applied to
00283 //    the sub tree.
00284 // 
00286 
00287 template<class Value_t, class Child_t>
00288 struct PETE_TUTree : public PETE_Expr< PETE_TUTree<Value_t, Child_t> >
00289 {
00290   enum { IsExpr = 1 };
00291   typedef PETE_TUTree<Value_t, Child_t> PETE_Expr_t;
00292   typedef typename PETEUnaryReturn<typename Child_t::PETE_Return_t, 
00293     Value_t>::type PETE_Return_t;
00294   const PETE_Expr_t& MakeExpression() const { return *this; };
00295 
00296   // The value and child expression stored in this node of the tree.
00297   
00298   Value_t Value;
00299   Child_t Child;
00300 
00301   // Default constructor: takes no action.
00302 
00303   PETE_TUTree() { }
00304 
00305   // Constructor using both a value and the child.
00306 
00307   PETE_TUTree(const Value_t& v, const Child_t& c)
00308   : Value(v), Child(c) { }
00309 
00310   // Constructor using just the child.
00311   
00312   PETE_TUTree(const Child_t& c)
00313   : Child(c) { }
00314 
00315 #if ( defined(PETE_BITWISE_COPY) && !defined(IPPL_INSURE) )
00316 
00317   // For efficiency, make the copy constructor bitwise. USE WITH CARE.
00318 
00319   PETE_TUTree(const PETE_TUTree<Value_t,Child_t>& t)
00320   {
00321     memcpy(this, &t, sizeof(*this));
00322   }
00323 
00324 #endif
00325   
00326 };
00327 
00328 
00330 //
00331 // CLASS NAME
00332 //    PETE_TBTree<Value_t, Left_t, Right_t>
00333 //
00334 // DESCRIPTION
00335 //    A tree node for representing binary expressions. The node holds a
00336 //    Left child (of type Left_t), which is the type of the LHS expression 
00337 //    sub tree, a Right child (of type Right_t), which is the type of the RHS 
00338 //    expression sub tree, and a Value (of type Value_t), which is typically 
00339 //    the operation applied to the two sub trees.
00340 // 
00342 
00343 template<class Value_t, class Left_t, class Right_t>
00344 struct PETE_TBTree :
00345   public PETE_Expr< PETE_TBTree<Value_t, Left_t, Right_t> >
00346 {
00347   enum { IsExpr = 1 };
00348   typedef PETE_TBTree<Value_t,Left_t,Right_t> PETE_Expr_t;
00349   typedef typename PETEBinaryReturn<typename Left_t::PETE_Return_t,
00350     typename Right_t::PETE_Return_t, Value_t>::type  PETE_Return_t;
00351   const PETE_Expr_t& MakeExpression() const { return *this; };
00352 
00353   // The value and left/right sub expressions stored in this node of the tree.
00354   
00355   Value_t Value;
00356   Left_t  Left;
00357   Right_t Right;
00358 
00359   // Default ctor: takes no action.
00360   
00361   PETE_TBTree() { }
00362 
00363   // Constructor using both the value and the two children.
00364   
00365   PETE_TBTree(const Value_t& v, const Left_t& l, const Right_t& r)
00366   : Value(v), Left(l), Right(r) { }
00367 
00368   // Constructor using just the two children.
00369   
00370   PETE_TBTree(const Left_t& l, const Right_t& r)
00371   : Left(l), Right(r) { }
00372 
00373 #if ( defined(PETE_BITWISE_COPY) && !defined(IPPL_INSURE) )
00374 
00375   // For efficiency, make the copy constructor bitwise. USE WITH CARE.
00376 
00377   PETE_TBTree(const PETE_TBTree<Value_t, Left_t, Right_t>& t)
00378   {
00379     memcpy(this,&t,sizeof(*this));
00380   }
00381 
00382 #endif
00383 
00384 };
00385 
00386 
00388 //
00389 // CLASS NAME
00390 //    PETE_TTTree<Value_t, Left_t, Middle_t, Right_t>
00391 //
00392 // DESCRIPTION
00393 //    A tree node for representing trinary expressions. The node holds a
00394 //    Left child (of type Left_t), which is the type of the LHS expression 
00395 //    sub tree (typically a comparison operation); a Middle child (of type
00396 //    Middle_t), which is the type of the middle (true branch) expression
00397 //    sub tree; a Right child (of type Right_t), which is the type of 
00398 //    the expression (false branch) sub tree; and a Value (of type Value_t), 
00399 //    which is typically the operation applied to the three sub trees.
00400 // 
00402 
00403 template< class Value_t, class Left_t, class Middle_t, class Right_t >
00404 class PETE_TTTree
00405   : public PETE_Expr< PETE_TTTree< Value_t, Left_t, Middle_t, Right_t > >
00406 {
00407 public:
00408   enum { IsExpr = 1 };
00409   typedef PETE_TTTree<Value_t,Left_t,Middle_t,Right_t> PETE_Expr_t;
00410   typedef typename PETETrinaryReturn<typename Left_t::PETE_Return_t, 
00411     typename Middle_t::PETE_Return_t,
00412     typename Right_t::PETE_Return_t, Value_t>::type PETE_Return_t;
00413   const PETE_Expr_t& MakeExpression() const { return *this; };
00414 
00415   // The value and left, right, and middle sub trees stored at this node.
00416 
00417   Value_t  Value;
00418   Left_t   Left;
00419   Middle_t Middle;
00420   Right_t  Right;
00421 
00422   // Default ctor: takes no action.
00423 
00424   PETE_TTTree() { }
00425 
00426   // Constructor using the value and three children.
00427 
00428   PETE_TTTree(const Value_t& v, const Left_t& l, 
00429     const Middle_t& m, const Right_t& r)
00430     : Value(v), Left(l), Middle(m), Right(r) { }
00431 
00432   // Constructor with just the three children.
00433 
00434   PETE_TTTree(const Left_t& l, const Middle_t& m,const Right_t& r)
00435     : Left(l), Middle(m), Right(r) {}
00436 
00437 #if ( defined(PETE_BITWISE_COPY) && !defined(IPPL_INSURE) )
00438 
00439   // For efficiency, make the copy constructor bitwise. USE WITH CARE.
00440 
00441   PETE_TTTree(const PETE_TTTree<Value_t, Left_t, Middle_t, Right_t>& t)
00442   {
00443     memcpy(this,&t,sizeof(*this));
00444   }
00445 
00446 #endif
00447 };
00448 
00449 
00450 //=========================================================================
00451 //
00452 // DEFAULT for_each FUNCTIONS INVOLVING PETE TREES
00453 // 
00454 //=========================================================================
00455 
00456 template<class Op, class T1, class Functor, class Combiner>
00457 inline
00458 typename Functor::PETE_Return_t
00459 for_each(PETE_TUTree<Op,T1>& node, Functor f, Combiner c)
00460 {
00461 #ifdef IPPL_SGI_PRAGMAS
00462 #pragma inline here
00463 #endif
00464   return c(for_each(node.Child, f, c));
00465 }
00466 
00467 template<class Op, class T1, class T2, class Functor, class Combiner>
00468 inline
00469 typename Functor::PETE_Return_t
00470 for_each(PETE_TBTree<Op,T1,T2>& node, Functor f, Combiner c)
00471 {
00472 #ifdef IPPL_SGI_PRAGMAS
00473 #pragma inline here
00474 #endif
00475   return c(for_each(node.Left, f, c), for_each(node.Right, f, c));
00476 }
00477 
00478 template<class Op, class T1, class T2, class T3, class Functor, class Combiner>
00479 inline
00480 typename Functor::PETE_Return_t
00481 for_each(PETE_TTTree<Op,T1,T2,T3>& node, Functor f, Combiner c)
00482 {
00483 #ifdef IPPL_SGI_PRAGMAS
00484 #pragma inline here
00485 #endif
00486   return c(for_each(node.Left, f, c), for_each(node.Middle, f, c) ,
00487     for_each(node.Right, f, c));
00488 }
00489 
00490 
00491 //
00492 // A useful combiner.
00493 //
00494 template<class T, class Op>
00495 struct PETE_Combiner
00496 {
00497 #ifdef IPPL_PURIFY
00498   PETE_Combiner() {}
00499   PETE_Combiner(const PETE_Combiner<T,Op> &) {}
00500   PETE_Combiner<T,Op>& operator=(const PETE_Combiner<T,Op> &) { return *this; }
00501 #endif
00502   T operator()(T x) { return x; }
00503   T operator()(T x, T y) { return PETE_apply(Op(),x,y); }
00504   T operator()(T x, T y, T z) {return PETE_apply(Op(),x,PETE_apply(Op(),y,z));}
00505 };
00506 
00507 struct AssertEquals
00508 {
00509 #ifdef IPPL_PURIFY
00510   AssertEquals() {}
00511   AssertEquals(const AssertEquals &) {}
00512   AssertEquals& operator=(const AssertEquals &) { return *this; }
00513 #endif
00514   int operator()(int l)
00515   {
00516     return l;
00517   }
00518   int operator()(int l, int r)
00519   {
00520     int ret = l;
00521     if ( (l>=0) && (r>=0) ) {
00522       PInsist(l==r,"Arguments not equal in AssertEquals()!!");
00523     }
00524     else {
00525       if ( r>=0 ) return ret = r;
00526     }
00527     return ret;
00528   }
00529   int operator()(int l, int m, int r)
00530   {
00531     int ret = l;
00532     if ( (l>=0) && (m>=0) && (r>=0) ) {
00533       PInsist(m==l && m==r,"Arguments not equal in AssertEquals()!!");
00534     }
00535     else if ( l>=0 ) {
00536       return l;
00537     }
00538     else if ( m>=0) {
00539       return m;
00540     }
00541     else if ( r>=0) {
00542       return r;
00543     }
00544     return ret;
00545   }
00546 };
00547 
00548 //
00549 // A combiner for when you don't want to return a value.
00550 //
00551 
00552 struct PETE_NullCombiner
00553 {
00554 #ifdef IPPL_PURIFY
00555   PETE_NullCombiner() {}
00556   PETE_NullCombiner(const PETE_NullCombiner &) {}
00557   PETE_NullCombiner& operator=(const PETE_NullCombiner &) { return *this; }
00558 #endif
00559   int operator()(int) { return 0; }
00560   int operator()(int, int) { return 0; }
00561   int operator()(int, int, int) { return 0; }
00562 };
00563 
00564 //
00565 // Some shorthand for common combiners.
00566 // 
00567 
00568 typedef PETE_Combiner<bool,OpAnd> PETE_AndCombiner;
00569 typedef PETE_Combiner<bool,OpOr> PETE_OrCombiner;
00570 typedef PETE_Combiner<int,OpAdd> PETE_SumCombiner;
00571 
00572 
00574 
00575 //
00576 // for_each functions that recurse through the tree doing evaluation.
00577 //
00578 
00579 template<class Op, class T1, class Functor>
00580 inline
00581 typename PETEUnaryReturn<typename T1::PETE_Return_t,Op>::type
00582 for_each(PETE_TUTree<Op,T1>& node, Functor f)
00583 {
00584 #ifdef IPPL_SGI_PRAGMAS
00585 #pragma inline here
00586 #endif
00587   return PETE_apply(node.Value,
00588                     for_each(node.Child,f));
00589 }
00590 
00591 
00592 template<class Op, class T1, class T2, class Functor>
00593 struct struct_for_each
00594 {
00595   typedef typename PETEBinaryReturn<typename T1::PETE_Return_t,
00596     typename T2::PETE_Return_t,Op>::type
00597   Return_t;
00598 
00599   static inline Return_t
00600   apply(PETE_TBTree<Op,T1,T2>& node, Functor f)
00601     {
00602       return PETE_apply(node.Value, 
00603                         for_each(node.Left,f),
00604                         for_each(node.Right,f) );
00605     }
00606 };
00607 
00608 template<class T>
00609 struct ConditionalAssign
00610 {
00611   ConditionalAssign(bool q, const T& v) : cond(q), value(v) {}
00612 #ifdef IPPL_PURIFY
00613   ConditionalAssign(const ConditionalAssign<T> &model)
00614   {
00615     cond = model.cond;
00616     if (cond)
00617       value = model.value;
00618   }
00619   ConditionalAssign& operator=(const ConditionalAssign<T> &model)
00620   {
00621     cond = model.cond;
00622     if (cond)
00623       value = model.value;
00624     return *this;
00625   }
00626 #endif
00627   bool cond;
00628   T value;
00629 };
00630 
00631 template<class T1, class T2, class Functor>
00632 struct struct_for_each<OpWhere,T1,T2,Functor>
00633 {
00634   typedef typename T2::PETE_Return_t T3;
00635   typedef ConditionalAssign<T3> Return_t;
00636 
00637   static inline Return_t
00638   apply(PETE_TBTree<OpWhere,T1,T2>& node, Functor f)
00639     {
00640       if ( for_each(node.Left,f) )
00641         return Return_t(true,for_each(node.Right,f));
00642       else
00643         return Return_t(false,T3());
00644     }
00645 };
00646 
00647 template<class Op, class T1, class T2, class Functor>
00648 inline
00649 typename struct_for_each<Op,T1,T2,Functor>::Return_t
00650 for_each(PETE_TBTree<Op,T1,T2>& node, Functor f)
00651 {
00652 #ifdef IPPL_SGI_PRAGMAS
00653 #pragma inline here
00654 #endif
00655   return struct_for_each<Op,T1,T2,Functor>::apply(node,f);
00656 }
00657 
00658 /***********************************************************************
00659 
00660   There are two ways to evaluate the trinary where operator:
00661 
00662       if (a) { return b; } else { return c; }
00663 
00664       return a ? b : c;
00665 
00666   The first is safer since b or c could have a divide by zero
00667   or something when it is not supposed to be evaluated, but the
00668   second can be much faster since there are more optimization
00669   opportunities, particularly strength reduction.
00670 
00671   Below we have some trait magic for looking at the right hand sides
00672   and deciding if the expression is "dangerous" and needs to be done
00673   the first way.  Otherwise it does it the second way.
00674 
00675   This uses partial specialization so it is user extensible for
00676   special cases.
00677 
00678 ***********************************************************************/
00679 
00680 template<int I1, int I2> struct SafeCombine {};
00681 template<> struct SafeCombine<0,0> { enum { safe=0 }; };
00682 template<> struct SafeCombine<1,0> { enum { safe=0 }; };
00683 template<> struct SafeCombine<0,1> { enum { safe=0 }; };
00684 template<> struct SafeCombine<1,1> { enum { safe=1 }; };
00685 
00686 // Expressions are safe unless proven otherwise.
00687 template<class Expr> struct SafeExpression { enum { safe=1 }; };
00688 
00689 // Unary expressions are safe if the sub-tree is safe.
00690 template<class Op, class Sub>
00691 struct SafeExpression< PETE_TUTree<Op,Sub> >
00692 {
00693   enum { safe = SafeExpression<Sub>::safe };
00694 };
00695 
00696 // Binary expressions are safe if both sub-trees are safe.
00697 template<class Op, class Left, class Right>
00698 struct SafeExpression< PETE_TBTree<Op,Left,Right> >
00699 {
00700   enum { safe = SafeCombine<SafeExpression<Left>::safe,SafeExpression<Right>::safe>::safe };
00701 };
00702 
00703 // Trinary expressions are safe if the true and false sub-trees are safe.
00704 template<class Op, class Left, class Middle, class Right>
00705 struct SafeExpression< PETE_TTTree<Op,Left,Middle,Right> >
00706 {
00707   enum { safe = SafeCombine<SafeExpression<Middle>::safe,SafeExpression<Right>::safe>::safe };
00708 };
00709 
00710 // OpDivide is unsafe.
00711 template<class Left, class Right>
00712 struct SafeExpression< PETE_TBTree<OpDivide,Left,Right> >
00713 {
00714   enum { safe = 0 };
00715 };
00716 
00717 // Functor class to evaluate the for_each.
00718 // If no specialization matches, use PETE_apply.
00719 // For OpWhere, this will use ?: through PETE_apply
00720 template<int Safe, class T1, class T2, class T3, class Op, class Functor>
00721 struct TrinaryForEach
00722 {
00723   static inline 
00724     typename PETETrinaryReturn<
00725       typename T1::PETE_Return_t, 
00726       typename T2::PETE_Return_t,
00727       typename T3::PETE_Return_t,
00728       Op>::type
00729   apply(PETE_TTTree<Op,T1,T2,T3>& node, Functor f) {
00730     return PETE_apply(node.Value,
00731                       for_each(node.Left,f),
00732                       for_each(node.Middle,f),
00733                       for_each(node.Right,f));
00734   }
00735 };
00736 
00737 // For an unsafe OpWhere, don't evaluate both args.
00738 template<class T1, class T2, class T3, class Functor>
00739 struct
00740 TrinaryForEach<0,T1,T2,T3,OpWhere,Functor>
00741 {
00742   static inline
00743     typename PETETrinaryReturn<
00744       typename T1::PETE_Return_t, 
00745       typename T2::PETE_Return_t,
00746       typename T3::PETE_Return_t,
00747       OpWhere>::type
00748   apply(PETE_TTTree<OpWhere,T1,T2,T3>& node, Functor f) {
00749     return for_each(node.Left,f) ? 
00750            for_each(node.Middle,f) : for_each(node.Right,f);
00751   }
00752 };
00753 
00754 // The general definition of for_each for trinary.
00755 // This just turns around and calls the class function.
00756 template<class T1, class T2, class T3, class Functor,class Op>
00757 inline
00758 typename PETETrinaryReturn<typename T1::PETE_Return_t, 
00759   typename T2::PETE_Return_t,
00760   typename T3::PETE_Return_t,Op>::type
00761 for_each(PETE_TTTree<Op,T1,T2,T3>& node, Functor f)
00762 {
00763   return TrinaryForEach<
00764     SafeExpression< PETE_TTTree<Op,T1,T2,T3> >::safe
00765     ,T1,T2,T3,Op,Functor>::apply(node,f);
00766 }
00767 
00768 //=========================================================================
00769 //
00770 // GENERAL PETE REDUCTION CODE
00771 // 
00772 //=========================================================================
00773 
00774 #if !defined(PETE_USER_REDUCTION_CODE)
00775 
00776 #define PETE_USER_REDUCTION_CODE
00777 
00778 #endif
00779 
00780 template< class R, class T, class InitOp, class AccOp>
00781 void Reduction(R& ret, const PETE_Expr<T>& const_expr,
00782   InitOp init_op, AccOp acc_op )
00783 {
00784   //  Extract the expression.
00785 
00786   typename T::PETE_Expr_t expr(const_expr.PETE_unwrap().MakeExpression());
00787 
00788   // Get the number of elements we will be looping over.
00789   
00790   int n = for_each(expr, PETE_CountElems(), AssertEquals());
00791 
00792   // Make sure there is something to do.
00793   
00794   if (n > 0) {
00795 
00796     // Get the first value.
00797   
00798     PETE_apply(init_op, ret, for_each(expr, EvalFunctor_0()));
00799 
00800     // Loop over all the elements.
00801     for (int i = 1; i < n; ++i)
00802       {
00803         // Increment the cursors.
00804         
00805         for_each(expr, PETE_Increment(), PETE_NullCombiner());
00806       
00807         // Accumulate.
00808       
00809         PETE_apply(acc_op, ret, for_each(expr, EvalFunctor_0()));
00810       }
00811   }
00812 
00813   // Allow users to augment the reduction code.
00814 
00815   PETE_USER_REDUCTION_CODE
00816 }
00817 
00818 
00819 //=========================================================================
00820 //
00821 // UNARY OPERATIONS
00822 // 
00823 //=========================================================================
00824 
00825 #define PETE_DefineUnary(Fun,Expr,Op)                                       \
00826 template<class T>                                                           \
00827 inline typename PETEUnaryReturn<T, Op>::type                                \
00828 PETE_apply(Op, const T& a)                                                  \
00829 {                                                                           \
00830   return Expr;                                                              \
00831 }                                                                           \
00832 template<class T>                                                           \
00833 inline PETE_TUTree<Op, typename T::PETE_Expr_t>                             \
00834 Fun(const PETE_Expr<T>& l)                                                  \
00835 {                                                                           \
00836   return PETE_TUTree<Op, typename T::PETE_Expr_t>                           \
00837     (l.PETE_unwrap().MakeExpression());                                     \
00838 }
00839 
00840 PETE_DefineUnary(operator-, (-a), OpUnaryMinus)
00841 PETE_DefineUnary(operator+, (+a), OpUnaryPlus)
00842 PETE_DefineUnary(operator~, (~a), OpBitwiseNot)
00843 PETE_DefineUnary(operator!, (!a), OpNot)
00844 PETE_DefineUnary(PETE_identity,   (a), OpIdentity)
00845 
00846 PETE_DefineUnary(acos, (acos(a)), FnArcCos)
00847 PETE_DefineUnary(asin, (asin(a)), FnArcSin)
00848 PETE_DefineUnary(atan, (atan(a)), FnArcTan)
00849 PETE_DefineUnary(ceil, (ceil(a)), FnCeil)
00850 PETE_DefineUnary(cos, (cos(a)), FnCos)
00851 PETE_DefineUnary(cosh, (cosh(a)), FnHypCos)
00852 PETE_DefineUnary(exp, (exp(a)), FnExp)
00853 PETE_DefineUnary(fabs, (fabs(a)), FnFabs)
00854 PETE_DefineUnary(floor, (floor(a)), FnFloor)
00855 PETE_DefineUnary(log, (log(a)), FnLog)
00856 PETE_DefineUnary(log10, (log10(a)), FnLog10)
00857 PETE_DefineUnary(sin, (sin(a)), FnSin)
00858 PETE_DefineUnary(sinh, (sinh(a)), FnHypSin)
00859 PETE_DefineUnary(sqrt, (sqrt(a)), FnSqrt)
00860 PETE_DefineUnary(tan, (tan(a)), FnTan)
00861 PETE_DefineUnary(tanh, (tanh(a)), FnHypTan)
00862 
00863 //
00864 // Define OpCast specially because it doesn't fit 
00865 // the pattern that the #define needs.
00866 //
00867 
00868 template<class T1, class T2>
00869 inline T1
00870 PETE_apply(OpCast<T1>, const T2& a)
00871 {
00872   return T1(a);
00873 }
00874 
00875 template<class T1, class Expr>
00876 inline PETE_TUTree<OpCast<T1>, typename Expr::PETE_Expr_t>
00877 pete_cast(const T1&, const PETE_Expr<Expr>& l)
00878 {
00879   return
00880     PETE_TUTree<OpCast<T1>, typename Expr::PETE_Expr_t>
00881     (l.PETE_unwrap().MakeExpression());
00882 }
00883 
00884 //=========================================================================
00885 //
00886 // BINARY OPERATIONS
00887 // 
00888 //=========================================================================
00889 
00890 #define PETE_DefineBinary(Fun,Expr,Op)                                      \
00891 template<class T1, class T2>                                                \
00892 inline typename PETEBinaryReturn<T1, T2, Op>::type                          \
00893 PETE_apply(Op, const T1& a, const T2& b)                                    \
00894 {                                                                           \
00895   return Expr;                                                              \
00896 }                                                                           \
00897 template<class T1, class T2>                                                \
00898 inline PETE_TBTree<Op, typename T1::PETE_Expr_t, typename T2::PETE_Expr_t>  \
00899 Fun(const PETE_Expr<T1>& l, const PETE_Expr<T2>& r)                         \
00900 {                                                                           \
00901   typedef PETE_TBTree<Op,typename T1::PETE_Expr_t,                          \
00902     typename T2::PETE_Expr_t> ret;                                          \
00903   return ret(l.PETE_unwrap().MakeExpression(),                              \
00904     r.PETE_unwrap().MakeExpression());                                      \
00905 }
00906 
00907 #define PETE_DefineBinarySynonym(Fun,Op)                                    \
00908 template<class T1, class T2>                                                \
00909 inline PETE_TBTree<Op, typename T1::PETE_Expr_t, typename T2::PETE_Expr_t>  \
00910 Fun(const PETE_Expr<T1>& l, const PETE_Expr<T2>& r)                         \
00911 {                                                                           \
00912   typedef PETE_TBTree<Op,typename T1::PETE_Expr_t,typename T2::PETE_Expr_t> \
00913     ret;                                                                    \
00914   return ret(l.PETE_unwrap().MakeExpression(),                              \
00915     r.PETE_unwrap().MakeExpression());                                      \
00916 }
00917 
00918 PETE_DefineBinary(operator+, (a + b), OpAdd)
00919 PETE_DefineBinary(operator-, (a - b), OpSubtract)
00920 PETE_DefineBinary(operator*, (a * b), OpMultipply)
00921 PETE_DefineBinary(operator/, (a / b), OpDivide)
00922 PETE_DefineBinary(operator%, (a % b), OpMod)
00923 PETE_DefineBinary(operator<, (a < b), OpLT)
00924 PETE_DefineBinary(operator<=, (a <= b), OpLE)
00925 PETE_DefineBinary(operator>, (a > b), OpGT)
00926 PETE_DefineBinary(operator>=, (a >= b), OpGE)
00927 PETE_DefineBinary(operator==, (a == b), OpEQ)
00928 PETE_DefineBinary(operator!=, (a != b), OpNE)
00929 PETE_DefineBinary(operator&&, (a && b), OpAnd)
00930 PETE_DefineBinary(operator||, (a || b), OpOr)
00931 PETE_DefineBinary(operator&, (a & b), OpBitwiseAnd)
00932 PETE_DefineBinary(operator|, (a | b), OpBitwiseOr)
00933 PETE_DefineBinary(operator^, (a ^ b), OpBitwiseXor)
00934   //PETE_DefineBinary(operator<<, (a << b), OpLeftShift)
00935   //PETE_DefineBinary(operator>>, (a >> b), OpRightShift)
00936 
00937 PETE_DefineBinary(copysign, (copysign(a,b)), FnCopysign)
00938 PETE_DefineBinary(ldexp, (ldexp(a,b)), FnLdexp)
00939 PETE_DefineBinary(pow, (pow(a,b)), FnPow)
00940 PETE_DefineBinary(fmod, (fmod(a,b)), FnFmod)
00941 PETE_DefineBinary(atan2, (atan2(a,b)), FnArcTan2)
00942 
00943 #define PETE_DefineBinaryWithScalars(Fun,Op,Sca)                            \
00944 template<class T>                                                           \
00945 inline PETE_TBTree<Op, PETE_Scalar<Sca>, typename T::PETE_Expr_t>           \
00946 Fun(const Sca l, const PETE_Expr<T>& r)                                     \
00947 {                                                                           \
00948   typedef PETE_TBTree<Op, PETE_Scalar<Sca>, typename T::PETE_Expr_t> ret;   \
00949   return ret(PETE_Scalar<Sca>(l), r.PETE_unwrap().MakeExpression());        \
00950 }                                                                           \
00951 template<class T>                                                           \
00952 inline PETE_TBTree<Op, typename T::PETE_Expr_t, PETE_Scalar<Sca> >          \
00953 Fun(const PETE_Expr<T>& l, const Sca r)                                     \
00954 {                                                                           \
00955   typedef PETE_TBTree<Op, typename T::PETE_Expr_t, PETE_Scalar<Sca> > ret;  \
00956   return ret(l.PETE_unwrap().MakeExpression(), PETE_Scalar<Sca>(r));        \
00957 }
00958 
00959 
00960 //=========================================================================
00961 //
00962 // TRINARY OPERATORS
00963 //
00964 //=========================================================================
00965 
00966 #define PETE_DefineTrinary(Fun,Expr,Op)                                     \
00967 template<class T1, class T2, class T3>                                      \
00968 inline typename PETETrinaryReturn<T1,T2,T3,Op>::type                        \
00969 PETE_apply(Op, const T1& a, const T2& b, const T3& c)                       \
00970 {                                                                           \
00971   return Expr;                                                              \
00972 }                                                                           \
00973 template<class Cond_t, class True_t, class False_t>                         \
00974 inline PETE_TTTree<Op, typename Cond_t::PETE_Expr_t,                        \
00975   typename True_t::PETE_Expr_t, typename False_t::PETE_Expr_t>              \
00976 Fun(const PETE_Expr<Cond_t>& c, const PETE_Expr<True_t>& t,                 \
00977   const PETE_Expr<False_t>& f)                                              \
00978 {                                                                           \
00979   typedef PETE_TTTree<Op, typename Cond_t::PETE_Expr_t,                     \
00980     typename True_t::PETE_Expr_t, typename False_t::PETE_Expr_t> ret;       \
00981   return ret(c.PETE_unwrap().MakeExpression(),                              \
00982     t.PETE_unwrap().MakeExpression(),                                       \
00983     f.PETE_unwrap().MakeExpression());                                      \
00984 }
00985 
00986 template<class T1, class T2, class T3>
00987 inline typename PETETrinaryReturn<T1,T2,T3,OpWhere>::type
00988 PETE_apply(OpWhere, const T1& a, const T2& b, const T3& c)
00989 {
00990   return a ? b : c;
00991 }
00992 
00993 template<class Cond_t, class True_t, class False_t>
00994 inline PETE_TTTree<OpWhere, typename Cond_t::PETE_Expr_t, 
00995   typename True_t::PETE_Expr_t,
00996   typename False_t::PETE_Expr_t>
00997 where(const PETE_Expr<Cond_t>& c, const PETE_Expr<True_t>& t,
00998   const PETE_Expr<False_t>& f)
00999 {
01000   typedef PETE_TTTree<OpWhere, typename Cond_t::PETE_Expr_t, 
01001     typename True_t::PETE_Expr_t,
01002     typename False_t::PETE_Expr_t> ret;
01003   return ret(c.PETE_unwrap().MakeExpression(),
01004     t.PETE_unwrap().MakeExpression(),
01005     f.PETE_unwrap().MakeExpression());
01006 }
01007 
01008 
01009 #define PETE_DefineTrinaryWithScalars(Fun, Op, Sca)                         \
01010 template<class Cond_t, class True_t>                                        \
01011 inline PETE_TTTree<Op, typename Cond_t::PETE_Expr_t,                        \
01012   typename True_t::PETE_Expr_t, PETE_Scalar<Sca> >                          \
01013 Fun(const PETE_Expr<Cond_t>& c, const PETE_Expr<True_t>& t,Sca f)           \
01014 {                                                                           \
01015   typedef PETE_TTTree<Op, typename Cond_t::PETE_Expr_t,                     \
01016     typename True_t::PETE_Expr_t, PETE_Scalar<Sca> > ret;                   \
01017   return ret(c.PETE_unwrap().MakeExpression(),                              \
01018     t.PETE_unwrap().MakeExpression(), PETE_Scalar<Sca>(f));                 \
01019 }                                                                           \
01020 template<class Cond_t, class False_t>                                       \
01021 inline PETE_TTTree<Op, typename Cond_t::PETE_Expr_t, PETE_Scalar<Sca>,      \
01022   typename False_t::PETE_Expr_t >                                           \
01023 Fun(const PETE_Expr<Cond_t>& c, Sca t, const PETE_Expr<False_t>& f)         \
01024 {                                                                           \
01025   typedef PETE_TTTree<Op, typename Cond_t::PETE_Expr_t, PETE_Scalar<Sca>,   \
01026     typename False_t::PETE_Expr_t > ret;                                    \
01027   return ret(c.PETE_unwrap().MakeExpression(),                              \
01028     PETE_Scalar<Sca>(t), f.PETE_unwrap().MakeExpression());                 \
01029 }                                                                           \
01030 template<class Cond_t>                                                      \
01031 inline PETE_TTTree<Op, typename Cond_t::PETE_Expr_t, PETE_Scalar<Sca>,      \
01032   PETE_Scalar<Sca> >                                                        \
01033 Fun(const PETE_Expr<Cond_t>& c, Sca t, Sca f)                               \
01034 {                                                                           \
01035   typedef PETE_TTTree<Op, typename Cond_t::PETE_Expr_t, PETE_Scalar<Sca>,   \
01036     PETE_Scalar<Sca> > ret;                                                 \
01037   return ret(c.PETE_unwrap().MakeExpression(),                              \
01038     PETE_Scalar<Sca>(t), PETE_Scalar<Sca>(f));                              \
01039 }
01040 
01041 
01042 //=========================================================================
01043 //
01044 // Two argument where
01045 //
01046 //   The conventional where operator has three arguments:
01047 //      where(conditional, true_expr, false_expr)
01048 //   It acts much like the ?: operator in expressions.
01049 //
01050 //   A common usage of that structure is 
01051 //      A = where(conditional,true_expr,A);
01052 //   to do something only in the locations where the conditional is true.
01053 //   This is inefficient.
01054 //
01055 //   The two argument where supports the following:
01056 //      A = where(conditional,true_expr);
01057 //   and means the same thing as the three argument version above.
01058 //
01059 //   This form of where cannot be used in expressions in which the where
01060 //   is not the whole right hand side of the expression.
01061 //
01062 //======================================================================
01063 //
01064 // EXPLANATION
01065 //
01066 //   The three argument where operator above produces code something 
01067 //   like this in the inner loop:
01068 //
01069 //      for (i=...)
01070 //        a(i) = conditional(i) ? true_expr(i) : false_expr(i);
01071 //
01072 //   The two argument where has to produce something like:
01073 //
01074 //      for (i=...)
01075 //        if ( conditional(i) ) 
01076 //          a(i) = true_expr(i);
01077 //
01078 //   Two things are being made conditional here: evaluating true_expr
01079 //   and assigning it to a.
01080 //
01081 //   In order to do that inside of expression templates, the following 
01082 //   things need to happen when evaluating an expression:
01083 //
01084 //   1. Evaluating the binary OpWhere expression returns a
01085 //   ConditionalAssign<T> with two components: A boolean for whether
01086 //   the conditional was true, and the result of evaluating the
01087 //   expression of type T.
01088 //
01089 //   2. The expression only gets evaluated if the conditional is true.
01090 //   If it is not true, then the ConditionalAssign<T> uses a default ctor
01091 //   to leave the T undefined.
01092 //
01093 //   3. The assigment operator from the ConditionalAssign<T> to a type
01094 //   T only actually does the assignment if the bool is true.
01095 //
01096 //=========================================================================
01097 
01098 PETE_DefineBinarySynonym(where, OpWhere)
01099 
01100 //=========================================================================
01101 //
01102 // SCALARS
01103 //
01104 //=========================================================================
01105 
01106 #define PETE_DefineScalar(Sca)                                              \
01107 PETE_DefineBinaryWithScalars(operator+, OpAdd, Sca)                         \
01108 PETE_DefineBinaryWithScalars(operator-, OpSubtract, Sca)                    \
01109 PETE_DefineBinaryWithScalars(operator*, OpMultipply, Sca)                    \
01110 PETE_DefineBinaryWithScalars(operator/, OpDivide, Sca)                      \
01111 PETE_DefineBinaryWithScalars(operator%, OpMod, Sca)                         \
01112 PETE_DefineBinaryWithScalars(operator<, OpLT, Sca)                          \
01113 PETE_DefineBinaryWithScalars(operator<=, OpLE, Sca)                         \
01114 PETE_DefineBinaryWithScalars(operator>, OpGT, Sca)                          \
01115 PETE_DefineBinaryWithScalars(operator>=, OpGE, Sca)                         \
01116 PETE_DefineBinaryWithScalars(operator==, OpEQ, Sca)                         \
01117 PETE_DefineBinaryWithScalars(operator!=, OpNE, Sca)                         \
01118 PETE_DefineBinaryWithScalars(operator&&, OpAnd, Sca)                        \
01119 PETE_DefineBinaryWithScalars(operator||, OpOr, Sca)                         \
01120 PETE_DefineBinaryWithScalars(operator&, OpBitwiseAnd, Sca)                  \
01121 PETE_DefineBinaryWithScalars(operator|, OpBitwiseOr, Sca)                   \
01122 PETE_DefineBinaryWithScalars(operator^, OpBitwiseXor, Sca)                  \
01123 PETE_DefineBinaryWithScalars(where, OpWhere, Sca)                           \
01124 PETE_DefineBinaryWithScalars(copysign, FnCopysign, Sca)                     \
01125 PETE_DefineBinaryWithScalars(ldexp, FnLdexp, Sca)                           \
01126 PETE_DefineBinaryWithScalars(pow, FnPow, Sca)                               \
01127 PETE_DefineBinaryWithScalars(fmod, FnFmod, Sca)                             \
01128 PETE_DefineBinaryWithScalars(atan2, FnArcTan2, Sca)                         \
01129 PETE_DefineTrinaryWithScalars(where, OpWhere, Sca)
01130 
01131 //PETE_DefineBinaryWithScalars(operator<<, OpLeftShift, Sca)                  \
01132 //PETE_DefineBinaryWithScalars(operator>>, OpRightShift, Sca)                 \
01133 
01134 PETE_DefineScalar(short)
01135 PETE_DefineScalar(int)
01136 PETE_DefineScalar(long)
01137 PETE_DefineScalar(float)
01138 PETE_DefineScalar(double)
01139 
01140 
01141 //=========================================================================
01142 //
01143 // ASSIGNMENT OPERATIONS
01144 // 
01145 //=========================================================================
01146 
01147 template<class Op, class T1, class T2> struct PETE_StructApply {};
01148 
01149 #define PETE_DefineAssign(Expr,Cond,Op)                         \
01150 template<class T1, class T2>                                    \
01151 struct PETE_StructApply<Op,T1,T2>                               \
01152 {                                                               \
01153   static void apply(T1& a,const T2& b) { Expr; }                \
01154 };                                                              \
01155                                                                 \
01156 template<class T1, class T2>                                    \
01157 struct PETE_StructApply<Op,T1,ConditionalAssign<T2> >           \
01158 {                                                               \
01159   static void apply(T1& a, const ConditionalAssign<T2>& b)      \
01160     {                                                           \
01161       if ( b.cond )                                             \
01162         Cond;                                                   \
01163     }                                                           \
01164 };                                                              \
01165                                                                 \
01166 template<class T1, class T2>                                    \
01167 inline void                                                     \
01168 PETE_apply(Op, T1 &a, const T2& b)                              \
01169 {                                                               \
01170   PETE_StructApply<Op,T1,T2>::apply(a,b);                       \
01171 }
01172 
01173 PETE_DefineAssign((a  = b) ,(a  = b.value) , OpAssign)
01174 PETE_DefineAssign((a += b) ,(a += b.value) , OpAddAssign)
01175 PETE_DefineAssign((a -= b) ,(a -= b.value) , OpSubtractAssign)
01176 PETE_DefineAssign((a *= b) ,(a *= b.value) , OpMultipplyAssign)
01177 PETE_DefineAssign((a /= b) ,(a /= b.value) , OpDivideAssign)
01178 PETE_DefineAssign((a %= b) ,(a %= b.value) , OpModAssign)
01179 PETE_DefineAssign((a |= b) ,(a |= b.value) , OpBitwiseOrAssign)
01180 PETE_DefineAssign((a &= b) ,(a &= b.value) , OpBitwiseAndAssign)
01181 PETE_DefineAssign((a ^= b) ,(a ^= b.value) , OpBitwiseXorAssign)
01182 PETE_DefineAssign((a <<= b),(a <<= b.value), OpLeftShiftAssign)
01183 PETE_DefineAssign((a >>= b),(a >>= b.value), OpRightShiftAssign)
01184 
01185 
01186 //=========================================================================
01187 //
01188 // FUNCTOR NAME
01189 //   Expressionize
01190 //
01191 // DESCRIPTION
01192 //   Sometimes the result of MakeExpression on a user type isn't itself an
01193 //   expression.  That is perfectly reasonable, but sometimes you need to
01194 //   be make it one.  This just looks for that case and wraps it in an
01195 //   identity operation if it is not already an expression.
01196 // 
01197 //=========================================================================
01198 
01199 //
01200 // If it is a general expression, wrap it.
01201 //
01202 template<class T>
01203 struct Expressionize
01204 {
01205   typedef PETE_TUTree< OpIdentity, T > type;
01206   static inline type
01207   apply(const T& t) { return type(t); }
01208 };
01209 
01210 //
01211 // If it is a PETE_Expr, return it as is.
01212 //
01213 template<class T>
01214 struct Expressionize< PETE_Expr<T> >
01215 {
01216   typedef PETE_Expr<T> type;
01217   static inline const type&
01218   apply(const PETE_Expr<T>& t) { return t; }
01219 };
01220 
01221 //=========================================================================
01222 //
01223 // REDUCTIONS
01224 // 
01225 //=========================================================================
01226 
01227 #ifdef __MWERKS__
01228 // Workaround for CodeWarrior 4 bug
01229 template<class T> 
01230 struct Sum {
01231   typedef typename T::PETE_Expr_t::PETE_Return_t type_t;
01232   static inline type_t apply(const PETE_Expr<T>& expr) {
01233     type_t val ;
01234     Reduction(val, Expressionize<typename T::PETE_Expr_t>::apply( expr.PETE_unwrap().MakeExpression() ), 
01235               OpAssign(), OpAddAssign());
01236     return val;
01237   }
01238 };
01239 
01240 template<class T> 
01241 inline typename Sum<T>::type_t 
01242 sum(const PETE_Expr<T>& expr) {
01243   return Sum<T>::apply(expr);
01244 }
01245 #else
01246 template<class T> 
01247 inline typename T::PETE_Expr_t::PETE_Return_t
01248 sum(const PETE_Expr<T>& expr)
01249 {
01250   typename T::PETE_Expr_t::PETE_Return_t val ;
01251   Reduction(val, Expressionize<typename T::PETE_Expr_t>::apply( expr.PETE_unwrap().MakeExpression() ), 
01252     OpAssign(), OpAddAssign());
01253   return val;
01254 }
01255 #endif // __MWERKS__
01256 
01257 #ifdef __MWERKS__
01258 // Workaround for CodeWarrior 4 bug
01259 template<class T> 
01260 struct Prod {
01261   typedef typename T::PETE_Expr_t::PETE_Return_t type_t;
01262   static inline type_t apply(const PETE_Expr<T>& expr) {
01263     type_t val ;
01264     Reduction(val, Expressionize<typename T::PETE_Expr_t>::apply(expr.PETE_unwrap().MakeExpression()),
01265               OpAssign(), OpMultipplyAssign());
01266     return val;
01267   }
01268 };
01269 
01270 template<class T> 
01271 inline typename Prod<T>::type_t 
01272 prod(const PETE_Expr<T>& expr) {
01273   return Prod<T>::apply(expr);
01274 }
01275 #else
01276 template<class T> 
01277 inline typename T::PETE_Expr_t::PETE_Return_t
01278 prod(const PETE_Expr<T>& expr)
01279 {
01280   typename T::PETE_Expr_t::PETE_Return_t val ;
01281   Reduction(val, Expressionize<typename T::PETE_Expr_t>::apply(expr.PETE_unwrap().MakeExpression()),
01282     OpAssign(), OpMultipplyAssign());
01283   return val;
01284 }
01285 #endif // __MWERKS__
01286 
01288 //
01289 // Some macros to make it easier to define new operators.
01290 //
01292 
01293 #define UNARY_FUNCTION(RET,FUNC,ARG)                                        \
01294 struct FnUnary_ ## FUNC {                                                   \
01295   enum { tag = PETE_UnaryPassThruTag };                                     \
01296 };                                                                          \
01297 PETE_DefineUnary(FUNC,FUNC(a),FnUnary_ ## FUNC)                             \
01298 template <>                                                                 \
01299 struct PETEUnaryReturn<ARG, FnUnary_ ## FUNC> {                             \
01300   typedef RET type;                                                         \
01301 };
01302 
01303 #define BINARY_FUNCTION(RET,FUNC,ARG1,ARG2)                                 \
01304 struct FnBinary_ ## FUNC {                                                  \
01305   enum { tag = PETE_BinaryPromoteTag };                                     \
01306 };                                                                          \
01307 PETE_DefineBinary(FUNC,(FUNC(a,b)),FnBinary_ ## FUNC)                       \
01308 template<>                                                                  \
01309 struct PETEBinaryReturn<ARG1,ARG2,FnBinary_ ## FUNC> {                      \
01310   typedef RET type;                                                         \
01311 };
01312 
01313 
01315 //
01316 // END OF FILE
01317 // 
01319 
01320 #endif // PETE_H
01321 
01322 /***************************************************************************
01323  * $RCSfile: PETE.h,v $   $Author: adelmann $
01324  * $Revision: 1.1.1.1 $   $Date: 2003/01/23 07:40:28 $
01325  * IPPL_VERSION_ID: $Id: PETE.h,v 1.1.1.1 2003/01/23 07:40:28 adelmann Exp $ 
01326  ***************************************************************************/

Generated on Mon Jan 16 13:23:54 2006 for IPPL by  doxygen 1.4.6