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.
It is a wrapper over dfhack.persistent calls.
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.
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.
Ask expwnent to try this if performance is bad.
--]]
--[[
function accessTable(...)
local args = {...}
local name = 'mastertable'
local previousName = nil
local child
for n,arg in ipairs(args) do
child = ensure(prefix .. name .. '$$' .. arg)
local old = child.value
if old == '' then
child.value = gensym()
child.ints[1] = 0
local size = ensure(prefix .. name .. '$size')
size.value = tostring(1+(tonumber(size.value) or 0))
size:save()
if previousName then
--local size = ensure(previousName .. '$size')
--size.value = tostring(1+(tonumber(size.value) or 0))
--size:save()
local prev = ensure(prefix .. name .. '$previous')
prev.value = previousName
prev:save()
end
child:save()
--new child
dfhack.persistent.save({key=prefix .. name, value=arg}, true)
end
--print(n,arg,previousName,child.key,child.value)
previousName = name
name = child.value
end
return child
Usage:
local persistTable = require 'persist-table'
persistTable.GlobalTable.doomitude = 'doom!' -- will be stored persistently
print(persistTable.GlobalTable.doomitude) --doom!
persistTable.GlobalTable.doomitude = nil --delete the persistent record
print(persistTable.GlobalTable.doomitude) --nil
persistTable.GlobalTable.mana = {} --allocate a subtable for mana
local mana = persistTable.GlobalTable.mana --setting elements in this table will be persistent too
mana['1'] = '3' --slightly faster than persistTable.GlobalTable.mana['1'] = '3'
--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
mana['2'] = '100'
mana.maximum = '1000' --tables can be any arbitrary shape
local globalTable = persistTable.GlobalTable --this is safe too
globalTable.mana = nil --this is safe: it will deallocate all subtables cleanly
globalTable.revengeDesire = {}
--globalTable.revengeDseire.foo = {} -- error: tables must be allocated first with parentTable.subtableName = {}
--you can check if it exists with globalTable.tableName != nil
local revengeTable = globalTable.revengeDesire
revengeTable['2'] = revengeTable['2'] or {} --this is fine too
revengeTable['2']['3'] = 'totally a lot, man'
revengeTable['3'] = {}
revengeTable['3']['2'] = 'maybe a little bit'
revengeTable['2'] = nil
-------------
And so on.
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.
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.
--table._children returns a list of child keys
for _,childKey in ipairs(table._children) do
local child = table[childKey]
--blah
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'
function ensure(name)
local function ensure(name)
return dfhack.persistent.save({key=name})
end
function gensym()
local function gensym()
local availables = dfhack.persistent.get_all(prefix .. '$available') or {}
local available = nil
local smallest = nil
for _,candidate in pairs(availables) do
--TODO: it would be great if we could iterate over these in order but we can't
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
smallest = score
available = candidate
@ -125,7 +75,7 @@ function gensym()
if available then
local value = available.value
available:delete()
print('gensym: allocate ' .. value)
--print('gensym: allocate ' .. value)
return value
end
--none explicitly available, so smallest unused is the next available number
@ -136,21 +86,21 @@ function gensym()
local result = smallestUnused.value
smallestUnused.value = tostring(1+tonumber(result))
smallestUnused:save()
print('gensym: allocate ' .. result)
--print('gensym: allocate ' .. result)
return result
end
function releasesym(symb)
local function releasesym(symb)
local availables = dfhack.persistent.get_all(prefix .. '$available') or {}
for _,available in pairs(availables) do
print('releasesym: ', symb, available.value, available)
--print('releasesym: ', symb, available.value, available)
if available.value == symb then
print('error: persist-table.releasesym(' .. symb .. '): available.value = ' .. available.value)
return
end
end
dfhack.persistent.save({key=prefix .. '$available', value=symb}, true)
print('releasesym: unallocate ' .. symb)
--print('releasesym: unallocate ' .. symb)
end
local intCount = 7
local existIndex = intCount-0
@ -179,30 +129,39 @@ local function deletePersistent(name)
releasesym(name)
end
GlobalTable = {key = 'mastertable'}
GlobalTable.mt = {}
GlobalTable.mt.__index = function(table, key)
print(rawget(table,'key') .. '[' .. key .. ']')
local entry = ensure(prefix .. rawget(table,'key') .. '$$' .. key)
GlobalTable = GlobalTable or {key = 'mastertable'}
GlobalTable.mt = GlobalTable.mt or {}
GlobalTable.mt.__index = GlobalTable.mt.__index or function(theTable, key)
if key == '_children' then
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
print('string: ' .. entry.value)
--print('string: ' .. entry.value)
return entry.value
end
if entry.ints[pointerIndex] == pointerValue then
--pre-existing pointer
local result = {key = entry.value}
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'))
print('table: ' .. entry.value)
--print('theTable: ' .. entry.value)
return result
end
entry:delete()
print 'table[key] does not exist.'
--print 'theTable[key] does not exist.'
return nil
end
GlobalTable.mt.__newindex = function(table, key, value)
print(rawget(table,'key') .. '[' .. key .. '] = ' .. tostring(value))
local entry = ensure(prefix .. rawget(table,'key') .. '$$' .. key)
GlobalTable.mt.__newindex = GlobalTable.mt.__newindex or function(theTable, key, value)
--print(rawget(theTable,'key') .. '[' .. key .. '] = ' .. tostring(value))
local entry = ensure(prefix .. rawget(theTable,'key') .. '$$' .. key)
local old = entry.value
local isNew = entry.ints[existIndex] == defaultValue
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)
end
if not value then
print('__newindesx: delete')
--print('__newindesx: 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
child:delete()
end
@ -223,23 +182,23 @@ GlobalTable.mt.__newindex = function(table, key, value)
entry:delete()
return
elseif type(value) == 'string' then
print('__newindesx: string')
--print('__newindesx: string')
entry.value = value
entry.ints[pointerIndex] = defaultValue
entry.ints[existIndex] = existValue
entry:save()
if isNew then
print('new child!')
dfhack.persistent.save({key=prefix .. rawget(table,'key'), value=key}, true)
--print('new child!')
dfhack.persistent.save({key=prefix .. rawget(theTable,'key'), value=key}, true)
end
return
elseif type(value) == 'table' then
print('__newindesx: table')
--print('__newindesx: table')
if rawget(value,'mt') ~= rawget(GlobalTable,'mt') then
if not isEmpty(value) then
error('setting value to an invalid table')
end
print('__newindesx: empty table')
--print('__newindesx: empty table')
--empty table: allocate a thing
entry.ints[pointerIndex] = pointerValue
entry.ints[existIndex] = existValue
@ -247,19 +206,19 @@ GlobalTable.mt.__newindex = function(table, key, value)
entry:save()
if isNew then
print('new child!')
dfhack.persistent.save({key=prefix .. rawget(table,'key'), value=key}, true)
--print('new child!')
dfhack.persistent.save({key=prefix .. rawget(theTable,'key'), value=key}, true)
end
return
end
print('__newindesx: table assignment')
--print('__newindesx: table assignment')
entry.value = rawget(value,'key')
entry.ints[pointerIndex] = pointerValue
entry.ints[existIndex] = existValue
entry:save()
if isNew then
print('new child!')
dfhack.persistent.save({key=prefix .. rawget(table,'key'), value=key}, true)
--print('new child!')
dfhack.persistent.save({key=prefix .. rawget(theTable,'key'), value=key}, true)
end
return
else