function gettable_event (table, key)
local h
if type(table) == "table" then
local v = rawget(table, key)
if v ~= nil then return v end
h = metatable(table).__index
if h == nil then return nil end
else
h = metatable(table).__index
if h == nil then
error(···)
end
end
if type(h) == "function" then
return (h(table, key)) -- call the handler
else return h[key] -- or repeat operation on it
end
end
-- tostring方法
function class.object:__tostring()
if self then
local ret = '[' .. self.__type .. ' : ' .. self.__classname .. ']'
if self.__instance_id then
ret = ret .. ' @' .. tostring(self.__instance_id)
end
return ret
end
return '[class : object] WARNING: you should use obj:__tostring but obj.__tostring'
end
-- 单例基类
do
class.singleton = class.register('utils.class.singleton')
rawset(class.singleton, 'new', function(self, inst)
if nil == self then
log_error('singleton class must using class:new or class:instance(class.new and class.instance is unavailable)')
return nil
end
return self
end)
rawset(class.singleton, 'instance', class.singleton.new)
end
-- 保护table数据
function class.protect(obj, r)
-- 和readonly混用的优化
local tmb = getmetatable(obj)
if tmb and class.readonly__newindex == tmb.__newindex then
obj = tmb.__index
end
local wrapper = {}
local wrapper_metatable = {}
setmetatable(wrapper, wrapper_metatable)
for k, v in pairs(obj) do
if r and 'table' == type(v) or 'userdata' == type(v) then
rawset(wrapper, k, class.protect(v, r))
else
rawset(wrapper, k, v)
end
end
rawset(wrapper_metatable, '__index', obj)
rawset(wrapper_metatable, '__newindex', function(tb, k, v)
rawset(tb, k, v)
end)
return wrapper
end
-- readonly 重载__newindex函数
function class.readonly__newindex(tb, key, value)
log_error('table %s is readonly, set key %s is invalid', tostring(tb), tostring(key))
end
-- 设置table为readonly
function class.set_readonly(obj)
local tmb = getmetatable(obj)
if not tmb or class.readonly__newindex ~= tmb.__newindex then
local wrapper = {
__index = obj,
__newindex = class.readonly__newindex,
}
-- 设置readonly后 # 操作符失效的解决方案
function wrapper:table_len()
return #obj
end
-- 设置readonly后pairs失效的解决方案
function wrapper:table_pairs()
return pairs(obj)
end
-- 设置readonly后ipairs失效的解决方案
function wrapper:table_ipairs()
return ipairs(obj)
end
-- 设置readonly后next失效的解决方案
function wrapper:table_next(index)
return next(obj, index)
end
-- 设置readonly后unpack失效的解决方案
function wrapper:table_unpack(index)
return table.unpack(obj, index)
end
-- 原始table
function wrapper:table_raw()
return obj
end
-- 复制可写表
function wrapper:table_make_writable()
local ret = table.extend(obj)
for k, v in pairs(ret) do
if 'table' == type(v) then
rawset(ret, k, v:table_make_writable())
else
rawset(ret, k, v)
end
end
return ret
end
setmetatable(wrapper, wrapper)
for k, v in pairs(obj) do
if 'table' == type(v) or 'userdata' == type(v) then
rawset(obj, k, class.set_readonly(v))
end
end
return wrapper
end
return obj
end