diff options
author | Norbert Preining <norbert@preining.info> | 2021-11-23 03:01:10 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2021-11-23 03:01:10 +0000 |
commit | 0b34c573a443a0ea2ce617f1466aef7ea2c38a98 (patch) | |
tree | 0a10ff22dddac4eef11f21687c390598dfc75f96 /macros/latex/contrib/l3kernel/l3intarray.dtx | |
parent | 3b45580e298046d6c1cb0431da31bea04bc6613a (diff) |
CTAN sync 202111230301
Diffstat (limited to 'macros/latex/contrib/l3kernel/l3intarray.dtx')
-rw-r--r-- | macros/latex/contrib/l3kernel/l3intarray.dtx | 781 |
1 files changed, 598 insertions, 183 deletions
diff --git a/macros/latex/contrib/l3kernel/l3intarray.dtx b/macros/latex/contrib/l3kernel/l3intarray.dtx index 3d95e6e04b..8f0976fb25 100644 --- a/macros/latex/contrib/l3kernel/l3intarray.dtx +++ b/macros/latex/contrib/l3kernel/l3intarray.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2021-11-12} +% \date{Released 2021-11-22} % % \maketitle % @@ -173,15 +173,15 @@ %<@@=intarray> % \end{macrocode} % -% \subsection{Allocating arrays} +% There are two implementations for this module: One \cs{fontdimen} based one +% for more traditional \TeX\ engines and a Lua based one for engines with Lua support. % -% \begin{macro}{\@@_entry:w, \@@_count:w} -% We use these primitives quite a lot in this module. +% Both versions do not allow negative array sizes. % \begin{macrocode} -\cs_new_eq:NN \@@_entry:w \tex_fontdimen:D -\cs_new_eq:NN \@@_count:w \tex_hyphenchar:D +%<*tex> +\msg_new:nnn { kernel } { negative-array-size } + { Size~of~array~may~not~be~negative:~#1 } % \end{macrocode} -% \end{macro} % % \begin{variable}{\l_@@_loop_int} % A loop index. @@ -190,25 +190,433 @@ % \end{macrocode} % \end{variable} % +% \subsection{Lua implementation} +% First, let's look at the Lua variant: +% +% We select the Lua version if the Lua helpers were defined. This can be detected by +% the presence of \cs{@@_gset_count:Nw}. +% +% \begin{macrocode} +\cs_if_exist:NTF \@@_gset_count:Nw + { +% \end{macrocode} +% +% \subsubsection{Allocating arrays} +% +% \begin{variable}{\g_@@_table_int, \l_@@_bad_index_int} +% Used to differentiate intarrays in Lua and to record an invalid index. +% \begin{macrocode} + \int_new:N \g_@@_table_int + \int_new:N \l_@@_bad_index_int +%</tex> +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\@@:w} +% Used as marker for intarrays in Lua. Followed by an unbraced number +% identifying the array and a single space. This format is used to make it +% easy to scan from Lua. +% \begin{macrocode} +%<*lua> +luacmd('@@:w', function() + scan_int() + tex.error'LaTeX Error: Isolated intarray ignored' +end, 'protected', 'global') +%</lua> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\intarray_new:Nn, \intarray_new:cn} +% \begin{macro}{\@@_new:N} +% Declare |#1| as a tokenlist with the scanmark and a unique number. +% Pass the array's size to the Lua helper. +% Every \texttt{intarray} must be global; it's enough to run this +% check in \cs{intarray_new:Nn}. +% \begin{macrocode} +%<*tex> + \cs_new_protected:Npn \@@_new:N #1 + { + \__kernel_chk_if_free_cs:N #1 + \int_gincr:N \g_@@_table_int + \cs_gset_nopar:Npx #1 { \@@:w \int_use:N \g_@@_table_int \c_space_tl } + } + \cs_new_protected:Npn \intarray_new:Nn #1#2 + { + \@@_new:N #1 + \@@_gset_count:Nw #1 \int_eval:n {#2} \scan_stop: + \int_compare:nNnT { \intarray_count:N #1 } < 0 + { + \msg_error:nnx { kernel } { negative-array-size } + { \intarray_count:N #1 } + } + } + \cs_generate_variant:Nn \intarray_new:Nn { c } +%</tex> +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% Before we get to the first command implmented in Lua, we first need some +% definitions. Since \texttt{token.create} only works correctly if \TeX{} +% has seen the tokens before, we first run a short \TeX{} sequence to ensure +% that all relevant control sequences are known. +% \begin{macrocode} +%<*lua> + +local scan_token = token.scan_token +local put_next = token.put_next +local intarray_marker = token_create_safe'@@:w' +local use_none = token_create_safe'use_none:n' +local use_i = token_create_safe'use:n' +local expand_after_scan_stop = {token_create_safe'exp_after:wN', + token_create_safe'scan_stop:'} +local comma = token_create(string.byte',') +% \end{macrocode} +% +% \begin{macro}{@@_table} +% Internal helper to scan an intarray token, extract the associated +% Lua table and return an error if the input is invalid. +% +% \begin{macrocode} +local @@_table do + local tables = get_luadata and get_luadata'@@' or {[0] = {}} + function @@_table() + local t = scan_token() + if t ~= intarray_marker then + put_next(t) + tex.error'LaTeX Error: intarray expected' + return tables[0] + end + local i = scan_int() + local current_table = tables[i] + if current_table then return current_table end + current_table = {} + tables[i] = current_table + return current_table + end +% \end{macrocode} +% Since in \LaTeX{} this is loaded in the format, we want to preserve any intarrays +% which are created while format building for the actual run. +% +% To do this, we use the \texttt{register_luadata} mechanism from \pkg{l3luatex}: +% Directly before the format get dumped, the following function gets invoked and serializes +% all existing tables into a string. This string gets compiled and dumped into the format and +% is made available at the beginning of regular runs as \texttt{get_luadata'@@'}. +% \begin{macrocode} + if register_luadata then + register_luadata('@@', function() + local t = "{[0]={}," + for i=1, #tables do + t = string.format("%s{%s},", t, table.concat(tables[i], ',')) + end + return t .. "}" + end) + end +end +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\intarray_count:N, \intarray_count:c} +% \begin{macro}[EXP]{\@@_gset_count:Nw} +% Set and get the size of an array. ``Setting the size'' means in this context that +% we add zeros until we reach the desired size. +% \begin{macrocode} + +local sprint = tex.sprint + +luacmd('@@_gset_count:Nw', function() + local t = @@_table() + local n = scan_int() + for i=#t+1, n do t[i] = 0 end +end, 'protected', 'global') + +luacmd('intarray_count:N', function() + sprint(-2, #@@_table()) +end, 'global') +%</lua> +% \end{macrocode} +% +% \begin{macrocode} +%<*tex> + \cs_generate_variant:Nn \intarray_count:N { c } +%</tex> +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsubsection{Array items} +% +% \begin{macro}{\@@_gset:wF, \@@_gset:w} +% The setter provided by Lua. The argument order somewhat emulates the |\fontdimen|: +% First the array index, followed by the intarray and then the new value. +% This has been chosen over a more conventional order to provide a delimiter for the numbers. +% \begin{macrocode} +%<*lua> +luacmd('@@_gset:wF', function() + local i = scan_int() + local t = @@_table() + if t[i] then + t[i] = scan_int() + put_next(use_none) + else + tex.count.l_@@_bad_index_int = i + scan_int() + put_next(use_i) + end +end, 'protected', 'global') + +luacmd('@@_gset:w', function() + local i = scan_int() + local t = @@_table() + t[i] = scan_int() +end, 'protected', 'global') +%</lua> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\intarray_gset:Nnn, \intarray_gset:cnn, \__kernel_intarray_gset:Nnn} +% 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} +%<*tex> + \cs_new_protected:Npn \__kernel_intarray_gset:Nnn #1#2#3 + { \@@_gset:w #2 #1 #3 \scan_stop: } + \cs_new_protected:Npn \intarray_gset:Nnn #1#2#3 + { + \@@_gset:wF \int_eval:n {#2} #1 \int_eval:n{#3} + { + \msg_error:nnxxx { kernel } { out-of-bounds } + { \token_to_str:N #1 } { \int_use:N \l_@@_bad_index_int } { \intarray_count:N #1 } + } + } + \cs_generate_variant:Nn \intarray_gset:Nnn { c } +%</tex> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\intarray_gzero:N, \intarray_gzero:c} +% Set the appropriate array entry to zero. No bound checking +% needed. +% \begin{macrocode} +%<*lua> +luacmd('intarray_gzero:N', function() + local t = @@_table() + for i=1, #t do + t[i] = 0 + end +end, 'global', 'protected') +%</lua> +%<*tex> + \cs_generate_variant:Nn \intarray_gzero:N { c } +%</tex> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\intarray_item:Nn, \intarray_item:cn, \__kernel_intarray_item:Nn} +% \begin{macro}{\@@_item:wF,\@@_item:w} +% Get the appropriate entry 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} +%<*lua> +luacmd('@@_item:wF', function() + local i = scan_int() + local t = @@_table() + local item = t[i] + if item then + put_next(use_none) + else + tex.l_@@_bad_index_int = i + put_next(use_i) + end + put_next(expand_after_scan_stop) + scan_token() + if item then + sprint(-2, item) + end +end, 'global') + +luacmd('@@_item:w', function() + local i = scan_int() + local t = @@_table() + sprint(-2, t[i]) +end, 'global') +%</lua> +% \end{macrocode} +% +% \begin{macrocode} +%<*tex> + \cs_new:Npn \__kernel_intarray_item:Nn #1#2 + { \@@_item:w #2 #1 } + \cs_new:Npn \intarray_item:Nn #1#2 + { + \@@_item:wF \int_eval:n {#2} #1 + { + \msg_expandable_error:nnfff { kernel } { out-of-bounds } + { \token_to_str:N #1 } { \int_use:N \l_@@_bad_index_int } { \intarray_count:N #1 } + 0 + } + } + \cs_generate_variant:Nn \intarray_item:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\intarray_rand_item:N, \intarray_rand_item:c} +% 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 } } } + \cs_generate_variant:Nn \intarray_rand_item:N { c } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Working with contents of integer arrays} +% +% \begin{macro}{\intarray_const_from_clist:Nn, \intarray_const_from_clist:cn} +% We use the \cs{__kernel_intarray_gset:Nnn} which does not do bounds checking +% and instead automatically resizes the array. +% This is not implemented in Lua to ensure that the clist parsing is consistent +% with the clist module. +% \begin{macrocode} + \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} + { + \int_incr:N \l_@@_loop_int + \__kernel_intarray_gset:Nnn #1 \l_@@_loop_int { \int_eval:n {##1} } } + } + \cs_generate_variant:Nn \intarray_const_from_clist:Nn { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[rEXP]{\intarray_to_clist:N, \intarray_to_clist:c} +% \begin{macro}[rEXP]{\@@_to_clist:Nn, \@@_to_clist:w} +% The \cs{@@_to_clist:Nn} auxiliary allows to choose the delimiter and +% is also used in \cs{intarray_show:N}. Here we just pass the information +% to Lua and let \texttt{table.concat} do the actual work. +% We discard the category codes of the passed delimiter but this is not +% an issue since the delimiter is always just a comma or a comma and a space. +% In both cases \texttt{sprint(2, ...)} provides the right catcodes. +% \begin{macrocode} + \cs_new:Npn \intarray_to_clist:N #1 { \@@_to_clist:Nn #1 { , } } + \cs_generate_variant:Nn \intarray_to_clist:N { c } +%</tex> +%<*lua> +local concat = table.concat +luacmd('@@_to_clist:Nn', function() + local t = @@_table() + local sep = token.scan_string() + sprint(-2, concat(t, sep)) +end, 'global') +%</lua> +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[rEXP]{\__kernel_intarray_range_to_clist:Nnn, \@@_range_to_clist:w} +% Loop through part of the array. +% \begin{macrocode} +%<*tex> + \cs_new:Npn \__kernel_intarray_range_to_clist:Nnn #1#2#3 + { + \@@_range_to_clist:w #1 + \int_eval:n {#2} ~ \int_eval:n {#3} ~ + } +%</tex> +%<*lua> +luacmd('@@_range_to_clist:w', function() + local t = @@_table() + local from = scan_int() + local to = scan_int() + sprint(-2, concat(t, ',', from, to)) +end, 'global') +%</lua> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\__kernel_intarray_gset_range_from_clist:Nnn, \@@_gset_range:nNw} +% Loop through part of the array. We allow additional commas at the end. +% \begin{macrocode} +%<*tex> + \cs_new_protected:Npn \__kernel_intarray_gset_range_from_clist:Nnn #1#2#3 + { + \@@_gset_range:w \int_eval:w #2 #1 #3 , , \scan_stop: + } +%</tex> +%<*lua> +luacmd('@@_gset_range:w', function() + local from = scan_int() + local t = @@_table() + while true do + local tok = scan_token() + if tok == comma then + repeat + tok = scan_token() + until tok ~= comma + break + else + put_next(tok) + end + t[from] = scan_int() + scan_token() + from = from + 1 + end + end, 'global', 'protected') +%</lua> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_gset_overflow_test:nw} +% In order to allow some code sharing later we provide the +% \cs{@@_gset_overflow_test:nw} name here. It doesn't actually test anything +% since the Lua implementation accepts all integers which could be tested with +% \cs{tex_ifabsnum:D}. +% \begin{macrocode} +%<*tex> + \cs_new_protected:Npn \@@_gset_overflow_test:nw #1 + { + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Font dimension based implementation} +% +% Go to the false branch of the conditional above. +% \begin{macrocode} + } + { +% \end{macrocode} +% +% \subsubsection{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}{\c_@@_sp_dim} % Used to convert integers to dimensions fast. % \begin{macrocode} -\dim_const:Nn \c_@@_sp_dim { 1 sp } + \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} -\int_new:N \g_@@_font_int + \int_new:N \g_@@_font_int % \end{macrocode} % \end{variable} % -% \begin{macrocode} -\msg_new:nnn { kernel } { negative-array-size } - { Size~of~array~may~not~be~negative:~#1 } -% \end{macrocode} -% % \begin{macro}{\intarray_new:Nn, \intarray_new:cn} % \begin{macro}{\@@_new:N} % Declare |#1| to be a font (arbitrarily |cmr10| at a never-used @@ -221,28 +629,28 @@ % 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: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: - \int_step_inline:nn { 8 } - { \__kernel_intarray_gset:Nnn #1 {##1} \c_zero_int } - } -\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 + \cs_new_protected:Npn \@@_new:N #1 { - \msg_error:nnx { kernel } { negative-array-size } - { \intarray_count: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: + \int_step_inline:nn { 8 } + { \__kernel_intarray_gset:Nnn #1 {##1} \c_zero_int } } - \int_compare:nNnT { \intarray_count:N #1 } > 0 - { \__kernel_intarray_gset:Nnn #1 { \intarray_count:N #1 } { 0 } } - } -\cs_generate_variant:Nn \intarray_new:Nn { c } + \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 + { + \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 } } + } + \cs_generate_variant:Nn \intarray_new:Nn { c } % \end{macrocode} % \end{macro} % \end{macro} @@ -250,19 +658,19 @@ % \begin{macro}[EXP]{\intarray_count:N, \intarray_count:c} % Size of an array. % \begin{macrocode} -\cs_new:Npn \intarray_count:N #1 { \int_value:w \@@_count:w #1 } -\cs_generate_variant:Nn \intarray_count:N { c } + \cs_new:Npn \intarray_count:N #1 { \int_value:w \@@_count:w #1 } + \cs_generate_variant:Nn \intarray_count:N { c } % \end{macrocode} % \end{macro} % -% \subsection{Array items} +% \subsubsection{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 } + \cs_new:Npn \@@_signed_max_dim:n #1 + { \int_value:w \int_compare:nNnT {#1} < 0 { - } \c_max_dim } % \end{macrocode} % \end{macro} % @@ -271,24 +679,24 @@ % bounds checking. The |T| branch is used if |#3| is within bounds of % the array |#2|. % \begin{macrocode} -\cs_new:Npn \@@_bounds:NNnTF #1#2#3 - { - \if_int_compare:w 1 > #3 \exp_stop_f: - \@@_bounds_error:NNnw #1 #2 {#3} - \else: - \if_int_compare:w #3 > \intarray_count:N #2 \exp_stop_f: - \@@_bounds_error:NNnw #1 #2 {#3} - \fi: - \fi: - \use_i:nn - } -\cs_new:Npn \@@_bounds_error:NNnw #1#2#3#4 \use_i:nn #5#6 - { - #4 - #1 { kernel } { out-of-bounds } - { \token_to_str:N #2 } {#3} { \intarray_count:N #2 } - #6 - } + \cs_new:Npn \@@_bounds:NNnTF #1#2#3 + { + \if_int_compare:w 1 > #3 \exp_stop_f: + \@@_bounds_error:NNnw #1 #2 {#3} + \else: + \if_int_compare:w #3 > \intarray_count:N #2 \exp_stop_f: + \@@_bounds_error:NNnw #1 #2 {#3} + \fi: + \fi: + \use_i:nn + } + \cs_new:Npn \@@_bounds_error:NNnw #1#2#3#4 \use_i:nn #5#6 + { + #4 + #1 { kernel } { out-of-bounds } + { \token_to_str:N #2 } {#3} { \intarray_count:N #2 } + #6 + } % \end{macrocode} % \end{macro} % @@ -300,48 +708,48 @@ % \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 - { \@@_entry:w #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_generate_variant:Nn \intarray_gset:Nnn { c } -\cs_new_protected:Npn \@@_gset:Nww #1#2 ; #3 ; - { - \@@_bounds:NNnTF \msg_error:nnxxx #1 {#2} + \cs_new_protected:Npn \__kernel_intarray_gset:Nnn #1#2#3 + { \@@_entry:w #2 #1 #3 \c_@@_sp_dim } + \cs_new_protected:Npn \intarray_gset:Nnn #1#2#3 { - \@@_gset_overflow_test:nw {#3} - \__kernel_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_if_exist:NTF \tex_ifabsnum:D - { - \cs_new_protected:Npn \@@_gset_overflow_test:nw #1 + \cs_generate_variant:Nn \intarray_gset:Nnn { c } + \cs_new_protected:Npn \@@_gset:Nww #1#2 ; #3 ; { - \tex_ifabsnum:D #1 > \c_max_dim - \exp_after:wN \@@_gset_overflow:NNnn - \fi: + \@@_bounds:NNnTF \msg_error:nnxxx #1 {#2} + { + \@@_gset_overflow_test:nw {#3} + \__kernel_intarray_gset:Nnn #1 {#2} {#3} + } + { } } - } - { - \cs_new_protected:Npn \@@_gset_overflow_test:nw #1 + \cs_if_exist:NTF \tex_ifabsnum:D { - \if_int_compare:w \int_abs:n {#1} > \c_max_dim - \exp_after:wN \@@_gset_overflow:NNnn - \fi: + \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 + { + \msg_error:nnxxxx { kernel } { overflow } + { \token_to_str:N #2 } {#3} {#4} { \@@_signed_max_dim:n {#4} } + #1 #2 {#3} { \@@_signed_max_dim:n {#4} } } - } -\cs_new_protected:Npn \@@_gset_overflow:NNnn #1#2#3#4 - { - \msg_error:nnxxxx { kernel } { overflow } - { \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} @@ -352,16 +760,16 @@ % 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 } + \cs_new_protected:Npn \intarray_gzero:N #1 { - \int_incr:N \l_@@_loop_int - \@@_entry:w \l_@@_loop_int #1 \c_zero_dim + \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 + } } - } -\cs_generate_variant:Nn \intarray_gzero:N { c } + \cs_generate_variant:Nn \intarray_gzero:N { c } % \end{macrocode} % \end{macro} % @@ -372,21 +780,21 @@ % \cs{int_eval:n}, namely its argument must be a \TeX{} integer % suitable for \cs{int_value:w}. % \begin{macrocode} -\cs_new:Npn \__kernel_intarray_item:Nn #1#2 - { \int_value:w \@@_entry:w #2 #1 } -\cs_new:Npn \intarray_item:Nn #1#2 - { - \exp_after:wN \@@_item:Nw - \exp_after:wN #1 - \int_value:w \int_eval:n {#2} ; - } -\cs_generate_variant:Nn \intarray_item:Nn { c } -\cs_new:Npn \@@_item:Nw #1#2 ; - { - \@@_bounds:NNnTF \msg_expandable_error:nnfff #1 {#2} - { \__kernel_intarray_item:Nn #1 {#2} } - { 0 } - } + \cs_new:Npn \__kernel_intarray_item:Nn #1#2 + { \int_value:w \@@_entry:w #2 #1 } + \cs_new:Npn \intarray_item:Nn #1#2 + { + \exp_after:wN \@@_item:Nw + \exp_after:wN #1 + \int_value:w \int_eval:n {#2} ; + } + \cs_generate_variant:Nn \intarray_item:Nn { c } + \cs_new:Npn \@@_item:Nw #1#2 ; + { + \@@_bounds:NNnTF \msg_expandable_error:nnfff #1 {#2} + { \__kernel_intarray_item:Nn #1 {#2} } + { 0 } + } % \end{macrocode} % \end{macro} % \end{macro} @@ -394,13 +802,13 @@ % \begin{macro}{\intarray_rand_item:N, \intarray_rand_item:c} % 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 } } } -\cs_generate_variant:Nn \intarray_rand_item:N { c } + \cs_new:Npn \intarray_rand_item:N #1 + { \intarray_item:Nn #1 { \int_rand:n { \intarray_count:N #1 } } } + \cs_generate_variant:Nn \intarray_rand_item:N { c } % \end{macrocode} % \end{macro} % -% \subsection{Working with contents of integer arrays} +% \subsubsection{Working with contents of integer arrays} % % \begin{macro}{\intarray_const_from_clist:Nn, \intarray_const_from_clist:cn} % \begin{macro}{\@@_const_from_clist:nN} @@ -413,21 +821,21 @@ % 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} -\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_generate_variant:Nn \intarray_const_from_clist:Nn { c } -\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} - } + \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_generate_variant:Nn \intarray_const_from_clist:Nn { c } + \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} % \end{macro} @@ -438,25 +846,25 @@ % 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_generate_variant:Nn \intarray_to_clist:N { c } -\cs_new:Npn \@@_to_clist:Nn #1#2 - { - \int_compare:nNnF { \intarray_count:N #1 } = \c_zero_int + \cs_new:Npn \intarray_to_clist:N #1 { \@@_to_clist:Nn #1 { , } } + \cs_generate_variant:Nn \intarray_to_clist:N { c } + \cs_new:Npn \@@_to_clist:Nn #1#2 { - \exp_last_unbraced:Nf \use_none:n - { \@@_to_clist:w 1 ; #1 {#2} \prg_break_point: } + \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} } - } -\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} % \end{macro} @@ -464,48 +872,54 @@ % \begin{macro}[rEXP]{\__kernel_intarray_range_to_clist:Nnn, \@@_range_to_clist:ww} % Loop through part of the array. % \begin{macrocode} -\cs_new:Npn \__kernel_intarray_range_to_clist:Nnn #1#2#3 - { - \exp_last_unbraced:Nf \use_none:n + \cs_new:Npn \__kernel_intarray_range_to_clist:Nnn #1#2#3 { + \exp_last_unbraced:Nf \use_none:n + { + \exp_after:wN \@@_range_to_clist:ww + \int_value:w \int_eval:w #2 \exp_after:wN ; + \int_value:w \int_eval:w #3 ; + #1 \prg_break_point: + } + } + \cs_new:Npn \@@_range_to_clist:ww #1 ; #2 ; #3 + { + \if_int_compare:w #1 > #2 \exp_stop_f: + \prg_break:n + \fi: + , \__kernel_intarray_item:Nn #3 {#1} \exp_after:wN \@@_range_to_clist:ww - \int_value:w \int_eval:w #2 \exp_after:wN ; - \int_value:w \int_eval:w #3 ; - #1 \prg_break_point: + \int_value:w \int_eval:w #1 + \c_one_int ; #2 ; #3 } - } -\cs_new:Npn \@@_range_to_clist:ww #1 ; #2 ; #3 - { - \if_int_compare:w #1 > #2 \exp_stop_f: - \prg_break:n - \fi: - , \__kernel_intarray_item:Nn #3 {#1} - \exp_after:wN \@@_range_to_clist:ww - \int_value:w \int_eval:w #1 + \c_one_int ; #2 ; #3 - } % \end{macrocode} % \end{macro} % % \begin{macro}{\__kernel_intarray_gset_range_from_clist:Nnn, \@@_gset_range:Nw} % Loop through part of the array. % \begin{macrocode} -\cs_new_protected:Npn \__kernel_intarray_gset_range_from_clist:Nnn #1#2#3 - { - \int_set:Nn \l_@@_loop_int {#2} - \@@_gset_range:Nw #1 #3 , , \prg_break_point: - } -\cs_new_protected:Npn \@@_gset_range:Nw #1 #2 , - { - \if_catcode:w \scan_stop: \tl_to_str:n {#2} \scan_stop: - \prg_break:n - \fi: - \__kernel_intarray_gset:Nnn #1 \l_@@_loop_int {#2} - \int_incr:N \l_@@_loop_int - \@@_gset_range:Nw #1 - } + \cs_new_protected:Npn \__kernel_intarray_gset_range_from_clist:Nnn #1#2#3 + { + \int_set:Nn \l_@@_loop_int {#2} + \@@_gset_range:Nw #1 #3 , , \prg_break_point: + } + \cs_new_protected:Npn \@@_gset_range:Nw #1 #2 , + { + \if_catcode:w \scan_stop: \tl_to_str:n {#2} \scan_stop: + \prg_break:n + \fi: + \__kernel_intarray_gset:Nnn #1 \l_@@_loop_int {#2} + \int_incr:N \l_@@_loop_int + \@@_gset_range:Nw #1 + } % \end{macrocode} % \end{macro} % +% \begin{macrocode} + } +% \end{macrocode} +% +% \subsection{Common parts} +% % \begin{macro}{\intarray_show:N, \intarray_show:c, \intarray_log:N, \intarray_log:c} % Convert the list to a comma list (with spaces after each comma) % \begin{macrocode} @@ -527,7 +941,7 @@ % \end{macrocode} % \end{macro} % -% \subsection{Random arrays} +% \subsubsection{Random arrays} % % \begin{macro}{\intarray_gset_rand:Nn, \intarray_gset_rand:cn} % \begin{macro}{\intarray_gset_rand:Nnn, \intarray_gset_rand:cnn} @@ -624,6 +1038,7 @@ % \end{macro} % % \begin{macrocode} +%</tex> %</package> % \end{macrocode} % |