How to update records in an array automatically before / at compile time or code initialization time?

Well, I have an abstract virtual machine (" PAWN ") that runs from my code, and scripts can execute functions, these functions are registered in a script from C code that runs my C ++ code.

C ++ code must contain an array in the form

{ "name_i_want_the_function_to_have_in_the_script" , function_in_my_cpp_code } 

if the function is not in the array, it cannot be executed. (because it does not exist ")

So this brings us to the following:

My functions look like this:

 //Pawn Functions #define PWNFUNC(a) static cell AMX_NATIVE_CALL a(AMX *amx, cell *params) namespace PawnFunc { PWNFUNC(GGV) { return pGameInterface->FindGameVersion(); } };//namespace PawnFunc 

and an array with information about script functions is in another file, for example:

 AMX_NATIVE_INFO custom_Natives[] = { { "GetGameVersion", PawnFunc::GGV }, { 0,0 } }; 

and now the question is:

Is it possible to update this array? (before / during compilation or code initialization time)

since now I have to add each function manually. Which is sometimes annoying and more error prone.

I would like to change it so that I can:

 //Pawn Functions #define PWNFUNC(a,b) ...?... namespace PawnFunc { PWNFUNC(GGV,GetGameVersion)//{ "GetGameVersion", PawnFunc::GGV }, is now added to "custom_Natives" array { return pGameInterface->FindGameVersion(); } };//namespace PawnFunc 

Is this even possible? If so, how can I achieve this?

maybe you can loop the namespace?

Edit: here is some kind of pseudo code: http://ideone.com/btG2lx

And also a note: I can do this at runtime, but then it needs to be done in DLLMain (my program is a DLL).

+4
source share
4 answers

This #define will do the job if you use std::vector as the repository for your script information.

(Note that the standard ensures that you still get a C-style array from &custom_Natives[0] )

 std::vector<AMX_NATIVE_INFO> custom_Natives; #define PWNFUNC(NAME, FUNC) \ struct IMPL_ ## FUNC { \ IMPL_ ## FUNC() { \ AMX_NATIVE_INFO entry = { NAME, PawnFunc::FUNC }; \ custom_Natives.push_back( entry ); \ } \ } INSTANCE_ ## FUNC; \ static cell AMX_NATIVE_CALL FUNC(AMX *amx, cell *params) 

Now code like this will define the function and by adding a script entry to custom_Natives .

 PWNFUNC("GetGameVersion", GGV) { return pGameInterface->FindGameVersion(); } 
+1
source

What could I come up with (assuming C-style arrays and C-linkage functions):

 AMX_NATIVE_INFO custom_natives[] = { { "GetGameVersion", TheGGVFunc }, { 0, 0 } }; // here a function call named `GetGameVersion` was encountered, // so let look it up using a naive linear search const char *toBeCalled = "GetGameVersion"; // obtain this somehow void (*fptr)(void) = NULL; for (int i = 0; i < sizeof(custom_natives) / sizeof(*custom_natives) - 1; i++) { const char *name = custom_natives[i].name; if (strcmp(toBeCalled, name) == 0) { fptr = custom_natives[i].func; break; } } if (fptr != NULL) { fptr(); } 
0
source

You can approximate it; the idea is to use global std::vector instead of the C array and use global object constructors to extend the vector. This way your array will be initialized to the start of main() . So instead of the custom_Natives array you will have

 std::vector<MethodArrayElementType> custom_Natives; 

(replace MethodArrayElementType with the name of the structure that contains the display of the line pointer → function). You can treat this vector as a simple C array with &custom_Natives[0] .

Then, next to each function you define, you add a little Registrar class to register the method:

 PWNFUNC(GGV) { // Your implementation goes here... } struct GGV_Registrar { GGV_Registrar() { MethodArrayElementType e = { "GetGameVersion", GGV }; custom_Natives.push_back( e ); }; } GGV_Registrar_instance; 

The constructor of the global constructor GGV_Registrar_instance is called before calling main() and updates the vector custom_Natives .

0
source

We do something similar, but instead of using an array, we use a linked list. So your example will become

 namespace PawnFunc { PWNFUNC(GGV) { return pGameInterface->FindGameVersion(); } PawnRegister GGVfunc( "GetGameVersion", GGV ); };//namespace PawnFunc 

The constructor for PawnRegister adds all objects (for example, GVVfunc) to the linked list. When your script engine wants to find a function, it iterates over the list instead of scanning the array. I suppose you could configure PawnRegister to add entries to the array.

0
source

All Articles