src/squirrel_helper.hpp
author truelight
Sun, 25 Mar 2007 16:10:40 +0000
branchnoai
changeset 9529 5f26f4bc574b
parent 9510 261d33fbabb8
child 9530 5b93bc87cc5e
permissions -rw-r--r--
(svn r9450) [NoAI] -Fix: don't allow static-method calls from SQ to non-static functions
-Add: added GetClassName() to all API functions (needed to do the thing above ;))
/* $Id$ */

/** @file squirrel_helper.hpp declarations and parts of the implementation of the class for convert code */

#ifndef SQUIRREL_HELPER_HPP
#define SQUIRREL_HELPER_HPP

#include <squirrel.h>

/**
 * The Squirrel convert routines
 */
namespace SQConvert {

	template <bool Y> struct YesT {
		static const bool Yes = Y;
		static const bool No = !Y;
	};

	/**
	 * Helper class to recognize if the given type is void. Usage: 'IsVoidT<T>::Yes'
	 */
	template <typename T> struct IsVoidT : YesT<false> {};
	template <> struct IsVoidT<void> : YesT<true> {};

	/**
	 * Helper class to recognize if the function/method return type is void.
	 */
	template <typename Tfunc> struct HasVoidReturnT;
	/* functions */
	template <typename Tretval> struct HasVoidReturnT<Tretval (*)()> : IsVoidT<Tretval> {};
	template <typename Tretval, typename Targ1> struct HasVoidReturnT<Tretval (*)(Targ1)> : IsVoidT<Tretval> {};
	template <typename Tretval, typename Targ1, typename Targ2> struct HasVoidReturnT<Tretval (*)(Targ1, Targ2)> : IsVoidT<Tretval> {};
	template <typename Tretval, typename Targ1, typename Targ2, typename Targ3> struct HasVoidReturnT<Tretval (*)(Targ1, Targ2, Targ3)> : IsVoidT<Tretval> {};
	template <typename Tretval, typename Targ1, typename Targ2, typename Targ3, typename Targ4> struct HasVoidReturnT<Tretval (*)(Targ1, Targ2, Targ3, Targ4)> : IsVoidT<Tretval> {};
	/* methods */
	template <class Tcls, typename Tretval> struct HasVoidReturnT<Tretval (Tcls::*)()> : IsVoidT<Tretval> {};
	template <class Tcls, typename Tretval, typename Targ1> struct HasVoidReturnT<Tretval (Tcls::*)(Targ1)> : IsVoidT<Tretval> {};
	template <class Tcls, typename Tretval, typename Targ1, typename Targ2> struct HasVoidReturnT<Tretval (Tcls::*)(Targ1, Targ2)> : IsVoidT<Tretval> {};
	template <class Tcls, typename Tretval, typename Targ1, typename Targ2, typename Targ3> struct HasVoidReturnT<Tretval (Tcls::*)(Targ1, Targ2, Targ3)> : IsVoidT<Tretval> {};
	template <class Tcls, typename Tretval, typename Targ1, typename Targ2, typename Targ3, typename Targ4> struct HasVoidReturnT<Tretval (Tcls::*)(Targ1, Targ2, Targ3, Targ4)> : IsVoidT<Tretval> {};


	/**
	 * Special class to make it possible for the compiler to pick the correct GetParam().
	 */
	template <typename T> class ForceType { };

	/**
	 * To return a value to squirrel, we call this function. It converts to the right format.
	 */
	template <typename T> static int Return(HSQUIRRELVM vm, T t);

	template <> inline int Return<uint8> (HSQUIRRELVM vm, uint8 res)  { sq_pushinteger(vm, (int32)res); return 1; }
	template <> inline int Return<uint16>(HSQUIRRELVM vm, uint16 res) { sq_pushinteger(vm, (int32)res); return 1; }
	template <> inline int Return<uint32>(HSQUIRRELVM vm, uint32 res) { sq_pushinteger(vm, (int32)res); return 1; }
	template <> inline int Return<int8>  (HSQUIRRELVM vm, int8 res)   { sq_pushinteger(vm, res); return 1; }
	template <> inline int Return<int16> (HSQUIRRELVM vm, int16 res)  { sq_pushinteger(vm, res); return 1; }
	template <> inline int Return<int32> (HSQUIRRELVM vm, int32 res)  { sq_pushinteger(vm, res); return 1; }
	template <> inline int Return<bool>  (HSQUIRRELVM vm, bool res)   { sq_pushbool   (vm, res); return 1; }
	template <> inline int Return<char *>(HSQUIRRELVM vm, char *res)  { if (res == NULL) sq_pushnull(vm); else sq_pushstring (vm, OTTD2FS(res), strlen(res)); free(res); return 1; }

