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