% \iffalse %% File: l3int.dtx Copyright (C) 1990-1998 LaTeX3 project % %<*dtx> \ProvidesFile{l3int.dtx} % %\NeedsTeXFormat{LaTeX2e} %\ProvidesPackage{l3int} % \ProvidesFile{l3int.drv} % \fi % \ProvidesFile{l3int.dtx} [1998/04/20 v1.0c L3 Experimental Integer module] % % \iffalse %<*driver> \documentclass{l3doc} \begin{document} \DocInput{l3int.dtx} \end{document} % % \fi % % % \GetFileInfo{l3int.dtx} % \title{The \textsf{l3int} package\thanks{This file % has version number \fileversion, last % revised \filedate.}\\ % Counters} % \author{\Team} % \date{\filedate} % \maketitle % % \section{Counters} % % \LaTeX3 maintains two type of integer registers for internal use. % One (associated with the name "int") uses the builtin counter % registers of \TeX{} and is therefore relatively fast and one % (associated with the name "fint" for fake counter) that implements the % operations within the \TeX{} macro language and is therefore much % slower in processing. This type of counter is also far more restricted % in its range. % % The fake counter should be used for variables that are not accessed % very often since this saves the important fast internal registers % (\TeX{} has only 255 of those). For example, all allocation routines % in \LaTeX3 make use of fake counters to remember the values of recent % allocated register numbers etc. % % Since all functions for both types are very similar (they usually % differ only in the initial "f") we describe them together. But % remember that you need to use "fint" variables when using "fint" % functions. % % \subsection{Functions} % % \begin{function}{% % \int_new:N | % \int_new:c | % \fint_new:N | % } % \begin{syntax} % "\int_new:N" % "\fint_new:N" % \end{syntax} % Defines to be a new variable of type "int". There is no way to % define constant counters with these functions. % \begin{texnote} % "\int_new:N" is the equivalent to plain \TeX{}'s \tn{newcount}. % However, the internal register allocation is done differently. % \end{texnote} % \end{function} % % \begin{function}{% % \int_incr:N | % \int_gincr:N | % \int_gincr:c | % \fint_incr:N | % \fint_gincr:N | % } % \begin{syntax} % "\int_incr:N" % "\fint_incr:N" % \end{syntax} % Increments by one. For global variables the global versions % should be used. % \end{function} % % \begin{function}{% % \int_decr:N | % \int_gdecr:N | % \int_gdecr:c | % \fint_decr:N | % \fint_gdecr:N | % } % \begin{syntax} % "\int_decr:N" % "\fint_decr:N" % \end{syntax} % Decrements by one. For global variables the global versions % should be used. % \end{function} % % \begin{function}{% % \int_set:Nn | % \int_set:cn | % \int_gset:Nn | % \int_gset:cn | % \fint_set:Nn | % \fint_gset:Nn | % } % \begin{syntax} % "\int_set:Nn" "{" "}" % "\fint_set:Nn" "{" "}" % \end{syntax} % These functions will set the register to the value. % \end{function} % % \begin{function}{% % \fint_set_eq:NN | % \fint_gset_eq:NN | % } % \begin{syntax} % "\fint_set_eq:NN" % \end{syntax} % Fast form for % \begin{syntax} % "\fint_set:No" "{\fint_use:N" "}" % \end{syntax} % when is known to be a variable of fake counter. Note that a % corresponding function for real counters is not implemented since the % "\int_set:Nn" function does this operation sufficiently when then second % argument is a instead of "{""}" value. % \end{function} % % \begin{function}{% % \int_add:Nn | % \int_add:cn | % \int_gadd:Nn | % \fint_add:Nn | % \fint_gadd:Nn | % } % \begin{syntax} % "\int_add:Nn" "{" "}" % "\fint_add:Nn" "{" "}" % \end{syntax} % These functions will add to the register the value . If % the second argument is a register too, the surrounding braces % can be left out. % % It not allowed to use a instead of the . If a fake % counter should be used as the second argument one needs to turn the % first into an by applying "\fint_use:N". % \end{function} % % \begin{function}{% % \int_sub:Nn | % \int_gsub:Nn | % \fint_sub:Nn | % \fint_gsub:Nn | % } % \begin{syntax} % "\int_gsub:Nn" "{" "}" % "\fint_gsub:Nn" "{" "}" % \end{syntax} % These functions will subtract from the register the value % . If the second argument is a register too, the % surrounding braces can be left out. % % It is not allowed to use a instead of the . If a fake % counter should be used as the second argument one needs to turn the % first into an by applying "\fint_use:N". % \end{function} % % \begin{function}{% % \int_use:N | % \int_use:c | % \fint_use:N | % } % \begin{syntax} % "\int_use:N" % "\fint_use:N" % \end{syntax} % This function returns the integer value kept in in a way % suitable for further processing. Be sure to use "\fint_use:N" if you % are accessing the value of a fake counter because otherwise your % result will be to some surprise to you (there is no check). % \begin{texnote} % The function "\int_use:N" could be implemented directly as the \TeX{} % primitive "\tex_the:D" which is also responsible to produce the values for % other internal quantities. We have chosen to use individual functions % for counters, dimenions etc.\ to allow checks and to make the code % more selfexplaining. % \end{texnote} % \end{function} % % \subsection{Formatting a counter value} % % \begin{function}{\int_to_arabic:n | % \int_to_alph:n | % \int_to_Alph:n | % \int_to_roman:n | % \int_to_Roman:n | % \int_to_symbol:n | % } % \begin{syntax} % "\int_to_alph:n" "{" "}" % "\int_to_alph:n" % "\int_to_alph:n" "{" "\fint_use:N" "}" % \end{syntax} % If some or the the current value of a should be % displayed or typeset in a special ways (e.g., as uppercase roman % numerals) these function can be used. We need braces if the argument % is a simple , they can be omitted in case of a . % % To format s with these functions it is necessary to turn the % value of the first into an by applying "\fint_use:N" % within the argument braces. % % All functions are fully expandable and will therefore produce the % correct output when used inside of deferred writes, etc. % \begin{texnote} % These are more or less the internal \LaTeX2 functions \tn{@arabic}, % \tn{@alph}, \tn{Alph}, \tn{@roman}, \tn{@Roman}, and \tn{@fnsymbol} % except that "\int_to_symbol:n" is also allowed outside math mode. % \end{texnote} % \end{function} % % \subsection{Variable and constants} % % \begin{variable}{% % \c_int_max | % \c_fint_max | % } % Constant that denote the maximum value which can be stored in a % or register. % \end{variable} % % \begin{variable}{% % \c_minus_one | % \c_zero | % \c_one | % \c_two | % \c_three | % \c_sixteen | % \c_twohundred_fifty_five | % \c_twohundredfiftysix | % \c_thousand | % \c_ten_thousand | % \c_twenty_thousand | % } % Set of constants denoting useful values. % \begin{texnote} % Most of these constants have been available under \LaTeX2 under names % like \tn{tw@}, \tn{thr@@} etc. % \end{texnote} % \end{variable} % % \begin{variable}{% % \l_tmpa_int | % \l_tmpb_int | % \l_tmpc_int | % \g_tmpa_int | % \g_tmpb_int | % } % Scratch register for immediate use. They are not used by conditionals % or predicate functions. % \end{variable} % % % \section{Integer registers} % % % We start by ensuring that the required packages are loaded. % \begin{macrocode} %\RequirePackage{l3basics}\par %\RequirePackage{l3chk}\par %<*package> % \end{macrocode} % % Functions that support \LaTeX's user accessible counters should be % added here, too. But first the internal counters. % % \begin{macro}{\int_incr:N} % \begin{macro}{\int_decr:N} % \begin{macro}{\int_gincr:N} % \begin{macro}{\int_gdecr:N} % Incrementing and decrementing of integer registers is done with % the following functions. % \begin{macrocode} \def_new:Npn \int_incr:N #1{\tex_advance:D#1\c_one %<*check> \chk_local_or_pref_global:N #1 % } \def_new:Npn \int_decr:N #1{\tex_advance:D#1\c_minus_one %<*check> \chk_local_or_pref_global:N #1 % } \def_new:Npn \int_gincr:N { % \end{macrocode} % We make sure that a local variable is not updated globally by % changing the internal test (i.e.\ |\chk_local_or_pref_global:N|) before % making the assignment. This is done by |\pref_global_chk:| which also % issues the necessary |\pref_global:D|. This is not very efficient, but % this code will be only included for debugging purposes. Using % |\pref_global:D| in front of the local function is better in the % production versions. % \begin{macrocode} %<*check> \pref_global_chk: % %<-check> \pref_global:D \int_incr:N} \def_new:Npn \int_gdecr:N { %<*check> \pref_global_chk: % %<-check> \pref_global:D \int_decr:N} % \end{macrocode} % With the |\int_add:Nn| functions we can shorten the above code. % If this makes it too slow \ldots % \begin{macrocode} \def:Npn \int_incr:N #1{\int_add:Nn#1\c_one} \def:Npn \int_decr:N #1{\int_add:Nn#1\c_minus_one} \def:Npn \int_gincr:N #1{\int_gadd:Nn#1\c_one} \def:Npn \int_gdecr:N #1{\int_gadd:Nn#1\c_minus_one} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\int_new:N} % \begin{macro}{\int_new:c} % Allocation of a new internal counter is already done above. Here we define % the next likely variant. % \begin{macrocode} \def_new:Npn \int_new:N {} % but since we don't distribute \let:NN \int_new:N \newcount % allocation better nick the LaTeX one ... \def_new:Npn \int_new:c {\exp_args:Nc \int_new:N} % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\int_set:Nn} % \begin{macro}{\int_set:cn} % \begin{macro}{\int_gset:Nn} % \begin{macro}{\int_gset:cn} % Setting counters is again something that I would like to make % uniform at the moment to get a better overview. % \begin{macrocode} \def_new:Npn \int_set:Nn #1#2{#1#2\scan_stop: %<*check> \chk_local_or_pref_global:N #1 % } \def_new:Npn \int_gset:Nn { %<*check> \pref_global_chk: % %<-check> \pref_global:D \int_set:Nn } \def_new:Npn \int_set:cn {\exp_args:Nc \int_set:Nn } \def_new:Npn \int_gset:cn {\exp_args:Nc \int_gset:Nn } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\int_add:Nn} % \begin{macro}{\int_add:cn} % \begin{macro}{\int_gadd:Nn} % \begin{macro}{\int_sub:Nn} % \begin{macro}{\int_gsub:Nn} % Adding and substracting to and from a counter \ldots % We should think of using these functions % \begin{macrocode} \def_new:Npn \int_add:Nn #1#2{ \tex_advance:D#1#2\scan_stop: %<*check> \chk_local_or_pref_global:N #1 % } \def_new:Npn\int_add:cn{\exp_args:Nc\int_add:Nn} \def_new:Npn \int_sub:Nn #1#2{ \tex_advance:D#1-#2\scan_stop: %<*check> \chk_local_or_pref_global:N #1 % } \def_new:Npn \int_gadd:Nn { %<*check> \pref_global_chk: % %<-check> \pref_global:D \int_add:Nn } \def_new:Npn \int_gsub:Nn { %<*check> \pref_global_chk: % %<-check> \pref_global:D \int_sub:Nn } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\int_use:N} % \begin{macro}{\int_use:c} % Here is how counters are accessed: % \begin{macrocode} \let_new:NN \int_use:N \tex_the:D \def_new:Npn \int_use:c #1{\int_use:N \cs:w#1\cs_end:} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\int_gincr:c} % \begin{macro}{\int_gdecr:c} % We also need \ldots % \begin{macrocode} \def_new:Npn \int_gincr:c {\exp_args:Nc \int_gincr:N} \def_new:Npn \int_gdecr:c {\exp_args:Nc \int_gdecr:N} % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\l_tmpa_int} % \begin{macro}{\l_tmpb_int} % \begin{macro}{\l_tmpc_int} % \begin{macro}{\g_tmpa_int} % \begin{macro}{\g_tmpb_int} % We provide two local and two global scratch counters, maybe we % need more or less. Instead of using the allocation routines we % partly allocate them by hand. % \begin{macrocode} \chk_new_cs:N \l_tmpa_int % \end{macrocode} % If it turns out that we don't need local counters then this % register should be used for global counter. We might also think of % using the |\l_last_alloc_fint| as a scratch register. % \begin{macrocode} \tex_countdef:D\l_tmpa_int 255 \int_new:N \l_tmpb_int \int_new:N \l_tmpc_int \int_new:N \g_tmpa_int \int_new:N \g_tmpb_int % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\c_minus_one} % \begin{macro}{\c_zero} % \begin{macro}{\c_one} % \begin{macro}{\c_two} % \begin{macro}{\c_three} % \begin{macro}{\c_four} % \begin{macro}{\c_sixteen} % \begin{macro}{\c_thirty_two} % \begin{macro}{\c_twohundred_fifty_five} % \begin{macro}{\c_twohundred_fifty_six} % \begin{macro}{\c_thousand} % \begin{macro}{\c_ten_thousand} % \begin{macro}{\c_ten_thousand_one} % \begin{macro}{\c_ten_thousand_two} % \begin{macro}{\c_ten_thousand_three} % \begin{macro}{\c_ten_thousand_four} % \begin{macro}{\c_twenty_thousand} % \begin{macro}{\c_int_max} % And the usual constants, others are still missing. Please, make % every constant a real constant at least for the moment. We can % easily convert things in the end when we have found what % constants are used in critical places and what not. % \begin{macrocode} \tex_chardef:D \c_zero = 0 \scan_stop: \tex_chardef:D \c_one = 1 \scan_stop: \tex_chardef:D \c_two = 2 \scan_stop: \tex_chardef:D \c_three = 3 \scan_stop: \tex_chardef:D \c_four = 4 \scan_stop: \tex_chardef:D \c_sixteen = 16 \scan_stop: \tex_chardef:D \c_thirty_two = 32 \scan_stop: \tex_chardef:D \c_twohundred_fifty_five = 255 \scan_stop: \tex_mathchardef:D \c_twohundred_fifty_six = 256 \scan_stop: \tex_mathchardef:D \c_thousand = 1000 \scan_stop: \tex_mathchardef:D \c_ten_thousand = 10000 \scan_stop: \tex_mathchardef:D \c_ten_thousand_one = 10001 \scan_stop: \tex_mathchardef:D \c_ten_thousand_two = 10002 \scan_stop: \tex_mathchardef:D \c_ten_thousand_three = 10003 \scan_stop: \tex_mathchardef:D \c_ten_thousand_four = 10004 \scan_stop: \tex_mathchardef:D \c_twenty_thousand = 20000 \scan_stop: % already defined ... %\int_new:N \c_minus_one % \c_minus_one = -1 % \end{macrocode} % The |\c_int_max| will be defined internally as the largest % dimen. % \begin{macrocode} %\int_new:N \c_int_max % \c_int_max = 2147483647 % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % Show token usage: % \begin{macrocode} % %<*showmemory> \showMemUsage % % \end{macrocode} % % % \section{Fake registers} % % Fake registers are registers which implement \m{counter}s, % \m{dimen}s, etc.\ which aren't used often and therefore don't need % to run efficiently. One possible way of using them is to prepare certain % registers this way, but |\let:NN| the mutator functions to real % \m{counter}s as long as we have a sufficient number available. Now % if we are making real large formats (by adding Pic\TeX, for example) % we can turn them easily into fake registers and everything will work % as before (only a bit slower). % % % I haven't implemented anything besides counters so far, but \m{dimen} % and \m{skip} present no principal problem and should probably be % added. % % \subsection{Fake counters} % % \begin{macro}{\fint_new:N} % A fake counter is internally a \m{muskip} register. A count value % \m{x} is saved as \m{x}|mu| (more exactly as \m{x}|.0mu|) in this % register. This means that fake counter values are far more % restricted then usual counters, the largest value is 16383, % i.e.\ the |pt| part of \TeX{}'s largest \m{dimen}. This could be % changed by using more complicated conversion routines, but it % might be all right in usual applications. % % Of course, we should make sure that we don't reach the borders, % otherwise the user will be faced by the surprising message that % some dimension got to large. (Not done yet). % \begin{macrocode} %<*package> \let_new:NN \fint_new:N \newmuskip % nicked from LaTeX % \end{macrocode} % \end{macro} % % % \begin{macro}{\fint_use:N} % \begin{macro}{\fint_use_aux:w} % To use the value of a fake counter we have to get rid of |.0mu| in % an expandable way, since we want to allow constructions like % \begin{verbatim} % \if_num:w\fint_use:N \l_test_fint > 55\scan_stop: ... %\end{verbatim} % The simplest way I came up with (not much thinking behind) was % using parameter matching. % \begin{macrocode} \def_new:Npn \fint_use:N {\exp_after:NN\fint_use_aux:w\the_internal:D} % \end{macrocode} % In the |\fint_use_aux:w| function we remove the |.0mu| and pass the % the result back into the input stream. The only thing we % have to think of, is that both |mu| have category code 12 when % they are returned by |\the_internal:D|. % \begin{macrocode} \tex_lccode:D`\!=`\m \tex_lccode:D`\?=`\u \tex_lowercase:D{\def_new:Npn \fint_use_aux:w #1.0!?{#1}} \tex_lccode:D`\!=0\scan_stop: \tex_lccode:D`\?=0\scan_stop: % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\fint_set:Nn} % \begin{macro}{\fint_gset:Nn} % The way both routines are set up, the second argument might be % either a \m{normal integer}, or an internal register. % \begin{macrocode} \def_new:Npn \fint_set:Nn #1#2{#1#2~mu\scan_stop: %<*check> \chk_local_or_pref_global:N #1 % } \def_new:Npn \fint_gset:Nn{ %<*check> \pref_global_chk: % %<-check> \pref_global:D \fint_set:Nn} % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\fint_set_eq:NN} % \begin{macro}{\fint_gset_eq:NN} % We can easily set two fake counters equal to each other, but if % fake counters and real counters are used, we have to use the % slower |set| functions. % \begin{macrocode} \def_new:Npn \fint_set_eq:NN #1#2{#1#2 %<*check> \chk_local_or_pref_global:N #1\chk_var_or_const:N #2 % } \def_new:Npn \fint_gset_eq:NN { %<*check> \pref_global_chk: % %<-check> \pref_global:D \fint_set_eq:NN} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\fint_add:Nn} % \begin{macro}{\fint_gadd:Nn} % \begin{macro}{\fint_sub:Nn} % \begin{macro}{\fint_gsub:Nn} % Adding and substracting; we make use of the fact that internally % \TeX{} always use the same primitives to advance a register. % \begin{macrocode} \def_new:Npn \fint_add:Nn #1#2{\int_add:Nn#1{#2mu}} \def_new:Npn \fint_gadd:Nn { %<*check> \pref_global_chk: % %<-check> \pref_global:D \fint_add:Nn} \def_new:Npn \fint_sub:Nn #1#2{\int_sub:Nn#1{#2mu}} \def_new:Npn \fint_gsub:Nn { %<*check> \pref_global_chk: % %<-check> \pref_global:D \fint_sub:Nn} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\fint_incr:N} % \begin{macro}{\fint_gincr:N} % \begin{macro}{\fint_decr:N} % \begin{macro}{\fint_gdecr:N} % Incrementing and decrementing the fake counters: % \begin{macrocode} \def_new:Npn \fint_incr:N #1{\advance:D#1\c_one mu\scan_stop: %<*check> \chk_local_or_pref_global:N #1 % } \def_new:Npn \fint_decr:N #1{\advance:D#1\c_minus_one mu\scan_stop: %<*check> \chk_local_or_pref_global:N #1 % } \def_new:Npn \fint_gincr:N { %<*check> \pref_global_chk: % %<-check> \pref_global:D \fint_incr:N} \def_new:Npn \fint_gdecr:N { %<*check> \pref_global_chk: % %<-check> \pref_global:D \fint_decr:N} % \end{macrocode} % This can be achieved with less tokens but extra expansions: % \begin{macrocode} \def:Npn \fint_incr:N #1{\fint_add:Nn#1\c_one} \def:Npn \fint_decr:N #1{\fint_add:Nn#1\c_minus_one} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\c_fint_max} % A constant, denoting the largest possible value for fake counters. % \begin{macrocode} \tex_mathchardef:D\c_fint_max=16383 \scan_stop: % \end{macrocode} % \end{macro} % % % \subsection{Fake skip registers} % % One has to convert simply from the \m{x}|pt| |plus| \m{y}|pt| |minus| % \m{z}|pt| representation produced by |\the_internal:D|, to the % corresponding |mu| representation. Complications arise from the % possibility that |plus| and/or |minus| is not present,\footnote{This % can be catched by adding a suitable constant and removing the % corresponding constant in the other representation.} and by the % possibility that the stretch or shrink component is a |fil| unit. % % \subsection{Fake dimen registers} % % I suppose this could be viewed as a subcase of the skip registers. % See later section for a fake fake version for the moment. % % % \subsection{Allocation routines} % % Counters are rare goods in \TeX{} and we are near the limit, if % for example \LaTeX{} and Pic\TeX{} are merged. Therefore we should % be careful not to throw away counter registers unnecessarily. One % place for instance, where we can save some of them are the % allocation routines. Instead of using counters we maintain the % number of the last allocated register in a fake counter. % % % \begin{macrocode} % %<*showmemory> \showMemUsage % % \end{macrocode}