Een tijd geleden ben ik begonnen met het maken van een eigen scripting-engine. Die werkt op dit moment prima (Spirit Parser genereert bytecode die een VM dan uitvoert). De API om classes scriptbaar te maken is zo simpel mogelijk gehouden en bestaat uit een interface Scriptable die een methode Execute definieert:
Een en ander met refcounting zodat het allemaal netjes werkt. Zoals je ziet krijgt een Scriptable class bij het uitvoeren van een bepaalde functie op die class gewoon een aanroep naar een methode 'Execute' met als parameters een string met de naam van de gevraagde functie (of veld) en een parameter-lijst.
Dat werkt allemaal prima en het is een hele simpele manier om je classes scriptable te maken. Het probleem is alleen dat het enorm traag is: iedere keer als ik een call maak naar een scriptable class moet hij de functienaam vergelijken met een aantal functienamen (in ifjes, dus slecht voor branch prediction enzo) en daarna pas de functie uitvoeren.
Nou dacht ik: stel dat ik de functienamen ("toString" etc) nou eens zou hashen. Dan krijg ik een int (hopelijk en waarschijnlijk uniek) die ik gewoon met een switch-statement kan 'matchen'. De compiler hasht de functienamen ook meteen en dat zorgt weer voor kleinere bytecode. Kandidaat hiervoor leek me de FNV-hash, omdat die snel en simpel is.
Het probleem: om het programmeren van scriptbare classes makkelijker te maken moet de hash eigenlijk compile-time worden gegenereerd uit een opgegeven functie-naam. Ik wil dus zoiets:
Maar hoe maak ik die hash compile-time?
C++:
1
2
3
4
5
6
| virtual ref<Scriptable> MijnScriptableClass::Execute(std::wstring command, ref<ParameterList> params) { if(c==L"toString") { return new ScriptString(L"Hello World!"); } return 0; // methode/veld bestaat niet } |
Een en ander met refcounting zodat het allemaal netjes werkt. Zoals je ziet krijgt een Scriptable class bij het uitvoeren van een bepaalde functie op die class gewoon een aanroep naar een methode 'Execute' met als parameters een string met de naam van de gevraagde functie (of veld) en een parameter-lijst.
Dat werkt allemaal prima en het is een hele simpele manier om je classes scriptable te maken. Het probleem is alleen dat het enorm traag is: iedere keer als ik een call maak naar een scriptable class moet hij de functienaam vergelijken met een aantal functienamen (in ifjes, dus slecht voor branch prediction enzo) en daarna pas de functie uitvoeren.
Nou dacht ik: stel dat ik de functienamen ("toString" etc) nou eens zou hashen. Dan krijg ik een int (hopelijk en waarschijnlijk uniek) die ik gewoon met een switch-statement kan 'matchen'. De compiler hasht de functienamen ook meteen en dat zorgt weer voor kleinere bytecode. Kandidaat hiervoor leek me de FNV-hash, omdat die snel en simpel is.
Het probleem: om het programmeren van scriptbare classes makkelijker te maken moet de hash eigenlijk compile-time worden gegenereerd uit een opgegeven functie-naam. Ik wil dus zoiets:
C++:
1
2
3
4
5
6
7
8
9
| virtual ref<Scriptable> MijnScriptableClass::Execute(int command, ref<ParameterList> params) { switch(c) { case HASH(L"toString"): return new ScriptString(L"Hello World!"); break; } return 0; } |
Maar hoe maak ik die hash compile-time?