🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

a simple wrapper base on template

Started by
3 comments, last by WitchLord 18 years, 10 months ago
This is my wrap codes. I very like AngleScript, hope it from strength to strength. Also, this is my first time to try to write a script engine wrap, thinking is not enough and it is await completed. I like hear some suggestion from you and I'll consummate it continued, thx:) Usage:

class test
{
public:
	bool Put(int i)
	{
		printf("%d\r\n", i);
		return true;
	}
	void Put(float f)
	{
		printf("%f\r\n", f);
	}
	void Test()
	{
		puts("In test");
	}
} ;

ScriptWrapBegin(test)
	.def_construct()
	.def_destruct()	
	.def_method(void, Test).end()
	.def_method_ovlod(bool, Put, (int))
		.add_arg("int")
		.end()
	.def_method_ovlod(void, Put, (float))
		.add_arg("float")
		.end()
ScriptWrapEnd(test)


	template <typename T> class object_wrap_handle;
	template <typename T> class object_method_wrap_handle
	{
		friend class object_wrap_handle<T>;
		friend class object_method_wrap_handle<T>;
	public:
		inline object_method_wrap_handle()
			: m_ptr			(NULL)
			, m_iParamCount	(0)
			, m_bEnd		(false)
		{
		}
		inline object_method_wrap_handle(object_method_wrap_handle<T>* ptr)
			: m_ptr			(ptr)
			, m_iParamCount	(0)
			, m_bEnd		(false)
			, m_strCombined	(ptr->m_strCombined)
		{
		}
		inline ~object_method_wrap_handle()
		{
			if (!m_bEnd) end();
		}
		inline const object_method_wrap_handle<T>& operator = (const object_method_wrap_handle<T>& src)
		{
			return *this;
		}

		object_method_wrap_handle<T>& add_arg(const char* pParameter)
		{
			if (m_iParamCount > 0)
				m_strCombined.append(", ", 2);
			m_strCombined += pParameter;
			m_iParamCount ++;

			return *this;
		}
		object_method_wrap_handle<T>& add_arg_in(const char* pParameter)
		{
			if (m_iParamCount > 0) m_strCombined += ', ';
			m_strCombined += pParameter;
			m_strCombined.append(" in", 3);
			m_strCombined ++;

			return *this;
		}
		object_method_wrap_handle<T>& add_arg_out(const char* pParameter)
		{
			return *this;
		}
		object_method_wrap_handle<T>& add_arg_inout(const char* pParameter)
		{
			return *this;
		}

		object_wrap_handle<T>& end()
		{
			if (!m_bEnd)
			{
				m_strCombined += ')';

				int r = PScriptHandle::GetInstance().RegisterObjectMethod(
					m_ptr->m_strClassName.c_str(),
					m_strCombined.c_str(),
					m_ptr->m_UPtr,
					asCALL_THISCALL);
				assert(r >= 0 && "script function RegisterObjectMethod()");

				m_bEnd = true;
			}
			return *m_ptr;
		}

	private:
		object_wrap_handle<T>*	m_ptr;
		String					m_strCombined;
		word					m_iParamCount;
		bool					m_bEnd;
	} ;


	template <typename T> class object_wrap_handle
	{
		friend class object_method_wrap_handle<T>;
	private:
		static void Construct(T* obj)
		{
			new(obj) T();
		}
		static void Destruct(T* obj)
		{
			obj->~T();
		}

	public:
		~object_wrap_handle()
		{
			if (m_bFirstDefMethod) register_class();
		}

		object_wrap_handle<T>& def_class(const char* pClassName)
		{
			m_strClassName = pClassName;
			m_TSize = sizeof(T);
			m_bWithConstruct = false;
			m_bWithDestruct = false;
			m_bWithAssigment = false;
			m_bFirstDefMethod = true;

			return *this;
		}

		object_wrap_handle<T>& def_construct()
		{
			m_bWithConstruct = true;
			return *this;
		}
		object_wrap_handle<T>& def_destruct()
		{
			m_bWithDestruct = true;
			return *this;
		}

		inline object_method_wrap_handle<T> def_method(asUPtr& UPtr, const char* pMethodName, 
			const char* pReturnType)
		{
			object_method_wrap_handle<T> h;
			add_method(UPtr, pMethodName, pReturnType, h);
			return h;
		}
		inline object_method_wrap_handle<T> def_method_ovlod(asUPtr& UPtr, const char* pMethodName, 
			const char* pReturnType)
		{
			object_method_wrap_handle<T> h;
			add_method(UPtr, pMethodName, pReturnType, h);
			return h;
		}

	private:
		void register_class()
		{
			asIScriptEngine& eng = PScriptHandle::GetInstance();

			int r;
			asDWORD flag = 1;
			if (m_bWithConstruct) flag |= asOBJ_CLASS_CONSTRUCTOR;
			if (m_bWithDestruct) flag |= asOBJ_CLASS_DESTRUCTOR;
			if (m_bWithAssigment) flag |= asOBJ_CLASS_ASSIGNMENT;

			r = eng.RegisterObjectType(m_strClassName.c_str(), (int)m_TSize, flag);
			assert(r >= 0 && "script function RegisterObjectType()");

			if (m_bWithConstruct)
			{
				r = eng.RegisterObjectBehaviour(m_strClassName.c_str(), asBEHAVE_CONSTRUCT, "void f()",
					asFUNCTION(object_wrap_handle<T>::Construct), asCALL_CDECL_OBJLAST);
				assert(r >= 0 && "script function RegisterObjectBehaviour() with register a construct function");
			}
			if (m_bWithDestruct)
			{
				r = eng.RegisterObjectBehaviour(m_strClassName.c_str(), asBEHAVE_DESTRUCT, "void f()",
					asFUNCTION(object_wrap_handle<T>::Destruct), asCALL_CDECL_OBJLAST);
				assert(r >= 0 && "script function RegisterObjectBehaviour() with register a destruct function");
			}

			m_bFirstDefMethod = false;
		}
		void add_method(asUPtr& UPtr, const char* pMethodName, const char* pReturnType,
			object_method_wrap_handle<T>& mhandle)
		{
			if (m_bFirstDefMethod) register_class();

			m_strMethodName = pMethodName;
			m_strReturnType = pReturnType;
			m_UPtr = UPtr;

			mhandle.m_ptr = this;
			mhandle.m_strCombined = m_strReturnType;
			mhandle.m_strCombined += ' ';
			mhandle.m_strCombined += m_strMethodName;
			mhandle.m_strCombined += '(';
		}

	private:
		String							m_strClassName, m_strMethodName, m_strReturnType;
		size_t							m_TSize;
		bool							m_bWithConstruct, m_bWithDestruct, m_bWithAssigment;
		bool							m_bFirstDefMethod;
		asUPtr							m_UPtr;
	} ;

