Revert "Remove Lua 5.1 support"
[lsnes.git] / src / lua / bit.cpp
blob133957f6656d98c9b7d5c3305ca7ff0c0116f611
1 #include "lua/internal.hpp"
2 #include "library/minmax.hpp"
3 #include "library/int24.hpp"
4 #include "library/serialization.hpp"
6 #define BITWISE_BITS 48
7 #define BITWISE_MASK ((1ULL << (BITWISE_BITS)) - 1)
9 namespace
11 uint64_t combine_none(uint64_t chain, uint64_t arg)
13 return (chain & ~arg) & BITWISE_MASK;
16 uint64_t combine_any(uint64_t chain, uint64_t arg)
18 return (chain | arg) & BITWISE_MASK;
21 uint64_t combine_all(uint64_t chain, uint64_t arg)
23 return (chain & arg) & BITWISE_MASK;
26 uint64_t combine_parity(uint64_t chain, uint64_t arg)
28 return (chain ^ arg) & BITWISE_MASK;
31 uint64_t shift_lrotate(uint64_t base, uint64_t amount, uint64_t bits)
33 uint64_t mask = ((1ULL << bits) - 1);
34 base &= mask;
35 base = (base << amount) | (base >> (bits - amount));
36 return base & mask & BITWISE_MASK;
39 uint64_t shift_rrotate(uint64_t base, uint64_t amount, uint64_t bits)
41 uint64_t mask = ((1ULL << bits) - 1);
42 base &= mask;
43 base = (base >> amount) | (base << (bits - amount));
44 return base & mask & BITWISE_MASK;
47 uint64_t shift_lshift(uint64_t base, uint64_t amount, uint64_t bits)
49 uint64_t mask = ((1ULL << bits) - 1);
50 base <<= amount;
51 return base & mask & BITWISE_MASK;
54 uint64_t shift_lrshift(uint64_t base, uint64_t amount, uint64_t bits)
56 uint64_t mask = ((1ULL << bits) - 1);
57 base &= mask;
58 base >>= amount;
59 return base & BITWISE_MASK;
62 uint64_t shift_arshift(uint64_t base, uint64_t amount, uint64_t bits)
64 uint64_t mask = ((1ULL << bits) - 1);
65 base &= mask;
66 bool negative = ((base >> (bits - 1)) != 0);
67 base >>= amount;
68 base |= ((negative ? BITWISE_MASK : 0) << (bits - amount));
69 return base & mask & BITWISE_MASK;
72 template<uint64_t (*combine)(uint64_t chain, uint64_t arg), uint64_t init>
73 int fold(lua::state& L, lua::parameters& P)
75 uint64_t ret = init;
76 while(P.more())
77 ret = combine(ret, P.arg<uint64_t>());
78 L.pushnumber(ret);
79 return 1;
82 template<uint64_t (*sh)(uint64_t base, uint64_t amount, uint64_t bits)>
83 int shift(lua::state& L, lua::parameters& P)
85 uint64_t base, amount, bits;
87 P(base, P.optional(amount, 1), P.optional(bits, BITWISE_BITS));
89 L.pushnumber(sh(base, amount, bits));
90 return 1;
93 template<typename T>
94 int bswap(lua::state& L, lua::parameters& P)
96 T val;
98 P(val);
100 serialization::swap_endian(val);
101 L.pushnumber(val);
102 return 1;
105 int bit_extract(lua::state& L, lua::parameters& P)
107 uint64_t ret = 0;
108 uint64_t num;
110 P(num);
112 for(size_t i = 0;; i++) {
113 if(P.is_boolean()) {
114 if(P.arg<bool>())
115 ret |= (1ULL << i);
116 } else if(P.is_number()) {
117 ret |= (((num >> P.arg<uint8_t>()) & 1) << i);
118 } else
119 break;
121 L.pushnumber(ret);
122 return 1;
125 int bit_value(lua::state& L, lua::parameters& P)
127 uint64_t ret = 0;
128 for(size_t i = 0;; i++) {
129 if(P.is_number()) {
130 ret |= (1ULL << P.arg<uint8_t>());
131 } else if(P.is_nil()) {
132 } else
133 break;
135 L.pushnumber(ret);
136 return 1;
139 template<bool all>
140 int bit_test(lua::state& L, lua::parameters& P)
142 uint64_t a, b;
144 P(a, b);
146 uint64_t t = a & b;
147 bool c = all ? (t == b) : (t != 0);
148 L.pushboolean(c);
149 return 1;
152 template<bool complement>
153 int bit_test2(lua::state& L, lua::parameters& P)
155 uint64_t a, b;
157 P(a, b);
159 uint64_t t = a & (1ULL << b);
160 L.pushboolean((t != 0) != complement);
161 return 1;
164 const int CONST_poptable[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
166 int popcount(uint64_t x)
168 int c = 0;
169 for(unsigned i = 0; i < 16; i++) {
170 c += CONST_poptable[x & 15];
171 x >>= 4;
173 return c;
176 int bit_popcount(lua::state& L, lua::parameters& P)
178 uint64_t a;
180 P(a);
182 L.pushnumber(popcount(a));
183 return 1;
186 template<bool right>
187 int bit_cshift(lua::state& L, lua::parameters& P)
189 uint64_t a, b;
190 unsigned amount, bits;
192 P(a, b, P.optional(amount, 1), P.optional(bits, BITWISE_BITS));
194 uint64_t mask = ((1ULL << bits) - 1);
195 a &= mask;
196 b &= mask;
197 if(right) {
198 b >>= amount;
199 b |= (a << (bits - amount));
200 b &= mask;
201 a >>= amount;
202 } else {
203 a <<= amount;
204 a &= mask;
205 a |= (b >> (bits - amount));
206 b <<= amount;
207 b &= mask;
209 L.pushnumber(a);
210 L.pushnumber(b);
211 return 2;
214 template<bool reverse>
215 int flagdecode_core(lua::state& L, lua::parameters& P)
217 uint64_t a, b;
218 std::string on, off;
220 P(a, b, P.optional(on, ""), P.optional(off, ""));
222 size_t onl = on.length();
223 size_t offl = off.length();
224 char onc = onl ? on[onl - 1] : '*';
225 char offc = offl ? off[offl - 1] : '-';
226 char buffer[65];
227 unsigned i;
228 size_t bias = min(b, (uint64_t)64) - 1;
229 for(i = 0; i < 64 && i < b; i++) {
230 char onc2 = (i < onl) ? on[i] : onc;
231 char offc2 = (i < offl) ? off[i] : offc;
232 buffer[reverse ? (bias - i) : i] = ((a >> i) & 1) ? onc2 : offc2;
234 buffer[i] = '\0';
235 L.pushstring(buffer);
236 return 1;
239 int bit_compose(lua::state& L, lua::parameters& P)
241 uint64_t res = 0;
242 uint8_t shift = 0;
243 while(P.more()) {
244 uint64_t t;
245 P(t);
246 res |= (t << shift);
247 shift += 8;
249 L.pushnumber(res);
250 return 1;
253 template<typename T, bool littleendian>
254 int bit_ldbinarynumber(lua::state& L, lua::parameters& P)
256 size_t pos;
257 const char* str;
258 size_t len;
260 str = L.tolstring(P.skip(), len);
261 P(pos);
263 if(pos + sizeof(T) > len)
264 throw std::runtime_error(P.get_fname() + ": Offset out of range");
266 L.pushnumber(serialization::read_endian<T>(str + pos, littleendian ? -1 : 1));
267 return 1;
270 template<typename T, bool littleendian>
271 int bit_stbinarynumber(lua::state& L, lua::parameters& P)
273 T val;
274 char buffer[sizeof(T)];
276 P(val);
278 serialization::write_endian<T>(buffer, val, littleendian ? -1 : 1);
279 L.pushlstring(buffer, sizeof(T));
280 return 1;
283 int bit_quotent(lua::state& L, lua::parameters& P)
285 int64_t a, b;
287 P(a, b);
289 L.pushnumber(a / b);
290 return 1;
293 int bit_multidiv(lua::state& L, lua::parameters& P)
295 double v;
296 unsigned values = L.gettop();
298 P(v);
300 for(unsigned i = 1; i < values; i++) {
301 int64_t q;
302 P(q);
303 int64_t qx = v / q;
304 L.pushnumber(qx);
305 v -= qx * q;
307 L.pushnumber(v);
308 return values;
311 int bit_mul32(lua::state& L, lua::parameters& P)
313 uint32_t a, b;
314 uint64_t c;
316 P(a, b);
318 c = (uint64_t)a * b;
319 L.pushnumber(c & 0xFFFFFFFFU);
320 L.pushnumber(c >> 32);
321 return 2;
324 lua::functions LUA_bitops_fn(lua_func_bit, "bit", {
325 {"flagdecode", flagdecode_core<false>},
326 {"rflagdecode", flagdecode_core<true>},
327 {"none", fold<combine_none, BITWISE_MASK>},
328 {"any", fold<combine_any, 0>},
329 {"all", fold<combine_all, BITWISE_MASK>},
330 {"parity", fold<combine_parity, 0>},
331 {"bnot", fold<combine_none, BITWISE_MASK>},
332 {"bor", fold<combine_any, 0>},
333 {"band", fold<combine_all, BITWISE_MASK>},
334 {"bxor", fold<combine_parity, 0>},
335 {"lrotate", shift<shift_lrotate>},
336 {"rrotate", shift<shift_rrotate>},
337 {"lshift", shift<shift_lshift>},
338 {"arshift", shift<shift_arshift>},
339 {"lrshift", shift<shift_lrshift>},
340 {"swapword", bswap<uint16_t>},
341 {"swaphword", bswap<ss_uint24_t>},
342 {"swapdword", bswap<uint32_t>},
343 {"swapqword", bswap<uint64_t>},
344 {"swapsword", bswap<int16_t>},
345 {"swapshword", bswap<ss_int24_t>},
346 {"swapsdword", bswap<int32_t>},
347 {"swapsqword", bswap<int64_t>},
348 {"extract", bit_extract},
349 {"value", bit_value},
350 {"test_any", bit_test<false>},
351 {"test_all", bit_test<true>},
352 {"test", bit_test2<false>},
353 {"testn", bit_test2<true>},
354 {"popcount", bit_popcount},
355 {"clshift", bit_cshift<false>},
356 {"crshift", bit_cshift<true>},
357 {"compose", bit_compose},
358 {"quotent", bit_quotent},
359 {"multidiv", bit_multidiv},
360 {"mul32", bit_mul32},
361 {"binary_ld_u8be", bit_ldbinarynumber<uint8_t, false>},
362 {"binary_ld_s8be", bit_ldbinarynumber<int8_t, false>},
363 {"binary_ld_u16be", bit_ldbinarynumber<uint16_t, false>},
364 {"binary_ld_s16be", bit_ldbinarynumber<int16_t, false>},
365 {"binary_ld_u24be", bit_ldbinarynumber<ss_uint24_t, false>},
366 {"binary_ld_s24be", bit_ldbinarynumber<ss_int24_t, false>},
367 {"binary_ld_u32be", bit_ldbinarynumber<uint32_t, false>},
368 {"binary_ld_s32be", bit_ldbinarynumber<int32_t, false>},
369 {"binary_ld_u64be", bit_ldbinarynumber<uint64_t, false>},
370 {"binary_ld_s64be", bit_ldbinarynumber<int64_t, false>},
371 {"binary_ld_floatbe", bit_ldbinarynumber<float, false>},
372 {"binary_ld_doublebe", bit_ldbinarynumber<double, false>},
373 {"binary_ld_u8le", bit_ldbinarynumber<uint8_t, true>},
374 {"binary_ld_s8le", bit_ldbinarynumber<int8_t, true>},
375 {"binary_ld_u16le", bit_ldbinarynumber<uint16_t, true>},
376 {"binary_ld_s16le", bit_ldbinarynumber<int16_t, true>},
377 {"binary_ld_u24le", bit_ldbinarynumber<ss_uint24_t, true>},
378 {"binary_ld_s24le", bit_ldbinarynumber<ss_int24_t, true>},
379 {"binary_ld_u32le", bit_ldbinarynumber<uint32_t, true>},
380 {"binary_ld_s32le", bit_ldbinarynumber<int32_t, true>},
381 {"binary_ld_u64le", bit_ldbinarynumber<uint64_t, true>},
382 {"binary_ld_s64le", bit_ldbinarynumber<int64_t, true>},
383 {"binary_ld_floatle", bit_ldbinarynumber<float, true>},
384 {"binary_ld_doublele", bit_ldbinarynumber<double, true>},
385 {"binary_st_u8be", bit_stbinarynumber<uint8_t, false>},
386 {"binary_st_s8be", bit_stbinarynumber<int8_t, false>},
387 {"binary_st_u16be", bit_stbinarynumber<uint16_t, false>},
388 {"binary_st_s16be", bit_stbinarynumber<int16_t, false>},
389 {"binary_st_u24be", bit_stbinarynumber<ss_uint24_t, false>},
390 {"binary_st_s24be", bit_stbinarynumber<ss_int24_t, false>},
391 {"binary_st_u32be", bit_stbinarynumber<uint32_t, false>},
392 {"binary_st_s32be", bit_stbinarynumber<int32_t, false>},
393 {"binary_st_u64be", bit_stbinarynumber<uint64_t, false>},
394 {"binary_st_s64be", bit_stbinarynumber<int64_t, false>},
395 {"binary_st_floatbe", bit_stbinarynumber<float, false>},
396 {"binary_st_doublebe", bit_stbinarynumber<double, false>},
397 {"binary_st_u8le", bit_stbinarynumber<uint8_t, true>},
398 {"binary_st_s8le", bit_stbinarynumber<int8_t, true>},
399 {"binary_st_u16le", bit_stbinarynumber<uint16_t, true>},
400 {"binary_st_s16le", bit_stbinarynumber<int16_t, true>},
401 {"binary_st_u24le", bit_stbinarynumber<ss_uint24_t, true>},
402 {"binary_st_s24le", bit_stbinarynumber<ss_int24_t, true>},
403 {"binary_st_u32le", bit_stbinarynumber<uint32_t, true>},
404 {"binary_st_s32le", bit_stbinarynumber<int32_t, true>},
405 {"binary_st_u64le", bit_stbinarynumber<uint64_t, true>},
406 {"binary_st_s64le", bit_stbinarynumber<int64_t, true>},
407 {"binary_st_floatle", bit_stbinarynumber<float, true>},
408 {"binary_st_doublele", bit_stbinarynumber<double, true>},