util-sto.lua / last modification: 2020-01-30 14:16
if not modules then modules = { } end modules ['util-sto'] = {
    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"
}

local setmetatable, getmetatable, rawset, type = setmetatable, getmetatable, rawset, type

utilities         = utilities or { }
utilities.storage = utilities.storage or { }
local storage     = utilities.storage

function storage.mark(t)
    if not t then
        print("\nfatal error: storage cannot be marked\n")
        os.exit()
        return
    end
    local m = getmetatable(t)
    if not m then
        m = { }
        setmetatable(t,m)
    end
    m.__storage__ = true
    return t
end

function storage.allocate(t)
    t = t or { }
    local m = getmetatable(t)
    if not m then
        m = { }
        setmetatable(t,m)
    end
    m.__storage__ = true
    return t
end

function storage.marked(t)
    local m = getmetatable(t)
    return m and m.__storage__
end

function storage.checked(t)
    if not t then
        report("\nfatal error: storage has not been allocated\n")
        os.exit()
        return
    end
    return t
end

-- function utilities.storage.delay(parent,name,filename)
--     local m = getmetatable(parent)
--     m.__list[name] = filename
-- end
--
-- function utilities.storage.predefine(parent)
--     local list = { }
--     local m = getmetatable(parent) or {
--         __list = list,
--         __index = function(t,k)
--             local l = require(list[k])
--             t[k] = l
--             return l
--         end
--     }
--     setmetatable(parent,m)
-- end
--
-- bla = { }
-- utilities.storage.predefine(bla)
-- utilities.storage.delay(bla,"test","oepsoeps")
-- local t = bla.test
-- table.print(t)
-- print(t.a)

function storage.setinitializer(data,initialize)
    local m = getmetatable(data) or { }
    m.__index = function(data,k)
        m.__index = nil -- so that we can access the entries during initializing
        initialize()
        return data[k]
    end
    setmetatable(data, m)
end

local keyisvalue = { __index = function(t,k)
    t[k] = k
    return k
end }

function storage.sparse(t)
    t = t or { }
    setmetatable(t,keyisvalue)
    return t
end

-- table namespace ?

local function f_empty ()                           return "" end -- t,k
local function f_self  (t,k) t[k] = k               return k  end
local function f_table (t,k) local v = { } t[k] = v return v  end
local function f_number(t,k) t[k] = 0               return 0  end -- t,k,v
local function f_ignore()                                     end -- t,k,v

local f_index = {
    ["empty"]  = f_empty,
    ["self"]   = f_self,
    ["table"]  = f_table,
    ["number"] = f_number,
}

function table.setmetatableindex(t,f)
    if type(t) ~= "table" then
        f, t = t, { }
    end
    local m = getmetatable(t)
    local i = f_index[f] or f
    if m then
        m.__index = i
    else
        setmetatable(t,{ __index = i })
    end
    return t
end

local f_index = {
    ["ignore"] = f_ignore,
}

function table.setmetatablenewindex(t,f)
    if type(t) ~= "table" then
        f, t = t, { }
    end
    local m = getmetatable(t)
    local i = f_index[f] or f
    if m then
        m.__newindex = i
    else
        setmetatable(t,{ __newindex = i })
    end
    return t
end

function table.setmetatablecall(t,f)
    if type(t) ~= "table" then
        f, t = t, { }
    end
    local m = getmetatable(t)
    if m then
        m.__call = f
    else
        setmetatable(t,{ __call = f })
    end
    return t
end

-- the manual is somewhat fuzzy about this but suggests that one can best
-- set all fields before assigning a metatable

function table.setmetatableindices(t,f,n,c)
    if type(t) ~= "table" then
        f, t = t, { }
    end
    local m = getmetatable(t)
    local i = f_index[f] or f
    if m then
        m.__index    = i
        m.__newindex = n
        m.__call     = c
    else
        setmetatable(t,{
            __index    = i,
            __newindex = n,
            __call     = c,
        })
    end
    return t
end

function table.setmetatablekey(t,key,value)
    local m = getmetatable(t)
    if not m then
        m = { }
        setmetatable(t,m)
    end
    m[key] = value
    return t
end

function table.getmetatablekey(t,key,value)
    local m = getmetatable(t)
    return m and m[key]
end

function table.makeweak(t)
    if not t then
        t = { }
    end
    local m = getmetatable(t)
    if m then
        m.__mode = "v"
    else
        setmetatable(t,{ __mode = "v" })
    end
    return t
end

-- Problem: we have no __next (which is ok as it would probably slow down lua) so
-- we cannot loop over the keys.

-- local parametersets = table.autokeys()
--
-- parametersets.foo.bar = function(t,k) return "OEPS" end
-- parametersets.foo.foo = "SPEO"
-- parametersets.crap = { a = "a", b = table.autokey { function() return "b" end } }
--
-- print(parametersets.foo.bar)
-- print(parametersets.foo.foo)
-- print(parametersets.crap.b)
-- print(parametersets.crap.b[1])

-- function table.autotables(t)
--     local t = t or { }
--     local m = getmetatable(t)
--     if not m then
--         m = { }
--         setmetatable(t,m)
--     end
--     m.__newindex = function(t,k,p)
--         local v = { }
--         local m = {
--             __index = function(t,k)
--                 local v = p[k]
--                 if type(v) == "function" then
--                     return v(t,k) -- so we can have multiple arguments
--                 else
--                     return v
--                 end
--             end,
--             __newindex = function(t,k,v)
--                 p[k] = v
--             end,
--             __len = function(t)
--                 return #p
--             end,
--         }
--         setmetatable(v,m)
--         rawset(t,k,v)
--         return v
--     end
--     m.__index = function(t,k)
--         local v = { }
--         t[k] = v -- calls newindex
--         return v
--     end
--     return t
-- end
--
-- function table.autokeys(p)
--     local t = { }
--     setmetatable(t, {
--         __newindex = function(t,k,v)
--             p[k] = v
--         end,
--         __index = function(t,k)
--             local v = p[k]
--             if type(v) == "function" then
--                 return v(t,k) -- so we can have multiple arguments
--             else
--                 return v
--             end
--         end,
--         __len = function(t)
--             return #p
--         end,
--     })
--     return t
-- end