/*
 * 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_NUMERIC_TRAITS_H
#define TVMET_NUMERIC_TRAITS_H

namespace tvmet {

/**
 * \class NumericTraits NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits for integral types for operations.
 *
 * For each type we have to specialize this traits.
 *
 * \note Keep in mind that the long types long long and long double doesn't
 *       have traits. This is due to the sum_type. We can't give a guarantee
 *       that there is a type of holding the sum. Therefore using this traits
 *       is only safe if you have long long resp. long double types by
 *       working on long ints and doubles. Otherwise you will get not expected
 *       result for some circumstances. Anyway, you can use big integer/float
 *       libraries and specialize the traits by your own.
 */
template<class T>
struct NumericTraits { };

/*
 * numeric traits for standard types
 */

/**
 * \class NumericTraits<char> NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for char.
 */
template<> struct NumericTraits<char> {
  typedef char				value_type;
  typedef long				sum_type;
  typedef int				diff_type;
  typedef float				float_type;
  typedef char				signed_type;
};

/**
 * \class NumericTraits<unsigned char> NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for unsigned char.
 */
template<> struct NumericTraits<unsigned char> {
  typedef unsigned char 		value_type;
  typedef unsigned long	 		sum_type;
  typedef int		 		diff_type;
  typedef float		 		float_type;
  typedef int				signed_type;
};

/**
 * \class NumericTraits<short int> NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for short int.
 */
template<> struct NumericTraits<short int> {
  typedef short int 			value_type;
#ifdef TVMET_HAVE_LONG_LONG
  typedef long long		 	sum_type;
#else
  typedef long 				sum_type;
#endif
  typedef int			 	diff_type;
  typedef float 			float_type;
  typedef short int			signed_type;
};

/**
 * \class NumericTraits<short unsigned int> NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for short unsigned int.
 */
template<> struct NumericTraits<short unsigned int> {
  typedef short unsigned int		value_type;
#ifdef TVMET_HAVE_LONG_LONG
  typedef unsigned long long		sum_type;
#else
  typedef unsigned long 		sum_type;
#endif
  typedef int 				diff_type;
  typedef float 			float_type;
  typedef int				signed_type;
};

/**
 * \class NumericTraits<int> NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for int.
 */
template<> struct NumericTraits<int> {
  typedef int 				value_type;
#ifdef TVMET_HAVE_LONG_LONG
  typedef long long		 	sum_type;
#else
  typedef long 				sum_type;
#endif
  typedef int			 	diff_type;
  typedef float			 	float_type;
  typedef int				signed_type;
};

/**
 * \class NumericTraits<unsigned int> NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for unsigned int.
 */
template<> struct NumericTraits<unsigned int> {
  typedef unsigned int 		 	value_type;
#ifdef TVMET_HAVE_LONG_LONG
  typedef unsigned long long		sum_type;
#else
  typedef unsigned long; 		sum_type;
#endif
  typedef int 			 	diff_type;
  typedef float 			float_type;
  typedef long			 	signed_type;
};

/**
 * \class NumericTraits<long> NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for long.
 */
template<> struct NumericTraits<long> {
  typedef long 			 	value_type;
#ifdef TVMET_HAVE_LONG_LONG
  typedef long long		 	sum_type;
#else
  typedef long			  	sum_type;
#endif
  typedef long 		 		diff_type;
  typedef double 			float_type;
  typedef long		 	 	signed_type;
};

/**
 * \class NumericTraits<unsigned long> NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for unsigned long.
 */
template<> struct NumericTraits<unsigned long> {
  typedef unsigned long 		value_type;
#ifdef TVMET_HAVE_LONG_LONG
  typedef unsigned long long 		sum_type;
#else
  typedef unsigned long 		sum_type;
#endif
  typedef unsigned long 		diff_type;
  typedef double 			float_type;
  typedef long				signed_type;
};

/**
 * \class NumericTraits<float> NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for float.
 */
template<> struct NumericTraits<float> {
  typedef float				value_type;
  typedef double 			sum_type;
  typedef float 			diff_type;
  typedef float 			float_type;
  typedef float				signed_type;
};

/**
 * \class NumericTraits<double> NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for double.
 */
template<> struct NumericTraits<double> {
  typedef double 			value_type;
#ifdef TVMET_HAVE_LONG_DOUBLE
  typedef long double		 	sum_type;
#else
  typedef double 			sum_type;
#endif
  typedef double			diff_type;
  typedef double 			float_type;
  typedef double			signed_type;
};


/*
 * numeric traits for complex types
 */
#ifdef TVMET_HAVE_COMPLEX

/**
 * \class NumericTraits< std::complex<int> > NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for std::complex<int>.
 */
template<> struct NumericTraits< std::complex<int> > {
  typedef std::complex<int>		value_type;
  typedef std::complex<long> 		sum_type;
  typedef std::complex<int>		diff_type;
  typedef std::complex<float>		float_type;
  typedef std::complex<int>		signed_type;
};

/**
 * \class NumericTraits< std::complex<unsigned int> > NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for std::complex<unsigned int>.
 */
template<> struct NumericTraits< std::complex<unsigned int> > {
  typedef std::complex<unsigned int> 	value_type;
  typedef std::complex<unsigned long> 	sum_type;
  typedef std::complex<int>		diff_type;
  typedef std::complex<float>		float_type;
  typedef std::complex<int>		signed_type;
};

/**
 * \class NumericTraits< std::complex<long> > NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for std::complex<long>.
 */
template<> struct NumericTraits< std::complex<long> > {
  typedef std::complex<long>		value_type;
#ifdef TVMET_HAVE_LONG_LONG
  typedef std::complex<long long>	sum_type;
#else
  typedef std::complex<long>		sum_type;
#endif
  typedef std::complex<int>		diff_type;
  typedef std::complex<float>		float_type;
  typedef std::complex<int>		signed_type;
};

/**
 * \class NumericTraits< std::complex<unsigned long> > NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for std::complex<unsigned long>.
 */
template<> struct NumericTraits< std::complex<unsigned long> > {
  typedef std::complex<unsigned long>	value_type;
#ifdef TVMET_HAVE_LONG_LONG
  typedef std::complex<unsigned long long> sum_type;
#else
  typedef std::complex<unsigned long>	sum_type;
#endif
  typedef std::complex<long>		diff_type;
  typedef std::complex<float>		float_type;
  typedef std::complex<long>		signed_type;
};

/**
 * \class NumericTraits< std::complex<float> > NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for std::complex<float>.
 */
template<> struct NumericTraits< std::complex<float> > {
  typedef std::complex<float>		value_type;
  typedef std::complex<double>		sum_type;
  typedef std::complex<float>		diff_type;
  typedef std::complex<float>		float_type;
  typedef std::complex<float>		signed_type;
};

/**
 * \class NumericTraits< std::complex<double> > NumericTraits.h "tvmet/NumericTraits.h"
 * \brief Traits specialized for std::complex<double>.
 */
template<> struct NumericTraits< std::complex<double> > {
  typedef std::complex<double>		value_type;
#ifdef TVMET_HAVE_LONG_DOUBLE
  typedef std::complex<long double> 	sum_type;
#else
  typedef std::complex<double>		sum_type;
#endif
  typedef std::complex<double>		diff_type;
  typedef std::complex<double>		float_type;
  typedef std::complex<double>		signed_type;
};

#endif // TVMET_HAVE_COMPLEX


} // namespace tvmet

#endif //  TVMET_NUMERIC_TRAITS_H

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