Files
evolved.lua/evolved/idpools.lua
2024-11-23 06:17:47 +07:00

78 lines
2.0 KiB
Lua

local bit = require 'bit'
---@class evolved.idpools
local idpools = {}
---@class evolved.idpool
---@field acquired_ids integer[]
---@field available_index integer
local evolved_idpool_mt = {}
evolved_idpool_mt.__index = evolved_idpool_mt
---@return evolved.idpool
function idpools.idpool()
---@type evolved.idpool
local idpool = {
acquired_ids = {},
available_index = 0,
}
return setmetatable(idpool, evolved_idpool_mt)
end
---@param id integer
---@return integer index
---@return integer version
function idpools.unpack_id(id)
return bit.band(id, 0xFFFFF), bit.rshift(id, 20)
end
---@param idpool evolved.idpool
---@return integer
---@nodiscard
function idpools.acquire_id(idpool)
if idpool.available_index ~= 0 then
local index = idpool.available_index
local version = bit.band(idpool.acquired_ids[index], 0x7FF00000)
idpool.available_index = bit.band(idpool.acquired_ids[index], 0xFFFFF)
idpool.acquired_ids[index] = index + version
return idpool.acquired_ids[index]
end
if #idpool.acquired_ids == 0xFFFFF then
error('id index overflow', 2)
end
local index, version = #idpool.acquired_ids + 1, 0x100000
idpool.acquired_ids[index] = index + version
return idpool.acquired_ids[index]
end
---@param idpool evolved.idpool
---@param id integer
function idpools.release_id(idpool, id)
local index = bit.band(id, 0xFFFFF)
local version = bit.band(id, 0x7FF00000)
if idpool.acquired_ids[index] ~= id then
error('id is not acquired or already released', 2)
end
version = version == 0x7FF00000
and 0x100000
or version + 0x100000
idpool.acquired_ids[index] = idpool.available_index + version
idpool.available_index = index
end
---@param idpool evolved.idpool
---@param id integer
---@return boolean
---@nodiscard
function idpools.is_id_alive(idpool, id)
local index = bit.band(id, 0xFFFFF)
return idpool.acquired_ids[index] == id
end
return idpools