	/**
	 * To get a param from squirrel, we call this function. It converts to the right format.
	 */
	template <typename T> static T GetParam(ForceType<T>, HSQUIRRELVM vm, int index);

	template <> inline uint8       GetParam(ForceType<uint8>       , HSQUIRRELVM vm, int index) { SQInteger     tmp; sq_getinteger(vm, index, &tmp); return tmp; }
	template <> inline uint16      GetParam(ForceType<uint16>      , HSQUIRRELVM vm, int index) { SQInteger     tmp; sq_getinteger(vm, index, &tmp); return tmp; }
	template <> inline uint32      GetParam(ForceType<uint32>      , HSQUIRRELVM vm, int index) { SQInteger     tmp; sq_getinteger(vm, index, &tmp); return tmp; }
	template <> inline int8        GetParam(ForceType<int8>        , HSQUIRRELVM vm, int index) { SQInteger     tmp; sq_getinteger(vm, index, &tmp); return tmp; }
	template <> inline int16       GetParam(ForceType<int16>       , HSQUIRRELVM vm, int index) { SQInteger     tmp; sq_getinteger(vm, index, &tmp); return tmp; }
	template <> inline int32       GetParam(ForceType<int32>       , HSQUIRRELVM vm, int index) { SQInteger     tmp; sq_getinteger(vm, index, &tmp); return tmp; }
	template <> inline bool        GetParam(ForceType<bool>        , HSQUIRRELVM vm, int index) { SQBool        tmp; sq_getbool   (vm, index, &tmp); return tmp != 0; }
	template <> inline const char *GetParam(ForceType<const char *>, HSQUIRRELVM vm, int index) { const SQChar *tmp; sq_getstring (vm, index, &tmp); return FS2OTTD(tmp); }

	/**
	* Helper class to recognize the function type (retval type, args) and use the proper specialization
	* for SQ callback. The partial specializations for the second arg (Tis_void_retval) are not possible
	* on the function. Therefore the class is used instead.
	*/
	template <typename Tfunc, bool Tis_void_retval = HasVoidReturnT<Tfunc>::Yes> struct HelperT;

	/**
	 * The real C++ caller for function with return value and 0 params.
	 */
	template <typename Tretval>
	struct HelperT<Tretval (*)(), false> {
		static int SQCall(void *instance, Tretval (*func)(), HSQUIRRELVM vm)
		{
			return Return(vm, (*func)());
		}
	};

	/**
	 * The real C++ caller for function with no return value and 0 params.
	 */
	template <typename Tretval>
	struct HelperT<Tretval (*)(), true> {
		static int SQCall(void *instance, Tretval (*func)(), HSQUIRRELVM vm)
		{
			(*func)();
			return 0;
		}
	};

	/**
	 * The real C++ caller for method with return value and 0 params.
	 */
	template <class Tcls, typename Tretval>
	struct HelperT<Tretval (Tcls::*)(), false> {
		static int SQCall(Tcls *instance, Tretval (Tcls::*func)(), HSQUIRRELVM vm)
		{
			return Return(vm, (instance->*func)());
		}
	};

	/**
	 * The real C++ caller for method with no return value and 0 params.
	 */
	template <class Tcls, typename Tretval>
	struct HelperT<Tretval (Tcls::*)(), true> {
		static int SQCall(Tcls *instance, Tretval (Tcls::*func)(), HSQUIRRELVM vm)
		{
			(instance->*func)();
			return 0;
		}
	};

	/**
	 * The real C++ caller for function with return value and 1 param.
	 */
	template <typename Tretval, typename Targ1>
	struct HelperT<Tretval (*)(Targ1), false> {
		static int SQCall(void *instance, Tretval (*func)(Targ1), HSQUIRRELVM vm)
		{
			return Return(vm, (*func)(
				GetParam(ForceType<Targ1>(), vm, 2)
			));
		}
	};

	/**
	 * The real C++ caller for function with no return value and 1 param.
	 */
	template <typename Tretval, typename Targ1>
	struct HelperT<Tretval (*)(Targ1), true> {
		static int SQCall(void *instance, Tretval (*func)(Targ1), HSQUIRRELVM vm)
		{
			(*func)(
				GetParam(ForceType<Targ1>(), vm, 2)
			);
			return 0;
		}
	};

