//
// $Id: Functional.h,v 1.21 2005/07/12 19:15:36 will_mason Exp $
//
// vi: set ft=objc:

/*
 * ObjectiveLib - a library of containers and algorithms for Objective-C
 *
 * Copyright (c) 2004
 * Will Mason
 *
 * Portions:
 *
 * Copyright (c) 1994
 * Hewlett-Packard Company
 *
 * Copyright (c) 1996,1997
 * Silicon Graphics Computer Systems, Inc.
 *
 * Copyright (c) 1997
 * Moscow Center for SPARC Technology
 *
 * Copyright (c) 1999 
 * Boris Fomitchev
 *
 * 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 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * You may contact the author at will_mason@users.sourceforge.net.
 */

#if !defined(FUNCTIONAL_OL_GUARD)
#define FUNCTIONAL_OL_GUARD

#import <ObjectiveLib/Memory.h>
#import <ObjectiveLib/Types.h>

/**
 * @defgroup Functors Function Objects
 *
 * A function object is simply an object that is treated as a function. There
 * are two types of function objects used in ObjectiveLib: unary function objects
 * and binary function objects. Unary function objects take a single object
 * as a parameter and return a result, and binary function objects take two
 * objects as parameters and return a result. They are used extensively for
 * example to define how a sorted container is sorted. In this case a binary
 * function object is used to compare two objects in the controlled sequence
 * to determine sorting order.
 */

/**
 * @protocol OLBinaryFunction Functional.h ObjectiveLib/Functional.h
 *
 * A protocol defining the message for performing the operation of a
 * binary function object.
 *
 * @ingroup Functors
 */
@protocol OLBinaryFunction

/**
 * Perform the function of this function object. The operation is performed
 * on the two parameters, a new object is allocated containing the result,
 * and it is returned.
 *
 * @param arg1 the first argument
 * @param arg2 the second argument
 * @return a new object containing the result
 */
- (id) performBinaryFunctionWithArg: (id)arg1 andArg: (id)arg2;

@end

/**
 * @protocol OLUnaryFunction Functional.h ObjectiveLib/Functional.h
 *
 * A protocol defining the message for performing the operation of a
 * unary function object.
 *
 * @ingroup Functors
 */
@protocol OLUnaryFunction

/**
 * Perform the function of this function object. The operation is performed
 * on the single parameter, a new object is allocated containing the result,
 * and it is returned.
 *
 * @param arg the argument to the function
 * @return a new object containing the result
 */
- (id) performUnaryFunctionWithArg: (id)arg;

@end

/**
 * @protocol OLBoolBinaryFunction Functional.h ObjectiveLib/Functional.h
 *
 * A protocol defining the message for performing the operation of a
 * binary function object. This is a specialized form of OLBinaryFunction
 * that returns the result as a boolean value instead of an allocated
 * object.
 *
 * @ingroup Functors
 */
@protocol OLBoolBinaryFunction

/**
 * Perform the function of this function object. The operation is performed
 * on the two parameters and the result is returned.
 *
 * @param arg1 the first argument
 * @param arg2 the second argument
 * @return the result
 */
- (BOOL) performBinaryFunctionWithArg: (id)arg1 andArg: (id)arg2;

@end

/**
 * @protocol OLBoolUnaryFunction Functional.h ObjectiveLib/Functional.h
 *
 * A protocol defining the message for performing the operation of a
 * unary function object. This is a specialized form of OLUnaryFunction
 * that returns the result as a boolean value instead of an allocated
 * object.
 *
 * @ingroup Functors
 */
@protocol OLBoolUnaryFunction

/**
 * Perform the function of this function object. The operation is performed
 * on the single parameter and the result is returned.
 *
 * @param arg the argument to the function
 * @return the result
 */
- (BOOL) performUnaryFunctionWithArg: (id)arg;

@end

/**
 * @class OLFunctor Functional.h ObjectiveLib/Functional.h
 *
 * A base class for function objects. This class merely provides the service
 * that will create and return an instance of a function object of a desired
 * type.
 *
 * @ingroup Functors
 */
@interface OLFunctor : NSObject
{
}

/**
 * Create and return an instance of a function object. All functors that are shipped
 * with @b ObjectiveLib and that have initializers that take no arguments can be
 * created with this message. The default memory allocator is used. If the platform
 * and the allocator both support autorelease, then the returned functor will
 * be autoreleased before being returned.
 *
 * @param type the type of functor to create
 * @return a new instance of the function object of the given type
 */
