/*
								+-----------------------------------+
								|                                   |
								|  ***  Function call wrapper  ***  |
								|                                   |
								|   Copyright  © -tHE SWINe- 2014   |
								|                                   |
								|          FunctionCall.h           |
								|                                   |
								+-----------------------------------+
*/

#pragma once
#ifndef __FUNCTION_CALL_WRAPPER_LIBRARY_INCLUDED
#define __FUNCTION_CALL_WRAPPER_LIBRARY_INCLUDED

/**
 *	@file FunctionCall.h
 *	@brief function call wrapper
 *	@author -tHE SWINe-
 *	@date 2014
 *
 *	This was heavily inspired by the interface of the XPU library by Nader Khammassi et. al.
 *
 *	Use as follows:
 *	@code
 *	int myFunction(int, float);
 *
 *	CAutoCallPointer p1 = GetSignature(&myFunction)(1, 2.3f);
 *	p1->Call();
 *	// managed pointer to a static function (follows the semantics of std::auto_ptr)
 *	@endcode
 *
 *	Use CCallPointer* to pass pointers:
 *	@code
 *	CAutoCallPointer p1 = GetSignature(&myFunction)(1, 2.3f);
 *	CCallPointer *p = p1.p_Release(); // p is no longer managed
 *	// see CAutoCallPointer::p_Get() or CAutoCallPointer::p_Release()
 *
 *	std::vector<CCallPointer*> calls;
 *	calls.push_back(p);
 *	// use CCallPointer* for passing call pointers to functions / storing in containers
 *
 *	std::for_each(calls.begin(), calls.end(), std::mem_fun(&CCallPointer::Call));
 *	// call all of the functions
 *
 *	for(std::vector<CCallPointer*>::iterator it = calls.begin(); it != calls.end(); ++ it)
 *		delete *it;
 *	// if we used CAutoCallPointer::p_Release(), we have to delete the calls manually
 *	@endcode
 *
 *	Fast (but strongly typed):
 *	@code
 *	int myFunction(int, float);
 *
 *	CStaticCallContext<int, MakeTypelist2(int, float)> p1 = GetSignature(&myFunction)(1, 2.3f);
 *	int n_result = p1.t_Call(); // can see result
 *	// statically typed and linked call context
 *	// (usually the same speed as direct call of the function)
 *	@endcode
 *
 *	Statically allocated (still fast but with a generic interface):
 *	@code
 *	int myFunction(int, float);
 *
 *	function_call::CTypedCallPointer<CStaticCallContext<int,
 *		MakeTypelist2(int, float)> > p1 = GetSignature(&myFunction)(1, 2.3f);
 *	int n_result = p1.t_Call(); // can see result
 *	// statically typed but dynamically linked call context
 *
 *	CCallPointer *p = &p1;
 *	p->Call(); // result hidden
 *	// can convert to CCallPointer and pass to generic functions
 *	@endcode
 *
 *	Example of the use with member functions:
 *	@code
 *	struct myClass {
 *		int memberFunction(int, float);
 *	};
 *
 *	myClass c;
 *	CAutoCallPointer p2 = GetMemSignature(&c, &myClass::memberFunction)(4, 5.6f);
 *	p2->Call();
 *	// managed pointer to a member function
 *	@endcode
 *
 *	@date 2014-05-05
 *
 *	Restored limited intellisense functionality in Visual Studio 2008
 *	(it works with static functions, still have problems with member functions).
 *
 *	Added extended call pointers (CCallPointerEx) to support the parallel library.
 *
 *	@date 2014-05-11
 *
 *	Added stack and placement duplication via CTypedCallPointerEx::p_Duplicate().
 *
 */

#include "../UberLame_src/Typelist.h"
#include <utility>

/**
 *	@def __FUNCTION_CALL_ARG_STORAGE_SWAP_ORDER
 *	@brief if defined, the order the arguments are stored is reversed
 *	@note This is aimed at minimizing the number of data copies, the order of arguments
 *		on the stack depends on the compiler but traditionally the arguments are pushed
 *		from the last one to the first one (the first one is on top, on the highest address).
 */
//#define __FUNCTION_CALL_ARG_STORAGE_SWAP_ORDER

/**
 *	@brief call pointer interface
 */
class CCallPointer {
public:
	/**
	 *	@brief calls the original function, with the specified context
	 *	@note The return value of the original call is lost.
	 */
	virtual void Call() = 0;

	/**
	 *	@brief destructor (only required by Visual Studio)
	 *	@note This does not affect size of CCallPointer or the derived
	 *		classes in g++.
	 */
	virtual ~CCallPointer()
	{}
};

/**
 *	@brief extended call pointer interface
 */
class CCallPointerEx : public virtual CCallPointer {
public:
	/**
	 *	@brief sets thread id and number of threads, associated with the call
	 *
	 *	@param[in] n_thread_id is zero-based index of thread in the group of cooperating threads
	 *	@param[in] n_thread_num is number of threads
	 */
	virtual void Set_ThreadId(int n_thread_id, int n_thread_num) = 0;

	/**
	 *	@brief sets parallel loop counters for this call
	 *
	 *	@param[in] n_loop_counter is loop counter value
	 *	@param[in] n_chunk_size is number of elements to be processed by this call
	 *	@param[in] n_increment is increment between the consecutive elements to be processed
	 */
	virtual void Set_LoopCounter(size_t n_loop_counter, size_t n_chunk_size, size_t n_increment) = 0;

	/**
	 *	@brief duplicates instance of the call pointer, along with argument storage
	 *
	 *	This can perform duplication on heap, duplication into preallocated memory or duplication
	 *	on stack. For duplication on heap, set all the arguments to null (default). For duplication
	 *	into preallocated array, use p_placement_memory and n_placement_size. For duplication on
	 *	stack, use p_stack_dup_callback and optionally p_callback_data.
	 *
	 *	If both p_placement_memory and p_stack_dup_callback are set, a runtime assertion triggers.
	 *
	 *	Note that this function is heavily overloaded in order to save virtual entry points.
	 *	Also note that this is not supposed to be called by common users, rather by the parallel
	 *	call library.
	 *
	 *	@param[in] p_placement_memory is pointer to memory for placement new allocation (or null)
	 *	@param[in] n_placement_size is size of memory for placement new allocation (ignored if
	 *		p_placement_memory is null; if the amount of memory is too little, std::bad_alloc is thrown)
	 *	@param[in] p_stack_dup_callback is pointer to a callback for stack duplication (or null)
	 *	@param[in] p_callback_data is pointer for user data on stack (ignored if
	 *		p_stack_dup_callback is null)
	 *
	 *	@return Returns a new instance of the call pointer (the caller is responsible for deleting it).
	 *
	 *	@note This function throws std::bad_alloc.
	 */
	virtual CCallPointerEx *p_Duplicate(void *p_placement_memory = 0, size_t n_placement_size = 0,
		void (*p_stack_dup_callback)(CCallPointerEx*, void*) = 0, void *p_callback_data = 0) const = 0; // throw(std::bad_alloc)
};

/**
 *	@def DECLARE_NAMED_INTEGER
 *	@brief declares a named wrapper arround a POD
 *
 *	@param[in] name is name of the wrapper
 *	@param[in] int_type is type of the POD to be wrapped
 */
#define DECLARE_NAMED_INTEGER(name,int_type)		\
	class name {									\
	protected:										\
		int_type m_n_value; /**< @brief value */	\
													\
	public:											\
		/**											\
		 *	@brief default constructor				\
		 *	@param[in] n_value is value				\
		 */											\
		inline name(int_type n_value = 0)			\
			:m_n_value(n_value)						\
		{}											\
													\
		/**											\
		 *	@brief conversion to size_t				\
		 *	@return Returns reference to value.		\
		 */											\
		inline operator int_type &()				\
		{											\
			return m_n_value;						\
		}											\
													\
		/**											\
		 *	@brief conversion to size_t				\
		 *	@return Returns value.					\
		 */											\
		inline operator int_type() const			\
		{											\
			return m_n_value;						\
		}											\
	}

/**
 *	@brief thread id in parallel constructs
 */
DECLARE_NAMED_INTEGER(TThreadId, int);

/**
 *	@brief number of threads in parallel constructs
 */
DECLARE_NAMED_INTEGER(TThreadNum, int);

/**
 *	@brief value of the parallel loop counter
 */
DECLARE_NAMED_INTEGER(TLoopCounter, size_t);

/**
 *	@brief parallel loop increment (typically equal to the number of threads or 1)
 */
DECLARE_NAMED_INTEGER(TLoopIncrement, size_t);

/**
 *	@brief number of items processed in a single loop iteration (1 unless instructed otherwise)
 */
DECLARE_NAMED_INTEGER(TLoopChunkSize, size_t);

/**
 *	@brief namespace with function call helper functions and classes
 */
namespace function_call {

/**
 *	@brief strongly typed call pointer
 *	@tparam CCallContextType is specialization of CStaticCallContext or CMemberCallContext
 *	@note For more convenient construction, use CAutoCallPointer::p_WrapCall().
 */
template <class CCallContextType>
class CTypedCallPointer : public virtual CCallPointer {
public:
	typedef CCallContextType _TyCallContext; /**< @brief call context type */

protected:
	_TyCallContext m_t_ctx; /**< @brief call context value */

public:
	/**
	 *	@brief default constructor; wraps a statically-typed call context
	 *	@param[in] t_ctx is call context (e.g. from GetContext())
	 */
	inline CTypedCallPointer(_TyCallContext t_ctx)
		:m_t_ctx(t_ctx)
	{}

