/* Bitwise operations library */ /* (c) Reuben Thomas 2000-2008 */ /* bitlib is copyright Reuben Thomas 2000-2008, and is released under the MIT license, like Lua (see http://www.lua.org/copyright.html; it's basically the same as the BSD license). There is no warranty. */ #include "config.h" #include "lua.h" #include "lauxlib.h" #include "lualib.h" #include /* FIXME: Assume lua_Integer is ptrdiff_t */ #define LUA_INTEGER_MAX INTPTR_MAX #define LUA_INTEGER_MIN INTPTR_MIN /* FIXME: Assume size_t is an unsigned lua_Integer */ typedef size_t lua_UInteger; #define LUA_UINTEGER_MAX UINT_MAX /* Bit type size and limits */ #define BIT_BITS (CHAR_BIT * sizeof(lua_Integer)) /* This code may give warnings if BITLIB_FLOAT_* are too big to fit in long, but that doesn't matter since in that case they won't be used. */ #define BIT_MAX (LUA_INTEGER_MAX) #define BIT_MIN (LUA_INTEGER_MIN) #define BIT_UMAX (LUA_UINTEGER_MAX) /* Define TOBIT to get a bit value */ #ifdef BUILTIN_CAST #define #define TOBIT(L, n, res) \ ((void)(res), luaL_checkinteger((L), (n))) #else #define TOBIT(L, n, res) \ ((lua_Integer)(((res) = luaL_checknumber(L, (n)) % BIT_UMAX), \ (res) > BIT_MAX ? ((res) -= BIT_UMAX, (res) -= 1) : \ ((res) < BIT_MIN ? ((res) += BIT_UMAX, (res) += 1) : (res)))) #endif #define BIT_TRUNCATE(i) \ ((i) & BIT_UMAX) /* Operations The macros MONADIC and VARIADIC only deal with bitwise operations. LOGICAL_SHIFT truncates its left-hand operand before shifting so that any extra bits at the most-significant end are not shifted into the result. ARITHMETIC_SHIFT does not truncate its left-hand operand, so that the sign bits are not removed and right shift work properly. */ #define MONADIC(name, op) \ static int bit_ ## name(lua_State *L) { \ lua_Number f; \ lua_pushinteger(L, BIT_TRUNCATE(op TOBIT(L, 1, f))); \ return 1; \ } #define VARIADIC(name, op) \ static int bit_ ## name(lua_State *L) { \ lua_Number f; \ int n = lua_gettop(L), i; \ lua_Integer w = TOBIT(L, 1, f); \ for (i = 2; i <= n; i++) \ w op TOBIT(L, i, f); \ lua_pushinteger(L, BIT_TRUNCATE(w)); \ return 1; \ } #define LOGICAL_SHIFT(name, op) \ static int bit_ ## name(lua_State *L) { \ lua_Number f; \ lua_pushinteger(L, BIT_TRUNCATE(BIT_TRUNCATE((lua_UInteger)TOBIT(L, 1, f)) op \ (unsigned)luaL_checknumber(L, 2))); \ return 1; \ } #define ARITHMETIC_SHIFT(name, op) \ static int bit_ ## name(lua_State *L) { \ lua_Number f; \ lua_pushinteger(L, BIT_TRUNCATE((lua_Integer)TOBIT(L, 1, f) op \ (unsigned)luaL_checknumber(L, 2))); \ return 1; \ } MONADIC(bnot, ~) VARIADIC(band, &=) VARIADIC(bor, |=) VARIADIC(bxor, ^=) ARITHMETIC_SHIFT(lshift, <<) LOGICAL_SHIFT(rshift, >>) ARITHMETIC_SHIFT(arshift, >>) static const struct luaL_reg bitlib[] = { {"bnot", bit_bnot}, {"band", bit_band}, {"bor", bit_bor}, {"bxor", bit_bxor}, {"lshift", bit_lshift}, {"rshift", bit_rshift}, {"arshift", bit_arshift}, {NULL, NULL} }; LUALIB_API int luaopen_bit (lua_State *L) { luaL_register(L, "bit", bitlib); lua_pushnumber(L, BIT_BITS); lua_setfield(L, -2, "bits"); return 1; }