[latex3-commits] [git/LaTeX3-latex3-latex3] master: Speed up \exp_args functions used in variants (957120b58)
Joseph Wright
joseph.wright at morningstar2.co.uk
Thu Sep 26 01:28:56 CEST 2019
Repository : https://github.com/latex3/latex3
On branch : master
Link : https://github.com/latex3/latex3/commit/957120b584e58201e83134e798942fe622009740
>---------------------------------------------------------------
commit 957120b584e58201e83134e798942fe622009740
Author: Bruno Le Floch <bruno at le-floch.fr>
Date: Sun Feb 10 17:11:50 2019 +0100
Speed up \exp_args functions used in variants
>---------------------------------------------------------------
957120b584e58201e83134e798942fe622009740
l3kernel/l3expan.dtx | 151 ++++++++++++++++-----
l3kernel/testfiles/m3expan001.tlg | 2 +-
.../{m3expan002.tlg => m3expan002.luatex.tlg} | 4 +-
l3kernel/testfiles/m3expan002.tlg | 4 +-
4 files changed, 119 insertions(+), 42 deletions(-)
diff --git a/l3kernel/l3expan.dtx b/l3kernel/l3expan.dtx
index af5d013fa..9b5bb6687 100644
--- a/l3kernel/l3expan.dtx
+++ b/l3kernel/l3expan.dtx
@@ -1128,7 +1128,7 @@
\exp_after:wN { \exp:w \@@_eval_register:N #3 }
{#1} {#2}
}
-\cs_new:Npn \::v # 1\::: #2#3
+\cs_new:Npn \::v #1 \::: #2#3
{
\exp_after:wN \@@_arg_next:nnn
\exp_after:wN { \exp:w \@@_eval_register:c {#3} }
@@ -2597,9 +2597,9 @@
% \begin{macrocode}
\cs_new:Npn \@@_generate_variant_same:N #1
{
- \if:w N #1 N \else:
- \if:w p #1 p \else:
- n
+ \if:w N #1 #1 \else:
+ \if:w p #1 #1 \else:
+ \token_to_str:N n
\if:w n #1 \else:
\@@_generate_variant_loop_special:NNwNNnn #1#1
\fi:
@@ -2633,38 +2633,127 @@
% \end{macro}
%
% \begin{macro}{\@@_generate_internal_variant:n}
-% \begin{macro}{\@@_generate_internal_variant:wwnw}
% \begin{macro}[rEXP]{\@@_generate_internal_variant_loop:n}
-% Test if |\exp_args:N #1| is already defined and if not define it via
-% the |\::| commands using the chars in |#1|. If |#1| contains an |x|
-% (this is the place where having converted the original comma-list
-% argument to a string is very important), the result should be
-% protected, and the next variant to be defined using that internal
-% variant should be protected.
+% First test for the presence of |x| (this is where working with
+% strings makes our lives easier), as the result should be protected,
+% and the next variant to be defined using that internal variant
+% should be protected (done by setting \cs{@@_tmp:w}). Then call
+% \cs{@@_generate_internal_variant:NNn} with arguments
+% \cs{cs_new_protected:cpn} \cs{use:x} (for protected) or
+% \cs{cs_new:cpn} \cs{use:e} (expandable) and the signature. If |p|
+% appears in the signature, or if the function to be defined is
+% expandable and the primitive \tn{expanded} is not available, call
+% some fall-back code that just puts the appropriate |\::| commands.
+% Otherwise, call \cs{@@_generate_internal_one_go:NNn} to construct
+% the \cs[no-index]{exp_args:N\dots} function as a macro taking up to
+% $9$~arguments and expanding them using \cs{use:x} or \cs{use:e}.
% \begin{macrocode}
\cs_new_protected:Npx \@@_generate_internal_variant:n #1
{
- \exp_not:N \@@_generate_internal_variant:wwnNwnn
+ \exp_not:N \@@_generate_internal_variant:wwnNwn
#1 \exp_not:N \q_mark
{ \cs_set_eq:NN \exp_not:N \@@_tmp:w \cs_new_protected:Npx }
- \cs_new_protected:cpx
+ \cs_new_protected:cpn
+ \use:x
\token_to_str:N x \exp_not:N \q_mark
{ }
- \cs_new:cpx
+ \cs_new:cpn
+ \exp_not:N \use:e
\exp_not:N \q_stop
- { exp_args:N #1 }
- {
- \exp_not:N \@@_generate_internal_variant_loop:n #1
- { : \exp_not:N \use_i:nn }
- }
+ {#1}
}
\exp_last_unbraced:NNNNo
- \cs_new_protected:Npn \@@_generate_internal_variant:wwnNwnn #1
- { \token_to_str:N x } #2 \q_mark #3#4#5 \q_stop #6#7
+ \cs_new_protected:Npn \@@_generate_internal_variant:wwnNwn #1
+ { \token_to_str:N x } #2 \q_mark #3#4#5#6 \q_stop #7
{
#3
- \cs_if_free:cT {#6} { #4 {#6} {#7} }
+ \cs_if_free:cT { exp_args:N #7 }
+ { \@@_generate_internal_variant:NNn #4 #5 {#7} }
}
+\cs_set_protected:Npn \@@_tmp:w #1
+ {
+ \cs_new_protected:Npn \@@_generate_internal_variant:NNn ##1##2##3
+ {
+ \@@_generate_internal_test:Nw ##2 ##3
+ \q_mark
+ {
+ \use:x
+ {
+ ##1 { exp_args:N ##3 }
+ { \@@_generate_internal_variant_loop:n ##3 { : \use_i:nn } }
+ }
+ }
+ #1
+ \q_mark
+ { \exp_not:n { \@@_generate_internal_one_go:NNn ##1 ##2 {##3} } }
+ \q_stop
+ }
+ \cs_new_protected:Npn \@@_generate_internal_test_aux:w
+ ##1 #1 ##2 \q_mark ##3 ##4 \q_stop {##3}
+ \cs_if_exist:NTF \tex_expanded:D
+ {
+ \cs_new_eq:NN \@@_generate_internal_test:Nw
+ \@@_generate_internal_test_aux:w
+ }
+ {
+ \cs_new_protected:Npn \@@_generate_internal_test:Nw ##1
+ {
+ \if_meaning:w \use:e ##1
+ \exp_after:wN \@@_generate_internal_test_aux:w
+ \exp_after:wN #1
+ \else:
+ \exp_after:wN \@@_generate_internal_test_aux:w
+ \fi:
+ }
+ }
+ }
+\exp_args:No \@@_tmp:w { \token_to_str:N p }
+\cs_new_protected:Npn \@@_generate_internal_one_go:NNn #1#2#3
+ {
+ \@@_generate_internal_loop:nwnnw
+ { \exp_not:N ##1 } 1 . { } { }
+ #3 { ? \@@_generate_internal_end:w } X ;
+ 23456789 { ? \@@_generate_internal_long:w } ;
+ #1 #2 {#3}
+ }
+\cs_new_protected:Npn \@@_generate_internal_loop:nwnnw #1#2 . #3#4#5#6 ; #7
+ {
+ \use_none:n #5
+ \use_none:n #7
+ \if_case:w
+ \if:w N #5 1 ~ \fi:
+ \if:w c #5 2 ~ \fi:
+ \if:w x #5 3 ~ \fi:
+ 4 ~
+ \or: \exp_after:wN \use_i:nnnn
+ \or: \exp_after:wN \use_ii:nnnn
+ \or: \exp_after:wN \use_iii:nnnn
+ \or: \exp_after:wN \use_iv:nnnn
+ \fi:
+ { \@@_generate_internal_loop:nwnnw { \exp_not:N ## #7 } }
+ { \@@_generate_internal_loop:nwnnw { \exp_not:c { ## #7 } } }
+ { \@@_generate_internal_loop:nwnnw { { ## #7 } } }
+ {
+ \exp_args:No \@@_generate_internal_loop:nwnnw
+ {
+ \exp_after:wN
+ { \exp:w \exp_args:Nc \exp_end: { exp_not:#5 } { ## #7 } }
+ }
+ }
+ #7 .
+ { #3 #1 } { #4 ## #2 }
+ #6 ;
+ }
+\cs_new_protected:Npn \@@_generate_internal_end:w #1 . #2#3#4 ; #5 ; #6#7#8
+ { #6 { exp_args:N #8 } #3 { #7 {#2} } }
+\cs_new_protected:Npn \@@_generate_internal_long:w #1 N #2#3 . #4#5#6#
+ {
+ \exp_args:Nx \@@_generate_internal_long:nnnNNn
+ { \@@_generate_internal_variant_loop:n #2 #6 { : \use_i:nn } }
+ {#4} {#5}
+ }
+\cs_new:Npn \@@_generate_internal_long:nnnNNn #1#2#3#4 ; ; #5#6#7
+ { #5 { exp_args:N #7 } #3 { #6 { \exp_not:n {#1} {#2} } } }
% \end{macrocode}
% This command grabs char by char outputting |\::#1| (not expanded
% further). We avoid tests by putting a trailing |: \use_i:nn|, which
@@ -2680,7 +2769,6 @@
% \end{macrocode}
% \end{macro}
% \end{macro}
-% \end{macro}
%
% \begin{macro}
% {
@@ -2749,9 +2837,7 @@
% that are defined in later modules. It also does not need to be fast
% so use inline mappings. For each requested variant we check that
% there are no characters besides |NnpcofVvx|, in particular that
-% there are no spaces. Then we loop through the variant specifier and
-% convert each letter to \cs[no-index]{::\meta{variant letter}}, with a
-% trailing \cs{:::}.
+% there are no spaces. Then we just call the internal function.
% \begin{macrocode}
\cs_new_protected:Npn \exp_args_generate:n #1
{
@@ -2763,21 +2849,12 @@
{
\__kernel_msg_error:nnnn { kernel } { invalid-exp-args }
{####1} {##1}
- \str_map_break:n { \use_none:nnnn }
+ \str_map_break:n { \use_none:nn }
}
}
- \exp_args:Nc \@@_args_generate:Nn { exp_args:N ##1 } {##1}
- }
- }
-\cs_new_protected:Npn \@@_args_generate:Nn #1#2
- {
- \cs_if_exist:NF #1
- {
- \str_if_in:nnTF {#2} { x } { \cs_new_protected:Npx } { \cs_new:Npx }
- #1 { \tl_map_function:nN { #2 : } \@@_args_generate:n }
+ \@@_generate_internal_variant:n {##1}
}
}
-\cs_new:Npn \@@_args_generate:n #1 { \exp_not:c { :: #1 } }
% \end{macrocode}
% \end{macro}
% \end{macro}
diff --git a/l3kernel/testfiles/m3expan001.tlg b/l3kernel/testfiles/m3expan001.tlg
index 9a498cc00..9ccd768f2 100644
--- a/l3kernel/testfiles/m3expan001.tlg
+++ b/l3kernel/testfiles/m3expan001.tlg
@@ -49,7 +49,7 @@ TEST 1: protection
\protected\long macro:->\exp_args:Nfx \foo:nn
\protected\long macro:->\exp_args:Nxf \foo:nn
\protected\long macro:->\exp_args:NfvVonx \bar:nnnnnn
-\protected\long macro:->\::f \::v \::V \::o \::n \::x \:::
+\protected\long macro:#1#2#3#4#5#6#7->\use:x {\exp_not:N #1{\exp_not:f {#2}}{\exp_not:v {#3}}{\exp_not:V {#4}}{\exp_not:o {#5}}{\exp_not:n {#6}}{#7}}
============================================================
============================================================
TEST 2: expansion
diff --git a/l3kernel/testfiles/m3expan002.tlg b/l3kernel/testfiles/m3expan002.luatex.tlg
similarity index 94%
copy from l3kernel/testfiles/m3expan002.tlg
copy to l3kernel/testfiles/m3expan002.luatex.tlg
index 315ae2068..f8579c329 100644
--- a/l3kernel/testfiles/m3expan002.tlg
+++ b/l3kernel/testfiles/m3expan002.luatex.tlg
@@ -142,6 +142,6 @@ LaTeX has been asked to create an \exp_args:N... function with signature
'Nabc' but 'a' is not a valid argument specifier.
Defining \exp_args:Nfoo on line ...
Defining \exp_args:Nfox on line ...
-undefined,\long macro:->\::f \::o \::o \::: ,\protected\long macro:->\::f \::o \::x \:::
-\long macro:->\::f \::o \::o \::: ,\protected\long macro:->\::f \::o \::x \:::
+undefined,\long macro:#1#2#3#4->\use:e {\exp_not:N #1{\exp_not:f {#2}}{\exp_not:o {#3}}{\exp_not:o {#4}}},\protected\long macro:#1#2#3#4->\use:x {\exp_not:N #1{\exp_not:f {#2}}{\exp_not:o {#3}}{#4}}
+\long macro:#1#2#3#4->\use:e {\exp_not:N #1{\exp_not:f {#2}}{\exp_not:o {#3}}{\exp_not:o {#4}}},\protected\long macro:#1#2#3#4->\use:x {\exp_not:N #1{\exp_not:f {#2}}{\exp_not:o {#3}}{#4}}
============================================================
diff --git a/l3kernel/testfiles/m3expan002.tlg b/l3kernel/testfiles/m3expan002.tlg
index 315ae2068..8a311211c 100644
--- a/l3kernel/testfiles/m3expan002.tlg
+++ b/l3kernel/testfiles/m3expan002.tlg
@@ -142,6 +142,6 @@ LaTeX has been asked to create an \exp_args:N... function with signature
'Nabc' but 'a' is not a valid argument specifier.
Defining \exp_args:Nfoo on line ...
Defining \exp_args:Nfox on line ...
-undefined,\long macro:->\::f \::o \::o \::: ,\protected\long macro:->\::f \::o \::x \:::
-\long macro:->\::f \::o \::o \::: ,\protected\long macro:->\::f \::o \::x \:::
+undefined,\long macro:->\::f \::o \::o \::: ,\protected\long macro:#1#2#3#4->\use:x {\exp_not:N #1{\exp_not:f {#2}}{\exp_not:o {#3}}{#4}}
+\long macro:->\::f \::o \::o \::: ,\protected\long macro:#1#2#3#4->\use:x {\exp_not:N #1{\exp_not:f {#2}}{\exp_not:o {#3}}{#4}}
============================================================
More information about the latex3-commits
mailing list