// functional standard header -*-c++-*-
// Copyright 2003-2020 IAR Systems AB. 
#ifndef _DLIB5_FUNCTIONAL_
#define _DLIB5_FUNCTIONAL_

#ifndef _SYSTEM_BUILD
#pragma system_include
#endif

#include <dlib5/xstddef>
#include <dlib5/iutility>

#pragma language=save
#pragma language=extended
_DLIB5_BEGIN

// TEMPLATE STRUCT unary_function
template<class _Arg,
         class _Result>
struct unary_function
{       // base class for unary functions
  typedef _Arg argument_type;
  typedef _Result result_type;
};

// TEMPLATE STRUCT binary_function
template<class _Arg1,
         class _Arg2,
         class _Result>
struct binary_function
{       // base class for binary functions
  typedef _Arg1 first_argument_type;
  typedef _Arg2 second_argument_type;
  typedef _Result result_type;
};

// TEMPLATE STRUCT plus
template<class _Ty>
struct plus
  : public binary_function<_Ty, _Ty, _Ty>
{       // functor for operator+
  typedef typename _TypeUtil::_ParameterType<_Ty>::_Type _ParamTy;

  _Ty operator()(_ParamTy _Left, _ParamTy _Right) const
  {       // apply operator+ to operands
    return (_Left + _Right); 
  }
};

// TEMPLATE STRUCT minus
template<class _Ty>
struct minus
  : public binary_function<_Ty, _Ty, _Ty>
{       // functor for operator-
  typedef typename _TypeUtil::_ParameterType<_Ty>::_Type _ParamTy;

  _Ty operator()(_ParamTy _Left, _ParamTy _Right) const
  {       // apply operator- to operands
    return (_Left - _Right); 
  }
};

// TEMPLATE STRUCT multiplies
template<class _Ty>
struct multiplies
  : public binary_function<_Ty, _Ty, _Ty>
{       // functor for operator*
  typedef typename _TypeUtil::_ParameterType<_Ty>::_Type _ParamTy;

  _Ty operator()(_ParamTy _Left, _ParamTy _Right) const
  {       // apply operator* to operands
    return (_Left * _Right); 
  }
};

// TEMPLATE STRUCT divides
template<class _Ty>
struct divides
  : public binary_function<_Ty, _Ty, _Ty>
{       // functor for operator/
  typedef typename _TypeUtil::_ParameterType<_Ty>::_Type _ParamTy;

  _Ty operator()(_ParamTy _Left, _ParamTy _Right) const
  {       // apply operator/ to operands
    return (_Left / _Right); 
  }
};

// TEMPLATE STRUCT modulus
template<class _Ty>
struct modulus
  : public binary_function<_Ty, _Ty, _Ty>
{       // functor for operator%
  typedef typename _TypeUtil::_ParameterType<_Ty>::_Type _ParamTy;

  _Ty operator()(_ParamTy _Left, _ParamTy _Right) const
  {       // apply operator% to operands
    return (_Left % _Right); 
  }
};

// TEMPLATE STRUCT negate
template<class _Ty>
struct negate
  : public unary_function<_Ty, _Ty>
{       // functor for unary operator-
  typedef typename _TypeUtil::_ParameterType<_Ty>::_Type _ParamTy;

  _Ty operator()(_ParamTy _Left) const
  {       // apply operator- to operand
    return (-_Left); 
  }
};

// TEMPLATE STRUCT equal_to
template<class _Ty>
struct equal_to
  : public binary_function<_Ty, _Ty, bool>
{       // functor for operator==
  typedef typename _TypeUtil::_ParameterType<_Ty>::_Type _ParamTy;

  bool operator()(_ParamTy _Left, _ParamTy _Right) const
  {       // apply operator== to operands
    return (_Left == _Right); 
  }
};

// TEMPLATE STRUCT not_equal_to
template<class _Ty>
struct not_equal_to
  : public binary_function<_Ty, _Ty, bool>
{       // functor for operator!=
  typedef typename _TypeUtil::_ParameterType<_Ty>::_Type _ParamTy;

  bool operator()(_ParamTy _Left, _ParamTy _Right) const
  {       // apply operator= to operands
    return (_Left != _Right); 
  }
};

