% \iffalse meta-comment
%
%% File: l3intarray.dtx Copyright (C) 2017 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 development version of the bundle can be found at
%
%    https://github.com/latex3/latex3
%
% for those people who are interested.
%
%<*driver>
\documentclass[full]{l3doc}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
%
% \title{^^A
%   The \textsf{l3intarray} package: low-level arrays of small integers^^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 2017/09/18}
%
% \maketitle
%
% \begin{documentation}
%
% \section{\pkg{l3intarray} documentation}
%
% This module provides no user function: at present it is meant for
% kernel use only.
%
% It is a wrapper around the \tn{fontdimen} primitive, used to store
% arrays of integers (with a restricted range: absolute value at most
% $2^{30}-1$).  In contrast to \pkg{l3seq} sequences the access to
% individual entries is done in constant time rather than linear time,
% but only integers can be stored.  More precisely, the primitive
% \tn{fontdimen} stores dimensions but the \pkg{l3intarray} package
% transparently converts these from/to integers.  Assignments are always
% global.
%
% While \LuaTeX{}'s memory is extensible, other engines can
% \enquote{only} deal with a bit less than $4\times 10^6$ entries in all
% \tn{fontdimen} arrays combined (with default \TeX{}Live settings).
%
% \subsection{Internal functions}
%
% \begin{function}{\__intarray_new:Nn}
%   \begin{syntax}
%     \cs{__intarray_new:Nn} \meta{intarray~var} \Arg{size}
%   \end{syntax}
%   Evaluates the integer expression \meta{size} and allocates an
%   \meta{integer array variable} with that number of (zero) entries.
% \end{function}
%
% \begin{function}[EXP]{\__intarray_count:N}
%   \begin{syntax}
%     \cs{__intarray_count:N} \meta{intarray~var}
%   \end{syntax}
%   Expands to the number of entries in the \meta{integer array variable}.
%   Contrarily to \cs{seq_count:N} this is performed in constant time.
% \end{function}
%
% \begin{function}{\__intarray_gset:Nnn, \__intarray_gset_fast:Nnn}
%   \begin{syntax}
%     \cs{__intarray_gset:Nnn} \meta{intarray~var} \Arg{position} \Arg{value}
%     \cs{__intarray_gset_fast:Nnn} \meta{intarray~var} \Arg{position} \Arg{value}
%   \end{syntax}
%   Stores the result of evaluating the integer expression \meta{value}
%   into the \meta{integer array variable} at the (integer expression)
%   \meta{position}.  While \cs{__intarray_gset:Nnn} checks that the
%   \meta{position} is between $1$ and the \cs{__intarray_count:N} and that
%   the \meta{value}'s absolute value is at most $2^{30}-1$, the
%   \enquote{fast} function performs no such bound check.
%   Assignments are always global.
% \end{function}
%
% \begin{function}[EXP]{\__intarray_item:Nn, \__intarray_item_fast:Nn}
%   \begin{syntax}
%     \cs{__intarray_item:Nn} \meta{intarray~var} \Arg{position}
%     \cs{__intarray_item_fast:Nn} \meta{intarray~var} \Arg{position}
%   \end{syntax}
%   Expands to the integer entry stored at the (integer expression)
%   \meta{position} in the \meta{integer array variable}.  While
%   \cs{__intarray_item:Nn} checks that the \meta{position} is between $1$
%   and the \cs{__intarray_count:N}, the \enquote{fast} function performs
%   no such bound check.
% \end{function}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{l3intarray} implementation}
%
%    \begin{macrocode}
%<*initex|package>
%    \end{macrocode}
%
%    \begin{macrocode}
%<@@=intarray>
%    \end{macrocode}
%
% \subsection{Allocating arrays}
%
% \begin{variable}{\g_@@_font_int}
%   Used to assign one font per array.
%    \begin{macrocode}
\int_new:N \g_@@_font_int
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[int]{\@@_new:Nn}
%   Declare |#1| to be a font (arbitrarily |cmr10| at a never-used
%   size).  Store the array's size as the \tn{hyphenchar} of that font
%   and make sure enough \tn{fontdimen} are allocated, by setting the
%   last one.  Then clear any \tn{fontdimen} that |cmr10| starts with.
%   It seems \LuaTeX{}'s |cmr10| has an extra \tn{fontdimen} parameter
%   number $8$ compared to other engines (for a math font we would
%   replace $8$ by $22$ or some such).
%    \begin{macrocode}
\cs_new_protected:Npn \@@_new:Nn #1#2
  {
    \__chk_if_free_cs:N #1
    \int_gincr:N \g_@@_font_int
    \tex_global:D \tex_font:D #1 = cmr10~at~ \g_@@_font_int sp \scan_stop:
    \tex_hyphenchar:D #1 = \int_eval:n {#2} \scan_stop:
    \int_compare:nNnT { \tex_hyphenchar:D #1 } > 0
      { \tex_fontdimen:D \tex_hyphenchar:D #1 #1 = 0 sp \scan_stop: }
    \int_step_inline:nnnn { 1 } { 1 } { 8 }
      { \tex_fontdimen:D ##1 #1 = 0 sp \scan_stop: }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int, EXP]{\@@_count:N}
%   Size of an array.
%    \begin{macrocode}
\cs_new:Npn \@@_count:N #1 { \tex_the:D \tex_hyphenchar:D #1 }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Array items}
%
% \begin{macro}[int]{\@@_gset:Nnn, \@@_gset_fast:Nnn}
% \begin{macro}[aux]{\@@_gset_aux:Nnn}
%   Set the appropriate \tn{fontdimen}.  The slow version checks the
%   position and value are within bounds.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_gset_fast:Nnn #1#2#3
  { \tex_fontdimen:D \int_eval:n {#2} #1 = \int_eval:n {#3} sp \scan_stop: }
\cs_new_protected:Npn \@@_gset:Nnn #1#2#3
  {
    \exp_args:Nff \@@_gset_aux:Nnn #1
      { \int_eval:n {#2} } { \int_eval:n {#3} }
  }
\cs_new_protected:Npn \@@_gset_aux:Nnn #1#2#3
  {
    \int_compare:nTF { 1 <= #2 <= \@@_count:N #1 }
      {
        \int_compare:nTF { - \c_max_dim <= \int_abs:n {#3} <= \c_max_dim }
          { \@@_gset_fast:Nnn #1 {#2} {#3} }
          {
            \__msg_kernel_error:nnxxxx { kernel } { overflow }
              { \token_to_str:N #1 } {#2} {#3}
              { \int_compare:nNnT {#3} < 0 { - } \__int_value:w \c_max_dim }
            \@@_gset_fast:Nnn #1 {#2}
              { \int_compare:nNnT {#3} < 0 { - } \c_max_dim }
          }
      }
      {
        \__msg_kernel_error:nnxxx { kernel } { out-of-bounds }
          { \token_to_str:N #1 } {#2} { \@@_count:N #1 }
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[EXP]{\@@_item:Nn, \@@_item_fast:Nn}
% \begin{macro}[aux]{\@@_item_aux:Nn}
%   Get the appropriate \tn{fontdimen} and perform bound checks if requested.
%    \begin{macrocode}
\cs_new:Npn \@@_item_fast:Nn #1#2
  { \__int_value:w \tex_fontdimen:D \int_eval:n {#2} #1 }
\cs_new:Npn \@@_item:Nn #1#2
  { \exp_args:Nf \@@_item_aux:Nn #1 { \int_eval:n {#2} } }
\cs_new:Npn \@@_item_aux:Nn #1#2
  {
    \int_compare:nTF { 1 <= #2 <= \@@_count:N #1 }
      { \@@_item_fast:Nn #1 {#2} }
      {
        \__msg_kernel_expandable_error:nnnnn { kernel } { out-of-bounds }
          { \token_to_str:N #1 } {#2} { \@@_count:N #1 }
        0
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%    \begin{macrocode}
%</initex|package>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
