/* Copyright (c) 1997-2010
   Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Darmstadt, Germany)
   http://www.polymake.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.
--------------------------------------------------------------------------------
   $Project: polymake $$Id: converters_basic_defs.h 9991 2010-12-12 23:36:28Z gawrilow $
*/

#ifndef POLYMAKE_INTERNAL_CONVERTERS_BASIC_DEFS_H
#define POLYMAKE_INTERNAL_CONVERTERS_BASIC_DEFS_H

#include "polymake/internal/type_manip.h"

#include <cstdlib>
#include <cmath>

namespace pm {

/** Type converter
    The primary template can't make any exotic assumptions about types to be converted.
    The only thing it can rely upon is an user-defined or built-in conversion operator
    or constructor.

    Specializations of this template may make use of some specific conversion routines
    that can't be called implicitly in C++.
*/
template <typename From, typename To>
struct conv {
   typedef From argument_type;
   typedef const To result_type;
   result_type operator() (typename function_argument<From>::type x) const { return result_type(x); }
};

/// Trivial conversion of a type to itself
template <typename T>
struct conv<T,T> {
   typedef T argument_type;
   typedef const T& result_type;
   result_type operator() (const T& x) const { return x; }
};

template <typename T>
struct threshold_test {
   typedef T argument_type;
   typedef bool result_type;

   const T epsilon;
   threshold_test(typename function_argument<T>::type epsilon_arg) : epsilon(epsilon_arg) { }

   result_type operator() (typename function_argument<T>::type x) const
   {
      return abs(x) > epsilon;
   }
};

template <>
struct conv<double, bool> : threshold_test<double> {
   static double global_epsilon;
   conv() : threshold_test<double>(global_epsilon) { }
   conv(double epsilon_arg) : threshold_test<double>(epsilon_arg) { }
};

template <>
struct conv<float, bool> : threshold_test<float> {
   conv() : threshold_test<float>(conv<double,bool>::global_epsilon) { }
   conv(float epsilon_arg) : threshold_test<float>(epsilon_arg) { }
};

class local_epsilon_keeper {
   mutable double saved;
public:
   local_epsilon_keeper(double new_val)
      : saved(conv<double,bool>::global_epsilon)
   {
      conv<double,bool>::global_epsilon=new_val;
   }

   local_epsilon_keeper(const local_epsilon_keeper& le)
      : saved(le.saved)
   {
      le.saved=conv<double,bool>::global_epsilon;
   }

   ~local_epsilon_keeper() { conv<double,bool>::global_epsilon=saved; }
};

inline
local_epsilon_keeper local_epsilon(double new_val)
{
   return local_epsilon_keeper(new_val);
}

} // end namespace pm

#endif // POLYMAKE_INTERNAL_CONVERTERS_BASIC_DEFS_H

// Local Variables:
// mode:C++
// c-basic-offset:3
// indent-tabs-mode:nil
// End:
