persist-table tweaks, delete debug print messages

develop
expwnent 2014-11-16 20:41:11 -05:00
parent f2e594ddfb
commit 97b44d5898
1 changed files with 76 additions and 117 deletions

@ -8,115 +8,65 @@ author expwnent
This module is intended to help facilitate persistent table lookups. This module is intended to help facilitate persistent table lookups.
It is a wrapper over dfhack.persistent calls. It is a wrapper over dfhack.persistent calls.
It supports tables of arbitrary dimension and shape. It supports tables of arbitrary dimension and shape.
Argument names should not include any of the following symbols: _\/&
It stores information about each table and subtable's size and children. It stores information about each table and subtable's size and children.
For convenience, all stored information is itself persistent. For convenience, all stored information is itself persistent.
It would be more efficient to cache stored information in global variables and update it on save/load but this is not yet implemented. It would be more efficient to cache stored information in global variables and update it on save/load but this is not yet implemented.
Ask expwnent to try this if performance is bad. Ask expwnent to try this if performance is bad.
--]]
--[[ Usage:
function accessTable(...) local persistTable = require 'persist-table'
local args = {...} persistTable.GlobalTable.doomitude = 'doom!' -- will be stored persistently
local name = 'mastertable' print(persistTable.GlobalTable.doomitude) --doom!
local previousName = nil persistTable.GlobalTable.doomitude = nil --delete the persistent record
local child print(persistTable.GlobalTable.doomitude) --nil
for n,arg in ipairs(args) do
child = ensure(prefix .. name .. '$$' .. arg) persistTable.GlobalTable.mana = {} --allocate a subtable for mana
local old = child.value local mana = persistTable.GlobalTable.mana --setting elements in this table will be persistent too
if old == '' then mana['1'] = '3' --slightly faster than persistTable.GlobalTable.mana['1'] = '3'
child.value = gensym() --be aware that if you don't change the local variable mana when the game exits and reloads a different save you will run into mysterious problems so don't do that
child.ints[1] = 0 mana['2'] = '100'
local size = ensure(prefix .. name .. '$size') mana.maximum = '1000' --tables can be any arbitrary shape
size.value = tostring(1+(tonumber(size.value) or 0)) local globalTable = persistTable.GlobalTable --this is safe too
size:save() globalTable.mana = nil --this is safe: it will deallocate all subtables cleanly
if previousName then globalTable.revengeDesire = {}
--local size = ensure(previousName .. '$size') --globalTable.revengeDseire.foo = {} -- error: tables must be allocated first with parentTable.subtableName = {}
--size.value = tostring(1+(tonumber(size.value) or 0)) --you can check if it exists with globalTable.tableName != nil
--size:save() local revengeTable = globalTable.revengeDesire
local prev = ensure(prefix .. name .. '$previous') revengeTable['2'] = revengeTable['2'] or {} --this is fine too
prev.value = previousName revengeTable['2']['3'] = 'totally a lot, man'
prev:save() revengeTable['3'] = {}
end revengeTable['3']['2'] = 'maybe a little bit'
child:save() revengeTable['2'] = nil
--new child -------------
dfhack.persistent.save({key=prefix .. name, value=arg}, true) And so on.
end
--print(n,arg,previousName,child.key,child.value) Be careful not to name your tables in a way that will conflict with other scripts! The easiest way is to just put all your tables in one giant table named based on your script.
previousName = name
name = child.value All stored values MUST be strings. Numbers can be supported later but are not yet supported. Keep in mind there is a significant overhead for each table element so don't go totally crazy storing massive amounts of information or the game will run out of RAM.
end
return child --table._children returns a list of child keys
for _,childKey in ipairs(table._children) do
local child = table[childKey]
--blah
end end
function deleteTable(name)
if not name then
do return end
end
local previous = ensure(prefix .. name .. '$previous').value
local children = dfhack.persistent.get_all(prefix .. name) or {}
for _,child in ipairs(children) do
--print('delete: ', name, previous, child)
local ptr = ensure(prefix .. name .. '$$' .. child.value)
if ( ptr.ints[1] == 0 ) then
--releasesym(ptr.value)
deleteTable(ptr.value)
end
ptr:delete()
child:delete()
end
ensure(prefix .. name .. '$previous'):delete()
ensure(prefix .. name .. '$size'):delete()
if previous ~= '' then
local size = ensure(prefix .. previous .. '$size')
size.value = tostring(-1 + tonumber(size.value))
size:save()
local children = dfhack.persistent.get_all(prefix .. previous) or {}
for _,sibling in ipairs(children) do
--print(sibling.value, name, previous .. '$$' .. sibling.value)
local ptr = ensure(prefix .. previous .. '$$' .. sibling.value)
if ptr.value == name then
ptr:delete()
sibling:delete()
end
end
end
releasesym(name)
end
function setTable(...)
local args = {...}
local last = args[#args]
table.remove(args,#args)
--table.setn(args, #args-1)
local entry = accessTable(table.unpack(args))
local old = entry.value
if entry.ints[1] == 0 then
deleteTable(old)
end
entry.ints[1] = -1
entry.value = last
entry:save()
return old
end
--]] --]]
local prefix = 'persist-table'
prefix = 'persist-table' local function ensure(name)
function ensure(name)
return dfhack.persistent.save({key=name}) return dfhack.persistent.save({key=name})
end end
function gensym() local function gensym()
local availables = dfhack.persistent.get_all(prefix .. '$available') or {} local availables = dfhack.persistent.get_all(prefix .. '$available') or {}
local available = nil local available = nil
local smallest = nil local smallest = nil
for _,candidate in pairs(availables) do for _,candidate in pairs(availables) do
--TODO: it would be great if we could iterate over these in order but we can't --TODO: it would be great if we could iterate over these in order but we can't
local score = tonumber(candidate.value) local score = tonumber(candidate.value)
print('gensym', candidate, score, available, smallest) --print('gensym', candidate, score, available, smallest)
if (score and (not available or score < smallest)) then if (score and (not available or score < smallest)) then
smallest = score smallest = score
available = candidate available = candidate
@ -125,7 +75,7 @@ function gensym()
if available then if available then
local value = available.value local value = available.value
available:delete() available:delete()
print('gensym: allocate ' .. value) --print('gensym: allocate ' .. value)
return value return value
end end
--none explicitly available, so smallest unused is the next available number --none explicitly available, so smallest unused is the next available number
@ -136,21 +86,21 @@ function gensym()
local result = smallestUnused.value local result = smallestUnused.value
smallestUnused.value = tostring(1+tonumber(result)) smallestUnused.value = tostring(1+tonumber(result))
smallestUnused:save() smallestUnused:save()
print('gensym: allocate ' .. result) --print('gensym: allocate ' .. result)
return result return result
end end
function releasesym(symb) local function releasesym(symb)
local availables = dfhack.persistent.get_all(prefix .. '$available') or {} local availables = dfhack.persistent.get_all(prefix .. '$available') or {}
for _,available in pairs(availables) do for _,available in pairs(availables) do
print('releasesym: ', symb, available.value, available) --print('releasesym: ', symb, available.value, available)
if available.value == symb then if available.value == symb then
print('error: persist-table.releasesym(' .. symb .. '): available.value = ' .. available.value) print('error: persist-table.releasesym(' .. symb .. '): available.value = ' .. available.value)
return return
end end
end end
dfhack.persistent.save({key=prefix .. '$available', value=symb}, true) dfhack.persistent.save({key=prefix .. '$available', value=symb}, true)
print('releasesym: unallocate ' .. symb) --print('releasesym: unallocate ' .. symb)
end end
local intCount = 7 local intCount = 7
local existIndex = intCount-0 local existIndex = intCount-0
@ -179,30 +129,39 @@ local function deletePersistent(name)
releasesym(name) releasesym(name)
end end
GlobalTable = {key = 'mastertable'} GlobalTable = GlobalTable or {key = 'mastertable'}
GlobalTable.mt = {} GlobalTable.mt = GlobalTable.mt or {}
GlobalTable.mt.__index = function(table, key) GlobalTable.mt.__index = GlobalTable.mt.__index or function(theTable, key)
print(rawget(table,'key') .. '[' .. key .. ']') if key == '_children' then
local entry = ensure(prefix .. rawget(table,'key') .. '$$' .. key) return rawget(theTable,key)
end
--print(rawget(theTable,'key') .. '[' .. key .. ']')
local entry = ensure(prefix .. rawget(theTable,'key') .. '$$' .. key)
if entry.ints[existIndex] == existValue and entry.ints[pointerIndex] == defaultValue then if entry.ints[existIndex] == existValue and entry.ints[pointerIndex] == defaultValue then
print('string: ' .. entry.value) --print('string: ' .. entry.value)
return entry.value return entry.value
end end
if entry.ints[pointerIndex] == pointerValue then if entry.ints[pointerIndex] == pointerValue then
--pre-existing pointer --pre-existing pointer
local result = {key = entry.value} local result = {key = entry.value}
result.mt = rawget(GlobalTable,'mt') result.mt = rawget(GlobalTable,'mt')
local childArgs = dfhack.persistent.get_all(prefix .. entry.value)
result._children = {}
for _,childArg in ipairs(childArgs or {}) do
--print(result._children, childArg.value)
table.insert(result._children, childArg.value)
end
setmetatable(result,rawget(GlobalTable,'mt')) setmetatable(result,rawget(GlobalTable,'mt'))
print('table: ' .. entry.value) --print('theTable: ' .. entry.value)
return result return result
end end
entry:delete() entry:delete()
print 'table[key] does not exist.' --print 'theTable[key] does not exist.'
return nil return nil
end end
GlobalTable.mt.__newindex = function(table, key, value) GlobalTable.mt.__newindex = GlobalTable.mt.__newindex or function(theTable, key, value)
print(rawget(table,'key') .. '[' .. key .. '] = ' .. tostring(value)) --print(rawget(theTable,'key') .. '[' .. key .. '] = ' .. tostring(value))
local entry = ensure(prefix .. rawget(table,'key') .. '$$' .. key) local entry = ensure(prefix .. rawget(theTable,'key') .. '$$' .. key)
local old = entry.value local old = entry.value
local isNew = entry.ints[existIndex] == defaultValue local isNew = entry.ints[existIndex] == defaultValue
if entry.ints[existIndex] == existValue and entry.ints[pointerIndex] == pointerValue then if entry.ints[existIndex] == existValue and entry.ints[pointerIndex] == pointerValue then
@ -213,9 +172,9 @@ GlobalTable.mt.__newindex = function(table, key, value)
deletePersistent(entry.value) deletePersistent(entry.value)
end end
if not value then if not value then
print('__newindesx: delete') --print('__newindesx: delete')
--delete --delete
for i,child in ipairs(dfhack.persistent.get_all(prefix .. rawget(table,'key')) or {}) do for i,child in ipairs(dfhack.persistent.get_all(prefix .. rawget(theTable,'key')) or {}) do
if child.value == key then if child.value == key then
child:delete() child:delete()
end end
@ -223,23 +182,23 @@ GlobalTable.mt.__newindex = function(table, key, value)
entry:delete() entry:delete()
return return
elseif type(value) == 'string' then elseif type(value) == 'string' then
print('__newindesx: string') --print('__newindesx: string')
entry.value = value entry.value = value
entry.ints[pointerIndex] = defaultValue entry.ints[pointerIndex] = defaultValue
entry.ints[existIndex] = existValue entry.ints[existIndex] = existValue
entry:save() entry:save()
if isNew then if isNew then
print('new child!') --print('new child!')
dfhack.persistent.save({key=prefix .. rawget(table,'key'), value=key}, true) dfhack.persistent.save({key=prefix .. rawget(theTable,'key'), value=key}, true)
end end
return return
elseif type(value) == 'table' then elseif type(value) == 'table' then
print('__newindesx: table') --print('__newindesx: table')
if rawget(value,'mt') ~= rawget(GlobalTable,'mt') then if rawget(value,'mt') ~= rawget(GlobalTable,'mt') then
if not isEmpty(value) then if not isEmpty(value) then
error('setting value to an invalid table') error('setting value to an invalid table')
end end
print('__newindesx: empty table') --print('__newindesx: empty table')
--empty table: allocate a thing --empty table: allocate a thing
entry.ints[pointerIndex] = pointerValue entry.ints[pointerIndex] = pointerValue
entry.ints[existIndex] = existValue entry.ints[existIndex] = existValue
@ -247,19 +206,19 @@ GlobalTable.mt.__newindex = function(table, key, value)
entry:save() entry:save()
if isNew then if isNew then
print('new child!') --print('new child!')
dfhack.persistent.save({key=prefix .. rawget(table,'key'), value=key}, true) dfhack.persistent.save({key=prefix .. rawget(theTable,'key'), value=key}, true)
end end
return return
end end
print('__newindesx: table assignment') --print('__newindesx: table assignment')
entry.value = rawget(value,'key') entry.value = rawget(value,'key')
entry.ints[pointerIndex] = pointerValue entry.ints[pointerIndex] = pointerValue
entry.ints[existIndex] = existValue entry.ints[existIndex] = existValue
entry:save() entry:save()
if isNew then if isNew then
print('new child!') --print('new child!')
dfhack.persistent.save({key=prefix .. rawget(table,'key'), value=key}, true) dfhack.persistent.save({key=prefix .. rawget(theTable,'key'), value=key}, true)
end end
return return
else else