Repository: mlange-42/arche
Pull request #91 (2023-02-16 00:27:06)

Simplify generic queries
Remove query methods `Get1`, `Get2`, ...

Builder methods `With` and `Optional` provide sufficient flexibility here.


Patch:
diff --git a/generic/generate/main.go b/generic/generate/main.go
index 6ce38ec..e064c5e 100644
--- a/generic/generate/main.go
+++ b/generic/generate/main.go
@@ -10,7 +10,6 @@ import (
 
 var typeLetters = []string{"A", "B", "C", "D", "E", "F", "G", "H"}
 var numbers = []string{"zero", "one", "two", "three", "four", "five", "six", "seven", "eight"}
-var indices = []string{"zeroth", "first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth"}
 
 type query struct {
 	Index       int
@@ -23,13 +22,6 @@ type query struct {
 	Components  string
 	Arguments   string
 }
-type getter struct {
-	Query    query
-	ID       int
-	Index    int
-	IndexStr string
-	Type     string
-}
 
 func main() {
 	generateQueries()
@@ -126,14 +118,6 @@ func generateQueries() {
 	if err != nil {
 		panic(err)
 	}
-	queryGetAll, err := template.ParseFiles("./generate/query_getall.go.txt")
-	if err != nil {
-		panic(err)
-	}
-	queryGet, err := template.ParseFiles("./generate/query_get.go.txt")
-	if err != nil {
-		panic(err)
-	}
 
 	for i := 0; i <= maxIndex; i++ {
 		types := ""
@@ -171,25 +155,6 @@ func generateQueries() {
 		if i == 0 {
 			continue
 		}
-
-		err = queryGetAll.Execute(&text, data)
-		if err != nil {
-			panic(err)
-		}
-
-		for j := 0; j < i; j++ {
-			getterData := getter{
-				Query:    data,
-				ID:       j + 1,
-				Index:    j,
-				IndexStr: indices[j+1],
-				Type:     typeLetters[j],
-			}
-			err = queryGet.Execute(&text, getterData)
-			if err != nil {
-				panic(err)
-			}
-		}
 	}
 	if err := os.WriteFile("query_generated.go", text.Bytes(), 0666); err != nil {
 		panic(err)
diff --git a/generic/generate/map.go.txt b/generic/generate/map.go.txt
index 833741a..b7790df 100644
--- a/generic/generate/map.go.txt
+++ b/generic/generate/map.go.txt
@@ -2,17 +2,14 @@
 //////////////////////////////////////////////////////////////////////////
 
 // Map{{ .Index }} is a helper for mapping {{ .NumberStr }} components.
-type Map{{ .Index }}{{ .TypesFull }} struct {
-	ids    []ecs.ID
-	world  *ecs.World
-}
+type Map{{ .Index }}{{ .TypesFull }} mapper
 
 // NewMap{{ .Index }} creates a new Map{{ .Index }} object.
 func NewMap{{ .Index }}{{ .TypesFull }}(w *ecs.World) Map{{ .Index }}{{ .Types }} {
-	return Map{{ .Index }}{{ .Types }}{
+	return Map{{ .Index }}{{ .Types }}(mapper{
 		ids:   {{ .Include }},
 		world: w,
-	}
+	})
 }
 
 // Get all the Map{{ .Index }}'s components for the given entity.
diff --git a/generic/generate/query.go.txt b/generic/generate/query.go.txt
index 79792d5..e8df288 100644
--- a/generic/generate/query.go.txt
+++ b/generic/generate/query.go.txt
@@ -2,20 +2,16 @@
 //////////////////////////////////////////////////////////////////////////
 
 // Filter{{ .Index }} is a helper for building [Query{{ .Index }}] query iterators.
-type Filter{{ .Index }}{{ .TypesFull }} struct {
-	include  []Comp
-	optional []Comp
-	exclude  []Comp
-	compiled compiledQuery
-}
+type Filter{{ .Index }}{{ .TypesFull }} filter
 
 // NewFilter{{ .Index }} creates a generic Filter{{ .Index }} for {{ .NumberStr }} components.
 //
 // See also [ecs.World.Query].
 func NewFilter{{ .Index }}{{ .TypesFull }}() *Filter{{ .Index }}{{ .Types }} {
-	return &Filter{{ .Index }}{{ .Types }}{
+	f := Filter{{ .Index }}{{ .Types }}(filter{
 		include: {{ .Include }},
-	}
+	})
+	return &f
 }
 
 {{if .Types}}
@@ -31,7 +27,7 @@ func (q *Filter{{ .Index }}{{ .Types }}) Optional(mask ...Comp) *Filter{{ .Index
 }
 {{ end }}
 
-// With adds more required components that are not accessible using Get... methods.
+// With adds components that are required, but not accessible via [Query{{ .Index }}.Get].
 //
 // Create the required mask items with [T].
 func (q *Filter{{ .Index }}{{ .Types }}) With(mask ...Comp) *Filter{{ .Index }}{{ .Types }} {
@@ -52,10 +48,10 @@ func (q *Filter{{ .Index }}{{ .Types }}) Without(mask ...Comp) *Filter{{ .Index
 // Query builds a [Query{{ .Index }}] query for iteration.
 func (q *Filter{{ .Index }}{{ .Types }}) Query(w *ecs.World) Query{{ .Index }}{{ .Types }} {
 	q.compiled.Compile(w, q.include, q.optional, q.exclude)
-	return Query{{ .Index }}{{ .Types }}{
+	return Query{{ .Index }}{{ .Types }}(query{
 		w.Query(q.compiled.Filter()),
 		q.compiled.Ids,
-	}
+	})
 }
 
 // Filter generates and return the [ecs.Filter] used after [Filter{{ .Index }}.Query].
@@ -70,7 +66,9 @@ func (q *Filter{{ .Index }}{{ .Types }}) Filter(w *ecs.World) ecs.MaskPair {
 // Query{{ .Index }} is a generic query iterator for {{ .NumberStr }} components.
 //
 // Create it with [NewFilter{{ .Index }}] and [Filter{{ .Index }}.Query]
-type Query{{ .Index }}{{ .TypesFull }} struct {
-	ecs.Query
-	ids []ecs.ID
+type Query{{ .Index }}{{ .TypesFull }} query
+
+// Get returns the [ecs.Entity] and all queried components for the current query iterator position.
+func (q *Query{{ .Index }}{{ .Types }}) Get() (ecs.Entity, {{ .TypesReturn }}) {
+	return q.Entity(){{if .ReturnAll}}, {{ .ReturnAll }}{{ end }}
 }
diff --git a/generic/generate/query_get.go.txt b/generic/generate/query_get.go.txt
deleted file mode 100644
index cef982f..0000000
--- a/generic/generate/query_get.go.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-
-// Get{{ .ID }} returns the {{ .IndexStr }} queried component for the current query iterator position.
-func (q *Query{{ .Query.Index }}{{ .Query.Types }}) Get{{ .ID }}() *{{ .Type }} {
-	return (*{{ .Type }})(q.Query.Get(q.ids[{{ .Index }}]))
-}
diff --git a/generic/generate/query_getall.go.txt b/generic/generate/query_getall.go.txt
deleted file mode 100644
index 5c6f708..0000000
--- a/generic/generate/query_getall.go.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-
-// Get returns the [ecs.Entity] and all queried components for the current query iterator position.
-func (q *Query{{ .Index }}{{ .Types }}) Get() (ecs.Entity, {{ .TypesReturn }}) {
-	return q.Entity(), {{ .ReturnAll }}
-}
diff --git a/generic/map_generated.go b/generic/map_generated.go
index 6cb1929..f94f19b 100644
--- a/generic/map_generated.go
+++ b/generic/map_generated.go
@@ -9,17 +9,14 @@ import (
 //////////////////////////////////////////////////////////////////////////
 
 // Map1 is a helper for mapping one components.
-type Map1[A any] struct {
-	ids   []ecs.ID
-	world *ecs.World
-}
+type Map1[A any] mapper
 
 // NewMap1 creates a new Map1 object.
 func NewMap1[A any](w *ecs.World) Map1[A] {
-	return Map1[A]{
+	return Map1[A](mapper{
 		ids:   []ecs.ID{ecs.ComponentID[A](w)},
 		world: w,
-	}
+	})
 }
 
 // Get all the Map1's components for the given entity.
@@ -75,17 +72,14 @@ func (m *Map1[A]) Remove(entity ecs.Entity) {
 //////////////////////////////////////////////////////////////////////////
 
 // Map2 is a helper for mapping two components.
-type Map2[A any, B any] struct {
-	ids   []ecs.ID
-	world *ecs.World
-}
+type Map2[A any, B any] mapper
 
 // NewMap2 creates a new Map2 object.
 func NewMap2[A any, B any](w *ecs.World) Map2[A, B] {
-	return Map2[A, B]{
+	return Map2[A, B](mapper{
 		ids:   []ecs.ID{ecs.ComponentID[A](w), ecs.ComponentID[B](w)},
 		world: w,
-	}
+	})
 }
 
 // Get all the Map2's components for the given entity.
@@ -143,17 +137,14 @@ func (m *Map2[A, B]) Remove(entity ecs.Entity) {
 //////////////////////////////////////////////////////////////////////////
 
 // Map3 is a helper for mapping three components.
-type Map3[A any, B any, C any] struct {
-	ids   []ecs.ID
-	world *ecs.World
-}
+type Map3[A any, B any, C any] mapper
 
 // NewMap3 creates a new Map3 object.
 func NewMap3[A any, B any, C any](w *ecs.World) Map3[A, B, C] {
-	return Map3[A, B, C]{
+	return Map3[A, B, C](mapper{
 		ids:   []ecs.ID{ecs.ComponentID[A](w), ecs.ComponentID[B](w), ecs.ComponentID[C](w)},
 		world: w,
-	}
+	})
 }
 
 // Get all the Map3's components for the given entity.
@@ -213,17 +204,14 @@ func (m *Map3[A, B, C]) Remove(entity ecs.Entity) {
 //////////////////////////////////////////////////////////////////////////
 
 // Map4 is a helper for mapping four components.
-type Map4[A any, B any, C any, D any] struct {
-	ids   []ecs.ID
-	world *ecs.World
-}
+type Map4[A any, B any, C any, D any] mapper
 
 // NewMap4 creates a new Map4 object.
 func NewMap4[A any, B any, C any, D any](w *ecs.World) Map4[A, B, C, D] {
-	return Map4[A, B, C, D]{
+	return Map4[A, B, C, D](mapper{
 		ids:   []ecs.ID{ecs.ComponentID[A](w), ecs.ComponentID[B](w), ecs.ComponentID[C](w), ecs.ComponentID[D](w)},
 		world: w,
-	}
+	})
 }
 
 // Get all the Map4's components for the given entity.
@@ -285,17 +273,14 @@ func (m *Map4[A, B, C, D]) Remove(entity ecs.Entity) {
 //////////////////////////////////////////////////////////////////////////
 
 // Map5 is a helper for mapping five components.
-type Map5[A any, B any, C any, D any, E any] struct {
-	ids   []ecs.ID
-	world *ecs.World
-}
+type Map5[A any, B any, C any, D any, E any] mapper
 
 // NewMap5 creates a new Map5 object.
 func NewMap5[A any, B any, C any, D any, E any](w *ecs.World) Map5[A, B, C, D, E] {
-	return Map5[A, B, C, D, E]{
+	return Map5[A, B, C, D, E](mapper{
 		ids:   []ecs.ID{ecs.ComponentID[A](w), ecs.ComponentID[B](w), ecs.ComponentID[C](w), ecs.ComponentID[D](w), ecs.ComponentID[E](w)},
 		world: w,
-	}
+	})
 }
 
 // Get all the Map5's components for the given entity.
@@ -359,17 +344,14 @@ func (m *Map5[A, B, C, D, E]) Remove(entity ecs.Entity) {
 //////////////////////////////////////////////////////////////////////////
 
 // Map6 is a helper for mapping six components.
-type Map6[A any, B any, C any, D any, E any, F any] struct {
-	ids   []ecs.ID
-	world *ecs.World
-}
+type Map6[A any, B any, C any, D any, E any, F any] mapper
 
 // NewMap6 creates a new Map6 object.
 func NewMap6[A any, B any, C any, D any, E any, F any](w *ecs.World) Map6[A, B, C, D, E, F] {
-	return Map6[A, B, C, D, E, F]{
+	return Map6[A, B, C, D, E, F](mapper{
 		ids:   []ecs.ID{ecs.ComponentID[A](w), ecs.ComponentID[B](w), ecs.ComponentID[C](w), ecs.ComponentID[D](w), ecs.ComponentID[E](w), ecs.ComponentID[F](w)},
 		world: w,
-	}
+	})
 }
 
 // Get all the Map6's components for the given entity.
@@ -435,17 +417,14 @@ func (m *Map6[A, B, C, D, E, F]) Remove(entity ecs.Entity) {
 //////////////////////////////////////////////////////////////////////////
 
 // Map7 is a helper for mapping seven components.
-type Map7[A any, B any, C any, D any, E any, F any, G any] struct {
-	ids   []ecs.ID
-	world *ecs.World
-}
+type Map7[A any, B any, C any, D any, E any, F any, G any] mapper
 
 // NewMap7 creates a new Map7 object.
 func NewMap7[A any, B any, C any, D any, E any, F any, G any](w *ecs.World) Map7[A, B, C, D, E, F, G] {
-	return Map7[A, B, C, D, E, F, G]{
+	return Map7[A, B, C, D, E, F, G](mapper{
 		ids:   []ecs.ID{ecs.ComponentID[A](w), ecs.ComponentID[B](w), ecs.ComponentID[C](w), ecs.ComponentID[D](w), ecs.ComponentID[E](w), ecs.ComponentID[F](w), ecs.ComponentID[G](w)},
 		world: w,
-	}
+	})
 }
 
 // Get all the Map7's components for the given entity.
@@ -513,17 +492,14 @@ func (m *Map7[A, B, C, D, E, F, G]) Remove(entity ecs.Entity) {
 //////////////////////////////////////////////////////////////////////////
 
 // Map8 is a helper for mapping eight components.
-type Map8[A any, B any, C any, D any, E any, F any, G any, H any] struct {
-	ids   []ecs.ID
-	world *ecs.World
-}
+type Map8[A any, B any, C any, D any, E any, F any, G any, H any] mapper
 
 // NewMap8 creates a new Map8 object.
 func NewMap8[A any, B any, C any, D any, E any, F any, G any, H any](w *ecs.World) Map8[A, B, C, D, E, F, G, H] {
-	return Map8[A, B, C, D, E, F, G, H]{
+	return Map8[A, B, C, D, E, F, G, H](mapper{
 		ids:   []ecs.ID{ecs.ComponentID[A](w), ecs.ComponentID[B](w), ecs.ComponentID[C](w), ecs.ComponentID[D](w), ecs.ComponentID[E](w), ecs.ComponentID[F](w), ecs.ComponentID[G](w), ecs.ComponentID[H](w)},
 		world: w,
-	}
+	})
 }
 
 // Get all the Map8's components for the given entity.
diff --git a/generic/query_generated.go b/generic/query_generated.go
index eb7cd8a..1b8a9ec 100644
--- a/generic/query_generated.go
+++ b/generic/query_generated.go
@@ -9,23 +9,19 @@ import (
 //////////////////////////////////////////////////////////////////////////
 
 // Filter0 is a helper for building [Query0] query iterators.
-type Filter0 struct {
-	include  []Comp
-	optional []Comp
-	exclude  []Comp
-	compiled compiledQuery
-}
+type Filter0 filter
 
 // NewFilter0 creates a generic Filter0 for zero components.
 //
 // See also [ecs.World.Query].
 func NewFilter0() *Filter0 {
-	return &Filter0{
+	f := Filter0(filter{
 		include: []Comp{},
-	}
+	})
+	return &f
 }
 
-// With adds more required components that are not accessible using Get... methods.
+// With adds components that are required, but not accessible via [Query0.Get].
 //
 // Create the required mask items with [T].
 func (q *Filter0) With(mask ...Comp) *Filter0 {
@@ -46,10 +42,10 @@ func (q *Filter0) Without(mask ...Comp) *Filter0 {
 // Query builds a [Query0] query for iteration.
 func (q *Filter0) Query(w *ecs.World) Query0 {
 	q.compiled.Compile(w, q.include, q.optional, q.exclude)
-	return Query0{
+	return Query0(query{
 		w.Query(q.compiled.Filter()),
 		q.compiled.Ids,
-	}
+	})
 }
 
 // Filter generates and return the [ecs.Filter] used after [Filter0.Query].
@@ -64,28 +60,26 @@ func (q *Filter0) Filter(w *ecs.World) ecs.MaskPair {
 // Query0 is a generic query iterator for zero components.
 //
 // Create it with [NewFilter0] and [Filter0.Query]
-type Query0 struct {
-	ecs.Query
-	ids []ecs.ID
+type Query0 query
+
+// Get returns the [ecs.Entity] and all queried components for the current query iterator position.
+func (q *Query0) Get() ecs.Entity {
+	return q.Entity()
 }
 
 //////////////////////////////////////////////////////////////////////////
 
 // Filter1 is a helper for building [Query1] query iterators.
-type Filter1[A any] struct {
-	include  []Comp
-	optional []Comp
-	exclude  []Comp
-	compiled compiledQuery
-}
+type Filter1[A any] filter
 
 // NewFilter1 creates a generic Filter1 for one components.
 //
 // See also [ecs.World.Query].
 func NewFilter1[A any]() *Filter1[A] {
-	return &Filter1[A]{
+	f := Filter1[A](filter{
 		include: []Comp{typeOf[A]()},
-	}
+	})
+	return &f
 }
 
 // Optional makes some of the query's components optional.
@@ -99,7 +93,7 @@ func (q *Filter1[A]) Optional(mask ...Comp) *Filter1[A] {
 	return q
 }
 
-// With adds more required components that are not accessible using Get... methods.
+// With adds components that are required, but not accessible via [Query1.Get].
 //
 // Create the required mask items with [T].
 func (q *Filter1[A]) With(mask ...Comp) *Filter1[A] {
@@ -120,10 +114,10 @@ func (q *Filter1[A]) Without(mask ...Comp) *Filter1[A] {
 // Query builds a [Query1] query for iteration.
 func (q *Filter1[A]) Query(w *ecs.World) Query1[A] {
 	q.compiled.Compile(w, q.include, q.optional, q.exclude)
-	return Query1[A]{
+	return Query1[A](query{
 		w.Query(q.compiled.Filter()),
 		q.compiled.Ids,
-	}
+	})
 }
 
 // Filter generates and return the [ecs.Filter] used after [Filter1.Query].
@@ -138,38 +132,26 @@ func (q *Filter1[A]) Filter(w *ecs.World) ecs.MaskPair {
 // Query1 is a generic query iterator for one components.
 //
 // Create it with [NewFilter1] and [Filter1.Query]
-type Query1[A any] struct {
-	ecs.Query
-	ids []ecs.ID
-}
+type Query1[A any] query
 
 // Get returns the [ecs.Entity] and all queried components for the current query iterator position.
 func (q *Query1[A]) Get() (ecs.Entity, *A) {
 	return q.Entity(), (*A)(q.Query.Get(q.ids[0]))
 }
 
-// Get1 returns the first queried component for the current query iterator position.
-func (q *Query1[A]) Get1() *A {
-	return (*A)(q.Query.Get(q.ids[0]))
-}
-
 //////////////////////////////////////////////////////////////////////////
 
 // Filter2 is a helper for building [Query2] query iterators.
-type Filter2[A any, B any] struct {
-	include  []Comp
-	optional []Comp
-	exclude  []Comp
-	compiled compiledQuery
-}
+type Filter2[A any, B any] filter
 
 // NewFilter2 creates a generic Filter2 for two components.
 //
 // See also [ecs.World.Query].
 func NewFilter2[A any, B any]() *Filter2[A, B] {
-	return &Filter2[A, B]{
+	f := Filter2[A, B](filter{
 		include: []Comp{typeOf[A](), typeOf[B]()},
-	}
+	})
+	return &f
 }
 
 // Optional makes some of the query's components optional.
@@ -183,7 +165,7 @@ func (q *Filter2[A, B]) Optional(mask ...Comp) *Filter2[A, B] {
 	return q
 }
 
-// With adds more required components that are not accessible using Get... methods.
+// With adds components that are required, but not accessible via [Query2.Get].
 //
 // Create the required mask items with [T].
 func (q *Filter2[A, B]) With(mask ...Comp) *Filter2[A, B] {
@@ -204,10 +186,10 @@ func (q *Filter2[A, B]) Without(mask ...Comp) *Filter2[A, B] {
 // Query builds a [Query2] query for iteration.
 func (q *Filter2[A, B]) Query(w *ecs.World) Query2[A, B] {
 	q.compiled.Compile(w, q.include, q.optional, q.exclude)
-	return Query2[A, B]{
+	return Query2[A, B](query{
 		w.Query(q.compiled.Filter()),
 		q.compiled.Ids,
-	}
+	})
 }
 
 // Filter generates and return the [ecs.Filter] used after [Filter2.Query].
@@ -222,43 +204,26 @@ func (q *Filter2[A, B]) Filter(w *ecs.World) ecs.MaskPair {
 // Query2 is a generic query iterator for two components.
 //
 // Create it with [NewFilter2] and [Filter2.Query]
-type Query2[A any, B any] struct {
-	ecs.Query
-	ids []ecs.ID
-}
+type Query2[A any, B any] query
 
 // Get returns the [ecs.Entity] and all queried components for the current query iterator position.
 func (q *Query2[A, B]) Get() (ecs.Entity, *A, *B) {
 	return q.Entity(), (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1]))
 }
 
-// Get1 returns the first queried component for the current query iterator position.
-func (q *Query2[A, B]) Get1() *A {
-	return (*A)(q.Query.Get(q.ids[0]))
-}
-
-// Get2 returns the second queried component for the current query iterator position.
-func (q *Query2[A, B]) Get2() *B {
-	return (*B)(q.Query.Get(q.ids[1]))
-}
-
 //////////////////////////////////////////////////////////////////////////
 
 // Filter3 is a helper for building [Query3] query iterators.
-type Filter3[A any, B any, C any] struct {
-	include  []Comp
-	optional []Comp
-	exclude  []Comp
-	compiled compiledQuery
-}
+type Filter3[A any, B any, C any] filter
 
 // NewFilter3 creates a generic Filter3 for three components.
 //
 // See also [ecs.World.Query].
 func NewFilter3[A any, B any, C any]() *Filter3[A, B, C] {
-	return &Filter3[A, B, C]{
+	f := Filter3[A, B, C](filter{
 		include: []Comp{typeOf[A](), typeOf[B](), typeOf[C]()},
-	}
+	})
+	return &f
 }
 
 // Optional makes some of the query's components optional.
@@ -272,7 +237,7 @@ func (q *Filter3[A, B, C]) Optional(mask ...Comp) *Filter3[A, B, C] {
 	return q
 }
 
-// With adds more required components that are not accessible using Get... methods.
+// With adds components that are required, but not accessible via [Query3.Get].
 //
 // Create the required mask items with [T].
 func (q *Filter3[A, B, C]) With(mask ...Comp) *Filter3[A, B, C] {
@@ -293,10 +258,10 @@ func (q *Filter3[A, B, C]) Without(mask ...Comp) *Filter3[A, B, C] {
 // Query builds a [Query3] query for iteration.
 func (q *Filter3[A, B, C]) Query(w *ecs.World) Query3[A, B, C] {
 	q.compiled.Compile(w, q.include, q.optional, q.exclude)
-	return Query3[A, B, C]{
+	return Query3[A, B, C](query{
 		w.Query(q.compiled.Filter()),
 		q.compiled.Ids,
-	}
+	})
 }
 
 // Filter generates and return the [ecs.Filter] used after [Filter3.Query].
@@ -311,48 +276,26 @@ func (q *Filter3[A, B, C]) Filter(w *ecs.World) ecs.MaskPair {
 // Query3 is a generic query iterator for three components.
 //
 // Create it with [NewFilter3] and [Filter3.Query]
-type Query3[A any, B any, C any] struct {
-	ecs.Query
-	ids []ecs.ID
-}
+type Query3[A any, B any, C any] query
 
 // Get returns the [ecs.Entity] and all queried components for the current query iterator position.
 func (q *Query3[A, B, C]) Get() (ecs.Entity, *A, *B, *C) {
 	return q.Entity(), (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2]))
 }
 
-// Get1 returns the first queried component for the current query iterator position.
-func (q *Query3[A, B, C]) Get1() *A {
-	return (*A)(q.Query.Get(q.ids[0]))
-}
-
-// Get2 returns the second queried component for the current query iterator position.
-func (q *Query3[A, B, C]) Get2() *B {
-	return (*B)(q.Query.Get(q.ids[1]))
-}
-
-// Get3 returns the third queried component for the current query iterator position.
-func (q *Query3[A, B, C]) Get3() *C {
-	return (*C)(q.Query.Get(q.ids[2]))
-}
-
 //////////////////////////////////////////////////////////////////////////
 
 // Filter4 is a helper for building [Query4] query iterators.
-type Filter4[A any, B any, C any, D any] struct {
-	include  []Comp
-	optional []Comp
-	exclude  []Comp
-	compiled compiledQuery
-}
+type Filter4[A any, B any, C any, D any] filter
 
 // NewFilter4 creates a generic Filter4 for four components.
 //
 // See also [ecs.World.Query].
 func NewFilter4[A any, B any, C any, D any]() *Filter4[A, B, C, D] {
-	return &Filter4[A, B, C, D]{
+	f := Filter4[A, B, C, D](filter{
 		include: []Comp{typeOf[A](), typeOf[B](), typeOf[C](), typeOf[D]()},
-	}
+	})
+	return &f
 }
 
 // Optional makes some of the query's components optional.
@@ -366,7 +309,7 @@ func (q *Filter4[A, B, C, D]) Optional(mask ...Comp) *Filter4[A, B, C, D] {
 	return q
 }
 
-// With adds more required components that are not accessible using Get... methods.
+// With adds components that are required, but not accessible via [Query4.Get].
 //
 // Create the required mask items with [T].
 func (q *Filter4[A, B, C, D]) With(mask ...Comp) *Filter4[A, B, C, D] {
@@ -387,10 +330,10 @@ func (q *Filter4[A, B, C, D]) Without(mask ...Comp) *Filter4[A, B, C, D] {
 // Query builds a [Query4] query for iteration.
 func (q *Filter4[A, B, C, D]) Query(w *ecs.World) Query4[A, B, C, D] {
 	q.compiled.Compile(w, q.include, q.optional, q.exclude)
-	return Query4[A, B, C, D]{
+	return Query4[A, B, C, D](query{
 		w.Query(q.compiled.Filter()),
 		q.compiled.Ids,
-	}
+	})
 }
 
 // Filter generates and return the [ecs.Filter] used after [Filter4.Query].
@@ -405,53 +348,26 @@ func (q *Filter4[A, B, C, D]) Filter(w *ecs.World) ecs.MaskPair {
 // Query4 is a generic query iterator for four components.
 //
 // Create it with [NewFilter4] and [Filter4.Query]
-type Query4[A any, B any, C any, D any] struct {
-	ecs.Query
-	ids []ecs.ID
-}
+type Query4[A any, B any, C any, D any] query
 
 // Get returns the [ecs.Entity] and all queried components for the current query iterator position.
 func (q *Query4[A, B, C, D]) Get() (ecs.Entity, *A, *B, *C, *D) {
 	return q.Entity(), (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2])), (*D)(q.Query.Get(q.ids[3]))
 }
 
-// Get1 returns the first queried component for the current query iterator position.
-func (q *Query4[A, B, C, D]) Get1() *A {
-	return (*A)(q.Query.Get(q.ids[0]))
-}
-
-// Get2 returns the second queried component for the current query iterator position.
-func (q *Query4[A, B, C, D]) Get2() *B {
-	return (*B)(q.Query.Get(q.ids[1]))
-}
-
-// Get3 returns the third queried component for the current query iterator position.
-func (q *Query4[A, B, C, D]) Get3() *C {
-	return (*C)(q.Query.Get(q.ids[2]))
-}
-
-// Get4 returns the fourth queried component for the current query iterator position.
-func (q *Query4[A, B, C, D]) Get4() *D {
-	return (*D)(q.Query.Get(q.ids[3]))
-}
-
 //////////////////////////////////////////////////////////////////////////
 
 // Filter5 is a helper for building [Query5] query iterators.
-type Filter5[A any, B any, C any, D any, E any] struct {
-	include  []Comp
-	optional []Comp
-	exclude  []Comp
-	compiled compiledQuery
-}
+type Filter5[A any, B any, C any, D any, E any] filter
 
 // NewFilter5 creates a generic Filter5 for five components.
 //
 // See also [ecs.World.Query].
 func NewFilter5[A any, B any, C any, D any, E any]() *Filter5[A, B, C, D, E] {
-	return &Filter5[A, B, C, D, E]{
+	f := Filter5[A, B, C, D, E](filter{
 		include: []Comp{typeOf[A](), typeOf[B](), typeOf[C](), typeOf[D](), typeOf[E]()},
-	}
+	})
+	return &f
 }
 
 // Optional makes some of the query's components optional.
@@ -465,7 +381,7 @@ func (q *Filter5[A, B, C, D, E]) Optional(mask ...Comp) *Filter5[A, B, C, D, E]
 	return q
 }
 
-// With adds more required components that are not accessible using Get... methods.
+// With adds components that are required, but not accessible via [Query5.Get].
 //
 // Create the required mask items with [T].
 func (q *Filter5[A, B, C, D, E]) With(mask ...Comp) *Filter5[A, B, C, D, E] {
@@ -486,10 +402,10 @@ func (q *Filter5[A, B, C, D, E]) Without(mask ...Comp) *Filter5[A, B, C, D, E] {
 // Query builds a [Query5] query for iteration.
 func (q *Filter5[A, B, C, D, E]) Query(w *ecs.World) Query5[A, B, C, D, E] {
 	q.compiled.Compile(w, q.include, q.optional, q.exclude)
-	return Query5[A, B, C, D, E]{
+	return Query5[A, B, C, D, E](query{
 		w.Query(q.compiled.Filter()),
 		q.compiled.Ids,
-	}
+	})
 }
 
 // Filter generates and return the [ecs.Filter] used after [Filter5.Query].
@@ -504,58 +420,26 @@ func (q *Filter5[A, B, C, D, E]) Filter(w *ecs.World) ecs.MaskPair {
 // Query5 is a generic query iterator for five components.
 //
 // Create it with [NewFilter5] and [Filter5.Query]
-type Query5[A any, B any, C any, D any, E any] struct {
-	ecs.Query
-	ids []ecs.ID
-}
+type Query5[A any, B any, C any, D any, E any] query
 
 // Get returns the [ecs.Entity] and all queried components for the current query iterator position.
 func (q *Query5[A, B, C, D, E]) Get() (ecs.Entity, *A, *B, *C, *D, *E) {
 	return q.Entity(), (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2])), (*D)(q.Query.Get(q.ids[3])), (*E)(q.Query.Get(q.ids[4]))
 }
 
-// Get1 returns the first queried component for the current query iterator position.
-func (q *Query5[A, B, C, D, E]) Get1() *A {
-	return (*A)(q.Query.Get(q.ids[0]))
-}
-
-// Get2 returns the second queried component for the current query iterator position.
-func (q *Query5[A, B, C, D, E]) Get2() *B {
-	return (*B)(q.Query.Get(q.ids[1]))
-}
-
-// Get3 returns the third queried component for the current query iterator position.
-func (q *Query5[A, B, C, D, E]) Get3() *C {
-	return (*C)(q.Query.Get(q.ids[2]))
-}
-
-// Get4 returns the fourth queried component for the current query iterator position.
-func (q *Query5[A, B, C, D, E]) Get4() *D {
-	return (*D)(q.Query.Get(q.ids[3]))
-}
-
-// Get5 returns the fifth queried component for the current query iterator position.
-func (q *Query5[A, B, C, D, E]) Get5() *E {
-	return (*E)(q.Query.Get(q.ids[4]))
-}
-
 //////////////////////////////////////////////////////////////////////////
 
 // Filter6 is a helper for building [Query6] query iterators.
-type Filter6[A any, B any, C any, D any, E any, F any] struct {
-	include  []Comp
-	optional []Comp
-	exclude  []Comp
-	compiled compiledQuery
-}
+type Filter6[A any, B any, C any, D any, E any, F any] filter
 
 // NewFilter6 creates a generic Filter6 for six components.
 //
 // See also [ecs.World.Query].
 func NewFilter6[A any, B any, C any, D any, E any, F any]() *Filter6[A, B, C, D, E, F] {
-	return &Filter6[A, B, C, D, E, F]{
+	f := Filter6[A, B, C, D, E, F](filter{
 		include: []Comp{typeOf[A](), typeOf[B](), typeOf[C](), typeOf[D](), typeOf[E](), typeOf[F]()},
-	}
+	})
+	return &f
 }
 
 // Optional makes some of the query's components optional.
@@ -569,7 +453,7 @@ func (q *Filter6[A, B, C, D, E, F]) Optional(mask ...Comp) *Filter6[A, B, C, D,
 	return q
 }
 
-// With adds more required components that are not accessible using Get... methods.
+// With adds components that are required, but not accessible via [Query6.Get].
 //
 // Create the required mask items with [T].
 func (q *Filter6[A, B, C, D, E, F]) With(mask ...Comp) *Filter6[A, B, C, D, E, F] {
@@ -590,10 +474,10 @@ func (q *Filter6[A, B, C, D, E, F]) Without(mask ...Comp) *Filter6[A, B, C, D, E
 // Query builds a [Query6] query for iteration.
 func (q *Filter6[A, B, C, D, E, F]) Query(w *ecs.World) Query6[A, B, C, D, E, F] {
 	q.compiled.Compile(w, q.include, q.optional, q.exclude)
-	return Query6[A, B, C, D, E, F]{
+	return Query6[A, B, C, D, E, F](query{
 		w.Query(q.compiled.Filter()),
 		q.compiled.Ids,
-	}
+	})
 }
 
 // Filter generates and return the [ecs.Filter] used after [Filter6.Query].
@@ -608,63 +492,26 @@ func (q *Filter6[A, B, C, D, E, F]) Filter(w *ecs.World) ecs.MaskPair {
 // Query6 is a generic query iterator for six components.
 //
 // Create it with [NewFilter6] and [Filter6.Query]
-type Query6[A any, B any, C any, D any, E any, F any] struct {
-	ecs.Query
-	ids []ecs.ID
-}
+type Query6[A any, B any, C any, D any, E any, F any] query
 
 // Get returns the [ecs.Entity] and all queried components for the current query iterator position.
 func (q *Query6[A, B, C, D, E, F]) Get() (ecs.Entity, *A, *B, *C, *D, *E, *F) {
 	return q.Entity(), (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2])), (*D)(q.Query.Get(q.ids[3])), (*E)(q.Query.Get(q.ids[4])), (*F)(q.Query.Get(q.ids[5]))
 }
 
-// Get1 returns the first queried component for the current query iterator position.
-func (q *Query6[A, B, C, D, E, F]) Get1() *A {
-	return (*A)(q.Query.Get(q.ids[0]))
-}
-
-// Get2 returns the second queried component for the current query iterator position.
-func (q *Query6[A, B, C, D, E, F]) Get2() *B {
-	return (*B)(q.Query.Get(q.ids[1]))
-}
-
-// Get3 returns the third queried component for the current query iterator position.
-func (q *Query6[A, B, C, D, E, F]) Get3() *C {
-	return (*C)(q.Query.Get(q.ids[2]))
-}
-
-// Get4 returns the fourth queried component for the current query iterator position.
-func (q *Query6[A, B, C, D, E, F]) Get4() *D {
-	return (*D)(q.Query.Get(q.ids[3]))
-}
-
-// Get5 returns the fifth queried component for the current query iterator position.
-func (q *Query6[A, B, C, D, E, F]) Get5() *E {
-	return (*E)(q.Query.Get(q.ids[4]))
-}
-
-// Get6 returns the sixth queried component for the current query iterator position.
-func (q *Query6[A, B, C, D, E, F]) Get6() *F {
-	return (*F)(q.Query.Get(q.ids[5]))
-}
-
 //////////////////////////////////////////////////////////////////////////
 
 // Filter7 is a helper for building [Query7] query iterators.
-type Filter7[A any, B any, C any, D any, E any, F any, G any] struct {
-	include  []Comp
-	optional []Comp
-	exclude  []Comp
-	compiled compiledQuery
-}
+type Filter7[A any, B any, C any, D any, E any, F any, G any] filter
 
 // NewFilter7 creates a generic Filter7 for seven components.
 //
 // See also [ecs.World.Query].
 func NewFilter7[A any, B any, C any, D any, E any, F any, G any]() *Filter7[A, B, C, D, E, F, G] {
-	return &Filter7[A, B, C, D, E, F, G]{
+	f := Filter7[A, B, C, D, E, F, G](filter{
 		include: []Comp{typeOf[A](), typeOf[B](), typeOf[C](), typeOf[D](), typeOf[E](), typeOf[F](), typeOf[G]()},
-	}
+	})
+	return &f
 }
 
 // Optional makes some of the query's components optional.
@@ -678,7 +525,7 @@ func (q *Filter7[A, B, C, D, E, F, G]) Optional(mask ...Comp) *Filter7[A, B, C,
 	return q
 }
 
-// With adds more required components that are not accessible using Get... methods.
+// With adds components that are required, but not accessible via [Query7.Get].
 //
 // Create the required mask items with [T].
 func (q *Filter7[A, B, C, D, E, F, G]) With(mask ...Comp) *Filter7[A, B, C, D, E, F, G] {
@@ -699,10 +546,10 @@ func (q *Filter7[A, B, C, D, E, F, G]) Without(mask ...Comp) *Filter7[A, B, C, D
 // Query builds a [Query7] query for iteration.
 func (q *Filter7[A, B, C, D, E, F, G]) Query(w *ecs.World) Query7[A, B, C, D, E, F, G] {
 	q.compiled.Compile(w, q.include, q.optional, q.exclude)
-	return Query7[A, B, C, D, E, F, G]{
+	return Query7[A, B, C, D, E, F, G](query{
 		w.Query(q.compiled.Filter()),
 		q.compiled.Ids,
-	}
+	})
 }
 
 // Filter generates and return the [ecs.Filter] used after [Filter7.Query].
@@ -717,68 +564,26 @@ func (q *Filter7[A, B, C, D, E, F, G]) Filter(w *ecs.World) ecs.MaskPair {
 // Query7 is a generic query iterator for seven components.
 //
 // Create it with [NewFilter7] and [Filter7.Query]
-type Query7[A any, B any, C any, D any, E any, F any, G any] struct {
-	ecs.Query
-	ids []ecs.ID
-}
+type Query7[A any, B any, C any, D any, E any, F any, G any] query
 
 // Get returns the [ecs.Entity] and all queried components for the current query iterator position.
 func (q *Query7[A, B, C, D, E, F, G]) Get() (ecs.Entity, *A, *B, *C, *D, *E, *F, *G) {
 	return q.Entity(), (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2])), (*D)(q.Query.Get(q.ids[3])), (*E)(q.Query.Get(q.ids[4])), (*F)(q.Query.Get(q.ids[5])), (*G)(q.Query.Get(q.ids[6]))
 }
 
-// Get1 returns the first queried component for the current query iterator position.
-func (q *Query7[A, B, C, D, E, F, G]) Get1() *A {
-	return (*A)(q.Query.Get(q.ids[0]))
-}
-
-// Get2 returns the second queried component for the current query iterator position.
-func (q *Query7[A, B, C, D, E, F, G]) Get2() *B {
-	return (*B)(q.Query.Get(q.ids[1]))
-}
-
-// Get3 returns the third queried component for the current query iterator position.
-func (q *Query7[A, B, C, D, E, F, G]) Get3() *C {
-	return (*C)(q.Query.Get(q.ids[2]))
-}
-
-// Get4 returns the fourth queried component for the current query iterator position.
-func (q *Query7[A, B, C, D, E, F, G]) Get4() *D {
-	return (*D)(q.Query.Get(q.ids[3]))
-}
-
-// Get5 returns the fifth queried component for the current query iterator position.
-func (q *Query7[A, B, C, D, E, F, G]) Get5() *E {
-	return (*E)(q.Query.Get(q.ids[4]))
-}
-
-// Get6 returns the sixth queried component for the current query iterator position.
-func (q *Query7[A, B, C, D, E, F, G]) Get6() *F {
-	return (*F)(q.Query.Get(q.ids[5]))
-}
-
-// Get7 returns the seventh queried component for the current query iterator position.
-func (q *Query7[A, B, C, D, E, F, G]) Get7() *G {
-	return (*G)(q.Query.Get(q.ids[6]))
-}
-
 //////////////////////////////////////////////////////////////////////////
 
 // Filter8 is a helper for building [Query8] query iterators.
-type Filter8[A any, B any, C any, D any, E any, F any, G any, H any] struct {
-	include  []Comp
-	optional []Comp
-	exclude  []Comp
-	compiled compiledQuery
-}
+type Filter8[A any, B any, C any, D any, E any, F any, G any, H any] filter
 
 // NewFilter8 creates a generic Filter8 for eight components.
 //
 // See also [ecs.World.Query].
 func NewFilter8[A any, B any, C any, D any, E any, F any, G any, H any]() *Filter8[A, B, C, D, E, F, G, H] {
-	return &Filter8[A, B, C, D, E, F, G, H]{
+	f := Filter8[A, B, C, D, E, F, G, H](filter{
 		include: []Comp{typeOf[A](), typeOf[B](), typeOf[C](), typeOf[D](), typeOf[E](), typeOf[F](), typeOf[G](), typeOf[H]()},
-	}
+	})
+	return &f
 }
 
 // Optional makes some of the query's components optional.
@@ -792,7 +597,7 @@ func (q *Filter8[A, B, C, D, E, F, G, H]) Optional(mask ...Comp) *Filter8[A, B,
 	return q
 }
 
-// With adds more required components that are not accessible using Get... methods.
+// With adds components that are required, but not accessible via [Query8.Get].
 //
 // Create the required mask items with [T].
 func (q *Filter8[A, B, C, D, E, F, G, H]) With(mask ...Comp) *Filter8[A, B, C, D, E, F, G, H] {
@@ -813,10 +618,10 @@ func (q *Filter8[A, B, C, D, E, F, G, H]) Without(mask ...Comp) *Filter8[A, B, C
 // Query builds a [Query8] query for iteration.
 func (q *Filter8[A, B, C, D, E, F, G, H]) Query(w *ecs.World) Query8[A, B, C, D, E, F, G, H] {
 	q.compiled.Compile(w, q.include, q.optional, q.exclude)
-	return Query8[A, B, C, D, E, F, G, H]{
+	return Query8[A, B, C, D, E, F, G, H](query{
 		w.Query(q.compiled.Filter()),
 		q.compiled.Ids,
-	}
+	})
 }
 
 // Filter generates and return the [ecs.Filter] used after [Filter8.Query].
@@ -831,52 +636,9 @@ func (q *Filter8[A, B, C, D, E, F, G, H]) Filter(w *ecs.World) ecs.MaskPair {
 // Query8 is a generic query iterator for eight components.
 //
 // Create it with [NewFilter8] and [Filter8.Query]
-type Query8[A any, B any, C any, D any, E any, F any, G any, H any] struct {
-	ecs.Query
-	ids []ecs.ID
-}
+type Query8[A any, B any, C any, D any, E any, F any, G any, H any] query
 
 // Get returns the [ecs.Entity] and all queried components for the current query iterator position.
 func (q *Query8[A, B, C, D, E, F, G, H]) Get() (ecs.Entity, *A, *B, *C, *D, *E, *F, *G, *H) {
 	return q.Entity(), (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2])), (*D)(q.Query.Get(q.ids[3])), (*E)(q.Query.Get(q.ids[4])), (*F)(q.Query.Get(q.ids[5])), (*G)(q.Query.Get(q.ids[6])), (*H)(q.Query.Get(q.ids[7]))
 }
-
-// Get1 returns the first queried component for the current query iterator position.
-func (q *Query8[A, B, C, D, E, F, G, H]) Get1() *A {
-	return (*A)(q.Query.Get(q.ids[0]))
-}
-
-// Get2 returns the second queried component for the current query iterator position.
-func (q *Query8[A, B, C, D, E, F, G, H]) Get2() *B {
-	return (*B)(q.Query.Get(q.ids[1]))
-}
-
-// Get3 returns the third queried component for the current query iterator position.
-func (q *Query8[A, B, C, D, E, F, G, H]) Get3() *C {
-	return (*C)(q.Query.Get(q.ids[2]))
-}
-
-// Get4 returns the fourth queried component for the current query iterator position.
-func (q *Query8[A, B, C, D, E, F, G, H]) Get4() *D {
-	return (*D)(q.Query.Get(q.ids[3]))
-}
-
-// Get5 returns the fifth queried component for the current query iterator position.
-func (q *Query8[A, B, C, D, E, F, G, H]) Get5() *E {
-	return (*E)(q.Query.Get(q.ids[4]))
-}
-
-// Get6 returns the sixth queried component for the current query iterator position.
-func (q *Query8[A, B, C, D, E, F, G, H]) Get6() *F {
-	return (*F)(q.Query.Get(q.ids[5]))
-}
-
-// Get7 returns the seventh queried component for the current query iterator position.
-func (q *Query8[A, B, C, D, E, F, G, H]) Get7() *G {
-	return (*G)(q.Query.Get(q.ids[6]))
-}
-
-// Get8 returns the eighth queried component for the current query iterator position.
-func (q *Query8[A, B, C, D, E, F, G, H]) Get8() *H {
-	return (*H)(q.Query.Get(q.ids[7]))
-}
diff --git a/generic/util.go b/generic/util.go
index 84a61fb..6227c9c 100644
--- a/generic/util.go
+++ b/generic/util.go
@@ -6,6 +6,23 @@ import (
 	"github.com/mlange-42/arche/ecs"
 )
 
+type filter struct {
+	include  []Comp
+	optional []Comp
+	exclude  []Comp
+	compiled compiledQuery
+}
+
+type query struct {
+	ecs.Query
+	ids []ecs.ID
+}
+
+type mapper struct {
+	ids   []ecs.ID
+	world *ecs.World
+}
+
 func typeOf[T any]() Comp {
 	return reflect.TypeOf((*T)(nil)).Elem()
 }


Test patch:
diff --git a/benchmark/iterate/arche_test.go b/benchmark/iterate/arche_test.go
index ae79833..26cb0dd 100644
--- a/benchmark/iterate/arche_test.go
+++ b/benchmark/iterate/arche_test.go
@@ -64,7 +64,7 @@ func runArcheQueryGeneric(b *testing.B, count int) {
 	for i := 0; i < count; i++ {
 		_ = world.NewEntity(posID, rotID)
 	}
-	query := generic.NewFilter2[position, rotation]()
+	query := generic.NewFilter1[position]()
 	b.StartTimer()
 
 	for i := 0; i < b.N; i++ {
@@ -72,7 +72,7 @@ func runArcheQueryGeneric(b *testing.B, count int) {
 		q := query.Query(&world)
 		b.StartTimer()
 		for q.Next() {
-			pos := q.Get1()
+			_, pos := q.Get()
 			_ = pos
 		}
 	}
@@ -130,13 +130,7 @@ func runArcheQueryGeneric5C(b *testing.B, count int) {
 		q := query.Query(&world)
 		b.StartTimer()
 		for q.Next() {
-			t1 := q.Get1()
-			t2 := q.Get2()
-			t3 := q.Get3()
-			t4 := q.Get4()
-			t5 := q.Get5()
-			_, _, _, _, _ = t1, t2, t3, t4, t5
-			_, _, _, _, _ = t1, t2, t3, t4, t5
+			_, _, _, _, _, _ = q.Get()
 		}
 	}
 }
diff --git a/generic/query_test.go b/generic/query_test.go
index 362cd36..2369e33 100644
--- a/generic/query_test.go
+++ b/generic/query_test.go
@@ -98,6 +98,7 @@ func TestQuery0(t *testing.T) {
 	assert.Equal(t, ecs.All(8).Without(9), filter.Filter(&w))
 	query := filter.Query(&w)
 	for query.Next() {
+		_ = query.Get()
 		cnt++
 	}
 	assert.Equal(t, 1, cnt)
@@ -132,9 +133,7 @@ func TestQuery1(t *testing.T) {
 	assert.Equal(t, ecs.All(0, 8).Without(9), filter.Filter(&w))
 	query := filter.Query(&w)
 	for query.Next() {
-		c0 := query.Get1()
-		_, c02 := query.Get()
-		assert.Equal(t, c0, c02)
+		_, c0 := query.Get()
 		assert.Equal(t, cnt+1, int(c0.val))
 		cnt++
 	}
@@ -174,14 +173,9 @@ func TestQuery2(t *testing.T) {
 		cnt := 0
 		q := filter.Query(&w)
 		for q.Next() {
-			c1 := q.Get1()
-			c2 := q.Get2()
+			_, c1, c2 := q.Get()
 			assert.Equal(t, cnt+1, int(c1.val))
 			assert.Equal(t, cnt+2, int(c2.val))
-
-			_, c12, c22 := q.Get()
-			assert.Equal(t, c1, c12)
-			assert.Equal(t, c2, c22)
 			cnt++
 		}
 		assert.Equal(t, 1, cnt)
@@ -223,17 +217,10 @@ func TestQuery3(t *testing.T) {
 	assert.Equal(t, ecs.All(0, 2, 8).Without(9), filter.Filter(&w))
 	query := filter.Query(&w)
 	for query.Next() {
-		c1 := query.Get1()
-		c2 := query.Get2()
-		c3 := query.Get3()
+		_, c1, c2, c3 := query.Get()
 		assert.Equal(t, cnt+1, int(c1.val))
 		assert.Equal(t, cnt+2, int(c2.val))
 		assert.Equal(t, cnt+3, int(c3.val))
-
-		_, c12, c22, c32 := query.Get()
-		assert.Equal(t, c1, c12)
-		assert.Equal(t, c2, c22)
-		assert.Equal(t, c3, c32)
 		cnt++
 	}
 	assert.Equal(t, 1, cnt)
@@ -278,20 +265,11 @@ func TestQuery4(t *testing.T) {
 	assert.Equal(t, ecs.All(0, 2, 3, 8).Without(9), filter.Filter(&w))
 	query := filter.Query(&w)
 	for query.Next() {
-		c1 := query.Get1()
-		c2 := query.Get2()
-		c3 := query.Get3()
-		c4 := query.Get4()
+		_, c1, c2, c3, c4 := query.Get()
 		assert.Equal(t, cnt+1, int(c1.val))
 		assert.Equal(t, cnt+2, int(c2.val))
 		assert.Equal(t, cnt+3, int(c3.val))
 		assert.Equal(t, cnt+4, int(c4.val))
-
-		_, c12, c22, c32, c42 := query.Get()
-		assert.Equal(t, c1, c12)
-		assert.Equal(t, c2, c22)
-		assert.Equal(t, c3, c32)
-		assert.Equal(t, c4, c42)
 		cnt++
 	}
 	assert.Equal(t, 1, cnt)
@@ -340,23 +318,12 @@ func TestQuery5(t *testing.T) {
 	assert.Equal(t, ecs.All(0, 2, 3, 4, 8).Without(9), filter.Filter(&w))
 	query := filter.Query(&w)
 	for query.Next() {
-		c1 := query.Get1()
-		c2 := query.Get2()
-		c3 := query.Get3()
-		c4 := query.Get4()
-		c5 := query.Get5()
+		_, c1, c2, c3, c4, c5 := query.Get()
 		assert.Equal(t, cnt+1, int(c1.val))
 		assert.Equal(t, cnt+2, int(c2.val))
 		assert.Equal(t, cnt+3, int(c3.val))
 		assert.Equal(t, cnt+4, int(c4.val))
 		assert.Equal(t, cnt+5, int(c5.val))
-
-		_, c12, c22, c32, c42, c52 := query.Get()
-		assert.Equal(t, c1, c12)
-		assert.Equal(t, c2, c22)
-		assert.Equal(t, c3, c32)
-		assert.Equal(t, c4, c42)
-		assert.Equal(t, c5, c52)
 		cnt++
 	}
 	assert.Equal(t, 1, cnt)
@@ -409,26 +376,13 @@ func TestQuery6(t *testing.T) {
 	assert.Equal(t, ecs.All(0, 2, 3, 4, 5, 8).Without(9), filter.Filter(&w))
 	query := filter.Query(&w)
 	for query.Next() {
-		c1 := query.Get1()
-		c2 := query.Get2()
-		c3 := query.Get3()
-		c4 := query.Get4()
-		c5 := query.Get5()
-		c6 := query.Get6()
+		_, c1, c2, c3, c4, c5, c6 := query.Get()
 		assert.Equal(t, cnt+1, int(c1.val))
 		assert.Equal(t, cnt+2, int(c2.val))
 		assert.Equal(t, cnt+3, int(c3.val))
 		assert.Equal(t, cnt+4, int(c4.val))
 		assert.Equal(t, cnt+5, int(c5.val))
 		assert.Equal(t, cnt+6, int(c6.val))
-
-		_, c12, c22, c32, c42, c52, c62 := query.Get()
-		assert.Equal(t, c1, c12)
-		assert.Equal(t, c2, c22)
-		assert.Equal(t, c3, c32)
-		assert.Equal(t, c4, c42)
-		assert.Equal(t, c5, c52)
-		assert.Equal(t, c6, c62)
 		cnt++
 	}
 	assert.Equal(t, 1, cnt)
@@ -488,13 +442,7 @@ func TestQuery7(t *testing.T) {
 	assert.Equal(t, ecs.All(0, 2, 3, 4, 5, 6, 8).Without(9), filter.Filter(&w))
 	query := filter.Query(&w)
 	for query.Next() {
-		c1 := query.Get1()
-		c2 := query.Get2()
-		c3 := query.Get3()
-		c4 := query.Get4()
-		c5 := query.Get5()
-		c6 := query.Get6()
-		c7 := query.Get7()
+		_, c1, c2, c3, c4, c5, c6, c7 := query.Get()
 		assert.Equal(t, cnt+1, int(c1.val))
 		assert.Equal(t, cnt+2, int(c2.val))
 		assert.Equal(t, cnt+3, int(c3.val))
@@ -502,15 +450,6 @@ func TestQuery7(t *testing.T) {
 		assert.Equal(t, cnt+5, int(c5.val))
 		assert.Equal(t, cnt+6, int(c6.val))
 		assert.Equal(t, cnt+7, int(c7.val))
-
-		_, c12, c22, c32, c42, c52, c62, c72 := query.Get()
-		assert.Equal(t, c1, c12)
-		assert.Equal(t, c2, c22)
-		assert.Equal(t, c3, c32)
-		assert.Equal(t, c4, c42)
-		assert.Equal(t, c5, c52)
-		assert.Equal(t, c6, c62)
-		assert.Equal(t, c7, c72)
 		cnt++
 	}
 	assert.Equal(t, 1, cnt)
@@ -566,14 +505,7 @@ func TestQuery8(t *testing.T) {
 	assert.Equal(t, ecs.All(0, 2, 3, 4, 5, 6, 7, 8).Without(9), filter.Filter(&w))
 	query := filter.Query(&w)
 	for query.Next() {
-		c1 := query.Get1()
-		c2 := query.Get2()
-		c3 := query.Get3()
-		c4 := query.Get4()
-		c5 := query.Get5()
-		c6 := query.Get6()
-		c7 := query.Get7()
-		c8 := query.Get8()
+		_, c1, c2, c3, c4, c5, c6, c7, c8 := query.Get()
 		assert.Equal(t, cnt+1, int(c1.val))
 		assert.Equal(t, cnt+2, int(c2.val))
 		assert.Equal(t, cnt+3, int(c3.val))
@@ -582,16 +514,6 @@ func TestQuery8(t *testing.T) {
 		assert.Equal(t, cnt+6, int(c6.val))
 		assert.Equal(t, cnt+7, int(c7.val))
 		assert.Equal(t, cnt+8, int(c8.val))
-
-		_, c12, c22, c32, c42, c52, c62, c72, c82 := query.Get()
-		assert.Equal(t, c1, c12)
-		assert.Equal(t, c2, c22)
-		assert.Equal(t, c3, c32)
-		assert.Equal(t, c4, c42)
-		assert.Equal(t, c5, c52)
-		assert.Equal(t, c6, c62)
-		assert.Equal(t, c7, c72)
-		assert.Equal(t, c8, c82)
 		cnt++
 	}
 	assert.Equal(t, 1, cnt)
@@ -613,8 +535,7 @@ func TestQueryGeneric(t *testing.T) {
 	q := query.Query(&world)
 	cnt := 0
 	for q.Next() {
-		s1 := q.Get1()
-		s2 := q.Get2()
+		_, s1, s2 := q.Get()
 		_ = s1
 		_ = s2
 		cnt++