Page 2 of 2

Re: Best way to iterate and remove

Posted: Thu Dec 19, 2013 11:47 am
by bartbes
Well, pairs uses next internally, and the docs have this to say about next:
The behavior of next is undefined if, during the traversal, you assign any value to a non-existent field in the table. You may however modify existing fields. In particular, you may clear existing fields.
Note that pairs is approximated by:

Code: Select all

function pairs(t)
    return next, t, nil
end

Re: Best way to iterate and remove

Posted: Thu Dec 19, 2013 9:37 pm
by Dattorz
For my engine, I wrote an ObjectList class that handles this pretty nicely. The idea is that changes (added/removed objects) only become "visible" after performing a manual sync on the list object for performance and consistency reasons. Generally one would perform the sync between each iteration. Syncing inside an iteration will lead to undefined behavior.

Marking an object for release adds its index as a value to the "objects needing release" table. During the sync, any objects that have been marked for release get nil'd out in the table, and only afterward does the list get re-compacted. I manually compact the list myself, rather than relying on table.remove(). In fact, the code doesn't use any table.* functions!

I tested the thing on removing 20,000 objects (the current hard object limit in my engine) and they all went poof without a hitch.

Only thing it doesn't do currently is sorting, though I imagine that might be pretty easy to add in...?

The code for it is here (though it's old and could use some cleanup - I'm pretty sure _count and _releaseListEmpty aren't actually necessary):
https://github.com/dattorz/klua/blob/ma ... ctlist.lua

You are free to use it; just don't claim it as your own.