summaryrefslogtreecommitdiff
path: root/xmake/core/base/hashset.lua
diff options
context:
space:
mode:
authorruki <[email protected]>2026-04-15 14:16:16 +0800
committerGitHub <[email protected]>2026-04-15 14:16:16 +0800
commitfabb25749492d6b26887da0217486bfbfd104bdd (patch)
treedd7456ec5a1a24044f32a74f7fcce3d107d9a1c6 /xmake/core/base/hashset.lua
parent346f929f7819e92e2752c7b3335894297fb02630 (diff)
parentbf5af4c886923bc2ce7cad3816d5f3cb71e770e3 (diff)
Merge pull request #7485 from xmake-io/pairs
improve pairs for lua5.5
Diffstat (limited to 'xmake/core/base/hashset.lua')
-rw-r--r--xmake/core/base/hashset.lua92
1 files changed, 57 insertions, 35 deletions
diff --git a/xmake/core/base/hashset.lua b/xmake/core/base/hashset.lua
index c052d36ee..405a23474 100644
--- a/xmake/core/base/hashset.lua
+++ b/xmake/core/base/hashset.lua
@@ -119,15 +119,27 @@ end
-- end
-- @endcode
--
+-- Stateful closure so the loop body can safely reassign the first loop
+-- variable under lua 5.4+ (paired with the RDKCONST->VDKREG compile-time
+-- patch in core/src/lua/xmake.lua).
function hashset: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
+ -- keep `next`'s key in an upvalue so the loop body can safely reassign
+ -- the first loop variable. In lua 5.4+ the for-in control slot is
+ -- merged with the first user variable; threading the key through the
+ -- loop would otherwise corrupt `next` on the following iteration.
+ --
+ -- nil-as-a-member is stored under the `_NIL` sentinel. For-loop
+ -- semantics don't let us yield nil (it would end the loop), so we
+ -- skip the sentinel and continue to the next real key; the nil
+ -- member is omitted but entries after it are still visited.
+ local data = self._DATA
+ local k = nil
+ return function ()
+ repeat
+ k = next(data, k)
+ until k ~= hashset._NIL
+ return k
+ end
end
-- iterate order items
@@ -154,16 +166,18 @@ function hashset:orderitems()
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
+ -- see hashset:items() for the `_NIL` handling rationale
+ local n = #orderkeys
+ local i = 0
+ return function ()
+ local k
+ repeat
+ i = i + 1
+ if i > n then return nil end
+ k = orderkeys[i]
+ until k ~= hashset._NIL
+ return k
+ end
end
-- iterate keys (deprecated, please use items())
@@ -175,14 +189,19 @@ end
-- @endcode
--
function hashset:keys()
- return function (t, key)
- local k, _ = next(t._DATA, key)
- if k == hashset._NIL then
- return k, nil
- else
- return k, k
+ -- see hashset:items() for the stateful-closure rationale and the
+ -- `_NIL` skipping behavior.
+ local data = self._DATA
+ local k = nil
+ return function ()
+ repeat
+ k = next(data, k)
+ until k ~= hashset._NIL
+ if k == nil then
+ return nil
end
- end, self, nil
+ return k, k
+ end
end
-- iterate order keys (deprecated, please use orderitems())
@@ -194,6 +213,8 @@ end
-- @endcode
--
function hashset:orderkeys()
+ -- see hashset:items() for the stateful-closure rationale and the
+ -- `_NIL` skipping behavior.
local orderkeys = table.keys(self._DATA)
table.sort(orderkeys, function (a, b)
if a == hashset._NIL then
@@ -210,16 +231,17 @@ function hashset:orderkeys()
end
return a < b
end)
- local i = 1
- return function (t, k)
- k = orderkeys[i]
- i = i + 1
- if k == hashset._NIL then
- return k, nil
- else
- return k, k
- end
- end, self, nil
+ local n = #orderkeys
+ local i = 0
+ return function ()
+ local k
+ repeat
+ i = i + 1
+ if i > n then return nil end
+ k = orderkeys[i]
+ until k ~= hashset._NIL
+ return k, k
+ end
end
-- get size of hashset