- Joined
- Mar 19, 2008
- Messages
- 3,141
You can check out BribeFromTheHive/NewTable as I have just made the two versions comparable with that view.@Bribe, thanks for taking time into updating Table resource. Could you provide output of 'git log -p -n 1' for your update? Would be so much easier to review.
@Bribe, could this line in the destroy methodsupposed to beJASS:call Table(t).remove(this)
?JASS:call Table(t).remove(0)
I see. I was interested whether I can save both. Thanks.As long as "type" is an integer value, and "this" is bounded up to 8191 (0x1fff), it will work, but don't expect it to store both a boolean and an integer value at the same time.
It's generally considered to be bad-practice, but I have heard of some success stories of non-overlapping basic types to be allowed to be stored separately within the same parent/child keys.I see. I was interested whether I can save both. Thanks.
If you're interested in storing multiple variables in a single Table instance you could make a struct with the various values and use Table to store and retrieve that specific struct instance, that's what I do in those cases.I see. I was interested whether I can save both. Thanks.
do Table = {}
--[[
Made by Bribe, special thanks to Vexorian & Nestharus
One map, no hashtables. Welcome to Lua NewTable version 1.0.1.0
API
------------
Table.create() returns a new Table. The difference between this and a regular table is only that it will ignore keyword indices such as "integer, boolean, handle, etc."
| tab.destroy()
| --flushes the table.
|
| tab:flush()
| --same as destroy.
|
| tab[some_index] = value
| store a value of any type in the table at some index.
|
| tab[some_index]
| load a value from a table at some index but ignore indices that were aligned to types like "integer/boolean/real/etc"
|
| tab:has(some_index)
| whether anything is stored at that index. Same as tab[some_index] ~= nil
|
| tab:remove(some_index)
| remove the value at that index. Same as tab[some_index] = nil
|
----------------
TableArray[array_size] returns a new TableArray.
| array:destroy()
| does nothing
|
| array:flush()
| flushes the array as well as any tables within it.
|
| array.size
| returns the size of the array specified at the time it was created.
|
| array[some_index]
| returns an existing Table or creates a new one at that index.
]]
Table.create = function() return setmetatable({}, Table) end
function Table:has(key) return self[key] ~= nil end
function Table:remove(key) self[key] = nil end
function Table:flush() for key,_ in pairs(self) do self[key] = nil end end
Table.destroy = Table.flush
local dump = { --Create a table just to store the types that will ignored
handle = true,
agent = true,
real = true,
boolean = true,
string = true,
integer = true,
player = true,
widget = true,
destructable = true,
item = true,
unit = true,
ability = true,
timer = true,
trigger = true,
triggercondition = true,
triggeraction = true,
event = true,
force = true,
group = true,
location = true,
rect = true,
boolexpr = true,
sound = true,
effect = true,
unitpool = true,
itempool = true,
quest = true,
questitem = true,
defeatcondition = true,
timerdialog = true,
leaderboard = true,
multiboard = true,
multiboarditem = true,
trackable = true,
dialog = true,
button = true,
texttag = true,
lightning = true,
image = true,
ubersplat = true,
region = true,
fogstate = true,
fogmodifier = true,
hashtable = true
}
Table.__index = function(self, key)
local get = dump[key] and self or rawget(Table, key)
if get then
rawset(self, key, get) --for performance on further calls at the expense of a little more memory usage.
return get
end
end
local repeater
TableArray = setmetatable(
{
destroy = DoNothing,
has = function(self, key) return rawget(self, key) ~= nil end,
flush = function(self)
for key, val in pairs(self) do
if type(val) == "table" then val:flush() end
self[key] = nil
end
end
},
{
__index = function(self, size)
if not repeater then
repeater = {
__index = function(self, key)
local new = rawget(TableArray, key)
if new then return new end
new = Table.create()
rawset(self, key, new)
return new
end
}
end
return setmetatable({size = size}, repeater)
end
})
HashTable = TableArray
HashTable.create = function(val) return HashTable[val] end
end--LIBRARY
do --Table BC methods for Lua, version 1.1
Table.exists = Table.has
Table.reset = Table.flush
function Table:flush(key) --no longer in conflict with NewTable. It only took 11 years?
if key then self[key] = nil
else Table.reset() end
end
local indexer = {}
function Table.flush2D(index)
indexer[index] = nil
end
local oldIndex = rawget(Table, __index)
rawset(Table, __index, function(self, index)
if self == Table then --need to check if it's a static method operator and not a regular instance.
local t = indexer[index]
if not t then
t = Table.create()
rawset(indexer, index, t)
end
return t
end
return oldIndex(self, index)
end)
setmetatable(Table, Table)
HandleTable = Table
StringTable = Table --Jesus Christ, Lua. Your tables are so overpowered.
end
HashTable
until I tested it. set heroAbility = HashTable.create()
set heroAbility[1].integer[2] = 47
set heroAbility[1][2].real[0] = 3.14
set heroAbility[1][2].integer[0] = 17
set heroAbility[1][2][0].integer[0] = 42
set heroAbility[1][2][0][123].integer[0] = 1337
call BJDebugMsg(I2S(heroAbility[1].integer[2]))
call BJDebugMsg(R2S(heroAbility[1][2].real[0]))
call BJDebugMsg(I2S(heroAbility[1][2].integer[0]))
call BJDebugMsg(I2S(heroAbility[1][2][0].integer[0]))
call BJDebugMsg(I2S(heroAbility[1][2][0][123].integer[0]))
set yourHash[index1][index2] = HashTable.create()
then you don't have to use the wrapper on subsequent "get" calls to that index point.heroAbility[unit-index][ability-event-index][extra-triggered-effect-index].integer[effect-identifier]
heroAbility[unit-index][ability-event-index][extra-triggered-effect-index].real[effect-data-index]
ability-event-index
and extra-triggered-effect-index
were zero-indexed, even when the above example printed expected values. My example wasn't as good as I expected, cool. Thanks.set yourHash[index1][index2] = HashTable.create()
will occupy the "integer" value for index2
. So I cannot keep an integer value at yourHash[index1].integer[index2]
while doing this, which makes sense.itemDB[playerId][playerId*10000]
I've not seen cases where hashtables values actually hit each other and start to override, so I would consider it safe. You can "allocate" as much in that 2D context as you want (or even make a TableArray instead) but unless you fill some data in the in-between parts it's just empty space. Hashtables are unlike JASS arrays in that they don't "fill in" or "allocate" empty areas.Hello sir @Bribe ,
I'm new to your table and fairly ignorant about Warcraft III performance / resource management.
My question:
I'm designing an inventory system with frames and want to use Table as a database for items.
Does table eat significant resources for "empty fields"? For example if my system refers to items in this way, do I risk stability or performance?
JASS:itemDB[playerId][playerId*10000]
If, I allow 24 players, and each player to have 10 heroes with unique inventories storing up to 1000 items each, that is 240 000 indexes storing 10-20 values each.
- Don't initialisize the HashTable inside the globals block, but in a normal function.
It works.Does Table not work for you? I've used this on all the patches since I think 1.28 and never had any issues.
Yeah this is mentioned somewhere earlier in the thread. I create Tables from index 8192 specifically so that you can use vJass "key" type to cast those to Table. You can also cast StructName.typeid into Table and it will work the same way (because struct type IDs share the same key stack as "key" itself).It works.
But initially I tried to do a initialize the table in the globals like this:
globals
Table InventoryDB = InventoryDB.create()
endglobals
The world editor does not throw an error, but it does not work when you initialize the table in the globals.
function Trig_Test_Actions takes nothing returns nothing
// create/destroy test 1
local Table4DT myTable = Table4DT.create()
set myTable[1][1][1][1] = 10
set myTable[1][2][2][2] = 20
set myTable[2][1][1][1] = 30
set myTable[2][2][2][2] = 40
set myTable[3][3][3][3] = myTable
call Table2DT(myTable).print()
call myTable.destroy()
// create/destroy test 2
set myTable = Table4DT.create()
set myTable[1][2][3][4] = 100
set myTable[5][6][7][8] = 200
set myTable[9][10][11][12] = 300
set myTable[13][14][15][16] = 400
set myTable[17][18][19][20] = myTable
call Table2DT(myTable).print()
call myTable.destroy()
set myTable = Table4DT.create()
set myTable[1][1][1][1] = 10
set myTable[1][2][2][2] = 20
call BJDebugMsg("Should load 10: " + I2S(myTable[1][1][1][1]))
call BJDebugMsg("Should load 20: " + I2S(myTable[1][2][2][2]))
call myTable[1].remove(2)
call BJDebugMsg("Should no longer have the *[2][2][2] branch:")
call Table2DT(myTable).print()
// remove Test 3: Destroy after remove
call myTable.destroy()
call BJDebugMsg("Should not print anything")
call Table2DT(myTable).print()
// remove Test 4: Self-reference and remove
set myTable = Table4DT.create()
set myTable[3][3][myTable][myTable] = myTable
call BJDebugMsg("Should contain self-reference at [3][3][*][*]")
call Table2DT(myTable).print()
call myTable[3][3].remove(myTable)
call BJDebugMsg("Should now only show [3][3] as indexed")
call Table2DT(myTable).print()
call myTable.destroy()
endfunction
//===========================================================================
function InitTrig_Test takes nothing returns nothing
call TimerStart(CreateTimer(), 0.01, false, function Trig_Test_Actions )
endfunction
save/store/write
instead of just []=
.N
) and indices 1-N
contain all of the keys in your table. So you can loop through all of your keys and do what you need or want with them, just like with a real programming language. Compares well with pairs
in Lua or Object.keys
in JavaScipt.function Trig_Test_Actions takes nothing returns nothing
// create/destroy test 1
local Table myTable = Table.create()
call myTable.link(1).link(1).link(1).save(1, 10)
call myTable.link(1).link(2).link(2).real.save(2, 20)
call myTable.link(2).link(1).link(1).boolean.save(1, false)
call myTable.link(2).link(2).link(2).string.save(2, "Hello, world")
call myTable.link(3).link(3).link(3).save(3, myTable)
call myTable.link(3).link(3).forkLink(69, 4).unit.save(0, null)
call myTable.print()
call myTable.destroy()
// create/destroy test 2
set myTable = Table.create()
call myTable.link(1).link(2).link(3).save(4, 100)
call myTable.link(5).link(6).link(7).save(8, 200)
call myTable.link(9).link(10).link(11).save(12, 300)
call myTable.link(13).link(14).link(15).save(16, 400)
call myTable.link(17).link(18).link(19).save(20, myTable)
call myTable.print()
call myTable.destroy()
set myTable = Table.create()
call myTable.link(1).link(1).link(1).save(1, 10)
call myTable.link(1).link(2).link(2).save(2, 20)
call BJDebugMsg("Should load 10: " + I2S(myTable[1][1][1][1]))
call BJDebugMsg("Should load 20: " + I2S(myTable[1][2][2][2]))
call myTable[1].remove(2)
call BJDebugMsg("Should no longer have the *[2][2][2] branch:")
call myTable.print()
// remove Test 3: Destroy after remove
call myTable.destroy()
call BJDebugMsg("Should print the Table as destroyed")
call myTable.print()
// remove Test 4: Self-reference and remove
set myTable = Table.create()
call myTable.link(3).link(3).link(myTable).save(myTable, myTable)
call BJDebugMsg("Should contain self-reference at [3][3][*][*]")
call myTable.print()
call myTable[3][3].remove(myTable)
call BJDebugMsg("Should now only show [3][3] as indexed")
call myTable.print()
call myTable.destroy()
endfunction
//===========================================================================
function InitTrig_Test takes nothing returns nothing
call TimerStart(CreateTimer(), 0.01, false, function Trig_Test_Actions )
endfunction
Thank you so much for this!Table Version 6 has just dropped, and it is the single largest undertaking I've worked on with this project since creating the original API years ago.
Indeed!So you can loop through all of your keys and do what you need or want with them, just like with a real programming language
//global Table heroAbility
local Table subtable = heroAbility.link(uix).link(abilityIndex).link(abilityEffects + 1) //next effect-index for this ability for this unit
//global HashTable heroAbility
local Table subtable
if abilityEffects == 0 then
set heroAbility[uix][abilityIndex] = Table.create()
endif
set subtable = Table(heroAbility[uix][abilityIndex])[abilityEffects + 1] //next effect-index for this ability for this unit
link
will always check if a key exists first, and create a new Table there if not.link
), you can use the normal [], get or read. So the extra effort is only needed on the first link/bind/join, and can be relaxed on follow-up references.local animalSounds = {
dog = "woof",
cat = "meow",
duck = "quack"
}
const animalSounds = {
dog: "woof",
cat: "meow",
duck: "quack"
};
local Table animalSounds = Table.create()/*
*/.string.write("dog", "woof")/*
*/.string.write("cat", "meow")/*
*/.string.write("duck", "quack")
Hi, is this live, can it be downloaded somewhere?Table Version 6 has just dropped, and it is the single largest undertaking I've worked on with this project since creating the original API years ago.
What's so special about version 6?
I've preserved backwards-compatibility with prior versions of Table as cleanly as possible. The deprecated TableArray and HashTable/TableXD syntax has been moved over to a separate resource, and all existing scripts will work fine as long as the map includes the Table5BC library.
- Every TableArray/HashTable method has been hoisted up to the Table struct itself.
- Tables can spawn new dimensions or forks (formerly TableArrays) on-demand, rather than needing to be created with their depth in mind.
- All values inside of a Table can be tracked, as long as you choose to use the new syntax of
save/store/write
instead of just[]=
.- Very powerful debugging of Table values when in TEST mode, which will help to isolate data issues very quickly.
- HandleTable/StringTable syntax is integrated directly into the Table API. Instead of save/[]/remove/has/link, you can use:
Handle-based keys: store/get/forget/stores/bind
String-based keys: write/read/delete/written/join- table.getKeys() returns a read-only Table listing all keys within contained in the Table. Index 0 contains the total number of keys inside of the table (
N
) and indices 1-N
contain all of the keys in your table. So you can loop through all of your keys and do what you need or want with them, just like with a real programming language. Compares well withpairs
in Lua orObject.keys
in JavaScipt.
Here are the new unit tests I've used:
JASS:function Trig_Test_Actions takes nothing returns nothing // create/destroy test 1 local Table myTable = Table.create() call myTable.link(1).link(1).link(1).save(1, 10) call myTable.link(1).link(2).link(2).real.save(2, 20) call myTable.link(2).link(1).link(1).boolean.save(1, false) call myTable.link(2).link(2).link(2).string.save(2, "Hello, world") call myTable.link(3).link(3).link(3).save(3, myTable) call myTable.link(3).link(3).forkLink(69, 4).unit.save(0, null) call myTable.print() call myTable.destroy() // create/destroy test 2 set myTable = Table.create() call myTable.link(1).link(2).link(3).save(4, 100) call myTable.link(5).link(6).link(7).save(8, 200) call myTable.link(9).link(10).link(11).save(12, 300) call myTable.link(13).link(14).link(15).save(16, 400) call myTable.link(17).link(18).link(19).save(20, myTable) call myTable.print() call myTable.destroy() set myTable = Table.create() call myTable.link(1).link(1).link(1).save(1, 10) call myTable.link(1).link(2).link(2).save(2, 20) call BJDebugMsg("Should load 10: " + I2S(myTable[1][1][1][1])) call BJDebugMsg("Should load 20: " + I2S(myTable[1][2][2][2])) call myTable[1].remove(2) call BJDebugMsg("Should no longer have the *[2][2][2] branch:") call myTable.print() // remove Test 3: Destroy after remove call myTable.destroy() call BJDebugMsg("Should print the Table as destroyed") call myTable.print() // remove Test 4: Self-reference and remove set myTable = Table.create() call myTable.link(3).link(3).link(myTable).save(myTable, myTable) call BJDebugMsg("Should contain self-reference at [3][3][*][*]") call myTable.print() call myTable[3][3].remove(myTable) call BJDebugMsg("Should now only show [3][3] as indexed") call myTable.print() call myTable.destroy() endfunction //=========================================================================== function InitTrig_Test takes nothing returns nothing call TimerStart(CreateTimer(), 0.01, false, function Trig_Test_Actions ) endfunction
Yes it is - [Lua][vJass] New TableHi, is this live, can it be downloaded somewhere?