bevy/crates
Oliver Maskery 022c6b1d34
Prevent creation of superfluous empty table (#16935)
# Objective

- To fix a tiny bug in `bevy_ecs::storage::Tables` that, in one case,
means it accidentally allocates an additional "empty" `Table`, resulting
in two "empty" `Table`s:
- The one pre-allocated empty table at index 0 whose index is designed
to match up with `TableId::empty()`
- One extra empty table, at some non-0 index, that does not match up
with `TableId::empty()`.
- This PR aims to prevent this extraneous `Table`, ensuring that
entities with no components in table-storage reliably have their
archetype's table ID be equal to `TableId::empty()`.

## Solution

### Background

The issue occurs because:

- `Tables` contains:
- `tables: Vec<Table>` - The set of all `Table`s allocated in the world.
- `table_ids: HashMap<Box<[ComponentId]>, TableId>` - An index to
rapidly lookup the `Table` in `tables` by a set of `ComponentId`s.
- When `Tables` is constructed it pre-populates the `tables` `Vec` with
an empty `Table`.
- This ensures that the first entry (index 0) is always the `Table` for
entities with no components in table storage.
- In particular, `TableId::empty()` is a utility that returns a
`TableId` of `0`.
- However, the `table_ids` map is not initialised to associate an empty
`[ComponentId]` with `TableId` `0`.
- This means, the first time a structural change tries to access a
`Table` for an archetype with 0 table components:
  - `Tables::get_id_or_insert` is used to retrieve the target `Table`
- The function attempts to lookup the entry in the `table_ids` `HashMap`
whose key is the empty `ComponentId` set
- The empty `Table` created at startup won't be found, because it was
never inserted into `table_ids`
- It will instead create a new table, insert it into the `HashMap`
(preventing further instances of this issue), and return it.

### Changes

- I considered simply initialising the `table_ids` `HashMap` to know
about the pre-allocated `Table`
- However, I ended up using the proposed solution discussed on Discord
[#ecs-dev](https://discord.com/channels/691052431525675048/749335865876021248/1320430933152759958):
- Make `Tables::get_id_or_insert` simply early-exit if the requested
`component_ids` was empty.
- This avoids unnecessarily hashing the empty slice and looking it up in
the `HashMap`.
- The `table_ids` `HashMap` is not exposed outside this struct, and is
only used within `get_id_or_insert`, so it seems wasteful to defensively
populate it with the empty `Table`.

## Testing

This is my first Bevy contribution, so I don't really know the processes
that well. That said:
- I have introduced a little test that exercises the original issue and
shows that it is now resolved.
- I have run the `bevy_ecs` tests locally, so I have reasonable
confidence I haven't broken that.
- I haven't run any further test suites, mostly as when I tried to run
test suites for the whole project it filled my entire SSD with >600GB of
target directory output 😱😱😱
2024-12-22 23:04:32 +00:00
..
bevy_a11y Replace bevy_a11y::Focus with InputFocus (#16863) 2024-12-18 00:16:19 +00:00
bevy_animation Remove bevy_core (#16897) 2024-12-19 18:36:51 +00:00
bevy_app Remove bevy_core (#16897) 2024-12-19 18:36:51 +00:00
bevy_asset Remove bevy_core (#16897) 2024-12-19 18:36:51 +00:00
bevy_audio Move Volume and GlobalVolume to own file (#16838) 2024-12-16 19:28:30 +00:00
bevy_color Deny derive_more error feature and replace it with thiserror (#16684) 2024-12-06 17:03:55 +00:00
bevy_core_pipeline Remove bevy_core (#16897) 2024-12-19 18:36:51 +00:00
bevy_derive Add benchmarks and compile_fail tests back to workspace (#16858) 2024-12-21 22:30:29 +00:00
bevy_dev_tools Draw the UI debug overlay using the UI renderer (#16693) 2024-12-11 00:49:47 +00:00
bevy_diagnostic Remove bevy_core (#16897) 2024-12-19 18:36:51 +00:00
bevy_dylib Generate links to definition in source code pages on docs.rs and dev-docs.bevyengine.org (#12965) 2024-07-29 23:10:16 +00:00
bevy_ecs Prevent creation of superfluous empty table (#16935) 2024-12-22 23:04:32 +00:00
bevy_encase_derive Rust 1.83, allow -> expect (missing_docs) (#16561) 2024-12-16 23:27:57 +00:00
bevy_gilrs Deny derive_more error feature and replace it with thiserror (#16684) 2024-12-06 17:03:55 +00:00
bevy_gizmos Add dashed lines (#16884) 2024-12-18 20:43:58 +00:00
bevy_gltf Remove bevy_core (#16897) 2024-12-19 18:36:51 +00:00
bevy_hierarchy Remove bevy_core (#16897) 2024-12-19 18:36:51 +00:00
bevy_image Rust 1.83, allow -> expect (missing_docs) (#16561) 2024-12-16 23:27:57 +00:00
bevy_input Remove bevy_core (#16897) 2024-12-19 18:36:51 +00:00
bevy_input_focus Remove SetInputFocus helper trait (#16888) 2024-12-19 00:40:10 +00:00
bevy_internal Remove bevy_core (#16897) 2024-12-19 18:36:51 +00:00
bevy_log Use en-us locale for typos (#16037) 2024-10-20 18:55:17 +00:00
bevy_macro_utils Use one BevyManifest instance in proc macros (#16766) 2024-12-15 15:00:05 +00:00
bevy_math f32 -> Rot2 in bounding volume docs (#16848) 2024-12-17 00:12:49 +00:00
bevy_mesh Rust 1.83, allow -> expect (missing_docs) (#16561) 2024-12-16 23:27:57 +00:00
bevy_mikktspace Rust 1.83, allow -> expect (missing_docs) (#16561) 2024-12-16 23:27:57 +00:00
bevy_pbr Fix several regressions from recent rendering changes. (#16890) 2024-12-22 23:03:06 +00:00
bevy_picking Rust 1.83, allow -> expect (missing_docs) (#16561) 2024-12-16 23:27:57 +00:00
bevy_ptr Fix MSRVs for standalone crates (#16333) 2024-11-17 09:38:13 +00:00
bevy_reflect Replace impl_param_set proc macro with a macro_rules macro (#16847) 2024-12-18 18:30:46 +00:00
bevy_remote BRP strict field in query (#16725) 2024-12-14 05:22:19 +00:00
bevy_render Fix several regressions from recent rendering changes. (#16890) 2024-12-22 23:03:06 +00:00
bevy_scene Add missing #[reflect(Component, Default)] to SceneRoot and DynamicSceneRoot. (#16816) 2024-12-15 19:18:22 +00:00
bevy_sprite Change GpuImage::size from UVec2 to Extent3d (#16815) 2024-12-17 19:08:09 +00:00
bevy_state Replace impl_param_set proc macro with a macro_rules macro (#16847) 2024-12-18 18:30:46 +00:00
bevy_tasks Remove bevy_core (#16897) 2024-12-19 18:36:51 +00:00
bevy_text fix tiny copy-paste mistake in bevy_text::font_atlas_set (#16667) 2024-12-10 03:17:09 +00:00
bevy_time Use en-us locale for typos (#16037) 2024-10-20 18:55:17 +00:00
bevy_transform track_change_detection: Also track spawns/despawns (#16047) 2024-12-17 04:46:31 +00:00
bevy_ui Change GpuImage::size from UVec2 to Extent3d (#16815) 2024-12-17 19:08:09 +00:00
bevy_utils Add no_std support to bevy_ecs (#16758) 2024-12-17 21:40:36 +00:00
bevy_window Replace bevy_a11y::Focus with InputFocus (#16863) 2024-12-18 00:16:19 +00:00
bevy_winit Replace bevy_a11y::Focus with InputFocus (#16863) 2024-12-18 00:16:19 +00:00