Table Persistence

lua-users home
wiki

TablePersistence is a small code snippet that allows storing and loading of lua variables containing primitive types. It is licensed under the MIT license, use it how ever is needed. A more detailed description and complete source can be downloaded on http://the-color-black.net/blog/article/LuaTablePersistence. A fork has been created on github that included lunatest unit tests: https://github.com/hipe/lua-table-persistence

Shortcomings/Limitations:

 local write, writeIndent, writers, refCount; persistence = {	store = function (path, ...) local file, e = io.open(path, "w"); if not file then return error(e); end local n = select("#", ...); -- Count references local objRefCount = {}; -- Stores reference that will be exported for i = 1, n do	refCount(objRefCount, (select(i,...))); end; -- Export Objects with more than one ref and assign name -- First, create empty tables for each local objRefNames = {}; local objRefIdx = 0;	file:write("-- Persistent Data\n");	file:write("local multiRefObjects = {\n"); for obj, count in pairs(objRefCount) do if count > 1 then	objRefIdx = objRefIdx + 1;	objRefNames[obj] = objRefIdx;	file:write("{};"); -- table objRefIdx end; end;	file:write("\n} -- multiRefObjects\n"); -- Then fill them (this requires all empty multiRefObjects to exist) for obj, idx in pairs(objRefNames) do for k, v in pairs(obj) do	file:write("multiRefObjects["..idx.."][");	write(file, k, 0, objRefNames);	file:write("] = ");	write(file, v, 0, objRefNames);	file:write(";\n"); end; end; -- Create the remaining objects for i = 1, n do	file:write("local ".."obj"..i.." = ");	write(file, (select(i,...)), 0, objRefNames);	file:write("\n"); end -- Return them if n > 0 then	file:write("return obj1"); for i = 2, n do	file:write(" ,obj"..i); end;	file:write("\n"); else	file:write("return\n"); end; if type(path) == "string" then	file:close(); end; end; load = function (path) local f, e; if type(path) == "string" then	f, e = loadfile(path); else	f, e = path:read('*a') end if f then return f(); else return nil, e; end; end; } -- Private methods -- write thing (dispatcher) write = function (file, item, level, objRefNames)	writers[type(item)](file, item, level, objRefNames); end; -- write indent writeIndent = function (file, level) for i = 1, level do	file:write("\t"); end; end; -- recursively count references refCount = function (objRefCount, item) -- only count reference types (tables) if type(item) == "table" then -- Increase ref count if objRefCount[item] then	objRefCount[item] = objRefCount[item] + 1; else	objRefCount[item] = 1; -- If first encounter, traverse for k, v in pairs(item) do	refCount(objRefCount, k);	refCount(objRefCount, v); end; end; end; end; -- Format items for the purpose of restoring writers = {	["nil"] = function (file, item)	file:write("nil"); end;	["number"] = function (file, item)	file:write(tostring(item)); end;	["string"] = function (file, item)	file:write(string.format("%q", item)); end;	["boolean"] = function (file, item) if item then	file:write("true"); else	file:write("false"); end end;	["table"] = function (file, item, level, objRefNames) local refIdx = objRefNames[item]; if refIdx then -- Table with multiple references	file:write("multiRefObjects["..refIdx.."]"); else -- Single use table	file:write("{\n"); for k, v in pairs(item) do	writeIndent(file, level+1);	file:write("[");	write(file, k, level+1, objRefNames);	file:write("] = ");	write(file, v, level+1, objRefNames);	file:write(";\n"); end	writeIndent(file, level);	file:write("}"); end; end;	["function"] = function (file, item) -- Does only work for "normal" functions, not those -- with upvalues or c functions local dInfo = debug.getinfo(item, "uS"); if dInfo.nups > 0 then	file:write("nil --[[functions with upvalue not supported]]"); elseif dInfo.what ~= "Lua" then	file:write("nil --[[non-lua function not supported]]"); else local r, s = pcall(string.dump,item); if r then	file:write(string.format("loadstring(%q)", s)); else	file:write("nil --[[function could not be dumped]]"); end end end;	["thread"] = function (file, item)	file:write("nil --[[thread]]\n"); end;	["userdata"] = function (file, item)	file:write("nil --[[userdata]]\n"); end; } 

It is used like this:

 t_original = {1, 2, ["a"] = "string", b = "test", {"subtable", [4] = 2}}; persistence.store("storage.lua", t_original); t_restored = persistence.load("storage.lua"); 

Example output (storage.lua):

 -- Persistent Data return {	[1] = 1;	[2] = 2;	[3] = {	[1] = "subtable";	[4] = 2;	};	["a"] = "string";	["b"] = "test"; } 

See Also


RecentChanges · preferences
edit · history
Last edited January 24, 2016 11:42 am GMT (diff)