	/**
	 *	@brief copy-constructor
	 *	@param[in] r_other is pointer to copy from
	 */
	inline CTypedCallPointer(const CTypedCallPointer &r_other)
		:m_t_ctx(r_other.m_t_ctx)
	{}

	/**
	 *	@brief conversion copy-operator
	 *	@param[in] t_ctx is call context (e.g. from GetContext())
	 *	@return Returns reference to this.
	 */
	inline CTypedCallPointer &operator =(_TyCallContext t_ctx)
	{
		m_t_ctx = t_ctx;
		return *this;
	}

	/**
	 *	@brief copy-operator
	 *	@param[in] r_other is pointer to copy from
	 *	@return Returns reference to this.
	 */
	inline CTypedCallPointer &operator =(const CTypedCallPointer &r_other)
	{
		m_t_ctx = r_other.m_t_ctx;
		return *this;
	}

	/**
	 *	@brief context accessor
	 *	@return Returns const reference to the statically-typed call context.
	 */
	const _TyCallContext &t_Context() const
	{
		return m_t_ctx;
	}

	/**
	 *	@copydoc CCallPointer::Call
	 */
	virtual inline void Call()
	{
		m_t_ctx.Call(); // now Call() is virtual, no need to know type of CTypedCallPointer to make the call
	}

	/**
	 *	@brief calls the original function, with the specified context
	 *	@return Returns the return value of the original call.
	 */
	inline typename _TyCallContext::_TyResultType t_Call()
	{
		return m_t_ctx.t_Call();
	}
};

#if defined(_MSC_VER) && !defined(__MWERKS__)
#pragma warning(disable: 4250)
#endif // _MSC_VER && !__MWERKS__
// disable MSVC warning "warning C4250: 'X' : inherits 'Y::Function' via dominance"

/**
 *	@brief strongly typed extended call pointer
 *	@tparam CCallContextType is specialization of CStaticCallContext or CMemberCallContext
 *	@note For more convenient construction, use CAutoCallPointerEx::p_WrapCall().
 */
template <class CCallContextType>
class CTypedCallPointerEx : public CTypedCallPointer<CCallContextType>, public virtual CCallPointerEx {
public:
	/**
	 *	@brief default constructor; wraps a statically-typed call context
	 *	@param[in] t_ctx is call context (e.g. from GetContext())
	 */
	inline CTypedCallPointerEx(typename CTypedCallPointer<CCallContextType>::_TyCallContext t_ctx)
		:CTypedCallPointer<CCallContextType>(t_ctx)
	{}

	/**
	 *	@brief copy-constructor
	 *	@param[in] r_other is pointer to copy from
	 */
	inline CTypedCallPointerEx(const CTypedCallPointerEx &r_other)
		:CTypedCallPointer<CCallContextType>(r_other)
	{}

#if 0
	using CTypedCallPointer<CCallContextType>::Call;
	// not required by g++, ignored by MSVC

	/**
	 *	@copydoc CCallPointer::Call
	 */
	virtual inline void Call()
	{
		//((CTypedCallPointer<CCallContextType>*)this)->Call(); // causes stack overflow
		CTypedCallPointer<CCallContextType>::Call(); // this is ok
		// this is somehow required, otherwise CTypedCallPointerEx remains abstract

		// t_odo - why does this not get inherited from CTypedCallPointer<CCallContextType>?
		// this is solved by virtual inheritance, otherwise vfptr entries is duplicated

		// without this implementation, Visual C++ compilers complain of:
		// warning C4250: 'function_call::CTypedCallPointerEx<class CStaticCallContext<R, L> >' : inherits
		//		'function_call::CTypedCallPointer<class CStaticCallContext<R, L> >::Call' via dominance
		// this could be fixed by adding "using CTypedCallPointer<CCallContextType>::Call;" but that does
		// not help - this is a known bug in visual studio, it is probably safe to ignore the warning
	}
#endif // 0

	/**
	 *	@copydoc CCallPointerEx::Set_ThreadId
	 */
	virtual inline void Set_ThreadId(int n_thread_id, int n_thread_num)
	{
		CTypedCallPointer<CCallContextType>::m_t_ctx.Set_ThreadId(n_thread_id, n_thread_num);
	}

	/**
	 *	@copydoc CCallPointerEx::Set_LoopCounter
	 */
	virtual inline void Set_LoopCounter(size_t n_loop_counter, size_t n_chunk_size, size_t n_increment)
	{
		CTypedCallPointer<CCallContextType>::m_t_ctx.Set_LoopCounter(n_loop_counter, n_chunk_size, n_increment);
	}

	/**
	 *	@copydoc CCallPointerEx::p_Duplicate
	 */
	virtual CCallPointerEx *p_Duplicate(void *p_placement_memory = 0, size_t n_placement_size = 0,
		void (*p_stack_dup_callback)(CCallPointerEx*, void*) = 0, void *p_callback_data = 0) const // throw(std::bad_alloc)
	{
		_ASSERTE(!p_placement_memory || !p_stack_dup_callback); // not both at once
		if(p_stack_dup_callback) {
			CTypedCallPointerEx t_copy(*this); // copy self onto the stack
			(*p_stack_dup_callback)(&t_copy, p_callback_data); // call the callback
			return 0; // can't return reference to a local temporary
		} else if(p_placement_memory) {
			_ASSERTE(p_placement_memory);
			if(sizeof(CTypedCallPointerEx) != n_placement_size)
				throw std::bad_alloc();
			return new(p_placement_memory) CTypedCallPointerEx(*this); // placement duplication
		} else
			return new CTypedCallPointerEx(*this); // heap duplication
	}
};

#if defined(_MSC_VER) && !defined(__MWERKS__)
#pragma warning(default: 4250)
#endif // _MSC_VER && !__MWERKS__
// put it back

/**
 *	@brief namespace with msvc 6.0 specific workarrounds
 */
namespace fc_msvc6 {

/**
 *	@brief type tag (msvc 6.0 does not support explicit template function specialization)
 *	@tparam CType is type to be passed to a template function
 */
template <class CType>
struct CTypeTag {
	typedef CType _TyType; /**< @brief type to be passed to a template function */
};

/**
 *	@brief argument resolve tag (msvc 6.0 does not support explicit template function specialization)
 *
 *	@tparam CType is type of the argument
 *	@tparam _n_index is index of the argument
 */
template <class CType, const unsigned int _n_index>
struct CArgResoloveTag {
	/**
	 *	@brief argument, stored as enum
	 */
	enum {
		n_index = _n_index /**< @brief index of the argument */
	};

	typedef CType _TyType; /**< @brief type of the argument */
};

} // ~fc_msvc6

/**
 *	@brief static assetion for function calls
 *	@tparam b_expression is value of the asserted expression
 */
template <bool b_expression>
class CStaticAssert {
public:
	typedef void FUNCTIONS_WITH_MORE_THAN_16_ARGUMENTS_NOT_SUPPORTED; /**< @brief static assert tag (function argument number exceeded the limit) */
	typedef void INTERNAL_ERROR_ARGUMENT_TYPE_MISMATCH; /**< @brief static assert tag (argument type mismatch error) */
	typedef void INTERNAL_ERROR_NOT_ENOUGH_ARGUMENTS; /**< @brief static assert tag (not enough arguments error) */
};

/**
 *	@brief static assetion for function calls (specialization for assertion failed)
 */
template <>
class CStaticAssert<false> {};

/**
 *	@brief argument resolution helper template
 *
 *	@tparam CArgType is type of the expected argument
 *	@tparam _TyArg is type of argument in the currect argument storage specialization
 *	@tparam _TyNext is type of the next argument storage specialization
 *	@tparam _n_index is argument index (zero-based, counted from the current storage
 *		at each specialization recursion)
 */
template <class CArgType, class _TyArg, class _TyNext, const unsigned int _n_index>
class CArgResolver {
public:
	/**
	 *	@brief resolver implementation
	 *
	 *	@tparam n_index is argument index (zero-based, counted from the current
	 *		storage at each specialization recursion)
	 *	@tparam _GppDummy is compatibility workarround for g++ (full independent specialization inside a template)
	 */
	template <const unsigned int n_index MSVC_OMMIT_ARG(class _GppDummy)>
	class CResolver {
	public:
		/**
		 *	@copydoc CArgResolver::V
		 */
		static inline CArgType V(_TyArg UNUSED(t_arg), _TyNext &r_next)
		{
#if defined(_MSC_VER) && !defined(__MWERKS__) && _MSC_VER <= 1200
			return r_next.t_Argument6(fc_msvc6::CArgResoloveTag<CArgType, n_index - 1>());
#else // _MSC_VER && !__MWERKS__ && _MSC_VER <= 1200
			return r_next.IS_OMMIT(template) t_Argument<CArgType, n_index - 1>();
#endif // _MSC_VER && !__MWERKS__ && _MSC_VER <= 1200
		}
	};

