diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3bitset.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3bitset.dtx | 604 |
1 files changed, 604 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3bitset.dtx b/Master/texmf-dist/source/latex/l3kernel/l3bitset.dtx new file mode 100644 index 00000000000..101a2aa4143 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3bitset.dtx @@ -0,0 +1,604 @@ +% \iffalse meta-comment +% +%% File: l3bitset.dtx +% +% Copyright (C) 2020-2023 The LaTeX Project +% +% It 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 file is part of the "l3kernel bundle" (The Work in LPPL) +% and all files in that bundle must be distributed together. +% +% ----------------------------------------------------------------------- +% +% The development version of the bundle can be found at +% +% https://github.com/latex3/latex3 +% +% for those people who are interested. +% +%<*driver> +\documentclass[full,kernel]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% \title{^^A +% The \pkg{l3bitset} package \\ Bitsets ^^A +% } +% +% \author{^^A +% The \LaTeX{} Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released 2023-12-08} +% +% \maketitle +% +% \begin{documentation} +% +% This package defines and implements the data type \texttt{bitset}, a vector of +% bits. The size of the vector may grow dynamically. +% Individual bits can be set and unset by names pointing to an index position. +% The names |1|, |2|, |3|, \ldots\ are predeclared and point to the +% index positions $1$, $2$, $3$,\ldots. More names can be added and existing names can +% be changed. +% The index is like all other indices in \pkg{expl3} modules \emph{1-based}. +% A \texttt{bitset} can be output as binary number or---as needed e.g. in a +% PDF dictionary---as decimal (arabic) number. +% Currently only a small subset of the functions provided by the \pkg{bitset} +% package are implemented here, mainly the functions needed to use bitsets in +% PDF dictionaries. +% +% The bitset is stored as a string (but one shouldn't rely on the internal +% representation) and so the vector size is theoretically +% unlimited, only restricted by \TeX-memory. But the functions to set and clear +% bits uses integer functions for the index so bitsets can't be longer +% than $2^{31} - 1$. +% The export function +% \cs{bitset_to_arabic:N} can use functions from the \texttt{int} module only if +% the largest index used for this bitset is smaller then $32$, for longer +% bitsets \texttt{fp} is used and this is slower. +% +% \section{Creating bitsets} +% +% \begin{function}[added = 2021-01-26,updated=2020-12-29] +% {\bitset_new:N,\bitset_new:c,\bitset_new:Nn, \bitset_new:cn} +% \begin{syntax} +% \cs{bitset_new:N} \meta{bitset var} \\ +% \cs{bitset_new:Nn} \meta{bitset var} +% \{ +% \meta{name1} |=| \meta{index1} |,| +% \meta{name2} |=| \meta{index2} |,| \ldots{} +% \} +% \end{syntax} +% Creates a new \meta{bitset var} or raises an error if the name is already taken. +% The declaration is global. The \meta{bitset var} is initially $0$. +% +% Bitsets are implemented as string variables consisting of +% \texttt{1}'s and \texttt{0}'s. +% The rightmost number is the index position $1$, so +% the string variable can be viewed directly as the binary number. +% But one shouldn't rely on the internal representation, but use the +% dedicated \cs{bitset_to_bin:N} instead to get the binary number. +% +% The name--index pairs given in the second +% argument of \cs{bitset_new:Nn} declares names for some indices, +% which can be used to set and unset bits. +% The names |1|, |2|, |3|, \ldots\ are predeclared and point to the +% index positions $1$, $2$, $3$, \ldots. +% +% \meta{index\ldots} should be a positive number or an +% \meta{integer expression} which evaluates to a positive number. +% The expression is evaluated when the index is used, not a declaration time. +% The names \meta{name\ldots} +% should be unique. Using a number as name, e.g.~|10=1|, is allowed, it +% then overwrites the predeclared name |10|, +% but the index position $10$ can then only be reached if some other +% name for it exists, e.g. |ten=10|. +% It is not necessary to give every index +% a name, and an index can have more than one name. The named index +% can be extended or changed with the next function. +% \end{function} +% +% \begin{function}[added = 2021-01-26] +% {\bitset_addto_named_index:Nn} +% \begin{syntax} +% \cs{bitset_addto_named_index:Nn} \meta{bitset var} +% \{ +% \meta{name1} |=| \meta{index1} |,| +% \meta{name2} |=| \meta{index2} |,| \ldots{} +% \} +% \end{syntax} +% This extends or changes the name--index pairs for \meta{bitset var} +% globally as described for \cs{bitset_new:Nn}. +% \end{function} +% +% For example after these settings +% \begin{verbatim} +% \bitset_new:Nn \l_pdfannot_F_bitset +% { +% Invisible = 1, +% Hidden = 2, +% Print = 3, +% NoZoom = 4, +% NoRotate = 5, +% NoView = 6, +% ReadOnly = 7, +% Locked = 8, +% ToggleNoView = 9, +% LockedContents = 10 +% } +% \bitset_addto_named_index:Nn \l_pdfannot_F_bitset +% { +% print = 3 +% } +% \end{verbatim} +% it is possible to set bit $3$ by using any of this alternatives: +% \begin{verbatim} +% \bitset_set_true:Nn \l_pdfannot_F_bitset {Print} +% \bitset_set_true:Nn \l_pdfannot_F_bitset {print} +% \bitset_set_true:Nn \l_pdfannot_F_bitset {3} +% \end{verbatim} +% +% \begin{function}[EXP, pTF,added = 2021-01-26] +% {\bitset_if_exist:N, \bitset_if_exist:c} +% \begin{syntax} +% \cs{bitset_if_exist_p:N} \meta{bitset var} +% \cs{bitset_if_exist:NTF} \meta{bitset var} \Arg{true code} \Arg{false code}% +% \end{syntax} +% Tests whether the \meta{bitset var} exist. +% \end{function} +% +% \section{Setting and unsetting bits} +% +% \begin{function}[added = 2021-01-26] +% { +% \bitset_set_true:Nn, \bitset_set_true:cn, +% \bitset_gset_true:Nn, \bitset_gset_true:cn +% } +% \begin{syntax} +% \cs{bitset_set_true:Nn} \meta{bitset var} \Arg{name}\\ +% \cs{bitset_gset_true:Nn} \meta{bitset var} \Arg{name} +% \end{syntax} +% This sets the bit of the index position represented by \Arg{name} to $1$. +% \Arg{name} should be either one of the predeclared names +% |1|, |2|, |3|, \ldots, or one of the names added manually. +% Index position are 1-based. +% If needed the length of the bit vector is enlarged. +% \end{function} +% +% \begin{function}[added = 2021-01-26] +% { +% \bitset_set_false:Nn, \bitset_set_false:cn, +% \bitset_gset_false:Nn, \bitset_set_false:cn +% } +% \begin{syntax} +% \cs{bitset_set_false:Nn} \meta{bitset var} \Arg{name}\\ +% \cs{bitset_gset_false:Nn} \meta{bitset var} \Arg{name} +% \end{syntax} +% This unsets the bit of the index position represented by \Arg{name} (sets +% it to $0$). +% \Arg{name} should be either one of the predeclared names +% |1|, |2|, |3|, \ldots, or one of the names added manually. +% The index is $1$-based. If the index position is larger +% than the current length of the bit vector +% nothing happens. If the leading (left most) bit is unset, +% zeros are not trimmed but stay in the bit vector and are still shown +% by \cs{bitset_show:N}. +% \end{function} +% +% \begin{function}[added = 2021-01-26] +% {\bitset_clear:N,\bitset_clear:c,\bitset_gclear:N,\bitset_gclear:c} +% \begin{syntax} +% \cs{bitset_clear:N} \meta{bitset var} \\ +% \cs{bitset_gclear:N} \meta{bitset var} +% \end{syntax} +% This resets the bitset to the initial state. The declared names are not changed. +% \end{function} +% +% \section{Using bitsets} +% +% \begin{function}[EXP,added = 2021-01-26] +% {\bitset_item:Nn, \bitset_item:cn} +% \begin{syntax} +% \cs{bitset_item:Nn} \meta{bitset var} \Arg{name} +% \end{syntax} +% \cs{bitset_item:Nn} outputs \texttt{1} if the bit with +% the index number represented by \Arg{name} is set and \texttt{0} otherwise. +% \Arg{name} is either one of the predeclared names +% |1|, |2|, |3|, \ldots, or one of the names added manually. +% \end{function} +% +% \begin{function}[EXP,added = 2021-01-26] +% {\bitset_to_bin:N, \bitset_to_bin:c} +% \begin{syntax} +% \cs{bitset_to_bin:N} \meta{bitset var} +% \end{syntax} +% This leaves the current value of the bitset expressed as +% a binary (string) number in the input stream. +% If no bit has been set yet, the output is zero. +% \end{function} +% \begin{function}[EXP,added = 2021-01-26] +% {\bitset_to_arabic:N, \bitset_to_arabic:c} +% \begin{syntax} +% \cs{bitset_to_arabic:N} \meta{bitset var} +% \end{syntax} +% This leaves the current value of the bitset expressed as +% a decimal number in the input stream. If no bit has been set yet, +% the output is zero. The function uses \cs{int_from_bin:n} if the largest +% index that have been set or unset is smaller then $32$, and a slower implementation +% based on \cs{fp_eval:n} otherwise. +% \end{function} +% +% \begin{function}[added = 2021-01-26] +% {\bitset_show:N, \bitset_show:c} +% \begin{syntax} +% \cs{bitset_show:N} \meta{bitset var} +% \end{syntax} +% Displays the binary and decimal value of the \meta{bitset var} on the terminal, +% \end{function} +% +% \begin{function}[added = 2021-01-26] +% {\bitset_log:N, \bitset_log:c} +% \begin{syntax} +% \cs{bitset_log:N} \meta{bitset var} +% \end{syntax} +% Writes the value of the \meta{bitset var} in the log file. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3bitset} implementation} +% +% \begin{macrocode} +%<*package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=bitset> +% \end{macrocode} +% +% Transitional support. +% \begin{macrocode} +\cs_if_exist:NT \@expl@finalise@setup@@@@ + { + \tl_gput_right:Nn \@expl@finalise@setup@@@@ + { \disable@package@load { l3bitset } { } } + } +% \end{macrocode} +% +% A bitset is a string variable. +% \begin{macro}{\bitset_new:N, \bitset_new:c} +% \begin{macro}{\bitset_new:Nn, \bitset_new:cn} +% \begin{macrocode} +\cs_new_protected:Npn \bitset_new:N #1 + { + \__kernel_chk_if_free_cs:N #1 + \cs_gset_eq:NN #1 \c_zero_str + \prop_new:c { g__bitset_ \cs_to_str:N #1 _name_prop } + } + +\cs_new_protected:Npn \bitset_new:Nn #1 #2 + { + \__kernel_chk_if_free_cs:N #1 + \cs_gset_eq:NN #1 \c_zero_str + \prop_new:c { g__bitset_ \cs_to_str:N #1 _name_prop } + \prop_gset_from_keyval:cn + { g__bitset_ \cs_to_str:N #1 _name_prop } + {#2} + } +\cs_generate_variant:Nn \bitset_new:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{variable}{\l_@@_tmp_prop} +% A scratch prop to be able to extend the names properties. +% \begin{macrocode} +\prop_new:N \l_@@_tmp_prop +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\bitset_addto_named_index:Nn} +% \begin{macrocode} +\cs_new_protected:Npn \bitset_addto_named_index:Nn #1#2 + { + \prop_set_from_keyval:Nn \l_@@_tmp_prop {#2} + \prop_map_inline:Nn \l_@@_tmp_prop + { + \prop_gput:cnn + { g_@@_ \cs_to_str:N #1 _name_prop } + {##1} + {##2} + } + } +% \end{macrocode} +% \end{macro} +% \begin{macro}[EXP,pTF] +% { +% \bitset_if_exist:N, \bitset_if_exist:c +% } +% Existence tests. +% \begin{macrocode} +\prg_new_eq_conditional:NNn + \bitset_if_exist:N \str_if_exist:N { p , T , F , TF } +\prg_new_eq_conditional:NNn + \bitset_if_exist:c \str_if_exist:c + { p , T , F , TF } +% \end{macrocode} +% \end{macro} +% \begin{macro}{\@@_set_true:Nn, \@@_gset_true:Nn, \@@_set_false:Nn, \@@_gset_false:Nn} +% \begin{macro}{\@@_set:NNnN} +% The internal command uses only numbers (integer expressions) for the +% position. +% A bit is set by either extending the string or by splitting it and +% then inserting an $1$. It is not checked if the value was already $1$. +% \begin{macrocode} +\cs_new_protected:Npn \@@_set_true:Nn #1#2 + { \@@_set:NNnN \str_set:Ne #1 {#2} 1 } +\cs_new_protected:Npn \@@_gset_true:Nn #1#2 + { \@@_set:NNnN \str_gset:Ne #1 {#2} 1 } +\cs_new_protected:Npn \@@_set_false:Nn #1#2 + { \@@_set:NNnN \str_set:Ne #1 {#2} 0 } +\cs_new_protected:Npn \@@_gset_false:Nn #1#2 + { \@@_set:NNnN \str_gset:Ne #1 {#2} 0 } +\cs_new_protected:Npn \@@_set:NNnN #1#2#3#4 + { + \int_compare:nNnT {#3} > { 0 } + { + \int_compare:nNnTF { \str_count:N #2 } < {#3} + { + #1 #2 + { + #4 + \prg_replicate:nn { #3 - \str_count:N #2 - 1 } { 0 } + #2 + } + } + { + #1 #2 + { + \str_range:Nnn #2 { 1 } { -1 - (#3) } + #4 + \str_range:Nnn #2 { 1 - (#3) } { -1 } + } + } + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{variable}{\l_@@_internal_int} +% \begin{macrocode} +\int_new:N \l_@@_internal_int +% \end{macrocode} +% \end{variable} +% +% \begin{macro}[TF]{\@@_test_digits:n} +% \begin{macro}{\@@_test_digits_end:n} +% \begin{macro}{\@@_test_digits:wn} +% \url{https://chat.stackexchange.com/transcript/message/56878159#56878159} +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \@@_test_digits:n #1 { TF } + { + \tex_afterassignment:D \@@_test_digits:w + \l_@@_internal_int = 0 \tl_trim_spaces_apply:nN {#1} \tl_to_str:n + \@@_test_digits_end: + \use_i:nnn \if_false: + \@@_test_digits_end: + \if_int_compare:w \c_zero_int < \l_@@_internal_int + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +\cs_new_eq:NN \@@_test_digits_end: \exp_stop_f: +\cs_new_protected:Npn \@@_test_digits:w #1 \@@_test_digits_end: { } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \bitset_set_true:Nn, \bitset_set_true:cn, +% \bitset_gset_true:Nn, \bitset_gset_true:cn, +% } +% \begin{macro}{\@@_set_aux:NNn} +% The user commands must first translate the argument to an index number. +% \begin{macrocode} +\cs_new_protected:Npn \bitset_set_true:Nn #1#2 + { \@@_set:NNn \@@_set_true:Nn #1 {#2} } +\cs_new_protected:Npn \bitset_gset_true:Nn #1#2 + { \@@_set:NNn \@@_gset_true:Nn #1 {#2} } +\cs_new_protected:Npn \bitset_set_false:Nn #1#2 + { \@@_set:NNn \@@_set_false:Nn #1 {#2} } +\cs_new_protected:Npn \bitset_gset_false:Nn #1#2 + { \@@_set:NNn \@@_gset_false:Nn #1 {#2} } +\cs_new_protected:Npn \@@_set:NNn #1#2#3 + { + \prop_if_in:cnTF { g_@@_ \cs_to_str:N #2 _name_prop } {#3} + { + #1 #2 + { + \prop_item:cn { g_@@_ \cs_to_str:N #2 _name_prop } {#3} + } + } + { + \@@_test_digits:nTF {#3} + { + #1 #2 {#3} + \prop_gput:cnn { g_@@_ \cs_to_str:N #2 _name_prop } {#3} {#3} + } + { + \msg_warning:nnee { bitset } { unknown-name } + { \token_to_str:N #2 } + { \tl_to_str:n {#3} } + } + } + } +\cs_generate_variant:Nn \bitset_set_true:Nn { c } +\cs_generate_variant:Nn \bitset_gset_true:Nn { c } +\cs_generate_variant:Nn \bitset_set_false:Nn { c } +\cs_generate_variant:Nn \bitset_gset_false:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \bitset_clear:N, \bitset_clear:c, +% \bitset_gclear:N, \bitset_gclear:c +% } +% \begin{macrocode} +\cs_new_protected:Npn \bitset_clear:N #1 + { + \str_set_eq:NN #1 \c_zero_str + } +\cs_new_protected:Npn \bitset_gclear:N #1 + { + \str_gset_eq:NN #1 \c_zero_str + } +\cs_generate_variant:Nn \bitset_clear:N { c } +\cs_generate_variant:Nn \bitset_gclear:N { c } +% \end{macrocode} +% \end{macro} +% \begin{macro} +% { +% \bitset_to_arabic:N, \bitset_to_arabic:c, +% \bitset_to_bin:N, \bitset_to_bin:c, +% } +% The naming of the commands follow the names in the \texttt{int} module. +% \cs{bitset_to_arabic:N} uses \cs{int_from_bin:n} if the string is shorter +% then $32$ and the slower \cs{fp_eval} for larger bitsets. +% \begin{macrocode} +\cs_new:Npn \bitset_to_arabic:N #1 + { + \int_compare:nNnTF { \str_count:N #1 } < { 32 } + { \exp_args:No \int_from_bin:n {#1} } + { + \exp_after:wN \@@_to_int:nN \exp_after:wN 0 + #1 \q_recursion_tail \q_recursion_stop + } + } + +\cs_new:Npn \@@_to_int:nN #1#2 + { + \quark_if_recursion_tail_stop_do:Nn #2 {#1} + \exp_args:Nf \@@_to_int:nN { \fp_eval:n { #1 * 2 + #2 } } + } + +\cs_new:Npn \bitset_to_bin:N #1 + { + #1 + } +\cs_generate_variant:Nn \bitset_to_arabic:N { c } +\cs_generate_variant:Nn \bitset_to_bin:N { c } +% \end{macrocode} +% \end{macro} +% \begin{macro} +% { +% \bitset_item:Nn, \bitset_item:cn +% } +% All bits that have been set at anytime have an entry in the prop, +% so we can take everything else as $0$. +% \begin{macrocode} +\cs_new:Npn \bitset_item:Nn #1#2 + { + \prop_if_in:cnTF { g_@@_ \cs_to_str:N #1 _name_prop } {#2} + { + \int_eval:n + { + \str_item:Nn #1 + { 0 - ( \prop_item:cn { g_@@_ \cs_to_str:N #1 _name_prop } {#2} ) } + +0 + } + } + { + 0 + } + } +\cs_generate_variant:Nn \bitset_item:Nn { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% { +% \bitset_show:N, \bitset_show:c, +% \bitset_log:N, \bitset_log:c +% } +% \begin{macrocode} +\cs_new_protected:Npn \bitset_show:N { \@@_show:NN \msg_show:nneeee } +\cs_generate_variant:Nn \bitset_show:N { c } +\cs_new_protected:Npn \bitset_log:N { \@@_show:NN \msg_log:nneeee } +\cs_generate_variant:Nn \bitset_log:N { c } +\cs_new_protected:Npn \bitset_show_named_index:N { \@@_show_named_index:NN \msg_show:nneeee } +\cs_generate_variant:Nn \bitset_show_named_index:N { c } +\cs_new_protected:Npn \@@_show:NN #1#2 + { + \__kernel_chk_defined:NT #2 + { + #1 { bitset } { show } + { \token_to_str:N #2 } + { \bitset_to_bin:N #2 } + { \bitset_to_arabic:N #2 } + { } + } + } +\cs_new_protected:Npn \@@_show_named_index:NN #1#2 + { + \__kernel_chk_defined:NT #2 + { + #1 { bitset } { show-names } + { \token_to_str:N #2 } + { \prop_map_function:cN { g_@@_ \cs_to_str:N #2 _name_prop } \msg_show_item:nn } + { } + { } + } + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Messages} +% \begin{macrocode} + \msg_new:nnn { bitset } { show } + { + The~bitset~#1~has~the~representation: \\ + >~binary:~#2 \\ + >~arabic:~#3 . + } +\msg_new:nnn { bitset } { show-names } + { + The~bitset~#1~ + \tl_if_empty:nTF {#2} + { knows~no~names~yet \\>~ . } + { knows~the~name/index~pairs~(without~outer~braces): #2 . } + } +\msg_new:nnn { bitset } { unknown-name } + { The~name~'#2'~is~unknown~for~bitset~\tl_to_str:n {#1} } +\prop_gput:Nnn \g_msg_module_name_prop { bitset } { LaTeX } +\prop_gput:Nnn \g_msg_module_type_prop { bitset } { } +% \end{macrocode} +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex |