/*
 * Tiny Vector Matrix Library
 * Dense Vector Matrix Libary of Tiny size using Expression Templates
 *
 * Copyright (C) 2001, 2002 Olaf Petzold <opetzold@wit.regiocom.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * "$Id:"
 */

#ifndef TVMET_XPR_OPERATORS_H
#define TVMET_XPR_OPERATORS_H

#include <tvmet/Functional.h>

namespace tvmet {

/***********************************************************************
 * global binary math, bitops and logical operators
 ***********************************************************************/

#define TVMET_BINARY_OPERATOR(FUNCTIONAL, OP)                   	\
template<class E1, class E2, std::size_t Sz>                   		\
inline                 			      			      	\
XprVector<                    	      					\
  XprBinOp<                    			      			\
    FUNCTIONAL<typename E1::value_type, typename E2::value_type>,	\
    XprVector<E1, Sz>,              			      		\
    XprVector<E2, Sz>               			      		\
  >,                   			      			      	\
  Sz                   			      			      	\
>                   			      		      		\
operator OP (XprVector<E1, Sz> lhs, XprVector<E2, Sz> rhs) {		\
  typedef XprBinOp<							\
    FUNCTIONAL<typename E1::value_type, typename E2::value_type>,	\
    XprVector<E1, Sz>, 							\
    XprVector<E2, Sz>               			      		\
  >		    					expr_type; 	\
  return XprVector<expr_type, Sz>(expr_type(lhs, rhs));			\
}                   			      		      		\
                   			      		      		\
template<class E1, class E2, std::size_t Rows, std::size_t Cols>	\
inline                 			      			      	\
XprMatrix<                    	      					\
  XprBinOp<                    			      			\
    FUNCTIONAL<typename E1::value_type, typename E2::value_type>,	\
    XprMatrix<E1, Rows, Cols>,         			      		\
    XprMatrix<E2, Rows, Cols>         			      		\
  >,                   			      			      	\
  Rows, Cols           			      			      	\
>                   			      		      		\
operator OP (XprMatrix<E1, Rows, Cols> lhs, XprMatrix<E2, Rows, Cols> rhs) { \
  typedef XprBinOp<							\
    FUNCTIONAL<typename E1::value_type, typename E2::value_type>,	\
    XprMatrix<E1, Rows, Cols>,						\
    XprMatrix<E2, Rows, Cols>						\
  >		    					expr_type; 	\
  return XprMatrix<expr_type, Rows, Cols>(expr_type(lhs, rhs));		\
}

TVMET_BINARY_OPERATOR(fcnl_Add, +)
TVMET_BINARY_OPERATOR(fcnl_Sub, -)
TVMET_BINARY_OPERATOR(fcnl_Mul, *)
TVMET_BINARY_OPERATOR(fcnl_Div, /)
TVMET_BINARY_OPERATOR(fcnl_Mod, %)
TVMET_BINARY_OPERATOR(fcnl_BitwiseXor, ^)
TVMET_BINARY_OPERATOR(fcnl_BitwiseAnd, &)
TVMET_BINARY_OPERATOR(fcnl_BitwiseOr, |)
TVMET_BINARY_OPERATOR(fcnl_Shl, <<)
TVMET_BINARY_OPERATOR(fcnl_Shr, >>)
TVMET_BINARY_OPERATOR(fcnl_Greater, >)
TVMET_BINARY_OPERATOR(fcnl_Less, <)
TVMET_BINARY_OPERATOR(fcnl_GreaterOrEqual, >=)
TVMET_BINARY_OPERATOR(fcnl_LessOrEqual, <=)
TVMET_BINARY_OPERATOR(fcnl_Equal, ==)
TVMET_BINARY_OPERATOR(fcnl_NotEqual, !=)
TVMET_BINARY_OPERATOR(fcnl_LogicalAnd, &&)
TVMET_BINARY_OPERATOR(fcnl_LogicalOr, ||)
#undef TVMET_BINARY_OPERATOR

/*
 * XprVector<E, Sz> and POD's
 * XprMatrix<E, Rows, Cols> and POD's
 */
#define TVMET_BINARY_OPERATOR(FUNCTIONAL, OP, TP)              		\
template<class E, std::size_t Sz>          				\
inline                 			      			      	\
XprVector<                  						\
  XprBinOp<          							\
    FUNCTIONAL<typename E::value_type, TP >,      			\
    XprVector<E, Sz>,			          			\
    XprLiteral< TP >          						\
  >,          								\
  Sz          								\
>          								\
operator OP (XprVector<E, Sz> lhs, TP rhs) {				\
  typedef XprBinOp<          						\
    FUNCTIONAL<typename E::value_type, TP >,   				\
    XprVector<E, Sz>,			        			\
    XprLiteral< TP >              			      		\
  >							expr_type;	\
  return XprVector<expr_type, Sz>(expr_type(lhs, XprLiteral< TP >(rhs))); \
}          								\
          								\
template<class E, std::size_t Sz>   					\
inline                 			      			      	\
XprVector<          							\
  XprBinOp<          							\
    FUNCTIONAL<TP, typename E::value_type>,    				\
    XprLiteral< TP >,          						\
    XprVector<E, Sz>   				      			\
  >,          								\
  Sz          								\
>          								\
operator OP (TP lhs, XprVector<E, Sz> rhs) {         			\
  typedef XprBinOp<         						\
    FUNCTIONAL< TP, typename E::value_type>,   				\
    XprLiteral< TP >,         						\
    XprVector<E, Sz>           			      			\
  >							expr_type;	\
  return XprVector<expr_type, Sz>(expr_type(XprLiteral< TP >(lhs), rhs)); \
}          								\
          								\
template<class E, std::size_t Rows, std::size_t Cols>			\
inline                 			      			      	\
XprMatrix<                  						\
  XprBinOp<          							\
    FUNCTIONAL<typename E::value_type, TP >,      			\
    XprMatrix<E, Rows, Cols>,		          			\
    XprLiteral< TP >          						\
  >,          								\
  Rows, Cols   								\
>          								\
operator OP (XprMatrix<E, Rows, Cols> lhs, TP rhs) {			\
  typedef XprBinOp<          						\
    FUNCTIONAL<typename E::value_type, TP >,   				\
    XprMatrix<E, Rows, Cols>,		        			\
    XprLiteral< TP >              			      		\
  >							expr_type;	\
  return XprMatrix<expr_type, Rows, Cols>(expr_type(lhs, XprLiteral< TP >(rhs))); \
}          								\
          								\
template<class E, std::size_t Rows, std::size_t Cols>			\
inline                 			      			      	\
XprMatrix<          							\
  XprBinOp<          							\
    FUNCTIONAL<TP, typename E::value_type>,    				\
    XprLiteral< TP >,          						\
    XprMatrix<E, Rows, Cols>			      			\
  >,          								\
  Rows, Cols   								\
>          								\
operator OP (TP lhs, XprMatrix<E, Rows, Cols> rhs) {  			\
  typedef XprBinOp<         						\
    FUNCTIONAL< TP, typename E::value_type>,   				\
    XprLiteral< TP >,         						\
    XprMatrix<E, Rows, Cols>   			      			\
  >							expr_type;	\
  return XprMatrix<expr_type, Rows, Cols>(expr_type(XprLiteral< TP >(lhs), rhs)); \
}

TVMET_BINARY_OPERATOR(fcnl_Add, +, int)
TVMET_BINARY_OPERATOR(fcnl_Sub, -, int)
TVMET_BINARY_OPERATOR(fcnl_Mul, *, int)
TVMET_BINARY_OPERATOR(fcnl_Div, /, int)
TVMET_BINARY_OPERATOR(fcnl_Mod, %, int)
TVMET_BINARY_OPERATOR(fcnl_BitwiseXor, ^, int)
TVMET_BINARY_OPERATOR(fcnl_BitwiseAnd, &, int)
TVMET_BINARY_OPERATOR(fcnl_BitwiseOr, |, int)
TVMET_BINARY_OPERATOR(fcnl_Shl, <<, int)
TVMET_BINARY_OPERATOR(fcnl_Shr, >>, int)
TVMET_BINARY_OPERATOR(fcnl_Greater, >, int)
TVMET_BINARY_OPERATOR(fcnl_Less, <, int)
TVMET_BINARY_OPERATOR(fcnl_GreaterOrEqual, >=, int)
TVMET_BINARY_OPERATOR(fcnl_LessOrEqual, <=, int)
TVMET_BINARY_OPERATOR(fcnl_Equal, ==, int)
TVMET_BINARY_OPERATOR(fcnl_NotEqual, !=, int)
TVMET_BINARY_OPERATOR(fcnl_LogicalAnd, &&, int)
TVMET_BINARY_OPERATOR(fcnl_LogicalOr, ||, int)

TVMET_BINARY_OPERATOR(fcnl_Add, +, float)
TVMET_BINARY_OPERATOR(fcnl_Sub, -, float)
TVMET_BINARY_OPERATOR(fcnl_Mul, *, float)
TVMET_BINARY_OPERATOR(fcnl_Div, /, float)
TVMET_BINARY_OPERATOR(fcnl_Greater, >, float)
TVMET_BINARY_OPERATOR(fcnl_Less, <, float)
TVMET_BINARY_OPERATOR(fcnl_GreaterOrEqual, >=, float)
TVMET_BINARY_OPERATOR(fcnl_LessOrEqual, <=, float)
TVMET_BINARY_OPERATOR(fcnl_Equal, ==, float)
TVMET_BINARY_OPERATOR(fcnl_NotEqual, !=, float)

TVMET_BINARY_OPERATOR(fcnl_Add, +, double)
TVMET_BINARY_OPERATOR(fcnl_Sub, -, double)
TVMET_BINARY_OPERATOR(fcnl_Mul, *, double)
TVMET_BINARY_OPERATOR(fcnl_Div, /, double)
TVMET_BINARY_OPERATOR(fcnl_Greater, >, double)
TVMET_BINARY_OPERATOR(fcnl_Less, <, double)
TVMET_BINARY_OPERATOR(fcnl_GreaterOrEqual, >=, double)
TVMET_BINARY_OPERATOR(fcnl_LessOrEqual, <=, double)
TVMET_BINARY_OPERATOR(fcnl_Equal, ==, double)
TVMET_BINARY_OPERATOR(fcnl_NotEqual, !=, double)

#ifdef TVMET_HAVE_LONG_DOUBLE
TVMET_BINARY_OPERATOR(fcnl_Add, +, long double)
TVMET_BINARY_OPERATOR(fcnl_Sub, -, long double)
TVMET_BINARY_OPERATOR(fcnl_Mul, *, long double)
TVMET_BINARY_OPERATOR(fcnl_Div, /, long double)
TVMET_BINARY_OPERATOR(fcnl_Greater, >, long double)
TVMET_BINARY_OPERATOR(fcnl_Less, <, long double)
TVMET_BINARY_OPERATOR(fcnl_GreaterOrEqual, >=, long double)
TVMET_BINARY_OPERATOR(fcnl_LessOrEqual, <=, long double)
TVMET_BINARY_OPERATOR(fcnl_Equal, ==, long double)
TVMET_BINARY_OPERATOR(fcnl_NotEqual, !=, long double)
#endif // TVMET_HAVE_LONG_DOUBLE

#undef TVMET_BINARY_OPERATOR

#ifdef TVMET_HAVE_COMPLEX
/*
 * XprVector<E, Sz> and std::complex<>
 * XprMatrix<E, Rows, Cols> and std::complex<>
 */
#define TVMET_BINARY_OPERATOR(FUNCTIONAL, OP, TP)              		\
template<class E, std::size_t Sz, class T>     				\
inline                 			      			      	\
XprVector<                  						\
  XprBinOp<          							\
    FUNCTIONAL<typename E::value_type, std::complex<T> >, 		\
    XprVector<E, Sz>,			          			\
    XprLiteral< std::complex<T> > 					\
  >,          								\
  Sz          								\
>          								\
operator OP (XprVector<E, Sz> lhs, const std::complex<T>& rhs) {	\
  typedef XprBinOp<          						\
    FUNCTIONAL<typename E::value_type, std::complex<T> >, 		\
    XprVector<E, Sz>,			        			\
    XprLiteral< std::complex<T> >              		      		\
  >							expr_type;	\
  return XprVector<expr_type, Sz>(expr_type(lhs, XprLiteral< std::complex<T> >(rhs))); \
}          								\
          								\
template<class E, std::size_t Sz, class T> 				\
inline                 			      			      	\
XprVector<          							\
  XprBinOp<          							\
    FUNCTIONAL<std::complex<T>, typename E::value_type>, 		\
    XprLiteral< std::complex<T> >,          				\
    XprVector<E, Sz>   				      			\
  >,          								\
  Sz          								\
>          								\
operator OP (const std::complex<T>& lhs, XprVector<E, Sz> rhs) {	\
  typedef XprBinOp<         						\
    FUNCTIONAL< std::complex<T>, typename E::value_type>,  		\
    XprLiteral< std::complex<T> >,         				\
    XprVector<E, Sz>           			      			\
  >							expr_type;	\
  return XprVector<expr_type, Sz>(expr_type(XprLiteral< std::complex<T> >(lhs), rhs)); \
}          								\
          								\
template<class E, std::size_t Rows, std::size_t Cols, class T>		\
inline                 			      			      	\
XprMatrix<                  						\
  XprBinOp<          							\
    FUNCTIONAL<typename E::value_type, std::complex<T> >,      		\
    XprMatrix<E, Rows, Cols>,		          			\
    XprLiteral< std::complex<T> >          				\
  >,          								\
  Rows, Cols   								\
>          								\
operator OP (XprMatrix<E, Rows, Cols> lhs, const std::complex<T>& rhs) { \
  typedef XprBinOp<          						\
    FUNCTIONAL<typename E::value_type, std::complex<T> >,   		\
    XprMatrix<E, Rows, Cols>,		        			\
    XprLiteral< std::complex<T> >              			      	\
  >							expr_type;	\
  return XprMatrix<expr_type, Rows, Cols>(expr_type(lhs, XprLiteral< std::complex<T> >(rhs))); \
}          								\
          								\
template<class E, std::size_t Rows, std::size_t Cols, class T>		\
inline                 			      			      	\
XprMatrix<          							\
  XprBinOp<          							\
    FUNCTIONAL<std::complex<T>, typename E::value_type>,    		\
    XprLiteral< std::complex<T> >,          				\
    XprMatrix<E, Rows, Cols>			      			\
  >,          								\
  Rows, Cols   								\
>          								\
operator OP (const std::complex<T>& lhs, XprMatrix<E, Rows, Cols> rhs) { \
  typedef XprBinOp<         						\
    FUNCTIONAL< std::complex<T>, typename E::value_type>,   		\
    XprLiteral< std::complex<T> >,         				\
    XprMatrix<E, Rows, Cols>   			      			\
  >							expr_type;	\
  return XprMatrix<expr_type, Rows, Cols>(expr_type(XprLiteral< std::complex<T> >(lhs), rhs)); \
}

TVMET_BINARY_OPERATOR(fcnl_Add, +, std::complex<T>)
TVMET_BINARY_OPERATOR(fcnl_Sub, -, std::complex<T>)
TVMET_BINARY_OPERATOR(fcnl_Mul, *, std::complex<T>)
TVMET_BINARY_OPERATOR(fcnl_Div, /, std::complex<T>)
TVMET_BINARY_OPERATOR(fcnl_Mod, %, std::complex<T>)
TVMET_BINARY_OPERATOR(fcnl_BitwiseXor, ^, std::complex<T>)
TVMET_BINARY_OPERATOR(fcnl_BitwiseAnd, &, std::complex<T>)
TVMET_BINARY_OPERATOR(fcnl_BitwiseOr, |, std::complex<T>)
TVMET_BINARY_OPERATOR(fcnl_Shl, <<, std::complex<T>)
TVMET_BINARY_OPERATOR(fcnl_Shr, >>, std::complex<T>)
TVMET_BINARY_OPERATOR(fcnl_Greater, >, std::complex<T>)
TVMET_BINARY_OPERATOR(fcnl_Less, <, std::complex<T>)
TVMET_BINARY_OPERATOR(fcnl_GreaterOrEqual, >=, std::complex<T>)
TVMET_BINARY_OPERATOR(fcnl_LessOrEqual, <=, std::complex<T>)
TVMET_BINARY_OPERATOR(fcnl_Equal, ==, std::complex<T>)
TVMET_BINARY_OPERATOR(fcnl_NotEqual, !=, std::complex<T>)
TVMET_BINARY_OPERATOR(fcnl_LogicalAnd, &&, std::complex<T>)
TVMET_BINARY_OPERATOR(fcnl_LogicalOr, ||, std::complex<T>)
#undef TVMET_BINARY_OPERATOR

#endif // TVMET_HAVE_COMPLEX

/***********************************************************************
 * global unary operators
 ***********************************************************************/

/*
 * Binary Operator on XprVector<E, Sz>
 * Operator on XprMatrix<E, Rows, Cols>
 */
#define TVMET_UNARY_OPERATOR(FUNCTIONAL, OP)                   		\
template <class E, std::size_t Sz>					\
inline                                                        		\
XprVector<                                                        	\
  XprUnOp<                                                        	\
    FUNCTIONAL<typename E::value_type>,                                 \
    XprVector<E, Sz>							\
  >,                                                        		\
  Sz									\
>                                                        		\
operator OP (XprVector<E, Sz> rhs) {					\
  typedef XprUnOp<                                                      \
    FUNCTIONAL<typename E::value_type>,                                 \
    XprVector<E, Sz>							\
  >  							 expr_type;	\
  return XprVector<expr_type, Sz>(expr_type(rhs));			\
}                                                        		\
                                                        		\
template <class E, std::size_t Rows, std::size_t Cols>			\
inline                                                        		\
XprMatrix<                                                        	\
  XprUnOp<                                                        	\
    FUNCTIONAL<typename E::value_type>,                                 \
    XprMatrix<E, Rows, Cols>						\
  >,                                                        		\
  Rows, Cols								\
>                                                        		\
operator OP (XprMatrix<E, Rows, Cols> rhs) {				\
  typedef XprUnOp<                                                      \
    FUNCTIONAL<typename E::value_type>,                                 \
    XprMatrix<E, Rows, Cols>						\
  >  							 expr_type;	\
  return XprMatrix<expr_type, Rows, Cols>(expr_type(rhs));		\
}

TVMET_UNARY_OPERATOR(fcnl_LogicalNot, !)
TVMET_UNARY_OPERATOR(fcnl_BitwiseNot, ~)
TVMET_UNARY_OPERATOR(fcnl_Negate, -)
#undef TVMET_UNARY_OPERATOR

} // namespace tvmet

#endif // TVMET_XPR_OPERATORS_H

// Local Variables:
// mode:C++
// End:
