/* Copyright (C) 2009 and 2014 Chris Vine

The library comprised in this file or of which this file is part is
distributed by Chris Vine under the GNU Lesser General Public
License as follows:

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public License
   as published by the Free Software Foundation; either version 2.1 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
   Lesser General Public License, version 2.1, for more details.

   You should have received a copy of the GNU Lesser General Public
   License, version 2.1, along with this library (see the file LGPL.TXT
   which came with this source code package in the c++-gtk-utils
   sub-directory); if not, write to the Free Software Foundation, Inc.,
   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

However, it is not intended that the object code of a program whose
source code instantiates a template from this file or uses macros or
inline functions (of any length) should by reason only of that
instantiation or use be subject to the restrictions of use in the GNU
Lesser General Public License.  With that in mind, the words "and
macros, inline functions and instantiations of templates (of any
length)" shall be treated as substituted for the words "and small
macros and small inline functions (ten lines or less in length)" in
the fourth paragraph of section 5 of that licence.  This does not
affect any other reason why object code may be subject to the
restrictions in that licence (nor for the avoidance of doubt does it
affect the application of section 2 of that licence to modifications
of the source code in this file).

*/

#ifndef CGU_MEM_FUN_H
#define CGU_MEM_FUN_H

/**
 * @file mem_fun.h
 * @brief This file contains an adaptor to create a functor from a
 * class member function to pass to C++ standard algorithms.
 *
 * \#include <c++-gtk-utils/mem_fun.h>
 *
 * Cgu::MemFun::make() is provided in order to provide source
 * compatibility with the 1.2 series of the library.  In C++11/14 it
 * is superseded by std::mem_fn() and std::bind.
 *
 * Cgu::MemFun::make() is an adaptor which allows a non-static class
 * member function to be called by standard algorithms such as
 * std::for_each() or std::transform(), whereby the member function is
 * passed a contained object as an argument on iterating through the
 * container.  It can also be used to make predicates from member
 * functions to pass to other algorithms, or indeed to generate a
 * general functor object representing a member function with object
 * and one or two arguments.  It does the equivalent of std::ptr_fun()
 * for ordinary functions.
 *
 * For example, to iterate over a std::vector<int> container object
 * named 'vec', calling a class method 'void MyObj::my_method(int)' on
 * each iteration, Cgu::MemFun::make() could be invoked as:
 *
 * @code 
 * using namespace Cgu;
 * std::for_each(vec.begin(), vec.end(),
 *               MemFun::make(my_obj, &MyObj::my_method));
 * @endcode 
 *
 * As in the case of std::ptr_fun(), when called via std::for_each(),
 * the member function called must be a unary function, although an
 * additional argument can be bound with std::bind2nd() or
 * std::bind1st() to enable it to be used with binary class functions.
 * (Note that in many implementations of std::bind1st/2nd, neither the
 * free nor the bound argument can be a reference, whether const or
 * non-const.  A reference argument can be employed with
 * Cgu::MemFun::make() where std::bind1st/2nd is not used.)  This
 * limitation with respect to reference arguments is not present with
 * std::mem_fn() and std::bind.
 *
 * In C++11/14, the above example could be reproduced as:
 *
 * @code
 * using namespace std::placeholders;  // for _1
 * std::for_each(vec.begin(), vec.end(),
 *               std::bind(&MyObj::my_method, &my_obj, _1));
 * @endcode 
 */

