//  functional : headerfile for the free standard C++ library
//  
//  Copyright (C) 1999 by the free standard C++ Library Team
//                        see AUTHORS for more details
//
//  Homepage : http://www.inf.fu-berlin.de/~mkrueger/fscl/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Library General Public
//  License as published by the Free Software Foundation; either	
//  version 2 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
//  Library General Public License for more details.
//  You should have received a copy of the GNU Library General Public
//  License along with this library; if not, write to the Free
//  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//  version : 0.1 last modified : 17.09.99


#ifndef __CPP_FUNCTIONAL
#define __CPP_FUNCTIONAL

#include<cstddef>
#include<new>

namespace std {

	// 20.3.1, base :	
    template <class Arg, class Result> 
	struct unary_function 
	{
		typedef Arg argument_type;
		typedef Result result_type;	
	};
    
	template <class Arg1, class Arg2, class Result>
	struct binary_function 
	{
		typedef Arg1   first_argument_type;
		typedef Arg2   second_argument_type;
		typedef Result result_type;   
	};
	
	// 20.3.2, arithmetic operations : 
    template <class T>
	struct plus : binary_function<T, T, T>
	{
		T operator()(const T& x, const T& y) const
		{
			return x + y;
		}
	};
	
    template <class T>
	struct minus : binary_function<T, T, T>
	{
		T operator()(const T& x, const T& y) const
		{
			return x - y;
		}
	};
	
    template <class T>
	struct multiplies : binary_function<T, T, T> 
	{
		T operator()(const T& x, const T& y) const
		{
			return x * y;
		}				
	};
	
    template <class T>
	struct divides : binary_function<T, T, T>
	{
		T operator()(const T& x, const T& y) const
		{
			return x / y;
		}
	};
	
    template <class T> 
	struct modulus : binary_function<T, T, T> 
	{
		T operator()(const T& x, const T& y) const
		{
			return x % y;
		}
	};
	
    template <class T> 
	struct negate : unary_function<T, T> 
	{
		T operator()(const T& x) const
		{
			return -x;
		}
	};
	
	// 20.3.3, comparisons:
    template <class T>
	struct equal_to : binary_function<T, T, T> 
	{
		T operator()(const T& x, const T& y) const
		{
			return x == y;
		}
	};

    template <class T>
	struct not_equal_to : binary_function<T, T, T> 
	{
		T operator()(const T& x, const T& y) const
		{
			return x != y;
		}
	};

    template <class T>
	struct greater : binary_function<T, T, T> 
	{
		T operator()(const T& x, const T& y) const
		{
			return x > y;
		}
	};

    template <class T>
	struct less : binary_function<T, T, T> 
	{
		T operator()(const T& x, const T& y) const
		{
			return x < y;
		}
	};

    template <class T>
	struct greater_equal : binary_function<T, T, T> 
	{
		T operator()(const T& x, const T& y) const
		{
			return x >= y;
		}
	};

    template <class T>
	struct less_equal : binary_function<T, T, T> 
	{
		T operator()(const T& x, const T& y) const
		{
			return x <= y;
		}
	};
	
	// 20.3.4, logical operations :
    template <class T>
	struct logical_and : binary_function<T, T, T> 
	{
		T operator()(const T& x, const T& y) const
		{
			return x && y;
		}
	};

    template <class T>
	struct logical_or : binary_function<T, T, T> 
	{
		T operator()(const T& x, const T& y) const
		{
			return x || y;
		}
	};

    template <class T>
	struct logical_not : unary_function<T, T> 
	{
		T operator()(const T& x) const
		{
			return !x;
		}
	};
	
	// NON STANDARD FUNCTIONS ///////////////////////////////////////////////

	template <class T>
	struct identity : unary_function<T, T> 
	{
		T operator()(const T& x) const
		{
			return x;
		}
	};

	template <class T>
	struct binary_and : binary_function<T, T, T> 
	{
		T operator()(const T& x, const T& y) const
		{
			return x & y;
		}
	};
	
	template <class T>
	struct binary_or : binary_function<T, T, T> 
	{
		T operator()(const T& x, const T& y) const
		{
			return x | y;
		}
	};

	template <class T>
	struct binary_xor : binary_function<T, T, T> 
	{
		T operator()(const T& x, const T& y) const
		{
			return x ^ y;
		}
	};

