[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Self-initializing tables
- From: Dirk Laurie <dirk.laurie@...>
- Date: Tue, 23 Feb 2016 09:46:32 +0200
2016-02-23 7:26 GMT+02:00 Paul K <paul@zerobrane.com>:
> Dirk,
>
>> A module is attached that contains the following comments:
>
> Missing attachment?
>
> Paul.
>
-- selfinit.lua © Dirk Laurie 2016 MIT license
-- Published as a contribution to lua-l@lists.lua.org on 2015-02-23
-- Self-initializing table. The point is that `tbl[key]` is never nil.
-- tbl = selfinit(tbl) -- makes an existing table self-initializing
-- and returns it
-- tblx = tbl.x -- tbl.x is an empty table with the same
-- metatable as x
-- tbl.a.b.c.d = 'item' -- tbl.a, tbl.a.b, tblc.a.b.c are created too,
-- even if `item` is nil.
-- tbl = selfinit() -- creates a new self-initializing table
-- WARNING: The implications are strongly counterintuitive.
-- 1. You will need `rawget` to find out whether a table entry exists.
-- 2. If `ipairs` is found by the module loader to treat an empty self-
-- initializing table as non-empty, it is monkey-patched to use `rawget`.
-- The module is not paranoid about abuse. The only legitimate error
-- is to try to overwrite an existing __index metamethod. If you supply
-- a 'tbl' on which 'setmetatable' fails, that's the error you will get.
local selfinit, selfinit_mt, selfinit_index
selfinit_index = function(tbl,item)
local sit = setmetatable({},getmetatable(tbl))
rawset(tbl,item,sit)
return sit
end
selfinit_mt = {__index = selfinit_index}
--- selfinit(tbl) makes 'tbl' self-initializing and returns it.
-- selfinit() is equivalent to selfinit{}
selfinit = function(tbl)
local mt
mt = getmetatable(tbl)
if mt then
if mt.__index then
error("Table already has an index metamethod",2)
end
mt.__index = selfinit_index
return tbl
end
return setmetatable(tbl or {},selfinit_mt)
end
local old_ipairs = ipairs
local selfinit_inext = function(tbl,key)
if not key then
local val = rawget(tbl,1)
if val then return 1, val
else return
end
end
key=key+1
return rawget(tbl,key),key
end
-- monkey-patch ipairs
for k in ipairs(selfinit{}) do
debug.getregistry().ipairs_before_selfinit = ipairs
ipairs = function(tbl) return selfinit_inext, tbl end
break
end
return selfinit