Vektor42O

Variadic arguments support

Recommended Posts

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;
}

 

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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.

Share this post


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

Share this post


Link to post
Share on other sites

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.

 

 

Share this post


Link to post
Share on other sites
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 &in, ?&in var = 0, ?&in var2 = 0, ?&in var3 = 0, ?&in var4 = 0, ?&in var5 = 0, ?&in var6 = 0, ?&in var7 = 0, ?&in var8 = 0, ?&in var9 = 0, ?&in var10 = 0, ?&in var11 = 0, ?&in var12 = 0, ?&in var13 = 0, ?&in var14 = 0, ?&in var15 = 0)", asFUNCTION(as_printf), asCALL_GENERIC); assert(r >= 0);

 

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

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now