	/**
	 *	@brief resolver implementation (specialization for zero index)
	 *	@tparam _GppDummy is compatibility workarround for g++ (full independent specialization inside a template)
	 */
	template <MSVC_OMMIT(class _GppDummy)>
	class CResolver<0 MSVC_OMMIT_ARG(_GppDummy)> {
	public:
		/**
		 *	@copydoc CArgResolver::V
		 */
		static inline CArgType V(_TyArg t_arg, _TyNext &UNUSED(r_next))
		{
			typedef typename CStaticAssert<CIsSameType<CArgType,
				_TyArg>::b_result>::INTERNAL_ERROR_ARGUMENT_TYPE_MISMATCH CAssert0;
			// make sure the types match precisely

			return t_arg;
		}
	};

public:
	/**
	 *	@brief gets value of the argument
	 *
	 *	@param[in] t_arg is value of the argument inside the currect argument storage
	 *	@param[in] r_next is value of the next argument storage specialization instance
	 */
	static inline CArgType V(_TyArg t_arg, _TyNext &r_next)
	{
		return CResolver<_n_index MSVC_OMMIT_ARG(void)>::V(t_arg, r_next);
	}
};

/**
 *	@brief late argument modification helper
 *
 *	@tparam _TyArg is type of an existing stured argument
 *	@tparam _TySetValue is type of the value to be assigned
 */
template <class _TyArg, class _TySetValue>
class CArgModifier {
public:
	/**
	 *	@brief helper class (msvc 6.0 partial specialization workarround)
	 *
	 *	@tparam b_is_same_type is type comparison flag
	 *	@tparam _GppDummy is compatibility workarround for g++ (full independent specialization inside a template)
	 */
	template <const bool b_is_same_type MSVC_OMMIT_ARG(class _GppDummy)>
	class CArgSet {
	public:
		/**
		 *	@brief assignment of a new value to an argument
		 *
		 *	@tparam CArgStorage is specialization of CArgumentStorage (CArgStorage::_TyArg must match _TyArg)
		 *
		 *	@param[out] r_dest is argument storage
		 *	@param[in] t_value is the new value of the argument
		 */
		template <class CArgStorage>
		static inline void Set_Arg(CArgStorage &r_dest, _TySetValue t_value)
		{
			r_dest.Set_ArgumentValue(t_value); // set new value
		}
	};

	/**
	 *	@brief helper class (specialization for no assignment)
	 *	@tparam _GppDummy is compatibility workarround for g++ (full independent specialization inside a template)
	 */
	template <MSVC_OMMIT(class _GppDummy)>
	class CArgSet<false MSVC_OMMIT_ARG(_GppDummy)> {
	public:
		/**
		 *	@brief empty function
		 *
		 *	@tparam CArgStorage is specialization of CArgumentStorage (CArgStorage::_TyArg must match _TyArg)
		 *
		 *	@param[out] r_dest is argument storage (unused)
		 *	@param[in] t_value is the new value of the argument (unused)
		 */
		template <class CArgStorage>
		static inline void Set_Arg(CArgStorage &UNUSED(r_dest), _TySetValue UNUSED(t_value))
		{
			// the types are different, do nothing
		}
	};

	/**
	 *	@brief result stored as enum
	 */
	enum {
		b_will_assign = CIsSameType<_TyArg, _TySetValue>::b_result /**< @brief type comparison result (if set, the assignment is effective; otherwise it is a no-op) */
	};

public:
	/**
	 *	@brief tries to set an argument
	 *
	 *	@tparam CArgStorage is specialization of CArgumentStorage (CArgStorage::_TyArg must match _TyArg)
	 *
	 *	@param[out] r_dest is argument storage
	 *	@param[in] t_value is the new value of the argument
	 */
	template <class CArgStorage>
	static inline void Set_Arg(CArgStorage &r_dest, _TySetValue t_value)
	{
		typedef MSVC6_OMMIT(typename) CStaticAssert<CIsSameType<_TyArg,
			MSVC6_OMMIT(typename) CArgStorage::_TyArg>::b_result>::INTERNAL_ERROR_ARGUMENT_TYPE_MISMATCH CAssert;
		// the types must match here

		CArgSet<b_will_assign MSVC_OMMIT_ARG(void)>::Set_Arg(r_dest, t_value);
	}
};

/**
 *	@brief function arguments storage
 *	@tparam CArgType_List is typelist containing types of function arguments
 *	@note This is variable-sized, no limit to the number of arguments (it could be slightly simpler to fix the number of arguments to 0-16 and provide specializations, then the whole CArgResolver would not have to be there, but it would still arguably be longer code and less flexible).
 *	@todo Think about how it orders the arguments, in case it is stored on the stack, provide a macro to reverse the storage order (easily swapped by swapping m_arg and m_tail, no other modifications required). Does \#pragma pack apply here?
 */
template <class CArgType_List>
class CArgumentStorage {
public:
	typedef typename CArgType_List::CHead _TyArg; /**< @brief argument type stored in this instance */
	typedef CArgumentStorage<typename CArgType_List::CTail> _TyNext; /**< @brief type of the recurrent instances */

protected:
#ifdef __FUNCTION_CALL_ARG_STORAGE_SWAP_ORDER
	_TyNext m_tail; /**< @brief values of the rest of the arguments */
	_TyArg m_arg; /**< @brief value of the argument */
#else // __FUNCTION_CALL_ARG_STORAGE_SWAP_ORDER
	_TyArg m_arg; /**< @brief value of the argument */
	_TyNext m_tail; /**< @brief values of the rest of the arguments */
#endif // __FUNCTION_CALL_ARG_STORAGE_SWAP_ORDER

public:
	/**
	 *	@brief default constructor; this should never be called
	 */
	inline CArgumentStorage()
	{
		//typedef CStaticAssert<false>::INTERNAL_ERROR_NOT_ENOUGH_ARGUMENTS CAssert0; // g++ compiles this, triggers the exception
		_ASSERTE(0);
		// not enough arguments, m_arg uninitialized; this should never get called, though
	}

	/**
	 *	@brief constructor; initializes a single argument
	 *	@param[in] t_arg0 is value of the argument
	 *	@note This must not be a template, no way to specialize it, drops references otherwise.
	 */
	inline CArgumentStorage(_TyArg t_arg0)
#ifdef __FUNCTION_CALL_ARG_STORAGE_SWAP_ORDER
		:m_tail(), m_arg(t_arg0) // just to avoid g++ warning "m_arg will be initialized after m_tail"
#else // __FUNCTION_CALL_ARG_STORAGE_SWAP_ORDER
		:m_arg(t_arg0), m_tail()
#endif // __FUNCTION_CALL_ARG_STORAGE_SWAP_ORDER
	{}

	/**
	 *	@brief constructor; initializes the next argument in an argument list
	 *
	 *	@param[in] t_arg0 is value of the argument
	 *	@param[in] tail_values is value of the rest of the arguments
	 *	@note This must not be a template, no way to specialize it, drops references otherwise.
	 */
	inline CArgumentStorage(_TyArg t_arg0, _TyNext tail_values)
#ifdef __FUNCTION_CALL_ARG_STORAGE_SWAP_ORDER
		:m_tail(tail_values), m_arg(t_arg0) // just to avoid g++ warning "m_arg will be initialized after m_tail"
#else // __FUNCTION_CALL_ARG_STORAGE_SWAP_ORDER
		:m_arg(t_arg0), m_tail(tail_values)
#endif // __FUNCTION_CALL_ARG_STORAGE_SWAP_ORDER
	{}

	/**
	 *	@brief copy-constructor
	 *	@param[in] r_other is reference to the copied argument storage
	 */
	inline CArgumentStorage(const CArgumentStorage<CArgType_List> &r_other)
#ifdef __FUNCTION_CALL_ARG_STORAGE_SWAP_ORDER
		:m_tail(r_other.m_tail), m_arg(r_other.m_arg) // just to avoid g++ warning "m_arg will be initialized after m_tail"
#else // __FUNCTION_CALL_ARG_STORAGE_SWAP_ORDER
		:m_arg(r_other.m_arg), m_tail(r_other.m_tail)
#endif // __FUNCTION_CALL_ARG_STORAGE_SWAP_ORDER
	{}

	/*template <class TPrev>
	inline CArgumentStorage<CTypelist<TPrev, CArgType_List> > operator <<(TPrev t_prev_arg)
	{
		return CArgumentStorage<CTypelist<TPrev, CArgType_List> >(t_prev_arg, *this);
	}*/
	// can't be used, need explicit specialization as the implicit specialization drops references. use Push() instead

	/**
	 *	@brief argument chaining operator
	 *	@tparam TPrev is type of the argument that precedes the existing chain
	 *	@param[in] t_prev_arg is value of the argument that precedes the existing chain
	 *	@return Returns this argument list with the specified argument prepended.
	 */
	template <class TPrev>
	inline CArgumentStorage<CTypelist<TPrev, CArgType_List> > Push(TPrev t_prev_arg) // wow
	{
		return CArgumentStorage<CTypelist<TPrev, CArgType_List> >(t_prev_arg, *this);
	}