	/**
	 * The real C++ caller for method with return value and 1 param.
	 */
	template <class Tcls, typename Tretval, typename Targ1>
	struct HelperT<Tretval (Tcls::*)(Targ1), false> {
		static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1), HSQUIRRELVM vm)
		{
			return Return(vm, (instance->*func)(
				GetParam(ForceType<Targ1>(), vm, 2)
			));
		}
	};

	/**
	 * The real C++ caller for method with no return value and 1 param.
	 */
	template <class Tcls, typename Tretval, typename Targ1>
	struct HelperT<Tretval (Tcls::*)(Targ1), true> {
		static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1), HSQUIRRELVM vm)
		{
			(instance->*func)(
				GetParam(ForceType<Targ1>(), vm, 2)
			);
			return 0;
		}
	};

	/**
	 * The real C++ caller for function with return value and 2 params.
	 */
	template <typename Tretval, typename Targ1, typename Targ2>
	struct HelperT<Tretval (*)(Targ1, Targ2), false> {
		static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2), HSQUIRRELVM vm)
		{
			return Return(vm, (*func)(
				GetParam(ForceType<Targ1>(), vm, 2),
				GetParam(ForceType<Targ2>(), vm, 3)
			));
		}
	};

	/**
	 * The real C++ caller for function with no return value and 2 params.
	 */
	template <typename Tretval, typename Targ1, typename Targ2>
	struct HelperT<Tretval (*)(Targ1, Targ2), true> {
		static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2), HSQUIRRELVM vm)
		{
			(*func)(
				GetParam(ForceType<Targ1>(), vm, 2),
				GetParam(ForceType<Targ2>(), vm, 3)
			);
			return 0;
		}
	};

	/**
	 * The real C++ caller for method with return value and 2 params.
	 */
	template <class Tcls, typename Tretval, typename Targ1, typename Targ2>
	struct HelperT<Tretval (Tcls::*)(Targ1, Targ2), false> {
		static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2), HSQUIRRELVM vm)
		{
			return Return(vm, (instance->*func)(
				GetParam(ForceType<Targ1>(), vm, 2),
				GetParam(ForceType<Targ2>(), vm, 3)
			));
		}
	};

	/**
	 * The real C++ caller for method with no return value and 2 params.
	 */
	template <class Tcls, typename Tretval, typename Targ1, typename Targ2>
	struct HelperT<Tretval (Tcls::*)(Targ1, Targ2), true> {
		static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2), HSQUIRRELVM vm)
		{
			(instance->*func)(
				GetParam(ForceType<Targ1>(), vm, 2),
				GetParam(ForceType<Targ2>(), vm, 3)
			);
			return 0;
		}
	};

	/**
	 * The real C++ caller for function with return value and 3 params.
	 */
	template <typename Tretval, typename Targ1, typename Targ2, typename Targ3>
	struct HelperT<Tretval (*)(Targ1, Targ2, Targ3), false> {
		static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2, Targ3), HSQUIRRELVM vm)
		{
			return Return(vm, (*func)(
				GetParam(ForceType<Targ1>(), vm, 2),
				GetParam(ForceType<Targ2>(), vm, 3),
				GetParam(ForceType<Targ3>(), vm, 4)
			));
		}
	};

	/**
	 * The real C++ caller for function with no return value and 3 params.
	 */
	template <typename Tretval, typename Targ1, typename Targ2, typename Targ3>
	struct HelperT<Tretval (*)(Targ1, Targ2, Targ3), true> {
		static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2, Targ3), HSQUIRRELVM vm)
		{
			(*func)(
				GetParam(ForceType<Targ1>(), vm, 2),
				GetParam(ForceType<Targ2>(), vm, 3),
				GetParam(ForceType<Targ3>(), vm, 4)
			);
			return 0;
		}
	};

	/**
	 * The real C++ caller for method with return value and 3 params.
	 */
	template <class Tcls, typename Tretval, typename Targ1, typename Targ2, typename Targ3>
	struct HelperT<Tretval (Tcls::*)(Targ1, Targ2, Targ3), false> {
		static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3), HSQUIRRELVM vm)
		{
			return Return(vm, (instance->*func)(
				GetParam(ForceType<Targ1>(), vm, 2),
				GetParam(ForceType<Targ2>(), vm, 3),
				GetParam(ForceType<Targ3>(), vm, 4)
			));
		}
	};

	/**
	 * The real C++ caller for method with no return value and 3 params.
	 */
	template <class Tcls, typename Tretval, typename Targ1, typename Targ2, typename Targ3>
	struct HelperT<Tretval (Tcls::*)(Targ1, Targ2, Targ3), true> {
		static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3), HSQUIRRELVM vm)
		{
			(instance->*func)(
				GetParam(ForceType<Targ1>(), vm, 2),
				GetParam(ForceType<Targ2>(), vm, 3),
				GetParam(ForceType<Targ3>(), vm, 4)
			);
			return 0;
		}
	};

	/**
	 * The real C++ caller for function with return value and 4 params.
	 */
	template <typename Tretval, typename Targ1, typename Targ2, typename Targ3, typename Targ4>
	struct HelperT<Tretval (*)(Targ1, Targ2, Targ3, Targ4), false> {
		static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2, Targ3, Targ4), HSQUIRRELVM vm)
		{
			return Return(vm, (*func)(
				GetParam(ForceType<Targ1>(), vm, 2),
				GetParam(ForceType<Targ2>(), vm, 3),
				GetParam(ForceType<Targ3>(), vm, 4),
				GetParam(ForceType<Targ4>(), vm, 5)
			));
		}
	};

	/**
	 * The real C++ caller for function with no return value and 4 params.
	 */
	template <typename Tretval, typename Targ1, typename Targ2, typename Targ3, typename Targ4>
	struct HelperT<Tretval (*)(Targ1, Targ2, Targ3, Targ4), true> {
		static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2, Targ3, Targ4), HSQUIRRELVM vm)
		{
			(*func)(
				GetParam(ForceType<Targ1>(), vm, 2),
				GetParam(ForceType<Targ2>(), vm, 3),
				GetParam(ForceType<Targ3>(), vm, 4),
				GetParam(ForceType<Targ4>(), vm, 5)
			);
			return 0;
		}
	};

	/**
	 * The real C++ caller for method with return value and 4 params.
	 */
	template <class Tcls, typename Tretval, typename Targ1, typename Targ2, typename Targ3, typename Targ4>
	struct HelperT<Tretval (Tcls::*)(Targ1, Targ2, Targ3, Targ4), false> {
		static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4), HSQUIRRELVM vm)
		{
			return Return(vm, (instance->*func)(
				GetParam(ForceType<Targ1>(), vm, 2),
				GetParam(ForceType<Targ2>(), vm, 3),
				GetParam(ForceType<Targ3>(), vm, 4),
				GetParam(ForceType<Targ4>(), vm, 5)
			));
		}
	};

	/**
	 * The real C++ caller for method with no return value and 4 params.
	 */
	template <class Tcls, typename Tretval, typename Targ1, typename Targ2, typename Targ3, typename Targ4>
	struct HelperT<Tretval (Tcls::*)(Targ1, Targ2, Targ3, Targ4), true> {
		static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4), HSQUIRRELVM vm)
		{
			(instance->*func)(
				GetParam(ForceType<Targ1>(), vm, 2),
				GetParam(ForceType<Targ2>(), vm, 3),
				GetParam(ForceType<Targ3>(), vm, 4),
				GetParam(ForceType<Targ4>(), vm, 5)
			);
			return 0;
		}
	};


	/**
	 * A general template for all callback functions from Squirrel.
	 *  In here the function_proc is recovered, and the SQCall is called that
	 *  can handle this exact amount of params.
	 */
	template <typename Tcls, typename Tmethod>
	inline SQInteger DefSQCallback(HSQUIRRELVM vm)
	{
		/* Find the amount of params we got */
		int nparam = sq_gettop(vm);
		SQUserPointer ptr = NULL;
		SQUserPointer real_instance = NULL;
		HSQOBJECT instance;

		/* Get the 'SQ' instance of this class */
		Squirrel::GetInstance(vm, &instance);

		/* Protect against calls to a non-static method in a static way */
		sq_pushroottable(vm);
		sq_pushstring(vm, Tcls::GetClassName(), -1);
		sq_get(vm, -2);
		sq_pushobject(vm, instance);
		if (sq_instanceof(vm) != SQTrue) return sq_throwerror(vm, "class method is non-static");
		sq_settop(vm, nparam);

		/* Get the 'real' instance of this class */
		sq_getinstanceup(vm, 1, &real_instance, 0);
		/* Get the real function pointer */
		sq_getuserdata(vm, nparam, &ptr, 0);

		/* Delegate it to a template that can handle this specific function */
		return HelperT<Tmethod>::SQCall((Tcls *)real_instance, *(Tmethod *)ptr, vm);
	}

}; // namespace SQConvert

#endif /* SQUIRREL_HELPER_HPP */