[latex3-commits] [git/latex3] sowreap: add \tl_sow:Nn / \tl_sow_reap:N & friends (377418f)

Will Robertson wspr81 at gmail.com
Thu Jan 4 15:42:18 CET 2018


Repository : https://github.com/latex3/latex3
On branch  : sowreap
Link       : https://github.com/latex3/latex3/commit/377418fde60ae7dd7cf21ad5bd9a446523d2fd35

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

commit 377418fde60ae7dd7cf21ad5bd9a446523d2fd35
Author: Will Robertson <wspr81 at gmail.com>
Date:   Thu Jan 4 22:42:18 2018 +0800

    add \tl_sow:Nn / \tl_sow_reap:N & friends
    
    this was discussed, oh, ages ago. to be discussed about whether we actually want it!!


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

377418fde60ae7dd7cf21ad5bd9a446523d2fd35
 l3kernel/l3candidates.dtx      |  163 ++++++++++++++++++++++++++++++++++++++++
 l3kernel/testfiles/m3tl015.lvt |  163 ++++++++++++++++++++++++++++++++++++++++
 l3kernel/testfiles/m3tl015.tlg |  100 ++++++++++++++++++++++++
 3 files changed, 426 insertions(+)

diff --git a/l3kernel/l3candidates.dtx b/l3kernel/l3candidates.dtx
index 851b381..c038fcb 100644
--- a/l3kernel/l3candidates.dtx
+++ b/l3kernel/l3candidates.dtx
@@ -1067,6 +1067,42 @@
 %   \end{texnote}
 % \end{function}
 %
