summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2018-05-13 21:56:47 +0000
committerKarl Berry <karl@freefriends.org>2018-05-13 21:56:47 +0000
commite6d38f40f0132914020c723840be3489c4b692f0 (patch)
treedac2c281e93cba461b3ff2c1e4b8e34aad401716 /Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx
parent55be422dc01e60cfae781a9a4a310a96c9e99256 (diff)
l3 (13may18)
git-svn-id: svn://tug.org/texlive/trunk@47705 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx297
1 files changed, 279 insertions, 18 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx b/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx
index 9ccc892e28d..90d734c438a 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx
@@ -42,7 +42,7 @@
% }^^A
% }
%
-% \date{Released 2018-04-30}
+% \date{Released 2018-05-12}
%
% \maketitle
%
@@ -70,6 +70,8 @@
% \end{syntax}
% Evaluates the integer expression \meta{size} and allocates an
% \meta{integer array variable} with that number of (zero) entries.
+% The variable name should start with |\g_| because assignments are
+% always global.
% \end{function}
%
% \begin{function}[EXP, added = 2018-03-29]{\intarray_count:N}
@@ -92,6 +94,14 @@
% global.
% \end{function}
%
+% \begin{function}[added = 2018-05-04]{\intarray_gzero:N}
+% \begin{syntax}
+% \cs{intarray_gzero:N} \meta{intarray~var}
+% \end{syntax}
+% Sets all entries of the \meta{integer array variable} to zero.
+% Assignments are always global.
+% \end{function}
+%
% \begin{function}[EXP, added = 2018-03-29]{\intarray_item:Nn}
% \begin{syntax}
% \cs{intarray_item:Nn} \meta{intarray~var} \Arg{position}
@@ -133,6 +143,21 @@
%
% \subsection{Allocating arrays}
%
+% \begin{macro}{\@@_entry:w, \@@_count:w}
+% We use these primitives quite a lot in this module.
+% \begin{macrocode}
+\cs_new_eq:NN \@@_entry:w \tex_fontdimen:D
+\cs_new_eq:NN \@@_count:w \tex_hyphenchar:D
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}{\l_@@_loop_int}
+% A loop index.
+% \begin{macrocode}
+\int_new:N \l_@@_loop_int
+% \end{macrocode}
+% \end{variable}
+%
% \begin{variable}{\c_@@_sp_dim}
% Used to convert integers to dimensions fast.
% \begin{macrocode}
@@ -147,7 +172,12 @@
% \end{macrocode}
% \end{variable}
%
-% \begin{macro}{\intarray_new:Nn}
+% \begin{macrocode}
+\__kernel_msg_new:nnn { kernel } { negative-array-size }
+ { Size~of~array~may~not~be~negative:~#1 }
+% \end{macrocode}
+%
+% \begin{macro}{\intarray_new:Nn, \@@_new:N}
% 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
@@ -158,17 +188,27 @@
% Every \texttt{intarray} must be global; it's enough to run this
% check in \cs{intarray_new:Nn}.
% \begin{macrocode}
-\__kernel_patch:nnNNpn { \__kernel_chk_var_scope:NN g #1 } { }
-\cs_new_protected:Npn \intarray_new:Nn #1#2
+\cs_new_protected:Npn \@@_new: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 \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 = \c_zero_dim }
- \int_step_inline:nn { 8 } { \tex_fontdimen:D ##1 #1 = \c_zero_dim }
+ \int_step_inline:nn { 8 }
+ { \__kernel_intarray_gset:Nnn #1 {##1} \c_zero_int }
+ }
+\__kernel_patch:nnNNpn { \__kernel_chk_var_scope:NN g #1 } { }
+\cs_new_protected:Npn \intarray_new:Nn #1#2
+ {
+ \@@_new:N #1
+ \@@_count:w #1 = \int_eval:n {#2} \scan_stop:
+ \int_compare:nNnT { \intarray_count:N #1 } < 0
+ {
+ \__kernel_msg_error:nnx { kernel } { negative-array-size }
+ { \intarray_count:N #1 }
+ }
+ \int_compare:nNnT { \intarray_count:N #1 } > 0
+ { \__kernel_intarray_gset:Nnn #1 { \intarray_count:N #1 } { 0 } }
}
% \end{macrocode}
% \end{macro}
@@ -176,12 +216,21 @@
% \begin{macro}[EXP]{\intarray_count:N}
% Size of an array.
% \begin{macrocode}
-\cs_new:Npn \intarray_count:N #1 { \tex_the:D \tex_hyphenchar:D #1 }
+\cs_new:Npn \intarray_count:N #1 { \int_value:w \@@_count:w #1 }
% \end{macrocode}
% \end{macro}
%
% \subsection{Array items}
%
+% \begin{macro}[EXP]{\@@_signed_max_dim:n}
+% Used when an item to be stored is larger than \cs{c_max_dim} in
+% absolute value; it is replaced by $\pm\cs{c_max_dim}$.
+% \begin{macrocode}
+\cs_new:Npn \@@_signed_max_dim:n #1
+ { \int_value:w \int_compare:nNnT {#1} < 0 { - } \c_max_dim }
+% \end{macrocode}
+% \end{macro}
+%
% \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
@@ -218,7 +267,7 @@
% 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 }
+ { \@@_entry:w #2 #1 #3 \c_@@_sp_dim }
\cs_new_protected:Npn \intarray_gset:Nnn #1#2#3
{
\exp_after:wN \@@_gset:Nww
@@ -230,25 +279,56 @@
{
\@@_bounds:NNnTF \__kernel_msg_error:nnxxx #1 {#2}
{
- \if_int_compare:w \int_abs:n {#3} > \c_max_dim
- \exp_after:wN \@@_gset_overflow:NNnn
- \fi:
+ \@@_gset_overflow_test:nw {#3}
\__kernel_intarray_gset:Nnn #1 {#2} {#3}
}
{ }
}
+\cs_if_exist:NTF \tex_ifabsnum:D
+ {
+ \cs_new_protected:Npn \@@_gset_overflow_test:nw #1
+ {
+ \tex_ifabsnum:D #1 > \c_max_dim
+ \exp_after:wN \@@_gset_overflow:NNnn
+ \fi:
+ }
+ }
+ {
+ \cs_new_protected:Npn \@@_gset_overflow_test:nw #1
+ {
+ \if_int_compare:w \int_abs:n {#1} > \c_max_dim
+ \exp_after:wN \@@_gset_overflow:NNnn
+ \fi:
+ }
+ }
\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 }
+ { \token_to_str:N #2 } {#3} {#4} { \@@_signed_max_dim:n {#4} }
+ #1 #2 {#3} { \@@_signed_max_dim:n {#4} }
}
% \end{macrocode}
% \end{macro}
% \end{macro}
%
+% \begin{macro}{\intarray_gzero:N}
+% Set the appropriate \tn{fontdimen} to zero. No bound checking
+% needed. The \cs{prg_replicate:nn} possibly uses quite a lot of
+% memory, but this is somewhat comparable to the size of the array,
+% and it is much faster than an \cs{int_step_inline:nn} loop.
+% \begin{macrocode}
+\cs_new_protected:Npn \intarray_gzero:N #1
+ {
+ \int_zero:N \l_@@_loop_int
+ \prg_replicate:nn { \intarray_count:N #1 }
+ {
+ \int_incr:N \l_@@_loop_int
+ \@@_entry:w \l_@@_loop_int #1 \c_zero_dim
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}[EXP]{\intarray_item:Nn, \__kernel_intarray_item:Nn}
% \begin{macro}{\@@_item:Nn}
% Get the appropriate \tn{fontdimen} and perform bound checks. The
@@ -257,7 +337,7 @@
% suitable for \cs{int_value:w}.
% \begin{macrocode}
\cs_new:Npn \__kernel_intarray_item:Nn #1#2
- { \int_value:w \tex_fontdimen:D #2 #1 }
+ { \int_value:w \@@_entry:w #2 #1 }
\cs_new:Npn \intarray_item:Nn #1#2
{
\exp_after:wN \@@_item:Nw
@@ -274,6 +354,187 @@
% \end{macro}
% \end{macro}
%
+% \begin{macro}{\intarray_rand_item:N}
+% Importantly, \cs{intarray_item:Nn} only evaluates its argument once.
+% \begin{macrocode}
+\cs_new:Npn \intarray_rand_item:N #1
+ { \intarray_item:Nn #1 { \int_rand:n { \intarray_count:N #1 } } }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Working with contents of integer arrays}
+%
+% At the time of writing these are candidates, but we need at least
+% \cs{intarray_const_from_clist:Nn} in \pkg{l3fp} so before
+% \pkg{l3candidates}.
+%
+% \begin{macro}{\intarray_const_from_clist:Nn, \@@_const_from_clist:nN}
+% Similar to \cs{intarray_new:Nn} (which we don't use because when
+% debugging is enabled that function checks the variable name starts
+% with |g_|). We make use of the fact that \TeX{} allows allocation
+% of successive \tn{fontdimen} as long as no other font has been
+% declared: no need to count the comma list items first. We need the
+% code in \cs{intarray_gset:Nnn} that checks the item value is not too
+% big, namely \cs{@@_gset_overflow_test:nw}, but not the code that
+% checks bounds. At the end, set the size of the intarray.
+% \begin{macrocode}
+\__kernel_patch:nnNNpn { \__kernel_chk_var_scope:NN c #1 } { }
+\cs_new_protected:Npn \intarray_const_from_clist:Nn #1#2
+ {
+ \@@_new:N #1
+ \int_zero:N \l_@@_loop_int
+ \clist_map_inline:nn {#2}
+ { \exp_args:Nf \@@_const_from_clist:nN { \int_eval:n {##1} } #1 }
+ \@@_count:w #1 \l_@@_loop_int
+ }
+\cs_new_protected:Npn \@@_const_from_clist:nN #1#2
+ {
+ \int_incr:N \l_@@_loop_int
+ \@@_gset_overflow_test:nw {#1}
+ \__kernel_intarray_gset:Nnn #2 \l_@@_loop_int {#1}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[rEXP]{\intarray_to_clist:N, \@@_to_clist:Nn, \@@_to_clist:w}
+% Loop through the array, putting a comma before each item. Remove
+% the leading comma with |f|-expansion. We also use the auxiliary in
+% \cs{intarray_show:N} with argument comma, space.
+% \begin{macrocode}
+\cs_new:Npn \intarray_to_clist:N #1 { \@@_to_clist:Nn #1 { , } }
+\cs_new:Npn \@@_to_clist:Nn #1#2
+ {
+ \int_compare:nNnF { \intarray_count:N #1 } = \c_zero_int
+ {
+ \exp_last_unbraced:Nf \use_none:n
+ { \@@_to_clist:w 1 ; #1 {#2} \prg_break_point: }
+ }
+ }
+\cs_new:Npn \@@_to_clist:w #1 ; #2#3
+ {
+ \if_int_compare:w #1 > \@@_count:w #2
+ \prg_break:n
+ \fi:
+ #3 \__kernel_intarray_item:Nn #2 {#1}
+ \exp_after:wN \@@_to_clist:w
+ \int_value:w \int_eval:w #1 + \c_one_int ; #2 {#3}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\intarray_show:N, \intarray_log:N}
+% Convert the list to a comma list (with spaces after each comma)
+% \begin{macrocode}
+\cs_new_protected:Npn \intarray_show:N { \@@_show:NN \msg_show:nnxxxx }
+\cs_generate_variant:Nn \intarray_show:N { c }
+\cs_new_protected:Npn \intarray_log:N { \@@_show:NN \msg_log:nnxxxx }
+\cs_generate_variant:Nn \intarray_log:N { c }
+\cs_new_protected:Npn \@@_show:NN #1#2
+ {
+ \__kernel_chk_defined:NT #2
+ {
+ #1 { LaTeX/kernel } { show-intarray }
+ { \token_to_str:N #2 }
+ { \intarray_count:N #2 }
+ { >~ \@@_to_clist:Nn #2 { , ~ } }
+ { }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Random arrays}
+%
+% \begin{macro}
+% {
+% \intarray_gset_rand:Nn,
+% \intarray_gset_rand:Nnn,
+% \@@_gset_rand:Nnn,
+% \@@_gset_rand:Nff,
+% \@@_gset_rand_auxi:Nnnn,
+% \@@_gset_rand_auxii:Nnnn,
+% \@@_gset_rand_auxiii:Nnnn,
+% \@@_gset_all_same:Nn,
+% }
+% We only perform the bounds checks once. This is done by two
+% \cs{@@_gset_overflow_test:nw}, with an appropriate empty argument to
+% avoid a spurious \enquote{at position \texttt{\#1}} part in the
+% error message. Then calculate the number of choices: this is at
+% most $(2^{30}-1)-(-(2^{30}-1))+1=2^{31}-1$, which just barely does
+% not overflow. For small ranges use \cs{__kernel_randint:n} (making
+% sure to subtract~$1$ \emph{before} adding the random number to the
+% \meta{min}, to avoid overflow when \meta{min} or \meta{max} are
+% $\pm\cs{c_max_int}$), otherwise \cs{__kernel_randint:nn}. Finally,
+% if there are no random numbers do not define any of the auxiliaries.
+% \begin{macrocode}
+\cs_new_protected:Npn \intarray_gset_rand:Nn #1
+ { \intarray_gset_rand:Nnn #1 { 1 } }
+\sys_if_rand_exist:TF
+ {
+ \cs_new_protected:Npn \intarray_gset_rand:Nnn #1#2#3
+ {
+ \@@_gset_rand:Nff #1
+ { \int_eval:n {#2} } { \int_eval:n {#3} }
+ }
+ \cs_new_protected:Npn \@@_gset_rand:Nnn #1#2#3
+ {
+ \int_compare:nNnTF {#2} > {#3}
+ {
+ \__kernel_msg_expandable_error:nnnn
+ { kernel } { randint-backward-range } {#2} {#3}
+ \@@_gset_rand:Nnn #1 {#3} {#2}
+ }
+ {
+ \@@_gset_overflow_test:nw {#2}
+ \@@_gset_rand_auxi:Nnnn #1 { } {#2} {#3}
+ }
+ }
+ \cs_generate_variant:Nn \@@_gset_rand:Nnn { Nff }
+ \cs_new_protected:Npn \@@_gset_rand_auxi:Nnnn #1#2#3#4
+ {
+ \@@_gset_overflow_test:nw {#4}
+ \@@_gset_rand_auxii:Nnnn #1 { } {#4} {#3}
+ }
+ \cs_new_protected:Npn \@@_gset_rand_auxii:Nnnn #1#2#3#4
+ {
+ \exp_args:NNf \@@_gset_rand_auxiii:Nnnn #1
+ { \int_eval:n { #3 - #4 + 1 } } {#4} {#3}
+ }
+ \cs_new_protected:Npn \@@_gset_rand_auxiii:Nnnn #1#2#3#4
+ {
+ \exp_args:NNf \@@_gset_all_same:Nn #1
+ {
+ \int_compare:nNnTF {#2} > \c__kernel_randint_max_int
+ {
+ \exp_stop_f:
+ \int_eval:n { \__kernel_randint:nn {#3} {#4} }
+ }
+ {
+ \exp_stop_f:
+ \int_eval:n { \__kernel_randint:n {#2} - 1 + #3 }
+ }
+ }
+ }
+ \cs_new_protected:Npn \@@_gset_all_same:Nn #1#2
+ {
+ \int_zero:N \l_@@_loop_int
+ \prg_replicate:nn { \intarray_count:N #1 }
+ {
+ \int_incr:N \l_@@_loop_int
+ \__kernel_intarray_gset:Nnn #1 \l_@@_loop_int {#2}
+ }
+ }
+ }
+ {
+ \cs_new_protected:Npn \intarray_gset_rand:Nnn #1#2#3
+ {
+ \__kernel_msg_error:nnn { kernel } { fp-no-random }
+ { \intarray_gset_rand:Nnn #1 {#2} {#3} }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macrocode}
%</initex|package>
% \end{macrocode}