/*************************************************************************
* File: function.hh
* Author: Keith Schwarz (htiek@cs.stanford.edu)
*
* A class that can hold a reference to any unary function, whether that
* function is a true C++ function or a functor (a class overloading
* operator()). The class is implemented using a trick called external
* polymorphism. Internally, the class stores a pointer to a polymorphic
* class that exports a function called execute. When the Function is
* assigned a value, it wraps that value up in a wrapper subclass of
* the polymorphic class. In this way, the Function object has type-safe
* access to the function, since no matter what the actual type of the
* function is, Function always sees it through the polymorphic wrapper.
*/
#ifndef Function_Included
#define Function_Included
/* This type is parameterized over its argument and return types. It is
* expected that one will treat these types as if one were writing a true
* function, so the argument type should be a reference-to-const where
* appropriate, etc. For example, one could write
*
* Function<int, void> f = MyFunction;
*
* This would declare an object called f that takes in an int, returns
* void, and which refers to a function MyFunction. If we call f, as
* shown here:
*
* f(137);
*
* This will then call MyFunction, passing in 137.
*/
template <typename ArgType, typename ReturnType>
class Function {
public:
/* Constructor: Function(UnaryFunction function);
* Usage: Function<int, int> myFunction = SomeFunction;
* ----------------------------------------------------------------------
* Constructs a new Function object that wraps the specified unary
* function. It is assumed that the function can be called with ArgType
* as its argument type and ReturnType as its return type; if this is
* not the case, the program will fail to compile.
*/
template <typename UnaryFunction> Function(UnaryFunction);
/* Destructor: ~Function();
* Usage: (implicit)
* ----------------------------------------------------------------------
* Deallocates all memory allocated by this Function object.
*/
~Function();
/* Copy functions: Function(const Function& other);
* Function& operator= (const Function& other);
* ----------------------------------------------------------------------
* Creates a new Function object that is a copy of an existing Function,
* or overwrites this Function object with a copy of some other Function.
*/
Function(const Function& other);
Function& operator= (const Function& other);
/* Function call operator: ReturnType operator() (ArgType value) const;
* Usage: f(137);
* ----------------------------------------------------------------------
* Invokes the function wrapped by this Function object, passing in the
* specified parameter and returning the result of the call.
*/
ReturnType operator() (ArgType value) const;
private:
/* Base class which represents some function that can be called with an ArgType
* that returns a ReturnType. ArbitraryFunctions can also be deep-copied using
* the clone() function.
*
* ArbitraryFunction is an abstract class since there is no good default
* implementation for any of its member functions.
*/
class ArbitraryFunction {
public:
/* Polymorphic classes need virtual destructors. */
virtual ~ArbitraryFunction() {}
/* execute calls the stored function and returns its return value. */
virtual ReturnType execute(ArgType param) const = 0;
/* clone returns a deep-copy of the receiver object. */
virtual ArbitraryFunction* clone() const = 0;
};
/* For any type of unary function, we define a subclass of ArbitraryFunction
* which wraps that object so it can be called through the ArbitraryFunction
* interface.
*/
template <typename UnaryFunction>
class SpecificFunction: public ArbitraryFunction {
public:
/* Constructor accepts and stores a UnaryFunction. */
explicit SpecificFunction(UnaryFunction fn) : function(fn) {}
/* execute just calls down to the function. */
virtual ReturnType execute(ArgType param) const {
return function(param);
}
/* Clone returns a deep-copy of this object. */
virtual ArbitraryFunction* clone() const {
return new SpecificFunction(*this);
}
private:
/* The actual function that gets called. */
UnaryFunction function;
};
/* This pointer to an ArbitraryFunction is the real implementation of the Function
* class. Whatever function clients provide to Function is stored in a wrapped
* form here.
*/
ArbitraryFunction* function;
/* Utility functions used to implement the copy functions. Clear deallocates all
* resources allocated by this object; copyOther makes this object a deep-copy of
* some other object.
*/
void clear();
void copyOther(const Function& other);
};
/* Constructor accepts a UnaryFunction of the proper type, then wraps it inside a
* SpecificFunction wrapper. Note that there are two template headers here since
* the class and constructor are both templates.
*/
template <typename ArgType, typename ReturnType>
template <typename UnaryFunction>
Function<ArgType, ReturnType>::Function(UnaryFunction fn) {
function = new SpecificFunction<UnaryFunction>(fn);
}
/* Destructor calls clear. */
template <typename ArgType, typename ReturnType>
Function<ArgType, ReturnType>::~Function() {
clear();
}
/* Copy ctor calls copyOther. */
template <typename ArgType, typename ReturnType>
Function<ArgType, ReturnType>::Function(const Function& other) {
copyOther(other);
}
/* Standard assignment operator. */
template <typename ArgType, typename ReturnType>
Function<ArgType, ReturnType>&
Function<ArgType, ReturnType>::operator=(const Function& other) {
if(this != &other) {
clear();
copyOther(other);
}
return *this;
}
/* clear deletes the stored pointer. */
template <typename ArgType, typename ReturnType>
void Function<ArgType, ReturnType>::clear() {
delete function;
}
/* copyOther uses the clone() member function to do the copy. Note that the copy
* is necessary instead of using a shallow copy because the function might be a
* functor with internal state.
*/
template <typename ArgType, typename ReturnType>
void Function<ArgType, ReturnType>::copyOther(const Function& other) {
function = other.function->clone();
}
/* Finally, operator() just calls down into the function and returns the result. */
template <typename ArgType, typename ReturnType>
ReturnType Function<ArgType, ReturnType>::operator()(ArgType param) const {
return function->execute(param);
}
#endif