/**
 * @namespace Cgu::MemFun
 * @brief This namespace contains an adaptor to create a functor from a
 * class member function to pass to C++ standard algorithms.
 *
 * \#include <c++-gtk-utils/mem_fun.h>
 *
 * Cgu::MemFun::make() is provided in order to provide source
 * compatibility with the 1.2 series of the library.  In C++11/14 it
 * is superseded by std::mem_fn() and std::bind.
 *
 * Cgu::MemFun::make() is an adaptor which allows a non-static class
 * member function to be called by standard algorithms such as
 * std::for_each() or std::transform(), whereby the member function is
 * passed a contained object as an argument on iterating through the
 * container.  It can also be used to make predicates from member
 * functions to pass to other algorithms, or indeed to generate a
 * general functor object representing a member function with object
 * and one or two arguments.  It does the equivalent of std::ptr_fun()
 * for ordinary functions.
 *
 * For example, to iterate over a std::vector<int> container object
 * named 'vec', calling a class method 'void MyObj::my_method(int)' on
 * each iteration, Cgu::MemFun::make() could be invoked as:
 *
 * @code 
 * using namespace Cgu;
 * std::for_each(vec.begin(), vec.end(),
 *               MemFun::make(my_obj, &MyObj::my_method));
 * @endcode 
 *
 * As in the case of std::ptr_fun(), when called via std::for_each(),
 * the member function called must be a unary function, although an
 * additional argument can be bound with std::bind2nd() or
 * std::bind1st() to enable it to be used with binary class functions.
 * (Note that in many implementations of std::bind1st/2nd, neither the
 * free nor the bound argument can be a reference, whether const or
 * non-const.  A reference argument can be employed with
 * Cgu::MemFun::make() where std::bind1st/2nd is not used.)  This
 * limitation with respect to reference arguments is not present with
 * std::mem_fn() and std::bind.
 *
 * In C++11/14, the above example could be reproduced as:
 *
 * @code
 * using namespace std::placeholders;  // for _1
 * std::for_each(vec.begin(), vec.end(),
 *               std::bind(&MyObj::my_method, &my_obj, _1));
 * @endcode 
 */

#include <functional>
#include <c++-gtk-utils/cgu_config.h>

namespace Cgu {

namespace MemFun {

template <class Ret, class Arg, class T>
class Functor1: public std::unary_function<Arg, Ret> {
  T* obj;
  Ret (T::*func)(Arg);
public:
  Ret operator()(Arg arg) const {return (obj->*func)(arg);}
  Functor1(T& obj_, Ret (T::*func_)(Arg)): obj(&obj_), func(func_) {}
};

template <class Ret, class Arg, class T>
Functor1<Ret, Arg, T> make(T& t,
			   Ret (T::*func)(Arg)) {
  return Functor1<Ret, Arg, T>(t, func);
}

/* const version, for binding to const methods */

template <class Ret, class Arg, class T>
class Functor1_const: public std::unary_function<Arg, Ret> {
  const T* obj;
  Ret (T::*func)(Arg) const;
public:
  Ret operator()(Arg arg) const {return (obj->*func)(arg);}
  Functor1_const(const T& obj_, Ret (T::*func_)(Arg) const): obj(&obj_), func(func_) {}
};

template <class Ret, class Arg, class T>
Functor1_const<Ret, Arg, T> make(const T& t,
				 Ret (T::*func)(Arg) const) {
  return Functor1_const<Ret, Arg, T>(t, func);
}

/* two argument version for use with std::bind* */

template <class Ret, class Arg1, class Arg2, class T>
class Functor2: public std::binary_function<Arg1, Arg2, Ret> {
  T* obj;
  Ret (T::*func)(Arg1, Arg2);
public:
  Ret operator()(Arg1 arg1, Arg2 arg2) const {return (obj->*func)(arg1, arg2);}
  Functor2(T& obj_, Ret (T::*func_)(Arg1, Arg2)): obj(&obj_), func(func_) {}
};

template <class Ret, class Arg1, class Arg2, class T>
Functor2<Ret, Arg1, Arg2, T> make(T& t,
				  Ret (T::*func)(Arg1, Arg2)) {
  return Functor2<Ret, Arg1, Arg2, T>(t, func);
}

/* const version, for binding to const methods */

template <class Ret, class Arg1, class Arg2, class T>
class Functor2_const: public std::binary_function<Arg1, Arg2, Ret> {
  const T* obj;
  Ret (T::*func)(Arg1, Arg2) const;
public:
  Ret operator()(Arg1 arg1, Arg2 arg2) const {return (obj->*func)(arg1, arg2);}
  Functor2_const(const T& obj_, Ret (T::*func_)(Arg1, Arg2) const): obj(&obj_), func(func_) {}
};

template <class Ret, class Arg1, class Arg2, class T>
Functor2_const<Ret, Arg1, Arg2, T> make(const T& t,
					Ret (T::*func)(Arg1, Arg2) const) {
  return Functor2_const<Ret, Arg1, Arg2, T>(t, func);
}

} // namespace MemFun

} // namespace Cgu

#endif
