OPAL (Object Oriented Parallel Accelerator Library) 2022.1
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
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
75template<class WrappedExpr>
77{
78public:
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
141template<class T>
142class PETE_Scalar : public PETE_Expr< PETE_Scalar<T> >
143{
144public:
145
146 // Required PETE typedefs and expression creation function.
147
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
164private:
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
200template<class T>
201inline T
203{
204 return T(p);
205}
206
207// Cursor increment, ignored by scalar.
208
209template<class T, class C>
210inline int
212{
213 return 0;
214}
215
216// Count elements, scalar returns code value -1.
217
218template<class T, class C>
219inline 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
245template<class Value_t, class Child_t>
246struct 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
289template<class Value_t, class Left_t, class Right_t>
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
337template< 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{
341public:
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
379template<class Op, class T1, class Functor, class Combiner>
380inline
381typename Functor::PETE_Return_t
382for_each(PETE_TUTree<Op,T1>& node, Functor f, Combiner c)
383{
384 return c(for_each(node.Child, f, c));
385}
386
387template<class Op, class T1, class T2, class Functor, class Combiner>
388inline
389typename Functor::PETE_Return_t
390for_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
395template<class Op, class T1, class T2, class T3, class Functor, class Combiner>
396inline
397typename Functor::PETE_Return_t
398for_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//
408template<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
478template<class Op, class T1, class Functor>
479inline
482{
483 return PETE_apply(node.Value,
484 for_each(node.Child,f));
485}
486
487
488template<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
504template<class T>
506{
507 ConditionalAssign(bool q, const T& v) : cond(q), value(v) {}
508 bool cond;
510};
511
512template<class T1, class T2, class Functor>
513struct 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
528template<class Op, class T1, class T2, class Functor>
529inline
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
558template<int I1, int I2> struct SafeCombine {};
559template<> struct SafeCombine<0,0> { enum { safe=0 }; };
560template<> struct SafeCombine<1,0> { enum { safe=0 }; };
561template<> struct SafeCombine<0,1> { enum { safe=0 }; };
562template<> struct SafeCombine<1,1> { enum { safe=1 }; };
563
564// Expressions are safe unless proven otherwise.
565template<class Expr> struct SafeExpression { enum { safe=1 }; };
566
567// Unary expressions are safe if the sub-tree is safe.
568template<class Op, class Sub>
570{
572};
573
574// Binary expressions are safe if both sub-trees are safe.
575template<class Op, class Left, class Right>
576struct SafeExpression< PETE_TBTree<Op,Left,Right> >
577{
579};
580
581// Trinary expressions are safe if the true and false sub-trees are safe.
582template<class Op, class Left, class Middle, class Right>
583struct SafeExpression< PETE_TTTree<Op,Left,Middle,Right> >
584{
586};
587
588// OpDivide is unsafe.
589template<class Left, class 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
598template<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.
616template<class T1, class T2, class T3, class Functor>
617struct
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.
634template<class T1, class T2, class T3, class Functor,class Op>
635inline
636typename 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
658template< class R, class T, class InitOp, class AccOp>
659inline void
660Reduction(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) \
705template<class T> \
706inline typename PETEUnaryReturn<T, Op>::type \
707PETE_apply(Op, const T& a) \
708{ \
709 return Expr; \
710} \
711template<class T> \
712inline PETE_TUTree<Op, typename T::PETE_Expr_t> \
713Fun(const PETE_Expr<T>& l) \
714{ \
715 return PETE_TUTree<Op, typename T::PETE_Expr_t> \
716 (l.PETE_unwrap().MakeExpression()); \
717}
718
722PETE_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
748template<class T1, class T2>
749inline T1
750PETE_apply(OpCast<T1>, const T2& a)
751{
752 return T1(a);
753}
754
755template<class T1, class Expr>
756inline PETE_TUTree<OpCast<T1>, typename Expr::PETE_Expr_t>
757pete_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) \
771template<class T1, class T2> \
772inline typename PETEBinaryReturn<T1, T2, Op>::type \
773PETE_apply(Op, const T1& a, const T2& b) \
774{ \
775 return Expr; \
776} \
777template<class T1, class T2> \
778inline PETE_TBTree<Op, typename T1::PETE_Expr_t, typename T2::PETE_Expr_t> \
779Fun(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) \
788template<class T1, class T2> \
789inline PETE_TBTree<Op, typename T1::PETE_Expr_t, typename T2::PETE_Expr_t> \
790Fun(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
798PETE_DefineBinary(operator+, (a + b), OpAdd)
801PETE_DefineBinary(operator/, (a / b), OpDivide)
802PETE_DefineBinary(operator%, (a % b), OpMod)
803PETE_DefineBinary(operator<, (a < b), OpLT)
804PETE_DefineBinary(operator<=, (a <= b), OpLE)
805PETE_DefineBinary(operator>, (a > b), OpGT)
806PETE_DefineBinary(operator>=, (a >= b), OpGE)
807PETE_DefineBinary(operator==, (a == b), OpEQ)
808PETE_DefineBinary(operator!=, (a != b), OpNE)
809PETE_DefineBinary(operator&&, (a && b), OpAnd)
810PETE_DefineBinary(operator||, (a || b), OpOr)
814 //PETE_DefineBinary(operator<<, (a << b), OpLeftShift)
815 //PETE_DefineBinary(operator>>, (a >> b), OpRightShift)
816
822
823#define PETE_DefineBinaryWithScalars(Fun,Op,Sca) \
824template<class T> \
825inline PETE_TBTree<Op, PETE_Scalar<Sca>, typename T::PETE_Expr_t> \
826Fun(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} \
831template<class T> \
832inline PETE_TBTree<Op, typename T::PETE_Expr_t, PETE_Scalar<Sca> > \
833Fun(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) \
847template<class T1, class T2, class T3> \
848inline typename PETETrinaryReturn<T1,T2,T3,Op>::type \
849PETE_apply(Op, const T1& a, const T2& b, const T3& c) \
850{ \
851 return Expr; \
852} \
853template<class Cond_t, class True_t, class False_t> \
854inline PETE_TTTree<Op, typename Cond_t::PETE_Expr_t, \
855 typename True_t::PETE_Expr_t, typename False_t::PETE_Expr_t> \
856Fun(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
866template<class T1, class T2, class T3>
868PETE_apply(OpWhere, const T1& a, const T2& b, const T3& c)
869{
870 return a ? b : c;
871}
872
873template<class Cond_t, class True_t, class False_t>
874inline 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) \
890template<class Cond_t, class True_t> \
891inline PETE_TTTree<Op, typename Cond_t::PETE_Expr_t, \
892 typename True_t::PETE_Expr_t, PETE_Scalar<Sca> > \
893Fun(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} \
900template<class Cond_t, class False_t> \
901inline PETE_TTTree<Op, typename Cond_t::PETE_Expr_t, PETE_Scalar<Sca>, \
902 typename False_t::PETE_Expr_t > \
903Fun(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} \
910template<class Cond_t> \
911inline PETE_TTTree<Op, typename Cond_t::PETE_Expr_t, PETE_Scalar<Sca>, \
912 PETE_Scalar<Sca> > \
913Fun(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) \
987PETE_DefineBinaryWithScalars(operator+, OpAdd, Sca) \
988PETE_DefineBinaryWithScalars(operator-, OpSubtract, Sca) \
989PETE_DefineBinaryWithScalars(operator*, OpMultipply, Sca) \
990PETE_DefineBinaryWithScalars(operator/, OpDivide, Sca) \
991PETE_DefineBinaryWithScalars(operator%, OpMod, Sca) \
992PETE_DefineBinaryWithScalars(operator<, OpLT, Sca) \
993PETE_DefineBinaryWithScalars(operator<=, OpLE, Sca) \
994PETE_DefineBinaryWithScalars(operator>, OpGT, Sca) \
995PETE_DefineBinaryWithScalars(operator>=, OpGE, Sca) \
996PETE_DefineBinaryWithScalars(operator==, OpEQ, Sca) \
997PETE_DefineBinaryWithScalars(operator!=, OpNE, Sca) \
998PETE_DefineBinaryWithScalars(operator&&, OpAnd, Sca) \
999PETE_DefineBinaryWithScalars(operator||, OpOr, Sca) \
1000PETE_DefineBinaryWithScalars(operator&, OpBitwiseAnd, Sca) \
1001PETE_DefineBinaryWithScalars(operator|, OpBitwiseOr, Sca) \
1002PETE_DefineBinaryWithScalars(operator^, OpBitwiseXor, Sca) \
1003PETE_DefineBinaryWithScalars(where, OpWhere, Sca) \
1004PETE_DefineBinaryWithScalars(copysign, FnCopysign, Sca) \
1005PETE_DefineBinaryWithScalars(ldexp, FnLdexp, Sca) \
1006PETE_DefineBinaryWithScalars(pow, FnPow, Sca) \
1007PETE_DefineBinaryWithScalars(fmod, FnFmod, Sca) \
1008PETE_DefineBinaryWithScalars(atan2, FnArcTan2, Sca) \
1009PETE_DefineTrinaryWithScalars(where, OpWhere, Sca)
1010
1011/*
1012PETE_DefineBinaryWithScalars(operator<<, OpLeftShift, Sca) \
1013PETE_DefineBinaryWithScalars(operator>>, OpRightShift, Sca) \
1014*/
1015
1021
1022
1023//=========================================================================
1024//
1025// ASSIGNMENT OPERATIONS
1026//
1027//=========================================================================
1028
1029template<class Op, class T1, class T2> struct PETE_StructApply {};
1030
1031#define PETE_DefineAssign(Expr,Cond,Op) \
1032template<class T1, class T2> \
1033struct PETE_StructApply<Op,T1,T2> \
1034{ \
1035 static void apply(T1& a,const T2& b) { Expr; } \
1036}; \
1037 \
1038template<class T1, class T2> \
1039struct 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 \
1048template<class T1, class T2> \
1049inline void \
1050PETE_apply(Op, T1 &a, const T2& b) \
1051{ \
1052 PETE_StructApply<Op,T1,T2>::apply(a,b); \
1053}
1054
1055PETE_DefineAssign((a = b) ,(a = b.value) , OpAssign)
1056PETE_DefineAssign((a += b) ,(a += b.value) , OpAddAssign)
1057PETE_DefineAssign((a -= b) ,(a -= b.value) , OpSubtractAssign)
1059PETE_DefineAssign((a /= b) ,(a /= b.value) , OpDivideAssign)
1060PETE_DefineAssign((a %= b) ,(a %= b.value) , OpModAssign)
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//
1084template<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//
1095template<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
1109template<class T>
1110inline typename T::PETE_Expr_t::PETE_Return_t
1111sum(const PETE_Expr<T>& expr)
1112{
1113 typename T::PETE_Expr_t::PETE_Return_t val ;
1115 OpAssign(), OpAddAssign());
1116 return val;
1117}
1118
1119template<class T>
1120inline typename T::PETE_Expr_t::PETE_Return_t
1121prod(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) \
1136struct FnUnary_ ## FUNC { \
1137 enum { tag = PETE_UnaryPassThruTag }; \
1138}; \
1139PETE_DefineUnary(FUNC,FUNC(a),FnUnary_ ## FUNC) \
1140template <> \
1141struct PETEUnaryReturn<ARG, FnUnary_ ## FUNC> { \
1142 typedef RET type; \
1143};
1144
1145#define BINARY_FUNCTION(RET,FUNC,ARG1,ARG2) \
1146struct FnBinary_ ## FUNC { \
1147 enum { tag = PETE_BinaryPromoteTag }; \
1148}; \
1149PETE_DefineBinary(FUNC,(FUNC(a,b)),FnBinary_ ## FUNC) \
1150template<> \
1151struct PETEBinaryReturn<ARG1,ARG2,FnBinary_ ## FUNC> { \
1152 typedef RET type; \
1153};
1154
1155
1157//
1158// END OF FILE
1159//
1161
1162#endif // PETE_H
1163
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
T::PETE_Expr_t::PETE_Return_t prod(const PETE_Expr< T > &expr)
Definition: PETE.h:1121
PETE_TUTree< FnLog10, typename T::PETE_Expr_t > log10(const PETE_Expr< T > &l)
Definition: PETE.h:735
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
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
T for_each(const PETE_Scalar< T > &p, EvalFunctor_0)
Definition: PETE.h:202
PETE_TUTree< FnHypSin, typename T::PETE_Expr_t > sinh(const PETE_Expr< T > &l)
Definition: PETE.h:737
#define PETE_USER_REDUCTION_CODE
Definition: PETE.h:654
#define PETE_DefineBinary(Fun, Expr, Op)
Definition: PETE.h:770
PETE_TUTree< FnLog, typename T::PETE_Expr_t > log(const PETE_Expr< T > &l)
Definition: PETE.h:734
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_Combiner< bool, OpOr > PETE_OrCombiner
Definition: PETE.h:468
PETE_TUTree< FnCeil, typename T::PETE_Expr_t > ceil(const PETE_Expr< T > &l)
Definition: PETE.h:728
PETE_TUTree< FnHypCos, typename T::PETE_Expr_t > cosh(const PETE_Expr< T > &l)
Definition: PETE.h:730
PETE_TUTree< FnSin, typename T::PETE_Expr_t > sin(const PETE_Expr< T > &l)
Definition: PETE.h:736
#define PETE_DefineBinarySynonym(Fun, Op)
Definition: PETE.h:787
PETE_TUTree< OpCast< T1 >, typename Expr::PETE_Expr_t > pete_cast(const T1 &, const PETE_Expr< Expr > &l)
Definition: PETE.h:757
PETE_TUTree< FnExp, typename T::PETE_Expr_t > exp(const PETE_Expr< T > &l)
Definition: PETE.h:731
PETE_TUTree< FnArcCos, typename T::PETE_Expr_t > acos(const PETE_Expr< T > &l)
Definition: PETE.h:725
PETE_Combiner< int, OpAdd > PETE_SumCombiner
Definition: PETE.h:469
#define PETE_DefineScalar(Sca)
Definition: PETE.h:986
#define PETE_DefineUnary(Fun, Expr, Op)
Definition: PETE.h:704
PETE_TUTree< FnErf, typename T::PETE_Expr_t > erf(const PETE_Expr< T > &l)
Definition: PETE.h:741
PETE_TUTree< FnHypTan, typename T::PETE_Expr_t > tanh(const PETE_Expr< T > &l)
Definition: PETE.h:740
PETE_TUTree< FnSqrt, typename T::PETE_Expr_t > sqrt(const PETE_Expr< T > &l)
Definition: PETE.h:738
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
PETEUnaryReturn< T, OpUnaryMinus >::type PETE_apply(OpUnaryMinus, const T &a)
Definition: PETE.h:719
PETE_TUTree< FnFabs, typename T::PETE_Expr_t > fabs(const PETE_Expr< T > &l)
Definition: PETE.h:732
PETE_TUTree< OpIdentity, typename T::PETE_Expr_t > PETE_identity(const PETE_Expr< T > &l)
Definition: PETE.h:723
PETE_TUTree< FnTan, typename T::PETE_Expr_t > tan(const PETE_Expr< T > &l)
Definition: PETE.h:739
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
PETE_TUTree< FnArcSin, typename T::PETE_Expr_t > asin(const PETE_Expr< T > &l)
Definition: PETE.h:726
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< FnCos, typename T::PETE_Expr_t > cos(const PETE_Expr< T > &l)
Definition: PETE.h:729
PETE_TUTree< FnArcTan, typename T::PETE_Expr_t > atan(const PETE_Expr< T > &l)
Definition: PETE.h:727
#define PETE_DefineAssign(Expr, Cond, Op)
Definition: PETE.h:1031
PETE_TUTree< FnFloor, typename T::PETE_Expr_t > floor(const PETE_Expr< T > &l)
Definition: PETE.h:733
PETE_Combiner< bool, OpAnd > PETE_AndCombiner
Definition: PETE.h:467
std::complex< double > a
#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:45
boost::function< boost::tuple< double, bool >(arguments_t)> type
Definition: function.hpp:21
Definition: Value.h:24
Definition: PETE.h:77
WrappedExpr & PETE_unwrap()
Definition: PETE.h:81
const WrappedExpr & PETE_unwrap() const
Definition: PETE.h:85
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
PETEUnaryReturn< typenameChild_t::PETE_Return_t, Value_t >::type PETE_Return_t
Definition: PETE.h:251
Value_t Value
Definition: PETE.h:252
PETE_TUTree< Value_t, Child_t > PETE_Expr_t
Definition: PETE.h:249
const PETE_Expr_t & MakeExpression() const
Definition: PETE.h:252
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
@ IsExpr
Definition: PETE.h:248
@ IsExpr
Definition: PETE.h:293
PETEBinaryReturn< typenameLeft_t::PETE_Return_t, typenameRight_t::PETE_Return_t, Value_t >::type PETE_Return_t
Definition: PETE.h:296
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
const PETE_Expr_t & MakeExpression() const
Definition: PETE.h:297
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
PETE_TBTree< Value_t, Left_t, Right_t > PETE_Expr_t
Definition: PETE.h:294
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
@ IsExpr
Definition: PETE.h:342
PETETrinaryReturn< typenameLeft_t::PETE_Return_t, typenameMiddle_t::PETE_Return_t, typenameRight_t::PETE_Return_t, Value_t >::type PETE_Return_t
Definition: PETE.h:346
PETE_TTTree(const Value_t &v, const Left_t &l, const Middle_t &m, const Right_t &r)
Definition: PETE.h:362
PETE_TTTree(const Left_t &l, const Middle_t &m, const Right_t &r)
Definition: PETE.h:368
Value_t Value
Definition: PETE.h:347
const PETE_Expr_t & MakeExpression() const
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
static Return_t apply(PETE_TBTree< Op, T1, T2 > &node, Functor f)
Definition: PETE.h:496
PETEBinaryReturn< typenameT1::PETE_Return_t, typenameT2::PETE_Return_t, Op >::type Return_t
Definition: PETE.h:493
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< typenameT1::PETE_Return_t, typenameT2::PETE_Return_t, typenameT3::PETE_Return_t, Op >::type apply(PETE_TTTree< Op, T1, T2, T3 > &node, Functor f)
Definition: PETE.h:607
static PETETrinaryReturn< typenameT1::PETE_Return_t, typenameT2::PETE_Return_t, typenameT3::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