Last active
June 8, 2024 17:35
-
-
Save JabDoesThings/1f6406caf5849b49aa528f9e149277ed to your computer and use it in GitHub Desktop.
Bitwise Ops Support for Project Zomboid (Build 41.78.16)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- BITE is a last resort for Lua 5.1 (Kahlua2) bitwise support for Project Zomboid. | |
-- | |
-- YES, THIS IS VERY VERY SLOW BUT BETTER THAN NOTHING AT ALL. | |
-- | |
-- @author JabDoesThings, asledgehammer 2023 | |
local BITS = 32; | |
--- @class bite | |
--- @field bcast fun(value): number Cast a value to the internally-used integer type | |
--- @field bnot fun(value): number Returns the one's compliment of the value. | |
--- @field band fun(value, ...): number Returns the bitwise AND of the values. | |
--- @field bor fun(value, ...): number Returns the bitwise OR of the values. | |
--- @field bxor fun(value, ...): number Returns the bitwise EXCLUSIVE OR of the values. | |
--- @field lshift fun(value, offset): number Returns value shifted by offset. | |
--- @field rshift fun(value, offset): number Returns value shifted logically right by offset. | |
--- @field arshift fun(value, offset): number Returns value shifted arithmetically right by offset. | |
--- @field tobit fun(value): number | |
--- @field tohex fun(value): string | |
--- @field rol fun(a, b): number | |
--- @field test fun(): void Tests 'bite' with 'bitlib' to see if the same results occur. | |
local readonly = function(table) | |
local meta = getmetatable(table) or {}; | |
return setmetatable({}, { | |
__index = table, | |
__newindex = function() error("Attempt to modify read-only class.", 2) end, | |
__metatable = false, | |
__add = meta.__add, | |
__sub = meta.__sub, | |
__mul = meta.__mul, | |
__div = meta.__div, | |
__mod = meta.__mod, | |
__pow = meta.__pow, | |
__eq = meta.__eq, | |
__lt = meta.__lt, | |
__le = meta.__le, | |
__concat = meta.__concat, | |
__call = meta.__call, | |
__tostring = meta.__tostring | |
}); | |
end | |
local HEX_BIN_DICTIONARY = { | |
['0'] = '0000', | |
['1'] = '0001', | |
['2'] = '0010', | |
['3'] = '0011', | |
['4'] = '0100', | |
['5'] = '0101', | |
['6'] = '0110', | |
['7'] = '0111', | |
['8'] = '1000', | |
['9'] = '1001', | |
['a'] = '1010', | |
['b'] = '1011', | |
['c'] = '1100', | |
['d'] = '1101', | |
['e'] = '1110', | |
['f'] = '1111' | |
}; | |
local BIN_HEX_DICTIONARY = { | |
['0000'] = '0', | |
['0001'] = '1', | |
['0010'] = '2', | |
['0011'] = '3', | |
['0100'] = '4', | |
['0101'] = '5', | |
['0110'] = '6', | |
['0111'] = '7', | |
['1000'] = '8', | |
['1001'] = '9', | |
['1010'] = 'A', | |
['1011'] = 'B', | |
['1100'] = 'C', | |
['1101'] = 'D', | |
['1110'] = 'E', | |
['1111'] = 'F' | |
}; | |
--- @param value string The hexadecimal string. | |
--- | |
--- @return string binary The binary string. | |
local function hex2bin(value, bits, positive) | |
local result = ''; | |
for i in string.gmatch(value, '.') do | |
i = string.lower(i); | |
result = result .. HEX_BIN_DICTIONARY[i]; | |
end | |
while #result < bits do | |
if positive then | |
result = '0' .. result; | |
else | |
result = '1' .. result; | |
end | |
end | |
return result; | |
end | |
--- @param value string The binary string. | |
--- | |
--- @return string binary The hexadecimal string. | |
local function bin2hex(value) | |
local l, result = string.len(value), ''; | |
local rem = (l % 4) - 1; | |
-- need to prepend zeros to eliminate mod 4 | |
if (rem > 0) then value = string.rep('0', 4 - rem) .. value end | |
for i = 1, l, 4 do result = result .. BIN_HEX_DICTIONARY[string.sub(value, i, i + 3)] end | |
return result; | |
end | |
--- @param value string The binary string. | |
--- | |
--- @return number | |
local function s_bin2dec(value) | |
local isNegative = string.sub(value, 1, 1) == '1'; | |
local ex2 = #value - 2; | |
local mRet = 0; | |
for i = 2, #value, 1 do | |
local charValue = string.sub(value, i, i); | |
if isNegative then | |
if charValue == '0' then | |
mRet = mRet + math.pow(2, ex2); | |
end | |
else | |
if charValue == '1' then | |
mRet = mRet + math.pow(2, ex2); | |
end | |
end | |
ex2 = ex2 - 1; | |
end | |
if isNegative then mRet = -mRet - 1 end | |
return mRet; | |
end | |
--- @param value number The Base10 string. | |
--- @param bits number The string length to extend. | |
--- | |
--- @return string binary The binary string. | |
local function s_dec2bin(value, bits) | |
local n = bits or 0; | |
local sValue = hex2bin(string.format('%x', value), BITS, value > -1); | |
if string.sub(sValue, 1, 1) == '1' then | |
while string.len(sValue) < n do sValue = '1' .. sValue end | |
else | |
while string.len(sValue) < n do sValue = '0' .. sValue end | |
end | |
return sValue; | |
end | |
--_________________________________________________________________-- | |
--- @type bite | |
--- @diagnostic disable-next-line: missing-fields | |
local bite = {}; | |
--_____________________-- | |
--- Unknown function. | |
bite.rol = function() error('The function \'rol(a, b)\' is not implemented.') end | |
bite.tohex = function(value) | |
if type(value) == 'string' then return string.format('%x', value) else return bin2hex(value) end | |
end | |
bite.tobit = function(value) | |
if type(value) == 'number' then return value else return s_bin2dec(hex2bin(value)) end | |
end | |
--- Calculates the 'AND' bitwise operation for two signed values. | |
--- | |
--- @param value number Either a number or NumberTable. | |
--- @param mask number Either a number or NumberTable. | |
--- | |
--- @return number result The calculated result. | |
bite.band = function(value, mask) end | |
--- Calculates the 'OR' bitwise operation for two signed values. | |
--- | |
--- @param value number Either a number or NumberTable. | |
--- @param mask number Either a number or NumberTable. | |
--- | |
--- @return number result The calculated result. | |
bite.bor = function(value, mask) end | |
--- Calculates the 'XOR' bitwise operation for two signed values. | |
--- | |
--- @param value number Either a number or NumberTable. | |
--- @param mask number Either a number or NumberTable. | |
--- | |
--- @return number result The calculated result. | |
bite.bxor = function(value, mask) end | |
--- Calculates the 'NOT' bitwise operation for two signed values. | |
--- | |
--- @param value number Either a number or NumberTable. | |
--- | |
--- @return number result The calculated result. | |
bite.bnot = function(value) end | |
--- Shifts a value's bits to the left. ( x << y ) | |
--- | |
--- @param value number Either a number or NumberTable to be shifted. | |
--- @param offset number The number of bits to shift to the left. | |
--- | |
--- @return number result The calculated result. | |
bite.lshift = function(value, offset) end | |
--- Shifts a value's bits to the right. ( x >> y ) | |
--- | |
--- @param value number Either a number or NumberTable to be shifted. | |
--- @param offset number The number of bits to shift to the left. | |
--- | |
--- @return number result The calculated result. | |
bite.rshift = function(value, offset) end | |
--- Shifts a value's bits to the right. ( x >>> y ) | |
--- | |
--- @param value number Either a number or NumberTable to be shifted. | |
--- @param offset number The number of bits to shift to the left. | |
--- | |
--- @return number result The calculated result. | |
bite.arshift = function(value, offset) end | |
if BitwiseOps and BitwiseOps.band32 then | |
bite.band = BitwiseOps.band32; | |
else | |
bite.band = function(value, mask) | |
local bv, bm, br, cv, cm = s_dec2bin(value, BITS), s_dec2bin(mask, BITS), '', '', ''; | |
for i = 1, BITS do | |
cv, cm = string.sub(bv, i, i), string.sub(bm, i, i); | |
if cv == '1' and cm == '1' then br = br .. '1' else br = br .. '0' end | |
end | |
return s_bin2dec(br); | |
end | |
end | |
if BitwiseOps and BitwiseOps.bor32 then | |
bite.bor = BitwiseOps.bor32; | |
else | |
bite.bor = function(value, mask) | |
local bv, bm, br, cv, cm = s_dec2bin(value, BITS), s_dec2bin(mask, BITS), '', '', ''; | |
for i = 1, BITS do | |
cv, cm = string.sub(bv, i, i), string.sub(bm, i, i); | |
if cv == '1' then br = br .. '1' elseif cm == '1' then br = br .. '1' else br = br .. '0' end | |
end | |
return s_bin2dec(br); | |
end | |
end | |
if BitwiseOps and BitwiseOps.bxor32 then | |
bite.bxor = BitwiseOps.bxor32; | |
else | |
bite.bxor = function(value, mask) | |
local bv, bm, br, cv, cm = s_dec2bin(value, BITS), s_dec2bin(mask, BITS), '', '', ''; | |
for i = 1, BITS do | |
cv, cm = string.sub(bv, i, i), string.sub(bm, i, i); | |
if cv == '1' then | |
if cm == '0' then br = br .. '1' else br = br .. '0' end | |
elseif cm == '1' then | |
if cv == '0' then br = br .. '1' else br = br .. '0' end | |
else | |
br = br .. '0' | |
end | |
end | |
return s_bin2dec(br); | |
end | |
end | |
if BitwiseOps and BitwiseOps.bnot32 then | |
bite.bnot = BitwiseOps.bnot32; | |
else | |
bite.bnot = function(value) | |
local bv, br = s_dec2bin(value, BITS), ''; | |
for i = 1, BITS do | |
if string.sub(bv, i, i) == '1' then br = br .. '0' else br = br .. '1' end | |
end | |
return s_bin2dec(br); | |
end | |
end | |
if BitwiseOps and BitwiseOps.lshift32 then | |
bite.lshift = BitwiseOps.lshift32; | |
else | |
bite.lshift = function(value, offset) | |
if offset >= BITS then return 0 elseif offset <= 0 then return value end | |
local bv = s_dec2bin(value, BITS); | |
local br = string.sub(bv, offset + 1); | |
while #br < BITS do br = br .. '0' end | |
return s_bin2dec(br); | |
end | |
end | |
if BitwiseOps and BitwiseOps.rshift32 then | |
bite.rshift = BitwiseOps.rshift32; | |
else | |
bite.rshift = function(value, offset) | |
if offset >= BITS then return 0 elseif offset <= 0 then return value end | |
local bv = s_dec2bin(value, BITS); | |
local br = string.sub(bv, 1, BITS - offset); | |
while (string.len(br) < BITS) do br = '0' .. br end | |
return s_bin2dec(br); | |
end | |
end | |
if BitwiseOps and BitwiseOps.arshift32 then | |
bite.arshift = BitwiseOps.arshift32; | |
else | |
bite.arshift = function(value, offset) | |
if offset >= BITS then return 0 elseif offset <= 0 then return value end | |
local bv = s_dec2bin(value, BITS); | |
local br, b1 = string.sub(bv, 1, BITS - offset), string.sub(bv, 1, 1); | |
while (string.len(br) < BITS) do br = b1 .. br end | |
return s_bin2dec(br); | |
end | |
end | |
return readonly(bite); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.asledgehammer.craftnail.util; | |
public class BitwiseOps { | |
public static byte bnot8(long value) { | |
return (byte) ~(byte) value; | |
} | |
public static byte band8(long value, long mask) { | |
return (byte) ((byte) value & (byte) mask); | |
} | |
public static byte bor8(long value, long mask) { | |
return (byte) ((byte) value | (byte) mask); | |
} | |
public static byte bxor8(long value, long mask) { | |
return (byte) ((byte) value ^ (byte) mask); | |
} | |
public static byte lshift8(long value, long offset) { | |
return (byte) ((byte) value << (byte) offset); | |
} | |
public static byte rshift8(long value, long offset) { | |
return (byte) ((byte) value >>> (byte) offset); | |
} | |
public static byte arshift8(long value, long offset) { | |
return (byte) ((byte) value >> (byte) offset); | |
} | |
public static short bnot16(long value) { | |
return (short) ~(short) value; | |
} | |
public static short band16(long value, long mask) { | |
return (short) ((short) value & (short) mask); | |
} | |
public static short bor16(long value, long mask) { | |
return (short) ((short) value | (short) mask); | |
} | |
public static short bxor16(long value, long mask) { | |
return (short) ((short) value ^ (short) mask); | |
} | |
public static short lshift16(long value, long offset) { | |
return (short) ((short) value << (short) offset); | |
} | |
public static short rshift16(long value, long offset) { | |
return (short) ((short) value >>> (short) offset); | |
} | |
public static short arshift16(long value, long offset) { | |
return (short) ((short) value >> (short) offset); | |
} | |
public static int bnot32(long value) { | |
return ~(int) value; | |
} | |
public static int band32(long value, long mask) { | |
return (int) value & (int) mask; | |
} | |
public static int bor32(long value, long mask) { | |
return (int) value | (int) mask; | |
} | |
public static int bxor32(long value, long mask) { | |
return (int) value ^ (int) mask; | |
} | |
public static int lshift32(long value, long offset) { | |
return (int) value << (int) offset; | |
} | |
public static int rshift32(long value, long offset) { | |
return (int) value >>> (int) offset; | |
} | |
public static int arshift32(long value, long offset) { | |
return (int) value >> (int) offset; | |
} | |
public static long bnot64(long value) { | |
return ~value; | |
} | |
public static long band64(long value, long mask) { | |
return value & mask; | |
} | |
public static long bor64(long value, long mask) { | |
return value | mask; | |
} | |
public static long bxor64(long value, long mask) { | |
return value ^ mask; | |
} | |
public static long lshift64(long value, long offset) { | |
return value << offset; | |
} | |
public static long rshift64(long value, long offset) { | |
return value >>> offset; | |
} | |
public static long arshift64(long value, long offset) { | |
return value >> offset; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment