Since \newsavebox{\name}
assigns the box register number to \name
, there are probably a maximum of 256 boxes available. Is there a way to release a \savebox
after you are through with it?
3 Answers
The normal model is to allocate a box once (before the document starts) and use it multiple times in whatever macro is being defined, so the limit is not usually a problem, however all modern distributions use an etex based format for LaTeX in which case there are 32768 registers available (although you need \usepackage{etex}
to declare that to latex and to use an allocation scheme that knows about the registers.
-
4
-
1
-
1I understand the current thinking in computer science is to deliberately make programs as bloated and slow as possible so as to force people to buy new computers. ;-) Jun 17, 2014 at 12:56
As mentioned by others, LaTeX doesn't provide a way to free up unused registers. It's bit more difficult that your example code suggests since you could add `holes' to the list of allocated registers that you'd need to fill; keeping track of them would be awkward or slow.
If you find yourself needing to use many many registers that you would like to free up, etex.sty
has `local' register allocation under the macros
\loccount
\locdimen
\locskip
\locmuskip
\locbox
\loctoks
\locmarks
An example is shown following; you can see that the same box gets allocated twice under different names.
\documentclass[a4paper]{article}
\usepackage{etex}
\begin{document}
\begingroup
\locbox\textbox
\savebox\textbox{this is box \the\textbox: some text}
\fbox{\usebox\textbox}
\endgroup
\begingroup
\locbox\textboxB
\savebox\textboxB{this is box \the\textboxB: some more text}
\fbox{\usebox\textboxB}
\endgroup
\end{document}
To be effective you'll need grouping, but if you have such a prodigious need for save boxes then you'll probably be grouping at some level anyway.
-
We've steered away from offering local allocators in expl3 because of inconsistencies with edge cases with token lists (specifically, if you globally assign to a local register, it still disappears, but if you globally assign to a local macro, it stays). But if we assumed that all
\g_
tls must be allocated globally and all\l_
must be allocated locally, we would be okay (and this is also recommended in TeX for performance reasons). So with sufficient interest this matter could probably be revived again... Jun 17, 2014 at 3:21 -
If you remember, the other problem was that as TeX's group model requires explicit groups, it looked as if creating local registers could lead to a lot of confusion.– Joseph Wright ♦Jun 17, 2014 at 5:53
-
@JosephWright — Looks like I don't remember
:)
We can discuss elsewhere, perhaps. Jun 17, 2014 at 8:32 -
BTW, is there an etex compatible macro to use instead of \chardef (like maybe \boxdef)? Jun 18, 2014 at 19:59
-
@JohnKormylo Not sure exactly what you mean — if you need larger values than
\chardef
allows you can use\mathchardef
.\boxdef
sounds like it would just be\newbox
wouldn't it? Jun 19, 2014 at 4:27
If you use a temporary box register (like \box0) you must make sure that no macros are called which use the same box, and you must hope that no updated version or package replacement will ever use it either. However if you use \newsavebox, then it is safe from anyone else using \newsavebox (until you release it with \freebox).
\documentclass{article}
\makeatletter
\newcounter{free@boxes}% push stack counter
\newcounter{free@count}% loop counter
\global\let\old@savebox=\newsavebox% save original version
\global\chardef\free@min 255
\global\chardef\free@max 0
\newcommand*{\freebox}[1]% #1 = old savebox name
{\newif\ifgood\goodtrue%
\ifnum#1<\free@min \goodfalse\fi%
\ifnum#1>\free@max \goodfalse\fi%
\ifnum\value{free@boxes}=0\relax%
\else\setcounter{free@count}{\value{free@boxes}}%
\loop% check for duplicates
\ifnum#1=\csname free@box\arabic{free@count}\endcsname
\goodfalse%
\setcounter{free@count}{0}%
\else\addtocounter{free@count}{-1}\fi%
\ifnum\value{free@count}>0 \repeat%
\fi %
\ifgood\stepcounter{free@boxes}%
\global\expandafter\let\csname free@box\arabic{free@boxes}\endcsname#1%
\fi%
\global\chardef#1 0}
\renewcommand*{\newsavebox}[1]{% #1 = new savebox name
\ifnum\value{free@boxes}>0%
\global\edef#1{\csname free@box\arabic{free@boxes}\endcsname}%
\addtocounter{free@boxes}{-1}%
\else\old@savebox{#1}%
\ifnum#1<\free@min \global\let\free@min=#1 \fi%
\ifnum#1>\free@max \global\let\free@max=#1 \fi%
\fi}
\makeatother
\begin{document}
\newsavebox{\test}
\savebox{\test}{This is a test}
\usebox{\test}
\newsavebox{\testb}
\savebox{\testb}{This is the second test}
\usebox{\testb}
\freebox{\test}% release box registers for reuse
\freebox{\testb}
\newsavebox{\reuseb}% push stack returns second box first
\usebox{\reuseb}
\newsavebox{\reuse}
\usebox{\reuse}
The following have been reset to zero:\newline
\verb$\test$ \the\test\newline
\verb$\testb$ \the\testb
\makeatletter
The following should all equal the first box register value:\newline
\verb$\reuse$ \the\reuse\newline
\verb$\free@box1$ \the\csname free@box1\endcsname
The following should all equal the second box register value:\newline
\verb$\reuseb$ \the\reuseb\newline
\verb$\free@box2$ \the\csname free@box2\endcsname
\makeatother
\end{document}
-
1Is this intended as an answer or a comment on the question? but why the complication, why not simply use the same box both times? Jun 16, 2014 at 17:52
-
-
@David Carlisle - The idea is that different macros by different authors could reuse the same box registers. Instead of trying to keep track of which boxes are still being used and which are not, this does it for you. Of course, it would work better to replace \newsavebox than introduce a new command \resusesavebox. Jun 17, 2014 at 1:22
-
@JohnKormylo I can't see a use case for this, either the box is only used in a controlled local scope in which case there is no need to allocate one you can use a scratch box such as 0 or 2 or 4 or \@tempboxa, or it needs to save box data across macros potentially from another package in which case you have nowhere to deallocate as you need to know the box has not been used when you come to use the saved value. Jun 17, 2014 at 9:12
-
@David Carlisle - The goal was not to use the contents of a previously filled savebox. This was just a test program to verify that it was working. Jun 17, 2014 at 12:11
\setbox0=\hbox{...}
then\box0
to output it. Depending on your application, these could serve and be constantly reused.\box
n causes\box
n to become void (i.e., it loses its contents). So I don't know the answer to your question, sad to say. I did just learn that\copy
n uses box n without destroying it. Interesting...