	template <class T>
	struct binary_not : unary_function<T, T>
	{
		T operator()(const T& x) const
		{
			return ~x;
		}
	};
	//////////////////////////////////////////////////////////////////////
	
	// 20.3.5, negators:
    template <class Predicate> 
	struct unary_negate : unary_function<typename Predicate::argument_type, bool>
	{
		explicit unary_negate(const Predicate &pred) 
		: p(pred)
		{
		}
		bool operator()(const typename Predicate::argument_type &x) const
		{
			return !p(x);
		}
	protected:
		Predicate p;
	};

    template <class Predicate>
	unary_negate<Predicate>  not1(const Predicate &pred)
	{
		return unary_negate<Predicate>(pred);
	}

    template <class Predicate> 
	struct binary_negate : binary_function<typename Predicate::first_argument_type, typename Predicate::second_argument_Type, bool> 
	{
		explicit binary_negate(const Predicate &pred) 
		: p(pred)
		{
		}
		
		bool operator()(const typename Predicate::first_argument_type &x, const typename Predicate::second_argument_type &y) const
		{
			return !p(x,y);
		}
	protected:
		Predicate p;
	};
	
	template <class Predicate>
	binary_negate<Predicate> not2(const Predicate &pred) 
	{
		return binary_negate<Predicate>(pred);
	}

	// 20.3.6, binders :
	template <class Operation>
	class binder1st : public unary_function<typename Operation::second_argument_type, typename Operation::result_type>
	{
		public:
			binder1st(const Operation &x, const typename Operation::first_argument_type &y)
			: op(x), value(y)
			{
			}
		
			typename Operation::result_type operator()(const typename Operation::argument_type& x) const
			{
				return op(value, x);
			}
		protected:
			Operation op;
			typename Operation::first_argument_type value;
	};

	template <class Operation, class T>
	binder1st<Operation> bind1st(const Operation& op, const T& x)
	{
		return binder1st<Operation>(op, Operation::first_argument_type(x));
	}
	
    template <class Operation>
	class binder2nd : public unary_function<typename Operation::first_argument_type,typename Operation::result_type> 
	{
		public:
			binder2nd(const Operation& x, const typename Operation::second_argument_type& y) 
			: op(x), value(y)
			{
			}
		
			typename Operation::result_type operator()(const typename Operation::argument_type& x) const
			{
				return op(x, value);
			}
		protected:
			Operation                       op;
			typename Operation::second_argument_type value;   
	};

	template <class Operation, class T>
	binder2nd<Operation> bind2nd(const Operation& op, const T& x)
	{
		return binder2nd<Operation>(op, Operation::second_argument_type(x));
	}

	// 20.3.7, adaptors:
    template <class Arg, class Result> 
	class pointer_to_unary_function : public unary_function<Arg, Result>
	{
		public:
			explicit pointer_to_unary_function(Result (*x)(Arg)) 
			: ptr(x)
			{
			}
		
			Result operator()(Arg x) const 
			{
				return ptr(x);
			}
		protected:
			Result (*ptr)(Arg);
	};
	
	template <class Arg, class Result>
	pointer_to_unary_function<Arg,Result> ptr_fun(Result (*)(Arg))
	{
		return pointer_to_unary_function<Arg, Result>(f);
	}
	
    template <class Arg1, class Arg2, class Result>
	class pointer_to_binary_function : public binary_function<Arg1,Arg2,Result>
	{
		public:
			explicit pointer_to_binary_function(Result (*x)(Arg1, Arg2)) 
			: ptr(x)
			{
			}
		
			Result operator()(Arg1 x, Arg2 y) const
			{
				return ptr(x,y);
			}
     
		protected:
			Result (*ptr)(Arg1, Arg2);
	};
	
	template <class Arg1, class Arg2, class Result>
	pointer_to_binary_function<Arg1,Arg2,Result> ptr_fun(Result (*f)(Arg1,Arg2))
	{
		return pointer_to_binary_function<Arg1,Arg2,Result>(f);
	}

	// 20.3.8, adaptors:
	template<class S, class T>
	class mem_fun_t : public unary_function<T*, S> 
	{
	    public:
			explicit mem_fun_t(S (T::*p)()) 
			: ptr(p)
			{
			}

