diff --git a/CHANGELOG.md b/CHANGELOG.md index c1ca5d43..b5d40e62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,17 +1,23 @@ +## [[v0.14.3]](https://github.com/mlange-42/arche/compare/v0.14.2...v0.14.3) + +### Performance + +* Avoids a bitmask heap escape in world component operations (add, remove, exchange, ...), with around 20ns improvement (#452) + ## [[v0.14.2]](https://github.com/mlange-42/arche/compare/v0.14.1...v0.14.2) ### Performance -* Optimize `MapX.Assign` and `MapX.NewWith` by use of `World.GetUnchecked` (#449) +* Optimizes `MapX.Assign` and `MapX.NewWith` by use of `World.GetUnchecked` (#449) ### Documentation -* Fix method names and ordering in benchmark tables (#448) -* Document listener notification handling in `MapX.NewWith` (#450) +* Fixes method names and ordering in benchmark tables (#448) +* Documents listener notification handling in `MapX.NewWith` (#450) ### Bugfixes -* Fix missing listener notification in `MapX.NewWith` when called with a relation target (#450) +* Fixes missing listener notification in `MapX.NewWith` when called with a relation target (#450) ## [[v0.14.1]](https://github.com/mlange-42/arche/compare/v0.14.0...v0.14.1) diff --git a/ecs/world_internal.go b/ecs/world_internal.go index d35ffa9b..e94ad29d 100644 --- a/ecs/world_internal.go +++ b/ecs/world_internal.go @@ -439,8 +439,8 @@ func (w *World) exchangeNoNotify(entity Entity, add []ID, rem []ID, relation ID, index := &w.entities[entity.id] oldArch := index.arch - oldMask := oldArch.Mask - mask := w.getExchangeMask(oldMask, add, rem) + mask := oldArch.Mask + w.getExchangeMask(&mask, add, rem) if hasRelation { if !mask.Get(relation) { @@ -496,7 +496,7 @@ func (w *World) exchangeNoNotify(entity Entity, add []ID, rem []ID, relation ID, w.cleanupArchetype(oldArch) - return arch, &oldMask, oldTarget, oldRel + return arch, &oldArch.Mask, oldTarget, oldRel } // notify listeners for an exchange. @@ -530,7 +530,7 @@ func (w *World) notifyExchange(arch *archetype, oldMask *Mask, entity Entity, ad // Modify a mask by adding and removing IDs. // Panics if adding a component already present or removing a component not present. // Also panics if the same component ID is in the add or remove list twice. -func (w *World) getExchangeMask(mask Mask, add []ID, rem []ID) Mask { +func (w *World) getExchangeMask(mask *Mask, add []ID, rem []ID) { for _, comp := range rem { if !mask.Get(comp) { panic(fmt.Sprintf("entity does not have a component of type %v, can't remove", w.registry.Types[comp.id])) @@ -543,7 +543,6 @@ func (w *World) getExchangeMask(mask Mask, add []ID, rem []ID) Mask { } mask.Set(comp, true) } - return mask } // ExchangeBatch exchanges components for many entities, matching a filter. @@ -615,7 +614,8 @@ func (w *World) exchangeBatchNoNotify(filter Filter, add []ID, rem []ID, relatio } func (w *World) exchangeArch(oldArch *archetype, oldArchLen uint32, add []ID, rem []ID, relation ID, hasRelation bool, target Entity) (*archetype, uint32) { - mask := w.getExchangeMask(oldArch.Mask, add, rem) + mask := oldArch.Mask + w.getExchangeMask(&mask, add, rem) oldIDs := oldArch.Components() if hasRelation {