-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
105 additions
and
126 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,117 +1,96 @@ | ||
--[[ | ||
An 64-bit library to provide 64-bit binary operation in luau, ideally luau would expose some sort of bit64 lib, | ||
but they don't, so this is the un-optimised, awkward approach! | ||
An optimized 64-bit library to provide 64-bit binary operations in Luau | ||
using 32-bit operations and `bit32` for improved performance. | ||
]] | ||
local Bit64 = {} | ||
|
||
--[[ | ||
Converts a number to a binary string. | ||
Splits a 64-bit integer into high and low 32-bit integers | ||
]] | ||
local function toBinary(number: number): string | ||
local binary = select( | ||
1, | ||
string.gsub(string.format("%o", number), ".", function(x) | ||
return ({ | ||
"000", | ||
"001", | ||
"010", | ||
"011", | ||
"100", | ||
"101", | ||
"110", | ||
"111", | ||
})[tonumber(x) :: number + 1] | ||
end) | ||
) | ||
local function split64(value: number): (number, number) | ||
local low = bit32.band(value, 0xFFFFFFFF) | ||
local high = math.floor(value / 4294967296) | ||
|
||
binary = `{string.rep("0", math.max(64 - #binary, 0))}{binary}` | ||
|
||
return binary | ||
return low, high | ||
end | ||
|
||
--[[ | ||
Converts a binary string to a number. | ||
Combines high and low 32-bit integers into a 64-bit integer | ||
]] | ||
local function toNumber(binary: string): number | ||
return tonumber(binary, 2) :: number | ||
local function combine64(low: number, high: number): number | ||
return (high * 4294967296) + low | ||
end | ||
|
||
--[[ | ||
Binary NOT operation for 64 bit ints | ||
Binary NOT operation | ||
]] | ||
function Bit64.bnot(value: number) | ||
local binary = toBinary(value) | ||
|
||
binary = string.gsub(binary, ".", function(x) | ||
if x == "0" then | ||
return "1" | ||
else | ||
return "0" | ||
end | ||
end) | ||
function Bit64.bnot(value: number): number | ||
local low, high = split64(value) | ||
local newLow = bit32.bnot(low) | ||
local newHigh = bit32.bnot(high) | ||
|
||
return toNumber(binary) | ||
return combine64(newLow, newHigh) | ||
end | ||
|
||
--[[ | ||
Binary OR operation for 64 bit ints | ||
Binary OR operation | ||
]] | ||
function Bit64.bor(value0: number, value1: number) | ||
local binary0 = toBinary(value0) | ||
local binary1 = toBinary(value1) | ||
|
||
local outputBinary = `` | ||
|
||
for index = 1, #binary0 do | ||
local binary0Bit = tonumber(string.sub(binary0, index, index)) :: number | ||
local binary1Bit = tonumber(string.sub(binary1, index, index)) :: number | ||
function Bit64.bor(value0: number, value1: number): number | ||
local low0, high0 = split64(value0) | ||
local low1, high1 = split64(value1) | ||
local newLow = bit32.bor(low0, low1) | ||
local newHigh = bit32.bor(high0, high1) | ||
|
||
if binary0Bit + binary1Bit > 0 then | ||
outputBinary ..= "1" | ||
else | ||
outputBinary ..= "0" | ||
end | ||
end | ||
|
||
return toNumber(outputBinary) | ||
return combine64(newLow, newHigh) | ||
end | ||
|
||
--[[ | ||
Binary AND operation for 64 bit ints | ||
Binary AND operation | ||
]] | ||
function Bit64.band(value0: number, value1: number) | ||
local binary0 = toBinary(value0) | ||
local binary1 = toBinary(value1) | ||
|
||
local outputBinary = `` | ||
function Bit64.band(value0: number, value1: number): number | ||
local low0, high0 = split64(value0) | ||
local low1, high1 = split64(value1) | ||
local newLow = bit32.band(low0, low1) | ||
local newHigh = bit32.band(high0, high1) | ||
|
||
for index = 1, #binary0 do | ||
local binary0Bit = tonumber(string.sub(binary0, index, index)) :: number | ||
local binary1Bit = tonumber(string.sub(binary1, index, index)) :: number | ||
|
||
outputBinary ..= tostring(binary0Bit * binary1Bit) | ||
end | ||
|
||
return toNumber(outputBinary) | ||
return combine64(newLow, newHigh) | ||
end | ||
|
||
--[[ | ||
Binary SHIFT operation for 64 bit ints, disposition is the number of bits to shift by, can support negative values | ||
Binary SHIFT operation | ||
]] | ||
function Bit64.shift(value: number, disposition: number) | ||
local binary = toBinary(value) | ||
function Bit64.shift(value: number, displacement: number): number | ||
if displacement == 0 then | ||
return value | ||
end | ||
|
||
if disposition > 0 then | ||
binary = string.sub(binary, 0, #binary - disposition) | ||
binary = `{string.rep("0", disposition)}{binary}` | ||
else | ||
disposition = math.abs(disposition) | ||
local low, high = split64(value) | ||
|
||
binary = string.sub(binary, -(#binary - disposition)) | ||
binary = `{binary}{string.rep("0", disposition)}` | ||
if displacement > 0 then | ||
-- Left shift | ||
if displacement >= 32 then | ||
high = bit32.lshift(low, displacement - 32) | ||
low = 0 | ||
else | ||
high = bit32.bor(bit32.lshift(high, displacement), bit32.rshift(low, 32 - displacement)) | ||
low = bit32.lshift(low, displacement) | ||
end | ||
else | ||
-- Right shift | ||
displacement = -displacement | ||
if displacement >= 32 then | ||
low = bit32.rshift(high, displacement - 32) | ||
high = 0 | ||
else | ||
low = bit32.bor(bit32.rshift(low, displacement), bit32.lshift(high, 32 - displacement)) | ||
high = bit32.rshift(high, displacement) | ||
end | ||
end | ||
|
||
return toNumber(binary) | ||
low = bit32.band(low, 0xFFFFFFFF) | ||
high = bit32.band(high, 0xFFFFFFFF) | ||
|
||
return combine64(low, high) | ||
end | ||
|
||
return Bit64 |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,75 +1,78 @@ | ||
--[[ | ||
A Bit wrapper library that supports both 64 Bit integers and 32 Bit integers. Primarily required in the calculation | ||
for snowflake IDs that the Discord API will give us. | ||
A Bit wrapper library that supports both 64-bit integers and 32-bit integers. | ||
Primarily required in the calculation for snowflake IDs that the Discord API will give us. | ||
]] | ||
|
||
local MAXIMUM_32BIT_VALUE = 2147483647 | ||
|
||
local Bit64 = require("./bit64") | ||
local Bit32 = bit32 | ||
|
||
local Bit = {} | ||
|
||
--[[ | ||
Binary NOT operation for 64 bit ints | ||
Returns true if the given value is a 32-bit integer. | ||
]] | ||
function Bit.is32Bit(value: number): boolean | ||
return value >= 0 and value <= 0xFFFFFFFF | ||
end | ||
|
||
--[[ | ||
Binary NOT operation for integers | ||
]] | ||
function Bit.bnot(value: number): number | ||
if value > MAXIMUM_32BIT_VALUE then | ||
return Bit64.bnot(value) | ||
if Bit.is32Bit(value) then | ||
return bit32.bnot(value) | ||
else | ||
return Bit32.bnot(value) | ||
return Bit64.bnot(value) | ||
end | ||
end | ||
|
||
--[[ | ||
Binary OR operation for 64 bit ints | ||
Binary OR operation for integers | ||
]] | ||
function Bit.bor(value0: number, value1: number): number | ||
if value0 > MAXIMUM_32BIT_VALUE then | ||
return Bit64.bor(value0, value1) | ||
if Bit.is32Bit(value0) and Bit.is32Bit(value1) then | ||
return bit32.bor(value0, value1) | ||
else | ||
return Bit32.bor(value0, value1) | ||
return Bit64.bor(value0, value1) | ||
end | ||
end | ||
|
||
--[[ | ||
Binary AND operation for 64 bit ints | ||
Binary AND operation for integers | ||
]] | ||
function Bit.band(value0: number, value1: number): number | ||
if value0 > MAXIMUM_32BIT_VALUE then | ||
return Bit64.band(value0, value1) | ||
if Bit.is32Bit(value0) and Bit.is32Bit(value1) then | ||
return bit32.band(value0, value1) | ||
else | ||
return Bit32.band(value0, value1) | ||
return Bit64.band(value0, value1) | ||
end | ||
end | ||
|
||
--[[ | ||
Binary SHIFT operation for 64 bit ints, disposition is the number of bits to shift by, can support negative values | ||
Binary SHIFT operation for integers | ||
]] | ||
function Bit.shift(value: number, disposition: number): number | ||
if value > MAXIMUM_32BIT_VALUE then | ||
return Bit64.shift(value, disposition) | ||
else | ||
if disposition > 0 then | ||
return Bit32.rshift(value, disposition) | ||
function Bit.shift(value: number, displacement: number): number | ||
if Bit.is32Bit(value) then | ||
if displacement >= 0 then | ||
return bit32.lshift(value, displacement) | ||
else | ||
return Bit32.lshift(value, disposition) | ||
return bit32.rshift(value, -displacement) | ||
end | ||
else | ||
return Bit64.shift(value, displacement) | ||
end | ||
end | ||
|
||
--[[ | ||
Binary LEFT SHIFT operation for 64 bit ints | ||
Binary LEFT SHIFT operation for integers | ||
]] | ||
function Bit.lshift(value: number, disposition: number): number | ||
return Bit.shift(value, disposition) | ||
function Bit.lshift(value: number, displacement: number): number | ||
return Bit.shift(value, displacement) | ||
end | ||
|
||
--[[ | ||
Binary RIGHT SHIFT operation for 64 bit ints | ||
Binary RIGHT SHIFT operation for integers | ||
]] | ||
function Bit.rshift(value: number, disposition: number): number | ||
return Bit.shift(value, -disposition) | ||
function Bit.rshift(value: number, displacement: number): number | ||
return Bit.shift(value, -displacement) | ||
end | ||
|
||
return Bit |
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