+ (id) functorOfType: (OLFunctorType)type;

@end

/**
 * @class OLCodableFunctor Functional.h ObjectiveLib/Functional.h
 *
 * A function object that can be encoded to and decoded from an archive. This
 * class merely provides the default implementation of the @c NSCoding protocol
 * for all function objects. Since most function objects don't have any instance
 * variables the encode and decode methods of this class do all the work for
 * the vast majority of function object classes. All function objects inherit
 * from OLCodableFunctor.
 * 
 * @ingroup Functors
 */
@interface OLCodableFunctor : OLFunctor <NSCoding>
{
}

/**
 * Initialize the function object. This initializer creates a new function object
 * from an archive and returns it.
 *
 * @post The function object returned will be identical to the function object
 * saved to the archive using the #encodeWithCoder: message.
 *
 * @param decoder the coder which will decode the archived function object
 * @return a reference to this function object
 */
- (id) initWithCoder: (NSCoder*)decoder;

/**
 * Encode the function object. The function object is saved to an archive
 * using @a encoder. The function object will be retrieved from the archive
 * using the initializer #initWithCoder:.
 *
 * @param encoder the coder which will save the function object to the archive
 */
- (void) encodeWithCoder: (NSCoder*)encoder;

@end

/**
 * @class OLAllocFunctor Functional.h ObjectiveLib/Functional.h
 *
 * A base class for function objects that will need to allocate memory.
 * The purpose of the base class is to provide memory management for
 * the function object. For example, a function object can be created
 * that does or does not attempt to autorelease its results. Additionally,
 * a specific allocator can be specified for the allocation of results.
 *
 * @ingroup Functors
 */
@interface OLAllocFunctor : OLCodableFunctor
{
@protected
    /**
     * The allocator to use for allocating the result objects created
     * by this function object.
     */
    OLAllocator*    allocator;

    /**
     * A flag indicating whether this object should autorelease its results
     * or not.
     */
    BOOL            autorelease;
}

/**
 * @name Initializers and Deallocators
 */
/* @{ */
/**
 * Initialize the function object. This initializer uses the default allocator
 * and turns on autoreleasing of results.
 *
 * @return a reference to this function object
 */
- (id) init;

/**
 * Initialize the function object. This initializer uses the given allocator
 * and turns on autoreleasing of results.
 *
 * @param alloc the allocator that this object should use to generate results
 * @return a reference to this function object
 */
- (id) initWithAllocator: (OLAllocator*)alloc;

/**
 * Initialize the function object. This initializer uses the given allocator
 * and sets autoreleasing of results according to the given value.
 *
 * @param alloc the allocator that this object should use to generate results
 * @param autorel YES if this object should attempt to autorelease its results,
 * NO otherwise
 * @return a reference to this function object
 */
- (id) initWithAllocator: (OLAllocator*)alloc autorelease: (BOOL)autorel;

/**
 * Initialize the function object. This initializer uses the default allocator
 * and sets autoreleasing of results according to the given value.
 *
 * @param autorel YES if this object should attempt to autorelease its results,
 * NO otherwise
 * @return a reference to this function object
 */
- (id) initWithAutorelease: (BOOL)autorel;
- (id) initWithCoder: (NSCoder*)decoder;

/**
 * Finalize the function object and deallocate any allocated memory.
 */
- (void) dealloc;
/* @} */

/**
 * Return whether this function object autoreleases its results.
 *
 * @return YES if autoreleasing is turned on, NO otherwise
 */
- (BOOL) autoreleasesResults;
- (void) encodeWithCoder: (NSCoder*)encoder;

/**
 * Return the allocator being used by this function object.
 *
 * @return the allocator in use
 */
- (OLAllocator*) allocator;

/**
 * Set the allocator used by this function object.
 *
 * @param alloc the new allocator to use
 */
- (void) setAllocator: (OLAllocator*)alloc;

/**
 * Set whether this function object should attempt to autorelease its results.
 *
 * @param autorel YES if autorelease should be turned on, NO otherwise
 */
- (void) setAutoreleasesResults: (BOOL)autorel;

@end

/**
 * @class OLBinaryNegate Functional.h ObjectiveLib/Functional.h
 *
 * A binary function object that negates the action of another binary
 * function object. The action message of this object simple returns
 * the opposite of the target function object.
 *
 * @ingroup Functors
 */
