OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
OPAL
PETE.h
Go to the documentation of this file.
1 // -*- C++ -*-
2 /***************************************************************************
3  *
4  * The IPPL Framework
5  *
6  ***************************************************************************/
7 
8 
10 //
11 // FILE NAME
12 // PETE.h
13 //
14 // CREATED
15 // July 11, 1997
16 //
17 // DESCRIPTION
18 // PETE: Portable Expression Template Engine.
19 //
20 // This header file defines the objects and operators necessary to use
21 // expression templates for a fairly large class of problems.
22 //
23 // It defines template functions for the standard unary, binary and
24 // trinary operators. Each of them is defined for only certain types to
25 // prevent clashes with global operator+.
26 //
28 
29 #ifndef PETE_H
30 #define PETE_H
31 
32 
33 // include files
34 #include "PETE/TypeComputations.h"
35 #include "Utility/PAssert.h"
36 
37 #include <cstdlib>
38 
39 //=========================================================================
40 //
41 // PETE BASE CLASS DEFINITIONS
42 //
43 //=========================================================================
44 
46 //
47 // CLASS NAME
48 // PETE_Expr<W>
49 //
50 // DESCRIPTION
51 // The base class for all objects that will participate in expressions
52 // All this wrapper class needs to do is let you convert back to
53 // the type W.
54 //
55 // The intended use for PETE_Expr is as a base class for
56 // a class you want to be able to enter into PETE expressions.
57 // You construct a PETE aware class by saying:
58 //
59 // class W : public PETE_Expr<W>
60 // {
61 // ...
62 // };
63 //
64 // Then a function that will recognize PETE expressions can do:
65 //
66 // template<class W>
67 // void foo(const PETE_Expr<W>& wrapped_expr)
68 // {
69 // const W& expr = wrapped_expr.PETE_unwrap();
70 // ... do stuff with expr ...
71 // }
72 //
74 
75 template<class WrappedExpr>
76 class PETE_Expr
77 {
78 public:
79  typedef WrappedExpr Wrapped;
80 
81  WrappedExpr& PETE_unwrap()
82  {
83  return static_cast<WrappedExpr&>(*this);
84  }
85  const WrappedExpr& PETE_unwrap() const
86  {
87  return static_cast<const WrappedExpr&>(*this);
88  }
89 
90 };
91 
92 
94 //
95 // CLASS NAME
96 // PETE_Scalar<T>
97 //
98 // DESCRIPTION
99 // A wrapper around a scalar to be used in PETE expressions.
100 //
101 // This is a simple illustration of how one makes a class PETE-aware.
102 // First, notice that PETE_Scalar<T> inherits publically from
103 // PETE_Expr< PETE_Scalar<T> >. In addition, a PETE-aware class must
104 // provide two typedefs:
105 //
106 // PETE_Expr_t: this is the actual class that will be used to
107 // compute an expression. Many simple classes act as both
108 // containers and cursor-like classes, so, often, this
109 // will simply be the class itself. However, classes with
110 // an STL-like iterator should use the iterator as PETE_Expr_t.
111 // PETE_Return_t: this is the type returned by evaluating the
112 // expression. Typically, this is the element-type of a container.
113 // For PETE_Scalar, this is the type of scalar.
114 //
115 // Classes need to supply a member function of the form:
116 //
117 // PETE_Expr_t MakeExpression() const { ... }
118 //
119 // This function should construct and return an appropriate object of
120 // type PETE_Expr_t.
121 //
122 // Finally, PETE really does its work by applying Functors recursively
123 // through the tree that represents an expression. At the leaves of the
124 // tree, these Functors encounter user classes like PETE_Scalar. There
125 // are three Functors that all user classes should support:
126 //
127 // EvalFunctor_0: returns a value for the leaf part of the expression.
128 // This Functor has no arguments so most containers will need to
129 // supply a cursor-like class that returns the current container value.
130 // The cursor is bumped using another Functor, PETE_Increment.
131 // PETE_Increment: moves the cursor to the next element.
132 // PETE_CountElems: returns the number of elements in the container.
133 // Used for testing conformance, for example.
134 //
135 // The actual code for evaluating these Functors for a particular user class
136 // is contained in a global function named 'for_each'. Users classes need
137 // to define a different 'for_each' for each Functor.
138 //
140 
141 template<class T>
142 class PETE_Scalar : public PETE_Expr< PETE_Scalar<T> >
143 {
144 public:
145 
146  // Required PETE typedefs and expression creation function.
147 
149  typedef T PETE_Return_t;
150 
151  PETE_Expr_t MakeExpression() const { return *this; }
152 
153  // Default constructor takes no action.
154 
156 
157  // Constructor from a single value.
158 
159  PETE_Scalar(const T& t) : scalar(t) { }
160 
161  // Conversion to a type T.
162  operator T() const { return scalar; }
163 
164 private:
165 
167 
168 };
169 
170 //=========================================================================
171 //
172 // BASIC FUNCTORS AND for_each FUNCTIONS FOR PETE_Scalar
173 //
174 //=========================================================================
175 
176 // Evaluation functor, no offsets.
177 
179 {
180 };
181 
182 // Increment functor
183 
185 {
186  typedef int PETE_Return_t;
187 };
188 
189 // Element count functor.
190 
192 {
193  typedef int PETE_Return_t;
194 };
195 
196 // Behavior of basic Functors for PETE_Scalar:
197 
198 // Evaluate a scalar.
199 
200 template<class T>
201 inline T
203 {
204  return T(p);
205 }
206 
207 // Cursor increment, ignored by scalar.
208 
209 template<class T, class C>
210 inline int
212 {
213  return 0;
214 }
215 
216 // Count elements, scalar returns code value -1.
217 
218 template<class T, class C>
219 inline int
221 {
222  return -1;
223 }
224 
225 
226 //=========================================================================
227 //
228 // PETE TREE CLASSES
229 //
230 //=========================================================================
231 
233 //
234 // CLASS NAME
235 // PETE_TUTree<Value_t, Child_t>
236 //
237 // DESCRIPTION
238 // A tree node for representing unary expressions. The node holds a
239 // Child (of type Child_t), which is the type of the expression sub tree,
240 // a Value (of type Value_t), which is typically the operation applied to
241 // the sub tree.
242 //
244 
245 template<class Value_t, class Child_t>
246 struct PETE_TUTree : public PETE_Expr< PETE_TUTree<Value_t, Child_t> >
247 {
248  enum { IsExpr = 1 };
250  typedef typename PETEUnaryReturn<typename Child_t::PETE_Return_t,
252  const PETE_Expr_t& MakeExpression() const { return *this; };
253 
254  // The value and child expression stored in this node of the tree.
255 
256  Value_t Value;
257  Child_t Child;
258 
259  // Default constructor: takes no action.
260 
262 
263  // Constructor using both a value and the child.
264 
265  PETE_TUTree(const Value_t& v, const Child_t& c)
266  : Value(v), Child(c) { }
267 
268  // Constructor using just the child.
269 
270  PETE_TUTree(const Child_t& c)
271  : Child(c) { }
272 };
273 
274 
276 //
277 // CLASS NAME
278 // PETE_TBTree<Value_t, Left_t, Right_t>
279 //
280 // DESCRIPTION
281 // A tree node for representing binary expressions. The node holds a
282 // Left child (of type Left_t), which is the type of the LHS expression
283 // sub tree, a Right child (of type Right_t), which is the type of the RHS
284 // expression sub tree, and a Value (of type Value_t), which is typically
285 // the operation applied to the two sub trees.
286 //
288 
289 template<class Value_t, class Left_t, class Right_t>
290 struct PETE_TBTree :
291  public PETE_Expr< PETE_TBTree<Value_t, Left_t, Right_t> >
292 {
293  enum { IsExpr = 1 };
295  typedef typename PETEBinaryReturn<typename Left_t::PETE_Return_t,
296  typename Right_t::PETE_Return_t, Value_t>::type PETE_Return_t;
297  const PETE_Expr_t& MakeExpression() const { return *this; };
298 
299  // The value and left/right sub expressions stored in this node of the tree.
300 
301  Value_t Value;
302  Left_t Left;
303  Right_t Right;
304 
305  // Default ctor: takes no action.
306 
308 
309  // Constructor using both the value and the two children.
310 
311  PETE_TBTree(const Value_t& v, const Left_t& l, const Right_t& r)
312  : Value(v), Left(l), Right(r) { }
313 
314  // Constructor using just the two children.
315 
316  PETE_TBTree(const Left_t& l, const Right_t& r)
317  : Left(l), Right(r) { }
318 };
319 
320 
322 //
323 // CLASS NAME
324 // PETE_TTTree<Value_t, Left_t, Middle_t, Right_t>
325 //
326 // DESCRIPTION
327 // A tree node for representing trinary expressions. The node holds a
328 // Left child (of type Left_t), which is the type of the LHS expression
329 // sub tree (typically a comparison operation); a Middle child (of type
330 // Middle_t), which is the type of the middle (true branch) expression
331 // sub tree; a Right child (of type Right_t), which is the type of
332 // the expression (false branch) sub tree; and a Value (of type Value_t),
333 // which is typically the operation applied to the three sub trees.
334 //
336 
337 template< class Value_t, class Left_t, class Middle_t, class Right_t >
339  : public PETE_Expr< PETE_TTTree< Value_t, Left_t, Middle_t, Right_t > >
340 {
341 public:
342  enum { IsExpr = 1 };
344  typedef typename PETETrinaryReturn<typename Left_t::PETE_Return_t,
345  typename Middle_t::PETE_Return_t,
346  typename Right_t::PETE_Return_t, Value_t>::type PETE_Return_t;
347  const PETE_Expr_t& MakeExpression() const { return *this; };
348 
349  // The value and left, right, and middle sub trees stored at this node.
350 
351  Value_t Value;
352  Left_t Left;
353  Middle_t Middle;
354  Right_t Right;
355 
356  // Default ctor: takes no action.
357 
359 
360  // Constructor using the value and three children.
361 
362  PETE_TTTree(const Value_t& v, const Left_t& l,
363  const Middle_t& m, const Right_t& r)
364  : Value(v), Left(l), Middle(m), Right(r) { }
365 
366  // Constructor with just the three children.
367 
368  PETE_TTTree(const Left_t& l, const Middle_t& m,const Right_t& r)
369  : Left(l), Middle(m), Right(r) {}
370 };
371 
372 
373 //=========================================================================
374 //
375 // DEFAULT for_each FUNCTIONS INVOLVING PETE TREES
376 //
377 //=========================================================================
378 
379 template<class Op, class T1, class Functor, class Combiner>
380 inline
381 typename Functor::PETE_Return_t
382 for_each(PETE_TUTree<Op,T1>& node, Functor f, Combiner c)
383 {
384  return c(for_each(node.Child, f, c));
385 }
386 
387 template<class Op, class T1, class T2, class Functor, class Combiner>
388 inline
389 typename Functor::PETE_Return_t
390 for_each(PETE_TBTree<Op,T1,T2>& node, Functor f, Combiner c)
391 {
392  return c(for_each(node.Left, f, c), for_each(node.Right, f, c));
393 }
394 
395 template<class Op, class T1, class T2, class T3, class Functor, class Combiner>
396 inline
397 typename Functor::PETE_Return_t
398 for_each(PETE_TTTree<Op,T1,T2,T3>& node, Functor f, Combiner c)
399 {
400  return c(for_each(node.Left, f, c), for_each(node.Middle, f, c) ,
401  for_each(node.Right, f, c));
402 }
403 
404 
405 //
406 // A useful combiner.
407 //
408 template<class T, class Op>
410 {
411  T operator()(T x) { return x; }
412  T operator()(T x, T y) { return PETE_apply(Op(),x,y); }
413  T operator()(T x, T y, T z) {return PETE_apply(Op(),x,PETE_apply(Op(),y,z));}
414 };
415 
417 {
418  int operator()(int l)
419  {
420  return l;
421  }
422  int operator()(int l, int r)
423  {
424  int ret = l;
425  if ( (l>=0) && (r>=0) ) {
426  PInsist(l==r,"Arguments not equal in AssertEquals()!!");
427  }
428  else {
429  if ( r>=0 ) return ret = r;
430  }
431  return ret;
432  }
433  int operator()(int l, int m, int r)
434  {
435  int ret = l;
436  if ( (l>=0) && (m>=0) && (r>=0) ) {
437  PInsist(m==l && m==r,"Arguments not equal in AssertEquals()!!");
438  }
439  else if ( l>=0 ) {
440  return l;
441  }
442  else if ( m>=0) {
443  return m;
444  }
445  else if ( r>=0) {
446  return r;
447  }
448  return ret;
449  }
450 };
451 
452 //
453 // A combiner for when you don't want to return a value.
454 //
455 
457 {
458  int operator()(int) { return 0; }
459  int operator()(int, int) { return 0; }
460  int operator()(int, int, int) { return 0; }
461 };
462 
463 //
464 // Some shorthand for common combiners.
465 //
466 
470 
471 
473 
474 //
475 // for_each functions that recurse through the tree doing evaluation.
476 //
477 
478 template<class Op, class T1, class Functor>
479 inline
481 for_each(PETE_TUTree<Op,T1>& node, Functor f)
482 {
483  return PETE_apply(node.Value,
484  for_each(node.Child,f));
485 }
486 
487 
488 template<class Op, class T1, class T2, class Functor>
490 {
491  typedef typename PETEBinaryReturn<typename T1::PETE_Return_t,
492  typename T2::PETE_Return_t,Op>::type
494 
495  static inline Return_t
496  apply(PETE_TBTree<Op,T1,T2>& node, Functor f)
497  {
498  return PETE_apply(node.Value,
499  for_each(node.Left,f),
500  for_each(node.Right,f) );
501  }
502 };
503 
504 template<class T>
506 {
507  ConditionalAssign(bool q, const T& v) : cond(q), value(v) {}
508  bool cond;
510 };
511 
512 template<class T1, class T2, class Functor>
513 struct struct_for_each<OpWhere,T1,T2,Functor>
514 {
515  typedef typename T2::PETE_Return_t T3;
517 
518  static inline Return_t
520  {
521  if ( for_each(node.Left,f) )
522  return Return_t(true,for_each(node.Right,f));
523  else
524  return Return_t(false,T3());
525  }
526 };
527 
528 template<class Op, class T1, class T2, class Functor>
529 inline
532 {
534 }
535 
536 /***********************************************************************
537 
538  There are two ways to evaluate the trinary where operator:
539 
540  if (a) { return b; } else { return c; }
541 
542  return a ? b : c;
543 
544  The first is safer since b or c could have a divide by zero
545  or something when it is not supposed to be evaluated, but the
546  second can be much faster since there are more optimization
547  opportunities, particularly strength reduction.
548 
549  Below we have some trait magic for looking at the right hand sides
550  and deciding if the expression is "dangerous" and needs to be done
551  the first way. Otherwise it does it the second way.
552 
553  This uses partial specialization so it is user extensible for
554  special cases.
555 
556 ***********************************************************************/
557 
558 template<int I1, int I2> struct SafeCombine {};
559 template<> struct SafeCombine<0,0> { enum { safe=0 }; };
560 template<> struct SafeCombine<1,0> { enum { safe=0 }; };
561 template<> struct SafeCombine<0,1> { enum { safe=0 }; };
562 template<> struct SafeCombine<1,1> { enum { safe=1 }; };
563 
564 // Expressions are safe unless proven otherwise.
565 template<class Expr> struct SafeExpression { enum { safe=1 }; };
566 
567 // Unary expressions are safe if the sub-tree is safe.
568 template<class Op, class Sub>
570 {
572 };
573 
574 // Binary expressions are safe if both sub-trees are safe.
575 template<class Op, class Left, class Right>
576 struct SafeExpression< PETE_TBTree<Op,Left,Right> >
577 {
579 };
580 
581 // Trinary expressions are safe if the true and false sub-trees are safe.
582 template<class Op, class Left, class Middle, class Right>
583 struct SafeExpression< PETE_TTTree<Op,Left,Middle,Right> >
584 {
586 };
587 
588 // OpDivide is unsafe.
589 template<class Left, class Right>
590 struct SafeExpression< PETE_TBTree<OpDivide,Left,Right> >
591 {
592  enum { safe = 0 };
593 };
594 
595 // Functor class to evaluate the for_each.
596 // If no specialization matches, use PETE_apply.
597 // For OpWhere, this will use ?: through PETE_apply
598 template<int Safe, class T1, class T2, class T3, class Op, class Functor>
600 {
601  static inline
602  typename PETETrinaryReturn<
603  typename T1::PETE_Return_t,
604  typename T2::PETE_Return_t,
605  typename T3::PETE_Return_t,
606  Op>::type
607  apply(PETE_TTTree<Op,T1,T2,T3>& node, Functor f) {
608  return PETE_apply(node.Value,
609  for_each(node.Left,f),
610  for_each(node.Middle,f),
611  for_each(node.Right,f));
612  }
613 };
614 
615 // For an unsafe OpWhere, don't evaluate both args.
616 template<class T1, class T2, class T3, class Functor>
617 struct
619 {
620  static inline
621  typename PETETrinaryReturn<
622  typename T1::PETE_Return_t,
623  typename T2::PETE_Return_t,
624  typename T3::PETE_Return_t,
627  return for_each(node.Left,f) ?
628  for_each(node.Middle,f) : for_each(node.Right,f);
629  }
630 };
631 
632 // The general definition of for_each for trinary.
633 // This just turns around and calls the class function.
634 template<class T1, class T2, class T3, class Functor,class Op>
635 inline
636 typename PETETrinaryReturn<typename T1::PETE_Return_t,
637  typename T2::PETE_Return_t,
638  typename T3::PETE_Return_t,Op>::type
640 {
641  return TrinaryForEach<
643  ,T1,T2,T3,Op,Functor>::apply(node,f);
644 }
645 
646 //=========================================================================
647 //
648 // GENERAL PETE REDUCTION CODE
649 //
650 //=========================================================================
651 
652 #if !defined(PETE_USER_REDUCTION_CODE)
653 
654 #define PETE_USER_REDUCTION_CODE
655 
656 #endif
657 
658 template< class R, class T, class InitOp, class AccOp>
659 inline void
660 Reduction(R& ret, const PETE_Expr<T>& const_expr,
661  InitOp init_op, AccOp acc_op )
662 {
663  // Extract the expression.
664 
665  typename T::PETE_Expr_t expr(const_expr.PETE_unwrap().MakeExpression());
666 
667  // Get the number of elements we will be looping over.
668 
669  int n = for_each(expr, PETE_CountElems(), AssertEquals());
670 
671  // Make sure there is something to do.
672 
673  if (n > 0) {
674 
675  // Get the first value.
676 
677  PETE_apply(init_op, ret, for_each(expr, EvalFunctor_0()));
678 
679  // Loop over all the elements.
680  for (int i = 1; i < n; ++i)
681  {
682  // Increment the cursors.
683 
685 
686  // Accumulate.
687 
688  PETE_apply(acc_op, ret, for_each(expr, EvalFunctor_0()));
689  }
690  }
691 
692  // Allow users to augment the reduction code.
693 
695 }
696 
697 
698 //=========================================================================
699 //
700 // UNARY OPERATIONS
701 //
702 //=========================================================================
703 
704 #define PETE_DefineUnary(Fun,Expr,Op) \
705 template<class T> \
706 inline typename PETEUnaryReturn<T, Op>::type \
707 PETE_apply(Op, const T& a) \
708 { \
709  return Expr; \
710 } \
711 template<class T> \
712 inline PETE_TUTree<Op, typename T::PETE_Expr_t> \
713 Fun(const PETE_Expr<T>& l) \
714 { \
715  return PETE_TUTree<Op, typename T::PETE_Expr_t> \
716  (l.PETE_unwrap().MakeExpression()); \
717 }
718 
722 PETE_DefineUnary(operator!, (!a), OpNot)
724 
742 
743 //
744 // Define OpCast specially because it doesn't fit
745 // the pattern that the #define needs.
746 //
747 
748 template<class T1, class T2>
749 inline T1
750 PETE_apply(OpCast<T1>, const T2& a)
751 {
752  return T1(a);
753 }
754 
755 template<class T1, class Expr>
756 inline PETE_TUTree<OpCast<T1>, typename Expr::PETE_Expr_t>
757 pete_cast(const T1&, const PETE_Expr<Expr>& l)
758 {
759  return
760  PETE_TUTree<OpCast<T1>, typename Expr::PETE_Expr_t>
761  (l.PETE_unwrap().MakeExpression());
762 }
763 
764 //=========================================================================
765 //
766 // BINARY OPERATIONS
767 //
768 //=========================================================================
769 
770 #define PETE_DefineBinary(Fun,Expr,Op) \
771 template<class T1, class T2> \
772 inline typename PETEBinaryReturn<T1, T2, Op>::type \
773 PETE_apply(Op, const T1& a, const T2& b) \
774 { \
775  return Expr; \
776 } \
777 template<class T1, class T2> \
778 inline PETE_TBTree<Op, typename T1::PETE_Expr_t, typename T2::PETE_Expr_t> \
779 Fun(const PETE_Expr<T1>& l, const PETE_Expr<T2>& r) \
780 { \
781  typedef PETE_TBTree<Op,typename T1::PETE_Expr_t, \
782  typename T2::PETE_Expr_t> ret; \
783  return ret(l.PETE_unwrap().MakeExpression(), \
784  r.PETE_unwrap().MakeExpression()); \
785 }
786 
787 #define PETE_DefineBinarySynonym(Fun,Op) \
788 template<class T1, class T2> \
789 inline PETE_TBTree<Op, typename T1::PETE_Expr_t, typename T2::PETE_Expr_t> \
790 Fun(const PETE_Expr<T1>& l, const PETE_Expr<T2>& r) \
791 { \
792  typedef PETE_TBTree<Op,typename T1::PETE_Expr_t,typename T2::PETE_Expr_t> \
793  ret; \
794  return ret(l.PETE_unwrap().MakeExpression(), \
795  r.PETE_unwrap().MakeExpression()); \
796 }
797 
798 PETE_DefineBinary(operator+, (a + b), OpAdd)
799 PETE_DefineBinary(operator-, (a - b), OpSubtract)
800 PETE_DefineBinary(operator*, (a * b), OpMultipply)
801 PETE_DefineBinary(operator/, (a / b), OpDivide)
802 PETE_DefineBinary(operator%, (a % b), OpMod)
803 PETE_DefineBinary(operator<, (a < b), OpLT)
804 PETE_DefineBinary(operator<=, (a <= b), OpLE)
805 PETE_DefineBinary(operator>, (a > b), OpGT)
806 PETE_DefineBinary(operator>=, (a >= b), OpGE)
807 PETE_DefineBinary(operator==, (a == b), OpEQ)
808 PETE_DefineBinary(operator!=, (a != b), OpNE)
809 PETE_DefineBinary(operator&&, (a && b), OpAnd)
810 PETE_DefineBinary(operator||, (a || b), OpOr)
811 PETE_DefineBinary(operator&, (a & b), OpBitwiseAnd)
812 PETE_DefineBinary(operator|, (a | b), OpBitwiseOr)
813 PETE_DefineBinary(operator^, (a ^ b), OpBitwiseXor)
814  //PETE_DefineBinary(operator<<, (a << b), OpLeftShift)
815  //PETE_DefineBinary(operator>>, (a >> b), OpRightShift)
816 
822 
823 #define PETE_DefineBinaryWithScalars(Fun,Op,Sca) \
824 template<class T> \
825 inline PETE_TBTree<Op, PETE_Scalar<Sca>, typename T::PETE_Expr_t> \
826 Fun(const Sca l, const PETE_Expr<T>& r) \
827 { \
828  typedef PETE_TBTree<Op, PETE_Scalar<Sca>, typename T::PETE_Expr_t> ret; \
829  return ret(PETE_Scalar<Sca>(l), r.PETE_unwrap().MakeExpression()); \
830 } \
831 template<class T> \
832 inline PETE_TBTree<Op, typename T::PETE_Expr_t, PETE_Scalar<Sca> > \
833 Fun(const PETE_Expr<T>& l, const Sca r) \
834 { \
835  typedef PETE_TBTree<Op, typename T::PETE_Expr_t, PETE_Scalar<Sca> > ret; \
836  return ret(l.PETE_unwrap().MakeExpression(), PETE_Scalar<Sca>(r)); \
837 }
838 
839 
840 //=========================================================================
841 //
842 // TRINARY OPERATORS
843 //
844 //=========================================================================
845 
846 #define PETE_DefineTrinary(Fun,Expr,Op) \
847 template<class T1, class T2, class T3> \
848 inline typename PETETrinaryReturn<T1,T2,T3,Op>::type \
849 PETE_apply(Op, const T1& a, const T2& b, const T3& c) \
850 { \
851  return Expr; \
852 } \
853 template<class Cond_t, class True_t, class False_t> \
854 inline PETE_TTTree<Op, typename Cond_t::PETE_Expr_t, \
855  typename True_t::PETE_Expr_t, typename False_t::PETE_Expr_t> \
856 Fun(const PETE_Expr<Cond_t>& c, const PETE_Expr<True_t>& t, \
857  const PETE_Expr<False_t>& f) \
858 { \
859  typedef PETE_TTTree<Op, typename Cond_t::PETE_Expr_t, \
860  typename True_t::PETE_Expr_t, typename False_t::PETE_Expr_t> ret; \
861  return ret(c.PETE_unwrap().MakeExpression(), \
862  t.PETE_unwrap().MakeExpression(), \
863  f.PETE_unwrap().MakeExpression()); \
864 }
865 
866 template<class T1, class T2, class T3>
868 PETE_apply(OpWhere, const T1& a, const T2& b, const T3& c)
869 {
870  return a ? b : c;
871 }
872 
873 template<class Cond_t, class True_t, class False_t>
874 inline PETE_TTTree<OpWhere, typename Cond_t::PETE_Expr_t,
875  typename True_t::PETE_Expr_t,
876  typename False_t::PETE_Expr_t>
878  const PETE_Expr<False_t>& f)
879 {
880  typedef PETE_TTTree<OpWhere, typename Cond_t::PETE_Expr_t,
881  typename True_t::PETE_Expr_t,
882  typename False_t::PETE_Expr_t> ret;
883  return ret(c.PETE_unwrap().MakeExpression(),
884  t.PETE_unwrap().MakeExpression(),
885  f.PETE_unwrap().MakeExpression());
886 }
887 
888 
889 #define PETE_DefineTrinaryWithScalars(Fun, Op, Sca) \
890 template<class Cond_t, class True_t> \
891 inline PETE_TTTree<Op, typename Cond_t::PETE_Expr_t, \
892  typename True_t::PETE_Expr_t, PETE_Scalar<Sca> > \
893 Fun(const PETE_Expr<Cond_t>& c, const PETE_Expr<True_t>& t,Sca f) \
894 { \
895  typedef PETE_TTTree<Op, typename Cond_t::PETE_Expr_t, \
896  typename True_t::PETE_Expr_t, PETE_Scalar<Sca> > ret; \
897  return ret(c.PETE_unwrap().MakeExpression(), \
898  t.PETE_unwrap().MakeExpression(), PETE_Scalar<Sca>(f)); \
899 } \
900 template<class Cond_t, class False_t> \
901 inline PETE_TTTree<Op, typename Cond_t::PETE_Expr_t, PETE_Scalar<Sca>, \
902  typename False_t::PETE_Expr_t > \
903 Fun(const PETE_Expr<Cond_t>& c, Sca t, const PETE_Expr<False_t>& f) \
904 { \
905  typedef PETE_TTTree<Op, typename Cond_t::PETE_Expr_t, PETE_Scalar<Sca>, \
906  typename False_t::PETE_Expr_t > ret; \
907  return ret(c.PETE_unwrap().MakeExpression(), \
908  PETE_Scalar<Sca>(t), f.PETE_unwrap().MakeExpression()); \
909 } \
910 template<class Cond_t> \
911 inline PETE_TTTree<Op, typename Cond_t::PETE_Expr_t, PETE_Scalar<Sca>, \
912  PETE_Scalar<Sca> > \
913 Fun(const PETE_Expr<Cond_t>& c, Sca t, Sca f) \
914 { \
915  typedef PETE_TTTree<Op, typename Cond_t::PETE_Expr_t, PETE_Scalar<Sca>, \
916  PETE_Scalar<Sca> > ret; \
917  return ret(c.PETE_unwrap().MakeExpression(), \
918  PETE_Scalar<Sca>(t), PETE_Scalar<Sca>(f)); \
919 }
920 
921 
922 //=========================================================================
923 //
924 // Two argument where
925 //
926 // The conventional where operator has three arguments:
927 // where(conditional, true_expr, false_expr)
928 // It acts much like the ?: operator in expressions.
929 //
930 // A common usage of that structure is
931 // A = where(conditional,true_expr,A);
932 // to do something only in the locations where the conditional is true.
933 // This is inefficient.
934 //
935 // The two argument where supports the following:
936 // A = where(conditional,true_expr);
937 // and means the same thing as the three argument version above.
938 //
939 // This form of where cannot be used in expressions in which the where
940 // is not the whole right hand side of the expression.
941 //
942 //======================================================================
943 //
944 // EXPLANATION
945 //
946 // The three argument where operator above produces code something
947 // like this in the inner loop:
948 //
949 // for (i=...)
950 // a(i) = conditional(i) ? true_expr(i) : false_expr(i);
951 //
952 // The two argument where has to produce something like:
953 //
954 // for (i=...)
955 // if ( conditional(i) )
956 // a(i) = true_expr(i);
957 //
958 // Two things are being made conditional here: evaluating true_expr
959 // and assigning it to a.
960 //
961 // In order to do that inside of expression templates, the following
962 // things need to happen when evaluating an expression:
963 //
964 // 1. Evaluating the binary OpWhere expression returns a
965 // ConditionalAssign<T> with two components: A boolean for whether
966 // the conditional was true, and the result of evaluating the
967 // expression of type T.
968 //
969 // 2. The expression only gets evaluated if the conditional is true.
970 // If it is not true, then the ConditionalAssign<T> uses a default ctor
971 // to leave the T undefined.
972 //
973 // 3. The assigment operator from the ConditionalAssign<T> to a type
974 // T only actually does the assignment if the bool is true.
975 //
976 //=========================================================================
977 
979 
980 //=========================================================================
981 //
982 // SCALARS
983 //
984 //=========================================================================
985 
986 #define PETE_DefineScalar(Sca) \
987 PETE_DefineBinaryWithScalars(operator+, OpAdd, Sca) \
988 PETE_DefineBinaryWithScalars(operator-, OpSubtract, Sca) \
989 PETE_DefineBinaryWithScalars(operator*, OpMultipply, Sca) \
990 PETE_DefineBinaryWithScalars(operator/, OpDivide, Sca) \
991 PETE_DefineBinaryWithScalars(operator%, OpMod, Sca) \
992 PETE_DefineBinaryWithScalars(operator<, OpLT, Sca) \
993 PETE_DefineBinaryWithScalars(operator<=, OpLE, Sca) \
994 PETE_DefineBinaryWithScalars(operator>, OpGT, Sca) \
995 PETE_DefineBinaryWithScalars(operator>=, OpGE, Sca) \
996 PETE_DefineBinaryWithScalars(operator==, OpEQ, Sca) \
997 PETE_DefineBinaryWithScalars(operator!=, OpNE, Sca) \
998 PETE_DefineBinaryWithScalars(operator&&, OpAnd, Sca) \
999 PETE_DefineBinaryWithScalars(operator||, OpOr, Sca) \
1000 PETE_DefineBinaryWithScalars(operator&, OpBitwiseAnd, Sca) \
1001 PETE_DefineBinaryWithScalars(operator|, OpBitwiseOr, Sca) \
1002 PETE_DefineBinaryWithScalars(operator^, OpBitwiseXor, Sca) \
1003 PETE_DefineBinaryWithScalars(where, OpWhere, Sca) \
1004 PETE_DefineBinaryWithScalars(copysign, FnCopysign, Sca) \
1005 PETE_DefineBinaryWithScalars(ldexp, FnLdexp, Sca) \
1006 PETE_DefineBinaryWithScalars(pow, FnPow, Sca) \
1007 PETE_DefineBinaryWithScalars(fmod, FnFmod, Sca) \
1008 PETE_DefineBinaryWithScalars(atan2, FnArcTan2, Sca) \
1009 PETE_DefineTrinaryWithScalars(where, OpWhere, Sca)
1010 
1011 /*
1012 PETE_DefineBinaryWithScalars(operator<<, OpLeftShift, Sca) \
1013 PETE_DefineBinaryWithScalars(operator>>, OpRightShift, Sca) \
1014 */
1015 
1021 
1022 
1023 //=========================================================================
1024 //
1025 // ASSIGNMENT OPERATIONS
1026 //
1027 //=========================================================================
1028 
1029 template<class Op, class T1, class T2> struct PETE_StructApply {};
1030 
1031 #define PETE_DefineAssign(Expr,Cond,Op) \
1032 template<class T1, class T2> \
1033 struct PETE_StructApply<Op,T1,T2> \
1034 { \
1035  static void apply(T1& a,const T2& b) { Expr; } \
1036 }; \
1037  \
1038 template<class T1, class T2> \
1039 struct PETE_StructApply<Op,T1,ConditionalAssign<T2> > \
1040 { \
1041  static void apply(T1& a, const ConditionalAssign<T2>& b) \
1042  { \
1043  if ( b.cond ) \
1044  Cond; \
1045  } \
1046 }; \
1047  \
1048 template<class T1, class T2> \
1049 inline void \
1050 PETE_apply(Op, T1 &a, const T2& b) \
1051 { \
1052  PETE_StructApply<Op,T1,T2>::apply(a,b); \
1053 }
1054 
1055 PETE_DefineAssign((a = b) ,(a = b.value) , OpAssign)
1056 PETE_DefineAssign((a += b) ,(a += b.value) , OpAddAssign)
1057 PETE_DefineAssign((a -= b) ,(a -= b.value) , OpSubtractAssign)
1058 PETE_DefineAssign((a *= b) ,(a *= b.value) , OpMultipplyAssign)
1059 PETE_DefineAssign((a /= b) ,(a /= b.value) , OpDivideAssign)
1060 PETE_DefineAssign((a %= b) ,(a %= b.value) , OpModAssign)
1061 PETE_DefineAssign((a |= b) ,(a |= b.value) , OpBitwiseOrAssign)
1062 PETE_DefineAssign((a &= b) ,(a &= b.value) , OpBitwiseAndAssign)
1063 PETE_DefineAssign((a ^= b) ,(a ^= b.value) , OpBitwiseXorAssign)
1064 PETE_DefineAssign((a <<= b),(a <<= b.value), OpLeftShiftAssign)
1065 PETE_DefineAssign((a >>= b),(a >>= b.value), OpRightShiftAssign)
1066 
1067 
1068 //=========================================================================
1069 //
1070 // FUNCTOR NAME
1071 // Expressionize
1072 //
1073 // DESCRIPTION
1074 // Sometimes the result of MakeExpression on a user type isn't itself an
1075 // expression. That is perfectly reasonable, but sometimes you need to
1076 // be make it one. This just looks for that case and wraps it in an
1077 // identity operation if it is not already an expression.
1078 //
1079 //=========================================================================
1080 
1081 //
1082 // If it is a general expression, wrap it.
1083 //
1084 template<class T>
1086 {
1088  static inline type
1089  apply(const T& t) { return type(t); }
1090 };
1091 
1092 //
1093 // If it is a PETE_Expr, return it as is.
1094 //
1095 template<class T>
1097 {
1099  static inline const type&
1100  apply(const PETE_Expr<T>& t) { return t; }
1101 };
1102 
1103 //=========================================================================
1104 //
1105 // REDUCTIONS
1106 //
1107 //=========================================================================
1108 
1109 template<class T>
1110 inline typename T::PETE_Expr_t::PETE_Return_t
1111 sum(const PETE_Expr<T>& expr)
1112 {
1113  typename T::PETE_Expr_t::PETE_Return_t val ;
1114  Reduction(val, Expressionize<typename T::PETE_Expr_t>::apply( expr.PETE_unwrap().MakeExpression() ),
1115  OpAssign(), OpAddAssign());
1116  return val;
1117 }
1118 
1119 template<class T>
1120 inline typename T::PETE_Expr_t::PETE_Return_t
1121 prod(const PETE_Expr<T>& expr)
1122 {
1123  typename T::PETE_Expr_t::PETE_Return_t val ;
1126  return val;
1127 }
1128 
1130 //
1131 // Some macros to make it easier to define new operators.
1132 //
1134 
1135 #define UNARY_FUNCTION(RET,FUNC,ARG) \
1136 struct FnUnary_ ## FUNC { \
1137  enum { tag = PETE_UnaryPassThruTag }; \
1138 }; \
1139 PETE_DefineUnary(FUNC,FUNC(a),FnUnary_ ## FUNC) \
1140 template <> \
1141 struct PETEUnaryReturn<ARG, FnUnary_ ## FUNC> { \
1142  typedef RET type; \
1143 };
1144 
1145 #define BINARY_FUNCTION(RET,FUNC,ARG1,ARG2) \
1146 struct FnBinary_ ## FUNC { \
1147  enum { tag = PETE_BinaryPromoteTag }; \
1148 }; \
1149 PETE_DefineBinary(FUNC,(FUNC(a,b)),FnBinary_ ## FUNC) \
1150 template<> \
1151 struct PETEBinaryReturn<ARG1,ARG2,FnBinary_ ## FUNC> { \
1152  typedef RET type; \
1153 };
1154 
1155 
1157 //
1158 // END OF FILE
1159 //
1161 
1162 #endif // PETE_H
1163 
std::complex< double > a
PETE_TUTree< FnErf, typename T::PETE_Expr_t > erf(const PETE_Expr< T > &l)
Definition: PETE.h:741
T::PETE_Expr_t::PETE_Return_t sum(const PETE_Expr< T > &expr)
Definition: PETE.h:1111
void Reduction(R &ret, const PETE_Expr< T > &const_expr, InitOp init_op, AccOp acc_op)
Definition: PETE.h:660
PETE_TUTree< FnHypTan, typename T::PETE_Expr_t > tanh(const PETE_Expr< T > &l)
Definition: PETE.h:740
T::PETE_Expr_t::PETE_Return_t prod(const PETE_Expr< T > &expr)
Definition: PETE.h:1121
PETEUnaryReturn< T, OpUnaryMinus >::type PETE_apply(OpUnaryMinus, const T &a)
Definition: PETE.h:719
PETE_TUTree< FnLog10, typename T::PETE_Expr_t > log10(const PETE_Expr< T > &l)
Definition: PETE.h:735
T for_each(const PETE_Scalar< T > &p, EvalFunctor_0)
Definition: PETE.h:202
PETE_TUTree< FnCeil, typename T::PETE_Expr_t > ceil(const PETE_Expr< T > &l)
Definition: PETE.h:728
PETE_TBTree< FnCopysign, typename T1::PETE_Expr_t, typename T2::PETE_Expr_t > copysign(const PETE_Expr< T1 > &l, const PETE_Expr< T2 > &r)
Definition: PETE.h:817
PETE_TUTree< FnHypCos, typename T::PETE_Expr_t > cosh(const PETE_Expr< T > &l)
Definition: PETE.h:730
#define PETE_USER_REDUCTION_CODE
Definition: PETE.h:654
#define PETE_DefineBinary(Fun, Expr, Op)
Definition: PETE.h:770
PETE_Combiner< bool, OpOr > PETE_OrCombiner
Definition: PETE.h:468
PETE_TTTree< OpWhere, typename Cond_t::PETE_Expr_t, typename True_t::PETE_Expr_t, typename False_t::PETE_Expr_t > where(const PETE_Expr< Cond_t > &c, const PETE_Expr< True_t > &t, const PETE_Expr< False_t > &f)
Definition: PETE.h:877
#define PETE_DefineBinarySynonym(Fun, Op)
Definition: PETE.h:787
PETE_TBTree< FnPow, typename T1::PETE_Expr_t, typename T2::PETE_Expr_t > pow(const PETE_Expr< T1 > &l, const PETE_Expr< T2 > &r)
Definition: PETE.h:819
PETE_TUTree< FnFabs, typename T::PETE_Expr_t > fabs(const PETE_Expr< T > &l)
Definition: PETE.h:732
PETE_Combiner< int, OpAdd > PETE_SumCombiner
Definition: PETE.h:469
PETE_TUTree< FnArcTan, typename T::PETE_Expr_t > atan(const PETE_Expr< T > &l)
Definition: PETE.h:727
PETE_TUTree< FnLog, typename T::PETE_Expr_t > log(const PETE_Expr< T > &l)
Definition: PETE.h:734
PETE_TBTree< FnArcTan2, typename T1::PETE_Expr_t, typename T2::PETE_Expr_t > atan2(const PETE_Expr< T1 > &l, const PETE_Expr< T2 > &r)
Definition: PETE.h:821
#define PETE_DefineScalar(Sca)
Definition: PETE.h:986
#define PETE_DefineUnary(Fun, Expr, Op)
Definition: PETE.h:704
PETE_TUTree< FnTan, typename T::PETE_Expr_t > tan(const PETE_Expr< T > &l)
Definition: PETE.h:739
PETE_TUTree< FnArcCos, typename T::PETE_Expr_t > acos(const PETE_Expr< T > &l)
Definition: PETE.h:725
PETE_TUTree< FnHypSin, typename T::PETE_Expr_t > sinh(const PETE_Expr< T > &l)
Definition: PETE.h:737
PETE_TUTree< FnExp, typename T::PETE_Expr_t > exp(const PETE_Expr< T > &l)
Definition: PETE.h:731
PETE_TUTree< OpCast< T1 >, typename Expr::PETE_Expr_t > pete_cast(const T1 &, const PETE_Expr< Expr > &l)
Definition: PETE.h:757
PETE_TUTree< OpIdentity, typename T::PETE_Expr_t > PETE_identity(const PETE_Expr< T > &l)
Definition: PETE.h:723
PETE_TUTree< FnArcSin, typename T::PETE_Expr_t > asin(const PETE_Expr< T > &l)
Definition: PETE.h:726
PETE_TUTree< FnSqrt, typename T::PETE_Expr_t > sqrt(const PETE_Expr< T > &l)
Definition: PETE.h:738
PETE_TUTree< FnSin, typename T::PETE_Expr_t > sin(const PETE_Expr< T > &l)
Definition: PETE.h:736
PETE_TUTree< FnFloor, typename T::PETE_Expr_t > floor(const PETE_Expr< T > &l)
Definition: PETE.h:733
PETE_TUTree< FnCos, typename T::PETE_Expr_t > cos(const PETE_Expr< T > &l)
Definition: PETE.h:729
PETE_TBTree< FnLdexp, typename T1::PETE_Expr_t, typename T2::PETE_Expr_t > ldexp(const PETE_Expr< T1 > &l, const PETE_Expr< T2 > &r)
Definition: PETE.h:818
PETE_TBTree< FnFmod, typename T1::PETE_Expr_t, typename T2::PETE_Expr_t > fmod(const PETE_Expr< T1 > &l, const PETE_Expr< T2 > &r)
Definition: PETE.h:820
#define PETE_DefineAssign(Expr, Cond, Op)
Definition: PETE.h:1031
PETE_Combiner< bool, OpAnd > PETE_AndCombiner
Definition: PETE.h:467
#define PInsist(c, m)
Definition: PAssert.h:120
double Sub(double a, double b)
constexpr double c
The velocity of light in m/s.
Definition: Physics.h:51
boost::function< boost::tuple< double, bool >arguments_t)> type
Definition: function.hpp:21
Definition: Value.h:24
Definition: PETE.h:77
const WrappedExpr & PETE_unwrap() const
Definition: PETE.h:85
WrappedExpr & PETE_unwrap()
Definition: PETE.h:81
WrappedExpr Wrapped
Definition: PETE.h:79
T PETE_Return_t
Definition: PETE.h:149
PETE_Scalar< T > PETE_Expr_t
Definition: PETE.h:148
PETE_Scalar()
Definition: PETE.h:155
PETE_Expr_t MakeExpression() const
Definition: PETE.h:151
PETE_Scalar(const T &t)
Definition: PETE.h:159
T scalar
Definition: PETE.h:166
int PETE_Return_t
Definition: PETE.h:186
int PETE_Return_t
Definition: PETE.h:193
PETE_TUTree(const Child_t &c)
Definition: PETE.h:270
Value_t Value
Definition: PETE.h:252
PETE_TUTree< Value_t, Child_t > PETE_Expr_t
Definition: PETE.h:249
PETE_TUTree(const Value_t &v, const Child_t &c)
Definition: PETE.h:265
PETE_TUTree()
Definition: PETE.h:261
Child_t Child
Definition: PETE.h:257
const PETE_Expr_t & MakeExpression() const
Definition: PETE.h:252
PETEUnaryReturn< typename Child_t::PETE_Return_t, Value_t >::type PETE_Return_t
Definition: PETE.h:251
@ IsExpr
Definition: PETE.h:248
const PETE_Expr_t & MakeExpression() const
Definition: PETE.h:297
Value_t Value
Definition: PETE.h:297
PETE_TBTree()
Definition: PETE.h:307
Left_t Left
Definition: PETE.h:302
Right_t Right
Definition: PETE.h:303
@ IsExpr
Definition: PETE.h:293
PETE_TBTree(const Left_t &l, const Right_t &r)
Definition: PETE.h:316
PETE_TBTree(const Value_t &v, const Left_t &l, const Right_t &r)
Definition: PETE.h:311
PETEBinaryReturn< typename Left_t::PETE_Return_t, typename Right_t::PETE_Return_t, Value_t >::type PETE_Return_t
Definition: PETE.h:296
PETE_TBTree< Value_t, Left_t, Right_t > PETE_Expr_t
Definition: PETE.h:294
@ IsExpr
Definition: PETE.h:342
Left_t Left
Definition: PETE.h:352
PETE_TTTree< Value_t, Left_t, Middle_t, Right_t > PETE_Expr_t
Definition: PETE.h:343
PETE_TTTree()
Definition: PETE.h:358
Middle_t Middle
Definition: PETE.h:353
PETE_TTTree(const Value_t &v, const Left_t &l, const Middle_t &m, const Right_t &r)
Definition: PETE.h:362
const PETE_Expr_t & MakeExpression() const
Definition: PETE.h:347
PETE_TTTree(const Left_t &l, const Middle_t &m, const Right_t &r)
Definition: PETE.h:368
PETETrinaryReturn< typename Left_t::PETE_Return_t, typename Middle_t::PETE_Return_t, typename Right_t::PETE_Return_t, Value_t >::type PETE_Return_t
Definition: PETE.h:346
Value_t Value
Definition: PETE.h:347
Right_t Right
Definition: PETE.h:354
T operator()(T x, T y)
Definition: PETE.h:412
T operator()(T x)
Definition: PETE.h:411
T operator()(T x, T y, T z)
Definition: PETE.h:413
int operator()(int l, int r)
Definition: PETE.h:422
int operator()(int l)
Definition: PETE.h:418
int operator()(int l, int m, int r)
Definition: PETE.h:433
int operator()(int, int, int)
Definition: PETE.h:460
int operator()(int, int)
Definition: PETE.h:459
int operator()(int)
Definition: PETE.h:458
PETEBinaryReturn< typename T1::PETE_Return_t, typename T2::PETE_Return_t, Op >::type Return_t
Definition: PETE.h:493
static Return_t apply(PETE_TBTree< Op, T1, T2 > &node, Functor f)
Definition: PETE.h:496
ConditionalAssign(bool q, const T &v)
Definition: PETE.h:507
static Return_t apply(PETE_TBTree< OpWhere, T1, T2 > &node, Functor f)
Definition: PETE.h:519
ConditionalAssign< T3 > Return_t
Definition: PETE.h:516
static PETETrinaryReturn< typename T1::PETE_Return_t, typename T2::PETE_Return_t, typename T3::PETE_Return_t, Op >::type apply(PETE_TTTree< Op, T1, T2, T3 > &node, Functor f)
Definition: PETE.h:607
static PETETrinaryReturn< typename T1::PETE_Return_t, typename T2::PETE_Return_t, typename T3::PETE_Return_t, OpWhere >::type apply(PETE_TTTree< OpWhere, T1, T2, T3 > &node, Functor f)
Definition: PETE.h:626
static type apply(const T &t)
Definition: PETE.h:1089
PETE_TUTree< OpIdentity, T > type
Definition: PETE.h:1087
static const type & apply(const PETE_Expr< T > &t)
Definition: PETE.h:1100
PETE_ComputeUnaryType< T, Op, Op::tag >::type type
PETE_ComputeBinaryType< T2, T3, Op, Op::tag >::type type