	/**
	 *	@brief argument chaining operator for msvc 6.0
	 *
	 *	@tparam TPrevWrap is wrapper with the type of the argument that precedes the existing chain
	 *
	 *	@param[in] t_type_tag is type tag (value unused; msvc 6.0 doesn't support explicit function
	 *		template specialization; see fc_msvc6::CTypeTag)
	 *	@param[in] t_prev_arg is value of the argument that precedes the existing chain
	 *
	 *	@return Returns this argument list with the specified argument prepended.
	 */
	template <class TPrevWrap>
	inline CArgumentStorage<CTypelist<typename TPrevWrap::_TyType, CArgType_List> >
		Push6(TPrevWrap UNUSED(t_type_tag), typename TPrevWrap::_TyType t_prev_arg) // for msvc 6.0
	{
		return CArgumentStorage<CTypelist<MSVC6_OMMIT(typename) TPrevWrap::_TyType,
			CArgType_List> >(t_prev_arg, *this);
	}

	/**
	 *	@brief argument access function
	 *
	 *	@tparam CArgType is the expected argument type (must match the real argument
	 *		type, otherwise static assertion is triggered)
	 *	@tparam n_index is zero-based argument index, counted from this argument
	 *
	 *	@return Returns the value of the argument, or <tt>int(0)</tt> in case the index
	 *		is greater or equal to the number of arguments.
	 */
	template <class CArgType, const unsigned int n_index>
	inline CArgType t_Argument()
	{
		return CArgResolver<CArgType, _TyArg, _TyNext, n_index>::V(m_arg, m_tail);
	}

	/**
	 *	@brief argument access function (version for msvc 6.0)
	 *	@tparam CResolver is specialization of fc_msvc6::CArgResoloveTag, containing
	 *		the expected argument type (must match the real argument
	 *		type, otherwise static assertion is triggered) and the zero-based
	 *		argument index, counted from this argument
	 *	@param[in] t_resolver_tag is resolver tag value (unused)
	 *	@return Returns the value of the argument, or <tt>int(0)</tt> in case the index
	 *		is greater or equal to the number of arguments.
	 */
	template <class CResolver>
	inline typename CResolver::_TyType t_Argument6(CResolver UNUSED(t_resolver_tag))
	{
		return CArgResolver<MSVC6_OMMIT(typename) CResolver::_TyType, _TyArg,
			_TyNext, CResolver::n_index>::V(m_arg, m_tail);
	}

	/**
	 *	@brief sets value of the first argument of the given type
	 *	@tparam CArgType is type of argument to set
	 *	@param[in] t_argument is the new value of the argument
	 */
	template <class CArgType>
	inline void Set_FirstArgOfType(CArgType t_argument)
	{
		if(CArgModifier<_TyArg, CArgType>::b_will_assign) { // compile-time constant
			CArgModifier<_TyArg, CArgType>::Set_Arg(*this, t_argument);
			// this only contains the assignment if the types match, otherwise it is an empty statement
		} else
			m_tail.Set_FirstArgOfType(t_argument);
	}

	/**
	 *	@brief sets value of this argument
	 *	@tparam CArgType is type of argument to set (must match _TyArg)
	 *	@param[in] t_argument is the new value of the argument
	 *	@note This is a template to avoid problems with references. Arguments
	 *		of type reference can not be changed once constructed.
	 */
	template <class CArgType>
	inline void Set_ArgumentValue(CArgType t_argument)
	{
		m_arg = t_argument;
	}
};

/**
 *	@brief function arguments storage (specialization for no arguments / argument chain end)
 */
template <>
class CArgumentStorage<CTypelistEnd> {
public:
	typedef int _TyArg; /**< @brief type of the argument */

public:
	/**
	 *	@brief default constructor (can be called, has no effect)
	 */
	inline CArgumentStorage()
	{}

	/**
	 *	@brief copy-constructor
	 *	@param[in] r_other is argument storage to copy from (holds no data, unused)
	 */
	inline CArgumentStorage(const CArgumentStorage<CTypelistEnd> &UNUSED(r_other))
	{}

	/*template <class TPrev>
	inline CArgumentStorage<MakeTypelist1(TPrev)> operator <<(TPrev t_prev_arg)
	{
		return CArgumentStorage<MakeTypelist1(TPrev)>(t_prev_arg);
	}*/
	// can't be used, need explicit specialization as the implicit specialization drops references. use Push() instead

	/**
	 *	@brief argument chaining operator
	 *	@tparam TPrev is type of the first argument
	 *	@param[in] t_first_arg is value of the first argument
	 *	@return Returns a new argument list with the specified argument.
	 */
	template <class TPrev>
	inline CArgumentStorage<MakeTypelist1(TPrev)> Push(TPrev t_first_arg) // construction shift operator
	{
		return CArgumentStorage<MakeTypelist1(TPrev)>(t_first_arg);
	}

	/**
	 *	@brief argument chaining operator for msvc 6.0
	 *
	 *	@tparam TPrevWrap is wrapper with the type of the argument that precedes the existing chain
	 *
	 *	@param[in] t_type_tag is type tag (value unused; msvc 6.0 doesn't support explicit function
	 *		template specialization; see fc_msvc6::CTypeTag)
	 *	@param[in] t_first_arg is value of the first argument
	 *
	 *	@return Returns a new argument list with the specified argument.
	 */
	template <class TPrevWrap>
	inline CArgumentStorage<MakeTypelist1(typename TPrevWrap::_TyType)>
		Push6(TPrevWrap t_type_tag, typename TPrevWrap::_TyType t_first_arg) // for msvc 6.0
	{
		return CArgumentStorage<MakeTypelist1(MSVC6_OMMIT(typename) TPrevWrap::_TyType)>(t_first_arg);
	}

	/**
	 *	@brief argument access function
	 *
	 *	@tparam CArgType is the expected argument type (must match the real argument
	 *		type, otherwise static assertion is triggered)
	 *	@tparam n_index is zero-based argument index, counted from this argument
	 *
	 *	@return Always returns <tt>int(0)</tt>.
	 */
	template <class CArgType, const unsigned int n_index>
	inline int t_Argument()
	{
		return 0; // always zero, this is just to satisfy semantic checks on the longer calls which will never be called
	}

	/**
	 *	@brief argument access function (version for msvc 6.0)
	 *	@tparam CResolver is specialization of fc_msvc6::CArgResoloveTag, containing
	 *		the expected argument type (must match the real argument
	 *		type, otherwise static assertion is triggered) and the zero-based
	 *		argument index, counted from this argument
	 *	@param[in] t_resolver_tag is resolver tag value (unused)
	 *	@return Always returns <tt>int(0)</tt>.
	 */
	template <class CResolver>
	inline int t_Argument6(CResolver t_resolver_tag)
	{
		return 0; // always zero, this is just to satisfy semantic checks on the longer calls which will never be called
	}

	/**
	 *	@brief sets value of the first argument of the given type
	 *	@tparam CArgType is type of argument to set
	 *	@param[in] t_arg_type is value of the argument (unused)
	 *	@note The absence of the argument is silently ignored. This is the intended behavior.
	 */
	template <class CArgType>
	inline void Set_FirstArgOfType(CArgType UNUSED(t_arg_type))
	{}
};

template <class CFunUtil, const unsigned int n_arg_num>
class CArgsInitializer; // forward declaraion

/**
 *	@brief call signature template
 *	@tparam CFunUtil is specialization of function_call::CStaticFunctionUtils
 *		or function_call::CMemberFunctionUtils
 *	@note This will work with any number of arguments.
 */
template <class CFunUtil>
class CCallSignature {
public:
	typedef typename CFunUtil::_TyContextData _TyContextData; /**< @copydoc  function_call::CStaticFunctionUtils::_TyContextData */
	typedef CArgsInitializer<CFunUtil, CFunUtil::n_arg_num> CInitializer; /**< @brief argument initializer template specialization */

protected:
	_TyContextData m_t_context; /**< @brief call context data */

public:
	/**
	 *	@brief default constructor
	 *	@param[in] t_context is call context data
	 */
	inline CCallSignature(_TyContextData t_context)
		:m_t_context(t_context)
	{}

	/**
	 *	@brief gets argument initilaizer object
	 *	@return Returns an instance of the argument initilaizer object.
	 */
	inline CInitializer Initializer()
	{
		return CInitializer(m_t_context);
	}
};

template <class CResultType, class CArgType_List>
class CStaticFunctionUtils; // forward declaration

template <class CClassType, class CResultType, class CArgType_List, const bool b_is_const_function = false>
class CMemberFunctionUtils; // forward declaration

} // ~function_call

/**
 *	@brief static function call context template
 *
 *	@tparam CResultType is data type of function call result
 *	@tparam CArgType_List is typelist containing types of function arguments
 */