namespace _PointerCompare
{
  // Get the type to use when comparing two objects of a given type.
  // For everything but pointers, use the types themselves.
  // For pointers, use the correct variant of uintptr_t, to ensure that
  // we compare the entire pointer for __far pointers.
  template<typename _Ty> struct _CompareType
  {
    typedef _Ty _Type;
  };
  #pragma basic_template_matching
  template<typename _Ty> struct _CompareType<_Ty *>
  {
    typedef typename _TypeUtil::_PointerInfo<_Ty *>::_UIntPtrType _Type;
  };
}

// TEMPLATE STRUCT greater
template<class _Ty>
struct greater
  : public binary_function<_Ty, _Ty, bool>
{       // functor for operator>
  typedef typename _TypeUtil::_ParameterType<_Ty>::_Type _ParamTy;

  bool operator()(_ParamTy _Left, _ParamTy _Right) const
  {       // apply operator> to operands
    typedef typename _PointerCompare::_CompareType<_ParamTy>::_Type _CType;
    return ((_CType)(_Left) > (_CType)(_Right)); 
  }
};

// TEMPLATE STRUCT less
template<class _Ty>
struct less
  : public binary_function<_Ty, _Ty, bool>
{       // functor for operator<
  typedef typename _TypeUtil::_ParameterType<_Ty>::_Type _ParamTy;

  bool operator()(_ParamTy _Left, _ParamTy _Right) const
  {       // apply operator< to operands
    typedef typename _PointerCompare::_CompareType<_ParamTy>::_Type _CType;
    return ((_CType)_Left < (_CType)_Right); 
  }
};

// TEMPLATE STRUCT greater_equal
template<class _Ty>
struct greater_equal
  : public binary_function<_Ty, _Ty, bool>
{       // functor for operator>=
  typedef typename _TypeUtil::_ParameterType<_Ty>::_Type _ParamTy;

  bool operator()(_ParamTy _Left, _ParamTy _Right) const
  {       // apply operator>= to operands
    typedef typename _PointerCompare::_CompareType<_ParamTy>::_Type _CType;
    return ((_CType)_Left >= (_CType)_Right); 
  }
};

// TEMPLATE STRUCT less_equal
template<class _Ty>
struct less_equal
  : public binary_function<_Ty, _Ty, bool>
{       // functor for operator<=
  typedef typename _TypeUtil::_ParameterType<_Ty>::_Type _ParamTy;

  bool operator()(_ParamTy _Left, _ParamTy _Right) const
  {       // apply operator<= to operands
    typedef typename _PointerCompare::_CompareType<_ParamTy>::_Type _CType;
    return ((_CType)_Left <= (_CType)_Right); 
  }
};

// TEMPLATE STRUCT logical_and
template<class _Ty>
struct logical_and
  : public binary_function<_Ty, _Ty, bool>
{       // functor for operator&&
  typedef typename _TypeUtil::_ParameterType<_Ty>::_Type _ParamTy;

  bool operator()(_ParamTy _Left, _ParamTy _Right) const
  {       // apply operator&& to operands
    return (_Left && _Right); 
  }
};

// TEMPLATE STRUCT logical_or
template<class _Ty>
struct logical_or
  : public binary_function<_Ty, _Ty, bool>
{       // functor for operator||
  typedef typename _TypeUtil::_ParameterType<_Ty>::_Type _ParamTy;

  bool operator()(_ParamTy _Left, _ParamTy _Right) const
  {       // apply operator|| to operands
    return (_Left || _Right); 
  }
};

// TEMPLATE STRUCT logical_not
template<class _Ty>
struct logical_not
  : public unary_function<_Ty, bool>
{       // functor for unary operator!
  typedef typename _TypeUtil::_ParameterType<_Ty>::_Type _ParamTy;

  bool operator()(_ParamTy _Left) const
  {       // apply operator! to operand
    return (!_Left); 
  }
};

