/*************************************************************************** * blitz/arrayexpr.h Array expression templates * * $Id: expr.h,v 1.1.1.1 1999-11-26 16:37:07 ansari Exp $ * * Copyright (C) 1997,1998 Todd Veldhuizen * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * Suggestions: blitz-suggest@cybervision.com * Bugs: blitz-bugs@cybervision.com * * For more information, please see the Blitz++ Home Page: * http://seurat.uwaterloo.ca/blitz/ * *************************************************************************** * $Log: not supported by cvs2svn $ * Revision 1.1.1.1 1999/04/09 17:59:03 ansari * Creation module DPC/Blitz (blitz 0.4) Reza 09/04/99 * * Revision 1.2 1998/03/14 00:04:47 tveldhui * 0.2-alpha-05 * * Revision 1.1 1997/07/16 14:51:20 tveldhui * Update: Alpha release 0.2 (Arrays) * */ #ifndef BZ_ARRAYEXPR_H #define BZ_ARRAYEXPR_H #ifndef BZ_ARRAY_H #error must be included via #endif #ifndef BZ_OPS_H #include #endif #ifndef BZ_PRETTYPRINT_H #include #endif #ifndef BZ_SHAPECHECK_H #include #endif #ifdef BZ_HAVE_NUMERIC_LIMITS #ifndef BZ_NUMINQUIRE_H #include #endif #endif /* * The array expression templates iterator interface is followed by * these classes: * * ArrayIterator * _bz_ArrayExpr * _bz_ArrayExprOp " * _bz_ArrayExprUnaryOp " * _bz_ArrayExprConstant " * _bz_ArrayMap * _bz_ArrayExprReduce * IndexPlaceholder */ BZ_NAMESPACE(blitz) template class _bz_ExprPair { public: _bz_ExprPair(const T1& a, const T2& b) : first_(a), second_(b) { } const T1& first() const { return first_; } const T2& second() const { return second_; } protected: T1 first_; T2 second_; }; template inline _bz_ExprPair makeExprPair(const T1& a, const T2& b) { return _bz_ExprPair(a,b); } template class _bz_ArrayExpr #ifdef BZ_NEW_EXPRESSION_TEMPLATES : public ETBase<_bz_ArrayExpr > #endif { public: typedef P_expr T_expr; typedef _bz_typename T_expr::T_numtype T_numtype; typedef T_expr T_ctorArg1; typedef int T_ctorArg2; // dummy enum { numArrayOperands = BZ_ENUM_CAST(P_expr::numArrayOperands), numIndexPlaceholders = BZ_ENUM_CAST(P_expr::numIndexPlaceholders), rank = BZ_ENUM_CAST(P_expr::rank) }; _bz_ArrayExpr(const _bz_ArrayExpr& a) : iter_(a.iter_) { } _bz_ArrayExpr(T_expr a) : iter_(a) { } _bz_ArrayExpr(_bz_typename T_expr::T_ctorArg1 a) : iter_(a) { } // This template is not possible because it masks the copy constructor, // wreaking havoc. #if BZ_TEMPLATE_CTOR_DOESNT_CAUSE_HAVOC template _bz_explicit _bz_ArrayExpr(T1 a) : iter_(a) { } #endif template _bz_ArrayExpr(T1 a, T2 b) : iter_(a, b) { } template _bz_ArrayExpr(T1 a, T2 b, T3 c) : iter_(a, b, c) { } template _bz_ArrayExpr(_bz_ExprPair pair) : iter_(pair.first(), pair.second()) { } T_numtype operator*() { return *iter_; } #ifdef BZ_ARRAY_EXPR_PASS_INDEX_BY_VALUE template T_numtype operator()(TinyVector i) { return iter_(i); } #else template T_numtype operator()(const TinyVector& i) { return iter_(i); } #endif int lbound(int rank) { return iter_.lbound(rank); } int ubound(int rank) { return iter_.ubound(rank); } void push(int position) { iter_.push(position); } void pop(int position) { iter_.pop(position); } void advance() { iter_.advance(); } void advance(int n) { iter_.advance(n); } void loadStride(int rank) { iter_.loadStride(rank); } _bz_bool isUnitStride(int rank) const { return iter_.isUnitStride(rank); } void advanceUnitStride() { iter_.advanceUnitStride(); } _bz_bool canCollapse(int outerLoopRank, int innerLoopRank) const { // BZ_DEBUG_MESSAGE("_bz_ArrayExpr<>::canCollapse()"); return iter_.canCollapse(outerLoopRank, innerLoopRank); } T_numtype operator[](int i) { return iter_[i]; } T_numtype fastRead(int i) { return iter_.fastRead(i); } int suggestStride(int rank) const { return iter_.suggestStride(rank); } _bz_bool isStride(int rank, int stride) const { return iter_.isStride(rank,stride); } void prettyPrint(string& str) const { prettyPrintFormat format(_bz_true); // Terse formatting by default iter_.prettyPrint(str, format); } void prettyPrint(string& str, prettyPrintFormat& format) const { iter_.prettyPrint(str, format); } template _bz_bool shapeCheck(const T_shape& shape) { return iter_.shapeCheck(shape); } template void moveTo(const TinyVector& i) { iter_.moveTo(i); } protected: _bz_ArrayExpr() { } T_expr iter_; }; struct bounds { static int compute_lbound(int rank, int lbound1, int lbound2) { // The value INT_MIN indicates that there are no arrays // in a subtree of the expression. This logic returns // whichever lbound is available. If there are two // conflicting lbound values, this is an error. if (lbound1 == lbound2) return lbound1; else if (lbound1 == INT_MIN) return lbound2; else if (lbound2 == INT_MIN) return lbound1; BZ_DEBUG_MESSAGE("Two array operands have different" << endl << "lower bounds: in rank " << rank << ", the bounds are " << lbound1 << " and " << lbound2 << endl); BZ_PRE_FAIL; return 0; } static int compute_ubound(int rank, int ubound1, int ubound2) { // The value INT_MAX indicates that there are no arrays // in a subtree of the expression. This logic returns // whichever ubound is available. If there are two // conflicting ubound values, this is an error. if (ubound1 == ubound2) return ubound1; else if (ubound1 == INT_MAX) return ubound2; else if (ubound2 == INT_MAX) return ubound1; BZ_DEBUG_MESSAGE("Two array operands have different" << endl << "upper bounds: in rank " << rank << ", the bounds are " << ubound1 << " and " << ubound2 << endl); BZ_PRE_FAIL; return 0; } }; template class _bz_ArrayExprOp { public: typedef P_expr1 T_expr1; typedef P_expr2 T_expr2; typedef _bz_typename T_expr1::T_numtype T_numtype1; typedef _bz_typename T_expr2::T_numtype T_numtype2; typedef _bz_typename P_op::T_numtype T_numtype; typedef P_op T_op; typedef T_expr1 T_ctorArg1; typedef T_expr2 T_ctorArg2; enum { numArrayOperands = BZ_ENUM_CAST(P_expr1::numArrayOperands) + BZ_ENUM_CAST(P_expr2::numArrayOperands), numIndexPlaceholders = BZ_ENUM_CAST(P_expr1::numIndexPlaceholders) + BZ_ENUM_CAST(P_expr2::numIndexPlaceholders), rank = (BZ_ENUM_CAST(P_expr1::rank) > BZ_ENUM_CAST(P_expr2::rank)) ? BZ_ENUM_CAST(P_expr1::rank) : BZ_ENUM_CAST(P_expr2::rank) }; _bz_ArrayExprOp(const _bz_ArrayExprOp& a) : iter1_(a.iter1_), iter2_(a.iter2_) { } template _bz_ArrayExprOp(T1 a, T2 b) : iter1_(a), iter2_(b) { } // _bz_ArrayExprOp(T_expr1 a, T_expr2 b) // : iter1_(a), iter2_(b) // { } T_numtype operator*() { return T_op::apply(*iter1_, *iter2_); } #ifdef BZ_ARRAY_EXPR_PASS_INDEX_BY_VALUE template T_numtype operator()(TinyVector i) { return T_op::apply(iter1_(i), iter2_(i)); } #else template T_numtype operator()(const TinyVector& i) { return T_op::apply(iter1_(i), iter2_(i)); } #endif int lbound(int rank) { return bounds::compute_lbound(rank, iter1_.lbound(rank), iter2_.lbound(rank)); } int ubound(int rank) { return bounds::compute_ubound(rank, iter1_.ubound(rank), iter2_.ubound(rank)); } void push(int position) { iter1_.push(position); iter2_.push(position); } void pop(int position) { iter1_.pop(position); iter2_.pop(position); } void advance() { iter1_.advance(); iter2_.advance(); } void advance(int n) { iter1_.advance(n); iter2_.advance(n); } void loadStride(int rank) { iter1_.loadStride(rank); iter2_.loadStride(rank); } _bz_bool isUnitStride(int rank) const { return iter1_.isUnitStride(rank) && iter2_.isUnitStride(rank); } void advanceUnitStride() { iter1_.advanceUnitStride(); iter2_.advanceUnitStride(); } _bz_bool canCollapse(int outerLoopRank, int innerLoopRank) const { // BZ_DEBUG_MESSAGE("_bz_ArrayExprOp<>::canCollapse"); return iter1_.canCollapse(outerLoopRank, innerLoopRank) && iter2_.canCollapse(outerLoopRank, innerLoopRank); } T_numtype operator[](int i) { return T_op::apply(iter1_[i], iter2_[i]); } T_numtype fastRead(int i) { return T_op::apply(iter1_.fastRead(i), iter2_.fastRead(i)); } int suggestStride(int rank) const { int stride1 = iter1_.suggestStride(rank); int stride2 = iter2_.suggestStride(rank); return (stride1 > stride2) ? stride1 : stride2; } _bz_bool isStride(int rank, int stride) const { return iter1_.isStride(rank,stride) && iter2_.isStride(rank,stride); } template void moveTo(const TinyVector& i) { iter1_.moveTo(i); iter2_.moveTo(i); } void prettyPrint(string& str, prettyPrintFormat& format) const { T_op::prettyPrint(str, format, iter1_, iter2_); } template _bz_bool shapeCheck(const T_shape& shape) { return iter1_.shapeCheck(shape) && iter2_.shapeCheck(shape); } protected: _bz_ArrayExprOp() { } T_expr1 iter1_; T_expr2 iter2_; }; template class _bz_ArrayExprUnaryOp { public: typedef P_expr T_expr; typedef _bz_typename P_expr::T_numtype T_numtype1; typedef _bz_typename P_op::T_numtype T_numtype; typedef P_op T_op; typedef T_expr T_ctorArg1; typedef int T_ctorArg2; // dummy enum { numArrayOperands = BZ_ENUM_CAST(T_expr::numArrayOperands), numIndexPlaceholders = BZ_ENUM_CAST(T_expr::numIndexPlaceholders), rank = BZ_ENUM_CAST(T_expr::rank) }; _bz_ArrayExprUnaryOp(const _bz_ArrayExprUnaryOp& a) : iter_(a.iter_) { } _bz_ArrayExprUnaryOp(T_expr a) : iter_(a) { } _bz_ArrayExprUnaryOp(_bz_typename T_expr::T_ctorArg1 a) : iter_(a) { } #if BZ_TEMPLATE_CTOR_DOESNT_CAUSE_HAVOC template _bz_explicit _bz_ArrayExprUnaryOp(T1 a) : iter_(a) { } #endif int lbound(int rank) { return iter_.lbound(rank); } int ubound(int rank) { return iter_.ubound(rank); } T_numtype operator*() { return T_op::apply(*iter_); } #ifdef BZ_ARRAY_EXPR_PASS_INDEX_BY_VALUE template T_numtype operator()(TinyVector i) { return T_op::apply(iter_(i)); } #else template T_numtype operator()(const TinyVector& i) { return T_op::apply(iter_(i)); } #endif void push(int position) { iter_.push(position); } void pop(int position) { iter_.pop(position); } void advance() { iter_.advance(); } void advance(int n) { iter_.advance(n); } void loadStride(int rank) { iter_.loadStride(rank); } _bz_bool isUnitStride(int rank) const { return iter_.isUnitStride(rank); } void advanceUnitStride() { iter_.advanceUnitStride(); } template void moveTo(const TinyVector& i) { iter_.moveTo(i); } _bz_bool canCollapse(int outerLoopRank, int innerLoopRank) const { // BZ_DEBUG_MESSAGE("_bz_ArrayExprUnaryOp<>::canCollapse"); return iter_.canCollapse(outerLoopRank, innerLoopRank); } T_numtype operator[](int i) { return T_op::apply(iter_[i]); } T_numtype fastRead(int i) { return T_op::apply(iter_.fastRead(i)); } int suggestStride(int rank) const { return iter_.suggestStride(rank); } _bz_bool isStride(int rank, int stride) const { return iter_.isStride(rank,stride); } void prettyPrint(string& str, prettyPrintFormat& format) const { T_op::prettyPrint(str, format, iter_); } template _bz_bool shapeCheck(const T_shape& shape) { return iter_.shapeCheck(shape); } protected: _bz_ArrayExprUnaryOp() { } T_expr iter_; }; template class _bz_ArrayExprConstant { public: typedef P_numtype T_numtype; typedef T_numtype T_ctorArg1; typedef int T_ctorArg2; // dummy enum { numArrayOperands = 0, numIndexPlaceholders = 0, rank = 0 }; _bz_ArrayExprConstant(const _bz_ArrayExprConstant& a) : value_(a.value_) { } _bz_ArrayExprConstant(T_numtype value) : value_(BZ_NO_PROPAGATE(value)) { } // tiny() and huge() return the smallest and largest representable // integer values. See // NEEDS_WORK: use tiny(int()) once numeric_limits available on // all platforms int lbound(int) { return INT_MIN; } int ubound(int) { return INT_MAX; } // NEEDS_WORK: use huge(int()) once numeric_limits available on // all platforms T_numtype operator*() { return value_; } #ifdef BZ_ARRAY_EXPR_PASS_INDEX_BY_VALUE template T_numtype operator()(TinyVector) { return value_; } #else template T_numtype operator()(const TinyVector&) { return value_; } #endif void push(int) { } void pop(int) { } void advance() { } void advance(int) { } void loadStride(int) { } _bz_bool isUnitStride(int rank) const { return _bz_true; } void advanceUnitStride() { } _bz_bool canCollapse(int,int) const { return _bz_true; } T_numtype operator[](int) { return value_; } T_numtype fastRead(int) { return value_; } int suggestStride(int) const { return 1; } _bz_bool isStride(int,int) const { return _bz_true; } template void moveTo(const TinyVector& i) { } void prettyPrint(string& str, prettyPrintFormat& format) const { if (format.tersePrintingSelected()) str += format.nextScalarOperandSymbol(); else str += BZ_DEBUG_TEMPLATE_AS_STRING_LITERAL(T_numtype); } template _bz_bool shapeCheck(const T_shape&) { return _bz_true; } protected: _bz_ArrayExprConstant() { } T_numtype value_; }; BZ_NAMESPACE_END #include #endif // BZ_ARRAYEXPR_H