@interface OLBinaryNegate : OLCodableFunctor <OLBoolBinaryFunction>
{
@protected
    /**
     * The function object to be negated
     */
    OLCodableFunctor<OLBoolBinaryFunction>* fn;
}

/**
 * Create and return an instance of OLBinaryNegate. The default memory allocator is used.
 * If the platform and allocator both support autorelease, then the functor
 * will be autoreleased before being returned.
 *
 * @param function the function that OLBinaryNegate will negate
 * @return a new functor
 */
+ (id) functorWithBinaryFunction: (OLCodableFunctor<OLBoolBinaryFunction>*)function;

/**
 * @name Initializers and Deallocators
 */
/* @{ */
- (id) initWithCoder: (NSCoder*)decoder;

/**
 * Initialize the function object with the function that should be negated.
 *
 * @param function the target function that will be negated
 * @return a reference to this function object
 */
- (id) initWithBinaryFunction: (OLCodableFunctor<OLBoolBinaryFunction>*)function;

/**
 * Finalize the function object and deallocate any allocated memory.
 */
- (void) dealloc;
/* @} */

- (void) encodeWithCoder: (NSCoder*)encoder;

/**
 * Perform the underlying function and return the opposite of its result.
 *
 * @param arg1 the first argument to pass to the target function
 * @param arg2 the second argument to pass to the target function
 * @return the opposite of the target function's result
 */
- (BOOL) performBinaryFunctionWithArg: (id)arg1 andArg: (id)arg2;

@end

/**
 * @class OLBinder1st Functional.h ObjectiveLib/Functional.h
 *
 * Transform a binary function object into a unary function object. This
 * function object binds a given object to the first argument of a
 * given binary function object, thus producing a unary function object.
 *
 * @ingroup Functors
 */
@interface OLBinder1st : OLAllocFunctor <OLUnaryFunction>
{
@protected
    /**
     * The function to which to bind an argument
     */
    OLAllocFunctor<OLBinaryFunction>*   fn;

    /**
     * The argument to bind
     */
    id                                  lft;
}

/**
 * Create and return an instance of OLBinder1st. The default memory allocator is used.
 * If the platform and allocator both support autorelease, then the functor
 * will be autoreleased before being returned.
 *
 * @param function the binary function object to use
 * @param left the left or first argument for the binary function object
 * @return a new functor
 */
+ (id) functorWithFunction: (OLAllocFunctor<OLBinaryFunction>*)function andLeftArg: (id)left;

/**
 * @name Initializers and Deallocators
 */
/* @{ */
- (id) initWithCoder: (NSCoder*)decoder;

/**
 * Initialize the function object. The binary function object and its first argument
 * are stored for later use. When this function object's #performUnaryFunctionWithArg:
 * message is sent the argument to the message becomes the second argument to the underlying
 * binary function object and its result is returned. The first argument to the
 * underlying binary function object will be @a left.
 *
 * @note If archiving or serializing the function object is desired, the argument
 * @a left @em must conform to the @c NSCoding protocol.
 *
 * @param function the binary function object to use
 * @param left the left or first argument for the binary function object
 * @return a reference to this function object
 */
- (id) initWithFunction: (OLAllocFunctor<OLBinaryFunction>*)function andLeftArg: (id)left;
- (void) dealloc;
/* @} */

- (void) encodeWithCoder: (NSCoder*)encoder;

/**
 * Perform the function of this function object. Specifically, the underlying
 * binary function object passed to #initWithFunction:andLeftArg: is called with
 * the stored object as the first argument and @a arg as the second argument. The
 * result of the binary function is then returned.
 *
 * @param arg the argument to the function
 * @return a new object containing the result
 */
- (id) performUnaryFunctionWithArg: (id)arg;

@end

/**
 * @class OLBinder2nd Functional.h ObjectiveLib/Functional.h
 *
 * Transform a binary function object into a unary function object. This
 * function object binds a given object to the second argument of a
 * given binary function object, thus producing a unary function object.
 *
 * @ingroup Functors
 */
@interface OLBinder2nd : OLAllocFunctor <OLUnaryFunction>
{
@protected
    /**
     * The function to which to bind an argument
     */
    OLAllocFunctor<OLBinaryFunction>*    fn;

    /**
     * The argument to bind
     */
    id                              rght;
}

/**
 * Create and return an instance of OLBinder2nd. The default memory allocator is used.
 * If the platform and allocator both support autorelease, then the functor
 * will be autoreleased before being returned.
 *
 * @param function the binary function object to use
 * @param right the right or second argument for the binary function object
 * @return a new functor
 */
