diff options
author | Context Git Mirror Bot <phg42.2a@gmail.com> | 2014-05-03 13:55:34 +0200 |
---|---|---|
committer | Context Git Mirror Bot <phg42.2a@gmail.com> | 2014-05-03 13:55:34 +0200 |
commit | 624cbb5da392e9403984dd1cf368c0d408b1c2a8 (patch) | |
tree | 489c049ac849bb5bbce7d32e4df477872c58373d /tex/context/base/node-res.lua | |
parent | 088de88944c1f2254250bb448c7371a87ff7ee39 (diff) | |
download | context-624cbb5da392e9403984dd1cf368c0d408b1c2a8.tar.gz |
2014-01-03 00:42:00
Diffstat (limited to 'tex/context/base/node-res.lua')
-rw-r--r-- | tex/context/base/node-res.lua | 530 |
1 files changed, 241 insertions, 289 deletions
diff --git a/tex/context/base/node-res.lua b/tex/context/base/node-res.lua index 968283745..ca9d67f91 100644 --- a/tex/context/base/node-res.lua +++ b/tex/context/base/node-res.lua @@ -18,8 +18,13 @@ local report_nodes = logs.reporter("nodes","housekeeping") local nodes, node = nodes, node +local copy_node = node.copy +local free_node = node.free +local free_list = node.flush_list +local new_node = node.new + nodes.pool = nodes.pool or { } -local nodepool = nodes.pool +local pool = nodes.pool local whatsitcodes = nodes.whatsitcodes local skipcodes = nodes.skipcodes @@ -30,453 +35,400 @@ local glyph_code = nodecodes.glyph local allocate = utilities.storage.allocate +local texgetbox = tex.getbox local texgetcount = tex.getcount local reserved, nofreserved = { }, 0 --- user nodes +local function register_node(n) + nofreserved = nofreserved + 1 + reserved[nofreserved] = n + return n +end -local userids = allocate() -local lastid = 0 +pool.register = register_node -setmetatable(userids, { - __index = function(t,k) - if type(k) == "string" then - lastid = lastid + 1 - rawset(userids,lastid,k) - rawset(userids,k,lastid) - return lastid - else - rawset(userids,k,k) - return k - end - end, - __call = function(t,k) - return t[k] +function pool.cleanup(nofboxes) -- todo + if nodes.tracers.steppers then -- to be resolved + nodes.tracers.steppers.reset() -- todo: make a registration subsystem end -} ) - --- nuts overload - -local nuts = nodes.nuts -local nutpool = { } -nuts.pool = nutpool - -local tonut = nuts.tonut -local tonode = nuts.tonode - -local getbox = nuts.getbox -local getfield = nuts.getfield -local setfield = nuts.setfield -local getid = nuts.getid - -local copy_nut = nuts.copy -local new_nut = nuts.new -local free_nut = nuts.free - --- at some point we could have a dual set (the overhead of tonut is not much larger than --- metatable associations at the lua/c end esp if we also take assignments into account - --- table.setmetatableindex(nodepool,function(t,k,v) --- -- report_nodes("defining nodepool[%s] instance",k) --- local f = nutpool[k] --- local v = function(...) --- return tonode(f(...)) --- end --- t[k] = v --- return v --- end) --- --- -- we delay one step because that permits us a forward reference --- -- e.g. in pdfsetmatrix - -table.setmetatableindex(nodepool,function(t,k,v) - -- report_nodes("defining nodepool[%s] instance",k) - local v = function(...) - local f = nutpool[k] - local v = function(...) - return tonode(f(...)) + local nl, nr = 0, nofreserved + for i=1,nofreserved do + local ri = reserved[i] + -- if not (ri.id == glue_spec and not ri.is_writable) then + free_node(reserved[i]) + -- end + end + if nofboxes then + for i=0,nofboxes do + local l = texgetbox(i) + if l then + free_node(l) -- also list ? + nl = nl + 1 + end end - t[k] = v - return v(...) end - t[k] = v - return v -end) - -local function register_nut(n) - nofreserved = nofreserved + 1 - reserved[nofreserved] = n - return n + reserved = { } + nofreserved = 0 + return nr, nl, nofboxes -- can be nil end -local function register_node(n) - nofreserved = nofreserved + 1 - if type(n) == "number" then -- isnut(n) - reserved[nofreserved] = n - else - reserved[nofreserved] = tonut(n) +function pool.usage() + local t = { } + for n, tag in gmatch(status.node_mem_usage,"(%d+) ([a-z_]+)") do + t[tag] = n end - return n + return t end -nodepool.userids = userids -nodepool.register = register_node - -nutpool.userids = userids -nutpool.register = register_node -- could be register_nut - --- so far - -local disc = register_nut(new_nut("disc")) -local kern = register_nut(new_nut("kern",kerncodes.userkern)) -local fontkern = register_nut(new_nut("kern",kerncodes.fontkern)) -local penalty = register_nut(new_nut("penalty")) -local glue = register_nut(new_nut("glue")) -- glue.spec = nil -local glue_spec = register_nut(new_nut("glue_spec")) -local glyph = register_nut(new_nut("glyph",0)) -local textdir = register_nut(new_nut("whatsit",whatsitcodes.dir)) -local latelua = register_nut(new_nut("whatsit",whatsitcodes.latelua)) -local special = register_nut(new_nut("whatsit",whatsitcodes.special)) -local user_n = register_nut(new_nut("whatsit",whatsitcodes.userdefined)) setfield(user_n,"type",100) -- 44 -local user_l = register_nut(new_nut("whatsit",whatsitcodes.userdefined)) setfield(user_l,"type",110) -- 44 -local user_s = register_nut(new_nut("whatsit",whatsitcodes.userdefined)) setfield(user_s,"type",115) -- 44 -local user_t = register_nut(new_nut("whatsit",whatsitcodes.userdefined)) setfield(user_t,"type",116) -- 44 -local left_margin_kern = register_nut(new_nut("margin_kern",0)) -local right_margin_kern = register_nut(new_nut("margin_kern",1)) -local lineskip = register_nut(new_nut("glue",skipcodes.lineskip)) -local baselineskip = register_nut(new_nut("glue",skipcodes.baselineskip)) -local leftskip = register_nut(new_nut("glue",skipcodes.leftskip)) -local rightskip = register_nut(new_nut("glue",skipcodes.rightskip)) -local temp = register_nut(new_nut("temp",0)) -local noad = register_nut(new_nut("noad")) +local disc = register_node(new_node("disc")) +local kern = register_node(new_node("kern",kerncodes.userkern)) +local fontkern = register_node(new_node("kern",kerncodes.fontkern)) +local penalty = register_node(new_node("penalty")) +local glue = register_node(new_node("glue")) -- glue.spec = nil +local glue_spec = register_node(new_node("glue_spec")) +local glyph = register_node(new_node("glyph",0)) +local textdir = register_node(new_node("whatsit",whatsitcodes.dir)) +local latelua = register_node(new_node("whatsit",whatsitcodes.latelua)) +local special = register_node(new_node("whatsit",whatsitcodes.special)) +local user_n = register_node(new_node("whatsit",whatsitcodes.userdefined)) user_n.type = 100 -- 44 +local user_l = register_node(new_node("whatsit",whatsitcodes.userdefined)) user_l.type = 110 -- 44 +local user_s = register_node(new_node("whatsit",whatsitcodes.userdefined)) user_s.type = 115 -- 44 +local user_t = register_node(new_node("whatsit",whatsitcodes.userdefined)) user_t.type = 116 -- 44 +local left_margin_kern = register_node(new_node("margin_kern",0)) +local right_margin_kern = register_node(new_node("margin_kern",1)) +local lineskip = register_node(new_node("glue",skipcodes.lineskip)) +local baselineskip = register_node(new_node("glue",skipcodes.baselineskip)) +local leftskip = register_node(new_node("glue",skipcodes.leftskip)) +local rightskip = register_node(new_node("glue",skipcodes.rightskip)) +local temp = register_node(new_node("temp",0)) +local noad = register_node(new_node("noad")) -- the dir field needs to be set otherwise crash: -local rule = register_nut(new_nut("rule")) setfield(rule, "dir","TLT") -local hlist = register_nut(new_nut("hlist")) setfield(hlist,"dir","TLT") -local vlist = register_nut(new_nut("vlist")) setfield(vlist,"dir","TLT") - -function nutpool.zeroglue(n) - local s = getfield(n,"spec") - return - getfield(s,"width") == 0 and - getfield(s,"stretch") == 0 and - getfield(s,"shrink") == 0 and - getfield(s,"stretch_order") == 0 and - getfield(s,"shrink_order") == 0 -end - -function nutpool.glyph(fnt,chr) - local n = copy_nut(glyph) - if fnt then setfield(n,"font",fnt) end - if chr then setfield(n,"char",chr) end +local rule = register_node(new_node("rule")) rule .dir = "TLT" +local hlist = register_node(new_node("hlist")) hlist.dir = "TLT" +local vlist = register_node(new_node("vlist")) vlist.dir = "TLT" + +function pool.zeroglue(n) + local s = n.spec + return not writable or ( + s.width == 0 + and s.stretch == 0 + and s.shrink == 0 + and s.stretch_order == 0 + and s.shrink_order == 0 + ) +end + +function pool.glyph(fnt,chr) + local n = copy_node(glyph) + if fnt then n.font = fnt end + if chr then n.char = chr end return n end -function nutpool.penalty(p) - local n = copy_nut(penalty) - setfield(n,"penalty",p) +function pool.penalty(p) + local n = copy_node(penalty) + n.penalty = p return n end -function nutpool.kern(k) - local n = copy_nut(kern) - setfield(n,"kern",k) +function pool.kern(k) + local n = copy_node(kern) + n.kern = k return n end -function nutpool.fontkern(k) - local n = copy_nut(fontkern) - setfield(n,"kern",k) +function pool.fontkern(k) + local n = copy_node(fontkern) + n.kern = k return n end -function nutpool.gluespec(width,stretch,shrink,stretch_order,shrink_order) - local s = copy_nut(glue_spec) - if width then setfield(s,"width",width) end - if stretch then setfield(s,"stretch",stretch) end - if shrink then setfield(s,"shrink",shrink) end - if stretch_order then setfield(s,"stretch_order",stretch_order) end - if shrink_order then setfield(s,"shrink_order",shrink_order) end +function pool.gluespec(width,stretch,shrink,stretch_order,shrink_order) + local s = copy_node(glue_spec) + if width then s.width = width end + if stretch then s.stretch = stretch end + if shrink then s.shrink = shrink end + if stretch_order then s.stretch_order = stretch_order end + if shrink_order then s.shrink_order = shrink_order end return s end local function someskip(skip,width,stretch,shrink,stretch_order,shrink_order) - local n = copy_nut(skip) + local n = copy_node(skip) if not width then -- no spec elseif width == false or tonumber(width) then - local s = copy_nut(glue_spec) - if width then setfield(s,"width",width) end - if stretch then setfield(s,"stretch",stretch) end - if shrink then setfield(s,"shrink",shrink) end - if stretch_order then setfield(s,"stretch_order",stretch_order) end - if shrink_order then setfield(s,"shrink_order",shrink_order) end - setfield(n,"spec",s) + local s = copy_node(glue_spec) + if width then s.width = width end + if stretch then s.stretch = stretch end + if shrink then s.shrink = shrink end + if stretch_order then s.stretch_order = stretch_order end + if shrink_order then s.shrink_order = shrink_order end + n.spec = s else -- shared - setfield(n,"spec",copy_nut(width)) + n.spec = copy_node(width) end return n end -function nutpool.stretch(a,b) - local n = copy_nut(glue) - local s = copy_nut(glue_spec) +function pool.stretch(a,b) + local n = copy_node(glue) + local s = copy_node(glue_spec) if b then - setfield(s,"stretch",a) - setfield(s,"stretch_order",b) + s.stretch = a + s.stretch_order = b else - setfield(s,"stretch",1) - setfield(s,"stretch_order",a or 1) + s.stretch = 1 + s.stretch_order = a or 1 end - setfield(n,"spec",s) + n.spec = s return n end -function nutpool.shrink(a,b) - local n = copy_nut(glue) - local s = copy_nut(glue_spec) +function pool.shrink(a,b) + local n = copy_node(glue) + local s = copy_node(glue_spec) if b then - setfield(s,"shrink",a) - setfield(s,"shrink_order",b) + s.shrink = a + s.shrink_order = b else - setfield(s,"shrink",1) - setfield(s,"shrink_order",a or 1) + s.shrink = 1 + s.shrink_order = a or 1 end - setfield(n,"spec",s) + n.spec = s return n end -function nutpool.glue(width,stretch,shrink,stretch_order,shrink_order) + +function pool.glue(width,stretch,shrink,stretch_order,shrink_order) return someskip(glue,width,stretch,shrink,stretch_order,shrink_order) end -function nutpool.leftskip(width,stretch,shrink,stretch_order,shrink_order) +function pool.leftskip(width,stretch,shrink,stretch_order,shrink_order) return someskip(leftskip,width,stretch,shrink,stretch_order,shrink_order) end -function nutpool.rightskip(width,stretch,shrink,stretch_order,shrink_order) +function pool.rightskip(width,stretch,shrink,stretch_order,shrink_order) return someskip(rightskip,width,stretch,shrink,stretch_order,shrink_order) end -function nutpool.lineskip(width,stretch,shrink,stretch_order,shrink_order) +function pool.lineskip(width,stretch,shrink,stretch_order,shrink_order) return someskip(lineskip,width,stretch,shrink,stretch_order,shrink_order) end -function nutpool.baselineskip(width,stretch,shrink) +function pool.baselineskip(width,stretch,shrink) return someskip(baselineskip,width,stretch,shrink) end -function nutpool.disc() - return copy_nut(disc) +function pool.disc() + return copy_node(disc) end -function nutpool.textdir(dir) - local t = copy_nut(textdir) - setfield(t,"dir",dir) +function pool.textdir(dir) + local t = copy_node(textdir) + t.dir = dir return t end -function nutpool.rule(width,height,depth,dir) -- w/h/d == nil will let them adapt - local n = copy_nut(rule) - if width then setfield(n,"width",width) end - if height then setfield(n,"height",height) end - if depth then setfield(n,"depth",depth) end - if dir then setfield(n,"dir",dir) end +function pool.rule(width,height,depth,dir) -- w/h/d == nil will let them adapt + local n = copy_node(rule) + if width then n.width = width end + if height then n.height = height end + if depth then n.depth = depth end + if dir then n.dir = dir end return n end --- if node.has_field(latelua,'string') then - function nutpool.latelua(code) - local n = copy_nut(latelua) - setfield(n,"string",code) +if node.has_field(latelua,'string') then + function pool.latelua(code) + local n = copy_node(latelua) + n.string = code + return n + end +else + function pool.latelua(code) + local n = copy_node(latelua) + n.data = code return n end --- else --- function nutpool.latelua(code) --- local n = copy_nut(latelua) --- setfield(n,"data",code) --- return n --- end --- end - -function nutpool.leftmarginkern(glyph,width) - local n = copy_nut(left_margin_kern) +end + +function pool.leftmarginkern(glyph,width) + local n = copy_node(left_margin_kern) if not glyph then report_nodes("invalid pointer to left margin glyph node") - elseif getid(glyph) ~= glyph_code then + elseif glyph.id ~= glyph_code then report_nodes("invalid node type %a for %s margin glyph node",nodecodes[glyph],"left") else - setfield(n,"glyph",glyph) + n.glyph = glyph end if width then - setfield(n,"width",width) + n.width = width end return n end -function nutpool.rightmarginkern(glyph,width) - local n = copy_nut(right_margin_kern) +function pool.rightmarginkern(glyph,width) + local n = copy_node(right_margin_kern) if not glyph then report_nodes("invalid pointer to right margin glyph node") - elseif getid(glyph) ~= glyph_code then + elseif glyph.id ~= glyph_code then report_nodes("invalid node type %a for %s margin glyph node",nodecodes[p],"right") else - setfield(n,"glyph",glyph) + n.glyph = glyph end if width then - setfield(n,"width",width) + n.width = width end return n end -function nutpool.temp() - return copy_nut(temp) +function pool.temp() + return copy_node(temp) end -function nutpool.noad() - return copy_nut(noad) +function pool.noad() + return copy_node(noad) end -function nutpool.hlist(list,width,height,depth) - local n = copy_nut(hlist) +function pool.hlist(list,width,height,depth) + local n = copy_node(hlist) if list then - setfield(n,"list",list) + n.list = list end if width then - setfield(n,"width",width) + n.width = width end if height then - setfield(n,"height",height) + n.height = height end if depth then - setfield(n,"depth",depth) + n.depth = depth end return n end -function nutpool.vlist(list,width,height,depth) - local n = copy_nut(vlist) +function pool.vlist(list,width,height,depth) + local n = copy_node(vlist) if list then - setfield(n,"list",list) + n.list = list end if width then - setfield(n,"width",width) + n.width = width end if height then - setfield(n,"height",height) + n.height = height end if depth then - setfield(n,"depth",depth) + n.depth = depth end return n end +--[[ +<p>At some point we ran into a problem that the glue specification +of the zeropoint dimension was overwritten when adapting a glue spec +node. This is a side effect of glue specs being shared. After a +couple of hours tracing and debugging Taco and I came to the +conclusion that it made no sense to complicate the spec allocator +and settled on a writable flag. This all is a side effect of the +fact that some glues use reserved memory slots (with the zeropoint +glue being a noticeable one). So, next we wrap this into a function +and hide it for the user. And yes, LuaTeX now gives a warning as +well.</p> +]]-- + +function nodes.writable_spec(n) -- not pool + local spec = n.spec + if not spec then + spec = copy_node(glue_spec) + n.spec = spec + elseif not spec.writable then + spec = copy_node(spec) + n.spec = spec + end + return spec +end + -- local num = userids["my id"] -- local str = userids[num] -function nutpool.usernumber(id,num) - local n = copy_nut(user_n) +local userids = allocate() pool.userids = userids +local lastid = 0 + +setmetatable(userids, { + __index = function(t,k) + if type(k) == "string" then + lastid = lastid + 1 + rawset(userids,lastid,k) + rawset(userids,k,lastid) + return lastid + else + rawset(userids,k,k) + return k + end + end, + __call = function(t,k) + return t[k] + end +} ) + +function pool.usernumber(id,num) + local n = copy_node(user_n) if num then - setfield(n,"user_id",id) - setfield(n,"value",num) + n.user_id, n.value = id, num elseif id then - setfield(n,"value",id) + n.value = id end return n end -function nutpool.userlist(id,list) - local n = copy_nut(user_l) +function pool.userlist(id,list) + local n = copy_node(user_l) if list then - setfield(n,"user_id",id) - setfield(n,"value",list) + n.user_id, n.value = id, list else - setfield(n,"value",id) + n.value = id end return n end -function nutpool.userstring(id,str) - local n = copy_nut(user_s) +function pool.userstring(id,str) + local n = copy_node(user_s) if str then - setfield(n,"user_id",id) - setfield(n,"value",str) + n.user_id, n.value = id, str else - setfield(n,"value",id) + n.value = id end return n end -function nutpool.usertokens(id,tokens) - local n = copy_nut(user_t) +function pool.usertokens(id,tokens) + local n = copy_node(user_t) if tokens then - setfield(n,"user_id",id) - setfield(n,"value",tokens) + n.user_id, n.value = id, tokens else - setfield(n,"value",id) + n.value = id end return n end -function nutpool.special(str) - local n = copy_nut(special) - setfield(n,"data",str) +function pool.special(str) + local n = copy_node(special) + n.data = str return n end --- housekeeping - -local function cleanup(nofboxes) -- todo - if nodes.tracers.steppers then -- to be resolved - nodes.tracers.steppers.reset() -- todo: make a registration subsystem - end - local nl, nr = 0, nofreserved - for i=1,nofreserved do - local ri = reserved[i] - -- if not (getid(ri) == glue_spec and not getfield(ri,"is_writable")) then - free_nut(reserved[i]) - -- end - end - if nofboxes then - for i=0,nofboxes do - local l = getbox(i) - if l then - free_nut(l) -- also list ? - nl = nl + 1 - end - end - end - reserved = { } - nofreserved = 0 - return nr, nl, nofboxes -- can be nil -end - - -local function usage() - local t = { } - for n, tag in gmatch(status.node_mem_usage,"(%d+) ([a-z_]+)") do - t[tag] = n - end - return t -end - -nutpool .cleanup = cleanup -nodepool.cleanup = cleanup - -nutpool .usage = usage -nodepool.usage = usage - --- end - statistics.register("cleaned up reserved nodes", function() - return format("%s nodes, %s lists of %s", cleanup(texgetcount("c_syst_last_allocated_box"))) + return format("%s nodes, %s lists of %s", pool.cleanup(texgetcount("c_syst_last_allocated_box"))) end) -- \topofboxstack statistics.register("node memory usage", function() -- comes after cleanup ! return status.node_mem_usage end) -lua.registerfinalizer(cleanup, "cleanup reserved nodes") +lua.registerfinalizer(pool.cleanup, "cleanup reserved nodes") |