/*
 * 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_BINARY_FUNCTIONAL_H
#define TVMET_BINARY_FUNCTIONAL_H

namespace tvmet {


/**
 * \class fcnl_Assign BinaryFunctionals.h "tvmet/BinaryFunctionals.h"
 * \brief Binary operator for assign operations.
 *
 * Unfortunally we have sometimes to cast on assign operations e.g.,
 * on assign on different POD. So we avoid warnings.
 */
template <class T1, class T2>
struct fcnl_Assign : public BinaryFunctional {
  typedef void						return_type;
  static inline return_type applyOn(T1& _tvmet_restrict lhs, T2 rhs) {
    lhs = static_cast<T1>(rhs);
  }
  static void print_on(std::ostream& os, std::size_t l=0) {
    os << IndentLevel(l) << "_fncl_Assign<"
       << typeid(T1).name() << ", " << typeid(T2).name() << ">,"
       << std::endl;
  }
};

/*
 *
 */
#define TVMET_BINARY_FUNCTIONAL(OPNAME, OP)                   		\
template <class T1, class T2>                                 		\
struct OPNAME : public BinaryFunctional {	          		\
  typedef void						return_type; 	\
  static inline return_type applyOn(T1& _tvmet_restrict lhs, T2 rhs) { 	\
    lhs OP rhs;                                           		\
  }                                                         		\
  static void print_on(std::ostream& os, std::size_t l=0) {    		\
    os << IndentLevel(l) << #OPNAME << "<"     				\
       << typeid(T1).name() << ", " << typeid(T2).name() << ">,"    	\
       << std::endl;  							\
  }     								\
};

TVMET_BINARY_FUNCTIONAL(fcnl_AddUpd, +=)
TVMET_BINARY_FUNCTIONAL(fcnl_SubUpd, -=)
TVMET_BINARY_FUNCTIONAL(fcnl_MulUpd, *=)
TVMET_BINARY_FUNCTIONAL(fcnl_DivUpd, /=)
TVMET_BINARY_FUNCTIONAL(fcnl_ModUpd, %=)
TVMET_BINARY_FUNCTIONAL(fcnl_BitwiseXorUpd, ^=)
TVMET_BINARY_FUNCTIONAL(fcnl_BitwiseAndUpd, &=)
TVMET_BINARY_FUNCTIONAL(fcnl_BitwiseOrUpd, |=)
TVMET_BINARY_FUNCTIONAL(fcnl_ShlUpd, <<=)
TVMET_BINARY_FUNCTIONAL(fcnl_ShrUpd, >>=)

/** \class fcnl_AddUpd 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_SubUpd 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_MulUpd 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_DivUpd 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_ModUpd 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_BitwiseXorUpd	BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_BitwiseAndUpd	BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_BitwiseOrUpd	BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_ShlUpd 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_ShrUpd 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */

#undef TVMET_BINARY_FUNCTIONAL


/*
 *
 */
#define TVMET_BINARY_FUNCTIONAL(OPNAME, OP)                   		\
template <class T1, class T2>                                 		\
struct OPNAME : public BinaryFunctional {              			\
  typedef typename  PromoteTraits<T1, T2>::value_type	return_type; 	\
  static inline return_type applyOn(T1 lhs, T2 rhs) {          		\
    return lhs OP rhs;                                     		\
  }                                                         		\
  static void print_on(std::ostream& os, std::size_t l=0) {    		\
    os << IndentLevel(l) << #OPNAME << "<"     				\
       << typeid(T1).name() << ", " << typeid(T2).name() << ">,"    	\
       << std::endl;  							\
  }     								\
};

TVMET_BINARY_FUNCTIONAL(fcnl_Add, +)
TVMET_BINARY_FUNCTIONAL(fcnl_Sub, -)
TVMET_BINARY_FUNCTIONAL(fcnl_Mul, *)
TVMET_BINARY_FUNCTIONAL(fcnl_Div, /)
TVMET_BINARY_FUNCTIONAL(fcnl_Mod, %)
TVMET_BINARY_FUNCTIONAL(fcnl_BitwiseXor, ^)
TVMET_BINARY_FUNCTIONAL(fcnl_BitwiseAnd, &)
TVMET_BINARY_FUNCTIONAL(fcnl_BitwiseOr, |)
TVMET_BINARY_FUNCTIONAL(fcnl_Shl, <<)
TVMET_BINARY_FUNCTIONAL(fcnl_Shr, >>)

