Skip to content

Refactor moving entity to new table#23151

Open
JaySpruce wants to merge 2 commits intobevyengine:mainfrom
JaySpruce:table_move_refactor
Open

Refactor moving entity to new table#23151
JaySpruce wants to merge 2 commits intobevyengine:mainfrom
JaySpruce:table_move_refactor

Conversation

@JaySpruce
Copy link
Member

Objective

When moving an entity from one table to another, we have 3 methods available:

  • move_to_superset_unchecked, for moving during insertion.
  • move_to_and_drop_missing_unchecked, for moving during normal removal.
  • move_to_and_forget_missing_unchecked, for moving during take removal.

However, when looking at flecs (to steal ideas, naturally), I noticed it just has one function for moving during insertion and removal: flecs_table_move. It also handles things a bit differently internally (details on that below).

Solution

There are essentially 3 somewhat independent changes here:

  • Combining the 3 methods into 1 called move_row.
  • Moving the move method to Tables and taking TableIds (rather than being Table::move_to(&mut self, other: &mut Table)).
  • Changing the internals of the move method to be more like flecs.

Combining the methods

The 3 methods were already very similar; move_to_superset just didn't check if components were missing. They could be combined without any of the other changes, but it's possible that insertion performance would suffer.

TableId instead of &mut Table

I believe the idea behind using references instead of IDs was to be able to cache the pointers and avoid fetching the tables more than once. However, the only callers of the move_to methods, BunderInserter and BundleRemover, only used the pointers for the move_to methods and didn't need them for anything else, so there isn't much point in caching them. And being able to just use IDs makes the code nicer, since we don't have to dance around the borrow checker.

Internals

Bevy's move_to methods don't rely on tables' columns being in any certain order; they just iterate the source table and fetch each matching column from the destination table individually.

flecs_table_move requires that tables' columns are sorted (by component ID, low-to-high). It iterates the source and destination tables at the same time (i.e. their component IDs and corresponding columns), but pauses one iterator when the other "falls behind" (has a lower component ID). If the source table falls behind, the source table's current component ID was removed, and if the destination table falls behind, the destination table's current component ID was added.

As it turns out, Bevy's tables are sorted in practice, we just never guaranteed or relied on it. A table's list of component IDs are sorted to use as the key in a HashMap, and the same list is used to build the table. So we can just make it official by asserting that a table's components are sorted when the table is finalized (TableBuilder::build).

Evidently, iterating the destination table is faster than fetching from it repeatedly:

Screenshot_20260224_135012

Misc

There's a PERF comment that has survived since 2021 (#2673) and I'm not really sure what it means:

// PERF: store "non bundle" components in edge, then just move those to avoid
// redundant copies

I didn't want to remove it without saying anything, but I think it's lived long enough.

@JaySpruce JaySpruce added A-ECS Entities, components, systems, and events C-Performance A change motivated by improving speed, memory usage or compile times C-Code-Quality A section of code that is hard to understand or change S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Feb 25, 2026
@github-project-automation github-project-automation bot moved this to Needs SME Triage in ECS Feb 25, 2026
@JaySpruce JaySpruce added the D-Unsafe Touches with unsafe code in some way label Feb 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-ECS Entities, components, systems, and events C-Code-Quality A section of code that is hard to understand or change C-Performance A change motivated by improving speed, memory usage or compile times D-Unsafe Touches with unsafe code in some way S-Needs-Review Needs reviewer attention (from anyone!) to move forward

Projects

Status: Needs SME Triage

Development

Successfully merging this pull request may close these issues.

1 participant