% \iffalse meta-comment
%
%% File: l3alloc.dtx Copyright (C) 1990-2011 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
%% license or (at your option) any later version.  The latest version
%% of this license is in the file
%%
%%    http://www.latex-project.org/lppl.txt
%%
%% This file is part of the "l3kernel bundle" (The Work in LPPL)
%% and all files in that bundle must be distributed together.
%%
%% The released version of this bundle is available from CTAN.
%%
%% -----------------------------------------------------------------------
%%
%% The development version of the bundle can be found at
%%
%%    http://www.latex-project.org/svnroot/experimental/trunk/
%%
%% for those people who are interested.
%%
%%%%%%%%%%%
%% NOTE: %%
%%%%%%%%%%%
%%
%%   Snapshots taken from the repository represent work in progress and may
%%   not work or may contain conflicting material!  We therefore ask
%%   people _not_ to put them into distributions, archives, etc. without
%%   prior consultation with the LaTeX3 Project.
%%
%% -----------------------------------------------------------------------
%
%<*driver|package>
\RequirePackage{l3names}
\GetIdInfo$Id: l3alloc.dtx 3355 2012-02-09 07:18:22Z joseph $
  {L3 Experimental register allocation}
%</driver|package>
%<*driver>
\documentclass[full]{l3doc}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \title{^^A
%   The \pkg{l3alloc} package\\ Register allocation^^A
%   \thanks{This file describes v\ExplFileVersion,
%      last revised \ExplFileDate.}^^A
% }
%
% \author{^^A
%  The \LaTeX3 Project\thanks
%    {^^A
%      E-mail:
%        \href{mailto:latex-team@latex-project.org}
%          {latex-team@latex-project.org}^^A
%    }^^A
% }
%
% \date{Released \ExplFileDate}
%
% \maketitle
%
% \begin{documentation}
%
%  Note that this module is only used for generating an pkg{expl3}-based
%  format. Under \LaTeX{}, the \pkg{etex} package is used for allocation
%  management.
%
%  This module provides the basic mechanism for allocating \TeX{}s
%  registers. While designing this we have to take into account the
%  following characteristics:
%  \begin{itemize}
%    \item |\box255| is reserved for use in the output routine, so it
%      should not be allocated otherwise.
%    \item \TeX{} can load up 256 hyphenation patterns (registers
%      \tn{language} 0--255),
%    \item \TeX{} can load no more than 16 math families,
%    \item \TeX{} supports no more than 16 I/O streams for reading
%      (\tn{read}) and 16 I/O streams for writing (\tn{write}),
%    \item \TeX{} supports no more than 256 inserts.
%    \item The other registers (\tn{count}, \tn{dimen},
%      \tn{skip}, \tn{muskip}, \tn{box}, and \tn{toks})
%      range from 0 to 32768, but registers numbered above 255 are
%      accessed somewhat less efficiently.
%    \item Registers could be allocated both globally and locally; the
%      use of registers could also be globally or locally. Here we
%      provide support for globally allocated registers for both
%      global and local use.
%    \end{itemize}
%  We also need to allow for some bookkeeping: we need to know which
%  register was allocated last and which registers can not be
%  allocated by the standard mechanisms.
%
% \begin{function}[updated = 2011-09-05]{\alloc_new:nnnN}
%   \begin{syntax}
%     \cs{alloc_new:nnnN} \Arg{type} \Arg{min} \Arg{max} \meta{function}
%   \end{syntax}
%   Shorthand for allocating new registers. Defines \cs{<type>_new:N} as
%   and allocator function of the specified \meta{type}, indexed up from
%   \meta{min} to a \meta{max}, and with assignment carried out by
%   the \meta{function}. This process will create two token lists,
%   \cs{g_\meta{type}_allocation_tl} and \cs{c_\meta{type}_allocation_max_tl},
%   to store the current and maximum allocation numbers, respectively.
%   It will also create \cs{g_\meta{type}_allocation_seq} to store allocation
%   numbers which should not be used.
% \end{function}
%
% \section{Internal functions}
%
%  \begin{function}[updated = 2011-09-05]{\alloc_setup_type:nnn}
%    \begin{syntax}
%      \cs{alloc_setup_type:nnn} \Arg{type} \Arg{min} \Arg{max}
%    \end{syntax}
%    Sets up the storage needed for the administration of registers of
%    \Arg{type}, which will start allocating at \meta{min} and will issue
%    an error if there is an attempt to allocate past the \meta{max}.
%  \end{function}
%
%  \begin{function}{\alloc_reg:nNN}
%    \begin{syntax}
%      \cs{alloc_reg:nNN} \Arg{type} \meta{function} \meta{register}
%    \end{syntax}
%    Preforms the allocation for a new \meta{register} of \meta{type},
%    using the allocator \meta{function} (which will be either a
%    primitive \tn{\ldots def} or \tn{chardef}).
%  \end{function}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{l3alloc} implementation}
%
%    \begin{macrocode}
%<*initex>
%    \end{macrocode}
%
% \begin{macro}{\alloc_new:nnnN}
%   Shorthand for defining new register types and their allocators:
%    \begin{macrocode}
\cs_new_protected:Npn \alloc_new:nnnN #1#2#3#4
  {
    \alloc_setup_type:nnn {#1} {#2} {#3}
    \cs_new:cpn { #1 _new:N } ##1 { \alloc_reg:nNN {#1} #4 ##1 }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\alloc_setup_type:nnn}
%   For each type of register we need to \enquote{counters} that hold the
%   last allocated global register, plus a constant for the maximum
%   allocation. We also need a sequence to store the \enquote{exceptions}.
%    \begin{macrocode}
\cs_new_protected:Npn \alloc_setup_type:nnn #1#2#3
  {
    \tl_new:c    { g_ #1 _allocation_tl }
    \tl_gset:cx  { g_ #1 _allocation_tl }     { \int_eval:n {#2} }
    \tl_const:cx { c_ #1 _allocation_max_tl } { \int_eval:n {#3} }
    \seq_new:c   { g_ #1 _allocation_seq }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\int_eval:n}
%   For bootstrapping purposes, a definition of \cs{int_eval:n} is needed
%   in terms of primitives. This is replaced in \pkg{l3int} with a clearer
%   one.
%    \begin{macrocode}
\cs_new:Npn \int_eval:n #1 { \tex_number:D \etex_numexpr:D #1 \scan_stop: }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}
%   {box_new:N, \dim_new:N, \int_new:N, \muskip_new:N \skip_new:N}
%   To get everything to work correctly for inserts, some register types
%   need to have their allocators set up \enquote{early}. It therefore
%   makes sense to collect most of them together here.
%    \begin{macrocode}
\luatex_if_engine:TF
  { \alloc_new:nnnN { box } \c_zero \c_max_register_int \tex_chardef:D }
  { \alloc_new:nnnN { box } \c_zero \c_max_register_int \tex_mathchardef:D }
\alloc_new:nnnN { dim }    \c_zero \c_max_register_int \tex_dimendef:D
\alloc_new:nnnN { int }    { 11 }  \c_max_register_int \tex_countdef:D
\alloc_new:nnnN { muskip } \c_zero \c_max_register_int \tex_muskipdef:D
\alloc_new:nnnN { skip }   \c_zero \c_max_register_int \tex_skipdef:D
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\insert_new:N}
% \begin{macro}[aux]{\alloc_reserve_insert:n}
%   For inserts, there is a need to reserve space in various other registers.
%    \begin{macrocode}
\alloc_new:nnnN { insert } { 221 } { 254 } \tex_chardef:D
\group_begin:
  \cs_set_protected:Npn \alloc_reserve_insert:n #1
    {
      \tex_ifnum:D #1 > \c_insert_allocation_max_tl \scan_stop:
        \exp_after:wN \use_none:n
      \tex_else:D
        \exp_after:wN \use:n
      \tex_fi:D
        {
          \seq_put_right:Nn \g_box_allocation_seq  {#1}
          \seq_put_right:Nn \g_dim_allocation_seq  {#1}
          \seq_put_right:Nn \g_int_allocation_seq  {#1}
          \seq_put_right:Nn \g_skip_allocation_seq {#1}
          \exp_args:Nf \alloc_reserve_insert:n
            { \etex_numexpr:D #1 + 1 \scan_stop: }
        }
    }
  \alloc_reserve_insert:n { 221 }
\group_end:
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% Box $255$ is reserved by \TeX{} for output, so is protected here from
% use by the allocator.
%    \begin{macrocode}
\seq_put_right:Nn \g_box_allocation_seq { 255 }
%    \end{macrocode}
%
% \begin{macro}[int]{\alloc_reg:nNN}
%   This internal macro performs the actual allocation.
%    \begin{macrocode}
\cs_new_protected:Npn \alloc_reg:nNN #1#2#3
  {
    \chk_if_free_cs:N #3
    \tex_global:D #2 #3 \tl_use:c { g_ #1 _allocation_tl } \scan_stop:
    \iow_log:x
      {
        \token_to_str:N #3 ~=~ #1 ~register~
        \tl_use:c { g_ #1 _allocation_tl }
      }
    \alloc_next:n {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[aux]{\alloc_next:n}
%   Finding the next register to use is a question of doing an increment
%   then a check: if we run out of registers then it is a fatal error, so
%   there is no need to unwind the change. (The check could be done
%   first but that needs an additional calculation.) There is a built-in
%   loop to handle reserved allocation positions.
%    \begin{macrocode}
\cs_new_protected:Npn \alloc_next:n #1
  {
    \tl_gset:cx { g_ #1 _allocation_tl }
      { \int_eval:n { \tl_use:c { g_ #1 _allocation_tl } + 1 } }
    \int_compare:nNnTF
      { \tl_use:c { g_ #1 _allocation_tl } }
      > { \tl_use:c { c_ #1 _allocation_max_tl } }
      { \msg_kernel_fatal:nnx { kernel } { out-of-registers } {#1} }
      {
        \seq_if_in:cxT { g_ #1 _allocation_seq }
          { \tl_use:c { g_ #1 _allocation_tl } }
          { \alloc_next:n {#1} }
      }
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</initex>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
