View Single Post
03-29-09, 08:43 AM   #16
watchout
A Fallenroot Satyr
Join Date: Mar 2008
Posts: 20
Concerning string/hash indexes vs. numerical indexes

Lua puts any numerically indexed table entries into an array as opposed to a hashed map (every lua table can have both array data and hashed data).
So in theory, accessing numbered entries should be faster (adding items however could be another thing)

Now, to contradict my previous paragraph... Some time ago I did some testing of numeric vs. hash indexes (in plain lua.exe) and I was not able to determine any difference at all. Any time differences (at some 100k iterations) were well in threshold margins.

Some day I might also read into Lua's hashing function, but until then I'd say you try to have shorter indexes so the function has less characters to parse.
Also Lua might fall back to hashing when you have a table like {[1] = ..., [10000] = ...}


One thing to also note is: Avoid global tables at all costs. WoWs current global table is so overpopulated that you're almost always faster when you first do local x = sometableinglobal; and then do your operations on x. You're even faster if you completely skip the global table and stay within your addon's scope (have a table where everything is inside that you can access using self, or use local-to-file variables if possible).
Also note that accessing anytable.number is always slower than accessing number without a table (100-1000 times or so)

also note that your line
Code:
buff_name = UnitBuff( unit, i );
will put buff_name into the global table (unless you have localized it somewhere outside of the code piece) which (as stated above) is hideously slow, especially in wow, since overpopulated. Do
Code:
local buff_name = UnitBuff( unit, i );
instead

Assuming that you have more than three "elseif( buff_name == BUFF3 )"-like branches, you can further reduce your code - if you use a metatable that returns an empty function when an empty index is accessed, and do the stuff you'd now do inside your "if buff_name == xyz then" constructs in functions defined in that table - to:

Code:
local i=1;
local buff_name = UnitBuff( unit, i );
while buff_name do
	watched_buffs[buff_name]();
	i=i+1;
	buff_name = UnitBuff( unit, i );
end
or
Code:
local i=1;
local buff_name = UnitBuff( unit, i );
while buff_name do
	watched_buffs[buff_name]();
	found_buffs[buff_name] = found_buffs[buff_name]+1;

	i=i+1;
	buff_name = UnitBuff( unit, i );
end
(using a 2nd metatable that discards any set if there's a new index and returns zero if an unknown index is requested, thats a pretty overhead though) if you really need that counting table.
What both options have in common is that they're slower when the buff is not in the table and really fast when it is, because then the metatable methods are not used.

The reason to do this is, because in an if/elseif/...../else construct lua has to parse every single branch in the worst case - half of them in the average case - and if you call the table it just does a hash of the string, goes there in the table (with native speed!) and calls that code (with some overhead due to function header).

Last edited by watchout : 03-29-09 at 08:50 AM. Reason: complete replacement code for clarity sake
  Reply With Quote