auxsparsearray.h /size: 10 Kb    last modification: 2025-02-21 11:03
1/*
2    See license.txt in the root of this project.
3*/
4
5# ifndef LMT_UTILITIES_SPARSEARRAY_H
6# define LMT_UTILITIES_SPARSEARRAY_H
7
8/*tex
9
10    This file originally was called |managed-sa| but becauss it kind of a library and also used in
11    \LUATEX\ it's better to use a different name. In this variant dumping is more sparse (resulting
12    in somewhat smaller format files). This might be backported but only after testing it here for a
13    long time. Of course the principles are the same, it's just extended.
14
15*/
16
17/*tex
18
19    The next two sets of three had better match up exactly, but using bare numbers is easier on the
20    \CCODE\ compiler. Here are some format sizes (for ConTeXt) with different values:
21
22     64 : 17562942
23    128 : 17548150 <= best value
24    256 : 17681398
25
26*/
27
28# if (0) 
29
30/* HHHHHHHMMMMMMMLLLLLLL */
31
32# define LMT_SA_HIGHPART 128
33# define LMT_SA_MIDPART  128
34# define LMT_SA_LOWPART  128
35
36# define LMT_SA_H_PART(a) (((a)>>14)&127)
37# define LMT_SA_M_PART(a) (((a)>> 7)&127)
38# define LMT_SA_L_PART(a) ( (a)     &127)
39
40# else 
41
42/* 40K less in 2023 */
43/* 90K less in 2024 */
44
45/* HHHHHHHMMMMMMMMLLLLLL */ /* This is about as small as we can go. */
46
47# define LMT_SA_HIGHPART 128
48# define LMT_SA_MIDPART  256
49# define LMT_SA_LOWPART   64
50
51# define LMT_SA_H_PART(a) (((a)>>14)&127)
52# define LMT_SA_M_PART(a) (((a)>> 6)&255)
53# define LMT_SA_L_PART(a) ( (a)      &63)
54
55# endif
56
57/*tex
58
59    In the early days of \LUATEX\ we had just simple items, all 32 bit values. Then we put the
60    delcodes in trees too which saved memory and format size but it introduced 32 bit slack in all
61    the other code arrays. We then also had to dump selectively, but it was no big deal. Eventually,
62    once it became clear that the concepts would not change a variant was made for \LUAMETATEX: we
63    just use a two times larger lower array when we have delimiters. This saves some memory. The
64    price we pay is that a stack entry now has two values but that is not really an issue.
65
66    By packing the math code values we loose the option to store an active state but that's no big
67    deal.
68
69    todo: consider simple char array for catcodes.
70
71    The code here is somewhat messy because we generalized it a bit. Maybe I'll redo it some day.
72
73 */
74
75typedef struct sparse_state_info {
76    memory_data sparse_data;
77} sparse_state_info;
78
79extern sparse_state_info lmt_sparse_state;
80
81typedef struct sa_mathblob {
82    unsigned int class_value:math_class_bits;
83    unsigned int family_value:math_family_bits;
84    unsigned int character_value:math_character_bits;
85} sa_mathblob;
86
87typedef struct sa_mathspec {
88    unsigned short properties;
89    unsigned short group;
90    unsigned int   index;
91} sa_mathspec;
92
93typedef struct packed_math_character {
94    union {
95        sa_mathblob sa_value;
96        unsigned    ui_value;
97    };
98} packed_math_character;
99
100typedef union sa_tree_item {
101    unsigned int   uint_value;
102    int            int_value;
103    sa_mathblob    math_code_value;
104    sa_mathspec    math_spec_value;
105    unsigned short ushort_value[2];
106    unsigned char  uchar_value[4];
107} sa_tree_item;
108
109typedef struct sa_stack_item {
110    int          code;
111    int          level;
112    sa_tree_item value_1;
113    sa_tree_item value_2;
114} sa_stack_item;
115
116typedef struct sa_tree_head {
117    int              sa_stack_size;         /*tex initial stack size   */
118    int              sa_stack_step;         /*tex increment stack step */
119    int              sa_stack_ptr;          /*tex current stack point  */
120    sa_tree_item     dflt;                  /*tex default item value   */
121 // sa_tree_item  ***tree;                  /*tex item tree head       */
122    sa_tree_item   **tree[LMT_SA_HIGHPART]; /*tex item tree head       */ /* we always have HIGH now cf mail by AK to luatex list, little gain */
123    sa_stack_item   *stack;                 /*tex stack tree head      */
124    int              bytes;                 /*tex the number of items per entry */
125    int              identifier;
126} sa_tree_head;
127
128typedef sa_tree_head *sa_tree;
129
130//define set_nibble(original,position,nibble) (((original) & ~(0xF << (4*(position%8)))) | ((nibble & 0xF) << (4*(position%8))))
131//define get_nibble(original,position)        (((original) >> (4*(position%8))) & 0xF)
132
133static inline unsigned int set_nibble(unsigned int original, int position, int nibble)
134{
135    position = 4 * (position % 8);
136    return (original & ~(0xF << position)) | ((nibble & 0xF) << position);
137}
138
139static inline unsigned int get_nibble(unsigned int original, int position)
140{
141    return (original >> (4 * (position % 8))) & 0xF;
142}
143
144# if (1) 
145
146    extern int sa_get_item_0 (const sa_tree head, int n);                                     /* these return the value or dflt */
147    extern int sa_get_item_1 (const sa_tree head, int n);                                     /* these return the value or dflt */
148    extern int sa_get_item_2 (const sa_tree head, int n);                                     /* these return the value or dflt */
149    extern int sa_get_item_4 (const sa_tree head, int n, sa_tree_item *v);                    /* these return success */
150    extern int sa_get_item_8 (const sa_tree head, int n, sa_tree_item *v1, sa_tree_item *v2); /* these return success */
151
152# else 
153
154    inline int sa_get_item_0(const sa_tree head, int n)
155    {
156        int h = LMT_SA_H_PART(n);
157        int m = LMT_SA_M_PART(n);
158        if (head->tree[h][m]) {
159            return get_nibble(head->tree[h][m][LMT_SA_L_PART(n)/8].uint_value,n);
160        }
161        return (int) get_nibble(head->dflt.uint_value,0);
162    }
163
164    inline int sa_get_item_1(const sa_tree head, int n)
165    {
166        int h = LMT_SA_H_PART(n);
167        int m = LMT_SA_M_PART(n);
168        if (head->tree[h][m]) {
169            return head->tree[h][m][LMT_SA_L_PART(n)/4].uchar_value[n%4];
170        }
171        return (int) head->dflt.uchar_value[0];
172    }
173    
174    inline int sa_get_item_2(const sa_tree head, int n)
175    {
176        int h = LMT_SA_H_PART(n);
177        int m = LMT_SA_M_PART(n);
178        if (head->tree[h][m]) {
179            return head->tree[h][m][LMT_SA_L_PART(n)/2].ushort_value[n%2];
180        }
181        return (int) head->dflt.ushort_value[0];
182    }
183    
184    inline int sa_get_item_4(const sa_tree head, int n, sa_tree_item *v)
185    {
186        int h = LMT_SA_H_PART(n);
187        int m = LMT_SA_M_PART(n);
188        if (head->tree[h][m]) {
189            *v = head->tree[h][m][LMT_SA_L_PART(n)];
190            return 1;
191        }
192        *v = head->dflt;
193        return 0;
194    }
195    
196    inline int sa_get_item_8(const sa_tree head, int n, sa_tree_item *v1, sa_tree_item *v2)
197    {
198        int h = LMT_SA_H_PART(n);
199        int m = LMT_SA_M_PART(n);
200        if (head->tree[h][m]) {
201            int l = 2*LMT_SA_L_PART(n);
202            *v1 = head->tree[h][m][l];
203            *v2 = head->tree[h][m][l+1];
204            return 1;
205        }
206        *v1 = head->dflt;
207        *v2 = head->dflt;
208        return 0;
209    }
210
211# endif 
212
213extern void    sa_set_item_0    (const sa_tree head, int n, int v, int gl);
214extern void    sa_set_item_1    (const sa_tree head, int n, int v, int gl);
215extern void    sa_set_item_2    (const sa_tree head, int n, int v, int gl);
216extern void    sa_set_item_4    (const sa_tree head, int n, const sa_tree_item v, int gl);
217extern void    sa_set_item_8    (const sa_tree head, int n, const sa_tree_item v1, const sa_tree_item v2, int gl);
218extern sa_tree sa_new_tree      (int identifier, int stacksize, int stackstep, int bytes, const sa_tree_item dflt);
219extern sa_tree sa_copy_tree     (const sa_tree head);
220extern void    sa_destroy_tree  (sa_tree head);
221extern void    sa_dump_tree     (dumpstream f, sa_tree a);
222extern sa_tree sa_undump_tree   (dumpstream f);
223extern void    sa_restore_stack (const sa_tree a, int gl);
224extern void    sa_reinit_stack  (const sa_tree a, int gl);
225extern void    sa_show_stack    (const sa_tree a);
226extern void    sa_clear_stack   (const sa_tree a);
227
228extern void    sa_set_item_n    (const sa_tree head, int n, int v, int gl);
229extern int     sa_get_item_n    (const sa_tree head, int n);
230
231static inline halfword sa_return_item_0(const sa_tree head, halfword n)
232{
233    int hp = LMT_SA_H_PART(n);
234    if (head->tree[hp]) {
235        int mp = LMT_SA_M_PART(n);
236        if (head->tree[hp][mp]) {
237            return (halfword) get_nibble(head->tree[hp][mp][LMT_SA_L_PART(n)/8].uint_value,n);
238        }
239    }
240    return (halfword) get_nibble(head->dflt.uint_value,0);
241}
242
243static inline halfword sa_return_item_1(const sa_tree head, halfword n)
244{
245    int hp = LMT_SA_H_PART(n);
246    if (head->tree[hp]) {
247        int mp = LMT_SA_M_PART(n);
248        if (head->tree[hp][mp]) {
249            return (halfword) head->tree[hp][mp][LMT_SA_L_PART(n)/4].uchar_value[n%4];
250        }
251    }
252    return (halfword) head->dflt.uchar_value[0];
253}
254
255static inline halfword sa_return_item_2(const sa_tree head, halfword n)
256{
257    int hp = LMT_SA_H_PART(n);
258    if (head->tree[hp]) {
259        int mp = LMT_SA_M_PART(n);
260        if (head->tree[hp][mp]) {
261            return (halfword) head->tree[hp][mp][LMT_SA_L_PART(n)/2].ushort_value[n%2];
262        }
263    }
264    return (halfword) head->dflt.ushort_value[0];
265}
266
267static inline halfword sa_return_item_4(const sa_tree head, halfword n)
268{
269    int hp = LMT_SA_H_PART(n);
270    if (head->tree[hp]) {
271        int mp = LMT_SA_M_PART(n);
272        if (head->tree[hp][mp]) {
273            return (halfword) head->tree[hp][mp][LMT_SA_L_PART(n)].int_value;
274        }
275    }
276    return (halfword) head->dflt.int_value;
277}
278
279static inline void sa_rawset_item_0(const sa_tree head, halfword n, unsigned char v)
280{
281    head->tree[LMT_SA_H_PART(n)][LMT_SA_M_PART(n)][LMT_SA_L_PART(n)/8].uint_value = set_nibble(head->tree[LMT_SA_H_PART(n)][LMT_SA_M_PART(n)][LMT_SA_L_PART(n)/8].uint_value,n,v);
282}
283
284static inline void sa_rawset_item_1(const sa_tree head, halfword n, unsigned char v)
285{
286    head->tree[LMT_SA_H_PART(n)][LMT_SA_M_PART(n)][LMT_SA_L_PART(n)/4].uchar_value[n%4] = v;
287}
288
289static inline void sa_rawset_item_2(const sa_tree head, halfword n, unsigned short v)
290{
291    head->tree[LMT_SA_H_PART(n)][LMT_SA_M_PART(n)][LMT_SA_L_PART(n)/2].ushort_value[n%2] = v;
292}
293
294static inline void sa_rawset_item_4(const sa_tree head, halfword n, const sa_tree_item v)
295{
296    head->tree[LMT_SA_H_PART(n)][LMT_SA_M_PART(n)][LMT_SA_L_PART(n)] = v;
297}
298
299static inline void sa_rawset_item_8(const sa_tree head, halfword n,  const sa_tree_item v1, const sa_tree_item v2)
300{
301    sa_tree_item *low = head->tree[LMT_SA_H_PART(n)][LMT_SA_M_PART(n)];
302    int l = 2*LMT_SA_L_PART(n);
303    low[l] = v1;
304    low[l+1] = v2;
305}
306
307// inline them
308
309extern void *sa_malloc_array  (int recordsize, int size);
310extern void *sa_realloc_array (void *p, int recordsize, int size, int step);
311extern void *sa_calloc_array  (int recordsize, int size);
312extern void *sa_free_array    (void *p);
313extern void  sa_wipe_array    (void *head, int recordsize, int size);
314
315# endif
316