template <class CResultType, class CArgType_List>
class CStaticCallContext { // want this in the global namespace
public:
	typedef function_call::CStaticFunctionUtils<CResultType, CArgType_List> _TyFunUtil; /**< @brief specialization of function_call::CStaticFunctionUtils */
	typedef CArgType_List _TyArgType_List; /**< @copydoc function_call::CStaticFunctionUtils::_TyArgType_List */
	typedef CResultType _TyResultType; /**< @copydoc function_call::CStaticFunctionUtils::_TyResultType  */
	typedef typename _TyFunUtil::_TyContextData _TyContextData; /**< @copydoc function_call::CStaticFunctionUtils::_TyContextData  */
	typedef function_call::CArgumentStorage<_TyArgType_List> _TyArgStorage; /**< @brief function arguments storage */
	typedef function_call::CTypedCallPointer<CStaticCallContext<CResultType, CArgType_List> > _TyPointer; /**< @brief call pointer type (CTypedCallPointer specialization) */
	typedef function_call::CTypedCallPointerEx<CStaticCallContext<CResultType, CArgType_List> > _TyExPtr; /**< @brief extended call pointer type (CTypedCallPointerEx specialization) */

protected:
	_TyContextData m_p_func; /**< @brief pointer to the function */
	_TyArgStorage m_arg_values; /**< @brief values of the arguments */

public:
	/**
	 *	@brief default constructor
	 *
	 *	@param[in] t_context is call context data (a pointer to the function)
	 *	@param[in] r_args is reference to the values of the arguments
	 */
	inline CStaticCallContext(_TyContextData t_context, const _TyArgStorage &r_args)
		:m_p_func(t_context), m_arg_values(r_args)
	{}

	/**
	 *	@copydoc function_call::CArgumentStorage::Set_FirstArgOfType
	 */
	template <class CArgType>
	inline void Set_FirstArgOfType(CArgType t_argument)
	{
		m_arg_values.Set_FirstArgOfType(t_argument);
	}

	/**
	 *	@copydoc CCallPointerEx::Set_ThreadId
	 */
	inline void Set_ThreadId(int n_thread_id, int n_thread_num)
	{
		Set_FirstArgOfType(TThreadId(n_thread_id));
		Set_FirstArgOfType(TThreadNum(n_thread_num));
	}

	/**
	 *	@copydoc CCallPointerEx::Set_LoopCounter
	 */
	inline void Set_LoopCounter(size_t n_loop_counter, size_t n_chunk_size, size_t n_increment)
	{
		Set_FirstArgOfType(TLoopCounter(n_loop_counter));
		Set_FirstArgOfType(TLoopChunkSize(n_chunk_size));
		Set_FirstArgOfType(TLoopIncrement(n_increment));
	}

	/**
	 *	@brief calls the function
	 *	@return Returns the result of the function call.
	 *	@note This may throw exceptions, generated by the original function.
	 */
	inline _TyResultType t_Call()
	{
		_ASSERTE(m_p_func);
		return _TyFunUtil::t_Call(m_p_func, m_arg_values);
	}

	/**
	 *	@brief calls the function
	 *
	 *	@note This may throw exceptions, generated by the original function.
	 */
	inline void Call()
	{
		_ASSERTE(m_p_func);
		_TyFunUtil::t_Call(m_p_func, m_arg_values);
	}
};

/**
 *	@brief member function call context template
 *
 *	@tparam CClassType is type of the class the function is member of (without a const qualifier)
 *	@tparam CResultType is data type of function call result
 *	@tparam CArgType_List is typelist containing types of function arguments
 *	@tparam b_is_const_function is const function flag (set if the member function is declared as const)
 */
template <class CClassType, class CResultType, class CArgType_List, const bool b_is_const_function = false>
class CMemberCallContext { // want this in the global namespace
public:
	typedef function_call::CMemberFunctionUtils<CClassType, CResultType, CArgType_List, b_is_const_function> _TyFunUtil; /**< @brief specialization of function_call::CMemberFunctionUtils */
	typedef CArgType_List _TyArgType_List; /**< @copydoc function_call::CMemberFunctionUtils::_TyArgType_List */
	typedef CResultType _TyResultType; /**< @copydoc function_call::CMemberFunctionUtils::_TyResultType */
	typedef typename _TyFunUtil::_TyContextData _TyContextData; /**< @copydoc function_call::CMemberFunctionUtils::_TyContextData */
	typedef function_call::CArgumentStorage<_TyArgType_List> _TyArgStorage; /**< @brief function arguments storage */
	typedef function_call::CTypedCallPointer<CMemberCallContext<CClassType, CResultType, CArgType_List, b_is_const_function> > _TyPointer; /**< @brief call pointer type (CTypedCallPointer specialization) */
	typedef function_call::CTypedCallPointerEx<CMemberCallContext<CClassType, CResultType, CArgType_List, b_is_const_function> > _TyExPtr; /**< @brief extended call pointer type (CTypedCallPointerEx specialization) */

protected:
	_TyContextData m_t_data; /**< @brief pointer to the object in context and ot the function */
	_TyArgStorage m_arg_values; /**< @brief values of the arguments */

public:
	/**
	 *	@brief default constructor
	 *
	 *	@param[in] t_context is call context data (a pointer to the object and to the function)
	 *	@param[in] r_args is reference to the values of the arguments
	 */
	inline CMemberCallContext(_TyContextData t_context, const _TyArgStorage &r_args)
		:m_t_data(t_context), m_arg_values(r_args)
	{}

	/**
	 *	@copydoc function_call::CArgumentStorage::Set_FirstArgOfType
	 */
	template <class CArgType>
	inline void Set_FirstArgOfType(CArgType t_argument)
	{
		m_arg_values.Set_FirstArgOfType(t_argument);
	}

	/**
	 *	@copydoc CCallPointerEx::Set_ThreadId
	 */
	inline void Set_ThreadId(int n_thread_id, int n_thread_num)
	{
		Set_FirstArgOfType(TThreadId(n_thread_id));
		Set_FirstArgOfType(TThreadNum(n_thread_num));
	}

	/**
	 *	@copydoc CCallPointerEx::Set_LoopCounter
	 */
	inline void Set_LoopCounter(size_t n_loop_counter, size_t n_chunk_size, size_t n_increment)
	{
		Set_FirstArgOfType(TLoopCounter(n_loop_counter));
		Set_FirstArgOfType(TLoopChunkSize(n_chunk_size));
		Set_FirstArgOfType(TLoopIncrement(n_increment));
	}

	/**
	 *	@brief calls the function
	 *	@return Returns the result of the function call.
	 *	@note This may throw exceptions, generated by the original function.
	 */
	inline _TyResultType t_Call()
	{
		_ASSERTE(m_t_data.first && m_t_data.second);
		return _TyFunUtil::t_Call(m_t_data.first, m_t_data.second, m_arg_values);
	}

	/**
	 *	@brief calls the function
	 *
	 *	@note This may throw exceptions, generated by the original function.
	 */
	inline void Call()
	{
		_ASSERTE(m_t_data.first && m_t_data.second);
		_TyFunUtil::t_Call(m_t_data.first, m_t_data.second, m_arg_values);
	}
};

/**
 *	@brief automatically managed call pointer
 */
class CAutoCallPointer {
protected:
	mutable CCallPointer *m_p_pointer; /**< @brief the managed call pointer */

public:
	/**
	 *	@brief default constructor; initializes to null pointer
	 */
	inline CAutoCallPointer()
		:m_p_pointer(0)
	{}

#if 1
	/**
	 *	@brief conversion constructor; creates a managed function pointer from a call context
	 *	@tparam CCallContextType is specialization of CStaticCallContext or CMemberCallContext
	 *	@param[in] t_call_context is call context value
	 *	@note This function throws std::bad_alloc.
	 */
	template <class CCallContextType>
	inline CAutoCallPointer(CCallContextType t_call_context) // throw(std::bad_alloc)
		:m_p_pointer(p_WrapCall(t_call_context))
	{}
#else // 1
	template <class CReturnType, class CArgTypeList>
	inline CAutoCallPointer(CStaticCallContext<CReturnType, CArgTypeList> t_call_context) // throw(std::bad_alloc)
		:m_p_pointer(p_WrapCall(t_call_context))
	{}

	template <class CClassType, class CReturnType, class CArgTypeList, const bool b_is_const>
	inline CAutoCallPointer(CMemberCallContext<CClassType, CReturnType, CArgTypeList, b_is_const> t_call_context) // throw(std::bad_alloc)
		:m_p_pointer(p_WrapCall(t_call_context))
	{}
#endif // 1

	/**
	 *	@brief copy-constructor
	 *	@param[in,out] r_pointer is pointer to copy from (loses ownership of the pointer)
	 */
	inline CAutoCallPointer(const CAutoCallPointer &r_pointer)
		:m_p_pointer(r_pointer.m_p_pointer)
	{
		r_pointer.m_p_pointer = 0; // releases the pointer in favor of this
	}

	/**
	 *	@brief destructor; deletes the object pointed to
	 */
	inline ~CAutoCallPointer()
	{
		if(m_p_pointer)
			delete m_p_pointer; // in case it was not passed on
	}

#if 1
	/**
	 *	@brief conversion copy operator; creates a managed function pointer from a call context
	 *
	 *	@tparam CCallContextType is specialization of CStaticCallContext or CMemberCallContext
	 *
	 *	@param[in] t_call_context is call context value
	 *
	 *	@note The original object pointed to by this is deleted (if any).
	 *	@note This function throws std::bad_alloc.
	 */
	template <class CCallContextType>
	inline CAutoCallPointer &operator =(CCallContextType t_call_context) // throw(std::bad_alloc)
	{
		Reset(p_WrapCall(t_call_context));
		return *this;
	}
#else // 1
	template <class CReturnType, class CArgTypeList>
	inline CAutoCallPointer &operator =(CStaticCallContext<CReturnType, CArgTypeList> t_call_context) // throw(std::bad_alloc)
	{
		Reset(p_WrapCall(t_call_context));
		return *this;
	}

