From d329532d12907f2f27f7c336ab0498700931317a Mon Sep 17 00:00:00 2001 From: ruki Date: Sun, 6 Oct 2024 23:09:48 +0800 Subject: [PATCH 1/5] improve hashset --- tests/modules/hashset/test.lua | 17 ++++++++++ xmake/core/base/hashset.lua | 59 ++++++++++++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 tests/modules/hashset/test.lua diff --git a/tests/modules/hashset/test.lua b/tests/modules/hashset/test.lua new file mode 100644 index 00000000000..a0df5a61d11 --- /dev/null +++ b/tests/modules/hashset/test.lua @@ -0,0 +1,17 @@ +import("core.base.hashset") + +function test_hashset(t) + local h = hashset.of(1, 2, 3, 5, 5, 7, 1, 9, 4, 6, 8, 0) + t:require(h:size() == 10) + t:require_not(h:empty()) + for item in h:items() do + t:require(h:has(item)) + t:require_not(h:has(item + 10)) + end + local prev = -1 + for item in h:orderitems() do + t:require(item > prev) + prev = item + end +end + diff --git a/xmake/core/base/hashset.lua b/xmake/core/base/hashset.lua index 2a0449ad4ea..e6668180bea 100644 --- a/xmake/core/base/hashset.lua +++ b/xmake/core/base/hashset.lua @@ -108,7 +108,62 @@ function hashset_impl:to_array() return result end --- iterate keys of hashtable +-- iterate items +-- +-- @code +-- for item in instance:items() do +-- ... +-- end +-- @endcode +-- +function hashset_impl:items() + return function (t, item) + local k, _ = next(t._DATA, item) + if k == hashset._NIL then + return nil + else + return k + end + end, self, nil +end + +-- iterate order items +-- +-- @code +-- for item in instance:orderitems() do +-- ... +-- end +-- @endcode +-- +function hashset_impl:orderitems() + local orderkeys = table.orderkeys(self._DATA, function (a, b) + if a == hashset._NIL then + a = math.inf + end + if b == hashset._NIL then + b = math.inf + end + if type(a) == "table" then + a = tostring(a) + end + if type(b) == "table" then + b = tostring(b) + end + return a < b + end) + local i = 1 + return function (t, k) + k = orderkeys[i] + i = i + 1 + if k == hashset._NIL then + return nil + else + return k + end + end, self, nil +end + +-- iterate keys (deprecated, please use items()) -- -- @code -- for _, key in instance:keys() do @@ -127,7 +182,7 @@ function hashset_impl:keys() end, self, nil end --- order keys iterator +-- iterate order keys (deprecated, please use orderitems()) -- -- @code -- for _, key in instance:orderkeys() do From 0ee97cd2935031e4181383c15e8121b1f52461c1 Mon Sep 17 00:00:00 2001 From: ruki Date: Sun, 6 Oct 2024 23:31:21 +0800 Subject: [PATCH 2/5] add clone and eq to hashset --- tests/modules/hashset/test.lua | 8 ++ xmake/core/base/hashset.lua | 131 ++++++++++++++++++++------------- 2 files changed, 89 insertions(+), 50 deletions(-) diff --git a/tests/modules/hashset/test.lua b/tests/modules/hashset/test.lua index a0df5a61d11..be75815ed7e 100644 --- a/tests/modules/hashset/test.lua +++ b/tests/modules/hashset/test.lua @@ -13,5 +13,13 @@ function test_hashset(t) t:require(item > prev) prev = item end + local h2 = h:clone() + t:require(h == h2) + h2:insert(11) + t:require_not(h == h2) + h2:remove(11) + t:require(h == h2) + h2:clear() + t:require(h2:empty()) end diff --git a/xmake/core/base/hashset.lua b/xmake/core/base/hashset.lua index e6668180bea..c6237a77ff1 100644 --- a/xmake/core/base/hashset.lua +++ b/xmake/core/base/hashset.lua @@ -14,32 +14,27 @@ -- -- Copyright (C) 2015-present, TBOOX Open Source Group. -- --- @author OpportunityLiu +-- @author OpportunityLiu, ruki -- @file hashset.lua -- --- define module -local hashset = hashset or {} -local hashset_impl = hashset.__index or {} - -- load modules -local table = require("base/table") -local todisplay = require("base/todisplay") +local object = require("base/object") +local table = require("base/table") +local todisplay = require("base/todisplay") --- representaion for nil key -hashset._NIL = setmetatable({}, { __todisplay = function() return "${reset}${color.dump.keyword}nil${reset}" end, __tostring = function() return "symbol(nil)" end }) +-- define module +local hashset = hashset or object { _init = {"_DATA", "_SIZE"} } -function hashset:__todisplay() - return string.format("hashset${reset}(%s) {%s}", todisplay(self._SIZE), table.concat(table.imap(table.keys(self._DATA), function (i, k) - if i > 10 then - return nil - elseif i == 10 and self._SIZE ~= 10 then - return "..." - else - return todisplay(k) - end - end), ", ")) -end +-- representaion for nil key +hashset._NIL = setmetatable({}, { + __todisplay = function() + return "${reset}${color.dump.keyword}nil${reset}" + end, + __tostring = function() + return "symbol(nil)" + end +}) function hashset._to_key(key) if key == nil then @@ -48,35 +43,43 @@ function hashset._to_key(key) return key end --- make a new hashset -function hashset.new() - return setmetatable({ _DATA = {}, _SIZE = 0 }, hashset) -end - --- construct from list of items -function hashset.of(...) - local result = hashset.new() - local data = table.pack(...) - for i = 1, data.n do - result:insert(data[i]) +-- h1 == h1? +function hashset:__eq(h) + if self._DATA == h._DATA then + return true end - return result + if self:size() ~= h:size() then + return false + end + for item in h:items() do + if not self:has(item) then + return false + end + end + return true end --- construct from an array -function hashset.from(array) - assert(array) - return hashset.of(table.unpack(array)) +-- to display +function hashset:__todisplay() + return string.format("hashset${reset}(%s) {%s}", todisplay(self._SIZE), table.concat(table.imap(table.keys(self._DATA), function (i, k) + if i > 10 then + return nil + elseif i == 10 and self._SIZE ~= 10 then + return "..." + else + return todisplay(k) + end + end), ", ")) end -- check value is in hashset -function hashset_impl:has(value) +function hashset:has(value) value = hashset._to_key(value) return self._DATA[value] or false end -- insert value to hashset, returns false if value has already in the hashset -function hashset_impl:insert(value) +function hashset:insert(value) value = hashset._to_key(value) local result = not (self._DATA[value] or false) if result then @@ -87,7 +90,7 @@ function hashset_impl:insert(value) end -- remove value from hashset, returns false if value is not in the hashset -function hashset_impl:remove(value) +function hashset:remove(value) value = hashset._to_key(value) local result = self._DATA[value] or false if result then @@ -98,7 +101,7 @@ function hashset_impl:remove(value) end -- convert hashset to an array, nil in the set will be ignored -function hashset_impl:to_array() +function hashset:to_array() local result = {} for k, _ in pairs(self._DATA) do if k ~= hashset._NIL then @@ -116,7 +119,7 @@ end -- end -- @endcode -- -function hashset_impl:items() +function hashset:items() return function (t, item) local k, _ = next(t._DATA, item) if k == hashset._NIL then @@ -135,7 +138,7 @@ end -- end -- @endcode -- -function hashset_impl:orderitems() +function hashset:orderitems() local orderkeys = table.orderkeys(self._DATA, function (a, b) if a == hashset._NIL then a = math.inf @@ -171,7 +174,7 @@ end -- end -- @endcode -- -function hashset_impl:keys() +function hashset:keys() return function (t, key) local k, _ = next(t._DATA, key) if k == hashset._NIL then @@ -190,7 +193,7 @@ end -- end -- @endcode -- -function hashset_impl:orderkeys() +function hashset:orderkeys() local orderkeys = table.keys(self._DATA) table.sort(orderkeys, function (a, b) if a == hashset._NIL then @@ -220,26 +223,54 @@ function hashset_impl:orderkeys() end -- get size of hashset -function hashset_impl:size() +function hashset:size() return self._SIZE end -- is empty? -function hashset_impl:empty() +function hashset:empty() return self:size() == 0 end -- get data of hashset -function hashset_impl:data() +function hashset:data() return self._DATA end -- clear hashset -function hashset_impl:clear() +function hashset:clear() self._DATA = {} self._SIZE = 0 end --- return module -hashset.__index = hashset_impl +-- clone hashset +function hashset:clone() + local h = hashset.new() + h._SIZE = self._SIZE + h._DATA = table.clone(self._DATA) + return h +end + +-- construct from list of items +function hashset.of(...) + local result = hashset.new() + local data = table.pack(...) + for i = 1, data.n do + result:insert(data[i]) + end + return result +end + +-- construct from an array +function hashset.from(array) + assert(array) + return hashset.of(table.unpack(array)) +end + +-- new hashset +function hashset.new() + return hashset {{}, 0} +end + +-- return module: hashset return hashset From 44f05cd75d6fb26adde30b4f055623ffe241eacd Mon Sep 17 00:00:00 2001 From: ruki Date: Sun, 6 Oct 2024 23:39:14 +0800 Subject: [PATCH 3/5] improve to_array --- tests/modules/hashset/test.lua | 1 + xmake/core/base/hashset.lua | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/modules/hashset/test.lua b/tests/modules/hashset/test.lua index be75815ed7e..c7222dcacf8 100644 --- a/tests/modules/hashset/test.lua +++ b/tests/modules/hashset/test.lua @@ -21,5 +21,6 @@ function test_hashset(t) t:require(h == h2) h2:clear() t:require(h2:empty()) + t:require(h == hashset.from(h:to_array())) end diff --git a/xmake/core/base/hashset.lua b/xmake/core/base/hashset.lua index c6237a77ff1..87acf6ceec8 100644 --- a/xmake/core/base/hashset.lua +++ b/xmake/core/base/hashset.lua @@ -103,9 +103,9 @@ end -- convert hashset to an array, nil in the set will be ignored function hashset:to_array() local result = {} - for k, _ in pairs(self._DATA) do - if k ~= hashset._NIL then - table.insert(result, k) + for item in self:items() do + if item ~= nil then + table.insert(result, item) end end return result From 69e854c602c1df0e72c2423fe53340816eff89c3 Mon Sep 17 00:00:00 2001 From: ruki Date: Sun, 6 Oct 2024 23:40:22 +0800 Subject: [PATCH 4/5] remove assert --- xmake/core/base/hashset.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/xmake/core/base/hashset.lua b/xmake/core/base/hashset.lua index 87acf6ceec8..ecdfe72fb99 100644 --- a/xmake/core/base/hashset.lua +++ b/xmake/core/base/hashset.lua @@ -263,7 +263,6 @@ end -- construct from an array function hashset.from(array) - assert(array) return hashset.of(table.unpack(array)) end From 5995fe8beb75a2f8e4438cdccc7186430953f5ed Mon Sep 17 00:00:00 2001 From: ruki Date: Sun, 6 Oct 2024 23:46:59 +0800 Subject: [PATCH 5/5] improve hashset.from --- xmake/core/base/hashset.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/xmake/core/base/hashset.lua b/xmake/core/base/hashset.lua index ecdfe72fb99..5d0ea761e60 100644 --- a/xmake/core/base/hashset.lua +++ b/xmake/core/base/hashset.lua @@ -263,7 +263,11 @@ end -- construct from an array function hashset.from(array) - return hashset.of(table.unpack(array)) + local result = hashset.new() + for i = 1, #array do + result:insert(array[i]) + end + return result end -- new hashset