/* Copyright (c) 1997-2006
   Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany)
   http://www.math.tu-berlin.de/polymake,  mailto:polymake@math.tu-berlin.de

   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, or (at your option) any
   later version: http://www.gnu.org/licenses/gpl.txt.

   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.
*/

#ifndef _POLYMAKE_COMPARATORS_BASIC_DEFS_H
#define _POLYMAKE_COMPARATORS_BASIC_DEFS_H "$Project: polymake $$Id: comparators_basic_defs.h 7476 2006-11-28 17:16:30Z gawrilow $"

#ifndef _POLYMAKE_OPERATIONS_BASIC_DEFS_H
#  include <operations_basic_defs.h>
#endif
#include <limits>

namespace pm {

enum cmp_value { cmp_lt=-1, cmp_eq=0, cmp_gt=1 };

template <typename T> inline
cmp_value sign(const T& x)
{
   return x<T(0) ? cmp_lt : cmp_value(x>T(0));
}

inline cmp_value sign(int x)
{
   const unsigned int bits=sizeof(int)*8-1;
   return cmp_value((x >> bits) + (((unsigned int)x + ((unsigned int)(-1) >> 1)) >> bits));
}
inline cmp_value sign(long x)
{
   const unsigned int bits=sizeof(long)*8-1;
   return cmp_value((x >> bits) + (((unsigned long)x + ((unsigned long)(-1L) >> 1)) >> bits));
}

template <typename T, bool _is_max> struct extremal { };
template <typename T> struct maximal : extremal<T,true> { };
template <typename T> struct minimal : extremal<T,false> { };

namespace operations {

template <typename T>
struct cmp_common {
   typedef T first_argument_type;
   typedef T second_argument_type;
   typedef cmp_value result_type;

   template <bool _is_max_l, bool _is_max_r>
   result_type operator() (const extremal<T,_is_max_l>&, const extremal<T,_is_max_r>&) const
   {
      return _is_max_l == _is_max_r ? cmp_eq : _is_max_l ? cmp_gt : cmp_lt;
   }

   template <bool _is_max_l>
   result_type operator() (const extremal<T,_is_max_l>&, const T&) const
   {
      return _is_max_l ? cmp_gt : cmp_lt;
   }

   template <bool _is_max_r>
   result_type operator() (const T&, const extremal<T,_is_max_r>&) const
   {
      return _is_max_r ? cmp_lt : cmp_gt;
   }
};

template <typename T>
struct cmp_scalar : cmp_common<T> {
   using cmp_common<T>::operator();

   cmp_value operator() (typename function_argument<T>::type a, typename function_argument<T>::type b) const
   {
      return a<b ? cmp_lt : cmp_value(a>b);
   }
};

template <typename T>
struct cmp_numeric : cmp_scalar<T> {
protected:
   typedef cmp_scalar<T> super;

   cmp_value _do(typename function_argument<T>::type a, typename function_argument<T>::type b, True) const
   {
      return sign(a-b);
   }
   cmp_value _do(typename function_argument<T>::type a, typename function_argument<T>::type b, False) const
   {
      return super::operator()(a,b);
   }
public:
   using cmp_common<T>::operator();

   cmp_value operator() (typename function_argument<T>::type a, typename function_argument<T>::type b) const
   {
      return _do(a,b,bool2type<std::numeric_limits<T>::is_integer>());
   }

   template <typename Iterator2>
   cmp_value operator() (partial_left, typename function_argument<T>::type a, const Iterator2&) const
   {
      return cmp_value(sign(a));
   }
   template <typename Iterator1>
   cmp_value operator() (partial_right, const Iterator1&, typename function_argument<T>::type b) const
   {
      return cmp_value(-sign(b));
   }
};

} // end namespace operations

template <typename T1, typename T2> inline
T1& assign_max(T1& max, const T2& x) { if (max<x) max=x; return max; }

template <typename T1, typename T2> inline
T1& assign_min(T1& min, const T2& x) { if (min>x) min=x; return min; }

template <typename T1, typename T2, typename T3> inline
void assign_min_max(T1& min, T2& max, const T3& x)
{
   if (min>x) min=x; else if (max<x) max=x;
}

} // end namespace pm

#endif // _POLYMAKE_COMPARATORS_BASIC_DEFS_H

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