	template <class CClassType, class CReturnType, class CArgTypeList, bool b_is_const>
	inline CAutoCallPointer &operator =(CMemberCallContext<CClassType, CReturnType, CArgTypeList, b_is_const> t_call_context) // throw(std::bad_alloc)
	{
		Reset(p_WrapCall(t_call_context));
		return *this;
	}
#endif // 1

	/**
	 *	@brief copy operator
	 *	@param[in,out] r_pointer is pointer to copy from (loses ownership of the pointer)
	 *	@note The original object pointed to by this is deleted (if any).
	 */
	inline CAutoCallPointer &operator =(const CAutoCallPointer &r_pointer)
	{
		Reset(r_pointer.m_p_pointer);
		r_pointer.m_p_pointer = 0; // releases the pointer in favor of this
		return *this;
	}

	/**
	 *	@brief conversion to bool
	 *	@return Returns false if this is a null pointer, otherwise returns true.
	 */
	inline operator bool() const
	{
		return m_p_pointer != 0;
	}

	/**
	 *	@brief sets a new pointer
	 *	@param[in] p_pointer is the new value of the pointer
	 *	@note The original object pointed to by this is deleted (if any).
	 */
	inline void Reset(CCallPointer *p_pointer = 0)
	{
		if(m_p_pointer)
			delete m_p_pointer;
		m_p_pointer = p_pointer;
	}

	/**
	 *	@brief gets value of the managed pointer
	 *	@return Returns the value of the managed pointer.
	 *	@note The pointer remains managed and will be automatically
	 *		deleted by this object. The caller must not delete it.
	 */
	inline CCallPointer *p_Get()
	{
		return m_p_pointer;
	}

	/**
	 *	@brief releases ownership of the managed pointer
	 *	@return Returns the value of the managed pointer.
	 *	@note The pointer is no longer managed and will not be automatically
	 *		deleted by this object. The caller is now respoinsinle for deleting it.
	 */
	inline CCallPointer *p_Release()
	{
		CCallPointer *p_context = m_p_pointer;
		m_p_pointer = 0;
		return p_context;
	}

	/**
	 *	@brief member access operator
	 *	@return Returns a pointer to the managed object for member lookup.
	 */
	inline CCallPointer *operator ->()
	{
		_ASSERTE(m_p_pointer);
		return m_p_pointer; // now we can use ->Call()
		// is this a design flaw? it does not zero out the pointer
		// no it is not, it can't be used to get the pointer, only to access its members.
	}

	/**
	 *	@brief indirection operator
	 *	@return Returns a reference to the managed object.
	 *	@note The pointer remains managed and will be automatically
	 *		deleted by this object. The caller must not delete it.
	 */
	inline CCallPointer &operator *()
	{
		_ASSERTE(m_p_pointer);
		return *m_p_pointer;
	}

	/**
	 *	@brief swaps two managed call pointers
	 *	@param[in,out] r_pointer is the other pointer to swap with
	 */
	inline void Swap(CAutoCallPointer &r_pointer)
	{
		CCallPointer *p_tmp = m_p_pointer;
		m_p_pointer = r_pointer.m_p_pointer;
		r_pointer.m_p_pointer = p_tmp;
	}

	/**
	 *	@brief creates a strongly typed call context on heap from a call context
	 *	@tparam CCallContextType is specialization of CStaticCallContext or CMemberCallContext
	 *	@param[in] t_call_context is call context value
	 *	@return Returns strongly typed extended call context (the caller is responsible for deleting it).
	 *	@note This function throws std::bad_alloc.
	 */
	template <class CCallContextType>
	static inline CCallPointer *p_WrapCall(CCallContextType t_call_context) // throw(std::bad_alloc)
	{
		return new function_call::CTypedCallPointer<CCallContextType>(t_call_context);
	}
};

/**
 *	@brief automatically managed extended call pointer
 *	@note This does not inherit from CAutoCallPointer. This is intended.
 */
class CAutoCallPointerEx {
protected:
	mutable CCallPointerEx *m_p_pointer; /**< @brief the managed call pointer */

public:
	/**
	 *	@brief default constructor; initializes to null pointer
	 */
	inline CAutoCallPointerEx()
		:m_p_pointer(0)
	{}

#if 1
	/**
	 *	@brief conversion constructor; creates a managed function pointer from a call context
	 *	@tparam CCallContextType is specialization of CStaticCallContext or CMemberCallContext
	 *	@param[in] t_call_context is call context value
	 *	@note This function throws std::bad_alloc.
	 */
	template <class CCallContextType>
	inline CAutoCallPointerEx(CCallContextType t_call_context) // throw(std::bad_alloc)
		:m_p_pointer(p_WrapCall(t_call_context))
	{}
#else // 1
	template <class CReturnType, class CArgTypeList>
	inline CAutoCallPointerEx(CStaticCallContext<CReturnType, CArgTypeList> t_call_context) // throw(std::bad_alloc)
		:m_p_pointer(p_WrapCall(t_call_context))
	{}

	template <class CClassType, class CReturnType, class CArgTypeList, const bool b_is_const>
	inline CAutoCallPointerEx(CMemberCallContext<CClassType, CReturnType, CArgTypeList, b_is_const> t_call_context) // throw(std::bad_alloc)
		:m_p_pointer(p_WrapCall(t_call_context))
	{}
#endif // 1

	/**
	 *	@brief constructor
	 *	@param[in] p_pointer is pointer to a call
	 */
	inline CAutoCallPointerEx(CCallPointerEx *p_pointer) // required for correct construction with ->p_Duplicate()
		:m_p_pointer(p_pointer)
	{}

	/**
	 *	@brief copy-constructor
	 *	@param[in,out] r_pointer is pointer to copy from (loses ownership of the pointer)
	 */
	inline CAutoCallPointerEx(const CAutoCallPointerEx &r_pointer)
		:m_p_pointer(r_pointer.m_p_pointer)
	{
		r_pointer.m_p_pointer = 0; // releases the pointer in favor of this
	}

	/**
	 *	@brief destructor; deletes the object pointed to
	 */
	inline ~CAutoCallPointerEx()
	{
		if(m_p_pointer)
			delete m_p_pointer; // in case it was not passed on
	}

#if 1
	/**
	 *	@brief conversion copy operator; creates a managed function pointer from a call context
	 *
	 *	@tparam CCallContextType is specialization of CStaticCallContext or CMemberCallContext
	 *
	 *	@param[in] t_call_context is call context value
	 *
	 *	@note The original object pointed to by this is deleted (if any).
	 *	@note This function throws std::bad_alloc.
	 */
	template <class CCallContextType>
	inline CAutoCallPointerEx &operator =(CCallContextType t_call_context) // throw(std::bad_alloc)
	{
		Reset(p_WrapCall(t_call_context));
		return *this;
	}
#else // 1
	template <class CReturnType, class CArgTypeList>
	inline CAutoCallPointerEx &operator =(CStaticCallContext<CReturnType, CArgTypeList> t_call_context) // throw(std::bad_alloc)
	{
		Reset(p_WrapCall(t_call_context));
		return *this;
	}

	template <class CClassType, class CReturnType, class CArgTypeList, bool b_is_const>
	inline CAutoCallPointerEx &operator =(CMemberCallContext<CClassType, CReturnType, CArgTypeList, b_is_const> t_call_context) // throw(std::bad_alloc)
	{
		Reset(p_WrapCall(t_call_context));
		return *this;
	}
#endif // 1

	/**
	 *	@brief copy operator
	 *	@param[in,out] r_pointer is pointer to copy from (loses ownership of the pointer)
	 *	@note The original object pointed to by this is deleted (if any).
	 */
	inline CAutoCallPointerEx &operator =(const CAutoCallPointerEx &r_pointer)
	{
		Reset(r_pointer.m_p_pointer);
		r_pointer.m_p_pointer = 0; // releases the pointer in favor of this
		return *this;
	}

	/**
	 *	@brief conversion to bool
	 *	@return Returns false if this is a null pointer, otherwise returns true.
	 */
	inline operator bool() const
	{
		return m_p_pointer != 0;
	}

	/**
	 *	@brief sets a new pointer
	 *	@param[in] p_pointer is the new value of the pointer
	 *	@note The original object pointed to by this is deleted (if any).
	 */
	inline void Reset(CCallPointerEx *p_pointer = 0)
	{
		if(m_p_pointer)
			delete m_p_pointer;
		m_p_pointer = p_pointer;
	}

	/**
	 *	@brief gets value of the managed pointer
	 *	@return Returns the value of the managed pointer.
	 *	@note The pointer remains managed and will be automatically
	 *		deleted by this object. The caller must not delete it.
	 */
	inline CCallPointerEx *p_Get()
	{
		return m_p_pointer;
	}

