[latex3-commits] [git/LaTeX3-latex3-latex3] main: Speed up all tl_map functions 2-8 fold (f31d4d77f)
Bruno Le Floch
blflatex at gmail.com
Fri May 14 23:52:40 CEST 2021
Repository : https://github.com/latex3/latex3
On branch : main
Link : https://github.com/latex3/latex3/commit/f31d4d77fc859841589870ed773d105b4975aa4c
>---------------------------------------------------------------
commit f31d4d77fc859841589870ed773d105b4975aa4c
Author: Bruno Le Floch <blflatex at gmail.com>
Date: Fri May 14 23:50:40 2021 +0200
Speed up all tl_map functions 2-8 fold
>---------------------------------------------------------------
f31d4d77fc859841589870ed773d105b4975aa4c
l3kernel/CHANGELOG.md | 3 ++
l3kernel/l3tl.dtx | 105 ++++++++++++++++++++++++++++++--------------------
2 files changed, 66 insertions(+), 42 deletions(-)
diff --git a/l3kernel/CHANGELOG.md b/l3kernel/CHANGELOG.md
index eb1cc9499..bae75dd08 100644
--- a/l3kernel/CHANGELOG.md
+++ b/l3kernel/CHANGELOG.md
@@ -19,6 +19,9 @@ this project uses date-based 'snapshot' version identifiers.
### Fixed
- Checking brace balance in all regex functions (issue #377)
+### Changed
+- Speed up mapping functions in l3tl
+
## [2021-05-11]
### Added
diff --git a/l3kernel/l3tl.dtx b/l3kernel/l3tl.dtx
index 4967c19a6..68b4e46c4 100644
--- a/l3kernel/l3tl.dtx
+++ b/l3kernel/l3tl.dtx
@@ -2465,37 +2465,56 @@
%
% \subsection{Mapping over token lists}
%
-% \begin{macro}{\tl_map_function:nN}
-% \begin{macro}{\tl_map_function:NN, \tl_map_function:cN}
-% \begin{macro}{\@@_map_function:Nn}
-% Expandable loop macro for token lists. These have the advantage of not
-% needing to test if the argument is empty, because if it is, the stop
-% marker is read immediately and the loop terminated.
+% \begin{macro}
+% {
+% \tl_map_function:nN, \tl_map_function:NN, \tl_map_function:cN,
+% \@@_map_function:Nnnnnnnnn, \@@_map_function_end:w,
+% \@@_use_none_delimit_by_s_stop:w
+% }
+% Expandable loop macro for token lists. We use the internal scan
+% mark \cs{s_@@_stop} (defined later), which is not allowed to show up
+% in the token list |#1| since it is internal to \pkg{l3tl}. This
+% allows us a very fast test of whether some \meta{item} is the
+% end-marker \cs{s_@@_stop}, namely call
+% \cs{@@_use_none_delimit_by_s_stop:w} \meta{item} \meta{function}
+% \cs{s_@@_stop}, which calls \meta{function} if the \meta{item} is
+% the end-marker. To speed up the loop even more, only test one out
+% of eight items, and once we hit one of the eight end-markers,
+% go more slowly through the last few items of the list using
+% \cs{@@_map_function_end:w}.
% \begin{macrocode}
\cs_new:Npn \tl_map_function:nN #1#2
{
- \@@_map_function:Nn #2 #1
- \q_@@_recursion_tail
+ \@@_map_function:Nnnnnnnnn #2 #1
+ \s_@@_stop \s_@@_stop \s_@@_stop \s_@@_stop
+ \s_@@_stop \s_@@_stop \s_@@_stop \s_@@_stop
\prg_break_point:Nn \tl_map_break: { }
}
\cs_new:Npn \tl_map_function:NN
{ \exp_args:No \tl_map_function:nN }
-\cs_new:Npn \@@_map_function:Nn #1#2
+\cs_generate_variant:Nn \tl_map_function:NN { c }
+\cs_new:Npn \@@_map_function:Nnnnnnnnn #1#2#3#4#5#6#7#8#9
{
- \@@_if_recursion_tail_break:nN {#2} \tl_map_break:
- #1 {#2} \@@_map_function:Nn #1
+ \@@_use_none_delimit_by_s_stop:w
+ #9 \@@_map_function_end:w \s_@@_stop
+ #1 {#2} #1 {#3} #1 {#4} #1 {#5} #1 {#6} #1 {#7} #1 {#8} #1 {#9}
+ \@@_map_function:Nnnnnnnnn #1
}
-\cs_generate_variant:Nn \tl_map_function:NN { c }
+\cs_new:Npn \@@_map_function_end:w \s_@@_stop #1#2
+ {
+ \@@_use_none_delimit_by_s_stop:w #2 \tl_map_break: \s_@@_stop
+ #1 {#2}
+ \@@_map_function_end:w \s_@@_stop
+ }
+\cs_new:Npn \@@_use_none_delimit_by_s_stop:w #1 \s_@@_stop { }
% \end{macrocode}
% \end{macro}
-% \end{macro}
-% \end{macro}
%
% \begin{macro}{\tl_map_inline:nn}
% \begin{macro}{\tl_map_inline:Nn, \tl_map_inline:cn}
% The inline functions are straight forward by now. We use a little
% trick with the counter \cs{g__kernel_prg_map_int} to make
-% them nestable. We can also make use of \cs{@@_map_function:Nn}
+% them nestable. We can also make use of \cs{@@_map_function:Nnnnnnnnn}
% from before.
% \begin{macrocode}
\cs_new_protected:Npn \tl_map_inline:nn #1#2
@@ -2503,9 +2522,11 @@
\int_gincr:N \g__kernel_prg_map_int
\cs_gset_protected:cpn
{ @@_map_ \int_use:N \g__kernel_prg_map_int :w } ##1 {#2}
- \exp_args:Nc \@@_map_function:Nn
+ \exp_args:Nc \@@_map_function:Nnnnnnnnn
{ @@_map_ \int_use:N \g__kernel_prg_map_int :w }
- #1 \q_@@_recursion_tail
+ #1
+ \s_@@_stop \s_@@_stop \s_@@_stop \s_@@_stop
+ \s_@@_stop \s_@@_stop \s_@@_stop \s_@@_stop
\prg_break_point:Nn \tl_map_break:
{ \int_gdecr:N \g__kernel_prg_map_int }
}
@@ -2516,54 +2537,54 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}{\tl_map_tokens:nn}
-% \begin{macro}{\tl_map_tokens:Nn, \tl_map_tokens:cn}
-% \begin{macro}{\@@_map_tokens:nn}
+% \begin{macro}
+% {
+% \tl_map_tokens:nn, \tl_map_tokens:Nn, \tl_map_tokens:cn,
+% \@@_map_tokens:nnnnnnnnn, \@@_map_tokens_end:w
+% }
% Much like the function mapping.
% \begin{macrocode}
\cs_new:Npn \tl_map_tokens:nn #1#2
{
- \@@_map_tokens:nn {#2} #1
- \q_@@_recursion_tail
+ \@@_map_tokens:nnnnnnnnn {#2} #1
+ \s_@@_stop \s_@@_stop \s_@@_stop \s_@@_stop
+ \s_@@_stop \s_@@_stop \s_@@_stop \s_@@_stop
\prg_break_point:Nn \tl_map_break: { }
}
\cs_new:Npn \tl_map_tokens:Nn
{ \exp_args:No \tl_map_tokens:nn }
\cs_generate_variant:Nn \tl_map_tokens:Nn { c }
-\cs_new:Npn \@@_map_tokens:nn #1#2
+\cs_new:Npn \@@_map_tokens:nnnnnnnnn #1#2#3#4#5#6#7#8#9
{
- \@@_if_recursion_tail_break:nN {#2} \tl_map_break:
- \use:n {#1} {#2}
- \@@_map_tokens:nn {#1}
+ \@@_use_none_delimit_by_s_stop:w
+ #9 \@@_map_tokens_end:w \s_@@_stop
+ \use:n {#1} {#2} \use:n {#1} {#3} \use:n {#1} {#4} \use:n {#1} {#5}
+ \use:n {#1} {#6} \use:n {#1} {#7} \use:n {#1} {#8} \use:n {#1} {#9}
+ \@@_map_tokens:nnnnnnnnn {#1}
+ }
+\cs_new:Npn \@@_map_tokens_end:w \s_@@_stop \use:n #1#2
+ {
+ \@@_use_none_delimit_by_s_stop:w #2 \tl_map_break: \s_@@_stop
+ #1 {#2}
+ \@@_map_tokens_end:w \s_@@_stop
}
% \end{macrocode}
% \end{macro}
-% \end{macro}
-% \end{macro}
%
% \begin{macro}{\tl_map_variable:nNn}
% \begin{macro}{\tl_map_variable:NNn, \tl_map_variable:cNn}
% \begin{macro}{\@@_map_variable:Nnn}
-% \cs{tl_map_variable:nNn} \meta{token list} \meta{tl~var}
-% \meta{action} assigns \meta{tl~var} to each element and executes
+% \cs{tl_map_variable:nNn} \Arg{token list} \meta{tl~var}
+% \Arg{action} assigns \meta{tl~var} to each element and executes
% \meta{action}. The assignment to \meta{tl~var} is done after the
% quark test so that this variable does not get set to a quark.
% \begin{macrocode}
\cs_new_protected:Npn \tl_map_variable:nNn #1#2#3
- {
- \@@_map_variable:Nnn #2 {#3} #1
- \q_@@_recursion_tail
- \prg_break_point:Nn \tl_map_break: { }
- }
+ { \tl_map_tokens:nn {#1} { \@@_map_variable:Nnn #2 {#3} } }
+\cs_new_protected:Npn \@@_map_variable:Nnn #1#2#3
+ { \tl_set:Nn #1 {#3} #2 }
\cs_new_protected:Npn \tl_map_variable:NNn
{ \exp_args:No \tl_map_variable:nNn }
-\cs_new_protected:Npn \@@_map_variable:Nnn #1#2#3
- {
- \@@_if_recursion_tail_break:nN {#3} \tl_map_break:
- \tl_set:Nn #1 {#3}
- \use:n {#2}
- \@@_map_variable:Nnn #1 {#2}
- }
\cs_generate_variant:Nn \tl_map_variable:NNn { c }
% \end{macrocode}
% \end{macro}
More information about the latex3-commits
mailing list.