diff --git a/library/lua/persist-table.lua b/library/lua/persist-table.lua new file mode 100644 index 000000000..387926eca --- /dev/null +++ b/library/lua/persist-table.lua @@ -0,0 +1,121 @@ + +local _ENV = mkmodule('persist-table') + +symbols = symbols or {} +symbolCount = symbolCount or {} + +function ensure(name) + return dfhack.persistent.save({key=name}) +end + +function gensym(prefix) + if not symbols[prefix] then + symbols[prefix] = {} + end + local sym = symbols[prefix] or {} + local i = 0 + while true do + if not sym[i] then + symbols[prefix][i] = true + symbolCount[prefix] = math.max(symbolCount[prefix] or 0,i) + return prefix .. '&' .. tostring(i) + end + i = i+1 + end +end + +function releasesym(prefix, symb) + local sym = symbols[prefix] or {} + local i = 0 + while true do + if prefix .. '&' .. tostring(i) == symb then + symbols[prefix][i] = nil + --symbolCount[prefix] = -1 + symbolCount[prefix] + end + i = i+1 + if i > symbolCount[prefix] then + return + end + end +end + +function accessTable(prefix,...) + local args = {...} + local name = '__master_table' + local previousName = nil + local child + for n,arg in ipairs(args) do + child = ensure(name .. '$$' .. arg) + local old = child.value + if old == '' then + child.value = gensym(prefix) + local size = ensure(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(name .. '$previous') + prev.value = previousName + prev:save() + end + child:save() + --new child + dfhack.persistent.save({key=name, value=arg}, true) + end + --print(n,arg,previousName,child.key,child.value) + previousName = name + name = child.value + end + return child +end + +function deleteTable(prefix,name) + if not name then + do return end + end + local previous = ensure(name .. '$previous').value + local children = dfhack.persistent.get_all(name) or {} + for _,child in ipairs(children) do + --print('delete: ', name, previous, child) + local ptr = ensure(name .. '$$' .. child.value) + releasesym(prefix,ptr.value) + deleteTable(prefix,ptr.value) + ptr:delete() + child:delete() + end + ensure(name .. '$previous'):delete() + ensure(name .. '$size'):delete() + if previous ~= '' then + local size = ensure(previous .. '$size') + size.value = tostring(-1 + tonumber(size.value)) + size:save() + local children = dfhack.persistent.get_all(previous) or {} + for _,sibling in ipairs(children) do + --print(sibling.value, name, previous .. '$$' .. sibling.value) + local ptr = ensure(previous .. '$$' .. sibling.value) + if ptr.value == name then + ptr:delete() + sibling:delete() + end + end + end + releasesym(prefix,name) +end + +function setTable(prefix,...) + local args = {...} + local last = args[#args] + table.remove(args,#args) + --table.setn(args, #args-1) + local entry = accessTable(prefix,table.unpack(args)) + local old = entry.value + deleteTable(prefix,old) + releasesym(prefix,old) + entry.value = last + entry:save() + return old +end + +return _ENV