	/**
	 *	@brief releases ownership of the managed pointer
	 *	@return Returns the value of the managed pointer.
	 *	@note The pointer is no longer managed and will not be automatically
	 *		deleted by this object. The caller is now respoinsinle for deleting it.
	 */
	inline CCallPointerEx *p_Release()
	{
		CCallPointerEx *p_context = m_p_pointer;
		m_p_pointer = 0;
		return p_context;
	}

	/**
	 *	@brief member access operator
	 *	@return Returns a pointer to the managed object for member lookup.
	 */
	inline CCallPointerEx *operator ->()
	{
		_ASSERTE(m_p_pointer);
		return m_p_pointer; // now we can use ->Call()
		// is this a design flaw? it does not zero out the pointer
		// no it is not, it can't be used to get the pointer, only to access its members.
	}

	/**
	 *	@brief indirection operator
	 *	@return Returns a reference to the managed object.
	 *	@note The pointer remains managed and will be automatically
	 *		deleted by this object. The caller must not delete it.
	 */
	inline CCallPointerEx &operator *()
	{
		_ASSERTE(m_p_pointer);
		return *m_p_pointer;
	}

	/**
	 *	@brief swaps two managed call pointers
	 *	@param[in,out] r_pointer is the other pointer to swap with
	 */
	inline void Swap(CAutoCallPointerEx &r_pointer)
	{
		CCallPointerEx *p_tmp = m_p_pointer;
		m_p_pointer = r_pointer.m_p_pointer;
		r_pointer.m_p_pointer = p_tmp;
	}

	/**
	 *	@brief creates a strongly typed extended call context on heap from a call context
	 *	@tparam CCallContextType is specialization of CStaticCallContext or CMemberCallContext
	 *	@param[in] t_call_context is call context value
	 *	@return Returns strongly typed extended call context (the caller is responsible for deleting it).
	 *	@note This function throws std::bad_alloc.
	 */
	template <class CCallContextType>
	static inline CCallPointerEx *p_WrapCall(CCallContextType t_call_context) // throw(std::bad_alloc)
	{
		return new function_call::CTypedCallPointerEx<CCallContextType>(t_call_context);
	}
};

// add std::swap for managed call pointers
namespace std {

/**
 *	@brief swaps two managed call pointers
 *
 *	@param[in,out] r_first is the first pointer to swap
 *	@param[in,out] r_second is the second pointer to swap
 */
inline void swap(CAutoCallPointer &r_first, CAutoCallPointer &r_second)
{
	r_first.Swap(r_second);
}

/**
 *	@brief swaps two managed call pointers
 *
 *	@param[in,out] r_first is the first pointer to swap
 *	@param[in,out] r_second is the second pointer to swap
 */
inline void swap(CAutoCallPointerEx &r_first, CAutoCallPointerEx &r_second)
{
	r_first.Swap(r_second);
}

} // ~std

// todo - come up with a "call pointer bundle" for batch/parallel task definition
//		where the storage for the pointers is pooled to improve locality of reference
//		and to reduce the number of malloc() / new calls

#if !defined(_MSC_VER) || defined(__MWERKS__) || _MSC_VER >= 1400

/**
 *	@def GetSignature
 *	@brief gets a static function call signature
 *	@param[in] p_function_pointer is static function pointer
 *	@note This safely supports implicit type casts.
 */
#define GetSignature(p_function_pointer) (function_call::GetCallSignature((p_function_pointer)))
// here we can basically eliminate the macro and use the function directly

/**
 *	@def GetSignature
 *	@brief gets a member function call signature
 *
 *	@param[in] p_class_pointer is pointer to an instance of the class
 *	@param[in] p_function_pointer is class member function pointer
 *
 *	@note This safely supports implicit type casts.
 *	@todo Think of a better name.
 */
#define GetMemSignature(p_class_pointer,p_function_pointer) \
	(function_call::GetMemCallSignature((p_class_pointer), (p_function_pointer)))
// here we can basically eliminate the macro and use the function directly

/**
 *	@def GetContext
 *
 *	@brief gets a function call context
 *
 *	@param[in] p_function_pointer is static function pointer
 *	@param[in] ... is list of argument values
 *
 *	@note This safely supports implicit type casts.
 *	@note This is not available in msvc 6.0 as it doesn't support variadic macros.
 */
#define GetContext(p_function_pointer,...) (GetSignature((p_function_pointer))(__VA_ARGS__))

#else // !_MSC_VER || __MWERKS__ || _MSC_VER >= 1400

/**
 *	@def GetSignature
 *	@brief gets a function call signature
 *	@param[in] p_function_pointer is static function pointer
 *	@note This safely supports implicit type casts.
 */
#define GetSignature(p_function_pointer) (function_call::GetCallSignature((p_function_pointer)).Get())
// no need for variadic macros with this construct, works with msvc 6.0 as well
// note that msvc 6.0 can't get rid of the .Get() due to the order of instantiation
// (it is not possible to call it inside GetCallSignature())

/**
 *	@def GetSignature
 *	@brief gets a member function call signature
 *
 *	@param[in] p_class_pointer is pointer to an instance of the class
 *	@param[in] p_function_pointer is class member function pointer
 *
 *	@note This safely supports implicit type casts.
 *	@todo Think of a better name.
 */
#define GetMemSignature(p_class_pointer,p_function_pointer) \
	(function_call::GetMemCallSignature((p_class_pointer), (p_function_pointer)).Get())

// msvc 6.0 can't have template function with return value of "A<...>::B", only "A<...>" is possible
// tried to make a wrapper "W<A<...>::B>" but that ended up with use of undefined class B
// if we could make the initializer implementation a top-level class,
// this would work in msvc 6.0 as well, but unfortunately we can't so msvc 6.0
// must use .Get() and GetMemSignature() must be a macro instead of a function

#endif // !_MSC_VER || __MWERKS__ || _MSC_VER >= 1400

/**
 *	@def GetContext
 *
 *	@brief gets a function call context (functions with no arguments)
 *
 *	@param[in] p_function_pointer is static function pointer
 *	@param[in] ... is list of argument values
 *
 *	@note This safely supports implicit type casts.
 *	@note This is not available in msvc 6.0 as it doesn't support variadic macros.
 */
#define GetContext0(p_function_pointer) (GetSignature((p_function_pointer))())

/**
 *	@def GetContext
 *
 *	@brief gets a function call context (functions with a single argument)
 *
 *	@param[in] p_function_pointer is static function pointer
 *	@param[in] a0 is argument value
 *
 *	@note This safely supports implicit type casts.
 *	@note This is not available in msvc 6.0 as it doesn't support variadic macros.
 */
#define GetContext1(p_function_pointer,a0) (GetSignature((p_function_pointer))((a0)))

/**
 *	@def GetContext2
 *
 *	@brief gets a function call context (functions with 2 argument)
 *
 *	@param[in] p_function_pointer is static function pointer
 *	@param[in] a0 is argument value
 *	@param[in] a1 is argument value
 *
 *	@note This safely supports implicit type casts.
 */
#define GetContext2(p_function_pointer,a0,a1) (GetSignature((p_function_pointer))((a0), (a1)))

/**
 *	@def GetContext3
 *
 *	@brief gets a function call context (functions with 3 argument)
 *
 *	@param[in] p_function_pointer is static function pointer
 *	@param[in] a0 is argument value
 *	@param[in] a1 is argument value
 *	@param[in] a2 is argument value
 *
 *	@note This safely supports implicit type casts.
 */
#define GetContext3(p_function_pointer,a0,a1,a2) (GetSignature((p_function_pointer))((a0), (a1), (a2)))

/**
 *	@def GetContext4
 *
 *	@brief gets a function call context (functions with 4 argument)
 *
 *	@param[in] p_function_pointer is static function pointer
 *	@param[in] a0 is argument value
 *	@param[in] a1 is argument value
 *	@param[in] a2 is argument value
 *	@param[in] a3 is argument value
 *
 *	@note This safely supports implicit type casts.
 */
#define GetContext4(p_function_pointer,a0,a1,a2,a3) (GetSignature((p_function_pointer))((a0), (a1), (a2), (a3)))

/**
 *	@def GetContext5
 *
 *	@brief gets a function call context (functions with 5 argument)
 *
 *	@param[in] p_function_pointer is static function pointer
 *	@param[in] a0 is argument value
 *	@param[in] a1 is argument value
 *	@param[in] a2 is argument value
 *	@param[in] a3 is argument value
 *	@param[in] a4 is argument value
 *
 *	@note This safely supports implicit type casts.
 */
#define GetContext5(p_function_pointer,a0,a1,a2,a3,a4) (GetSignature((p_function_pointer))((a0), (a1), (a2), (a3), (a4)))

/**
 *	@def GetContext6
 *
 *	@brief gets a function call context (functions with 6 argument)
 *
 *	@param[in] p_function_pointer is static function pointer
 *	@param[in] a0 is argument value
 *	@param[in] a1 is argument value
 *	@param[in] a2 is argument value
 *	@param[in] a3 is argument value
 *	@param[in] a4 is argument value
 *	@param[in] a5 is argument value
 *
 *	@note This safely supports implicit type casts.
 */
#define GetContext6(p_function_pointer,a0,a1,a2,a3,a4,a5) \
	(GetSignature((p_function_pointer))((a0), (a1), (a2), (a3), (a4), (a5)))

