Upload UI
[lsnes.git] / src / lua / bit.cpp
blob08e47721723980094f285aa908d73971964697f0
1 #include "lua/internal.hpp"
2 #include "library/minmax.hpp"
4 #define BITWISE_BITS 48
5 #define BITWISE_MASK ((1ULL << (BITWISE_BITS)) - 1)
7 namespace
9 uint64_t combine_none(uint64_t chain, uint64_t arg)
11 return (chain & ~arg) & BITWISE_MASK;
14 uint64_t combine_any(uint64_t chain, uint64_t arg)
16 return (chain | arg) & BITWISE_MASK;
19 uint64_t combine_all(uint64_t chain, uint64_t arg)
21 return (chain & arg) & BITWISE_MASK;
24 uint64_t combine_parity(uint64_t chain, uint64_t arg)
26 return (chain ^ arg) & BITWISE_MASK;
29 uint64_t shift_lrotate(uint64_t base, uint64_t amount, uint64_t bits)
31 uint64_t mask = ((1ULL << bits) - 1);
32 base &= mask;
33 base = (base << amount) | (base >> (bits - amount));
34 return base & mask & BITWISE_MASK;
37 uint64_t shift_rrotate(uint64_t base, uint64_t amount, uint64_t bits)
39 uint64_t mask = ((1ULL << bits) - 1);
40 base &= mask;
41 base = (base >> amount) | (base << (bits - amount));
42 return base & mask & BITWISE_MASK;
45 uint64_t shift_lshift(uint64_t base, uint64_t amount, uint64_t bits)
47 uint64_t mask = ((1ULL << bits) - 1);
48 base <<= amount;
49 return base & mask & BITWISE_MASK;
52 uint64_t shift_lrshift(uint64_t base, uint64_t amount, uint64_t bits)
54 uint64_t mask = ((1ULL << bits) - 1);
55 base &= mask;
56 base >>= amount;
57 return base & BITWISE_MASK;
60 uint64_t shift_arshift(uint64_t base, uint64_t amount, uint64_t bits)
62 uint64_t mask = ((1ULL << bits) - 1);
63 base &= mask;
64 bool negative = ((base >> (bits - 1)) != 0);
65 base >>= amount;
66 base |= ((negative ? BITWISE_MASK : 0) << (bits - amount));
67 return base & mask & BITWISE_MASK;
70 template<uint64_t (*combine)(uint64_t chain, uint64_t arg), uint64_t init>
71 class lua_symmetric_bitwise : public lua_function
73 public:
74 lua_symmetric_bitwise(const std::string& s) : lua_function(lua_func_bit, s) {};
75 int invoke(lua_state& L)
77 int stacksize = 0;
78 while(!L.isnone(stacksize + 1))
79 stacksize++;
80 uint64_t ret = init;
81 for(int i = 0; i < stacksize; i++)
82 ret = combine(ret, L.get_numeric_argument<uint64_t>(i + 1, fname.c_str()));
83 L.pushnumber(ret);
84 return 1;
88 template<uint64_t (*shift)(uint64_t base, uint64_t amount, uint64_t bits)>
89 class lua_shifter : public lua_function
91 public:
92 lua_shifter(const std::string& s) : lua_function(lua_func_bit, s) {};
93 int invoke(lua_state& L)
95 uint64_t base;
96 uint64_t amount = 1;
97 uint64_t bits = BITWISE_BITS;
98 base = L.get_numeric_argument<uint64_t>(1, fname.c_str());
99 L.get_numeric_argument(2, amount, fname.c_str());
100 L.get_numeric_argument(3, bits, fname.c_str());
101 L.pushnumber(shift(base, amount, bits));
102 return 1;
106 function_ptr_luafun lua_bextract(lua_func_bit, "bit.extract", [](lua_state& L, const std::string& fname)
107 -> int {
108 uint64_t num = L.get_numeric_argument<uint64_t>(1, fname.c_str());
109 uint64_t ret = 0;
110 for(size_t i = 0;; i++) {
111 if(L.isboolean(i + 2)) {
112 if(L.toboolean(i + 2))
113 ret |= (1ULL << i);
114 } else if(L.isnumber(i + 2)) {
115 uint8_t bit = L.get_numeric_argument<uint8_t>(i + 2, fname.c_str());
116 ret |= (((num >> bit) & 1) << i);
117 } else
118 break;
120 L.pushnumber(ret);
121 return 1;
124 function_ptr_luafun lua_bvalue(lua_func_bit, "bit.value", [](lua_state& L, const std::string& fname) -> int {
125 uint64_t ret = 0;
126 for(size_t i = 0;; i++) {
127 if(L.isnumber(i + 1)) {
128 uint8_t bit = L.get_numeric_argument<uint8_t>(i + 1, fname.c_str());
129 ret |= (1ULL << bit);
130 } else if(L.isnil(i + 1)) {
131 } else
132 break;
134 L.pushnumber(ret);
135 return 1;
138 function_ptr_luafun lua_testany(lua_func_bit, "bit.test_any", [](lua_state& L, const std::string& fname)
139 -> int {
140 uint64_t a = L.get_numeric_argument<uint64_t>(1, fname.c_str());
141 uint64_t b = L.get_numeric_argument<uint64_t>(2, fname.c_str());
142 L.pushboolean((a & b) != 0);
143 return 1;
146 function_ptr_luafun lua_testall(lua_func_bit, "bit.test_all", [](lua_state& L, const std::string& fname)
147 -> int {
148 uint64_t a = L.get_numeric_argument<uint64_t>(1, fname.c_str());
149 uint64_t b = L.get_numeric_argument<uint64_t>(2, fname.c_str());
150 L.pushboolean((a & b) == b);
151 return 1;
154 int poptable[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
156 int popcount(uint64_t x)
158 int c = 0;
159 for(unsigned i = 0; i < 16; i++) {
160 c += poptable[x & 15];
161 x >>= 4;
163 return c;
166 function_ptr_luafun lua_popcount(lua_func_bit, "bit.popcount", [](lua_state& L, const std::string& fname)
167 -> int {
168 uint64_t a = L.get_numeric_argument<uint64_t>(1, fname.c_str());
169 L.pushnumber(popcount(a));
170 return 1;
173 function_ptr_luafun lua_clshift(lua_func_bit, "bit.clshift", [](lua_state& L, const std::string& fname)
174 -> int {
175 unsigned amount = 1;
176 unsigned bits = 48;
177 uint64_t a = L.get_numeric_argument<uint64_t>(1, fname.c_str());
178 uint64_t b = L.get_numeric_argument<uint64_t>(2, fname.c_str());
179 L.get_numeric_argument(3, amount, fname.c_str());
180 L.get_numeric_argument(4, bits, fname.c_str());
181 uint64_t mask = ((1ULL << bits) - 1);
182 a &= mask;
183 b &= mask;
184 a <<= amount;
185 a &= mask;
186 a |= (b >> (bits - amount));
187 b <<= amount;
188 b &= mask;
189 L.pushnumber(a);
190 L.pushnumber(b);
191 return 2;
194 function_ptr_luafun lua_crshift(lua_func_bit, "bit.crshift", [](lua_state& L, const std::string& fname)
195 -> int {
196 unsigned amount = 1;
197 unsigned bits = 48;
198 uint64_t a = L.get_numeric_argument<uint64_t>(1, fname.c_str());
199 uint64_t b = L.get_numeric_argument<uint64_t>(2, fname.c_str());
200 L.get_numeric_argument(3, amount, fname.c_str());
201 L.get_numeric_argument(4, bits, fname.c_str());
202 uint64_t mask = ((1ULL << bits) - 1);
203 a &= mask;
204 b &= mask;
205 b >>= amount;
206 b |= (a << (bits - amount));
207 b &= mask;
208 a >>= amount;
209 L.pushnumber(a);
210 L.pushnumber(b);
211 return 2;
214 int flagdecode_core(lua_state& L, const std::string& fname, bool reverse)
216 uint64_t a = L.get_numeric_argument<uint64_t>(1, fname.c_str());
217 uint64_t b = L.get_numeric_argument<uint64_t>(2, fname.c_str());
218 std::string on, off;
219 if(L.type(3) == LUA_TSTRING)
220 on = L.get_string(3, fname.c_str());
221 if(L.type(4) == LUA_TSTRING)
222 off = L.get_string(4, fname.c_str());
223 size_t onl = on.length();
224 size_t offl = off.length();
225 char onc = onl ? on[onl - 1] : '*';
226 char offc = offl ? off[offl - 1] : '-';
227 char buffer[65];
228 unsigned i;
229 size_t bias = min(b, (uint64_t)64) - 1;
230 for(i = 0; i < 64 && i < b; i++) {
231 char onc2 = (i < onl) ? on[i] : onc;
232 char offc2 = (i < offl) ? off[i] : offc;
233 buffer[reverse ? (bias - i) : i] = ((a >> i) & 1) ? onc2 : offc2;
235 buffer[i] = '\0';
236 L.pushstring(buffer);
237 return 1;
240 function_ptr_luafun lua_flagdecode(lua_func_bit, "bit.flagdecode", [](lua_state& L, const std::string& fname)
241 -> int {
242 return flagdecode_core(L, fname, false);
245 function_ptr_luafun lua_rflagdecode(lua_func_bit, "bit.rflagdecode", [](lua_state& L,
246 const std::string& fname) -> int {
247 return flagdecode_core(L, fname, true);
250 lua_symmetric_bitwise<combine_none, BITWISE_MASK> bit_none("bit.none");
251 lua_symmetric_bitwise<combine_none, BITWISE_MASK> bit_bnot("bit.bnot");
252 lua_symmetric_bitwise<combine_any, 0> bit_any("bit.any");
253 lua_symmetric_bitwise<combine_any, 0> bit_bor("bit.bor");
254 lua_symmetric_bitwise<combine_all, BITWISE_MASK> bit_all("bit.all");
255 lua_symmetric_bitwise<combine_all, BITWISE_MASK> bit_band("bit.band");
256 lua_symmetric_bitwise<combine_parity, 0> bit_parity("bit.parity");
257 lua_symmetric_bitwise<combine_parity, 0> bit_bxor("bit.bxor");
258 lua_shifter<shift_lrotate> bit_lrotate("bit.lrotate");
259 lua_shifter<shift_rrotate> bit_rrotate("bit.rrotate");
260 lua_shifter<shift_lshift> bit_lshift("bit.lshift");
261 lua_shifter<shift_arshift> bit_arshift("bit.arshift");
262 lua_shifter<shift_lrshift> bit_lrshift("bit.lrshift");