From 304c581005a34f9df9a5e6ea7158969db5f5a079 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Fri, 22 Nov 2024 08:56:27 +0700 Subject: [PATCH] simple idpools module --- .vscode/extensions.json | 3 +- develop/untests.lua | 2 +- develop/untests/idpools_untests.lua | 85 +++++++++++++++++++++++++++++ evolved/evolved.lua | 1 + evolved/idpools.lua | 69 +++++++++++++++++++++++ 5 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 develop/untests/idpools_untests.lua create mode 100644 evolved/idpools.lua diff --git a/.vscode/extensions.json b/.vscode/extensions.json index d9b86f8..533d0a2 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,5 +1,6 @@ { "recommendations": [ - "sumneko.lua" + "sumneko.lua", + "tomblind.local-lua-debugger-vscode" ] } diff --git a/develop/untests.lua b/develop/untests.lua index 67ce65b..391df24 100644 --- a/develop/untests.lua +++ b/develop/untests.lua @@ -1 +1 @@ -local evo = require 'evolved.evolved' +require 'develop.untests.idpools_untests' diff --git a/develop/untests/idpools_untests.lua b/develop/untests/idpools_untests.lua new file mode 100644 index 0000000..ff0e23b --- /dev/null +++ b/develop/untests/idpools_untests.lua @@ -0,0 +1,85 @@ +local evo = require 'evolved.evolved' + +do + local p1 = evo.idpools.idpool() + local p2 = evo.idpools.idpool() + assert(p1 ~= p2) +end + +do + local p = evo.idpools.idpool() + + local i1_1 = evo.idpools.acquire_id(p) + assert(i1_1 == 0x100001) + + local i2_1 = evo.idpools.acquire_id(p) + assert(i2_1 == 0x100002) + + do + local i, v = evo.idpools.unpack_id(i1_1) + assert(i == 1 and v == 1) + end + + do + local i, v = evo.idpools.unpack_id(i2_1) + assert(i == 2 and v == 1) + end +end + +do + local p = evo.idpools.idpool() + + local i1_1 = evo.idpools.acquire_id(p) + local i2_1 = evo.idpools.acquire_id(p) + assert(evo.idpools.is_id_alive(p, i1_1)) + assert(evo.idpools.is_id_alive(p, i2_1)) + + evo.idpools.release_id(p, i1_1) + assert(not evo.idpools.is_id_alive(p, i1_1)) + assert(evo.idpools.is_id_alive(p, i2_1)) + + evo.idpools.release_id(p, i2_1) + assert(not evo.idpools.is_id_alive(p, i1_1)) + assert(not evo.idpools.is_id_alive(p, i2_1)) + + local i2_2 = evo.idpools.acquire_id(p) + assert(i2_2 == 0x200002) + + local i1_2 = evo.idpools.acquire_id(p) + assert(i1_2 == 0x200001) + + assert(not evo.idpools.is_id_alive(p, i1_1)) + assert(not evo.idpools.is_id_alive(p, i2_1)) + assert(evo.idpools.is_id_alive(p, i1_2)) + assert(evo.idpools.is_id_alive(p, i2_2)) +end + +do + local p = evo.idpools.idpool() + + for _ = 1, 0xFFFFF - 1 do + _ = evo.idpools.acquire_id(p) + end + + assert(evo.idpools.acquire_id(p) == 0x1FFFFF) + + if not os.getenv("LOCAL_LUA_DEBUGGER_VSCODE") then + assert(not pcall(evo.idpools.acquire_id, p)) + end +end + +do + local p = evo.idpools.idpool() + + for _ = 1, 0x7FF - 1 do + evo.idpools.release_id(p, evo.idpools.acquire_id(p)) + end + + local i1_7FF = evo.idpools.acquire_id(p) + assert(i1_7FF == 0x7FF00001) + evo.idpools.release_id(p, i1_7FF) + + local i1_1 = evo.idpools.acquire_id(p) + assert(i1_1 == 0x100001) + evo.idpools.release_id(p, i1_1) +end diff --git a/evolved/evolved.lua b/evolved/evolved.lua index 10a78cd..5996e8a 100644 --- a/evolved/evolved.lua +++ b/evolved/evolved.lua @@ -1,4 +1,5 @@ return { + idpools = require 'evolved.idpools', registry = require 'evolved.registry', singles = require 'evolved.singles', vectors = require 'evolved.vectors', diff --git a/evolved/idpools.lua b/evolved/idpools.lua new file mode 100644 index 0000000..e69b388 --- /dev/null +++ b/evolved/idpools.lua @@ -0,0 +1,69 @@ +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 self = { + acquired_ids = {}, + available_index = 0, + } + return setmetatable(self, 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) + 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