Change directory structure
This commit is contained in:
513
luprex/ext/eris-master/test/persist.lua
Normal file
513
luprex/ext/eris-master/test/persist.lua
Normal file
@@ -0,0 +1,513 @@
|
||||
local rootobj = {}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Used by C callbacks, so let's define it first.
|
||||
|
||||
function booleanpersist(udata)
|
||||
local b = unboxboolean(udata)
|
||||
return function()
|
||||
return boxboolean(b)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Permanent values.
|
||||
|
||||
local permtable = { 1234 }
|
||||
|
||||
rootobj.testperm = permtable
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Basic value types.
|
||||
|
||||
rootobj.testnil = nil
|
||||
rootobj.testfalse = false
|
||||
rootobj.testtrue = true
|
||||
rootobj.testludata = createludata()
|
||||
rootobj.testseven = 7
|
||||
rootobj.testfoobar = "foobar"
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Tables.
|
||||
|
||||
local testtbl = { a = 2, [2] = 4 }
|
||||
|
||||
rootobj.testtbl = testtbl
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- NaNs in tables (checks that this doesn't break the internal ref table).
|
||||
|
||||
local nantable = {}
|
||||
nantable[1] = 0/0
|
||||
|
||||
rootobj.testnan = nantable
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Cycles in tables.
|
||||
|
||||
local testloopa = {}
|
||||
local testloopb = { testloopa = testloopa }
|
||||
testloopa.testloopb = testloopb
|
||||
|
||||
rootobj.testlooptable = testloopa
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Metatables.
|
||||
|
||||
local twithmt = {}
|
||||
setmetatable( twithmt, { __call = function() return 21 end } )
|
||||
|
||||
rootobj.testmt = twithmt
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Yet more metatables.
|
||||
|
||||
local niinmt = { a = 3 }
|
||||
setmetatable(niinmt, {__newindex = function(key, val) end })
|
||||
|
||||
rootobj.testniinmt = niinmt
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Literal userdata.
|
||||
|
||||
local literaludata = boxinteger(71)
|
||||
|
||||
rootobj.testliteraludata = literaludata
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Functions (closures without upvalues).
|
||||
|
||||
local function func()
|
||||
return 4
|
||||
end
|
||||
|
||||
rootobj.testfuncreturnsfour = func
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Environment. This is really redundant in 5.2 since envs are just upvalues,
|
||||
-- but it may still be considered somewhat special.
|
||||
local testfenv = (function()
|
||||
local _ENV = { abc = 456 }
|
||||
return function()
|
||||
return abc
|
||||
end
|
||||
end)()
|
||||
|
||||
rootobj.testfenv = testfenv
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Closures.
|
||||
|
||||
local function funcreturningclosure(n)
|
||||
return function()
|
||||
return n
|
||||
end
|
||||
end
|
||||
|
||||
rootobj.testclosure = funcreturningclosure(11)
|
||||
rootobj.testnilclosure = funcreturningclosure(nil)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- More closures.
|
||||
|
||||
local function nestedfunc(n)
|
||||
return (function(m) return m+2 end)(n+3)
|
||||
end
|
||||
|
||||
rootobj.testnest = nestedfunc
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Cycles in upvalues.
|
||||
|
||||
local function GenerateObjects()
|
||||
local Table = {}
|
||||
|
||||
function Table:Func()
|
||||
return { Table, self }
|
||||
end
|
||||
|
||||
function uvcycle()
|
||||
return Table:Func()
|
||||
end
|
||||
end
|
||||
|
||||
GenerateObjects()
|
||||
|
||||
rootobj.testuvcycle = uvcycle
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Special callback for persisting tables.
|
||||
--
|
||||
-- Note: the __persist metamethod was deliberately disabled in the
|
||||
-- luprex version of eris. Therefore this unit test was also disabled.
|
||||
--
|
||||
|
||||
-- local sptable = { a = 3 }
|
||||
--
|
||||
-- setmetatable(sptable, {
|
||||
-- __persist = function(tbl)
|
||||
-- local a = tbl.a
|
||||
-- return function()
|
||||
-- return { a = a+3 }
|
||||
-- end
|
||||
-- end
|
||||
-- })
|
||||
--
|
||||
-- rootobj.testsptable = sptable
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Special callbacks for persisting userdata.
|
||||
|
||||
rootobj.testspudata1 = boxboolean(true)
|
||||
rootobj.testspudata2 = boxboolean(false)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Reference correctness.
|
||||
|
||||
local sharedref = {}
|
||||
refa = {sharedref = sharedref}
|
||||
refb = {sharedref = sharedref}
|
||||
|
||||
rootobj.testsharedrefa = refa
|
||||
rootobj.testsharedrefb = refb
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Shared upvalues (like reference correctness for upvalues).
|
||||
|
||||
local function makecounter()
|
||||
local a = 0
|
||||
return {
|
||||
inc = function() a = a + 1 end,
|
||||
cur = function() return a end
|
||||
}
|
||||
end
|
||||
|
||||
rootobj.testsharedupval = makecounter()
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Debug info.
|
||||
|
||||
local function debuginfo(foo)
|
||||
foo = foo + foo
|
||||
return debug.getlocal(1,1)
|
||||
end
|
||||
|
||||
rootobj.testdebuginfo = debuginfo
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Suspended thread.
|
||||
|
||||
local function fc(i)
|
||||
local ic = i + 1
|
||||
coroutine.yield()
|
||||
return ic*2
|
||||
end
|
||||
|
||||
local function fb(i)
|
||||
local ib = i + 1
|
||||
ib = ib + fc(ib)
|
||||
return ib
|
||||
end
|
||||
|
||||
local function fa(i)
|
||||
local ia = i + 1
|
||||
return fb(ia)
|
||||
end
|
||||
|
||||
local thr = coroutine.create(fa)
|
||||
coroutine.resume(thr, 2)
|
||||
|
||||
rootobj.testthread = thr
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Not yet started thread.
|
||||
|
||||
rootobj.testnthread = coroutine.create(function() return func() end)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Dead thread.
|
||||
|
||||
local deadthr = coroutine.create(function() return func() end)
|
||||
coroutine.resume(deadthr)
|
||||
|
||||
rootobj.testdthread = deadthr
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Open upvalues (stored in thread stack).
|
||||
|
||||
local function uvinthreadfunc()
|
||||
local a = 1
|
||||
local b = function()
|
||||
a = a+1
|
||||
coroutine.yield(a)
|
||||
a = a+1
|
||||
end
|
||||
a = a+1
|
||||
b()
|
||||
a = a+1
|
||||
return a
|
||||
end
|
||||
|
||||
local uvinthread = coroutine.create(uvinthreadfunc)
|
||||
coroutine.resume(uvinthread)
|
||||
|
||||
rootobj.testuvinthread = uvinthread
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Yield across pcall.
|
||||
|
||||
local function protf(arg)
|
||||
coroutine.yield()
|
||||
error(arg, 0)
|
||||
end
|
||||
local function protthreadfunc()
|
||||
local res, err = pcall(protf, "test")
|
||||
return err
|
||||
end
|
||||
|
||||
local protthr = coroutine.create(protthreadfunc)
|
||||
coroutine.resume(protthr)
|
||||
|
||||
rootobj.testprotthr = protthr
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Yield across xpcall with message handler.
|
||||
|
||||
local function xprotthreadfunc()
|
||||
local function handler(msg)
|
||||
return "handler:" .. msg
|
||||
end
|
||||
local res, err = xpcall(protf, handler, "test")
|
||||
return err
|
||||
end
|
||||
|
||||
local xprotthr = coroutine.create(xprotthreadfunc)
|
||||
coroutine.resume(xprotthr)
|
||||
|
||||
rootobj.testxprotthr = xprotthr
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Yield out of metafunction.
|
||||
|
||||
local function ymtf(arg)
|
||||
coroutine.yield()
|
||||
return true
|
||||
end
|
||||
function ymtthreadfunc()
|
||||
local t = setmetatable({}, {__lt = ymtf})
|
||||
return t < 5
|
||||
end
|
||||
|
||||
local ymtthr = coroutine.create(ymtthreadfunc)
|
||||
coroutine.resume(ymtthr)
|
||||
|
||||
rootobj.testymtthr = ymtthr
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-- I considered supporting the hook callback from the debug library, but then
|
||||
-- Eris would also have to persist the registry table the debug library uses,
|
||||
-- and things go quickly out of hand that way, so I decided against that.
|
||||
--[[
|
||||
function hookthrfunc()
|
||||
local hookRan = false
|
||||
local function callback()
|
||||
print("hook!")
|
||||
hookRan = true
|
||||
end
|
||||
debug.sethook(callback, "", 100000)
|
||||
coroutine.yield("yielded")
|
||||
for i = 1, 10000000 do
|
||||
if hookRan then break end
|
||||
end
|
||||
return hookRan
|
||||
end
|
||||
|
||||
hookthr = coroutine.create(hookthrfunc)
|
||||
print(coroutine.resume(hookthr))
|
||||
|
||||
rootobj.testhookthr = hookthr
|
||||
]]
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Deep callstacks (100 levels).
|
||||
|
||||
local function deepfunc(x)
|
||||
x = x or 0
|
||||
if x == 100 then
|
||||
coroutine.yield()
|
||||
return x
|
||||
end
|
||||
local result = deepfunc(x + 1) -- no tailcall
|
||||
return result
|
||||
end
|
||||
|
||||
local deepcall = coroutine.wrap(deepfunc)
|
||||
deepcall()
|
||||
|
||||
rootobj.testdeep = deepcall
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Tail calls.
|
||||
|
||||
local function tailfunc()
|
||||
local function tailer(x)
|
||||
x = x or 0
|
||||
if x == 100 then
|
||||
coroutine.yield()
|
||||
return x
|
||||
end
|
||||
return tailer(x + 1)
|
||||
end
|
||||
local result = tailer()
|
||||
return result
|
||||
end
|
||||
|
||||
function wrap(t)
|
||||
local co = coroutine.create(t)
|
||||
return function(...)
|
||||
local res = {coroutine.resume(co, ...)}
|
||||
if res[1] then return select(2, table.unpack(res)) end
|
||||
error(select(2, table.unpack(res)), 0)
|
||||
end
|
||||
end
|
||||
|
||||
local tailcall = wrap(tailfunc)
|
||||
tailcall()
|
||||
|
||||
rootobj.testtail = tailcall
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- From the Lua test cases, as a more complex piece of code. Since this is
|
||||
-- easier to verify visually it spams the output quite a bit, so it's disabled
|
||||
-- per default.
|
||||
|
||||
--[[
|
||||
local lifethr = coroutine.create(function()
|
||||
local _ENV = { write = coroutine.yield }
|
||||
|
||||
-- life.lua
|
||||
-- original by Dave Bollinger <DBollinger@compuserve.com> posted to lua-l
|
||||
-- modified to use ANSI terminal escape sequences
|
||||
-- modified to use for instead of while
|
||||
-- modified for this test
|
||||
|
||||
ALIVE="¥" DEAD="þ"
|
||||
ALIVE="O" DEAD="-"
|
||||
|
||||
function ARRAY2D(w,h)
|
||||
local t = {w=w,h=h}
|
||||
for y=1,h do
|
||||
t[y] = {}
|
||||
for x=1,w do
|
||||
t[y][x]=0
|
||||
end
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
_CELLS = {}
|
||||
|
||||
-- give birth to a "shape" within the cell array
|
||||
function _CELLS:spawn(shape,left,top)
|
||||
for y=0,shape.h-1 do
|
||||
for x=0,shape.w-1 do
|
||||
self[top+y][left+x] = shape[y*shape.w+x+1]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- run the CA and produce the next generation
|
||||
function _CELLS:evolve(next)
|
||||
local ym1,y,yp1,yi=self.h-1,self.h,1,self.h
|
||||
while yi > 0 do
|
||||
local xm1,x,xp1,xi=self.w-1,self.w,1,self.w
|
||||
while xi > 0 do
|
||||
local sum = self[ym1][xm1] + self[ym1][x] + self[ym1][xp1] +
|
||||
self[y][xm1] + self[y][xp1] +
|
||||
self[yp1][xm1] + self[yp1][x] + self[yp1][xp1]
|
||||
next[y][x] = ((sum==2) and self[y][x]) or ((sum==3) and 1) or 0
|
||||
xm1,x,xp1,xi = x,xp1,xp1+1,xi-1
|
||||
end
|
||||
ym1,y,yp1,yi = y,yp1,yp1+1,yi-1
|
||||
end
|
||||
end
|
||||
|
||||
-- output the array to screen
|
||||
function _CELLS:draw()
|
||||
local out="" -- accumulate to reduce flicker
|
||||
for y=1,self.h do
|
||||
for x=1,self.w do
|
||||
out=out..(((self[y][x]>0) and ALIVE) or DEAD)
|
||||
end
|
||||
out=out.."\n"
|
||||
end
|
||||
write(out)
|
||||
end
|
||||
|
||||
-- constructor
|
||||
function CELLS(w,h)
|
||||
local c = ARRAY2D(w,h)
|
||||
c.spawn = _CELLS.spawn
|
||||
c.evolve = _CELLS.evolve
|
||||
c.draw = _CELLS.draw
|
||||
return c
|
||||
end
|
||||
|
||||
--
|
||||
-- shapes suitable for use with spawn() above
|
||||
--
|
||||
HEART = { 1,0,1,1,0,1,1,1,1; w=3,h=3 }
|
||||
GLIDER = { 0,0,1,1,0,1,0,1,1; w=3,h=3 }
|
||||
EXPLODE = { 0,1,0,1,1,1,1,0,1,0,1,0; w=3,h=4 }
|
||||
FISH = { 0,1,1,1,1,1,0,0,0,1,0,0,0,0,1,1,0,0,1,0; w=5,h=4 }
|
||||
BUTTERFLY = { 1,0,0,0,1,0,1,1,1,0,1,0,0,0,1,1,0,1,0,1,1,0,0,0,1; w=5,h=5 }
|
||||
|
||||
-- the main routine
|
||||
function LIFE(w,h)
|
||||
-- create two arrays
|
||||
local thisgen = CELLS(w,h)
|
||||
local nextgen = CELLS(w,h)
|
||||
|
||||
-- create some life
|
||||
-- about 1000 generations of fun, then a glider steady-state
|
||||
thisgen:spawn(GLIDER,5,4)
|
||||
thisgen:spawn(EXPLODE,25,10)
|
||||
thisgen:spawn(FISH,4,12)
|
||||
|
||||
-- run until break
|
||||
local gen=1
|
||||
while 1 do
|
||||
thisgen:evolve(nextgen)
|
||||
thisgen,nextgen = nextgen,thisgen
|
||||
thisgen:draw()
|
||||
gen=gen+1
|
||||
if gen>2000 then break end
|
||||
end
|
||||
end
|
||||
|
||||
LIFE(40,20)
|
||||
end)
|
||||
print(select(2, coroutine.resume(lifethr)))
|
||||
print(select(2, coroutine.resume(lifethr)))
|
||||
|
||||
rootobj.testlife = lifethr
|
||||
--]]
|
||||
-------------------------------------------------------------------------------
|
||||
-- Do actual persisting with some perms.
|
||||
|
||||
perms = {
|
||||
[_ENV] = "_ENV",
|
||||
[coroutine.yield] = 1,
|
||||
[permtable] = 2,
|
||||
[pcall] = 3,
|
||||
[xpcall] = 4,
|
||||
}
|
||||
buf = eris.persist(perms, rootobj)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Write to file.
|
||||
|
||||
outfile = io.open(..., "wb")
|
||||
outfile:write(buf)
|
||||
outfile:close()
|
||||
Reference in New Issue
Block a user