// lib/prec_stl/functional

#pragma ifndef PREC_STL_FUNCTIONAL
#pragma define PREC_STL_FUNCTIONAL
#pragma link off global PREC_STL_FUNCTIONAL;
#pragma link C++ nestedtypedef;
#pragma link C++ nestedclass;

// Implemented by Scott Snyder, Fermi-lab

// clause _lib.base_, 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;
};


// clause _lib.arithmetic.operations_, arithmetic operations:
template <class T> struct plus : binary_function<T,T,T> {
  T operator()(const T& x, const T& y) const;
};


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


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


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

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

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


// clause _lib.comparisons_, comparisons:
template <class T> struct equal_to : binary_function<T,T,bool> {
  bool operator()(const T& x, const T& y) const;
};

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

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

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

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

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


// clause _lib.logical.operations_, logical operations:
template <class T> struct logical_and : binary_function<T,T,bool> {
  bool operator()(const T& x, const T& y) const;
};

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

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


// clause _lib.negators_, negators:
template <class Predicate>
class unary_negate
  : public unary_function<Predicate::argument_type, bool>
{
public:
  explicit unary_negate(const Predicate& pred);
  bool operator()(const argument_type& x) const;
};

#if 0
template <class Predicate>
  unary_negate<Predicate> not1(const Predicate& pred);
#endif

template <class Predicate>
class binary_negate
  : public binary_function<Predicate::first_argument_type,
                           Predicate::second_argument_type, bool>
{
public:
  explicit binary_negate(const Predicate& pred);
  bool operator()(const first_argument_type&  x,
                  const second_argument_type& y) const;
};

// operations omitted (cint can't handle template forward decls...)
#if 0
template <class Predicate>
  binary_negate<Predicate> not2(const Predicate& pred);
#endif



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


// operations omitted (cint can't handle template forward decls...)
#if 0
template <class Operation, class T>
  binder1st<Operation> bind1st(const Operation&, const T&);
#endif

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


// operations omitted (cint can't handle template forward decls...)
#if 0
template <class Operation, class T>
  binder2nd<Operation> bind2nd(const Operation&, const T&);
#endif


// clause _lib.function.pointer.adaptors_, adaptors:
template <class Arg, class Result>
class pointer_to_unary_function
  : public unary_function<Arg, Result>
{
public:
  explicit pointer_to_unary_function(Result (*f)(Arg));
  Result operator()(Arg x) const;
};

// operations omitted (cint can't handle template forward decls...)
#if 0
template <class Arg, class Result>
  pointer_to_unary_function<Arg,Result> ptr_fun(Result (*)(Arg));
#endif

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 (*f)(Arg1, Arg2));
  Result operator()(Arg1 x, Arg2 y) const;
};

// operations omitted (cint can't handle template forward decls...)
#if 0
template <class Arg1, class Arg2, class Result>
  pointer_to_binary_function<Arg1,Arg2,Result> ptr_fun(Result (*)(Arg1,Arg2));
#endif


// omit these for now.
#if 0
// clause _lib.member.pointer.adaptors_, adaptors:
template<class S, class T> class mem_fun_t;
template<class S, class T, class A> class mem_fun1_t;
template<class S, class T>
    mem_fun_t<S,T> mem_fun(S (T::*f)());
template<class S, class T, class A>
    mem_fun1_t<S,T,A> mem_fun1(S (T::*f)(A));
template<class S, class T> class mem_fun_ref_t;
template<class S, class T, class A> class mem_fun1_ref_t;
template<class S, class T>
    mem_fun_ref_t<S,T> mem_fun_ref(S (T::*f)());
template<class S, class T, class A>
    mem_fun1_ref_t<S,T,A> mem_fun1_ref(S (T::*f)(A));
#endif

#pragma endif