+ (id) functorWithFunction: (OLAllocFunctor<OLBinaryFunction>*)function andRightArg: (id)right;

/**
 * @name Initializers and Deallocators
 */
/* @{ */
- (id) initWithCoder: (NSCoder*)decoder;

/**
 * Initialize the function object. The binary function object and its second argument
 * are stored for later use. When this function object's #performUnaryFunctionWithArg:
 * message is sent the argument to the message becomes the first argument to the underlying
 * binary function object and its result is returned. The second argument to the
 * underlying binary function object will be @a right.
 *
 * @note If archiving or serializing the function object is desired, the argument
 * @a right @em must conform to the @c NSCoding protocol.
 *
 * @param function the binary function object to use
 * @param right the right or second argument for the binary function object
 * @return a reference to this function object
 */
- (id) initWithFunction: (OLAllocFunctor<OLBinaryFunction>*)function andRightArg: (id)right;
- (void) dealloc;
/* @} */

- (void) encodeWithCoder: (NSCoder*)encoder;

/**
 * Perform the function of this function object. Specifically, the underlying
 * binary function object passed to #initWithFunction:andLeftArg: is called with
 * @a arg as the first argument and the stored object as the second argument. The
 * result of the binary function is then returned.
 *
 * @param arg the argument to the function
 * @return a new object containing the result
 */
- (id) performUnaryFunctionWithArg: (id)arg;

@end

/**
 * @class OLBoolBinder1st Functional.h ObjectiveLib/Functional.h
 *
 * Transform a binary function object into a unary function object. This
 * function object binds a given object to the first argument of a
 * given binary function object, thus producing a unary function object.
 *
 * @ingroup Functors
 */
@interface OLBoolBinder1st : OLCodableFunctor <OLBoolUnaryFunction>
{
@protected
    /**
     * The function to which to bind an argument
     */
    OLCodableFunctor<OLBoolBinaryFunction>* fn;

    /**
     * The argument to bind
     */
    id                              lft;
}

/**
 * Create and return an instance of OLBoolBinder1st. The default memory allocator is used.
 * If the platform and allocator both support autorelease, then the functor
 * will be autoreleased before being returned.
 *
 * @param function the binary function object to use
 * @param left the left or first argument for the binary function object
 * @return a new functor
 */
+ (id) functorWithBoolFunction: (OLCodableFunctor<OLBoolBinaryFunction>*)function andLeftArg: (id)left;

/**
 * @name Initializers and Deallocators
 */
/* @{ */
/**
 * Initialize the function object. The binary function object and its first argument
 * are stored for later use. When this function object's #performUnaryFunctionWithArg:
 * message is sent the argument to the message becomes the second argument to the underlying
 * binary function object and its result is returned. The first argument to the
 * underlying binary function object will be @a left.
 *
 * @param function the binary function object to use
 * @param left the left or first argument for the binary function object
 * @return a reference to this function object
 */
- (id) initWithBoolFunction: (OLCodableFunctor<OLBoolBinaryFunction>*)function andLeftArg: (id)left;
- (id) initWithCoder: (NSCoder*)decoder;
- (void) dealloc;
/* @} */

- (void) encodeWithCoder: (NSCoder*)encoder;

/**
 * Perform the function of this function object. Specifically, the underlying
 * binary function object passed to #initWithFunction:andLeftArg: is called with
 * the stored object as the first argument and @a arg as the second argument. The
 * result of the binary function is then returned.
 *
 * @param arg the argument to the function
 * @return a new object containing the result
 */
- (BOOL) performUnaryFunctionWithArg: (id)arg;

@end

/**
 * @class OLBoolBinder2nd Functional.h ObjectiveLib/Functional.h
 *
 * Transform a binary function object into a unary function object. This
 * function object binds a given object to the second argument of a
 * given binary function object, thus producing a unary function object.
 *
 * @ingroup Functors
 */
@interface OLBoolBinder2nd : OLCodableFunctor <OLBoolUnaryFunction>
{
@protected
    /**
     * The function to which to bind an argument
     */
    OLCodableFunctor<OLBoolBinaryFunction>* fn;

    /**
     * The argument to bind
     */
    id                              rght;
}

/**
 * Create and return an instance of OLBoolBinder2nd. The default memory allocator is used.
 * If the platform and allocator both support autorelease, then the functor
 * will be autoreleased before being returned.
 *
 * @param function the binary function object to use
 * @param right the right or second argument for the binary function object
 * @return a new functor
 */
