bit.(r)flagdecode: Fix unicode in on/off strings
[lsnes.git] / src / lua / bit.cpp
blob1edf4be4f3dc637c9c4b5238bd77b02f0b717a2b
1 #include "lua/internal.hpp"
2 #include "library/minmax.hpp"
3 #include "library/int24.hpp"
4 #include "library/serialization.hpp"
6 namespace
8 template<unsigned nbits>
9 uint64_t maskn()
11 if(nbits > 63)
12 return 0xFFFFFFFFFFFFFFFFULL;
13 else
14 return (1ULL << (nbits&63)) - 1;
17 uint64_t maskx(unsigned nbits)
19 if(nbits > 63)
20 return 0xFFFFFFFFFFFFFFFFULL;
21 else
22 return (1ULL << (nbits&63)) - 1;
25 template<unsigned nbits>
26 uint64_t combine_none(uint64_t chain, uint64_t arg)
28 return (chain & ~arg) & maskn<nbits>();
31 template<unsigned nbits>
32 uint64_t combine_any(uint64_t chain, uint64_t arg)
34 return (chain | arg) & maskn<nbits>();
37 template<unsigned nbits>
38 uint64_t combine_all(uint64_t chain, uint64_t arg)
40 return (chain & arg) & maskn<nbits>();
43 template<unsigned nbits>
44 uint64_t combine_parity(uint64_t chain, uint64_t arg)
46 return (chain ^ arg) & maskn<nbits>();
49 template<unsigned nbits>
50 uint64_t shift_lrotate(uint64_t base, uint64_t amount, uint64_t bits)
52 uint64_t mask = maskx(bits);
53 base &= mask;
54 base = (base << amount) | (base >> (bits - amount));
55 return base & mask & maskn<nbits>();
58 template<unsigned nbits>
59 uint64_t shift_rrotate(uint64_t base, uint64_t amount, uint64_t bits)
61 uint64_t mask = maskx(bits);
62 base &= mask;
63 base = (base >> amount) | (base << (bits - amount));
64 return base & mask & maskn<nbits>();
67 template<unsigned nbits>
68 uint64_t shift_lshift(uint64_t base, uint64_t amount, uint64_t bits)
70 uint64_t mask = maskx(bits);
71 base <<= amount;
72 return base & mask & maskn<nbits>();
75 template<unsigned nbits>
76 uint64_t shift_lrshift(uint64_t base, uint64_t amount, uint64_t bits)
78 uint64_t mask = maskx(bits);
79 base &= mask;
80 base >>= amount;
81 return base & maskn<nbits>();
84 template<unsigned nbits>
85 uint64_t shift_arshift(uint64_t base, uint64_t amount, uint64_t bits)
87 uint64_t mask = maskx(bits);
88 base &= mask;
89 bool negative = ((base >> (bits - 1)) != 0);
90 base >>= amount;
91 base |= ((negative ? maskn<nbits>() : 0) << (bits - amount));
92 return base & mask & maskn<nbits>();
95 uint64_t zero()
97 return 0;
100 template<unsigned nbits>
101 uint64_t ones()
103 return maskn<nbits>();
106 template<uint64_t (*combine)(uint64_t chain, uint64_t arg), uint64_t (*init)()>
107 int fold(lua::state& L, lua::parameters& P)
109 uint64_t ret = init();
110 while(P.more())
111 ret = combine(ret, P.arg<uint64_t>());
112 L.pushnumber(ret);
113 return 1;
116 template<uint64_t (*sh)(uint64_t base, uint64_t amount, uint64_t bits), unsigned nbits>
117 int shift(lua::state& L, lua::parameters& P)
119 uint64_t base, amount, bits;
121 P(base, P.optional(amount, 1), P.optional(bits, nbits));
123 L.pushnumber(sh(base, amount, bits));
124 return 1;
127 template<typename T>
128 int bswap(lua::state& L, lua::parameters& P)
130 T val;
132 P(val);
134 serialization::swap_endian(val);
135 L.pushnumber(val);
136 return 1;
139 int bit_extract(lua::state& L, lua::parameters& P)
141 uint64_t ret = 0;
142 uint64_t num;
144 P(num);
146 for(size_t i = 0;; i++) {
147 if(P.is_boolean()) {
148 if(P.arg<bool>())
149 ret |= (1ULL << i);
150 } else if(P.is_number()) {
151 ret |= (((num >> P.arg<uint8_t>()) & 1) << i);
152 } else
153 break;
155 L.pushnumber(ret);
156 return 1;
159 int bit_value(lua::state& L, lua::parameters& P)
161 uint64_t ret = 0;
162 for(size_t i = 0;; i++) {
163 if(P.is_number()) {
164 ret |= (1ULL << P.arg<uint8_t>());
165 } else if(P.is_nil()) {
166 } else
167 break;
169 L.pushnumber(ret);
170 return 1;
173 template<bool all>
174 int bit_test(lua::state& L, lua::parameters& P)
176 uint64_t a, b;
178 P(a, b);
180 uint64_t t = a & b;
181 bool c = all ? (t == b) : (t != 0);
182 L.pushboolean(c);
183 return 1;
186 template<bool complement>
187 int bit_test2(lua::state& L, lua::parameters& P)
189 uint64_t a, b;
191 P(a, b);
193 uint64_t t = a & (1ULL << b);
194 L.pushboolean((t != 0) != complement);
195 return 1;
198 const int CONST_poptable[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
200 int popcount(uint64_t x)
202 int c = 0;
203 for(unsigned i = 0; i < 16; i++) {
204 c += CONST_poptable[x & 15];
205 x >>= 4;
207 return c;
210 int bit_popcount(lua::state& L, lua::parameters& P)
212 uint64_t a;
214 P(a);
216 L.pushnumber(popcount(a));
217 return 1;
220 template<bool right, unsigned nbits>
221 int bit_cshift(lua::state& L, lua::parameters& P)
223 uint64_t a, b;
224 unsigned amount, bits;
226 P(a, b, P.optional(amount, 1), P.optional(bits, nbits));
228 uint64_t mask = maskx(bits);
229 a &= mask;
230 b &= mask;
231 if(right) {
232 b >>= amount;
233 b |= (a << (bits - amount));
234 b &= mask;
235 a >>= amount;
236 } else {
237 a <<= amount;
238 a &= mask;
239 a |= (b >> (bits - amount));
240 b <<= amount;
241 b &= mask;
243 L.pushnumber(a);
244 L.pushnumber(b);
245 return 2;
248 template<bool reverse>
249 int flagdecode_core(lua::state& L, lua::parameters& P)
251 uint64_t a, b;
252 std::string on, off;
254 P(a, b, P.optional(on, ""), P.optional(off, ""));
256 auto on32 = utf8::to32(on);
257 auto off32 = utf8::to32(off);
259 size_t onl = on32.length();
260 size_t offl = off32.length();
261 auto onc = onl ? on32[onl - 1] : '*';
262 auto offc = offl ? off32[offl - 1] : '-';
263 char32_t buffer[65];
264 unsigned i;
265 size_t bias = min(b, (uint64_t)64) - 1;
266 for(i = 0; i < 64 && i < b; i++) {
267 auto onc2 = (i < onl) ? on32[i] : onc;
268 auto offc2 = (i < offl) ? off32[i] : offc;
269 buffer[reverse ? (bias - i) : i] = ((a >> i) & 1) ? onc2 : offc2;
271 buffer[i] = '\0';
272 L.pushlstring(utf8::to8(buffer));
273 return 1;
276 int bit_compose(lua::state& L, lua::parameters& P)
278 uint64_t res = 0;
279 uint8_t shift = 0;
280 while(P.more()) {
281 uint64_t t;
282 P(t);
283 res |= (t << shift);
284 shift += 8;
286 L.pushnumber(res);
287 return 1;
290 template<typename T, bool littleendian>
291 int bit_ldbinarynumber(lua::state& L, lua::parameters& P)
293 size_t pos;
294 const char* str;
295 size_t len;
297 str = L.tolstring(P.skip(), len);
298 P(pos);
300 if(pos + sizeof(T) > len)
301 throw std::runtime_error(P.get_fname() + ": Offset out of range");
303 L.pushnumber(serialization::read_endian<T>(str + pos, littleendian ? -1 : 1));
304 return 1;
307 template<typename T, bool littleendian>
308 int bit_stbinarynumber(lua::state& L, lua::parameters& P)
310 T val;
311 char buffer[sizeof(T)];
313 P(val);
315 serialization::write_endian<T>(buffer, val, littleendian ? -1 : 1);
316 L.pushlstring(buffer, sizeof(T));
317 return 1;
320 int bit_quotent(lua::state& L, lua::parameters& P)
322 int64_t a, b;
324 P(a, b);
326 L.pushnumber(a / b);
327 return 1;
330 int bit_multidiv(lua::state& L, lua::parameters& P)
332 double v;
333 unsigned values = L.gettop();
335 P(v);
337 for(unsigned i = 1; i < values; i++) {
338 int64_t q;
339 P(q);
340 int64_t qx = v / q;
341 L.pushnumber(qx);
342 v -= qx * q;
344 L.pushnumber(v);
345 return values;
348 int bit_mul32(lua::state& L, lua::parameters& P)
350 uint32_t a, b;
351 uint64_t c;
353 P(a, b);
355 c = (uint64_t)a * b;
356 L.pushnumber(c & 0xFFFFFFFFU);
357 L.pushnumber(c >> 32);
358 return 2;
361 lua::functions LUA_bitops_fn(lua_func_bit, "bit", {
362 {"flagdecode", flagdecode_core<false>},
363 {"rflagdecode", flagdecode_core<true>},
364 {"none", fold<combine_none<48>, ones<48>>},
365 {"any", fold<combine_any<48>, zero>},
366 {"all", fold<combine_all<48>, ones<48>>},
367 {"parity", fold<combine_parity<48>, zero>},
368 {"bnot", fold<combine_none<48>, ones<48>>},
369 {"bor", fold<combine_any<48>, zero>},
370 {"band", fold<combine_all<48>, ones<48>>},
371 {"bxor", fold<combine_parity<48>, zero>},
372 {"lrotate", shift<shift_lrotate<48>, 48>},
373 {"rrotate", shift<shift_rrotate<48>, 48>},
374 {"lshift", shift<shift_lshift<48>, 48>},
375 {"arshift", shift<shift_arshift<48>, 48>},
376 {"lrshift", shift<shift_lrshift<48>, 48>},
377 #ifdef LUA_SUPPORTS_INTEGERS
378 {"wnone", fold<combine_none<64>, ones<64>>},
379 {"wany", fold<combine_any<64>, zero>},
380 {"wall", fold<combine_all<64>, ones<64>>},
381 {"wparity", fold<combine_parity<64>, zero>},
382 {"wbnot", fold<combine_none<64>, ones<64>>},
383 {"wbor", fold<combine_any<64>, zero>},
384 {"wband", fold<combine_all<64>, ones<64>>},
385 {"wbxor", fold<combine_parity<64>, zero>},
386 {"wlrotate", shift<shift_lrotate<64>, 64>},
387 {"wrrotate", shift<shift_rrotate<64>, 64>},
388 {"wlshift", shift<shift_lshift<64>, 64>},
389 {"warshift", shift<shift_arshift<64>, 64>},
390 {"wlrshift", shift<shift_lrshift<64>, 64>},
391 {"wclshift", bit_cshift<false, 64>},
392 {"wcrshift", bit_cshift<true, 64>},
393 #endif
394 {"swapword", bswap<uint16_t>},
395 {"swaphword", bswap<ss_uint24_t>},
396 {"swapdword", bswap<uint32_t>},
397 {"swapqword", bswap<uint64_t>},
398 {"swapsword", bswap<int16_t>},
399 {"swapshword", bswap<ss_int24_t>},
400 {"swapsdword", bswap<int32_t>},
401 {"swapsqword", bswap<int64_t>},
402 {"extract", bit_extract},
403 {"value", bit_value},
404 {"test_any", bit_test<false>},
405 {"test_all", bit_test<true>},
406 {"test", bit_test2<false>},
407 {"testn", bit_test2<true>},
408 {"popcount", bit_popcount},
409 {"clshift", bit_cshift<false, 48>},
410 {"crshift", bit_cshift<true, 48>},
411 {"compose", bit_compose},
412 {"quotent", bit_quotent},
413 {"multidiv", bit_multidiv},
414 {"mul32", bit_mul32},
415 {"binary_ld_u8be", bit_ldbinarynumber<uint8_t, false>},
416 {"binary_ld_s8be", bit_ldbinarynumber<int8_t, false>},
417 {"binary_ld_u16be", bit_ldbinarynumber<uint16_t, false>},
418 {"binary_ld_s16be", bit_ldbinarynumber<int16_t, false>},
419 {"binary_ld_u24be", bit_ldbinarynumber<ss_uint24_t, false>},
420 {"binary_ld_s24be", bit_ldbinarynumber<ss_int24_t, false>},
421 {"binary_ld_u32be", bit_ldbinarynumber<uint32_t, false>},
422 {"binary_ld_s32be", bit_ldbinarynumber<int32_t, false>},
423 {"binary_ld_u64be", bit_ldbinarynumber<uint64_t, false>},
424 {"binary_ld_s64be", bit_ldbinarynumber<int64_t, false>},
425 {"binary_ld_floatbe", bit_ldbinarynumber<float, false>},
426 {"binary_ld_doublebe", bit_ldbinarynumber<double, false>},
427 {"binary_ld_u8le", bit_ldbinarynumber<uint8_t, true>},
428 {"binary_ld_s8le", bit_ldbinarynumber<int8_t, true>},
429 {"binary_ld_u16le", bit_ldbinarynumber<uint16_t, true>},
430 {"binary_ld_s16le", bit_ldbinarynumber<int16_t, true>},
431 {"binary_ld_u24le", bit_ldbinarynumber<ss_uint24_t, true>},
432 {"binary_ld_s24le", bit_ldbinarynumber<ss_int24_t, true>},
433 {"binary_ld_u32le", bit_ldbinarynumber<uint32_t, true>},
434 {"binary_ld_s32le", bit_ldbinarynumber<int32_t, true>},
435 {"binary_ld_u64le", bit_ldbinarynumber<uint64_t, true>},
436 {"binary_ld_s64le", bit_ldbinarynumber<int64_t, true>},
437 {"binary_ld_floatle", bit_ldbinarynumber<float, true>},
438 {"binary_ld_doublele", bit_ldbinarynumber<double, true>},
439 {"binary_st_u8be", bit_stbinarynumber<uint8_t, false>},
440 {"binary_st_s8be", bit_stbinarynumber<int8_t, false>},
441 {"binary_st_u16be", bit_stbinarynumber<uint16_t, false>},
442 {"binary_st_s16be", bit_stbinarynumber<int16_t, false>},
443 {"binary_st_u24be", bit_stbinarynumber<ss_uint24_t, false>},
444 {"binary_st_s24be", bit_stbinarynumber<ss_int24_t, false>},
445 {"binary_st_u32be", bit_stbinarynumber<uint32_t, false>},
446 {"binary_st_s32be", bit_stbinarynumber<int32_t, false>},
447 {"binary_st_u64be", bit_stbinarynumber<uint64_t, false>},
448 {"binary_st_s64be", bit_stbinarynumber<int64_t, false>},
449 {"binary_st_floatbe", bit_stbinarynumber<float, false>},
450 {"binary_st_doublebe", bit_stbinarynumber<double, false>},
451 {"binary_st_u8le", bit_stbinarynumber<uint8_t, true>},
452 {"binary_st_s8le", bit_stbinarynumber<int8_t, true>},
453 {"binary_st_u16le", bit_stbinarynumber<uint16_t, true>},
454 {"binary_st_s16le", bit_stbinarynumber<int16_t, true>},
455 {"binary_st_u24le", bit_stbinarynumber<ss_uint24_t, true>},
456 {"binary_st_s24le", bit_stbinarynumber<ss_int24_t, true>},
457 {"binary_st_u32le", bit_stbinarynumber<uint32_t, true>},
458 {"binary_st_s32le", bit_stbinarynumber<int32_t, true>},
459 {"binary_st_u64le", bit_stbinarynumber<uint64_t, true>},
460 {"binary_st_s64le", bit_stbinarynumber<int64_t, true>},
461 {"binary_st_floatle", bit_stbinarynumber<float, true>},
462 {"binary_st_doublele", bit_stbinarynumber<double, true>},