minetest_x_bows/bin/lua-language-server-3.5.6-l.../script/gc.lua
2022-11-03 11:37:33 -04:00

119 lines
2.9 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

local util = require 'utility'
---@class gc
---@field _list table
local mt = {}
mt.__index = mt
mt.type = 'gc'
mt._removed = false
mt._max = 10
local function destroyGCObject(obj)
local tp = type(obj)
if tp == 'function' then
xpcall(obj, log.error)
elseif tp == 'table' then
local remove = obj.remove
if type(remove) == 'function' then
xpcall(remove, log.error, obj)
end
end
end
local function isRemoved(obj)
local tp = type(obj)
if tp == 'function' then
for i = 1, 1000 do
local n, v = debug.getupvalue(obj, i)
if not n then
log.warn('函数式析构器没有 removed 上值!', util.dump(debug.getinfo(obj)))
break
end
if n == 'removed' then
if v then
return true
end
break
end
end
elseif tp == 'table' then
if obj._removed then
return true
end
end
return false
end
local function zip(self)
local list = self._list
local index = 1
for i = 1, #list do
local obj = list[index]
if not obj then
break
end
if isRemoved(obj) then
if index == #list then
list[#list] = nil
break
end
list[index] = list[#list]
else
index = index + 1
end
end
self._max = #list * 1.5
if self._max < 10 then
self._max = 10
end
end
function mt:remove()
if self._removed then
return
end
self._removed = true
local list = self._list
for i = 1, #list do
destroyGCObject(list[i])
end
end
--- 标记`obj`在buff移除时自动移除。如果`obj`是个`function`,
--- 则直接调用;如果`obj`是个`table`,则调用内部的`remove`方法。
--- 其他情况不做处理
---@param obj any
---@return any
function mt:add(obj)
if self._removed then
destroyGCObject(obj)
return nil
end
self._list[#self._list+1] = obj
if #self._list > self._max then
zip(self)
end
return obj
end
--- 创建一个gc容器使用 `gc:add(obj)` 将析构器放入gc容器。
---
--- 当gc容器被销毁时会调用内部的析构器不保证调用顺序
---
--- 析构器必须是以下格式中的一种:
--- 1. 一个对象,使用 `obj:remove()` 方法来析构,使用 `obj._removed` 属性来标记已被析构。
--- 2. 一个析构函数,使用上值 `removed` 来标记已被析构。
---
--- ```lua
--- local gc = ac.gc() -- 创建gc容器
--- gc:add(obj1) -- 将obj1放入gc容器
--- gc:add(obj2) -- 将obj2放入gc容器
--- gc:remove() -- 移除gc容器同时也会移除obj1与obj2
--- ```
return function ()
return setmetatable({
_list = {},
}, mt)
end