auxsparsearray.h /size: 9249 b    last modification: 2024-01-16 10:22
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# define LMT_SA_HIGHPART 128
29# define LMT_SA_MIDPART  128
30# define LMT_SA_LOWPART  128
31
32# define LMT_SA_H_PART(a) (((a)>>14)&127)
33# define LMT_SA_M_PART(a) (((a)>> 7)&127)
34# define LMT_SA_L_PART(a) ( (a)     &127)
35
36/* 40K less in 2023 */
37
38// # define LMT_SA_HIGHPART 128
39// # define LMT_SA_MIDPART  256
40// # define LMT_SA_LOWPART   64
41// 
42// # define LMT_SA_H_PART(a) (((a)>>14)&127)
43// # define LMT_SA_M_PART(a) (((a)>> 6)&255)
44// # define LMT_SA_L_PART(a) ( (a)      &63)
45
46/*tex
47
48    In the early days of \LUATEX\ we had just simple items, all 32 bit values. Then we put the
49    delcodes in trees too which saved memory and format size but it introduced 32 bit slack in all
50    the other code arrays. We then also had to dump selectively, but it was no big deal. Eventually,
51    once it became clear that the concepts would not change a variant was made for \LUAMETATEX: we
52    just use a two times larger lower array when we have delimiters. This saves some memory. The
53    price we pay is that a stack entry now has two values but that is not really an issue.
54
55    By packing the math code values we loose the option to store an active state but that's no big
56    deal.
57
58    todo: consider simple char array for catcodes.
59
60    The code here is somewhat messy because we generalized it a bit. Maybe I'll redo it some day.
61
62 */
63
64typedef struct sparse_state_info {
65    memory_data sparse_data;
66} sparse_state_info;
67
68extern sparse_state_info lmt_sparse_state;
69
70typedef struct sa_mathblob {
71    unsigned int class_value:math_class_bits;
72    unsigned int family_value:math_family_bits;
73    unsigned int character_value:math_character_bits;
74} sa_mathblob;
75
76typedef struct sa_mathspec {
77    unsigned short properties;
78    unsigned short group;
79    unsigned int   index;
80} sa_mathspec;
81
82typedef struct packed_math_character {
83    union {
84        sa_mathblob sa_value;
85        unsigned    ui_value;
86    };
87} packed_math_character;
88
89typedef union sa_tree_item {
90    unsigned int   uint_value;
91    int            int_value;
92    sa_mathblob    math_code_value;
93    sa_mathspec    math_spec_value;
94    unsigned short ushort_value[2];
95    unsigned char  uchar_value[4];
96} sa_tree_item;
97
98typedef struct sa_stack_item {
99    int          code;
100    int          level;
101    sa_tree_item value_1;
102    sa_tree_item value_2;
103} sa_stack_item;
104
105typedef struct sa_tree_head {
106    int              sa_stack_size;         /*tex initial stack size   */
107    int              sa_stack_step;         /*tex increment stack step */
108    int              sa_stack_ptr;          /*tex current stack point  */
109    sa_tree_item     dflt;                  /*tex default item value   */
110 // sa_tree_item  ***tree;                  /*tex item tree head       */
111    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 */
112    sa_stack_item   *stack;                 /*tex stack tree head      */
113    int              bytes;                 /*tex the number of items per entry */
114    int              padding;
115} sa_tree_head;
116
117typedef sa_tree_head *sa_tree;
118
119# if (1) 
120
121    extern int     sa_get_item_1    (const sa_tree head, int n);                                     /* these return the value or dflt */
122    extern int     sa_get_item_2    (const sa_tree head, int n);                                     /* these return the value or dflt */
123    extern int     sa_get_item_4    (const sa_tree head, int n, sa_tree_item *v);                    /* these return success */
124    extern int     sa_get_item_8    (const sa_tree head, int n, sa_tree_item *v1, sa_tree_item *v2); /* these return success */
125
126# else 
127
128    inline int sa_get_item_1(const sa_tree head, int n)
129    {
130        int h = LMT_SA_H_PART(n);
131        if (head->tree[h]) {
132            int m = LMT_SA_M_PART(n);
133            if (head->tree[h][m]) {
134                return head->tree[h][m][LMT_SA_L_PART(n)/4].uchar_value[n%4];
135            }
136        }
137        return (int) head->dflt.uchar_value[0];
138    }
139    
140    inline int sa_get_item_2(const sa_tree head, int n)
141    {
142        int h = LMT_SA_H_PART(n);
143        if (head->tree[h]) {
144            int m = LMT_SA_M_PART(n);
145            if (head->tree[h][m]) {
146                return head->tree[h][m][LMT_SA_L_PART(n)/2].ushort_value[n%2];
147            }
148        }
149        return (int) head->dflt.ushort_value[0];
150    }
151    
152    inline int sa_get_item_4(const sa_tree head, int n, sa_tree_item *v)
153    {
154        int h = LMT_SA_H_PART(n);
155        if (head->tree[h]) {
156            int m = LMT_SA_M_PART(n);
157            if (head->tree[h][m]) {
158                *v = head->tree[h][m][LMT_SA_L_PART(n)];
159                return 1;
160            }
161        }
162        *v = head->dflt;
163        return 0;
164    }
165    
166    inline int sa_get_item_8(const sa_tree head, int n, sa_tree_item *v1, sa_tree_item *v2)
167    {
168        int h = LMT_SA_H_PART(n);
169        if (head->tree[h]) {
170            int m = LMT_SA_M_PART(n);
171            if (head->tree[h][m]) {
172                int l = 2*LMT_SA_L_PART(n);
173                *v1 = head->tree[h][m][l];
174                *v2 = head->tree[h][m][l+1];
175                return 1;
176            }
177        }
178        *v1 = head->dflt;
179        *v2 = head->dflt;
180        return 0;
181    }
182
183# endif 
184
185extern void    sa_set_item_1    (const sa_tree head, int n, int v, int gl);
186extern void    sa_set_item_2    (const sa_tree head, int n, int v, int gl);
187extern void    sa_set_item_4    (const sa_tree head, int n, sa_tree_item v, int gl);
188extern void    sa_set_item_8    (const sa_tree head, int n, sa_tree_item v1, sa_tree_item v2, int gl);
189extern sa_tree sa_new_tree      (int size, int bytes, sa_tree_item dflt);
190extern sa_tree sa_copy_tree     (const sa_tree head);
191extern void    sa_destroy_tree  (sa_tree head);
192extern void    sa_dump_tree     (dumpstream f, sa_tree a);
193extern sa_tree sa_undump_tree   (dumpstream f);
194extern void    sa_restore_stack (const sa_tree a, int gl);
195extern void    sa_clear_stack   (const sa_tree a);
196
197extern void    sa_set_item_n    (const sa_tree head, int n, int v, int gl);
198extern int     sa_get_item_n    (const sa_tree head, int n);
199
200static inline halfword sa_return_item_1(const sa_tree head, halfword n)
201{
202 // if (head->tree) {
203        int hp = LMT_SA_H_PART(n);
204        if (head->tree[hp]) {
205            int mp = LMT_SA_M_PART(n);
206            if (head->tree[hp][mp]) {
207                return (halfword) head->tree[hp][mp][LMT_SA_L_PART(n)/4].uchar_value[n%4];
208            }
209        }
210 // }
211    return (halfword) head->dflt.uchar_value[0];
212}
213
214static inline halfword sa_return_item_2(const sa_tree head, halfword n)
215{
216 // if (head->tree) {
217        int hp = LMT_SA_H_PART(n);
218        if (head->tree[hp]) {
219            int mp = LMT_SA_M_PART(n);
220            if (head->tree[hp][mp]) {
221                return (halfword) head->tree[hp][mp][LMT_SA_L_PART(n)/2].ushort_value[n%2];
222            }
223        }
224 // }
225    return (halfword) head->dflt.ushort_value[0];
226}
227
228static inline halfword sa_return_item_4(const sa_tree head, halfword n)
229{
230 // if (head->tree) {
231        int hp = LMT_SA_H_PART(n);
232        if (head->tree[hp]) {
233            int mp = LMT_SA_M_PART(n);
234            if (head->tree[hp][mp]) {
235                return (halfword) head->tree[hp][mp][LMT_SA_L_PART(n)].int_value;
236            }
237        }
238 // }
239    return (halfword) head->dflt.int_value;
240}
241
242static inline void sa_rawset_item_1(const sa_tree head, halfword n, unsigned char v)
243{
244    head->tree[LMT_SA_H_PART(n)][LMT_SA_M_PART(n)][LMT_SA_L_PART(n)/4].uchar_value[n%4] = v;
245}
246
247static inline void sa_rawset_item_2(const sa_tree head, halfword n, unsigned short v)
248{
249    head->tree[LMT_SA_H_PART(n)][LMT_SA_M_PART(n)][LMT_SA_L_PART(n)/2].ushort_value[n%2] = v;
250}
251
252static inline void sa_rawset_item_4(const sa_tree head, halfword n, sa_tree_item v)
253{
254    head->tree[LMT_SA_H_PART(n)][LMT_SA_M_PART(n)][LMT_SA_L_PART(n)] = v;
255}
256
257static inline void sa_rawset_item_8(const sa_tree head, halfword n, sa_tree_item v1, sa_tree_item v2)
258{
259    sa_tree_item *low = head->tree[LMT_SA_H_PART(n)][LMT_SA_M_PART(n)];
260    int l = 2*LMT_SA_L_PART(n);
261    low[l] = v1;
262    low[l+1] = v2;
263}
264
265// inline them
266
267extern void *sa_malloc_array  (int recordsize, int size);
268extern void *sa_realloc_array (void *p, int recordsize, int size, int step);
269extern void *sa_calloc_array  (int recordsize, int size);
270extern void *sa_free_array    (void *p);
271extern void  sa_wipe_array    (void *head, int recordsize, int size);
272
273# endif
274