Jump to content
  • Advertisement
Sign in to follow this  
coollofty

a simple wrapper base on template

This topic is 4836 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.



Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!