[latex3-commits] [git/LaTeX3-latex3-latex3] main: Speed up l3clist N-type mappings (582270fe3)

Bruno Le Floch blflatex at gmail.com
Sat May 15 02:15:27 CEST 2021


Repository : https://github.com/latex3/latex3
On branch  : main
Link       : https://github.com/latex3/latex3/commit/582270fe3b0c3c83951389d447e274f36eab7232

>---------------------------------------------------------------

commit 582270fe3b0c3c83951389d447e274f36eab7232
Author: Bruno Le Floch <blflatex at gmail.com>
Date:   Sat May 15 02:15:27 2021 +0200

    Speed up l3clist N-type mappings
    
    The speed up is around 2-8 times (largest for larger comma lists)


>---------------------------------------------------------------

582270fe3b0c3c83951389d447e274f36eab7232
 l3kernel/CHANGELOG.md |  2 +-
 l3kernel/l3clist.dtx  | 96 ++++++++++++++++++++++++++++-----------------------
 2 files changed, 54 insertions(+), 44 deletions(-)

diff --git a/l3kernel/CHANGELOG.md b/l3kernel/CHANGELOG.md
index 44677a176..029a2291d 100644
--- a/l3kernel/CHANGELOG.md
+++ b/l3kernel/CHANGELOG.md
@@ -20,7 +20,7 @@ this project uses date-based 'snapshot' version identifiers.
 - Checking brace balance in all regex functions (issue #377)
 
 ### Changed
-- Speed up mapping functions in l3tl, l3seq, l3prop
+- Speed up mapping functions in l3clist, l3prop, l3seq, l3tl
 
 ## [2021-05-11]
 
diff --git a/l3kernel/l3clist.dtx b/l3kernel/l3clist.dtx
index 16142c3f1..4b3684308 100644
--- a/l3kernel/l3clist.dtx
+++ b/l3kernel/l3clist.dtx
@@ -1654,28 +1654,38 @@
 %
 % \begin{macro}{\clist_map_function:NN, \clist_map_function:cN}
 % \UnitTested
-% \begin{macro}{\@@_map_function:nw}
+% \begin{macro}{\@@_map_function:Nw, \@@_map_function_end:w}
 %   If the variable is empty, the mapping is skipped (otherwise,
 %   that comma-list would be seen as consisting of one empty item).
-%   Then loop over the comma-list, grabbing one comma-delimited
-%   item at a time. The end is marked by \cs{q_@@_recursion_tail}.
-%   The auxiliary function \cs{@@_map_function:nw} is also used
-%   in \cs{clist_map_inline:Nn}.
+%   Then loop over the comma-list, grabbing eight comma-delimited items
+%   at a time. The end is marked by \cs{s_@@_stop}, which may not appear
+%   in any of the items.  Once the last group of eight items has been
+%   reached, we go through them more slowly using
+%   \cs{@@_map_function_end:w}.  The auxiliary function
+%   \cs{@@_map_function:Nw} is also used in some other clist mappings.
 %    \begin{macrocode}
 \cs_new:Npn \clist_map_function:NN #1#2
   {
     \clist_if_empty:NF #1
       {
-        \exp_last_unbraced:NNo \@@_map_function:nw #2 #1
-          , \q_@@_recursion_tail ,
+        \exp_after:wN \@@_map_function:Nw \exp_after:wN #2 #1 ,
+          \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop ,
+          \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop ,
         \prg_break_point:Nn \clist_map_break: { }
       }
   }
-\cs_new:Npn \@@_map_function:nw #1#2 ,
+\cs_new:Npn \@@_map_function:Nw #1 #2, #3, #4, #5, #6, #7, #8, #9,
   {
-    \@@_if_recursion_tail_break:nN {#2} \clist_map_break:
+    \@@_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:Nw #1
+  }
+\cs_new:Npn \@@_map_function_end:w \s_@@_stop #1#2
+  {
+    \@@_use_none_delimit_by_s_stop:w #2 \clist_map_break: \s_@@_stop
     #1 {#2}
-    \@@_map_function:nw {#1}
+    \@@_map_function_end:w \s_@@_stop
   }
 \cs_generate_variant:Nn \clist_map_function:NN { c }
 %    \end{macrocode}
@@ -1736,9 +1746,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_last_unbraced:Nco \@@_map_function:nw
+        \exp_last_unbraced:Nco \@@_map_function:Nw
           { @@_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 \clist_map_break:
           { \int_gdecr:N \g__kernel_prg_map_int }
       }
@@ -1756,59 +1768,57 @@
 % \begin{macro}{\clist_map_variable:NNn, \clist_map_variable:cNn}
 % \UnitTested
 % \begin{macro}{\clist_map_variable:nNn}
-% \begin{macro}{\@@_map_variable:Nnw}
-%   As for other comma-list mappings, filter out the case of
-%   an empty list. Same approach as \cs{clist_map_function:Nn},
-%   additionally we store each item in the given variable.
-%   As for inline mappings, space trimming for the \texttt{n}
-%   variant is done by storing the comma list in a variable.
-%   The quark test is done before assigning the item to the variable:
-%   this avoids storing a quark which the user wouldn't expect.
-%   The strange \cs{use:n} avoids unlikely problems when |#2| would
-%   contain \cs{q_@@_recursion_stop}.
+% \begin{macro}{\@@_map_variable:Nnn}
+%   The |N|-type version is a straightforward application of
+%   \cs{clist_map_tokens:Nn}, calling \cs{@@_map_variable:Nnn} for each
+%   item to assign the variable and run the user's code.  The |n|-type
+%   version is \emph{not} implemented in terms of the |n|-type function
+%   \cs{clist_map_tokens:Nn}, because here we are allowed to clean up
+%   the |n|-type comma list non-expandably.
 %    \begin{macrocode}
 \cs_new_protected:Npn \clist_map_variable:NNn #1#2#3
-  {
-    \clist_if_empty:NF #1
-      {
-        \exp_args:Nno \use:nn
-          { \@@_map_variable:Nnw #2 {#3} }
-          #1
-          , \q_@@_recursion_tail , \q_@@_recursion_stop
-        \prg_break_point:Nn \clist_map_break: { }
-      }
-  }
+  { \clist_map_tokens:Nn #1 { \@@_map_variable:Nnn #2 {#3} } }
+\cs_generate_variant:Nn \clist_map_variable:NNn { c }
+\cs_new_protected:Npn \@@_map_variable:Nnn #1#2#3
+  { \tl_set:Nn #1 {#3} #2 }
 \cs_new_protected:Npn \clist_map_variable:nNn #1
   {
     \clist_set:Nn \l_@@_internal_clist {#1}
     \clist_map_variable:NNn \l_@@_internal_clist
   }
-\cs_new_protected:Npn \@@_map_variable:Nnw #1#2#3,
-  {
-    \@@_if_recursion_tail_stop:n {#3}
-    \tl_set:Nn #1 {#3}
-    \use:n {#2}
-    \@@_map_variable:Nnw #1 {#2}
-  }
-\cs_generate_variant:Nn \clist_map_variable:NNn { c }
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
 % \end{macro}
 %
 % \begin{macro}{\clist_map_tokens:Nn, \clist_map_tokens:cn}
-% \begin{macro}{\@@_map_tokens:nw}
+% \begin{macro}{\@@_map_tokens:nw, \@@_map_tokens_end:w}
 %   Essentially a copy of \cs{clist_map_function:NN} with braces added.
 %    \begin{macrocode}
 \cs_new:Npn \clist_map_tokens:Nn #1#2
   {
     \clist_if_empty:NF #1
       {
-        \exp_last_unbraced:Nno \@@_map_function:nw {#2} #1
-          , \q_@@_recursion_tail ,
+        \exp_last_unbraced:Nno \@@_map_tokens:nw {#2} #1 ,
+          \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop ,
+          \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop ,
         \prg_break_point:Nn \clist_map_break: { }
       }
   }
+\cs_new:Npn \@@_map_tokens:nw #1 #2, #3, #4, #5, #6, #7, #8, #9,
+  {
+    \@@_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:nw {#1}
+  }
+\cs_new:Npn \@@_map_tokens_end:w \s_@@_stop \use:n #1#2
+  {
+    \@@_use_none_delimit_by_s_stop:w #2 \clist_map_break: \s_@@_stop
+    #1 {#2}
+    \@@_map_tokens_end:w \s_@@_stop
+  }
 \cs_generate_variant:Nn \clist_map_tokens:Nn { c }
 %    \end{macrocode}
 % \end{macro}





More information about the latex3-commits mailing list.