Skip to main content
GameDev.net gamedev.net
🔒 Locked

Variadic arguments support

Started by Vektor42O Oct 1, 2017 at 5:51 PM 7 replies 5.4k views
Original Post
Vektor42O
Vektor42O

Hey!

The variadic arguments are supported in angelscript?

Im looking for something like this:


void CAngelScript::printf(string format, ...)
{
	const char * c_format = format.c_str();

	va_list	ap;
	va_start(ap, c_format);
	vprintf(c_format, ap);
	va_end(ap);
	return;
}

//later
r = this->engine->RegisterGlobalFunction("void printf(string , ...)", asMETHOD(CAngelScript, printf), asCALL_THISCALL_ASGLOBAL, this); assert(r >= 0);


And the script:


void OnScriptInit()
{
    printf("%s-%d", "test", 1);
    return;
}


WitchLord
WitchLord

Not with the variadic syntax. However you can do something similar with dictionaries, allowing a syntax like this:



	void OnScriptInit()
{
  printf("%s-%d", {{'arg0', 'test'},{'arg1', 1}});
  return;
}
	


The dictionary would even be able to receive updates so the function can return values into the dictionary.

If you do not like the idea of dictionaries, you could use an array instead. Though I don't currently supply a standard add-on for an array that can hold variable types in the elements. With a little effort you ought to be able to implement that yourself by merging the code from the array and dictionary add-ons.


The implementation to support actual variadic argument lists is still on my to-do list, but currently with a very low priority.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - <a href="http://www.angelcode.com/tower" rel
Vektor42O
Vektor42O

Sad to hear that :(

The dictionary version is not the best way to do that.

But if you tell me where i should implement it i will try. Its possible that hundreds of people will use it so i want to make it the best as i can.

Solokiller
Solokiller

You can use the generic calling convention along with variable parameters. You'll have to register one for each number of parameters but it'll work like you want it to.

Sandu Liviu Catalin
Sandu Liviu Catalin
On 10/4/2017 at 9:29 PM, Solokiller said:

You can use the generic calling convention along with variable parameters. You'll have to register one for each number of parameters but it'll work like you want it to.

I actually did that to make bindings for https://github.com/fmtlib/fmt And it worked surprisingly well.

Vektor42O
Vektor42O

Should i register functions for each variation of argument types and length?

WitchLord
WitchLord

You don't need to register one for each combination of type and length. With the use of the variable parameter type and default arguments you can potentially implement and register a single function with the maximum number or arguments that you wish to support.

Of course, if you're thinking of supporting a huge number of arguments, then you probably want to provide at least a couple of variants with less arguments that will likely be more frequently used to avoid unnecessary overhead when all the extra unused parameters are evaluated with the default argument.



AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - <a href="http://www.angelcode.com/tower" rel
Vektor42O
Vektor42O

bool replace(std::string& str, const std::string& from, const std::string& to) 
{
	size_t start_pos = str.find(from);
	if (start_pos == std::string::npos)
		return false;
	str.replace(start_pos, from.length(), to);
	return true;
}

void as_printf(asIScriptGeneric *gen)
{
	
	void *ref = gen->GetArgAddress(0);
	int typeId = gen->GetArgTypeId(0);

	string format = *static_cast<string*>(ref);
	
	for (int i = 1; i < 16; i++)
	{
		ref = gen->GetArgAddress(i);
		typeId = gen->GetArgTypeId(i);

		switch (typeId)
		{
			case 67108876: //string?
			{
				string local = *static_cast<string*>(ref);
				replace(format, "%s", local);
				break;
			}
			case 2:
			{
				char local = *static_cast<char*>(ref);
				replace(format, "%d", to_string(local));
				break;
			}
			case 3:
			{
				short local = *static_cast<short*>(ref);
				replace(format, "%d", to_string(local));
				break;
			}
			case 4:
			{
				int local = *static_cast<int*>(ref);
				replace(format, "%d", to_string(local));
				break;
			}
			case 5:
			{
				long long local = *static_cast<long long*>(ref);
				replace(format, "%d", to_string(local));
				break;
			}
			case 6:
			{
				unsigned char local = *static_cast<unsigned char*>(ref);
				replace(format, "%d", to_string(local));
				break;
			}
			case 7:
			{
				unsigned short local = *static_cast<unsigned short*>(ref);
				replace(format, "%d", to_string(local));
				break;
			}
			case 8:
			{
				unsigned int local = *static_cast<unsigned int*>(ref);
				replace(format, "%d", to_string(local));
				break;
			}
			case 9:
			{
				unsigned long long local = *static_cast<unsigned long long*>(ref);
				replace(format, "%d", to_string(local));
				break;
			}
			case 10:
			{
				float local = *static_cast<float*>(ref);
				replace(format, "%f", to_string(local));
				break;
			}
			case 11:
			{
				double local = *static_cast<double*>(ref);
				replace(format, "%f", to_string(local));
				break;
			}
		}
	}

	cout << format << endl;
	return;
}

//later
r = this->engine->RegisterGlobalFunction("void printf(string ∈, ?∈ var = 0, ?∈ var2 = 0, ?∈ var3 = 0, ?∈ var4 = 0, ?∈ var5 = 0, ?∈ var6 = 0, ?∈ var7 = 0, ?∈ var8 = 0, ?∈ var9 = 0, ?∈ var10 = 0, ?∈ var11 = 0, ?∈ var12 = 0, ?∈ var13 = 0, ?∈ var14 = 0, ?∈ var15 = 0)", asFUNCTION(as_printf), asCALL_GENERIC); assert(r >= 0);


Okay thanks! Got it working. Not the best but atleast it works.


Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.