/** \class fcnl_Add 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_Sub 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_Mul 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_Div 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_Mod 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_BitwiseXor	BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_BitwiseAnd	BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_BitwiseOr	BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_Shl 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_Shr 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */

#undef TVMET_BINARY_FUNCTIONAL


/*
 *
 */
#define TVMET_BINARY_FUNCTIONAL(OPNAME, OP)                   		\
template <class T1, class T2>                            		\
struct OPNAME : public BinaryFunctional {          			\
  typedef bool						return_type; 	\
  static inline return_type applyOn(T1 lhs, T2 rhs) {          		\
    return lhs OP rhs;                                     		\
  }                                                         		\
  static void print_on(std::ostream& os, std::size_t l=0) {    		\
    os << IndentLevel(l) << #OPNAME << "<"     				\
       << typeid(T1).name() << ", " << typeid(T2).name() << ">,"    	\
       << std::endl;  							\
  }     								\
};

TVMET_BINARY_FUNCTIONAL(fcnl_Greater, >)
TVMET_BINARY_FUNCTIONAL(fcnl_Less, <)
TVMET_BINARY_FUNCTIONAL(fcnl_GreaterOrEqual, >=)
TVMET_BINARY_FUNCTIONAL(fcnl_LessOrEqual, <=)
TVMET_BINARY_FUNCTIONAL(fcnl_Equal, ==)
TVMET_BINARY_FUNCTIONAL(fcnl_NotEqual, !=)
TVMET_BINARY_FUNCTIONAL(fcnl_LogicalAnd, &&)
TVMET_BINARY_FUNCTIONAL(fcnl_LogicalOr, ||)

/** \class fcnl_Greater 	BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_GreaterOrEqual 	BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_Less 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_LessOrEqual 	BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_Equal 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_NotEqual 	BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_LogicalAnd 	BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_LogicalOr 	BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */

#undef TVMET_BINARY_FUNCTIONAL


/*
 *
 */
#define TVMET_BINARY_FUNCTIONAL(FUNCNAME, MATHFUNC)             	\
template <class T1, class T2>	                               		\
struct FUNCNAME : public BinaryFunctional {	              		\
  typedef typename PromoteTraits<T1, T2>::value_type	return_type; 	\
  static inline return_type applyOn(T1 lhs, T2 rhs) {	        	\
    return MATHFUNC(lhs, rhs);						\
  }                                                         		\
  static void print_on(std::ostream& os, std::size_t l=0) {    		\
    os << IndentLevel(l) << #FUNCNAME << "<"   				\
       << typeid(T1).name() << ", " << typeid(T2).name() << ">,"    	\
       << std::endl;  							\
  }     								\
};

TVMET_BINARY_FUNCTIONAL(fcnl_atan2, std::atan2)
TVMET_BINARY_FUNCTIONAL(fcnl_drem, std::drem)
TVMET_BINARY_FUNCTIONAL(fcnl_fmod, std::fmod)
TVMET_BINARY_FUNCTIONAL(fcnl_hypot, std::hypot)
TVMET_BINARY_FUNCTIONAL(fcnl_jn, std::jn)
TVMET_BINARY_FUNCTIONAL(fcnl_yn, std::yn)
TVMET_BINARY_FUNCTIONAL(fcnl_pow, std::pow)

/** \class fcnl_atan2 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_drem 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_fmod 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_hypot 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_jn 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_yn 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */
/** \class fcnl_pow 		BinaryFunctionals.h "tvmet/BinaryFunctionals.h" */

#undef TVMET_BINARY_FUNCTIONAL


/**
 * \class fcnl_Swap BinaryFunctionals.h "tvmet/BinaryFunctionals.h"
 * \brief Binary operator for swapping values using temporaries.
 */
template <class T1, class T2>
struct fcnl_Swap : public BinaryFunctional {
  typedef void						return_type;
  static inline return_type applyOn(T1& _tvmet_restrict lhs, T2& _tvmet_restrict rhs) {
    typedef typename  PromoteTraits<T1, T2>::value_type	tmp_type;
    tmp_type tmp(lhs);
    lhs = static_cast<T1>(rhs);
    rhs = static_cast<T2>(tmp);
  }
  static void print_on(std::ostream& os, std::size_t l=0) {
    os << IndentLevel(l) << "_fncl_Swap<"
       << typeid(T1).name() << ", " << typeid(T2).name() << ">,"
       << std::endl;
  }
};


} // namespace tvmet

#endif // TVMET_BINARY_FUNCTIONAL_H

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