// TEMPLATE CLASS unary_negate
template<class _Fn1>
class unary_negate
: public unary_function<typename _Fn1::argument_type, bool>
{       // functor adapter !_Func(left)
public:
  explicit unary_negate(const _Fn1& _Func)
    : _Functor(_Func)
  {}      // construct from functor

  bool operator()(const typename _Fn1::argument_type& _Left) const
  {       // apply functor to operand
    return (!_Functor(_Left)); 
  }

protected:
  _Fn1 _Functor;  // the functor to apply
};

// TEMPLATE FUNCTION not1
template<class _Fn1> inline
unary_negate<_Fn1> not1(const _Fn1& _Func)
{       // return a unary_negate functor adapter
  return (_DLIB5 unary_negate<_Fn1>(_Func)); 
}

// TEMPLATE CLASS binary_negate
template<class _Fn2>
class binary_negate
: public binary_function<typename _Fn2::first_argument_type,
  typename _Fn2::second_argument_type, bool>
{       // functor adapter !_Func(left, right)
public:
  explicit binary_negate(const _Fn2& _Func)
    : _Functor(_Func)
  {}      // construct from functor

  bool operator()(const typename _Fn2::first_argument_type& _Left,
                  const typename _Fn2::second_argument_type& _Right) const
  {       // apply functor to operands
      return (!_Functor(_Left, _Right)); 
  }

protected:
  _Fn2 _Functor;  // the functor to apply
};

// TEMPLATE FUNCTION not2
template<class _Fn2> inline
binary_negate<_Fn2> not2(const _Fn2& _Func)
{       // return a binary_negate functor adapter
  return (_DLIB5 binary_negate<_Fn2>(_Func)); 
}

// TEMPLATE CLASS binder1st
template<class _Fn2>
class binder1st
: public unary_function<typename _Fn2::second_argument_type,
  typename _Fn2::result_type>
{       // functor adapter _Func(stored, right)
public:
  typedef unary_function<typename _Fn2::second_argument_type,
    typename _Fn2::result_type> _Base;
  typedef typename _Base::argument_type argument_type;
  typedef typename _Base::result_type result_type;
  typedef typename _TypeUtil::_ParameterType<argument_type>::_Type _ParamTy;

  binder1st(const _Fn2& _Func,
            const typename _Fn2::first_argument_type& _Left)
    : op(_Func), value(_Left)
  {}      // construct from functor and left operand

  result_type operator()(_ParamTy _Right) const
  {       // apply functor to operands
      return (op(value, _Right)); 
  }

protected:
  _Fn2 op;        // the functor to apply
  typename _Fn2::first_argument_type value;       // the left operand
};

// TEMPLATE FUNCTION bind1st
template<class _Fn2,
         class _Ty> inline
binder1st<_Fn2> bind1st(const _Fn2& _Func, const _Ty& _Left)
{       // return a binder1st functor adapter
  typename _Fn2::first_argument_type _Val(_Left);
  return (_DLIB5 binder1st<_Fn2>(_Func, _Val)); 
}

// TEMPLATE CLASS binder2nd
template<class _Fn2>
class binder2nd
: public unary_function<typename _Fn2::first_argument_type,
  typename _Fn2::result_type>
{       // functor adapter _Func(left, stored)
public:
  typedef unary_function<typename _Fn2::first_argument_type,
    typename _Fn2::result_type> _Base;
  typedef typename _Base::argument_type argument_type;
  typedef typename _Base::result_type result_type;
  typedef typename _TypeUtil::_ParameterType<argument_type>::_Type _ParamTy;

  binder2nd(const _Fn2& _Func,
            const typename _Fn2::second_argument_type& _Right)
    : op(_Func), value(_Right)
  {}      // construct from functor and right operand

  result_type operator()(_ParamTy _Left) const
  {       // apply functor to operands
      return (op(_Left, value)); 
  }

protected:
  _Fn2 op;        // the functor to apply
  typename _Fn2::second_argument_type value;      // the right operand
};

// TEMPLATE FUNCTION bind2nd
template<class _Fn2,
         class _Ty> inline