			S operator()(T *p) const
			{
				return ((p->*ptr)());
			}
		protected:
			S (T::*ptr)();
	};

	template<class S, class T>
	mem_fun_t<S, T> mem_fun(S (T::*f)())
	{
		return (mem_fun_t<S, T>(f));
	}	

	template<class S, class T, class A>
	class mem_fun1_t : public binary_function<T*, A, S> 
	{
		public:
			explicit mem_fun1_t(S (T::*p)(A)) 
			: ptr(p)
			{
			}
			
			S operator()(T* p, A x) const
			{
				return ((p->*ptr)(x));
			}
		protected:
			S (T::*ptr)(A);
	};
	
	template<class S, class T, class A>
	mem_fun1_t<S, T, A> mem_fun1(S (T::*f)(A))
	{
		return mem_fun1_t<S, T, A>( f);
	}
	
	template<class S, class T>
	class mem_fun_ref_t : public unary_function<T, S>
	{
		public:
			explicit mem_fun_ref_t(S (T::*p)()) 
			: ptr(p)
			{
			}
		
			S operator()(T &x) const
			{
				return ((x.*ptr)()); 
			}
		protected:
			S (T::*ptr)();
	};
	
	template<class S, class T>
	mem_fun_ref_t<S, T> mem_fun_ref(S (T::*f)())
	{
		return (mem_fun_ref_t<S, T>(f));
	}
	
	template<class S, class T, class A> 
	class mem_fun1_ref_t : public binary_function<T, A, S>
	{
		public:
			explicit mem_fun1_ref_t(S (T::*p)(A)) 
			: ptr(p)
			{
			}

			S operator()(T& p, A x) const
			{
				return ((p.*ptr)(x));
			}

		protected:
			S (T::*ptr)();
	};
    	
	template<class S, class T, class A>
	mem_fun1_ref_t<S, T,A> mem_fun1_ref(S (T::*f)(A))
	{
		return  (mem_fun1_ref_t<S, T, A>(f)); 
	}


	
	template<class S, class T>
	class const_mem_fun_t : public unary_function<T*, S> 
	{
	    public:
			explicit const_mem_fun_t(S (T::*p)() const) 
			: ptr(p)
			{
			}
		
			S operator()(const T *p) const
			{
				return ((p->*ptr)());
			}
		protected:
			S (T::*ptr)();
	};


	template<class S, class T>
	const_mem_fun_t<S, T> const_mem_fun(S (T::*f)() const)
	{
		return (const_mem_fun_t<S, T>(f));
	}	

	template<class S, class T, class A>
	class const_mem_fun1_t : public binary_function<T*, A, S> 
	{
		public:
			explicit const_mem_fun1_t(S (T::*p)(A) const) 
			: ptr(p)
			{
			}
			
			S operator()(const T* p, A x) const
			{
				return ((p->*ptr)(x));
			}
		protected:
			S (T::*ptr)(A);
	};
	
	template<class S, class T, class A>
	const_mem_fun1_t<S, T, A> const_mem_fun1(S (T::*f)(A) const)
	{
		return const_mem_fun1_t<S, T, A>(f);
	}
	
	template<class S, class T>
	class const_mem_fun_ref_t : public unary_function<T, S>
	{
		public:
			explicit const_mem_fun_ref_t(S (T::*p)() const) 
			: ptr(p)
			{
			}
		
			S operator()(const T &x) const
			{
				return ((x.*ptr)()); 
			}
		protected:
			S (T::*ptr)();
	};
	
	template<class S, class T>
	const_mem_fun_ref_t<S, T> const_mem_fun_ref(S (T::*f)() const)
	{
		return (const_mem_fun_ref_t<S, T>(f));
	}
	
	template<class S, class T, class A> 
	class const_mem_fun1_ref_t : public binary_function<T, A, S>
	{
		public:
			explicit const_mem_fun1_ref_t(S (T::*p)(A) const) 
			: ptr(p)
			{
			}

			S operator()(const T& p, A x) const
			{
				return ((p.*ptr)(x));
			}

		protected:
			S (T::*ptr)();
	};
    	
	template<class S, class T, class A>
	const_mem_fun1_ref_t<S, T,A> const_mem_fun1_ref(S (T::*f)(A) const)
	{
		return  (const_mem_fun1_ref_t<S, T, A>(f)); 
	}
	
}

#endif
