Advertisement

Variadic arguments support

Started by October 01, 2017 05:51 PM
7 comments, last by Vektor42O 7 years, 1 month ago

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

 

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 - Tower - free puzzle game

Advertisement

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.

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.

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.

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

Advertisement

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 - Tower - free puzzle game


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.

 

This topic is closed to new replies.

Advertisement