+ (id) functorWithBoolFunction: (OLCodableFunctor<OLBoolBinaryFunction>*)function andRightArg: (id)right;

/**
 * @name Initializers and Deallocators
 */
/* @{ */
/**
 * Initialize the function object. The binary function object and its second argument
 * are stored for later use. When this function object's #performUnaryFunctionWithArg:
 * message is sent the argument to the message becomes the first argument to the underlying
 * binary function object and its result is returned. The second argument to the
 * underlying binary function object will be @a right.
 *
 * @param function the binary function object to use
 * @param right the right or second argument for the binary function object
 * @return a reference to this function object
 */
- (id) initWithBoolFunction: (OLCodableFunctor<OLBoolBinaryFunction>*)function andRightArg: (id)right;
- (id) initWithCoder: (NSCoder*)decoder;
- (void) dealloc;
/* @} */

- (void) encodeWithCoder: (NSCoder*)encoder;

/**
 * Perform the function of this function object. Specifically, the underlying
 * binary function object passed to #initWithFunction:andLeftArg: is called with
 * @a arg as the first argument and the stored object as the second argument. The
 * result of the binary function is then returned.
 *
 * @param arg the argument to the function
 * @return a new object containing the result
 */
- (BOOL) performUnaryFunctionWithArg: (id)arg;

@end

/**
 * @class OLDivides Functional.h ObjectiveLib/Functional.h
 *
 * A function object for performing division. This function object divides
 * a given value by another given value and returns the result.
 *
 * @ingroup Functors
 */
@interface OLDivides : OLAllocFunctor <OLBinaryFunction>
{
}

/**
 * Divide @a arg1 by @a arg2 and return the result.
 *
 * @pre @a arg1 must respond to the message @c arithmeticDivideBy:allocator:
 * found in the OLArithmetic protocol.
 *
 * @param arg1 the value to divide
 * @param arg2 the value by which to divide
 * @return the result of dividing @a arg1 by @a arg2
 */
- (id) performBinaryFunctionWithArg: (id)arg1 andArg: (id)arg2;

@end

/**
 * @class OLEqualTo Functional.h ObjectiveLib/Functional.h
 *
 * A function object for assessing equality. The object compares two objects
 * a returns a boolean value indicating equality.
 *
 * @ingroup Functors
 */
@interface OLEqualTo : OLCodableFunctor <OLBoolBinaryFunction>
{
}

/**
 * Compare @a arg1 to @a arg2 and return whether they are equal.
 *
 * @pre @a arg1 must respond to the message @c isEqualTo:.
 *
 * @param arg1 the first object
 * @param arg2 the second object
 * @return YES if the two objects are equal, NO otherwise
 */
- (BOOL) performBinaryFunctionWithArg: (id)arg1 andArg: (id)arg2;

@end

/**
 * @class OLGreater Functional.h ObjectiveLib/Functional.h
 *
 * A function object for comparing objects. This object determines whether
 * a given object is greater than another given object.
 *
 * @ingroup Functors
 */
@interface OLGreater : OLCodableFunctor <OLBoolBinaryFunction>
{
}

/**
 * Test whether @a arg1 is greater than @a arg2.
 *
 * @pre @a arg1 must respond to the message @c isGreaterThan:.
 *
 * @param arg1 the first argument
 * @param arg2 the second argument
 * @return YES if @a arg1 is greater than @a arg2, NO otherwise
 */
- (BOOL) performBinaryFunctionWithArg: (id)arg1 andArg: (id)arg2;

@end

/**
 * @class OLGreaterEqual Functional.h ObjectiveLib/Functional.h
 *
 * A function object for comparing objects. This object determines whether
 * a given object is greater than or equal to another given object.
 *
 * @ingroup Functors
 */
@interface OLGreaterEqual : OLCodableFunctor <OLBoolBinaryFunction>
{
}

/**
 * Test whether @a arg1 is greater than or equal to @a arg2.
 *
 * @pre @a arg1 must respond to the message @c isGreaterThanOrEqualTo:.
 *
 * @param arg1 the first argument
 * @param arg2 the second argument
 * @return YES if @a arg1 is greater than or equal to @a arg2, NO otherwise
 */
- (BOOL) performBinaryFunctionWithArg: (id)arg1 andArg: (id)arg2;

@end

/**
 * @class OLLess Functional.h ObjectiveLib/Functional.h
 *
 * A function object for comparing objects. This object determines whether
 * a given object is less than another given object.
 *
 * @ingroup Functors
 */
