You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

176 lines
3.5 KiB
Lua

-- 嵌套表
local skynet = require "skynet"
local class = class
local select = select
local next = next
local setmetatable = setmetatable
local assert = assert
local type = type
local getmetatable = getmetatable
local pairs = pairs
local xpcall = xpcall
local tostring = tostring
local table_insert = table.insert
--------------------------------------------------
local NestingTable = class("NestingTable")
-- 断言类型
local function isKind(obj, strKind)
local mt
if type(obj) == "table" then
mt = getmetatable(obj)
end
while mt do
if mt.__cname == strKind then
return true
end
mt = mt.super
end
return false
end
local function exception(e)
skynet.error(e)
return e
end
local function xxpcall(f, ...)
return xpcall(f, exception, ...)
end
--- 构造函数
-- @param deep 深度
-- @param bWeak 弱引用
function NestingTable:__init(deep, bWeak)
self.m_deep = deep or 1
self.m_bWeak = bWeak == true
self.m_count = 0
self.m_items = {}
self:clear()
end
--- 新增对象
-- @param item 对象实例
-- @param k 键值
-- @param ... 多个键值
function NestingTable:add(item, k, ...)
if not item or not k or select("#", k, ...) ~= self.m_deep then
return
end
if ... then
local _item = self:get(k)
if not _item then
local deep = self.m_deep - 1
_item = NestingTable.new(deep, self.m_bWeak)
self.m_items[k] = _item
end
_item:add(item, ...)
else
self.m_items[k] = item
end
end
--- 删除对象
-- @param k 键值
-- @param ... 多个键值
function NestingTable:remove(k, ...)
if not k or select("#", k, ...) ~= self.m_deep then
return
end
local _item = self:get(k)
if not ... then
self.m_items[k] = nil
elseif _item then
_item:remove(...)
if not next(_item:getItems()) then
self.m_items[k] = nil
end
end
end
--- 取对象
-- @param k 键值
-- @param ... 多个键值
-- @return 被管理对象实例
function NestingTable:get(k, ...)
if not k then
-- Log.w("NestingTable get k nil!")
return
end
local item = self.m_items[k]
if not ... then
return item
end
if item then
return item:get(...)
end
end
--- 取所有对象
function NestingTable:getItems()
return self.m_items
end
function NestingTable:clear()
if self.m_deep <= 1 then
self.m_items = self.m_bWeak and setmetatable({}, {
__mode = "v",
}) or {}
else
self.m_items = {}
end
end
function NestingTable:traverse(closure)
assert(closure)
for _, item in pairs(self.m_items) do
if isKind(item, "NestingTable") then
item:traverse(closure)
else
xxpcall(closure, item)
end
end
end
function NestingTable:pack(packName, ...)
local ret = {}
for key, item in pairs(self.m_items) do
if isKind(item, "NestingTable") then
ret[tostring(key)] = item:pack(packName, ...)
elseif packName then
ret[tostring(key)] = item[packName](item, ...)
else
ret[tostring(key)] = item
end
end
return ret
end
function NestingTable:packKey(deep)
assert(deep, "packKey")
local ret = {}
for key, item in pairs(self.m_items) do
if deep <= self.m_deep then
ret[tostring(key)] = item:packKey(deep)
else
table_insert(ret, key)
end
end
return ret
end
return NestingTable