1if not modules then modules = { } end modules ['node-res'] = {
2 version = 1.001,
3 comment = "companion to node-ini.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9local type, next = type, next
10local gmatch, format = string.gmatch, string.format
11
12local nodes, node = nodes, node
13
14local report_nodes = logs.reporter("nodes","housekeeping")
15
16nodes.pool = nodes.pool or { }
17local nodepool = nodes.pool
18
19local whatsitcodes = nodes.whatsitcodes
20local gluecodes = nodes.gluecodes
21local kerncodes = nodes.kerncodes
22local rulecodes = nodes.rulecodes
23local nodecodes = nodes.nodecodes
24local boundarycodes = nodes.boundarycodes
25local usercodes = nodes.usercodes
26
27local nodeproperties = nodes.properties.data
28
29local glyph_code = nodecodes.glyph
30local rule_code = nodecodes.rule
31local kern_code = nodecodes.kern
32local glue_code = nodecodes.glue
33local gluespec_code = nodecodes.gluespec
34local whatsit_code = nodecodes.whatsit
35
36local currentfont = font.current
37local texgetcount = tex.getcount
38
39local allocate = utilities.storage.allocate
40
41local reserved = { }
42local nofreserved = 0
43local userids = allocate()
44local lastid = 0
45
46setmetatable(userids, {
47 __index = function(t,k)
48 if type(k) == "string" then
49 lastid = lastid + 1
50 rawset(userids,lastid,k)
51 rawset(userids,k,lastid)
52 return lastid
53 else
54 rawset(userids,k,k)
55 return k
56 end
57 end,
58 __call = function(t,k)
59 return t[k]
60 end
61} )
62
63
64
65local nuts = nodes.nuts
66local nutpool = { }
67nuts.pool = nutpool
68
69local tonut = nuts.tonut
70local tonode = nuts.tonode
71
72local getbox = nuts.getbox
73local getid = nuts.getid
74local getlist = nuts.getlist
75local getglue = nuts.getglue
76
77local setfield = nuts.setfield
78local setchar = nuts.setchar
79local setlist = nuts.setlist
80local setwhd = nuts.setwhd
81local setglue = nuts.setglue
82local setdisc = nuts.setdisc
83local setfont = nuts.setfont
84local setkern = nuts.setkern
85local setpenalty = nuts.setpenalty
86local setdir = nuts.setdir
87local setdirection = nuts.setdirection
88local setshift = nuts.setshift
89local setwidth = nuts.setwidth
90local setsubtype = nuts.setsubtype
91local setleader = nuts.setleader
92
93local setdata = nuts.setdata
94local setruledata = nuts.setruledata
95local setvalue = nuts.setvalue
96
97local copy_nut = nuts.copy
98local new_nut = nuts.new
99local flush_nut = nuts.flush
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117table.setmetatableindex(nodepool,function(t,k,v)
118
119 local v = function(...)
120 local f = nutpool[k]
121 local v = function(...)
122 return tonode(f(...))
123 end
124 t[k] = v
125 return v(...)
126 end
127 t[k] = v
128 return v
129end)
130
131local function register_nut(n)
132 nofreserved = nofreserved + 1
133 reserved[nofreserved] = n
134 return n
135end
136
137local function register_node(n)
138 nofreserved = nofreserved + 1
139 if type(n) == "number" then
140 reserved[nofreserved] = n
141 else
142 reserved[nofreserved] = tonut(n)
143 end
144 return n
145end
146
147nodepool.userids = userids
148nodepool.register = register_node
149
150nutpool.userids = userids
151nutpool.register = register_node
152
153
154
155local disc = register_nut(new_nut(nodecodes.disc))
156local kern = register_nut(new_nut(kern_code,kerncodes.userkern))
157local fontkern = register_nut(new_nut(kern_code,kerncodes.fontkern))
158local italickern = register_nut(new_nut(kern_code,kerncodes.italiccorrection))
159local penalty = register_nut(new_nut(nodecodes.penalty))
160local glue = register_nut(new_nut(glue_code))
161local gluespec = register_nut(new_nut(gluespec_code))
162local glyph = register_nut(new_nut(glyph_code,0))
163
164local textdir = register_nut(new_nut(nodecodes.dir))
165
166local latelua = register_nut(new_nut(whatsit_code,whatsitcodes.latelua))
167local savepos = register_nut(new_nut(whatsit_code,whatsitcodes.savepos))
168
169local user_node = new_nut(whatsit_code,whatsitcodes.userdefined)
170
171setfield(user_node,"type",usercodes.number)
172
173local left_margin_kern = register_nut(new_nut(nodecodes.marginkern,0))
174local right_margin_kern = register_nut(new_nut(nodecodes.marginkern,1))
175
176local lineskip = register_nut(new_nut(glue_code,gluecodes.lineskip))
177local baselineskip = register_nut(new_nut(glue_code,gluecodes.baselineskip))
178local leftskip = register_nut(new_nut(glue_code,gluecodes.leftskip))
179local rightskip = register_nut(new_nut(glue_code,gluecodes.rightskip))
180local lefthangskip = register_nut(new_nut(glue_code,gluecodes.lefthangskip))
181local righthangskip = register_nut(new_nut(glue_code,gluecodes.righthangskip))
182local indentskip = register_nut(new_nut(glue_code,gluecodes.indentskip))
183local correctionskip = register_nut(new_nut(glue_code,gluecodes.correctionskip))
184
185local temp = register_nut(new_nut(nodecodes.temp,0))
186
187local noad = register_nut(new_nut(nodecodes.noad))
188local delimiter = register_nut(new_nut(nodecodes.delimiter))
189local fence = register_nut(new_nut(nodecodes.fence))
190local submlist = register_nut(new_nut(nodecodes.submlist))
191local accent = register_nut(new_nut(nodecodes.accent))
192local radical = register_nut(new_nut(nodecodes.radical))
193local fraction = register_nut(new_nut(nodecodes.fraction))
194local subbox = register_nut(new_nut(nodecodes.subbox))
195local mathchar = register_nut(new_nut(nodecodes.mathchar))
196local mathtextchar = register_nut(new_nut(nodecodes.mathtextchar))
197local choice = register_nut(new_nut(nodecodes.choice))
198
199local boundary = register_nut(new_nut(nodecodes.boundary,boundarycodes.user))
200local wordboundary = register_nut(new_nut(nodecodes.boundary,boundarycodes.word))
201
202local cleader = register_nut(copy_nut(glue)) setsubtype(cleader,gluecodes.cleaders) setglue(cleader,0,65536,0,2,0)
203
204
205
206local lefttoright_code = nodes.dirvalues.lefttoright
207
208local rule = register_nut(new_nut(rule_code)) setdirection(rule, lefttoright_code)
209local emptyrule = register_nut(new_nut(rule_code,rulecodes.empty)) setdirection(rule, lefttoright_code)
210local userrule = register_nut(new_nut(rule_code,rulecodes.user)) setdirection(rule, lefttoright_code)
211local outlinerule = register_nut(new_nut(rule_code,rulecodes.outline)) setdirection(rule, lefttoright_code)
212local hlist = register_nut(new_nut(nodecodes.hlist)) setdirection(hlist,lefttoright_code)
213local vlist = register_nut(new_nut(nodecodes.vlist)) setdirection(vlist,lefttoright_code)
214
215function nutpool.glyph(fnt,chr)
216 local n = copy_nut(glyph)
217 if fnt then
218 setfont(n,fnt == true and currentfont() or fnt,chr)
219 elseif chr then
220 setchar(n,chr)
221 end
222 return n
223end
224
225function nutpool.penalty(p)
226 local n = copy_nut(penalty)
227 if p and p ~= 0 then
228 setpenalty(n,p)
229 end
230 return n
231end
232
233function nutpool.kern(k)
234 local n = copy_nut(kern)
235 if k and k ~= 0 then
236 setkern(n,k)
237 end
238 return n
239end
240
241function nutpool.boundary(v)
242 local n = copy_nut(boundary)
243 if v and v ~= 0 then
244 setvalue(n,v)
245 end
246 return n
247end
248
249function nutpool.wordboundary(v)
250 local n = copy_nut(wordboundary)
251 if v and v ~= 0 then
252 setvalue(n,v)
253 end
254 return n
255end
256
257function nutpool.fontkern(k)
258 local n = copy_nut(fontkern)
259 if k and k ~= 0 then
260 setkern(n,k)
261 end
262 return n
263end
264
265function nutpool.italickern(k)
266 local n = copy_nut(italickern)
267 if k and k ~= 0 then
268 setkern(n,k)
269 end
270 return n
271end
272
273function nutpool.gluespec(width,stretch,shrink,stretch_order,shrink_order)
274 local n = copy_nut(gluespec)
275 if width or stretch or shrink or stretch_order or shrink_order then
276 setglue(n,width,stretch,shrink,stretch_order,shrink_order)
277 end
278 return n
279end
280
281local function someskip(skip,width,stretch,shrink,stretch_order,shrink_order)
282
283 local n = copy_nut(skip)
284 if width or stretch or shrink or stretch_order or shrink_order then
285 setglue(n,width,stretch,shrink,stretch_order,shrink_order)
286 end
287 return n
288end
289
290function nutpool.stretch(a,b)
291
292 local n = copy_nut(glue)
293 if not b then
294 a, b = 1, a or 1
295 end
296 setglue(n,0,a,0,b,0)
297 return n
298end
299
300function nutpool.shrink(a,b)
301 local n = copy_nut(glue)
302 if not b then
303 a, b = 1, a or 1
304 end
305 setglue(n,0,0,a,0,0,b)
306 return n
307end
308
309function nutpool.glue(width,stretch,shrink,stretch_order,shrink_order)
310 return someskip(glue,width,stretch,shrink,stretch_order,shrink_order)
311end
312
313function nutpool.negatedglue(glue)
314 local n = copy_nut(glue)
315 local width, stretch, shrink = getglue(n)
316 setglue(n,-width,-stretch,-shrink)
317 return n
318end
319
320function nutpool.leftskip(width,stretch,shrink,stretch_order,shrink_order)
321 return someskip(leftskip,width,stretch,shrink,stretch_order,shrink_order)
322end
323
324function nutpool.rightskip(width,stretch,shrink,stretch_order,shrink_order)
325 return someskip(rightskip,width,stretch,shrink,stretch_order,shrink_order)
326end
327
328function nutpool.lefthangskip(width,stretch,shrink,stretch_order,shrink_order)
329 return someskip(lefthangskip,width,stretch,shrink,stretch_order,shrink_order)
330end
331
332function nutpool.righthangskip(width,stretch,shrink,stretch_order,shrink_order)
333 return someskip(righthangskip,width,stretch,shrink,stretch_order,shrink_order)
334end
335
336function nutpool.indentskip(width,stretch,shrink,stretch_order,shrink_order)
337 return someskip(indentskip,width,stretch,shrink,stretch_order,shrink_order)
338end
339
340function nutpool.lineskip(width,stretch,shrink,stretch_order,shrink_order)
341 return someskip(lineskip,width,stretch,shrink,stretch_order,shrink_order)
342end
343
344function nutpool.baselineskip(width,stretch,shrink)
345 return someskip(baselineskip,width,stretch,shrink)
346end
347
348function nutpool.disc(pre,post,replace)
349 local d = copy_nut(disc)
350 if pre or post or replace then
351 setdisc(d,pre,post,replace)
352 end
353 return d
354end
355
356function nutpool.direction(dir,swap)
357 local t = copy_nut(textdir)
358 if not dir then
359
360 elseif swap then
361 setdirection(t,dir,true)
362 else
363 setdirection(t,dir,false)
364 end
365 return t
366end
367
368function nutpool.rule(width,height,depth)
369 local n = copy_nut(rule)
370 if width or height or depth then
371 setwhd(n,width,height,depth)
372 end
373 return n
374end
375
376function nutpool.emptyrule(width,height,depth)
377 local n = copy_nut(emptyrule)
378 if width or height or depth then
379 setwhd(n,width,height,depth)
380 end
381 return n
382end
383
384function nutpool.userrule(width,height,depth)
385 local n = copy_nut(userrule)
386 if width or height or depth then
387 setwhd(n,width,height,depth)
388 end
389 return n
390end
391
392function nutpool.outlinerule(width,height,depth,line)
393 local n = copy_nut(outlinerule)
394 if width or height or depth then
395 setwhd(n,width,height,depth)
396 end
397 if line then
398 setruledata(n,line)
399 end
400 return n
401end
402
403function nutpool.leader(width,list)
404 local n = copy_nut(cleader)
405 if width then
406 setwidth(n,width)
407 end
408 if list then
409 setleader(n,list)
410 end
411 return n
412end
413
414function nutpool.savepos()
415 return copy_nut(savepos)
416end
417
418function nutpool.latelua(code)
419 local n = copy_nut(latelua)
420 if type(code) == "table" then
421 local action = code.action
422 local specification = code.specification or code
423 code = function() action(specification) end
424 end
425 setdata(n,code)
426 return n
427end
428
429function nutpool.leftmarginkern(glyph,width)
430 local n = copy_nut(left_margin_kern)
431 if not glyph then
432 report_nodes("invalid pointer to left margin glyph node")
433 elseif getid(glyph) ~= glyph_code then
434 report_nodes("invalid node type %a for %s margin glyph node",nodecodes[glyph],"left")
435 else
436 setfield(n,"glyph",glyph)
437 end
438 if width and width ~= 0 then
439 setwidth(n,width)
440 end
441 return n
442end
443
444function nutpool.rightmarginkern(glyph,width)
445 local n = copy_nut(right_margin_kern)
446 if not glyph then
447 report_nodes("invalid pointer to right margin glyph node")
448 elseif getid(glyph) ~= glyph_code then
449 report_nodes("invalid node type %a for %s margin glyph node",nodecodes[p],"right")
450 else
451 setfield(n,"glyph",glyph)
452 end
453 if width and width ~= 0 then
454 setwidth(n,width)
455 end
456 return n
457end
458
459function nutpool.temp()
460 return copy_nut(temp)
461end
462
463function nutpool.noad() return copy_nut(noad) end
464function nutpool.delimiter() return copy_nut(delimiter) end nutpool.delim = nutpool.delimiter
465function nutpool.fence() return copy_nut(fence) end
466function nutpool.submlist() return copy_nut(submlist) end
467function nutpool.noad() return copy_nut(noad) end
468function nutpool.fence() return copy_nut(fence) end
469function nutpool.accent() return copy_nut(accent) end
470function nutpool.radical() return copy_nut(radical) end
471function nutpool.fraction() return copy_nut(fraction) end
472function nutpool.subbox() return copy_nut(subbox) end
473function nutpool.mathchar() return copy_nut(mathchar) end
474function nutpool.mathtextchar() return copy_nut(mathtextchar) end
475function nutpool.choice() return copy_nut(choice) end
476
477local function new_hlist(list,width,height,depth,shift)
478 local n = copy_nut(hlist)
479 if list then
480 setlist(n,list)
481 end
482 if width or height or depth then
483 setwhd(n,width,height,depth)
484 end
485 if shift and shift ~= 0 then
486 setshift(n,shift)
487 end
488 return n
489end
490
491local function new_vlist(list,width,height,depth,shift)
492 local n = copy_nut(vlist)
493 if list then
494 setlist(n,list)
495 end
496 if width or height or depth then
497 setwhd(n,width,height,depth)
498 end
499 if shift and shift ~= 0 then
500 setshift(n,shift)
501 end
502 return n
503end
504
505nutpool.hlist = new_hlist
506nutpool.vlist = new_vlist
507
508function nodepool.hlist(list,width,height,depth,shift)
509 return tonode(new_hlist(list and tonut(list),width,height,depth,shift))
510end
511
512function nodepool.vlist(list,width,height,depth,shift)
513 return tonode(new_vlist(list and tonut(list),width,height,depth,shift))
514end
515
516function nutpool.usernode(id,data)
517 local n = copy_nut(user_node)
518 nodeproperties[n] = {
519 id = id,
520 data = data,
521 }
522 return n
523end
524
525
526
527local function cleanup(nofboxes)
528 local tracers = nodes.tracers
529 if tracers and tracers.steppers then
530 tracers.steppers.reset()
531 end
532 local nl = 0
533 local nr = nofreserved
534 for i=1,nofreserved do
535 local ri = reserved[i]
536 flush_nut(reserved[i])
537 end
538 if nofboxes then
539 for i=0,nofboxes do
540 local l = getbox(i)
541 if l then
542 flush_nut(l)
543 nl = nl + 1
544 end
545 end
546 end
547 reserved = { }
548 nofreserved = 0
549 return nr, nl, nofboxes
550end
551
552local function usage()
553 local t = { }
554 for n, tag in gmatch(status.node_mem_usage,"(%d+) ([a-z_]+)") do
555 t[tag] = tonumber(n) or 0
556 end
557 return t
558end
559
560local stock = { }
561
562nutpool .cleanup = cleanup
563nodepool.cleanup = cleanup
564
565nutpool .usage = usage
566nodepool.usage = usage
567
568nutpool .stock = stock
569nodepool.stock = stock
570
571
572
573statistics.register("cleaned up reserved nodes", function()
574 return format("%s nodes, %s lists of %s", cleanup(texgetcount("c_syst_last_allocated_box")))
575end)
576
577statistics.register("node memory usage", function()
578 local used = usage()
579 if next(used) then
580 local t, n = { }, 0
581 for k, v in table.sortedhash(used) do
582 n = n + 1 ; t[n] = format("%s %s",v,k)
583 end
584 return table.concat(t,", ")
585 end
586end)
587
588lua.registerinitexfinalizer(cleanup, "cleanup reserved nodes")
589
590
591
592do
593
594 local glyph = tonode(glyph)
595 local traverseid = nodes.traverseid
596
597 local traversers = table.setmetatableindex(function(t,k)
598 local v = traverseid(type(k) == "number" and k or nodecodes[k],glyph)
599 t[k] = v
600 return v
601 end)
602
603 traversers.node = nodes.traverse (glyph)
604 traversers.char = nodes.traversechar (glyph)
605 if nodes.traverseglyph then traversers.glyph = nodes.traverseglyph(glyph) end
606 if nodes.traverselist then traversers.list = nodes.traverselist (glyph) end
607
608 nodes.traversers = traversers
609
610end
611
612do
613
614 local glyph = glyph
615 local traverseid = nuts.traverseid
616
617 local traversers = table.setmetatableindex(function(t,k)
618 local v = traverseid(type(k) == "number" and k or nodecodes[k],glyph)
619 t[k] = v
620 return v
621 end)
622
623 traversers.node = nuts.traverse (glyph)
624 traversers.char = nuts.traversechar (glyph)
625 if nuts.traverseglyph then traversers.glyph = nuts.traverseglyph (glyph) end
626 if nuts.traverselist then traversers.list = nuts.traverselist (glyph) end
627 if nuts.traversecontent then traversers.content = nuts.traversecontent(glyph) end
628
629 nuts.traversers = traversers
630
631end
632 |