if not modules then modules = { } end modules ['l-number'] = {
    version   = 1.001,
    comment   = "companion to luat-lib.mkiv",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

-- this module will be replaced when we have the bit library .. the number based sets
-- might go away

local tostring, tonumber = tostring, tonumber
local format, floor, match, rep = string.format, math.floor, string.match, string.rep
local concat, insert = table.concat, table.insert
local lpegmatch = lpeg.match

number       = number or { }
local number = number

if bit32 then -- I wonder if this is faster

    local btest, bor = bit32.btest, bit32.bor

    function number.bit(p)
        return 2 ^ (p - 1) -- 1-based indexing
    end

    number.hasbit = btest
    number.setbit = bor

    function number.setbit(x,p) -- why not bor?
        return btest(x,p) and x or x + p
    end

    function number.clearbit(x,p)
        return btest(x,p) and x - p or x
    end

else

    -- http://ricilake.blogspot.com/2007/10/iterating-bits-in-lua.html

    function number.bit(p)
        return 2 ^ (p - 1) -- 1-based indexing
    end

    function number.hasbit(x, p) -- typical call: if hasbit(x, bit(3)) then ...
        return x % (p + p) >= p
    end

    function number.setbit(x, p)
        return (x % (p + p) >= p) and x or x + p
    end

    function number.clearbit(x, p)
        return (x % (p + p) >= p) and x - p or x
    end

end

-- print(number.tobitstring(8))
-- print(number.tobitstring(14))
-- print(number.tobitstring(66))
-- print(number.tobitstring(0x00))
-- print(number.tobitstring(0xFF))
-- print(number.tobitstring(46260767936,4))

if bit32 then

    local bextract = bit32.extract

    local t = {
        "0", "0", "0", "0", "0", "0", "0", "0",
        "0", "0", "0", "0", "0", "0", "0", "0",
        "0", "0", "0", "0", "0", "0", "0", "0",
        "0", "0", "0", "0", "0", "0", "0", "0",
    }

    function number.tobitstring(b,m)
        -- if really needed we can speed this one up
        -- because small numbers need less extraction
        local n = 32
        for i=0,31 do
            local v = bextract(b,i)
            local k = 32 - i
            if v == 1 then
                n = k
                t[k] = "1"
            else
                t[k] = "0"
            end
        end
        if m then
            m = 33 - m * 8
            if m < 1 then
                m = 1
            end
            return concat(t,"",m)
        elseif n < 8 then
            return concat(t)
        elseif n < 16 then
            return concat(t,"",9)
        elseif n < 24 then
            return concat(t,"",17)
        else
            return concat(t,"",25)
        end
    end

else

    function number.tobitstring(n,m)
        if n > 0 then
            local t = { }
            while n > 0 do
                insert(t,1,n % 2 > 0 and 1 or 0)
                n = floor(n/2)
            end
            local nn = 8 - #t % 8
            if nn > 0 and nn < 8 then
                for i=1,nn do
                    insert(t,1,0)
                end
            end
            if m then
                m = m * 8 - #t
                if m > 0 then
                    insert(t,1,rep("0",m))
                end
            end
            return concat(t)
        elseif m then
            rep("00000000",m)
        else
            return "00000000"
        end
    end

end

function number.valid(str,default)
    return tonumber(str) or default or nil
end

function number.toevenhex(n)
    local s = format("%X",n)
    if #s % 2 == 0 then
        return s
    else
        return "0" .. s
    end
end

-- a,b,c,d,e,f = number.toset(100101)
--
-- function number.toset(n)
--     return match(tostring(n),"(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)")
-- end
--
-- -- the lpeg way is slower on 8 digits, but faster on 4 digits, some 7.5%
-- -- on
--
-- for i=1,1000000 do
--     local a,b,c,d,e,f,g,h = number.toset(12345678)
--     local a,b,c,d         = number.toset(1234)
--     local a,b,c           = number.toset(123)
--     local a,b,c           = number.toset("123")
-- end

local one = lpeg.C(1-lpeg.S('')/tonumber)^1

function number.toset(n)
    return lpegmatch(one,tostring(n))
end

-- function number.bits(n,zero)
--     local t, i = { }, (zero and 0) or 1
--     while n > 0 do
--         local m = n % 2
--         if m > 0 then
--             insert(t,1,i)
--         end
--         n = floor(n/2)
--         i = i + 1
--     end
--     return t
-- end
--
-- -- a bit faster

local function bits(n,i,...)
    if n > 0 then
        local m = n % 2
        local n = floor(n/2)
        if m > 0 then
            return bits(n, i+1, i, ...)
        else
            return bits(n, i+1,    ...)
        end
    else
        return ...
    end
end

function number.bits(n)
    return { bits(n,1) }
end
