From f1dacf4a5d258b27a60af43432524674b27d5a9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Ke=C3=9Fler?= Date: Wed, 2 Feb 2022 22:34:39 +0100 Subject: [PATCH] implement caching in groupthm --- src/environments/groupthm/groupthm.dtx | 360 +++++++++++++++++-------- 1 file changed, 251 insertions(+), 109 deletions(-) diff --git a/src/environments/groupthm/groupthm.dtx b/src/environments/groupthm/groupthm.dtx index 81385f1..b16cc26 100644 --- a/src/environments/groupthm/groupthm.dtx +++ b/src/environments/groupthm/groupthm.dtx @@ -23,7 +23,7 @@ % https://www.latex-project.org/lppl.txt % % ----------------------------------------------------------------------- -%\ProvidesExplPackage{groupthm}{2022/01/17}{0.0.1}{Grouped theorems.} +%\ProvidesExplPackage{groupthm}{2022/02/02}{0.0.2}{Grouped theorems.} % %<*driver> \documentclass[full,kernel]{l3doc} @@ -845,26 +845,17 @@ % \end{syntax} % % This is just a private wrapper around \cs{declaretheorem} of the \pkg{thmtools} package. +% +% We additionally cache % % \begin{macrocode} \cs_new:Npn \@@_thmtools_declare_theorem:nn #1 #2 { \tl_log:n { Declaring ~ thmtools ~ theorem ~ #2 } \declaretheorem [ #1 ] { #2 } - \bool_if:NT \g_@@_cache_bool + \@@_cache:n { - \hook_gput_code:nnn { enddocument / afterlastpage } { groupthm } - { - \iow_now:cn { @auxout } - { - \ExplSyntaxOn - \hook_gput_code:nnn { @@ / auxfile define cached } { groupthm } - { - \@@_thmtools_declare_theorem:nn { #1 } { #2 } - } - \ExplSyntaxOff - } - } + \csname @@_thmtools_declare_theorem:nn \endcsname { #1 } { #2 } } } \cs_generate_variant:Nn \@@_thmtools_declare_theorem:nn { V n } @@ -982,10 +973,6 @@ \hook_new:n { @@/thmtools } % \end{macrocode} % \begin{macrocode} -\hook_new:n { @@/document define cached } -\hook_new:n { @@/auxfile define cached } -% \end{macrocode} -% \begin{macrocode} \hook_new:n { @@/groupsort } % \end{macrocode} % @@ -1106,6 +1093,36 @@ \int_set:Nn \g_@@_cache_version_aux_int { -1 } % \end{macrocode} % \end{variable} +% +% +% +% \begin{variable}{\g_@@_lazy_document_tl, \g_@@_lazy_auxfile_tl} +% +% During the preamble, if in caching mode, we will collect definitions for +% theorems in these token lists. At the beginning of the document, we select the +% proper one. +% +% \begin{macrocode} +\tl_new:N \g_@@_lazy_document_tl +\tl_new:N \g_@@_lazy_auxfile_tl +% \end{macrocode} +% \end{variable} +% +% +% +% \begin{variable}{\g_@@_dump_auxfile_clist, \g_@@_dump_cache_clist} +% +% With these, we collect stuff written to the aux file at the end of the document +% +% The \cs{g_@@_dump_cache_clist} will be treated specially: +% We will dump such that in a re-run of \LaTeX, the contents will +% be available for execution in the \cs{g_@@_lazy_auxfile_tl} +% \begin{macrocode} +\clist_new:N \g_@@_dump_auxfile_clist +\clist_new:N \g_@@_dump_cache_clist +% \end{macrocode} +% \end{variable} +% % % % @@ -1799,7 +1816,7 @@ { \@@_Declarator: TheoremGroup } { O{} m } { - \groupthm_do_cached:n + \@@_lazy:n { \use:c { groupthm_#1 _group:nn } { ##1 } { ##2 } } @@ -1857,7 +1874,7 @@ % \begin{macrocode} \NewDocumentCommand { \DeclareTheoremGroupRule } { O{??} m m m } { - \groupthm_do_cached:n + \@@_lazy:n { \groupthm_declare_group_rule:nnnn {#1} {#2} {#3} {#4} } @@ -1896,7 +1913,7 @@ % \begin{macrocode} \NewDocumentCommand { \AddTheoremGroupParent } { m m } { - \groupthm_do_cached:n + \@@lazy:n { \groupthm_add_parent:nn { #1 } { #2 } } @@ -1986,9 +2003,10 @@ % \begin{macrocode} \NewDocumentCommand { \AppendToTheoremGroup } { O{} m } { - \groupthm_do_cached:n { - \groupthm_append_to_group:nn { #1 } { #2 } - } + \@@lazy:n + { + \groupthm_append_to_group:nn { #1 } { #2 } + } } % \end{macrocode} % \end{macro} @@ -2304,13 +2322,13 @@ { \@@_Declarator: GroupedTheorem } { s O{} m } { - \groupthm_do_cached:n - { - \use:c { groupthm_#1_theorem:nnn } - { ##2 } - { ##3 } - { ##1 } - } + \@@_lazy:n + { + \use:c { groupthm_#1_theorem:nnn } + { ##2 } + { ##3 } + { ##1 } + } } % \end{macrocode} % \end{macro} @@ -2457,13 +2475,13 @@ { \@@_Declarator: GroupedTheoremFamily } { s O{} m } { - \groupthm_do_cached:n + \@@_lazy:n { \use:c { groupthm_#1_family:nnn } { ##2 } { ##3 } { ##1 } - } + } } % \end{macrocode} % \end{macro} @@ -2581,21 +2599,15 @@ \@@_sort_group_names: \end { __#1__groups_ \clist_use:Nn \l_@@_group_clist { _ } } } - \bool_if:NT \g_@@_cache_bool - { - \hook_gput_code:nnn { enddocument / afterlastpage } { groupthm } - { - \iow_now:cn { @auxout } - { - \ExplSyntaxOn - \hook_gput_code:nnn { @@ / auxfile define cached } { groupthm } - { - \@@_define_family_options:nnnn { #1 } { #2 } { #3 } { #4 } - } - \ExplSyntaxOff - } - } - } +% \end{macrocode} +% +% Cache this definition for re-runs of \LaTeX. +% +% \begin{macrocode} + \@@_cache:n + { + \@@_define_family_options:nnnn { #1 } { #2 } { #3 } { #4 } + } } % \end{macrocode} % \end{macro} @@ -2658,7 +2670,7 @@ { \@@_Declarator: GroupedTheoremFamilyOptions } { s O{} m m m } { - \groupthm_do_cached:n + \@@_lazy:n { \keys_set:nn { groupthm / theorem ~ family ~ options } { starred ~ version } \keys_set:nn { groupthm / theorem ~ family ~ options } { ##2 } @@ -2697,88 +2709,218 @@ % % % +% We differentiate between caching and non-caching mode here. +% First, we provide some wrappers for writing to the aux file: +% % % -% \begin{macro}{\groupthm_do_cached:n} -% \begin{syntax} -% \cs{groupthm_do_cached:n}\marg{code} -% \end{syntax} +% \begin{macrocode} +\bool_if:NTF \g_@@_cache_bool + { +% \end{macrocode} +% +% +% \begin{macro}{\@@_write_auxout:n, \@@_write_auxout:x} % -% Executes this code lazy at beginning of the document, -% iff caching is active. -% -% At beginning of document, code will be only executed -% if the aux file version was too old, otherwise dropped. +% Immediate write to aux file. % % \begin{macrocode} -\cs_new:Npn \groupthm_do_cached:n - { - \bool_if:NTF \g_@@_cache_bool + \cs_new:Npn \@@_write_auxout:n { - \hook_gput_code:nnn {@@/document define cached} { groupthm } + \iow_now:cn { @auxout } } + \cs_generate_variant:Nn \@@_write_auxout:n { x } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\@@_dump_auxfile:n} +% +% Dump to auxfile at end of document. +% This is used to dump to the aux file at any point of the document +% without messing with preamble / document treatment etc. +% +% \begin{macrocode} + \cs_new:Npn \@@_dump_auxfile:n { - \use:n + \clist_gput_right:Nn \g_@@_dump_auxfile_clist + } +% \end{macrocode} +% \end{macro} + + +% \begin{macro}{\@@_cache_auxfile:n, \@@_cache_auxfile:V} +% +% +% This also pipes data through the auxfile, +% but will cache it to make it available in the next run. +% +% \begin{macrocode} + \cs_new:Npn \@@_cache_auxfile:n + { + \clist_gput_right:Nn \g_@@_dump_cache_clist + } + \cs_generate_variant:NN \@@_cache_auxfile:n { V } +% \end{macrocode} +% \end{macro} + + +% This handles the dumping to the auxfile at the end of the document: +% \begin{macrocode} + \hook_gput_code:nnn { enddocument } { groupthm } + { +% \end{macrocode} +% First, perform the regular dump: +% \begin{macrocode} + \clist_map_function:NN \g_@@_dump_auxfile_clist + \_@@_write_auxout:n + +% \end{macrocode} +% Now, we want to dump the cached clist, but wrap it into the +% the corresponding macro call for storing it in +% \cs{g_@@_lazy_auxfile_tl} on re-reading the auxfile. +% For this, we have to put two single braces into the auxfile +% separately +% \begin{macrocode} + \_@@_write_auxout:n + { + \csname tl_gput_right:cn \endcsname + { + g_@@_lazy_auxfile_tl + } + } + \_@@_write_auxout:x { \str_use:N \c_left_brace_str } +% \end{macrocode} +% Now, dump the list +% \begin{macrocode} + \clist_map_function:NN \g_@@_dump_cache_clist + \_@@_write_auxout:n + + \_@@_write_auxout:x { \str_use:N \c_right_brace_str } + } +% \end{macrocode} + + +% This makes sure that we restore the cache version +% on the next run of LaTeX +% \begin{macrocode} + \_@@_dump_auxfile:x + { + \ExplSyntaxOn + \int_gset:Nn \exp_not:N \g_@@_cache_version_aux_int + { + \int_use:N \g_@@_cache_version_document_int + } + \ExplSyntaxOff + } +% \end{macrocode} +% +% +% We can now provide the two main macros responsible for the caching feature. +% +% \begin{macro}{\@@_lazy:n} +% \begin{syntax} +% \cs{@@_lazy:n}\marg{code} +% \end{syntax} +% +% Lazy execution will just append to the corresponding token list +% +% \begin{macrocode} + \cs_new:Npn \@@_lazy:n + { + \tl_gput_right:Nn \g_@@_lazy_document_tl } - } % \end{macrocode} % \end{macro} % -% % -% This makes sure that at the beginning of the document, after reading -% in the aux file with possible precomputed definitions of the last run, -% we will execute either the definitions of the auxfile or all the -% lazy computation from the current run that we collected. % -% These hooks should actually be one-time hooks, but this would cause -% problems when \LaTeX rereads the aux file a second time at the end -% of the document, since we want no declarations there % +% \begin{macro}{\@@_cache:n} +% \begin{syntax} +% \cs{@@_cache:n}\marg{code} +% \end{syntax} +% +% We have to replace parameter-tokens of category code 6 +% with regular \enquote{\#} tokens of category code 12 +% so that we don't double them when writing to the aux file. +% See +% \href +% {https://tex.stackexchange.com/questions/632294/writing-nested-argument-specifier-to-aux-file} +% {https://tex.stackexchange.com/questions/632294/writing-nested-argument-specifier-to-aux-file} +% for details. % % \begin{macrocode} -\hook_gput_code:nnn { begindocument } { groupthm } - { - \bool_if:nTF + \cs_new:Npn \@@_cache:n #1 { - \g_@@_cache_bool - && - \int_compare_p:n + \tl_set:Nn \l_tmpa_tl { - \g_@@_cache_version_aux_int < \g_@@_cache_version_document_int + { #1 } } + \regex_replace_all:nnN { \cP\# } { \cO\# } \l_tmpa_tl + \@@_dump_cache:V \l_tmpa_tl } - { - \hook_use:n { @@ / document define cached } - } - { - \hook_use:n { @@ / auxfile define cached } - } - } -% \end{macrocode} -% -% -% This code makes sure that in the next run of \LaTeX, when reading in the aux-file, -% before processing the rest of the groupthm aux file macros, -% we set the depth of the document cache version available so that we can -% query this value in the next run as soon as possible. -% -% \begin{macrocode} -\bool_if:NT \g_@@_cache_bool - { - \hook_gput_code:nnn { enddocument / afterlastpage } { before-groupthm } - { - \iow_now:cx { @auxout } - { - \token_to_str:N \ExplSyntaxOn - \int_gset:Nn \g_@@_cache_version_aux_int - { \int_use:N \g_@@_cache_version_document_int } - \token_to_str:N \ExplSyntaxOff - } - } - } -\hook_gset_rule:nnnn { enddocument / afterlastpage } { before-groupthm } { before } { groupthm } % \end{macrocode} +% \end{macro} +% +% +% +% Finally, at the beginning of the document, call the correct code for execution +% \begin{macrocode} + \hook_gput_code:nnn { begindocument } { groupthm } + { + \int_compare:nNnTF + \g_@@_cache_version_aux_int < \g_@@_cache_version_document_int + { + \tl_use:N \g_@@_lazy_document_tl + } + { + \tl_use:N \g_@@_lazy_auxfile_tl + } + } +% \end{macrocode} +% +% +% It remains to handle the non-caching case, in which +% we only have to define \cs{@@_cache:n} and \cs{@@_lazy:n} to be simple +% wrappers. +% +% \begin{macrocode} + } + { +% \end{macrocode} +% +% +% +% +% +% \begin{macro}{\@@_cache:n} +% +% +% \begin{macrocode} + \cs_set_eq:NN \@@_cache:n \use_none:n +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\@@_lazy:n} +% +% +% +% \begin{macrocode} + \cs_set_eq:NN \@@_lazy:n \use:n +% \end{macrocode} +% \end{macro} +% +% +% This ends the non-caching case. +% +% \begin{macrocode} + } +% \end{macrocode} +% +% +% % % % \begin{macrocode}