@interface OLLess : OLCodableFunctor <OLBoolBinaryFunction>
{
}

/**
 * Test whether @a arg1 is less than @a arg2.
 *
 * @pre @a arg1 must respond to the message @c isLessThan:.
 *
 * @param arg1 the first argument
 * @param arg2 the second argument
 * @return YES if @a arg1 is less than @a arg2, NO otherwise
 */
- (BOOL) performBinaryFunctionWithArg: (id)arg1 andArg: (id)arg2;

@end

/**
 * @class OLLessEqual Functional.h ObjectiveLib/Functional.h
 *
 * A function object for comparing objects. This object determines whether
 * a given object is less than or equal to another given object.
 *
 * @ingroup Functors
 */
@interface OLLessEqual : OLCodableFunctor <OLBoolBinaryFunction>
{
}

/**
 * Test whether @a arg1 is less than or equal to @a arg2.
 *
 * @pre @a arg1 must respond to the message @c isLessThanOrEqualTo:.
 *
 * @param arg1 the first argument
 * @param arg2 the second argument
 * @return YES if @a arg1 is less than or equal to @a arg2, NO otherwise
 */
- (BOOL) performBinaryFunctionWithArg: (id)arg1 andArg: (id)arg2;

@end

/**
 * @class OLLogicalAnd Functional.h ObjectiveLib/Functional.h
 *
 * A function object that tests whether two object are both true.
 * Both objects passed must be convertible to boolean values, meaning
 * that they must respond to the message @c boolValue.
 *
 * @ingroup Functors
 */
@interface OLLogicalAnd : OLCodableFunctor <OLBoolBinaryFunction>
{
}

/**
 * Test whether both arguments are true. The message converts both
 * arguments to boolean values using the message @c boolValue, then
 * returns YES if neither value is false.
 *
 * @pre @a arg1 and @a arg2 must respond to the message @c boolValue.
 *
 * @param arg1 the first argument
 * @param arg2 the second argument
 * @return YES if @a arg1 and @a arg2 are both true, NO otherwise
 */
- (BOOL) performBinaryFunctionWithArg: (id)arg1 andArg: (id)arg2;

@end

/**
 * @class OLLogicalNot Functional.h ObjectiveLib/Functional.h
 *
 * A function object is true only if its argument is false. The given
 * argument must be convertible to a boolean value, meaning that it
 * must respond to the message @c boolValue.
 *
 * @ingroup Functors
 */
@interface OLLogicalNot : OLCodableFunctor <OLBoolUnaryFunction>
{
}

/**
 * Test @a arg and return YES only if @a arg is false.
 *
 * @pre @a arg must respond to the message @c boolValue.
 *
 * @param arg the argument to test
 * @return YES if @a arg is false, NO otherwise
 */
- (BOOL) performUnaryFunctionWithArg: (id)arg;

@end

/**
 * @class OLLogicalOr Functional.h ObjectiveLib/Functional.h
 *
 * A function object that tests whether either of two object is true.
 * Both objects passed must be convertible to boolean values, meaning
 * that they must respond to the message @c boolValue.
 *
 * @ingroup Functors
 */
@interface OLLogicalOr : OLCodableFunctor <OLBoolBinaryFunction>
{
}

/**
 * Test whether either of the arguments is true. The message converts both
 * arguments to boolean values using the message @c boolValue, then
 * returns YES if either value is true.
 *
 * @pre @a arg1 and @a arg2 must respond to the message @c boolValue.
 *
 * @param arg1 the first argument
 * @param arg2 the second argument
 * @return YES if @a arg1 or @a arg2 is true, NO otherwise
 */
- (BOOL) performBinaryFunctionWithArg: (id)arg1 andArg: (id)arg2;

@end

/**
 * @class OLMemFun Functional.h ObjectiveLib/Functional.h
 *
 * A function object that sends a given message to a given object and
 * returns the result. The selector is stored in the function object and
 * then is invoked by the function object using the given argument as
 * the object to which to send the message.
 *
 * @sa OLMemFun1
 *
 * @ingroup Functors
 */
@interface OLMemFun : OLAllocFunctor <OLUnaryFunction>
{
@protected
    /**
     * The selector to perform
     */
    SEL sel;
}

/**
 * Create and return an instance of OLMemFun. The default memory allocator is used.
 * If the platform and allocator both support autorelease, then the functor
 * will be autoreleased before being returned.
 *
 * @param selector the selector to store for future invocation
 * @return a new functor
 */
