1
4
5# include "luametatex.h"
6
7
17
18# define SPARSE_STACK 8
19# define SPARSE_BYTES 4
20
21typedef struct sa_tree_object {
22 sa_tree tree;
23 int min;
24 int max;
25} sa_tree_object;
26
27static sa_tree_object *sparselib_aux_check_is_sa_object(lua_State *L, int n)
28{
29 sa_tree_object *o = (sa_tree_object *) lua_touserdata(L, n);
30 if (o && lua_getmetatable(L, n)) {
31 lua_get_metatablelua(sparse_instance);
32 if (! lua_rawequal(L, -1, -2)) {
33 o = NULL;
34 }
35 lua_pop(L, 2);
36 if (o) {
37 return o;
38 }
39 }
40 tex_normal_warning("sparse lib", "lua <sparse object> expected");
41 return NULL;
42}
43
44
45
46static int sparselib_new(lua_State *L)
47{
48 int bytes = lmt_optinteger(L, 1, SPARSE_BYTES);
49 int defval = lmt_optinteger(L, 2, 0);
50 sa_tree_item item = { .int_value = defval };
51 sa_tree_object *o = lua_newuserdatauv(L, sizeof(sa_tree_object), 0);
52 switch (bytes) {
53 case 1:
54 {
55 int d = defval < 0 ? 0 : (defval > 0xFF ? 0xFF : defval);
56 for (int i = 0; i <= 3; i++) {
57 item.uchar_value[i] = (unsigned char) d;
58 }
59 break;
60 }
61 case 2:
62 {
63 int d = defval < 0 ? 0 : (defval > 0xFFFF ? 0xFFFF : defval);
64 for (int i = 0; i <= 1; i++) {
65 item.ushort_value[i] = (unsigned short) d;
66 }
67 break;
68 }
69 case 4:
70 break;
71 default:
72 bytes = SPARSE_BYTES;
73 break;
74 }
75 o->tree = sa_new_tree(SPARSE_STACK, bytes, item);
76 o->min = -1;
77 o->max = -1;
78 luaL_setmetatable(L, SPARSE_METATABLE_INSTANCE);
79 return 1;
80}
81
82static int sparselib_gc(lua_State *L)
83{
84 sa_tree_object *o = (sa_tree_object *) lua_touserdata(L, 1);
85 if (o) {
86 sa_destroy_tree(o->tree);
87 }
88 return 0;
89}
90
91static int sparselib_tostring(lua_State *L) {
92 sa_tree_object *o = sparselib_aux_check_is_sa_object(L, 1);
93 if (o) {
94 lua_pushfstring(L, "<sa.object %p>", o->tree);
95 return 1;
96 } else {
97 return 0;
98 }
99}
100
101
102
103static int sparselib_set(lua_State *L)
104{
105 sa_tree_object *o = sparselib_aux_check_is_sa_object(L, 1);
106 if (o) {
107 quarterword level;
108 int slot = lmt_check_for_level(L, 2, &level, cur_level);
109 int n = lmt_tointeger(L, slot++);
110 if (n >= 0) {
111 int v = lmt_optinteger(L, slot++, 1);
112 if (o->min < 0) {
113 o->min = n;
114 o->max = n;
115 } else if (n < o->min) {
116 o->min = n;
117 } else if (n > o->max) {
118 o->max = n;
119 }
120 sa_set_item_n(o->tree, n, v, (int) level);
121 }
122 }
123 return 0;
124}
125
126
127
128static int sparselib_get(lua_State *L)
129{
130 sa_tree_object *o = sparselib_aux_check_is_sa_object(L, 1);
131 if (o) {
132 int n = lmt_tointeger(L, 2);
133 if (n >= 0) {
134 lua_pushinteger(L, sa_get_item_n(o->tree, n));
135 return 1;
136 }
137 }
138 lua_pushnil(L);
139 return 1;
140}
141
142static int sparselib_min(lua_State *L)
143{
144 sa_tree_object *o = sparselib_aux_check_is_sa_object(L, 1);
145 if (o) {
146 lua_pushinteger(L, o->min >= 0 ? o->min : 0);
147 } else {
148 lua_pushnil(L);
149 }
150 return 1;
151}
152
153static int sparselib_max(lua_State *L)
154{
155 sa_tree_object *o = sparselib_aux_check_is_sa_object(L, 1);
156 if (o) {
157 lua_pushinteger(L, o->max >= 0 ? o->max : 0);
158 } else {
159 lua_pushnil(L);
160 }
161 return 1;
162}
163
164static int sparselib_range(lua_State *L)
165{
166 sa_tree_object *o = sparselib_aux_check_is_sa_object(L, 1);
167 if (o) {
168 lua_pushinteger(L, o->min >= 0 ? o->min : 0);
169 lua_pushinteger(L, o->max >= 0 ? o->max : 0);
170 } else {
171 lua_pushnil(L);
172 lua_pushnil(L);
173 }
174 return 2;
175}
176
177static int sparselib_aux_nil(lua_State *L)
178{
179 lua_pushnil(L);
180 return 1;
181}
182
183static int sparselib_aux_next(lua_State *L)
184{
185 sa_tree_object *o = (sa_tree_object *) lua_touserdata(L, lua_upvalueindex(1));
186 int ind = lmt_tointeger(L, lua_upvalueindex(2));
187 if (ind <= o->max) {
188 lua_pushinteger(L, (lua_Integer) ind + 1);
189 lua_replace(L, lua_upvalueindex(2));
190 lua_pushinteger(L, ind);
191 lua_pushinteger(L, sa_get_item_n(o->tree, ind));
192 return 2;
193 } else {
194 return 0;
195 }
196}
197
198static int sparselib_traverse(lua_State *L)
199{
200 sa_tree_object *o = sparselib_aux_check_is_sa_object(L, 1);
201 if (o && o->min >= 0) {
202 lua_settop(L, 1);
203 lua_pushinteger(L, o->min);
204 lua_pushcclosure(L, sparselib_aux_next, 2);
205 } else {
206 lua_pushcclosure(L, sparselib_aux_nil, 0);
207 }
208 return 1;
209}
210
211typedef enum concat_options {
212 concat_as_byte = 0,
213 concat_as_lsb = 1,
214 concat_as_msb = 2,
215} concat_options;
216
217inline static char sparselib_aux_concat(sa_tree t, int i)
218{
219 int h = LMT_SA_H_PART(i);
220 if (t->tree[h]) {
221 int m = LMT_SA_M_PART(i);
222 if (t->tree[h][m]) {
223 return (char) t->tree[h][m][LMT_SA_L_PART(i)/4].uchar_value[i%4];
224 } else {
225 return (char) t->dflt.uchar_value[i%4];
226 }
227 } else {
228 return (char) t->dflt.uchar_value[i%4];
229 }
230}
231
232static int sparselib_concat(lua_State *L)
233{
234 sa_tree_object *o = sparselib_aux_check_is_sa_object(L, 1);
235 if (o) {
236 sa_tree t = o->tree;
237 if (t->bytes == 1) {
238
239 luaL_Buffer buffer;
240 int min = lmt_optinteger(L, 2, o->min);
241 int max = lmt_optinteger(L, 3, o->max);
242 int how = lmt_optinteger(L, 4, concat_as_byte);
243 int siz = 0;
244 if (min < 0) {
245 min = 0;
246 }
247 if (max < min) {
248 max = min;
249 }
250 siz = (size_t) max - (size_t) min + 1;
251 luaL_buffinitsize(L, &buffer, siz);
252 switch (how) {
253 case concat_as_lsb:
254 case concat_as_msb:
255 {
256 int n = 0;
257 char b = 0;
258 luaL_buffinitsize(L, &buffer, (siz / 8) + 1);
259 for (int i = min; i <= max; i++) {
260 char c = sparselib_aux_concat(t, i);
261 if (c) {
262 b |= how == concat_as_lsb ? (1 << n) : (1 << (7 - n));
263 }
264 if (++n == 8) {
265 luaL_addlstring(&buffer, &b, 1);
266 n = 0;
267 }
268 }
269 if (n) {
270 luaL_addlstring(&buffer, &b, 1);
271 }
272 }
273 break;
274 default:
275 {
276 luaL_buffinitsize(L, &buffer, siz);
277 for (int i = min; i <= max; i++) {
278 char c = sparselib_aux_concat(t, i);
279 luaL_addlstring(&buffer, &c, 1);
280 }
281 }
282 break;
283 }
284 luaL_pushresult(&buffer);
285 return 1;
286 }
287 }
288 lua_pushnil(L);
289 return 1;
290}
291
292static int sparselib_restore(lua_State *L)
293{
294 sa_tree_object *o = sparselib_aux_check_is_sa_object(L, 1);
295 if (o) {
296
297 sa_restore_stack(o->tree, cur_level+1);
298 }
299 return 0;
300}
301
302static int sparselib_wipe(lua_State *L)
303{
304 sa_tree_object *o = sparselib_aux_check_is_sa_object(L, 1);
305 if (o) {
306 int bytes = o->tree->bytes;
307 sa_tree_item dflt = o->tree->dflt;
308 sa_destroy_tree(o->tree);
309 o->tree = sa_new_tree(SPARSE_STACK, bytes, dflt);
310 o->min = -1;
311 o->max = -1;
312 }
313 return 0;
314}
315
316static const struct luaL_Reg sparselib_instance[] = {
317 { "__tostring", sparselib_tostring },
318 { "__gc", sparselib_gc },
319 { "__index", sparselib_get },
320 { "__newindex", sparselib_set },
321 { NULL, NULL },
322};
323
324static const luaL_Reg sparselib_function_list[] =
325{
326 { "new", sparselib_new },
327 { "set", sparselib_set },
328 { "get", sparselib_get },
329 { "min", sparselib_min },
330 { "max", sparselib_max },
331 { "range", sparselib_range },
332 { "traverse", sparselib_traverse },
333 { "concat", sparselib_concat },
334 { "restore", sparselib_restore },
335 { "wipe", sparselib_wipe },
336 { NULL, NULL },
337};
338
339int luaopen_sparse(lua_State *L)
340{
341 luaL_newmetatable(L, SPARSE_METATABLE_INSTANCE);
342 luaL_setfuncs(L, sparselib_instance, 0);
343 lua_newtable(L);
344 luaL_setfuncs(L, sparselib_function_list, 0);
345 return 1;
346}
347 |