3

As the manual of l3intarray says, for the command \intarray_new:Nn, variable assignments are always global, and that the size of the array is fixed and must be given at point of initialization.

This leads to a problem, for example my code defines

\newcommand{\mycommand}[1]{
  \intarray_new:Nn\g_myarray{#1}
  % Some useful operations with it here
}

then when I use \mycommand more than once it raises an error. However I can't put the initialization outside because the {<size>} is meant to vary. And I don't want to create a huge array to satisfy all cases.

By now, I have such a solution,

\newcommand{\mycommand}[1]{
  \let\g_myarray\undefined
  \intarray_new:Nn\g_myarray{#1}
  % Some useful operations with it here
}

Is there any better way to do this, or is my method the only possible method?

youthdoo
  • 861
  • 1
    No, create a huge array. Your method creates a "memory leak". (as usual, expl3 commands inherit limitations from the corresponding TeX primitive) – user202729 Dec 28 '22 at 03:52
  • @user202729 Sorry, I couldn't understand the final part. Could you explain more? – youthdoo Dec 28 '22 at 03:57
  • 2
    Which part? For the memory leak part, every time you do \let\g_myarray\undefined you throw away the memory of the old array. For the primitive limitation part intarray is internally implemented using the method described in https://tex.stackexchange.com/questions/95635/using-fontdimen-as-an-array-to-store-data (see also texdoc source3) and there's no way to deallocate memory/"garbage collection" as explained there. – user202729 Dec 28 '22 at 04:07
  • So my method is likely to take up too much memory? @user202729 – youthdoo Dec 28 '22 at 04:18
  • 2
    \int_array… (ab)uses \fontdimen arrays. When you allocate one, a new font is loaded so it’s possible to assign it a number of \fontdimen parameters. When a font is loaded in TeX, it is stored in memory and it can’t be removed. Create a huge array. – egreg Dec 28 '22 at 08:28
  • 1
    If you don't know the array size, and it's dynamic, I'd usually stick to a 'classical' approach using a set of int values. Can you give details of the wider context? – Joseph Wright Dec 28 '22 at 10:53
  • @JosephWright I chose the intarray because it allows be to change the value of a certain term by providing its index and new value. This kind of operation happens a lot in my code. – youthdoo Dec 28 '22 at 10:56
  • 1
    @youthdoo Sure, but you can do that using an array of the form \l__my_array_<n>_int, i.e. a set of ints used to store one value each. For a dynamic array, that's likely a more flexible approach. – Joseph Wright Dec 28 '22 at 10:58

1 Answers1

5

When you do \intarray_new:Nn, a font is loaded; it doesn't matter which one, because it's not used for typesetting but just in order to exploit a feature of TeX. From the TeXbook, pp. 277–278

When a \fontdimen value is assigned, the <number> must be positive and not greater than the number of parameters in the font's metric information file, unless that font information has just been loaded into TeX's memory; in the latter case, you are allowed to increase the number of parameters (see Appendix F).

Then \intarray_new:Nn allocates as many \fontdimen parameters as specified in the second argument. It is not possible to change the number of parameters afterwards, as explained in the above quotation.

When a font is loaded, its metric information and its \fontdimen parameters are stored in memory and cannot be removed. There is a large amount of font memory nowadays; TeX Live 2022 sets

% Words of font info for TeX (total size of all TFM files, approximately).
% Must be >= 20000 and <= 147483647 (without tex.ch changes).
font_mem_size = 8000000

% Total number of fonts. Must be >= 50 and <= 9000 (without tex.ch changes). font_max = 9000

While loading several intarrays should not be a big problem as regards to the number of fonts, it might be with respect to the font memory size. Let's see. With an empty LaTeX file, I get

 512287 words of font info for 32 fonts, out of 8000000 for 9000

If I add \intarray_new:Nn \g_tmpa_intarray { 65536 }, the figures become

 578116 words of font info for 33 fonts, out of 8000000 for 9000

The difference is 65829 and you see that allocating more than 8000000 parameters will require increasing font_mem_size. It's hard to imagine applications where such huge size of an array is needed.

Your strategy of undefining \g_myarray (by the way, this is inconsistent with the naming standards) will lead to memory fill up, sooner or later.

Allocate

\intarray_new:Nn \g_youthdoo_myarray_intarray { <number> }

with a big enough <number> of entries sufficient for your applications.

You may want to also allocate

\int_new:N \g_youthdoo_myarray_int

so when you set the values in \g_youthdoo_myarray_intarray you can also set the highest legal index in \g_youthdoo_myarray_int and when you retrieve a value you can check that its index is inside the currently set range.

egreg
  • 1,121,712
  • From your \int_array_new:Nn, are you talking about some array data structure under l3int? Because I intended to ask about \intarray_new:Nn. However in the rest of your post you didn't have the _. Is it a typo? Or are these commands equivalent? – youthdoo Dec 28 '22 at 10:25
  • @youthdoo Sorry, typo. – egreg Dec 28 '22 at 10:30