+ (id) functorWithSelector: (SEL)selector;

/**
 * @name Initializers and Deallocators
 */
/* @{ */
- (id) initWithCoder: (NSCoder*)decoder;

/**
 * Initialize the function object with the given selector.
 *
 * @param selector the selector to store for future invocation
 * @return a reference to this function object
 */
- (id) initWithSelector: (SEL)selector;
/* @} */

- (void) encodeWithCoder: (NSCoder*)encoder;

/**
 * Send the stored message to the object referenced by @a arg. The object
 * returned may or may not be owned by the sender of the message, depending
 * on the nature of the message being sent. No attempt is made by the
 * function object to control memory management of the returned object.
 *
 * @pre @a arg must respond to the selector passed to the initializer.
 *
 * @param arg the object to which to send the message
 * @return the result of invoking the message. Note that memory management
 * is not controlled by the function object and the question of whether
 * to deallocate the returned object depends on the nature of the message.
 */
- (id) performUnaryFunctionWithArg: (id)arg;

@end

/**
 * @class OLMemFun1 Functional.h ObjectiveLib/Functional.h
 *
 * A function object that sends a given message and a given argument
 * to a given object and returns the result. The selector is stored in the function object and
 * then is invoked by the function object using the given argument as
 * the object to which to send the message.
 *
 * @sa OLMemFun
 *
 * @ingroup Functors
 */
@interface OLMemFun1 : OLAllocFunctor <OLBinaryFunction>
{
@protected
    /**
     * The selector to perform
     */
    SEL sel;
}

/**
 * Create and return an instance of OLMemFun1. The default memory allocator is used.
 * If the platform and allocator both support autorelease, then the functor
 * will be autoreleased before being returned.
 *
 * @param selector the selector to store for future invocation
 * @return a new functor
 */
+ (id) functorWithSelector: (SEL)selector;

/**
 * @name Initializers and Deallocators
 */
/* @{ */
- (id) initWithCoder: (NSCoder*)decoder;

/**
 * Initialize the function object with the given selector.
 *
 * @param selector the selector to store for future invocation
 * @return a reference to this function object
 */
- (id) initWithSelector: (SEL)selector;
/* @} */

- (void) encodeWithCoder: (NSCoder*)encoder;

/**
 * Send the stored message to the object referenced by @a arg1 using @a arg2
 * as an additional parameter. The object returned may or may not be owned
 * by the sender of the message, depending on the nature of the message
 * being sent. No attempt is made by the function object to control memory
 * management of the returned object.
 *
 * @pre @a arg1 must respond to the selector passed to the initializer.
 *
 * @param arg1 the object to which to send the message
 * @param arg2 the argument to send along with the message
 * @return the result of invoking the message. Note that memory management
 * is not controlled by the function object and the question of whether
 * to deallocate the returned object depends on the nature of the message.
 */
- (id) performBinaryFunctionWithArg: (id)arg1 andArg: (id)arg2;

@end

/**
 * @class OLMinus Functional.h ObjectiveLib/Functional.h
 *
 * A function object that subtracts the value of one object from
 * the value of another.
 *
 * @ingroup Functors
 */
@interface OLMinus : OLAllocFunctor <OLBinaryFunction>
{
}

/**
 * Subtract the value of @a arg2 from the value of @a arg1.
 *
 * @pre @a arg1 must respond to the message @c arithmeticSubtract:allocator:
 * found in the OLArithmetic protocol.
 *
 * @param arg1 the value from which to subtract
 * @param arg2 the value to subtract
 * @return the result of subtraction
 */
- (id) performBinaryFunctionWithArg: (id)arg1 andArg: (id)arg2;

@end

/**
 * @class OLModulus Functional.h ObjectiveLib/Functional.h
 *
 * Compute the remainder of division. The value of one argument is divided
 * by the value of another, and the result is the remainder of division.
 *
 * @ingroup Functors
 */
@interface OLModulus : OLAllocFunctor <OLBinaryFunction>
{
}

/**
 * Compute the remainder of the division of the value of @a arg1 by
 * the value of @a arg2.
 *
 * @pre @a arg1 must respond to the message @c arithmeticModulus:allocator:
 * found in the OLArithmetic protocol.
 *
 * @param arg1 the value to divide
 * @param arg2 the value by which to divide
 * @return the remainder of division
 */
- (id) performBinaryFunctionWithArg: (id)arg1 andArg: (id)arg2;

@end

/**
 * @class OLMultiplies Functional.h ObjectiveLib/Functional.h
 *
 * A function object that multiplies the value of one object by the
 * value of another.
 *
 * @ingroup Functors
 */
@interface OLMultiplies : OLAllocFunctor <OLBinaryFunction>
{
}

/**
 * Multiply the value of @a arg1 by the value of @a arg2.
 *
 * @pre @a arg1 must respond to the message @c arithmeticMultiply:allocator:
 * found in the OLArithmetic protocol.
 *
 * @param arg1 the first value
 * @param arg2 the second value
 * @return the result of multiplication
 */
- (id) performBinaryFunctionWithArg: (id)arg1 andArg: (id)arg2;

@end

/**
 * @class OLNegate Functional.h ObjectiveLib/Functional.h
 *
 * A function object for reversing the sign of the value of a given
 * object.
 *
 * @ingroup Functors
 */
@interface OLNegate : OLAllocFunctor <OLUnaryFunction>
{
}

/**
 * Reverse the sign of the value of @a arg and return the result.
 *
 * @pre @a arg must respond to the message @c arithmeticNegateWithAllocator:
 * found in the OLArithmetic protocol.
 *
 * @param arg the value of which to reverse the sign
 * @return the negation of the value of @a arg
 */
- (id) performUnaryFunctionWithArg: (id)arg;

@end

/**
 * @class OLNotEqualTo Functional.h ObjectiveLib/Functional.h
 *
 * A function object for assessing inequality. The object compares two objects
 * a returns a boolean value of true if the objects are not equal.
 *
 * @ingroup Functors
 */
@interface OLNotEqualTo : OLCodableFunctor <OLBoolBinaryFunction>
{
}

/**
 * Compare @a arg1 to @a arg2 and return whether they are equal.
 *
 * @pre @a arg1 must respond to the message @c isNotEqualTo:.
 *
 * @param arg1 the first object
 * @param arg2 the second object
 * @return YES if the two objects are not equal, NO otherwise
 */
- (BOOL) performBinaryFunctionWithArg: (id)arg1 andArg: (id)arg2;

@end

/**
 * @class OLPlus Functional.h ObjectiveLib/Functional.h
 *
 * A function object for adding the values of two objects.
 *
 * @ingroup Functors
 */
@interface OLPlus : OLAllocFunctor <OLBinaryFunction>
{
}

/**
 * Add the value of @a arg2 to the value of @a arg1.
 *
 * @pre @a arg1 must respond to the message @c arithmeticAdd:allocator:
 * found in the OLArithmetic protocol.
 *
 * @param arg1 the first value
 * @param arg2 the second value
 * @return the result of addition
 */
- (id) performBinaryFunctionWithArg: (id)arg1 andArg: (id)arg2;

@end

/**
 * @class OLUnaryNegate Functional.h ObjectiveLib/Functional.h
 *
 * A unary function object that negates the action of another unary
 * function object. The action message of this object simple returns
 * the opposite of the target function object.
 *
 * @ingroup Functors
 */
@interface OLUnaryNegate : OLCodableFunctor <OLBoolUnaryFunction>
{
@protected
    /**
     * The underyling unary function that will be negated
     */
    OLCodableFunctor<OLBoolUnaryFunction>* fn;
}

/**
 * Create and return an instance of OLUnaryNegate. The default memory allocator is used.
 * If the platform and allocator both support autorelease, then the functor
 * will be autoreleased before being returned.
 *
 * @param function the function that OLUnaryNegate will negate
 * @return a new functor
 */
+ (id) functorWithUnaryFunction: (OLCodableFunctor<OLBoolUnaryFunction>*)function;

/**
 * @name Initializers and Deallocators
 */
/* @{ */
- (id) initWithCoder: (NSCoder*)decoder;

/**
 * Initialize the function object with the function that should be negated.
 *
 * @param function the target function that will be negated
 * @return a reference to this function object
 */
- (id) initWithUnaryFunction: (OLCodableFunctor<OLBoolUnaryFunction>*)function;

/**
 * Finalize the function object and deallocate any allocated memory.
 */
- (void) dealloc;
/* @} */

- (void) encodeWithCoder: (NSCoder*)encoder;

/**
 * Perform the underlying function and return the opposite of its result.
 *
 * @param arg the argument to pass to the target function
 * @return the opposite of the target function's result
 */
- (BOOL) performUnaryFunctionWithArg: (id)arg;

@end

#endif