#define ScriptWrapBegin(ClassName)	struct __WrapClassObject__##ClassName{		__WrapClassObject__##ClassName(){			typedef ClassName tClass;			object_wrap_handle<ClassName> owh;			owh.def_class(#ClassName)

#define def_method(ReturnType, MethodName) 	def_method(asMETHOD(tClass, MethodName), #MethodName, #ReturnType)

#define def_method_ovlod(ReturnType, MethodName, Parameters) 	def_method_ovlod(asMETHODPR(tClass, MethodName, Parameters, ReturnType), #MethodName, #ReturnType)

#define ScriptWrapEnd(ClassName)		;}	} __WrapClassObject__##ClassName##_Instance;

[Edited by - coollofty on August 18, 2005 10:01:53 PM]
Advertisement
Is this supposed to replace the long chains of asRegisterX functions? It would be a lot more readable inside source tags. The member chaining is a good syntax for this, though.

Some points -
Don't use identifiers starting with double underscores. Not even in macros.
If you String class is just like std::string, just use std::string.
I noticed one specific point of non-genericy - the way it gets ahold of the engine pointer.

I have a similiar piece of code laying around, though mine works entirely with the preprocessor. Do your 'ScriptWrapBegin(...)...ScriptWrapEnd(...)' calls have to be inside a function, or do they work at file-scope? As an example, binding your test class in my system would look like
REGISTER_TYPE("test",test,asCLASS);REGISTER_METHOD("test","bool Put(int)",asMETHODPR(...etc...),asCALL_THISCALL);REGISTER_METHOD(..etc...);


Expand it to support free functions, behaviors, and member data. A method for logging everything that's bound would also be usefull.

En, may be you are right. But a simple question I think that may not notice, that is : if you register a method with a object in or out parameter, then you will get a error, because of the register order problem. is it? :)
Certainly I said, The piece of code I have not completed, such as the above problem it will be automatic solved, and some others. If you directly use the AngelScript interface, you must manage the register order, the automation and other possible problems.

The reason that use my String class instead of std::string class is my String class have a little speed faster then std::string :)
And, I think it is no necessary that register a object with methods or functions or others in a function call, commonly we register these to AngleScript is a global work, I think it do in program startup is rather than do in any time:)

Last, I forgot use the source tag, now I have edited it.
Quote: En, may be you are right. But a simple question I think that may not notice, that is : if you register a method with a object in or out parameter, then you will get a error, because of the register order problem. is it? :)
Certainly I said, The piece of code I have not completed, such as the above problem it will be automatic solved, and some others. If you directly use the AngelScript interface, you must manage the register order, the automation and other possible problems.


Sure. Just register all the types first. No problem at all; I already solved this problem myself. You havn't, however. See below.

Quote: The reason that use my String class instead of std::string class is my String class have a little speed faster then std::string :)


I highly doubt that.

Quote: And, I think it is no necessary that register a object with methods or functions or others in a function call, commonly we register these to AngleScript is a global work, I think it do in program startup is rather than do in any time:)


It's usually still important to control initialization time. Doing it all a startup means you can't, for example, have an object in file B use an object in file A. You can't tell what order they will be bound in. The only solution is to bind the classes all in one source file.
I like the cool macros you've come up with. Their usage certainly looks very clean. [smile]

I won't comment on their usefulness at this moment as I need more time to analyze them first.

I however think that the application needs to be able to control exactly when and where objects, methods, etc are registered with the engine. Some applications may for example use more than one engine. In version 2.4.0 there will be also dynamic configuration groups where object types, functions, etc can be added and removed as needed during the life time of the engine.



AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

This topic is closed to new replies.

Advertisement