-
-
Notifications
You must be signed in to change notification settings - Fork 23.4k
[3.x] Fast child iteration in Node
, Spatial
, CanvasItem
#107702
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For me this is more of an indicator to use iterators instead.
Iterators use ptr
iteration (or should at least, not sure where 3.x is at), and so are optimal on that front. But we don't need to do the manual 'ptr()' dance to avoid redundant index checks.
As I said before, I hate iterators with a passion, I prefer to see exactly what is happening. Many of us older gen prefer to use c++ as c with classes, and minimize the overly clever c++ stuff. Juan has written quite a bit on this subject, and keeping the codebase accessible as much as possible has been important in allowing contributors to get into it as easily as possible. 3.x hardly uses any iterators, and I'm keen to keep it that way. If the project as a whole were to insist on iterators, I would move on to a different project. I did originally add a function |
53c7ee7
to
aa3dc85
Compare
aa3dc85
to
cd9713e
Compare
Indeed we don't have iterators in 3.x for There is also a potential problem with the current iterators in 4.x (and why we can't use it instead of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested locally, it works as expected. Code looks good to me.
Is this PR applicable to 4.x, or should we go for a different solution there? |
Thanks! |
I did move 4.x to use |
+1. |
Now that these node types are using
LocalVector
for children, we have the opportunity to speed up child access in bottleneck loops by using the unguarded access and saving needlessERR_FAIL_INDEX
checks.Really inside hot loops, there is no good reason to use the
[]
operator inLocalVector
(which contains aCRASH_COND
range check). We have already checked the size condition at the start of the loop, so it should never trigger.There are previously two ways of doing unguarded access to elements:
ptr()
before the loop, and get a raw pointer which can be dereferenced during the loopptr()
each time within the loop, and deference during the loop(1) is fine when the size of the
LocalVector
can be guaranteed never to change during iteration.(2) is safer when the vector may be resized.
The primary reason for (2) is that during a resize, the base address of the data may change (during a grow or shrink). A resize will also potentially invalidate iterators (used in 4.x, but not present in 3.x) and cause crashes / UB, so using 4.x style iterators is not an option here for (2).
get_unchecked()
Although I began this PR using the
vector.ptr()[..]
type syntax for (2), I thought it would be likely nicer to add syntactic sugar here and add a wrapper function. There are several advantages of a wrapper:()[]
which is not something you see so commonly in c++)DEV_ENABLED
checks to prevent errors creeping in during developmentThis PR
In this PR I add some cases where we can use either method (1) above, or the
get_unchecked()
version.Notes
children_lock
fromSpatial
as it is unused.Things to watch for in
LocalVector
iteration in generalresize
).Any stored raw pointers / iterators may become invalid.
Any local
num_children
stored outside the loop becomes invalid. Getting thenum_children
each time is safer, although may not be optimized out in all cases versus storing in a local variable.There is no thread protection in
LocalVector
.