diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx | 228 |
1 files changed, 140 insertions, 88 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx b/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx index 56128aa8e1c..9ccc892e28d 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx @@ -1,6 +1,6 @@ % \iffalse meta-comment % -%% File: l3intarray.dtx Copyright (C) 2017 The LaTeX3 Project +%% File: l3intarray.dtx Copyright (C) 2017-2018 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 @@ -30,7 +30,7 @@ % % % \title{^^A -% The \textsf{l3intarray} package: low-level arrays of small integers^^A +% The \textsf{l3intarray} package: fast global integer arrays^^A % } % % \author{^^A @@ -42,7 +42,7 @@ % }^^A % } % -% \date{Released 2018/03/05} +% \date{Released 2018-04-30} % % \maketitle % @@ -50,66 +50,73 @@ % % \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} +% For applications requiring heavy use of integers, this module provides +% arrays which can be accessed in constant time (contrast \pkg{l3seq}, +% where access time is linear). These arrays have several important +% features +% \begin{itemize} +% \item The size of the array is fixed and must be given at +% point of initialisation +% \item The absolute value of each entry has maximum $2^{30}-1$ +% (\emph{i.e.}~one power lower than the usual \cs{c_max_int} +% ceiling of $2^{31}-1$) +% \end{itemize} +% The use of \texttt{intarray} data is therefore recommended for cases where +% the need for fast access is of paramount importance. +% +% \begin{function}[added = 2018-03-29]{\intarray_new:Nn} % \begin{syntax} -% \cs{__intarray_new:Nn} \meta{intarray~var} \Arg{size} +% \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{function}[EXP, added = 2018-03-29]{\intarray_count:N} % \begin{syntax} -% \cs{__intarray_count:N} \meta{intarray~var} +% \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{function}[added = 2018-03-29]{\intarray_gset: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} +% \cs{intarray_gset: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. +% \meta{position}. If the \meta{position} is not between $1$ and the +% \cs{intarray_count:N}, or the \meta{value}'s absolute value is +% bigger than $2^{30}-1$, an error occurs. Assignments are always +% global. % \end{function} % -% \begin{function}[EXP]{\__intarray_item:Nn, \__intarray_item_fast:Nn} +% \begin{function}[EXP, added = 2018-03-29]{\intarray_item:Nn} % \begin{syntax} -% \cs{__intarray_item:Nn} \meta{intarray~var} \Arg{position} -% \cs{__intarray_item_fast:Nn} \meta{intarray~var} \Arg{position} +% \cs{intarray_item: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. +% \meta{position} in the \meta{integer array variable}. If the +% \meta{position} is not between $1$ and the \cs{intarray_count:N}, an +% error occurs. % \end{function} % +% \subsection{Implementation notes} +% +% 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). +% % \end{documentation} % % \begin{implementation} @@ -126,6 +133,13 @@ % % \subsection{Allocating arrays} % +% \begin{variable}{\c_@@_sp_dim} +% Used to convert integers to dimensions fast. +% \begin{macrocode} +\dim_const:Nn \c_@@_sp_dim { 1 sp } +% \end{macrocode} +% \end{variable} +% % \begin{variable}{\g_@@_font_int} % Used to assign one font per array. % \begin{macrocode} @@ -133,7 +147,7 @@ % \end{macrocode} % \end{variable} % -% \begin{macro}{\@@_new:Nn} +% \begin{macro}{\intarray_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 @@ -141,82 +155,120 @@ % 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). +% Every \texttt{intarray} must be global; it's enough to run this +% check in \cs{intarray_new:Nn}. % \begin{macrocode} -\cs_new_protected:Npn \@@_new:Nn #1#2 +\__kernel_patch:nnNNpn { \__kernel_chk_var_scope:NN g #1 } { } +\cs_new_protected:Npn \intarray_new:Nn #1#2 { - \__chk_if_free_cs:N #1 + \__kernel_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_global:D \tex_font:D #1 + = cmr10~at~ \g_@@_font_int \c_@@_sp_dim \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: } + { \tex_fontdimen:D \tex_hyphenchar:D #1 #1 = \c_zero_dim } + \int_step_inline:nn { 8 } { \tex_fontdimen:D ##1 #1 = \c_zero_dim } } % \end{macrocode} % \end{macro} % -% \begin{macro}[EXP]{\@@_count:N} +% \begin{macro}[EXP]{\intarray_count:N} % Size of an array. % \begin{macrocode} -\cs_new:Npn \@@_count:N #1 { \tex_the:D \tex_hyphenchar:D #1 } +\cs_new:Npn \intarray_count:N #1 { \tex_the:D \tex_hyphenchar:D #1 } % \end{macrocode} % \end{macro} % % \subsection{Array items} % -% \begin{macro}{\@@_gset:Nnn, \@@_gset_fast:Nnn} -% \begin{macro}{\@@_gset_aux:Nnn} -% Set the appropriate \tn{fontdimen}. The slow version checks the -% position and value are within bounds. +% \begin{macro}[EXP]{\@@_bounds:NNnTF, \@@_bounds_error:NNn} +% The functions \cs{intarray_gset:Nnn} and \cs{intarray_item:Nn} share +% bounds checking. The |T| branch is used if |#3| is within bounds of +% the array |#2|. % \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 +\cs_new:Npn \@@_bounds:NNnTF #1#2#3#4#5 { - \exp_args:Nff \@@_gset_aux:Nnn #1 - { \int_eval:n {#2} } { \int_eval:n {#3} } + \if_int_compare:w 1 > #3 \exp_stop_f: + \@@_bounds_error:NNn #1 #2 {#3} + #5 + \else: + \if_int_compare:w #3 > \intarray_count:N #2 \exp_stop_f: + \@@_bounds_error:NNn #1 #2 {#3} + #5 + \else: + #4 + \fi: + \fi: } -\cs_new_protected:Npn \@@_gset_aux:Nnn #1#2#3 +\cs_new:Npn \@@_bounds_error: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} } - { - \__kernel_msg_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 } - } - } + #1 { kernel } { out-of-bounds } + { \token_to_str:N #2 } {#3} { \intarray_count:N #2 } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\intarray_gset:Nnn, \__kernel_intarray_gset:Nnn} +% \begin{macro}{\@@_gset:Nnn, \@@_gset_overflow:Nnn} +% Set the appropriate \tn{fontdimen}. The +% \cs{__kernel_intarray_gset:Nnn} function does not use +% \cs{int_eval:n}, namely its arguments must be suitable for +% \cs{int_value:w}. The user version checks the position and value +% are within bounds. +% \begin{macrocode} +\cs_new_protected:Npn \__kernel_intarray_gset:Nnn #1#2#3 + { \tex_fontdimen:D #2 #1 #3 \c_@@_sp_dim } +\cs_new_protected:Npn \intarray_gset:Nnn #1#2#3 + { + \exp_after:wN \@@_gset:Nww + \exp_after:wN #1 + \int_value:w \int_eval:n {#2} \exp_after:wN ; + \int_value:w \int_eval:n {#3} ; + } +\cs_new_protected:Npn \@@_gset:Nww #1#2 ; #3 ; + { + \@@_bounds:NNnTF \__kernel_msg_error:nnxxx #1 {#2} { - \__kernel_msg_error:nnxxx { kernel } { out-of-bounds } - { \token_to_str:N #1 } {#2} { \@@_count:N #1 } + \if_int_compare:w \int_abs:n {#3} > \c_max_dim + \exp_after:wN \@@_gset_overflow:NNnn + \fi: + \__kernel_intarray_gset:Nnn #1 {#2} {#3} } + { } + } +\cs_new_protected:Npn \@@_gset_overflow:NNnn #1#2#3#4 + { + \__kernel_msg_error:nnxxxx { kernel } { overflow } + { \token_to_str:N #2 } {#3} {#4} + { \int_value:w \int_compare:nNnT {#4} < 0 { - } \c_max_dim } + \__kernel_intarray_gset:Nnn #2 {#3} + { \int_value:w \int_compare:nNnT {#4} < 0 { - } \c_max_dim } } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}[EXP]{\@@_item:Nn, \@@_item_fast:Nn} -% \begin{macro}{\@@_item_aux:Nn} -% Get the appropriate \tn{fontdimen} and perform bound checks if requested. +% \begin{macro}[EXP]{\intarray_item:Nn, \__kernel_intarray_item:Nn} +% \begin{macro}{\@@_item:Nn} +% Get the appropriate \tn{fontdimen} and perform bound checks. The +% \cs{__kernel_intarray_item:Nn} function omits bound checks and omits +% \cs{int_eval:n}, namely its argument must be a \TeX{} integer +% suitable for \cs{int_value:w}. % \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 +\cs_new:Npn \__kernel_intarray_item:Nn #1#2 + { \int_value:w \tex_fontdimen:D #2 #1 } +\cs_new:Npn \intarray_item:Nn #1#2 { - \int_compare:nTF { 1 <= #2 <= \@@_count:N #1 } - { \@@_item_fast:Nn #1 {#2} } - { - \__kernel_msg_expandable_error:nnnnn { kernel } { out-of-bounds } - { \token_to_str:N #1 } {#2} { \@@_count:N #1 } - 0 - } + \exp_after:wN \@@_item:Nw + \exp_after:wN #1 + \int_value:w \int_eval:n {#2} ; + } +\cs_new:Npn \@@_item:Nw #1#2 ; + { + \@@_bounds:NNnTF \__kernel_msg_expandable_error:nnfff #1 {#2} + { \__kernel_intarray_item:Nn #1 {#2} } + { 0 } } % \end{macrocode} % \end{macro} |