%% %% This is file `erw-l3.sty', %% generated with the docstrip utility. %% %% The original source files were: %% %% erw-l3.dtx (with options: `package') %% ----------------------------------------------------------------------------- %% erw-l3 --- Utilities based on LaTeX3, such as 'merge sort' %% Released under the LaTeX Project Public License v1.3c or later %% See http://www.latex-project.org/lppl.txt %% ---------------------------------------------------------------------------- %% \NeedsTeXFormat{LaTeX2e}[2021-06-01] \RequirePackage{xparse, l3keys2e, xtemplate}[2021-06-01] \ProvidesExplPackage {erw-l3} % Package name {2022-01-28} % Release date {4.2} % Release version {erw-l3 --- Utilities based on LaTeX3, such as 'merge sort' } % Description \cs_generate_variant:Nn\int_compare_p:nNn{eNe} \cs_generate_variant:Nn\int_eval:n{e} \cs_generate_variant:Nn\prg_new_conditional:Nnn{c} \cs_generate_variant:Nn\prg_replicate:nn{e} \cs_generate_variant:Nn\regex_gset:Nn{c} \cs_generate_variant:Nn\regex_log:N{c} \cs_generate_variant:Nn\regex_match:NnTF{c} \cs_generate_variant:Nn\tl_to_str:n{e} \cs_generate_variant:Nn\prop_put:Nnn{Nne} \msg_new:nnnn{__erw}{text}{text~is~not~loaded}{load~amsmath} \cs_new:Npn \__erw_text:n #1 {\cs_if_exist:NTF\text{\text{#1}}{\msg_error:nn{__erw}{text}}} \cs_new:Npn\__erw_empty:w #1 \q_recursion_stop {\c_empty_tl} \cs_new_protected:Nn\erw_keys_set:n{ \keys_set:nn{__erw}{#1} } \cs_new_protected:Nn\erw_keys_set:nn{ \keys_set:nn{__erw / #1}{#2} } \cs_generate_variant:Nn\erw_apply:Nw{c} \cs_new:Npn \erw_identity:n#1{#1} \cs_new:Npn \erw_int_incr:n#1{\int_eval:n{#1+1}} \cs_new:Npn \erw_swap:nn#1#2{#2#1} \cs_generate_variant:Nn \erw_swap:nn{e} \cs_new:Npn \erw_name_signature_cs:N #1 { \exp_last_unbraced:Ne \__erw_name_signature_cs:nnn{\cs_split_function:N#1}} \cs_new:Nn \__erw_name_signature_cs:nnn{{#1}{#2}} \msg_new:nnn{erw}{quark-only-tail} {requires~tail;~got~'#1';~\msg_line_context:} \cs_new:Npn \erw_all_q:w #1 \q_recursion_stop {% \erw_remove_last_q:w#1\q_recursion_stop \erw_last_q:w#1\q_recursion_stop } \cs_new:Npn \erw_remove_first_q:w #1 % \q_recursion_stop {\quark_if_recursion_tail_stop:n{#1} \__erw_remove_first_q:nw#1\q_recursion_stop} \cs_new:Npn \__erw_remove_first_q:nw #1 % #2 % \q_recursion_stop {\erw_remove_last_q:w#2\q_recursion_stop \erw_last_q:w#2\q_recursion_stop} \cs_new:Npn \erw_first_q:w #1 \q_recursion_stop {% \quark_if_recursion_tail_stop:n{#1} \__erw_first_q:enw{ \tl_if_head_is_group_p:n{#1}}#1\q_recursion_stop } \cs_new:Npn \__erw_first_q:nnw #1 % #2 % #3 % \q_recursion_stop {% \bool_if:nTF{#1}{{#2}}{#2} } \cs_generate_variant:Nn\__erw_first_q:nnw{e} \cs_new:Npn \erw_remove_last_q:w #1 \q_recursion_stop {% \quark_if_recursion_tail_stop:n{#1} \__erw_remove_last_q:ew{\tl_if_head_is_group_p:n{#1}}#1\q_recursion_stop } \cs_new:Npn \__erw_remove_last_q:nw #1 % #2 % \q_recursion_stop { \__erw_remove_last_q:nnw{#1}#2\q_recursion_stop } \cs_generate_variant:Nn\__erw_remove_last_q:nw{e} \cs_new:Npn \__erw_remove_last_q:nnw #1 % #2 % #3 % \q_recursion_stop {% \quark_if_recursion_tail_stop:n{#3} \bool_if:nTF{#1}{{#2}}{#2} \__erw_remove_last_q:ew {\tl_if_head_is_group_p:n{#3}} #3 \q_recursion_stop } \cs_generate_variant:Nn\__erw_remove_last_q:nnw{e} \cs_new:Npn \erw_last_q:w #1 \q_recursion_stop {\quark_if_recursion_tail_stop:n{#1} \__erw_last_q:ew{\tl_if_head_is_group_p:n{#1}}#1\q_recursion_stop} \cs_new:Npn \__erw_last_q:nw #1 % #2 % \q_recursion_stop { \__erw_last_q:nnw{#1}#2\q_recursion_stop } \cs_generate_variant:Nn\__erw_last_q:nw{e} \cs_new:Npn \__erw_last_q:nnw #1 % #2 % #3 % \q_recursion_stop {% \quark_if_recursion_tail_stop_do:nn{#3}{ \bool_if:nTF{#1}{{#2}}{#2} } \__erw_last_q:ew {\tl_if_head_is_group_p:n{#3}} #3 \q_recursion_stop } \cs_generate_variant:Nn\__erw_last_q:nnw{e} \msg_new:nnn{__erw}{predicate-empty} {empty~expression~in~predicate} \prg_new_conditional:Npnn \erw_and_tl:nn #1 % #2 % {p} {%^^A \__erw_and_tl:nw {#1}#2 \q_recursion_tail\q_recursion_stop } \cs_new:Npn \__erw_and_tl:nw #1 % #2 % \q_recursion_stop {% \quark_if_recursion_tail_stop_do:nn{#2} { \prg_return_true: } \__erw_and_tl:nnw {#1} % #2 % \q_recursion_stop } \cs_new:Npn \__erw_and_tl:nnw #1 % #2 % #3 % \q_recursion_stop {% \bool_if:nTF {#1{#2}} {\__erw_and_tl:nw{#1}#3\q_recursion_stop} { \prg_return_false: } } \cs_new:Npn \__erw_new_compare_p:nnn #1 % #2 % #3 % {% \prg_new_conditional:cnn{#1:#2} {p} {% \bool_if:nTF {#3} {\prg_return_true:} {\prg_return_false:} } } \keys_define:nn{ __erw } { new_compare_p.code:n = {\__erw_new_compare_p:nnn#1} } \erw_keys_set:n {% new_compare_p = {erw_compare} % {nNnNn} { \__erw_compare:eecN{ #2{#3} }{ #2{#5} }{ #1:nNn }#4 } } \cs_new:Npn \__erw_compare:nnNN #1 % #2 % #3 % #4 % { #3{ #1 }#4{ #2 } } \cs_generate_variant:Nn\__erw_compare:nnNN{eec} \erw_keys_set:n {% new_compare_p = {erw_int_incr} {nn} {\exp_args:Ne \int_compare_p:nNn{ \int_eval:n{#1+1} } = {#2} } } \cs_new:Npn\__erw_keyval_key:w #1 = #2 \q_recursion_stop{#1} \cs_new:Npn\__erw_keyval_value:w #1 = #2 \q_recursion_stop{#2} \cs_new:Npn \erw_keyval_key:n#1{\__erw_keyval_key:w #1 \q_recursion_stop} \cs_new:Npn \erw_keyval_value:n#1{\__erw_keyval_value:w #1 \q_recursion_stop} \cs_new:Npn \erw_keyval:nn#1#2{ #1 = #2 } \erw_keys_set:n { new_compare_p = {erw_key_compare} {nNn}{ \erw_compare_p:nNnNn {int_compare_p}\erw_keyval_key:n{#1}#2{#3} }, new_compare_p = {erw_key_compare} {n}{ \erw_compare_recurse_p:nnNN{#1} {int_compare_p}\erw_keyval_key:n< } } \cs_new:Npn \erw_remove_first:n #1 % {\erw_remove_first_q:w#1\q_recursion_tail\q_recursion_stop} \cs_generate_variant:Nn\erw_remove_first:n{e} \cs_new:Npn \erw_remove_last:n #1 % {\erw_remove_last_q:w#1\q_recursion_tail\q_recursion_stop} \cs_generate_variant:Nn\erw_remove_last:n{e} \cs_new:Npn \erw_first:n #1 {\erw_first_q:w#1\q_recursion_tail\q_recursion_stop} \cs_generate_variant:Nn\erw_first:n{e} \cs_new:Npn \erw_last:n #1 % {\erw_last_q:w#1\q_recursion_tail\q_recursion_stop} \cs_generate_variant:Nn\erw_last:n{e} \cs_new:Npn \erw_adjacent_insert:nn #1 % #2 % {% \erw_first:n{#1} \erw_swap:en { \erw_remove_first:n{#1} } {% \__erw_adjacent_insert:nw {#2} % } \q_recursion_tail \q_recursion_stop } \cs_generate_variant:Nn\erw_adjacent_insert:nn{e} \cs_new:Npn \__erw_adjacent_insert:nw #1 % #2 % \q_recursion_stop {% \quark_if_recursion_tail_stop:n{#2} \__erw_adjacent_insert:new {#1}{\tl_if_head_is_group_p:n{#2}}#2 \q_recursion_stop } \cs_new:Npn \__erw_adjacent_insert:nnw #1 % #2 % #3 % #4 % \q_recursion_stop {% #1\bool_if:nTF{#2}{{#3}}{#3} \__erw_adjacent_insert:nw{#1}#4\q_recursion_stop } \cs_generate_variant:Nn\__erw_adjacent_insert:nnw{ne} \cs_new:Npn \erw_clist_tl:nn #1 % #2 % { \erw_clist_tl:nnw {#1} #2 \q_recursion_tail\q_recursion_stop } \cs_new:Npn \erw_clist_tl:nnw #1 #2\q_recursion_stop {\quark_if_recursion_tail_stop:n{#2} \erw_clist_tl:nenw {#1} {\tl_if_head_is_group_p:n{#2}} #2 \q_recursion_stop} \cs_generate_variant:Nn\erw_clist_tl:nnw{ne} \cs_new:Npn \erw_clist_tl:nnnw #1 % #2 % #3 % #4 % \q_recursion_stop { \quark_if_recursion_tail_stop_do:nn{#4} {% \bool_if:nTF {\bool_lazy_and_p:nn{#1}{#2}} {{#3}}{#3} } \bool_if:nTF{\bool_lazy_and_p:nn{#1}{#2}} {{#3}}{#3}, \erw_clist_tl:nnw {#1} #4 \q_recursion_stop } \cs_generate_variant:Nn\erw_clist_tl:nnnw{ne} \prg_new_conditional:Npnn \erw_if_in_clist:nn #1 % #2 % {p} { \__erw_clist_if_in:nw {#1} #2, \q_recursion_tail \q_recursion_stop } \cs_new:Npn \__erw_clist_if_in:nw #1 #2 \q_recursion_stop {% \quark_if_recursion_tail_stop:n{#2} \__erw_clist_if_in:nnw {#1} #2 \q_recursion_stop } \cs_new:Nn \__erw_clist_if_in:nn {\__erw_clist_if_in:nw{#1} #2 \q_recursion_stop} \cs_new:Npn \__erw_clist_if_in:nnw #1 #2, #3 \q_recursion_stop {% \quark_if_recursion_tail_stop_do:nn{#3} {% \str_if_eq:nnTF{#1}{#2} {\prg_return_true:}{\prg_return_false:} } \str_if_eq:nnTF{#1}{#2} {\prg_return_true:} {\__erw_clist_if_in:nw {#1} #3 \q_recursion_stop} \__erw_empty:w\q_recursion_stop } \cs_new:Npn \erw_split_even:n #1 % {% \tl_if_empty:nF{#1} {% \exp_last_unbraced:Ne \__erw_split_even:nnnw {% {\__erw_split_even_threshold:n{#1}} % {\tl_if_head_is_group_p:n{#1}} % } #1 % \q_recursion_tail \q_recursion_stop } } \cs_generate_variant:Nn\erw_split_even:n{e} \cs_new:Npn \__erw_split_even_threshold:n #1 % {\exp_args:Ne \int_div_round:nn{\tl_count:n{#1}}{2}} \cs_new:Npn \__erw_split_even:nnnw #1 % #2 % #3 % #4 % \q_recursion_stop {% \quark_if_recursion_tail_stop_do:nn{#4} { { \bool_if:nTF{#2}{{#3}}{#3} }{} } \exp_last_unbraced:Ne \__erw_split_even:nnnnw {% {1} % { \tl_if_head_is_group_p:n{#4} } {#1} % { \bool_if:nTF{#2}{{#3}}{#3} } % } #4 % \q_recursion_stop } \cs_new:Npn \__erw_split_even:nnnnw #1 % #2 % #3 % #4 % #5 % #6 % \q_recursion_stop {% \bool_if:nTF { \int_compare_p:nNn {#1}<{#3} } {% \exp_last_unbraced:Ne \__erw_split_even:nnnnw { { \int_eval:n{#1+1} } % { \tl_if_head_is_group_p:n{#6} } % {#3} % {#4\bool_if:nTF{#2}{{#5}}{#5}} % } #6 \q_recursion_stop } {% {#4} {% \bool_if:nTF{#2}{{#5}}{#5} \erw_remove_last_q:w#6\q_recursion_stop\erw_last_q:w#6\q_recursion_stop} } } \cs_new:Npn \erw_thread_sort:nnNn #1 % #2 % #3 % #4 % {% \__erw_thread_sort:nNnnn {#3} % #4 % {\c_empty_tl} % {#1} {#2} } \cs_generate_variant:Nn\erw_thread_sort:nnNn{ee} \cs_new:Npn \__erw_thread_sort:nNnnn #1 % #2 % #3 % #4 % #5 % {% \__erw_thread_sort:nNnww {#1} % {#2} % {#3} % #4 \q_recursion_tail% \q_stop #5 \q_recursion_tail% \q_recursion_stop } \cs_generate_variant:Nn\__erw_thread_sort:nNnnn{nNeee} \cs_new:Npn \__erw_thread_sort:nNnww #1 % #2 % #3 % #4 % \q_stop #5 % \q_recursion_stop {% \quark_if_recursion_tail_stop_do:nn{#4} { #3 \erw_all_q:w #5 \q_recursion_stop } \quark_if_recursion_tail_stop_do:nn{#5} { #3 \erw_all_q:w #4 \q_recursion_stop } \__erw_thread_sort:nNneeww {#1}#2{#3} { \tl_if_head_is_group_p:n{#4} } { \tl_if_head_is_group_p:n{#5} } #4\q_stop #5\q_recursion_stop } \cs_new:Npn \__erw_thread_sort:nNnnnww #1 % #2 % #3 % #4 % #5 % #6 % #7 % \q_stop #8 % #9 % \q_recursion_stop {% \bool_if:nTF { \use:c{#1:nNn}{#6}#2{#8} } {% \__erw_thread_sort:nNeee {#1} #2 {#3\bool_if:nTF{#4}{{#6}}{#6}} {\erw_all_q:w#7\q_recursion_stop} {\bool_if:nTF{#5}{{#8}}{#8}\erw_all_q:w#9\q_recursion_stop} } {% \__erw_thread_sort:nNeee {#1} #2 {#3\bool_if:nTF{#5}{{#8}}{#8}} {\bool_if:nTF{#4}{{#6}}{#6}\erw_all_q:w#7\q_recursion_stop} {\erw_all_q:w#9\q_recursion_stop} } } \cs_generate_variant:Nn\__erw_thread_sort:nNnnnww{nNnee} \cs_new:Npn \erw_merge_sort:nNn #1 % #2 % #3 % {% \tl_if_empty:nF{#3} {% \__erw_sort_merge:enNw {\tl_if_head_is_group_p:n{#3}} % {#1} % #2 % #3 % \q_recursion_tail \q_recursion_stop } } \cs_generate_variant:Nn\erw_merge_sort:nNn{nNe} \cs_new:Npn \__erw_sort_merge:nnNw #1 % #2 % #3 % #4 % #5 % \q_recursion_stop {% \quark_if_recursion_tail_stop_do:nn{#5} { \bool_if:nTF{#1}{{#4}}{#4} } \exp_last_unbraced:Ne \__erw_sort_merge:nnnN {% \erw_split_even:e {% \bool_if:nTF{#1}{{#4}}{#4} \erw_all_q:w#5\q_recursion_stop } } % {}{} {#2} % #3 % \__erw_empty:w \q_recursion_stop } \cs_generate_variant:Nn\__erw_sort_merge:nnNw{e} \cs_new:Npn \__erw_sort_merge:nnnN #1 % #2 % #3 % #4 % {% \erw_thread_sort:eeNn {% \__erw_sort_merge:enNw {\tl_if_head_is_group_p:n{#1}} {#3} % #4 % #1 % \q_recursion_tail \q_recursion_stop } % {% \__erw_sort_merge:enNw {\tl_if_head_is_group_p:n{#2}} {#3} % #4 % #2 % \q_recursion_tail \q_recursion_stop } % {#3} % #4 % } \msg_new:nnn{__erw}{tokenlist-incr} {expecting~an~ascending~tokenlist~got~#1~followed~by~#2} \cs_new:Npn \__erw_filter_uniq:nnw #1 % #2 % #3 % \q_recursion_stop { % \quark_if_recursion_tail_stop:n{#3} \__erw_filter_uniq_aux:nnw{#1}{#2}#3\q_recursion_stop} \cs_new:Npn \__erw_filter_uniq_aux:nw #1 % #2 % #3 % \q_recursion_stop {% {#2} \__erw_filter_uniq:nnw {#1} % {#2} #3 % \q_recursion_stop } \cs_new:Npn \__erw_filter_uniq_aux:nnw #1 % #2 % #3 % #4 % \q_recursion_stop { % \bool_if:nTF{\use:c{#1:nNn}{#3}<{#2}} {\msg_error:nnnn{__erw}{tokenlist-incr}{#2}{#3}} {% \bool_if:nF {\use:c{#1:nNn}{#3}={#2}} {\tl_if_single_token:nTF{#3}{#3}{{#3}}} } \quark_if_recursion_tail_stop:n{#4} \__erw_filter_uniq:nnw{#1}{#3}#4\q_recursion_stop } \cs_new:Npn \__erw_filter_uniq:nw #1 % #2 % {% \quark_if_recursion_tail_stop_do:nn{#2}{\c_empty_tl} \__erw_filter_uniq_aux:nw {#1}#2 \q_recursion_stop} \cs_new:Npn \erw_filter_uniq:nn #1 % #2 % {% \__erw_filter_uniq_aux:nw {#1} % #2 \q_recursion_tail % \q_recursion_stop} \cs_new:Npn \erw_filter_uniq:n #1 % { \erw_filter_uniq:nn{int_compare_p}{#1} } \cs_generate_variant:Nn\erw_filter_uniq:nn{ne} \keys_define:nn{__erw} { clist_map_inline.code:n = \__erw_map_inline_clist:nnn#1 } \cs_new_protected:Npn \__erw_map_inline_clist:nnn #1 % #2 % #3 % { \cs_new_protected:cn {__erw_do:#2}{#3} \clist_map_inline:nn {#1} {\use:c{__erw_do:#2}##1} } \cs_new:Npn \erw_parameter:n #1 %^^A {## #1} \cs_new:Npn \__erw_parameter_aux:nn #1 % #2 % { \int_step_function:nnN {#2}{#1}\erw_parameter:n} \cs_new:Npn \erw_parameter:nn #1 % #2 % {% \exp_args:Ne \__erw_parameter_aux:nn {\int_eval:n{#1+#2-1}}{#1}} \cs_new:Npn \erw_argument:nn #1 % #2 % {\__erw_argument:nw{#1}#2\q_recursion_tail\q_recursion_stop} \cs_new:Npn \__erw_argument_unit:nn #1 % #2 % {\use:c{__erw_argument_#2:w} #1 \q_recursion_stop} \cs_new:Npn\__erw_argument_n:w #1 \q_recursion_stop{{## #1}} \cs_new:Npn\__erw_argument_N:w #1 \q_recursion_stop{## #1} \cs_new:Npn \__erw_argument:nw #1 % #2 % \q_recursion_stop { \quark_if_recursion_tail_stop:n{#2} \__erw_argument:nnw{#1}#2\q_recursion_stop } \cs_new:Npn \__erw_argument:nnw #1 % #2 % #3 % \q_recursion_stop {% \__erw_argument_unit:nn{#1}{#2} \exp_args:Ne \__erw_argument:nw {\erw_int_incr:n{#1}}#3\q_recursion_stop } \ProcessKeysOptions{__erw} \ExplSyntaxOff %% %% Copyright (C) 2020-2022 by Erwann Rogard %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License (LPPL), either %% version 1.3c of this license or (at your option) any later %% version. The latest version of this license is in the file: %% %% http://www.latex-project.org/lppl.txt %% %% This work is "maintained" (as per LPPL maintenance status) by %% Erwann Rogard. %% %% This work consists of the file erw-l3.dtx and the derived files: %% erw-l3.sty, and erw-l3.pdf. %% %% %% End of file `erw-l3.sty'.