// **********************************************************************
//
// Copyright (c) 2002
// IONA Technologies, Inc.
// Waltham, MA, USA
//
// All Rights Reserved
//
// **********************************************************************


#ifndef OB_FUNCTION_H
#define OB_FUNCTION_H

#include <OB/STLConfig.h>

namespace OB
{

namespace stl
{

template<class Arg, class Result>
class unary_function
{
public:
    typedef Arg    argument_type;
    typedef Result result_type;
};

template<class UnaryPredicate>
class unary_negate :
        public unary_function<typename UnaryPredicate::argument_type,
                              bool>
{
    UnaryPredicate pred_;
    
public:
    unary_negate(const UnaryPredicate& pred)
        : pred_(pred) {}
    
    bool operator()(typename UnaryPredicate::argument_type arg)
    {
        return !pred_(arg);
    }
};

template<class UnaryPredicate>
unary_negate<UnaryPredicate> not1(UnaryPredicate pred)
{
    return unary_negate<UnaryPredicate>(pred);
}

template<class Arg1, class Arg2, class Result>
class binary_function
{
public:
    typedef Arg1   first_argument_type;
    typedef Arg2   second_argument_type;
    typedef Result result_type;
};

template<class BinaryPredicate>
class binary_negate :
        public binary_function<typename BinaryPredicate::first_argument_type,
                               typename BinaryPredicate::second_argument_type,
                               bool>
{
    BinaryPredicate pred_;
    
public:
    binary_negate(const BinaryPredicate& pred)
        : pred_(pred) {}
    
    bool operator()(typename BinaryPredicate::first_argument_type arg1,
                    typename BinaryPredicate::second_argument_type arg2)
    {
        return !pred_(arg1, arg2);
    }
};

template<class BinaryPredicate>
binary_negate<BinaryPredicate> not2(BinaryPredicate pred)
{
    return binary_negate<BinaryPredicate>(pred);
}

template<class R, class X>
class mem_fun_t : public unary_function<X*, R>
{
    R (X::*f_)();

public:
    explicit mem_fun_t(R (X::*f)()) : f_(f)
    {
    }

    R operator()(X* x) const
    {
        x -> f_();
    }
};

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

template<class R, class X, class A>
class mem_fun1_t : public binary_function<X*, A, R>
{
    R (X::*f_)(A);

public:
    explicit mem_fun1_t(R (X::*f)(A)) : f_(f)
    {
    }

    R operator()(X* x, A a) const
    {
        x -> f_();
    }
};

template<class R, class X, class A>
mem_fun1_t<R, X, A> mem_fun1(R (X::*f)(A))
{
    return mem_fun1_t<R, X, A>(f);
}

template<class BinaryFun>
class binder1st :
    public unary_function<typename BinaryFun::second_argument_type,
                          typename BinaryFun::result_type>
{
    BinaryFun& f_;
    typename BinaryFun::first_argument_type c_;
    
public:
    binder1st(BinaryFun& f, typename BinaryFun::first_argument_type c)
        : f_(f), c_(c)
    {
    }
    
    typename BinaryFun::result_type
    operator()(const typename BinaryFun::second_argument_type& x) const
    {
        return f_(c_, x);
    }
};

template<class BinaryFun, class T>
binder1st<BinaryFun> bind1st(const BinaryFun& f, const T& c)
{
    return binder1st<BinaryFun>(f, c);
}

template<class BinaryFun>
class binder2nd :
    public unary_function<typename BinaryFun::first_argument_type,
                          typename BinaryFun::result_type>
{
    BinaryFun& f_;
    typename BinaryFun::second_argument_type c_;
    
public:
    binder2nd(BinaryFun& f, typename BinaryFun::second_argument_type c)
        : f_(f), c_(c)
    {
    }
    
    typename BinaryFun::result_type
    operator()(const typename BinaryFun::first_argument_type& x) const
    {
        return f_(x, c_);
    }
};

template<class BinaryFun, class T>
binder2nd<BinaryFun> bind2nd(const BinaryFun& f, const T& c)
{
    return binder2nd<BinaryFun>(f, c);
}

} // End namespace stl

} // End namespace OB

#endif