+
+% \begin{function}[added = 2018-01-04]{\tl_sow_prepare:N,\tl_sow:Nn,\tl_sow_reap:,\tl_gsow_prepare:N,\tl_gsow:Nn,\tl_gsow_greap:}
+%   \begin{syntax}
+%     \cs{tl_sow_prepare:N} \meta{tl var} \\
+%     \cs{tl_sow:Nn} \meta{tl var} \Arg{tokens} \\
+%     \cs{tl_sow_reap:N} \meta{tl var}
+%   \end{syntax}
+% When building the contents of token list variables with multiple \cs{tl_put_right:Nn}
+% commands, performance can be poor when there are many iterations.
+% The \cs{tl_sow:Nn} and \cs{tl_sow_reap:N} commands provide a faster alternative
+% for large variable sizes at the expense of greater memory consumption and \TeX\ hash space.
+%
+% To start, `prepare' for the sowing to come:
+% \begin{verbatim}
+% \tl_sow_prepare:N \l_tmpa_tl
+% \end{verbatim}
+% This clears the token list variable and initialises internal variables.
+% Here, call \cs{tl_sow:Nn} as many times as necessary:
+% \begin{verbatim}
+% \tl_sow:Nn \l_tmpa_tl {tokens1}
+% \tl_sow:Nn \l_tmpa_tl {tokens2}
+% \tl_sow:Nn \l_tmpa_tl {tokens3}
+% \tl_sow:Nn \l_tmpa_tl {tokens4}
+% \end{verbatim}
+% At this point, the token list variable (here, \cs{l_tmpa_tl}) will be unchanged
+% from its original definition. Now `reap' the token list variable:
+% \begin{verbatim}
+% \tl_sow_reap:N \l_tmpa_tl
+% \end{verbatim}
+% This defines the token list variables as the concatenation of the tokens defined in each `sow' command.
+% To complete the example, the contents of \cs{l_tmpa_tl} are now:
+% \begin{verbatim}
+% tokens1tokens2tokens3tokens4
+% \end{verbatim}
+% \end{function}
+%
 % \section{Additions to \pkg{l3token}}
 %
 % \begin{variable}[added = 2017-08-07]{\c_catcode_active_space_tl}
@@ -4277,6 +4313,133 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \subsection{Sow/reap}
+%
+% This is a sketch of how sow/reap works:
+% \begin{verbatim}
+%   \def\l_foo_1_tl{\unexpanded{sow1}}
+%   \def\l_foo_2_tl{\unexpanded{sow2}}
+%   % ...
+%   \edef\foo{\l_foo_1_tl\l_foo_2_tl...}
+% \end{verbatim}
+% We use a variable-specific to keep track of as many sow/reap variables
+% as desired.
+%
+% Important question: after reaping, should we also zero all internal sow
+% tl variables? Would it help memory consumption in any meaningful way
+% or just slow things down a bit?
+%
+% Both local and global variantions are defined, and this is done manually
+% because there are too many different functions that need to be switched
+% between the cases.
+%
+% \begin{macro}{\__tl_sow_item:Nn,\__tl_gsow_item:Nn}
+% Helper variables for constructing \verb|c|-type arguments.
+%    \begin{macrocode}
+\cs_new:Nn \__tl_sow_item:Nn  { l___sow___ \token_to_str:N #1 ___ #2 ___tl }
+\cs_new:Nn \__tl_gsow_item:Nn { g___sow___ \token_to_str:N #1 ___ #2 ___tl }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\__tl_sow_int:N,\__tl_gsow_int:N}
+% Helper variables for constructing \verb|c|-type arguments.
+%    \begin{macrocode}
+\cs_new:Nn \__tl_sow_int:N  { l___sow___ \token_to_str:N #1 ___int }
+\cs_new:Nn \__tl_gsow_int:N { g___sow___ \token_to_str:N #1 ___int }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\tl_sow_prepare:N,\tl_gsow_prepare:N}
+%    \begin{macrocode}
+\cs_new:Nn \tl_sow_prepare:N
+  {
+    \tl_clear:N #1
+    \int_zero_new:c { \__tl_sow_int:N #1 }
+  }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\cs_new:Nn \tl_gsow_prepare:N
+  {
+    \tl_gclear:N #1
+    \int_gzero_new:c { \__tl_gsow_int:N #1 }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\tl_sow:Nn,\tl_gsow:Nn}
+%    \begin{macrocode}
+\cs_new:Nn \tl_sow:Nn
+  {
+    \int_incr:c { \__tl_sow_int:N #1 }
+    \tl_clear_new:c
+      {
+        \__tl_sow_item:Nn #1
+          { \int_use:c { \__tl_sow_int:N #1 } }
+      }
+    \tl_set:cn
+      {
+        \__tl_sow_item:Nn #1
+          { \int_use:c { \__tl_sow_int:N #1 } }
+      }
+      { #2 }
+  }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\cs_new:Nn \tl_gsow:Nn
+  {
+    \int_gincr:c { \__tl_gsow_int:N #1 }
+    \tl_gclear_new:c
+      {
+        \__tl_gsow_item:Nn #1
+          { \int_use:c { \__tl_gsow_int:N #1 } }
+      }
+    \tl_gset:cn
+      {
+        \__tl_gsow_item:Nn #1
+          { \int_use:c { \__tl_gsow_int:N #1 } }
+      }
+      { #2 }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\tl_sow_reap:N,\tl_gsow_greap:N}
+%    \begin{macrocode}
+\cs_new:Nn \tl_sow_reap:N
+  {
+    \cs_set:Npn \__tl_sow_tmp:n ##1
+      {
+        \exp_not:v { \__tl_sow_item:Nn #1 {##1} }
+      }
+    \tl_set:Nx #1
+      {
+        \int_step_function:nnnN {1} {1}
+          { \int_use:c { \__tl_sow_int:N #1 } }
+          \__tl_sow_tmp:n
+      }
+
+  }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\cs_new:Nn \tl_gsow_greap:N
+  {
+    \cs_set:Npn \__tl_sow_tmp:n ##1
+      {
+        \exp_not:v { \__tl_gsow_item:Nn #1 {##1} }
+      }
+    \tl_gset:Nx #1
+      {
+        \int_step_function:nnnN {1} {1}
+          { \int_use:c { \__tl_gsow_int:N #1 } }
+          \__tl_sow_tmp:n
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
 % \subsection{Additions to \pkg{l3token}}
 %
 % \begin{variable}{\c_catcode_active_space_tl}
diff --git a/l3kernel/testfiles/m3tl015.lvt b/l3kernel/testfiles/m3tl015.lvt
new file mode 100644
index 0000000..a1882f9
--- /dev/null
+++ b/l3kernel/testfiles/m3tl015.lvt
@@ -0,0 +1,163 @@
+%
+% Copyright (C) 2012,2015 The LaTeX3 Project
+%
+\documentclass{minimal}
+\input{regression-test}
+\RequirePackage[check-declarations,log-functions]{expl3}
+
+\begin{document}
+
+\START
+\AUTHOR{Will Robertson}
+\ExplSyntaxOn
+
+\tl_new:N \l_A_tl  \tl_set:Nn \l_A_tl { Abc }
+\tl_new:N \l_B_tl  \tl_set:Nn \l_B_tl { Bcd }
+\tl_new:N \l_C_tl  \tl_set:Nn \l_C_tl { Cde }
+\tl_new:N \g_A_tl  \tl_gset:Nn \g_A_tl { Abc }
+\tl_new:N \g_B_tl  \tl_gset:Nn \g_B_tl { Bcd }
+\tl_new:N \g_C_tl  \tl_gset:Nn \g_C_tl { Cde }
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\TEST { tl~sow/reap }
+  {
+    {
+      \tl_sow_prepare:N \l_A_tl
+      \tl_log:N  \l_A_tl
+      \tl_sow:Nn \l_A_tl {A1}
+      \tl_log:N  \l_A_tl
+      \tl_sow:Nn \l_A_tl {A2}
+      \tl_sow:Nn \l_A_tl {A3}
+      \tl_sow:Nn \l_A_tl {A4}
+      \tl_sow_reap:N \l_A_tl
+      \tl_log:N  \l_A_tl
+    }
+    \tl_log:N \l_A_tl
+  }
+  
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\TEST { tl~gsow/reap }
+  {
+    {
+      \tl_gsow_prepare:N \g_A_tl
+      \tl_log:N  \g_A_tl
+      \tl_gsow:Nn \g_A_tl {A1}
+      \tl_log:N  \g_A_tl
+      \tl_gsow:Nn \g_A_tl {A2}
+      \tl_gsow:Nn \g_A_tl {A3}
+      \tl_gsow:Nn \g_A_tl {A4}
+      \tl_gsow_greap:N \g_A_tl
+      \tl_log:N  \g_A_tl
+    }
+    \tl_log:N \g_A_tl
+  }
+  
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\TEST { tl~gsow/reap~2 }
+  {
+    {
+      \tl_gsow_prepare:N \g_A_tl
+      \tl_log:N  \g_A_tl
+      \tl_gsow:Nn \g_A_tl {A1}
+      \tl_log:N  \g_A_tl
+      \tl_gsow:Nn \g_A_tl {A2}
+      \tl_gsow:Nn \g_A_tl {A3}
+      \tl_gsow:Nn \g_A_tl {A4}
+    }
+    \tl_gsow_greap:N \g_A_tl
+    \tl_log:N \g_A_tl
+  }
+  
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\TEST { tl~sow/reap~interleaved }
+  {
+    {
+      \tl_sow_prepare:N \l_A_tl
+      \tl_sow_prepare:N \l_B_tl
+      \tl_log:N  \l_A_tl
+      \tl_log:N  \l_B_tl
+      \tl_sow:Nn \l_A_tl {A1}
+      \tl_sow:Nn \l_B_tl {B1}
+      \tl_sow:Nn \l_A_tl {A2}
+      \tl_sow:Nn \l_B_tl {B2}
+      \tl_sow:Nn \l_A_tl {A3}
+      \tl_sow:Nn \l_B_tl {B3}
+      \tl_sow_reap:N \l_A_tl
+      \tl_sow_reap:N \l_B_tl
+      \tl_log:N  \l_A_tl
+      \tl_log:N  \l_B_tl
+    }
+    \tl_log:N \l_A_tl
+    \tl_log:N \l_B_tl
+  }
+  
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\TEST { tl~gsow/reap~interleaved }
+  {
+    {
+      \tl_gsow_prepare:N \g_A_tl
+      \tl_gsow_prepare:N \g_B_tl
+      \tl_log:N  \g_A_tl
+      \tl_log:N  \g_B_tl
+      \tl_gsow:Nn \g_A_tl {A1}
+      \tl_gsow:Nn \g_B_tl {B1}
+      \tl_gsow:Nn \g_A_tl {A2}
+      \tl_gsow:Nn \g_B_tl {B2}
+      \tl_gsow:Nn \g_A_tl {A3}
+      \tl_gsow:Nn \g_B_tl {B3}
+      \tl_gsow_greap:N \g_A_tl
+      \tl_gsow_greap:N \g_B_tl
+      \tl_log:N  \g_A_tl
+      \tl_log:N  \g_B_tl
+    }
+    \tl_log:N \g_A_tl
+    \tl_log:N \g_B_tl
+  }
+  
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\TEST { tl~gsow/reap~interleaved~2 }
+  {
+    {
+      \tl_gsow_prepare:N \g_A_tl
+      \tl_gsow_prepare:N \g_B_tl
+      \tl_log:N  \g_A_tl
+      \tl_log:N  \g_B_tl
+      \tl_gsow:Nn \g_A_tl {A1}
+      \tl_gsow:Nn \g_B_tl {B1}
+      \tl_gsow:Nn \g_A_tl {A2}
+      \tl_gsow:Nn \g_B_tl {B2}
+      \tl_gsow:Nn \g_A_tl {A3}
+      \tl_gsow:Nn \g_B_tl {B3}
+    }
+    \tl_gsow_greap:N \g_A_tl
+    \tl_gsow_greap:N \g_B_tl
+    \tl_log:N  \g_A_tl
+    \tl_log:N  \g_B_tl
+  }
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\TEST { tl~sow/reap~empty }
+  {
+    {
+      \tl_sow_prepare:N \l_C_tl
+      \tl_log:N  \l_C_tl
+      \tl_sow_reap:N \l_C_tl
+      \tl_log:N  \l_C_tl
+    }
+    \tl_log:N  \l_C_tl
+  }
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\TEST { tl~gsow/reap~empty }
+  {
+    {
+      \tl_gsow_prepare:N \g_C_tl
+      \tl_log:N  \g_C_tl
+      \tl_gsow_greap:N \g_C_tl
+      \tl_log:N  \g_C_tl
+    }
+    \tl_log:N  \g_C_tl
+  }
+
+
+\END
diff --git a/l3kernel/testfiles/m3tl015.tlg b/l3kernel/testfiles/m3tl015.tlg
new file mode 100644
index 0000000..b3239de
--- /dev/null
+++ b/l3kernel/testfiles/m3tl015.tlg
@@ -0,0 +1,100 @@
+This is a generated file for the LaTeX (2e + expl3) validation system.
+Don't change this file in any respect.
+Author: Will Robertson
+Defining \l_A_tl on line ...
+Defining \l_B_tl on line ...
+Defining \l_C_tl on line ...
+Defining \g_A_tl on line ...
+Defining \g_B_tl on line ...
+Defining \g_C_tl on line ...
+============================================================
+TEST 1: tl sow/reap
+============================================================
+Defining \l___sow___\l_A_tl___int on line ...
+\l___sow___\l_A_tl___int=\count...
+> \l_A_tl=.
+Defining \l___sow___\l_A_tl___1___tl on line ...
+> \l_A_tl=.
+Defining \l___sow___\l_A_tl___2___tl on line ...
+Defining \l___sow___\l_A_tl___3___tl on line ...
+Defining \l___sow___\l_A_tl___4___tl on line ...
+> \l_A_tl=A1A2A3A4.
+> \l_A_tl=Abc.
+============================================================
+============================================================
+TEST 2: tl gsow/reap
+============================================================
+Defining \g___sow___\g_A_tl___int on line ...
+\g___sow___\g_A_tl___int=\count...
+> \g_A_tl=.
+Defining \g___sow___\g_A_tl___1___tl on line ...
+> \g_A_tl=.
+Defining \g___sow___\g_A_tl___2___tl on line ...
+Defining \g___sow___\g_A_tl___3___tl on line ...
+Defining \g___sow___\g_A_tl___4___tl on line ...
+> \g_A_tl=A1A2A3A4.
+> \g_A_tl=A1A2A3A4.
+============================================================
+============================================================
+TEST 3: tl gsow/reap 2
+============================================================
+> \g_A_tl=.
+> \g_A_tl=.
+> \g_A_tl=A1A2A3A4.
+============================================================
+============================================================
+TEST 4: tl sow/reap interleaved
+============================================================
+Defining \l___sow___\l_B_tl___int on line ...
+\l___sow___\l_B_tl___int=\count...
+> \l_A_tl=.
+> \l_B_tl=.
+Defining \l___sow___\l_B_tl___1___tl on line ...
+Defining \l___sow___\l_B_tl___2___tl on line ...
+Defining \l___sow___\l_B_tl___3___tl on line ...
+> \l_A_tl=A1A2A3.
+> \l_B_tl=B1B2B3.
+> \l_A_tl=Abc.
+> \l_B_tl=Bcd.
+============================================================
+============================================================
+TEST 5: tl gsow/reap interleaved
+============================================================
+Defining \g___sow___\g_B_tl___int on line ...
+\g___sow___\g_B_tl___int=\count...
+> \g_A_tl=.
+> \g_B_tl=.
+Defining \g___sow___\g_B_tl___1___tl on line ...
+Defining \g___sow___\g_B_tl___2___tl on line ...
+Defining \g___sow___\g_B_tl___3___tl on line ...
+> \g_A_tl=A1A2A3.
+> \g_B_tl=B1B2B3.
+> \g_A_tl=A1A2A3.
+> \g_B_tl=B1B2B3.
+============================================================
+============================================================
+TEST 6: tl gsow/reap interleaved 2
+============================================================
+> \g_A_tl=.
+> \g_B_tl=.
+> \g_A_tl=A1A2A3.
+> \g_B_tl=B1B2B3.
+============================================================
+============================================================
+TEST 7: tl sow/reap empty
+============================================================
+Defining \l___sow___\l_C_tl___int on line ...
+\l___sow___\l_C_tl___int=\count...
+> \l_C_tl=.
+> \l_C_tl=.
+> \l_C_tl=Cde.
+============================================================
+============================================================
+TEST 8: tl gsow/reap empty
+============================================================
+Defining \g___sow___\g_C_tl___int on line ...
+\g___sow___\g_C_tl___int=\count...
+> \g_C_tl=.
+> \g_C_tl=.
+> \g_C_tl=.
+============================================================





More information about the latex3-commits mailing list