binder2nd<_Fn2> bind2nd(const _Fn2& _Func, const _Ty& _Right)
{       // return a binder2nd functor adapter
  typename _Fn2::second_argument_type _Val(_Right);
  return (_DLIB5 binder2nd<_Fn2>(_Func, _Val)); 
}

// TEMPLATE CLASS pointer_to_unary_function
template<class _Arg,
         class _Result>
class pointer_to_unary_function
: public unary_function<_Arg, _Result>
{       // functor adapter (*pfunc)(left)
 public:
  explicit pointer_to_unary_function(_Result (*_Left)(_Arg))
    : _Pfun(_Left)
  {}      // construct from pointer

  _Result operator()(_Arg _Left) const
  {       // call function with operand
      return (_Pfun(_Left)); 
  }

protected:
  _Result (*_Pfun)(_Arg); // the function pointer
};

// TEMPLATE CLASS pointer_to_binary_function
template<class _Arg1,
         class _Arg2,
         class _Result>
class pointer_to_binary_function
: public binary_function<_Arg1, _Arg2, _Result>
{       // functor adapter (*pfunc)(left, right)
public:
  explicit pointer_to_binary_function(
    _Result (*_Left)(_Arg1, _Arg2))
    : _Pfun(_Left)
  {}      // construct from pointer

  _Result operator()(_Arg1 _Left, _Arg2 _Right) const
  {       // call function with operands
      return (_Pfun(_Left, _Right)); 
  }

protected:
  _Result (*_Pfun)(_Arg1, _Arg2); // the function pointer
};

// TEMPLATE FUNCTION ptr_fun
template<class _Arg,
         class _Result> inline
pointer_to_unary_function<_Arg, _Result>
ptr_fun(_Result (*_Left)(_Arg))
{       // return pointer_to_unary_function functor adapter
  return (_DLIB5 pointer_to_unary_function<_Arg, _Result>(_Left)); 
}

template<class _Arg1,
         class _Arg2,
         class _Result> inline
pointer_to_binary_function<_Arg1, _Arg2, _Result>
ptr_fun(_Result (*_Left)(_Arg1, _Arg2))
{       // return pointer_to_binary_function functor adapter
  return (_DLIB5 pointer_to_binary_function<_Arg1, _Arg2, _Result>(_Left)); 
}

// TEMPLATE CLASS mem_fun_t
template<class _Result,
         class _Ty>
class mem_fun_t
: public unary_function<_Ty *, _Result>
{       // functor adapter (*p->*pfunc)(), non-const *pfunc
public:
  explicit mem_fun_t(_Result (_Ty::*_Pm)())
    : _Pmemfun(_Pm)
  {}      // construct from pointer

  _Result operator()(_Ty *_Pleft) const
   {       // call function
      return ((_Pleft->*_Pmemfun)()); 
   }

private:
  _Result (_Ty::*_Pmemfun)();     // the member function pointer
};

// TEMPLATE CLASS mem_fun1_t
template<class _Result,
         class _Ty,
         class _Arg>
class mem_fun1_t
: public binary_function<_Ty *, _Arg, _Result>
{       // functor adapter (*p->*pfunc)(val), non-const *pfunc
public:
  explicit mem_fun1_t(_Result (_Ty::*_Pm)(_Arg))
    : _Pmemfun(_Pm)
  {}      // construct from pointer

  _Result operator()(_Ty *_Pleft, _Arg _Right) const
  {       // call function with operand
    return ((_Pleft->*_Pmemfun)(_Right)); 
  }

private:
  _Result (_Ty::*_Pmemfun)(_Arg); // the member function pointer
};

// TEMPLATE CLASS const_mem_fun_t
template<class _Result,
         class _Ty>
class const_mem_fun_t
: public unary_function<const _Ty *, _Result>
{       // functor adapter (*p->*pfunc)(), const *pfunc
public:
  explicit const_mem_fun_t(_Result (_Ty::*_Pm)() const)
    : _Pmemfun(_Pm)
  {}      // construct from pointer

  _Result operator()(const _Ty *_Pleft) const
  {       // call function
    return ((_Pleft->*_Pmemfun)()); 
  }

private:
  _Result (_Ty::*_Pmemfun)() const;       // the member function pointer
};

