%% This is part of the OpTeX project, see http://petr.olsak.net/optex

\_codedecl \newdimen {Allocators for registers <2023-02-03>} % preloaded in format

   \_doc -----------------------------
   The limits are set first.
   \_cod -----------------------------

\_chardef\_maicount = 65535    % Max Allocation Index for counts registers in LuaTeX
\_let\_maidimen  = \_maicount
\_let\_maiskip   = \_maicount
\_let\_maimuskip = \_maicount
\_let\_maibox    = \_maicount
\_let\_maitoks   = \_maicount
\_chardef\_mairead  = 15
\_chardef\_maiwrite = 15
\_chardef\_maifam   = 255
\_chardef\_mailanguage = 16380 % In fact 16383, but we reserve next numbers for dummy patterns

   \_doc -----------------------------
   Each allocation macro needs its own counter.
   \_cod -----------------------------

\_countdef\_countalloc=10     \_countalloc=255
\_countdef\_dimenalloc=11     \_dimenalloc=255
\_countdef\_skipalloc=12      \_skipalloc=255
\_countdef\_muskipalloc=13    \_muskipalloc=255
\_countdef\_boxalloc=14       \_boxalloc=255
\_countdef\_toksalloc=15      \_toksalloc=255
\_countdef\_readalloc=16      \_readalloc=-1
\_countdef\_writealloc=17     \_writealloc=0 % should be -1 but there is bug in new luatex
\_countdef\_famalloc=18       \_famalloc=42  % \newfam are 43, 44, 45, ...
\_countdef\_languagealloc=19  \_languagealloc=0

   \_doc -----------------------------
   The common allocation macro
   \`\_allocator` `\<sequence> {<type>} \<primitive declarator>`
   is defined. This idea was used in classical plain \TeX/ by
   Donald Knuth too but the macro from plain \TeX/ seems to be
   more complicated:).
   \_cod -----------------------------

