Skip to content

Commit

Permalink
Deprecate slow methods like World.Assign and World.NewEntityWith (#…
Browse files Browse the repository at this point in the history
…441)

The fix in #438 slows these methods down due to more use of reflection. However, their generic counterparts were optimized in #440 to not use any reflection.

Thus, we deprecate the slow, non-generic methods.

* deprecate slow methods Assign and NewEntityWith
* ignore deprecated Assign in generic query tests
* add deprecation node to benchmarks in user guide
* update CHANGELOG
  • Loading branch information
mlange-42 authored Dec 22, 2024
1 parent bb6ea79 commit 30c1f4b
Show file tree
Hide file tree
Showing 6 changed files with 32 additions and 23 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## [[unpublished]](https://github.com/mlange-42/arche/compare/v0.13.3...main)

### Features

* Slow assignment methods like `World.Assign` and `World.NewEntityWith` are deprecated, in favour of their faster generic counterparts (#441)

### Performance

* Optimizes `Map.Set`, `MapX.Assign` and `MapX.NewWith`, by not using runtime reflection (#440)
Expand Down
4 changes: 2 additions & 2 deletions benchmark/table/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ func benchesComponents() []bench {

{Name: "World.Exchange 1 Comp", Desc: "memory already allocated", F: componentsExchange1_1000, N: 1000},

{Name: "World.Assign 1 Comp", Desc: "memory already allocated", F: componentsAssign1_1000, N: 1000},
{Name: "World.Assign 5 Comps", Desc: "memory already allocated", F: componentsAssign5_1000, N: 1000},
{Name: "World.Assign 1 Comp", Desc: "⚠️ deprecated, memory already allocated", F: componentsAssign1_1000, N: 1000},
{Name: "World.Assign 5 Comps", Desc: "⚠️ deprecated, memory already allocated", F: componentsAssign5_1000, N: 1000},
{Name: "MapX.Assign 1 Comps", Desc: "memory already allocated", F: componentsAssignGeneric1_1000, N: 1000},
{Name: "MapX.Assign 5 Comps", Desc: "memory already allocated", F: componentsAssignGeneric5_1000, N: 1000},
}
Expand Down
4 changes: 2 additions & 2 deletions benchmark/table/entities.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ func benchesEntities() []bench {
{Name: "World.RemoveEntity w/ 1 Comp", Desc: "", F: entitiesRemove_1Comp_1000, N: 1000},
{Name: "World.RemoveEntity w/ 5 Comps", Desc: "", F: entitiesRemove_5Comp_1000, N: 1000},

{Name: "World.NewEntityWith w/ 1 Comp", Desc: "memory already allocated", F: entitiesCreateWith_1Comp_1000, N: 1000},
{Name: "World.NewEntityWith w/ 5 Comps", Desc: "memory already allocated", F: entitiesCreateWith_5Comp_1000, N: 1000},
{Name: "World.NewEntityWith w/ 1 Comp", Desc: "⚠️ deprecated, memory already allocated", F: entitiesCreateWith_1Comp_1000, N: 1000},
{Name: "World.NewEntityWith w/ 5 Comps", Desc: "⚠️ deprecated, memory already allocated", F: entitiesCreateWith_5Comp_1000, N: 1000},

{Name: "MapX.NewEntityWith w/ 1 Comp", Desc: "memory already allocated", F: entitiesCreateWithGeneric_1Comp_1000, N: 1000},
{Name: "MapX.NewEntityWith w/ 5 Comps", Desc: "memory already allocated", F: entitiesCreateWithGeneric_5Comp_1000, N: 1000},
Expand Down
4 changes: 4 additions & 0 deletions ecs/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ func NewBuilder(w *World, comps ...ID) *Builder {
}

// NewBuilderWith creates a builder from component pointers.
//
// Deprecated: This method is slow. Instead, use NewWith of the generic API
// under [github.com/mlange-42/arche/generic.Map1], etc.
// This function may be removed in a future version.
func NewBuilderWith(w *World, comps ...Component) *Builder {
return &Builder{
world: w,
Expand Down
12 changes: 12 additions & 0 deletions ecs/world.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ func (w *World) NewEntity(comps ...ID) Entity {
// NewEntityWith returns a new or recycled [Entity].
// The given component values are assigned to the entity.
//
// Deprecated: This method is slow. Instead, use NewWith of the generic API
// under [github.com/mlange-42/arche/generic.Map1], etc.
// This method may be removed in a future version.
//
// The components in the Comp field of [Component] must be pointers.
// The passed pointers are no valid references to the assigned memory!
//
Expand Down Expand Up @@ -273,6 +277,10 @@ func (w *World) Add(entity Entity, comps ...ID) {

// Assign assigns multiple components to an [Entity], using pointers for the content.
//
// Deprecated: This method is slow. Instead, use Assign of the generic API
// under [github.com/mlange-42/arche/generic.Map1], etc.
// This method may be removed in a future version.
//
// The components in the Comp field of [Component] must be pointers.
// The passed pointers are no valid references to the assigned memory!
//
Expand All @@ -288,6 +296,10 @@ func (w *World) Assign(entity Entity, comps ...Component) {

// Set overwrites a component for an [Entity], using the given pointer for the content.
//
// Deprecated: This method is slow. Instead, use Set of the generic API
// under [github.com/mlange-42/arche/generic.Map].
// This method may be removed in a future version.
//
// The passed component must be a pointer.
// Returns a pointer to the assigned memory.
// The passed in pointer is not a valid reference to that memory!
Expand Down
27 changes: 8 additions & 19 deletions generic/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"github.com/stretchr/testify/assert"
)

//lint:file-ignore SA1019 Ignore deprecated World.Assign.

func TestQueryOptionalNot(t *testing.T) {
w := ecs.NewWorld()

Expand All @@ -16,18 +18,9 @@ func TestQueryOptionalNot(t *testing.T) {
e1 := w.NewEntity()
e2 := w.NewEntity()

w.Assign(e0, ecs.Component{ID: ids[0], Comp: &testStruct0{1}})
w.Assign(e0, ecs.Component{ID: ids[1], Comp: &testStruct1{1}})

w.Assign(e1, ecs.Component{ID: ids[0], Comp: &testStruct0{2}})
w.Assign(e1, ecs.Component{ID: ids[1], Comp: &testStruct1{2}})
w.Assign(e1, ecs.Component{ID: ids[2], Comp: &testStruct2{1, 1}})
w.Assign(e1, ecs.Component{ID: ids[8], Comp: &testStruct8{}})

w.Assign(e2, ecs.Component{ID: ids[0], Comp: &testStruct0{3}})
w.Assign(e2, ecs.Component{ID: ids[1], Comp: &testStruct1{3}})
w.Assign(e2, ecs.Component{ID: ids[2], Comp: &testStruct2{1, 1}})
w.Assign(e2, ecs.Component{ID: ids[9], Comp: &testStruct9{}})
w.Add(e0, ids[0], ids[1])
w.Add(e1, ids[0], ids[1], ids[2], ids[8])
w.Add(e2, ids[0], ids[1], ids[2], ids[9])

query2 := NewFilter2[testStruct0, testStruct1]().Query(&w)
cnt := 0
Expand Down Expand Up @@ -111,13 +104,9 @@ func TestQuery0(t *testing.T) {
e1 := w.NewEntity()
e2 := w.NewEntity()

w.Assign(e0, ecs.Component{ID: ids[0], Comp: &testStruct0{1}})
w.Assign(e0, ecs.Component{ID: ids[8], Comp: &testStruct8{}})

w.Assign(e1, ecs.Component{ID: ids[0], Comp: &testStruct0{2}})

w.Assign(e2, ecs.Component{ID: ids[0], Comp: &testStruct0{2}})
w.Assign(e2, ecs.Component{ID: ids[9], Comp: &testStruct9{}})
w.Add(e0, ids[0], ids[8])
w.Add(e1, ids[0])
w.Add(e2, ids[0], ids[9])

cnt := 0
filter :=
Expand Down

0 comments on commit 30c1f4b

Please sign in to comment.