fix(lua/splay_tree): for_each method was crashing if the map was updated during for_each
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
64cce595a5
commit
abe93dfec0
2 changed files with 38 additions and 1 deletions
|
@ -168,7 +168,11 @@ static int splay_map_pred(lua_State * L) {
|
|||
}
|
||||
|
||||
static int splay_map_for_each(lua_State * L) {
|
||||
lua_splay_map & m = to_splay_map(L, 1); // map
|
||||
// Remark: we take a copy of the map to make sure
|
||||
// for_each will not crash if the map is updated while being
|
||||
// traversed.
|
||||
// The copy operation is very cheap O(1).
|
||||
lua_splay_map m(to_splay_map(L, 1)); // map
|
||||
luaL_checktype(L, 2, LUA_TFUNCTION); // user-fun
|
||||
m.for_each([&](lua_ref const & k, lua_ref const & v) {
|
||||
lua_pushvalue(L, 2); // push user-fun
|
||||
|
|
33
tests/lua/map2.lua
Normal file
33
tests/lua/map2.lua
Normal file
|
@ -0,0 +1,33 @@
|
|||
local m = splay_map()
|
||||
for i = 1, 100 do
|
||||
m:insert(i, i * 3)
|
||||
end
|
||||
|
||||
local prev_k = nil
|
||||
-- It is safe to add/erase elements from m while we are traversing.
|
||||
-- The for_each method will traverse the elements that are in m
|
||||
-- when the for_each is invoked
|
||||
m:for_each(
|
||||
function(k, v)
|
||||
if prev_k then
|
||||
assert(prev_k < k)
|
||||
end
|
||||
print(k .. " -> " .. v)
|
||||
prev_k = k
|
||||
m:insert(-k, v)
|
||||
end
|
||||
)
|
||||
|
||||
assert(m:size() == 200)
|
||||
m2 = m:copy()
|
||||
m:for_each(
|
||||
function(k, v)
|
||||
assert(m2:contains(-k))
|
||||
assert(m2:find(-k) == v)
|
||||
if k > 0 then
|
||||
m:erase(k)
|
||||
end
|
||||
end
|
||||
)
|
||||
assert(m:size() == 100)
|
||||
m:for_each(function(k, v) assert(k < 0) end)
|
Loading…
Reference in a new issue