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