--:Minify:--

local bit32 = {}

local MOD32 = 2^32
local MOD31 = 2^31

local function norm(x)
    return x % MOD32
end

-- Convert number to bit table
local function tobits(x)
    x = norm(x)
    local t = {}
    for i = 0, 31 do
        local b = x % 2
        t[i] = b
        x = (x - b) / 2
    end
    return t
end

-- Convert bit table to number
local function frombits(t)
    local x = 0
    local p = 1
    for i = 0, 31 do
        if t[i] == 1 then
            x = x + p
        end
        p = p * 2
    end
    return norm(x)
end

-- ===== Logical ops =====

function bit32.band(...)
    local args = {...}
    if #args == 0 then return 0xFFFFFFFF end
    local bits = tobits(args[1])
    for i = 2, #args do
        local b = tobits(args[i])
        for j = 0, 31 do
            bits[j] = (bits[j] == 1 and b[j] == 1) and 1 or 0
        end
    end
    return frombits(bits)
end

function bit32.bor(...)
    local args = {...}
    if #args == 0 then return 0 end
    local bits = tobits(args[1])
    for i = 2, #args do
        local b = tobits(args[i])
        for j = 0, 31 do
            bits[j] = (bits[j] == 1 or b[j] == 1) and 1 or 0
        end
    end
    return frombits(bits)
end

function bit32.bxor(...)
    local args = {...}
    if #args == 0 then return 0 end
    local bits = tobits(args[1])
    for i = 2, #args do
        local b = tobits(args[i])
        for j = 0, 31 do
            bits[j] = (bits[j] ~= b[j]) and 1 or 0
        end
    end
    return frombits(bits)
end

function bit32.bnot(x)
    local bits = tobits(x)
    for i = 0, 31 do
        bits[i] = bits[i] == 1 and 0 or 1
    end
    return frombits(bits)
end

-- ===== Shifts =====

function bit32.lshift(x, n)
    return norm(norm(x) * 2^n)
end

function bit32.rshift(x, n)
    return math.floor(norm(x) / 2^n)
end

function bit32.arshift(x, n)
    x = norm(x)
    if x >= MOD31 then
        return math.floor((x - MOD32) / 2^n)
    else
        return math.floor(x / 2^n)
    end
end

-- ===== Rotates =====

function bit32.lrotate(x, n)
    n = n % 32
    x = norm(x)
    local left = (x * 2^n) % MOD32
    local right = math.floor(x / 2^(32 - n))
    return norm(left + right)
end

function bit32.rrotate(x, n)
    n = n % 32
    x = norm(x)
    local right = math.floor(x / 2^n)
    local left = (x * 2^(32 - n)) % MOD32
    return norm(left + right)
end

-- ===== Bit fields =====

function bit32.extract(x, field, width)
    width = width or 1
    return bit32.band(bit32.rshift(x, field), 2^width - 1)
end

function bit32.replace(x, v, field, width)
    width = width or 1
    local mask = bit32.lshift(2^width - 1, field)
    x = bit32.band(x, bit32.bnot(mask))
    return bit32.bor(x, bit32.lshift(v, field))
end

return bit32