// TEMPLATE CLASS const_mem_fun1_t
template<class _Result,
         class _Ty,
         class _Arg>
class const_mem_fun1_t
                : public binary_function<const _Ty *, _Arg, _Result>
{       // functor adapter (*p->*pfunc)(val), const *pfunc
public:
  explicit const_mem_fun1_t(_Result (_Ty::*_Pm)(_Arg) const)
    : _Pmemfun(_Pm)
  {}      // construct from pointer

  _Result operator()(const _Ty *_Pleft, _Arg _Right) const
  {       // call function with operand
    return ((_Pleft->*_Pmemfun)(_Right)); 
  }

private:
  _Result (_Ty::*_Pmemfun)(_Arg) const;   // the member function pointer
};

// TEMPLATE FUNCTION mem_fun
template<class _Result,
         class _Ty> inline
mem_fun_t<_Result, _Ty> mem_fun(_Result (_Ty::*_Pm)())
{       // return a mem_fun_t functor adapter
  return (_DLIB5 mem_fun_t<_Result, _Ty>(_Pm)); 
}

template<class _Result,
         class _Ty,
         class _Arg> inline
mem_fun1_t<_Result, _Ty, _Arg> mem_fun(_Result (_Ty::*_Pm)(_Arg))
{       // return a mem_fun1_t functor adapter
  return (_DLIB5 mem_fun1_t<_Result, _Ty, _Arg>(_Pm)); 
}

template<class _Result,
         class _Ty> inline
const_mem_fun_t<_Result, _Ty>
mem_fun(_Result (_Ty::*_Pm)() const)
{       // return a const_mem_fun_t functor adapter
  return (_DLIB5 const_mem_fun_t<_Result, _Ty>(_Pm)); 
}

template<class _Result,
         class _Ty,
         class _Arg> inline
const_mem_fun1_t<_Result, _Ty, _Arg>
mem_fun(_Result (_Ty::*_Pm)(_Arg) const)
{       // return a const_mem_fun1_t functor adapter
  return (_DLIB5 const_mem_fun1_t<_Result, _Ty, _Arg>(_Pm)); 
}

// TEMPLATE FUNCTION mem_fun1 (retained)
template<class _Result,
         class _Ty,
         class _Arg> inline
mem_fun1_t<_Result, _Ty, _Arg> mem_fun1(_Result (_Ty::*_Pm)(_Arg))
{       // return a mem_fun1_t functor adapter 
  return (_DLIB5 mem_fun1_t<_Result, _Ty, _Arg>(_Pm)); 
}

// TEMPLATE CLASS mem_fun_ref_t
template<class _Result,
         class _Ty>
class mem_fun_ref_t
: public unary_function<_Ty, _Result>
{       // functor adapter (*left.*pfunc)(), non-const *pfunc
public:
  explicit mem_fun_ref_t(_Result (_Ty::*_Pm)())
    : _Pmemfun(_Pm)
  {}      // construct from pointer

  _Result operator()(_Ty& _Left) const
  {       // call function
    return ((_Left.*_Pmemfun)()); 
  }

private:
  _Result (_Ty::*_Pmemfun)();     // the member function pointer
};

// TEMPLATE CLASS mem_fun1_ref_t
template<class _Result,
         class _Ty,
         class _Arg>
class mem_fun1_ref_t
: public binary_function<_Ty, _Arg, _Result>
{       // functor adapter (*left.*pfunc)(val), non-const *pfunc
public:
  explicit mem_fun1_ref_t(_Result (_Ty::*_Pm)(_Arg))
    : _Pmemfun(_Pm)
  {}      // construct from pointer

  _Result operator()(_Ty& _Left, _Arg _Right) const
  {       // call function with operand
    return ((_Left.*_Pmemfun)(_Right)); 
  }

private:
  _Result (_Ty::*_Pmemfun)(_Arg); // the member function pointer
};

// TEMPLATE CLASS const_mem_fun_ref_t
template<class _Result,
         class _Ty>
class const_mem_fun_ref_t
: public unary_function<_Ty, _Result>
{       // functor adapter (*left.*pfunc)(), const *pfunc
public:
  explicit const_mem_fun_ref_t(_Result (_Ty::*_Pm)() const)
    : _Pmemfun(_Pm)
  {}      // construct from pointer

  _Result operator()(const _Ty& _Left) const
  {       // call function
    return ((_Left.*_Pmemfun)()); 
  }

private:
  _Result (_Ty::*_Pmemfun)() const;       // the member function pointer
};

// TEMPLATE CLASS const_mem_fun1_ref_t
template<class _Result,
         class _Ty,
         class _Arg>
class const_mem_fun1_ref_t
: public binary_function<_Ty, _Arg, _Result>
{       // functor adapter (*left.*pfunc)(val), const *pfunc
public:
  explicit const_mem_fun1_ref_t(_Result (_Ty::*_Pm)(_Arg) const)
    : _Pmemfun(_Pm)
  {}      // construct from pointer

  _Result operator()(const _Ty& _Left, _Arg _Right) const
  {       // call function with operand
    return ((_Left.*_Pmemfun)(_Right)); 
  }

private:
  _Result (_Ty::*_Pmemfun)(_Arg) const;   // the member function pointer
};

// TEMPLATE FUNCTION mem_fun_ref
template<class _Result,
         class _Ty> inline
mem_fun_ref_t<_Result, _Ty> mem_fun_ref(_Result (_Ty::*_Pm)())
{       // return a mem_fun_ref_t functor adapter
  return (_DLIB5 mem_fun_ref_t<_Result, _Ty>(_Pm)); 
}

template<class _Result,
         class _Ty,
         class _Arg> inline
mem_fun1_ref_t<_Result, _Ty, _Arg>
mem_fun_ref(_Result (_Ty::*_Pm)(_Arg))
{       // return a mem_fun1_ref_t functor adapter
  return (_DLIB5 mem_fun1_ref_t<_Result, _Ty, _Arg>(_Pm)); 
}

template<class _Result,
         class _Ty> inline
const_mem_fun_ref_t<_Result, _Ty>
mem_fun_ref(_Result (_Ty::*_Pm)() const)
{       // return a const_mem_fun_ref_t functor adapter
  return (_DLIB5 const_mem_fun_ref_t<_Result, _Ty>(_Pm)); 
}

template<class _Result,
         class _Ty,
         class _Arg> inline
const_mem_fun1_ref_t<_Result, _Ty, _Arg>
mem_fun_ref(_Result (_Ty::*_Pm)(_Arg) const)
{       // return a const_mem_fun1_ref_t functor adapter
  return (_DLIB5 const_mem_fun1_ref_t<_Result, _Ty, _Arg>(_Pm)); 
}

// TEMPLATE FUNCTION mem_fun1_ref (retained)
template<class _Result,
         class _Ty,
         class _Arg> inline
mem_fun1_ref_t<_Result, _Ty, _Arg> mem_fun1_ref(_Result (_Ty::*_Pm)(_Arg))
{       // return a mem_fun1_ref_t functor adapter
  return (_DLIB5 mem_fun1_ref_t<_Result, _Ty, _Arg>(_Pm)); 
}

_DLIB5_END

#pragma language=restore

#endif /* _FUNCTIONAL_ */

/*
 * This file is derived from software bearing the following
 * restrictions:
 *
 * Copyright (c) 1994
 * Hewlett-Packard Company
 *
 * Permission to use, copy, modify, distribute and sell this
 * software and its documentation for any purpose is hereby
 * granted without fee, provided that the above copyright notice
 * appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation.
 * Hewlett-Packard Company makes no representations about the
 * suitability of this software for any purpose. It is provided
 * "as is" without express or implied warranty.
 */

/*
 * Copyright (c) 1992-2009 by P.J. Plauger.  ALL RIGHTS RESERVED.
 * Consult your license regarding permissions and restrictions.
 V5.04:0576 */