/**
 *	@def GetContext7
 *
 *	@brief gets a function call context (functions with 7 argument)
 *
 *	@param[in] p_function_pointer is static function pointer
 *	@param[in] a0 is argument value
 *	@param[in] a1 is argument value
 *	@param[in] a2 is argument value
 *	@param[in] a3 is argument value
 *	@param[in] a4 is argument value
 *	@param[in] a5 is argument value
 *	@param[in] a6 is argument value
 *
 *	@note This safely supports implicit type casts.
 */
#define GetContext7(p_function_pointer,a0,a1,a2,a3,a4,a5,a6) \
	(GetSignature((p_function_pointer))((a0), (a1), (a2), (a3), (a4), (a5), (a6)))

/**
 *	@def GetContext8
 *
 *	@brief gets a function call context (functions with 8 argument)
 *
 *	@param[in] p_function_pointer is static function pointer
 *	@param[in] a0 is argument value
 *	@param[in] a1 is argument value
 *	@param[in] a2 is argument value
 *	@param[in] a3 is argument value
 *	@param[in] a4 is argument value
 *	@param[in] a5 is argument value
 *	@param[in] a6 is argument value
 *	@param[in] a7 is argument value
 *
 *	@note This safely supports implicit type casts.
 */
#define GetContext8(p_function_pointer,a0,a1,a2,a3,a4,a5,a6,a7) \
	(GetSignature((p_function_pointer))((a0), (a1), (a2), (a3), (a4), (a5), (a6), (a7)))

/**
 *	@def GetContext9
 *
 *	@brief gets a function call context (functions with 9 argument)
 *
 *	@param[in] p_function_pointer is static function pointer
 *	@param[in] a0 is argument value
 *	@param[in] a1 is argument value
 *	@param[in] a2 is argument value
 *	@param[in] a3 is argument value
 *	@param[in] a4 is argument value
 *	@param[in] a5 is argument value
 *	@param[in] a6 is argument value
 *	@param[in] a7 is argument value
 *	@param[in] a8 is argument value
 *
 *	@note This safely supports implicit type casts.
 */
#define GetContext9(p_function_pointer,a0,a1,a2,a3,a4,a5,a6,a7,a8) \
	(GetSignature((p_function_pointer))((a0), (a1), (a2), (a3), (a4), (a5), (a6), (a7), (a8)))

/**
 *	@def GetContext10
 *
 *	@brief gets a function call context (functions with 10 argument)
 *
 *	@param[in] p_function_pointer is static function pointer
 *	@param[in] a0 is argument value
 *	@param[in] a1 is argument value
 *	@param[in] a2 is argument value
 *	@param[in] a3 is argument value
 *	@param[in] a4 is argument value
 *	@param[in] a5 is argument value
 *	@param[in] a6 is argument value
 *	@param[in] a7 is argument value
 *	@param[in] a8 is argument value
 *	@param[in] a9 is argument value
 *
 *	@note This safely supports implicit type casts.
 */
#define GetContext10(p_function_pointer,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9) \
	(GetSignature((p_function_pointer))((a0), (a1), (a2), (a3), (a4), (a5), (a6), (a7), (a8), (a9)))

/**
 *	@def GetContext11
 *
 *	@brief gets a function call context (functions with 11 argument)
 *
 *	@param[in] p_function_pointer is static function pointer
 *	@param[in] a0 is argument value
 *	@param[in] a1 is argument value
 *	@param[in] a2 is argument value
 *	@param[in] a3 is argument value
 *	@param[in] a4 is argument value
 *	@param[in] a5 is argument value
 *	@param[in] a6 is argument value
 *	@param[in] a7 is argument value
 *	@param[in] a8 is argument value
 *	@param[in] a9 is argument value
 *	@param[in] a10 is argument value
 *
 *	@note This safely supports implicit type casts.
 */
#define GetContext11(p_function_pointer,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) \
	(GetSignature((p_function_pointer))((a0), (a1), (a2), (a3), (a4), (a5), (a6), (a7), (a8), (a9), (a10)))

/**
 *	@def GetContext12
 *
 *	@brief gets a function call context (functions with 12 argument)
 *
 *	@param[in] p_function_pointer is static function pointer
 *	@param[in] a0 is argument value
 *	@param[in] a1 is argument value
 *	@param[in] a2 is argument value
 *	@param[in] a3 is argument value
 *	@param[in] a4 is argument value
 *	@param[in] a5 is argument value
 *	@param[in] a6 is argument value
 *	@param[in] a7 is argument value
 *	@param[in] a8 is argument value
 *	@param[in] a9 is argument value
 *	@param[in] a10 is argument value
 *	@param[in] a11 is argument value
 *
 *	@note This safely supports implicit type casts.
 */
#define GetContext12(p_function_pointer,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) \
	(GetSignature((p_function_pointer))((a0), (a1), (a2), (a3), (a4), (a5), (a6), (a7), (a8), (a9), \
	(a10), (a11)))

/**
 *	@def GetContext13
 *
 *	@brief gets a function call context (functions with 13 argument)
 *
 *	@param[in] p_function_pointer is static function pointer
 *	@param[in] a0 is argument value
 *	@param[in] a1 is argument value
 *	@param[in] a2 is argument value
 *	@param[in] a3 is argument value
 *	@param[in] a4 is argument value
 *	@param[in] a5 is argument value
 *	@param[in] a6 is argument value
 *	@param[in] a7 is argument value
 *	@param[in] a8 is argument value
 *	@param[in] a9 is argument value
 *	@param[in] a10 is argument value
 *	@param[in] a11 is argument value
 *	@param[in] a12 is argument value
 *
 *	@note This safely supports implicit type casts.
 */
#define GetContext13(p_function_pointer,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) \
	(GetSignature((p_function_pointer))((a0), (a1), (a2), (a3), (a4), (a5), (a6), (a7), (a8), (a9), \
	(a10), (a11), (a12)))

/**
 *	@def GetContext14
 *
 *	@brief gets a function call context (functions with 14 argument)
 *
 *	@param[in] p_function_pointer is static function pointer
 *	@param[in] a0 is argument value
 *	@param[in] a1 is argument value
 *	@param[in] a2 is argument value
 *	@param[in] a3 is argument value
 *	@param[in] a4 is argument value
 *	@param[in] a5 is argument value
 *	@param[in] a6 is argument value
 *	@param[in] a7 is argument value
 *	@param[in] a8 is argument value
 *	@param[in] a9 is argument value
 *	@param[in] a10 is argument value
 *	@param[in] a11 is argument value
 *	@param[in] a12 is argument value
 *	@param[in] a13 is argument value
 *
 *	@note This safely supports implicit type casts.
 */
#define GetContext14(p_function_pointer,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13) \
	(GetSignature((p_function_pointer))((a0), (a1), (a2), (a3), (a4), (a5), (a6), (a7), (a8), (a9), \
	(a10), (a11), (a12), (a13)))

/**
 *	@def GetContext15
 *
 *	@brief gets a function call context (functions with 15 argument)
 *
 *	@param[in] p_function_pointer is static function pointer
 *	@param[in] a0 is argument value
 *	@param[in] a1 is argument value
 *	@param[in] a2 is argument value
 *	@param[in] a3 is argument value
 *	@param[in] a4 is argument value
 *	@param[in] a5 is argument value
 *	@param[in] a6 is argument value
 *	@param[in] a7 is argument value
 *	@param[in] a8 is argument value
 *	@param[in] a9 is argument value
 *	@param[in] a10 is argument value
 *	@param[in] a11 is argument value
 *	@param[in] a12 is argument value
 *	@param[in] a13 is argument value
 *	@param[in] a14 is argument value
 *
 *	@note This safely supports implicit type casts.
 */
#define GetContext15(p_function_pointer,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14) \
	(GetSignature((p_function_pointer))((a0), (a1), (a2), (a3), (a4), (a5), (a6), (a7), (a8), (a9), \
	(a10), (a11), (a12), (a13), (a14)))

/**
 *	@def GetContext16
 *
 *	@brief gets a function call context (functions with 16 argument)
 *
 *	@param[in] p_function_pointer is static function pointer
 *	@param[in] a0 is argument value
 *	@param[in] a1 is argument value
 *	@param[in] a2 is argument value
 *	@param[in] a3 is argument value
 *	@param[in] a4 is argument value
 *	@param[in] a5 is argument value
 *	@param[in] a6 is argument value
 *	@param[in] a7 is argument value
 *	@param[in] a8 is argument value
 *	@param[in] a9 is argument value
 *	@param[in] a10 is argument value
 *	@param[in] a11 is argument value
 *	@param[in] a12 is argument value
 *	@param[in] a13 is argument value
 *	@param[in] a14 is argument value
 *	@param[in] a15 is argument value
 *
 *	@note This safely supports implicit type casts.
 */
#define GetContext16(p_function_pointer,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) \
	(GetSignature((p_function_pointer))((a0), (a1), (a2), (a3), (a4), (a5), (a6), (a7), (a8), (a9), \
	(a10), (a11), (a12), (a13), (a14), (a15)))

// msvc 6.0 doesn't have variadic macros

#include "FunctionCall.inl"

#endif // !__FUNCTION_CALL_WRAPPER_LIBRARY_INCLUDED