\_def\_allocator #1#2#3{%
   \_incr{\_cs{_#2alloc}}%
   \_ifnum\_cs{_#2alloc}>\_cs{_mai#2}%
      \_errmessage{No room for a new \_ea\_string\_csname #2\_endcsname}%
   \_else
      \_global#3#1=\_cs{_#2alloc}%
      \_wloga{\_string#1=\_ea\_string\_csname #2\_endcsname\_the\_cs{_#2alloc}}%
   \_fi
}
\_let\_wloga=\_wlog % you can suppress the logging by \_let\_wloga=\_ignoreit

   \_doc -----------------------------
   The allocation macros
   \`\newcount`, \`\newdimen`, \`\newskip`, \`\newmuskip`, \`\newbox`,
   \`\newtoks`, \`\newread`, \`\newwrite`, \`\newfam`, and \`\newlanguage`
   are defined here.
   \_cod -----------------------------

\_def\_newcount #1{\_allocator #1{count}\_countdef}
\_def\_newdimen #1{\_allocator #1{dimen}\_dimendef}
\_def\_newskip #1{\_allocator #1{skip}\_skipdef}
\_def\_newmuskip #1{\_allocator #1{muskip}\_muskipdef}
\_def\_newbox #1{\_allocator #1{box}\_chardef}
\_def\_newtoks #1{\_allocator #1{toks}\_toksdef}
\_def\_newread #1{\_allocator #1{read}\_chardef}
\_def\_newwrite #1{\_allocator #1{write}\_chardef}
\_def\_newfam #1{\_allocator #1{fam}\_chardef}
\_def\_newlanguage #1{\_allocator #1{language}\_chardef}

\_public \newcount \newdimen \newskip \newmuskip \newbox \newtoks
         \newread \newwrite \newfam \newlanguage ;

   \_doc -----------------------------
   The \`\newinsert` macro is defined differently than others.
   \_cod -----------------------------

\_newcount\_insertalloc   \_insertalloc=255
\_chardef\_insertmin = 201

\_def\_newinsert #1{%
   \_decr\_insertalloc
   \_ifnum\_insertalloc <\_insertmin
      \_errmessage {No room for a new \_string\insert}%
   \_else
      \_global\_chardef#1=\_insertalloc
      \_wlog {\_string#1=\_string\_insert\_the\_insertalloc}%
   \_fi
}
\_public \newinsert ;

   \_doc -----------------------------
   Other allocation macros \`\newmarks`. \`\newattribute` and \`\newcatcodetable`
   have their counter allocated by the `\newcount` macro.
   \`\_noattr` is constant `-"7FFFFFFF`, i.e. unused attribute
   \_cod -----------------------------

\_newcount \_marksalloc \_marksalloc=0 % start at 1, 0 is \mark
\_chardef\_maimarks=\_maicount
\_def\_newmarks #1{\_allocator #1{marks}\_chardef}

\_newcount \_attributealloc  \_attributealloc=0
\_chardef\_maiattribute=\_numexpr\_maicount -1\_relax
\_attributedef\_noattr \_maicount
\_def\_newattribute #1{\_allocator #1{attribute}\_attributedef}

\_newcount \_catcodetablealloc  \_catcodetablealloc=10
\_chardef\_maicatcodetable=32767
\_def\_newcatcodetable #1{\_allocator #1{catcodetable}\_chardef}

\_public \newmarks \newattribute \newcatcodetable ;

   \_doc -----------------------------
   We declare public and private versions of `\tmpnum` and `\tmpdim`
   registers separately. They are independent registers.
   \_cod -----------------------------

\_newcount \tmpnum  \_newcount \_tmpnum
\_newdimen \tmpdim  \_newdimen \_tmpdim

   \_doc -----------------------------
   A few registers are initialized like in plain\TeX/. We absolutely
   don't support the `@`category dance, so `\z@skip`
   `\z@`, `\p@` etc. are defined but not recommended in \OpTeX/.

   The \`\_zo` and \`\_zoskip` (equivalents to `\z@` and `\z@skip`)
   are declared here and used in some internal macros of \OpTeX/
   for improving speed.
   \_cod -----------------------------

\_newdimen\_maxdimen \_maxdimen=16383.99999pt % the largest legal <dimen>
\_newdimen\_zo \_zo=0pt
\_newskip\_hideskip \_hideskip=-1000pt plus 1fill % negative but can grow
\_newskip\_centering \_centering=0pt plus 1000pt minus 1000pt
\_newskip\_zoskip \_zoskip=0pt plus0pt minus0pt
\_newbox\_voidbox % permanently void box register

\_public \maxdimen \hideskip \centering \voidbox ;

\_endcode %---------------------------------------------------

Like plain\TeX, the allocators `\newcount`, `\newwrite`, etc. are defined.
The registers are allocated from 256 to the `\_mai<type>` which is 65535 in
\LuaTeX/.

Unlike in Plain\TeX/, the mentioned allocators are not `\outer`.

User can use `\dimen0` to `\dimen200` and similarly for `\skip`,
`\muskip`, `\box`, and `\toks` directly. User can use
`\count20` to `\count200` directly too. This is the same
philosophy as in old plain\TeX/, but the range of directly used registers
is wider.

Inserts are allocated from 254 to 201 using `\newinsert`.

You can define your own allocation concept (for example for allocation of
arrays) from the top of the registers array. The example shows a definition of
the array-like declarator of counters.

\nobreak
\begtt
\newcount \_maicount    % redefine maximal allocation index as variable
\_maicount = \maicount  % first value is top of the array

\def\newcountarray #1[#2]{% \newcountarray \foo[100]
    \global\advance\_maicount by -#2\relax
    \ifnum \_countalloc > \_maicount
        \errmessage{No room for a new array of \string\count}%
    \else
        \global\chardef#1=\_maicount
    \fi
}
\def\usecount #1[#2]{%  \usecount \foo[2]
    \count\numexpr#1+#2\relax
}
\endtt

\_endinput

2023-02-03  \_wloga introduced
2022-06-10  \_famalloc set to 42 (answer to the biggest fundamental question)
2022-03-07  \_noattr allocated
2022-02-19  \_newlanguage introduced
2021-02-15  \_advance -> \_incr, \_decr
2020-05-12  \newmath -> \newfam  bug fixing
2020-01-23  released
