• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mlange-42 / ark / 13768706324

10 Mar 2025 03:38PM CUT coverage: 99.437%. Remained the same
13768706324

Pull #179

github

web-flow
Merge 8094be2da into 093db9782
Pull Request #179: Fix false-positive debug checks

6538 of 6575 relevant lines covered (99.44%)

27299.41 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.09
/ecs/query_gen.go
1
package ecs
2

3
// Code generated by go generate; DO NOT EDIT.
4

5
type cursor struct {
6
        archetype int
7
        table     int
8
        index     uintptr
9
        maxIndex  int64
10
}
11

12
// Query0 is a query for 0 components.
13
// Use a [Filter0] to create one.
14
//
15
// Queries are one-time use iterators and must be re-created each time before iterating.
16
//
17
// See [Query2] for a usage example.
18
type Query0 struct {
19
        world      *World
20
        filter     *filter
21
        relations  []RelationID
22
        lock       uint8
23
        cursor     cursor
24
        tables     []tableID
25
        table      *table
26
        cache      *cacheEntry
27
        components []*componentStorage
28
}
29

30
func newQuery0(world *World, filter *filter, relations []RelationID,
31
        cacheID cacheID, components []*componentStorage) Query0 {
10✔
32
        var cache *cacheEntry
10✔
33
        if cacheID != maxCacheID {
11✔
34
                cache = world.storage.getRegisteredFilter(cacheID)
1✔
35
        }
1✔
36

37
        return Query0{
10✔
38
                world:      world,
10✔
39
                filter:     filter,
10✔
40
                relations:  relations,
10✔
41
                cache:      cache,
10✔
42
                lock:       world.lock(),
10✔
43
                components: components,
10✔
44
                cursor: cursor{
10✔
45
                        archetype: -1,
10✔
46
                        table:     -1,
10✔
47
                        index:     0,
10✔
48
                        maxIndex:  -1,
10✔
49
                },
10✔
50
        }
10✔
51
}
52

53
// Next advances the query's cursor to the next entity.
54
func (q *Query0) Next() bool {
239✔
55
        q.world.checkQueryNext(&q.cursor)
239✔
56
        if int64(q.cursor.index) < q.cursor.maxIndex {
452✔
57
                q.cursor.index++
213✔
58
                return true
213✔
59
        }
213✔
60
        return q.nextTableOrArchetype()
26✔
61
}
62

63
// Entity returns the current entity.
64
func (q *Query0) Entity() Entity {
218✔
65
        q.world.checkQueryGet(&q.cursor)
218✔
66
        return q.table.GetEntity(q.cursor.index)
218✔
67
}
218✔
68

69
// Count counts the entities matching this query.
70
//
71
// Has some overhead of iterating through archetypes.
72
// However, this is still much faster than manual counting via iteration.
73
//
74
// Does not iterate or close the query.
75
func (q *Query0) Count() int {
7✔
76
        if q.cache == nil {
13✔
77
                return countQuery(&q.world.storage, q.filter, q.relations)
6✔
78
        }
6✔
79
        return countQueryCache(&q.world.storage, q.cache, q.relations)
1✔
80
}
81

82
// Close closes the Query and unlocks the world.
83
//
84
// Automatically called when iteration completes.
85
// Needs to be called only if breaking out of the query iteration or not iterating at all.
86
func (q *Query0) Close() {
10✔
87
        q.cursor.archetype = -2
10✔
88
        q.cursor.table = -2
10✔
89
        q.tables = nil
10✔
90
        q.table = nil
10✔
91
        q.cache = nil
10✔
92
        q.world.unlock(q.lock)
10✔
93
}
10✔
94

95
func (q *Query0) nextTableOrArchetype() bool {
26✔
96
        if q.cache != nil {
31✔
97
                return q.nextTable(q.cache.tables)
5✔
98
        }
5✔
99
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
23✔
100
                return true
2✔
101
        }
2✔
102
        return q.nextArchetype()
19✔
103
}
104

105
func (q *Query0) nextArchetype() bool {
19✔
106
        maxArchIndex := len(q.world.storage.archetypes) - 1
19✔
107
        for q.cursor.archetype < maxArchIndex {
40✔
108
                q.cursor.archetype++
21✔
109
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
21✔
110
                if !q.filter.matches(&archetype.mask) {
25✔
111
                        continue
4✔
112
                }
113

114
                if !archetype.HasRelations() {
31✔
115
                        table := &q.world.storage.tables[archetype.tables[0]]
15✔
116
                        if table.Len() > 0 {
23✔
117
                                q.setTable(0, table)
8✔
118
                                return true
8✔
119
                        }
8✔
120
                        continue
7✔
121
                }
122

123
                q.tables = archetype.GetTables(q.relations)
1✔
124
                q.cursor.table = -1
1✔
125
                if q.nextTable(q.tables) {
2✔
126
                        return true
1✔
127
                }
1✔
128
        }
129
        q.Close()
9✔
130
        return false
9✔
131
}
132

133
func (q *Query0) nextTable(tables []tableID) bool {
17✔
134
        maxTableIndex := len(tables) - 1
17✔
135
        for q.cursor.table < maxTableIndex {
24✔
136
                q.cursor.table++
7✔
137
                table := &q.world.storage.tables[tables[q.cursor.table]]
7✔
138
                if table.Len() == 0 {
7✔
139
                        continue
×
140
                }
141
                if !table.Matches(q.relations) {
7✔
142
                        continue
×
143
                }
144
                q.setTable(q.cursor.table, table)
7✔
145
                return true
7✔
146
        }
147
        if q.cache != nil {
11✔
148
                q.Close()
1✔
149
        }
1✔
150
        return false
10✔
151
}
152

153
func (q *Query0) setTable(index int, table *table) {
15✔
154
        q.cursor.table = index
15✔
155
        q.table = table
15✔
156
        q.cursor.index = 0
15✔
157
        q.cursor.maxIndex = int64(q.table.Len() - 1)
15✔
158
}
15✔
159

160
// Query1 is a query for 1 components.
161
// Use a [Filter1] to create one.
162
//
163
// Queries are one-time use iterators and must be re-created each time before iterating.
164
//
165
// See [Query2] for a usage example.
166
type Query1[A any] struct {
167
        world      *World
168
        filter     *filter
169
        relations  []RelationID
170
        lock       uint8
171
        cursor     cursor
172
        tables     []tableID
173
        table      *table
174
        cache      *cacheEntry
175
        components []*componentStorage
176
        columnA    *column
177
}
178

179
func newQuery1[A any](world *World, filter *filter, ids []ID, relations []RelationID,
180
        cacheID cacheID, components []*componentStorage) Query1[A] {
1,118✔
181
        var cache *cacheEntry
1,118✔
182
        if cacheID != maxCacheID {
1,121✔
183
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
184
        }
3✔
185

186
        return Query1[A]{
1,118✔
187
                world:      world,
1,118✔
188
                filter:     filter,
1,118✔
189
                relations:  relations,
1,118✔
190
                cache:      cache,
1,118✔
191
                lock:       world.lock(),
1,118✔
192
                components: components,
1,118✔
193
                cursor: cursor{
1,118✔
194
                        archetype: -1,
1,118✔
195
                        table:     -1,
1,118✔
196
                        index:     0,
1,118✔
197
                        maxIndex:  -1,
1,118✔
198
                },
1,118✔
199
        }
1,118✔
200
}
201

202
// Next advances the query's cursor to the next entity.
203
func (q *Query1[A]) Next() bool {
997,360✔
204
        q.world.checkQueryNext(&q.cursor)
997,360✔
205
        if int64(q.cursor.index) < q.cursor.maxIndex {
1,992,474✔
206
                q.cursor.index++
995,114✔
207
                return true
995,114✔
208
        }
995,114✔
209
        return q.nextTableOrArchetype()
2,246✔
210
}
211

212
// Entity returns the current entity.
213
func (q *Query1[A]) Entity() Entity {
1,990,576✔
214
        q.world.checkQueryGet(&q.cursor)
1,990,576✔
215
        return q.table.GetEntity(q.cursor.index)
1,990,576✔
216
}
1,990,576✔
217

218
// Get returns the queried components of the current entity.
219
//
220
// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)!
221
func (q *Query1[A]) Get() *A {
995,425✔
222
        q.world.checkQueryGet(&q.cursor)
995,425✔
223
        return (*A)(q.columnA.Get(q.cursor.index))
995,425✔
224
}
995,425✔
225

226
// GetRelation returns the entity relation target of the component at the given index.
227
func (q *Query1[A]) GetRelation(index int) Entity {
42✔
228
        return q.components[index].columns[q.table.id].target
42✔
229
}
42✔
230

231
// Count counts the entities matching this query.
232
//
233
// Has some overhead of iterating through archetypes.
234
// However, this is still much faster than manual counting via iteration.
235
//
236
// Does not iterate or close the query.
237
func (q *Query1[A]) Count() int {
11✔
238
        if q.cache == nil {
19✔
239
                return countQuery(&q.world.storage, q.filter, q.relations)
8✔
240
        }
8✔
241
        return countQueryCache(&q.world.storage, q.cache, q.relations)
3✔
242
}
243

244
// Close closes the Query and unlocks the world.
245
//
246
// Automatically called when iteration completes.
247
// Needs to be called only if breaking out of the query iteration or not iterating at all.
248
func (q *Query1[A]) Close() {
1,118✔
249
        q.cursor.archetype = -2
1,118✔
250
        q.cursor.table = -2
1,118✔
251
        q.tables = nil
1,118✔
252
        q.table = nil
1,118✔
253
        q.cache = nil
1,118✔
254
        q.columnA = nil
1,118✔
255
        q.world.unlock(q.lock)
1,118✔
256
}
1,118✔
257

258
func (q *Query1[A]) nextTableOrArchetype() bool {
2,246✔
259
        if q.cache != nil {
2,253✔
260
                return q.nextTable(q.cache.tables)
7✔
261
        }
7✔
262
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
2,240✔
263
                return true
1✔
264
        }
1✔
265
        return q.nextArchetype()
2,238✔
266
}
267

268
func (q *Query1[A]) nextArchetype() bool {
2,238✔
269
        maxArchIndex := len(q.world.storage.archetypes) - 1
2,238✔
270
        for q.cursor.archetype < maxArchIndex {
4,753✔
271
                q.cursor.archetype++
2,515✔
272
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
2,515✔
273
                if !q.filter.matches(&archetype.mask) {
3,830✔
274
                        continue
1,315✔
275
                }
276

277
                if !archetype.HasRelations() {
2,376✔
278
                        table := &q.world.storage.tables[archetype.tables[0]]
1,177✔
279
                        if table.Len() > 0 {
2,286✔
280
                                q.setTable(0, table)
1,109✔
281
                                return true
1,109✔
282
                        }
1,109✔
283
                        continue
68✔
284
                }
285

286
                q.tables = archetype.GetTables(q.relations)
22✔
287
                q.cursor.table = -1
22✔
288
                if q.nextTable(q.tables) {
35✔
289
                        return true
13✔
290
                }
13✔
291
        }
292
        q.Close()
1,115✔
293
        return false
1,115✔
294
}
295

296
func (q *Query1[A]) nextTable(tables []tableID) bool {
1,152✔
297
        maxTableIndex := len(tables) - 1
1,152✔
298
        for q.cursor.table < maxTableIndex {
1,183✔
299
                q.cursor.table++
31✔
300
                table := &q.world.storage.tables[tables[q.cursor.table]]
31✔
301
                if table.Len() == 0 {
43✔
302
                        continue
12✔
303
                }
304
                if !table.Matches(q.relations) {
20✔
305
                        continue
1✔
306
                }
307
                q.setTable(q.cursor.table, table)
18✔
308
                return true
18✔
309
        }
310
        if q.cache != nil {
1,137✔
311
                q.Close()
3✔
312
        }
3✔
313
        return false
1,134✔
314
}
315

316
func (q *Query1[A]) setTable(index int, table *table) {
1,127✔
317
        q.cursor.table = index
1,127✔
318
        q.table = table
1,127✔
319
        q.columnA = q.components[0].columns[q.table.id]
1,127✔
320
        q.cursor.index = 0
1,127✔
321
        q.cursor.maxIndex = int64(q.table.Len() - 1)
1,127✔
322
}
1,127✔
323

324
// Query2 is a query for 2 components.
325
// Use a [Filter2] to create one.
326
//
327
// Queries are one-time use iterators and must be re-created each time before iterating.
328
type Query2[A any, B any] struct {
329
        world      *World
330
        filter     *filter
331
        relations  []RelationID
332
        lock       uint8
333
        cursor     cursor
334
        tables     []tableID
335
        table      *table
336
        cache      *cacheEntry
337
        components []*componentStorage
338
        columnA    *column
339
        columnB    *column
340
}
341

342
func newQuery2[A any, B any](world *World, filter *filter, ids []ID, relations []RelationID,
343
        cacheID cacheID, components []*componentStorage) Query2[A, B] {
16✔
344
        var cache *cacheEntry
16✔
345
        if cacheID != maxCacheID {
19✔
346
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
347
        }
3✔
348

349
        return Query2[A, B]{
16✔
350
                world:      world,
16✔
351
                filter:     filter,
16✔
352
                relations:  relations,
16✔
353
                cache:      cache,
16✔
354
                lock:       world.lock(),
16✔
355
                components: components,
16✔
356
                cursor: cursor{
16✔
357
                        archetype: -1,
16✔
358
                        table:     -1,
16✔
359
                        index:     0,
16✔
360
                        maxIndex:  -1,
16✔
361
                },
16✔
362
        }
16✔
363
}
364

365
// Next advances the query's cursor to the next entity.
366
func (q *Query2[A, B]) Next() bool {
251✔
367
        q.world.checkQueryNext(&q.cursor)
251✔
368
        if int64(q.cursor.index) < q.cursor.maxIndex {
469✔
369
                q.cursor.index++
218✔
370
                return true
218✔
371
        }
218✔
372
        return q.nextTableOrArchetype()
33✔
373
}
374

375
// Entity returns the current entity.
376
func (q *Query2[A, B]) Entity() Entity {
204✔
377
        q.world.checkQueryGet(&q.cursor)
204✔
378
        return q.table.GetEntity(q.cursor.index)
204✔
379
}
204✔
380

381
// Get returns the queried components of the current entity.
382
//
383
// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)!
384
func (q *Query2[A, B]) Get() (*A, *B) {
236✔
385
        q.world.checkQueryGet(&q.cursor)
236✔
386
        return (*A)(q.columnA.Get(q.cursor.index)),
236✔
387
                (*B)(q.columnB.Get(q.cursor.index))
236✔
388
}
236✔
389

390
// GetRelation returns the entity relation target of the component at the given index.
391
func (q *Query2[A, B]) GetRelation(index int) Entity {
40✔
392
        return q.components[index].columns[q.table.id].target
40✔
393
}
40✔
394

395
// Count counts the entities matching this query.
396
//
397
// Has some overhead of iterating through archetypes.
398
// However, this is still much faster than manual counting via iteration.
399
//
400
// Does not iterate or close the query.
401
func (q *Query2[A, B]) Count() int {
11✔
402
        if q.cache == nil {
19✔
403
                return countQuery(&q.world.storage, q.filter, q.relations)
8✔
404
        }
8✔
405
        return countQueryCache(&q.world.storage, q.cache, q.relations)
3✔
406
}
407

408
// Close closes the Query and unlocks the world.
409
//
410
// Automatically called when iteration completes.
411
// Needs to be called only if breaking out of the query iteration or not iterating at all.
412
func (q *Query2[A, B]) Close() {
16✔
413
        q.cursor.archetype = -2
16✔
414
        q.cursor.table = -2
16✔
415
        q.tables = nil
16✔
416
        q.table = nil
16✔
417
        q.cache = nil
16✔
418
        q.columnA = nil
16✔
419
        q.columnB = nil
16✔
420
        q.world.unlock(q.lock)
16✔
421
}
16✔
422

423
func (q *Query2[A, B]) nextTableOrArchetype() bool {
33✔
424
        if q.cache != nil {
40✔
425
                return q.nextTable(q.cache.tables)
7✔
426
        }
7✔
427
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
27✔
428
                return true
1✔
429
        }
1✔
430
        return q.nextArchetype()
25✔
431
}
432

433
func (q *Query2[A, B]) nextArchetype() bool {
25✔
434
        maxArchIndex := len(q.world.storage.archetypes) - 1
25✔
435
        for q.cursor.archetype < maxArchIndex {
58✔
436
                q.cursor.archetype++
33✔
437
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
33✔
438
                if !q.filter.matches(&archetype.mask) {
54✔
439
                        continue
21✔
440
                }
441

442
                if !archetype.HasRelations() {
18✔
443
                        table := &q.world.storage.tables[archetype.tables[0]]
7✔
444
                        if table.Len() > 0 {
14✔
445
                                q.setTable(0, table)
7✔
446
                                return true
7✔
447
                        }
7✔
448
                        continue
×
449
                }
450

451
                q.tables = archetype.GetTables(q.relations)
4✔
452
                q.cursor.table = -1
4✔
453
                if q.nextTable(q.tables) {
8✔
454
                        return true
4✔
455
                }
4✔
456
        }
457
        q.Close()
13✔
458
        return false
13✔
459
}
460

461
func (q *Query2[A, B]) nextTable(tables []tableID) bool {
23✔
462
        maxTableIndex := len(tables) - 1
23✔
463
        for q.cursor.table < maxTableIndex {
36✔
464
                q.cursor.table++
13✔
465
                table := &q.world.storage.tables[tables[q.cursor.table]]
13✔
466
                if table.Len() == 0 {
16✔
467
                        continue
3✔
468
                }
469
                if !table.Matches(q.relations) {
11✔
470
                        continue
1✔
471
                }
472
                q.setTable(q.cursor.table, table)
9✔
473
                return true
9✔
474
        }
475
        if q.cache != nil {
17✔
476
                q.Close()
3✔
477
        }
3✔
478
        return false
14✔
479
}
480

481
func (q *Query2[A, B]) setTable(index int, table *table) {
16✔
482
        q.cursor.table = index
16✔
483
        q.table = table
16✔
484
        q.columnA = q.components[0].columns[q.table.id]
16✔
485
        q.columnB = q.components[1].columns[q.table.id]
16✔
486
        q.cursor.index = 0
16✔
487
        q.cursor.maxIndex = int64(q.table.Len() - 1)
16✔
488
}
16✔
489

490
// Query3 is a query for 3 components.
491
// Use a [Filter3] to create one.
492
//
493
// Queries are one-time use iterators and must be re-created each time before iterating.
494
//
495
// See [Query2] for a usage example.
496
type Query3[A any, B any, C any] struct {
497
        world      *World
498
        filter     *filter
499
        relations  []RelationID
500
        lock       uint8
501
        cursor     cursor
502
        tables     []tableID
503
        table      *table
504
        cache      *cacheEntry
505
        components []*componentStorage
506
        columnA    *column
507
        columnB    *column
508
        columnC    *column
509
}
510

511
func newQuery3[A any, B any, C any](world *World, filter *filter, ids []ID, relations []RelationID,
512
        cacheID cacheID, components []*componentStorage) Query3[A, B, C] {
16✔
513
        var cache *cacheEntry
16✔
514
        if cacheID != maxCacheID {
19✔
515
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
516
        }
3✔
517

518
        return Query3[A, B, C]{
16✔
519
                world:      world,
16✔
520
                filter:     filter,
16✔
521
                relations:  relations,
16✔
522
                cache:      cache,
16✔
523
                lock:       world.lock(),
16✔
524
                components: components,
16✔
525
                cursor: cursor{
16✔
526
                        archetype: -1,
16✔
527
                        table:     -1,
16✔
528
                        index:     0,
16✔
529
                        maxIndex:  -1,
16✔
530
                },
16✔
531
        }
16✔
532
}
533

534
// Next advances the query's cursor to the next entity.
535
func (q *Query3[A, B, C]) Next() bool {
289✔
536
        q.world.checkQueryNext(&q.cursor)
289✔
537
        if int64(q.cursor.index) < q.cursor.maxIndex {
539✔
538
                q.cursor.index++
250✔
539
                return true
250✔
540
        }
250✔
541
        return q.nextTableOrArchetype()
39✔
542
}
543

544
// Entity returns the current entity.
545
func (q *Query3[A, B, C]) Entity() Entity {
204✔
546
        q.world.checkQueryGet(&q.cursor)
204✔
547
        return q.table.GetEntity(q.cursor.index)
204✔
548
}
204✔
549

550
// Get returns the queried components of the current entity.
551
//
552
// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)!
553
func (q *Query3[A, B, C]) Get() (*A, *B, *C) {
204✔
554
        q.world.checkQueryGet(&q.cursor)
204✔
555
        return (*A)(q.columnA.Get(q.cursor.index)),
204✔
556
                (*B)(q.columnB.Get(q.cursor.index)),
204✔
557
                (*C)(q.columnC.Get(q.cursor.index))
204✔
558
}
204✔
559

560
// GetRelation returns the entity relation target of the component at the given index.
561
func (q *Query3[A, B, C]) GetRelation(index int) Entity {
40✔
562
        return q.components[index].columns[q.table.id].target
40✔
563
}
40✔
564

565
// Count counts the entities matching this query.
566
//
567
// Has some overhead of iterating through archetypes.
568
// However, this is still much faster than manual counting via iteration.
569
//
570
// Does not iterate or close the query.
571
func (q *Query3[A, B, C]) Count() int {
11✔
572
        if q.cache == nil {
19✔
573
                return countQuery(&q.world.storage, q.filter, q.relations)
8✔
574
        }
8✔
575
        return countQueryCache(&q.world.storage, q.cache, q.relations)
3✔
576
}
577

578
// Close closes the Query and unlocks the world.
579
//
580
// Automatically called when iteration completes.
581
// Needs to be called only if breaking out of the query iteration or not iterating at all.
582
func (q *Query3[A, B, C]) Close() {
16✔
583
        q.cursor.archetype = -2
16✔
584
        q.cursor.table = -2
16✔
585
        q.tables = nil
16✔
586
        q.table = nil
16✔
587
        q.cache = nil
16✔
588
        q.columnA = nil
16✔
589
        q.columnB = nil
16✔
590
        q.columnC = nil
16✔
591
        q.world.unlock(q.lock)
16✔
592
}
16✔
593

594
func (q *Query3[A, B, C]) nextTableOrArchetype() bool {
39✔
595
        if q.cache != nil {
46✔
596
                return q.nextTable(q.cache.tables)
7✔
597
        }
7✔
598
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
37✔
599
                return true
5✔
600
        }
5✔
601
        return q.nextArchetype()
27✔
602
}
603

604
func (q *Query3[A, B, C]) nextArchetype() bool {
27✔
605
        maxArchIndex := len(q.world.storage.archetypes) - 1
27✔
606
        for q.cursor.archetype < maxArchIndex {
62✔
607
                q.cursor.archetype++
35✔
608
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
35✔
609
                if !q.filter.matches(&archetype.mask) {
56✔
610
                        continue
21✔
611
                }
612

613
                if !archetype.HasRelations() {
20✔
614
                        table := &q.world.storage.tables[archetype.tables[0]]
7✔
615
                        if table.Len() > 0 {
14✔
616
                                q.setTable(0, table)
7✔
617
                                return true
7✔
618
                        }
7✔
619
                        continue
×
620
                }
621

622
                q.tables = archetype.GetTables(q.relations)
6✔
623
                q.cursor.table = -1
6✔
624
                if q.nextTable(q.tables) {
12✔
625
                        return true
6✔
626
                }
6✔
627
        }
628
        q.Close()
13✔
629
        return false
13✔
630
}
631

632
func (q *Query3[A, B, C]) nextTable(tables []tableID) bool {
31✔
633
        maxTableIndex := len(tables) - 1
31✔
634
        for q.cursor.table < maxTableIndex {
51✔
635
                q.cursor.table++
20✔
636
                table := &q.world.storage.tables[tables[q.cursor.table]]
20✔
637
                if table.Len() == 0 {
23✔
638
                        continue
3✔
639
                }
640
                if !table.Matches(q.relations) {
19✔
641
                        continue
2✔
642
                }
643
                q.setTable(q.cursor.table, table)
15✔
644
                return true
15✔
645
        }
646
        if q.cache != nil {
19✔
647
                q.Close()
3✔
648
        }
3✔
649
        return false
16✔
650
}
651

652
func (q *Query3[A, B, C]) setTable(index int, table *table) {
22✔
653
        q.cursor.table = index
22✔
654
        q.table = table
22✔
655
        q.columnA = q.components[0].columns[q.table.id]
22✔
656
        q.columnB = q.components[1].columns[q.table.id]
22✔
657
        q.columnC = q.components[2].columns[q.table.id]
22✔
658
        q.cursor.index = 0
22✔
659
        q.cursor.maxIndex = int64(q.table.Len() - 1)
22✔
660
}
22✔
661

662
// Query4 is a query for 4 components.
663
// Use a [Filter4] to create one.
664
//
665
// Queries are one-time use iterators and must be re-created each time before iterating.
666
//
667
// See [Query2] for a usage example.
668
type Query4[A any, B any, C any, D any] struct {
669
        world      *World
670
        filter     *filter
671
        relations  []RelationID
672
        lock       uint8
673
        cursor     cursor
674
        tables     []tableID
675
        table      *table
676
        cache      *cacheEntry
677
        components []*componentStorage
678
        columnA    *column
679
        columnB    *column
680
        columnC    *column
681
        columnD    *column
682
}
683

684
func newQuery4[A any, B any, C any, D any](world *World, filter *filter, ids []ID, relations []RelationID,
685
        cacheID cacheID, components []*componentStorage) Query4[A, B, C, D] {
13✔
686
        var cache *cacheEntry
13✔
687
        if cacheID != maxCacheID {
16✔
688
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
689
        }
3✔
690

691
        return Query4[A, B, C, D]{
13✔
692
                world:      world,
13✔
693
                filter:     filter,
13✔
694
                relations:  relations,
13✔
695
                cache:      cache,
13✔
696
                lock:       world.lock(),
13✔
697
                components: components,
13✔
698
                cursor: cursor{
13✔
699
                        archetype: -1,
13✔
700
                        table:     -1,
13✔
701
                        index:     0,
13✔
702
                        maxIndex:  -1,
13✔
703
                },
13✔
704
        }
13✔
705
}
706

707
// Next advances the query's cursor to the next entity.
708
func (q *Query4[A, B, C, D]) Next() bool {
216✔
709
        q.world.checkQueryNext(&q.cursor)
216✔
710
        if int64(q.cursor.index) < q.cursor.maxIndex {
403✔
711
                q.cursor.index++
187✔
712
                return true
187✔
713
        }
187✔
714
        return q.nextTableOrArchetype()
29✔
715
}
716

717
// Entity returns the current entity.
718
func (q *Query4[A, B, C, D]) Entity() Entity {
204✔
719
        q.world.checkQueryGet(&q.cursor)
204✔
720
        return q.table.GetEntity(q.cursor.index)
204✔
721
}
204✔
722

723
// Get returns the queried components of the current entity.
724
//
725
// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)!
726
func (q *Query4[A, B, C, D]) Get() (*A, *B, *C, *D) {
204✔
727
        q.world.checkQueryGet(&q.cursor)
204✔
728
        return (*A)(q.columnA.Get(q.cursor.index)),
204✔
729
                (*B)(q.columnB.Get(q.cursor.index)),
204✔
730
                (*C)(q.columnC.Get(q.cursor.index)),
204✔
731
                (*D)(q.columnD.Get(q.cursor.index))
204✔
732
}
204✔
733

734
// GetRelation returns the entity relation target of the component at the given index.
735
func (q *Query4[A, B, C, D]) GetRelation(index int) Entity {
40✔
736
        return q.components[index].columns[q.table.id].target
40✔
737
}
40✔
738

739
// Count counts the entities matching this query.
740
//
741
// Has some overhead of iterating through archetypes.
742
// However, this is still much faster than manual counting via iteration.
743
//
744
// Does not iterate or close the query.
745
func (q *Query4[A, B, C, D]) Count() int {
11✔
746
        if q.cache == nil {
19✔
747
                return countQuery(&q.world.storage, q.filter, q.relations)
8✔
748
        }
8✔
749
        return countQueryCache(&q.world.storage, q.cache, q.relations)
3✔
750
}
751

752
// Close closes the Query and unlocks the world.
753
//
754
// Automatically called when iteration completes.
755
// Needs to be called only if breaking out of the query iteration or not iterating at all.
756
func (q *Query4[A, B, C, D]) Close() {
13✔
757
        q.cursor.archetype = -2
13✔
758
        q.cursor.table = -2
13✔
759
        q.tables = nil
13✔
760
        q.table = nil
13✔
761
        q.cache = nil
13✔
762
        q.columnA = nil
13✔
763
        q.columnB = nil
13✔
764
        q.columnC = nil
13✔
765
        q.columnD = nil
13✔
766
        q.world.unlock(q.lock)
13✔
767
}
13✔
768

769
func (q *Query4[A, B, C, D]) nextTableOrArchetype() bool {
29✔
770
        if q.cache != nil {
36✔
771
                return q.nextTable(q.cache.tables)
7✔
772
        }
7✔
773
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
23✔
774
                return true
1✔
775
        }
1✔
776
        return q.nextArchetype()
21✔
777
}
778

779
func (q *Query4[A, B, C, D]) nextArchetype() bool {
21✔
780
        maxArchIndex := len(q.world.storage.archetypes) - 1
21✔
781
        for q.cursor.archetype < maxArchIndex {
50✔
782
                q.cursor.archetype++
29✔
783
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
29✔
784
                if !q.filter.matches(&archetype.mask) {
47✔
785
                        continue
18✔
786
                }
787

788
                if !archetype.HasRelations() {
17✔
789
                        table := &q.world.storage.tables[archetype.tables[0]]
7✔
790
                        if table.Len() > 0 {
14✔
791
                                q.setTable(0, table)
7✔
792
                                return true
7✔
793
                        }
7✔
794
                        continue
×
795
                }
796

797
                q.tables = archetype.GetTables(q.relations)
3✔
798
                q.cursor.table = -1
3✔
799
                if q.nextTable(q.tables) {
6✔
800
                        return true
3✔
801
                }
3✔
802
        }
803
        q.Close()
10✔
804
        return false
10✔
805
}
806

807
func (q *Query4[A, B, C, D]) nextTable(tables []tableID) bool {
21✔
808
        maxTableIndex := len(tables) - 1
21✔
809
        for q.cursor.table < maxTableIndex {
33✔
810
                q.cursor.table++
12✔
811
                table := &q.world.storage.tables[tables[q.cursor.table]]
12✔
812
                if table.Len() == 0 {
15✔
813
                        continue
3✔
814
                }
815
                if !table.Matches(q.relations) {
10✔
816
                        continue
1✔
817
                }
818
                q.setTable(q.cursor.table, table)
8✔
819
                return true
8✔
820
        }
821
        if q.cache != nil {
16✔
822
                q.Close()
3✔
823
        }
3✔
824
        return false
13✔
825
}
826

827
func (q *Query4[A, B, C, D]) setTable(index int, table *table) {
15✔
828
        q.cursor.table = index
15✔
829
        q.table = table
15✔
830
        q.columnA = q.components[0].columns[q.table.id]
15✔
831
        q.columnB = q.components[1].columns[q.table.id]
15✔
832
        q.columnC = q.components[2].columns[q.table.id]
15✔
833
        q.columnD = q.components[3].columns[q.table.id]
15✔
834
        q.cursor.index = 0
15✔
835
        q.cursor.maxIndex = int64(q.table.Len() - 1)
15✔
836
}
15✔
837

838
// Query5 is a query for 5 components.
839
// Use a [Filter5] to create one.
840
//
841
// Queries are one-time use iterators and must be re-created each time before iterating.
842
//
843
// See [Query2] for a usage example.
844
type Query5[A any, B any, C any, D any, E any] struct {
845
        world      *World
846
        filter     *filter
847
        relations  []RelationID
848
        lock       uint8
849
        cursor     cursor
850
        tables     []tableID
851
        table      *table
852
        cache      *cacheEntry
853
        components []*componentStorage
854
        columnA    *column
855
        columnB    *column
856
        columnC    *column
857
        columnD    *column
858
        columnE    *column
859
}
860

861
func newQuery5[A any, B any, C any, D any, E any](world *World, filter *filter, ids []ID, relations []RelationID,
862
        cacheID cacheID, components []*componentStorage) Query5[A, B, C, D, E] {
13✔
863
        var cache *cacheEntry
13✔
864
        if cacheID != maxCacheID {
16✔
865
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
866
        }
3✔
867

868
        return Query5[A, B, C, D, E]{
13✔
869
                world:      world,
13✔
870
                filter:     filter,
13✔
871
                relations:  relations,
13✔
872
                cache:      cache,
13✔
873
                lock:       world.lock(),
13✔
874
                components: components,
13✔
875
                cursor: cursor{
13✔
876
                        archetype: -1,
13✔
877
                        table:     -1,
13✔
878
                        index:     0,
13✔
879
                        maxIndex:  -1,
13✔
880
                },
13✔
881
        }
13✔
882
}
883

884
// Next advances the query's cursor to the next entity.
885
func (q *Query5[A, B, C, D, E]) Next() bool {
216✔
886
        q.world.checkQueryNext(&q.cursor)
216✔
887
        if int64(q.cursor.index) < q.cursor.maxIndex {
403✔
888
                q.cursor.index++
187✔
889
                return true
187✔
890
        }
187✔
891
        return q.nextTableOrArchetype()
29✔
892
}
893

894
// Entity returns the current entity.
895
func (q *Query5[A, B, C, D, E]) Entity() Entity {
204✔
896
        q.world.checkQueryGet(&q.cursor)
204✔
897
        return q.table.GetEntity(q.cursor.index)
204✔
898
}
204✔
899

900
// Get returns the queried components of the current entity.
901
//
902
// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)!
903
func (q *Query5[A, B, C, D, E]) Get() (*A, *B, *C, *D, *E) {
204✔
904
        q.world.checkQueryGet(&q.cursor)
204✔
905
        return (*A)(q.columnA.Get(q.cursor.index)),
204✔
906
                (*B)(q.columnB.Get(q.cursor.index)),
204✔
907
                (*C)(q.columnC.Get(q.cursor.index)),
204✔
908
                (*D)(q.columnD.Get(q.cursor.index)),
204✔
909
                (*E)(q.columnE.Get(q.cursor.index))
204✔
910
}
204✔
911

912
// GetRelation returns the entity relation target of the component at the given index.
913
func (q *Query5[A, B, C, D, E]) GetRelation(index int) Entity {
40✔
914
        return q.components[index].columns[q.table.id].target
40✔
915
}
40✔
916

917
// Count counts the entities matching this query.
918
//
919
// Has some overhead of iterating through archetypes.
920
// However, this is still much faster than manual counting via iteration.
921
//
922
// Does not iterate or close the query.
923
func (q *Query5[A, B, C, D, E]) Count() int {
11✔
924
        if q.cache == nil {
19✔
925
                return countQuery(&q.world.storage, q.filter, q.relations)
8✔
926
        }
8✔
927
        return countQueryCache(&q.world.storage, q.cache, q.relations)
3✔
928
}
929

930
// Close closes the Query and unlocks the world.
931
//
932
// Automatically called when iteration completes.
933
// Needs to be called only if breaking out of the query iteration or not iterating at all.
934
func (q *Query5[A, B, C, D, E]) Close() {
13✔
935
        q.cursor.archetype = -2
13✔
936
        q.cursor.table = -2
13✔
937
        q.tables = nil
13✔
938
        q.table = nil
13✔
939
        q.cache = nil
13✔
940
        q.columnA = nil
13✔
941
        q.columnB = nil
13✔
942
        q.columnC = nil
13✔
943
        q.columnD = nil
13✔
944
        q.columnE = nil
13✔
945
        q.world.unlock(q.lock)
13✔
946
}
13✔
947

948
func (q *Query5[A, B, C, D, E]) nextTableOrArchetype() bool {
29✔
949
        if q.cache != nil {
36✔
950
                return q.nextTable(q.cache.tables)
7✔
951
        }
7✔
952
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
23✔
953
                return true
1✔
954
        }
1✔
955
        return q.nextArchetype()
21✔
956
}
957

958
func (q *Query5[A, B, C, D, E]) nextArchetype() bool {
21✔
959
        maxArchIndex := len(q.world.storage.archetypes) - 1
21✔
960
        for q.cursor.archetype < maxArchIndex {
50✔
961
                q.cursor.archetype++
29✔
962
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
29✔
963
                if !q.filter.matches(&archetype.mask) {
47✔
964
                        continue
18✔
965
                }
966

967
                if !archetype.HasRelations() {
17✔
968
                        table := &q.world.storage.tables[archetype.tables[0]]
7✔
969
                        if table.Len() > 0 {
14✔
970
                                q.setTable(0, table)
7✔
971
                                return true
7✔
972
                        }
7✔
973
                        continue
×
974
                }
975

976
                q.tables = archetype.GetTables(q.relations)
3✔
977
                q.cursor.table = -1
3✔
978
                if q.nextTable(q.tables) {
6✔
979
                        return true
3✔
980
                }
3✔
981
        }
982
        q.Close()
10✔
983
        return false
10✔
984
}
985

986
func (q *Query5[A, B, C, D, E]) nextTable(tables []tableID) bool {
21✔
987
        maxTableIndex := len(tables) - 1
21✔
988
        for q.cursor.table < maxTableIndex {
33✔
989
                q.cursor.table++
12✔
990
                table := &q.world.storage.tables[tables[q.cursor.table]]
12✔
991
                if table.Len() == 0 {
15✔
992
                        continue
3✔
993
                }
994
                if !table.Matches(q.relations) {
10✔
995
                        continue
1✔
996
                }
997
                q.setTable(q.cursor.table, table)
8✔
998
                return true
8✔
999
        }
1000
        if q.cache != nil {
16✔
1001
                q.Close()
3✔
1002
        }
3✔
1003
        return false
13✔
1004
}
1005

1006
func (q *Query5[A, B, C, D, E]) setTable(index int, table *table) {
15✔
1007
        q.cursor.table = index
15✔
1008
        q.table = table
15✔
1009
        q.columnA = q.components[0].columns[q.table.id]
15✔
1010
        q.columnB = q.components[1].columns[q.table.id]
15✔
1011
        q.columnC = q.components[2].columns[q.table.id]
15✔
1012
        q.columnD = q.components[3].columns[q.table.id]
15✔
1013
        q.columnE = q.components[4].columns[q.table.id]
15✔
1014
        q.cursor.index = 0
15✔
1015
        q.cursor.maxIndex = int64(q.table.Len() - 1)
15✔
1016
}
15✔
1017

1018
// Query6 is a query for 6 components.
1019
// Use a [Filter6] to create one.
1020
//
1021
// Queries are one-time use iterators and must be re-created each time before iterating.
1022
//
1023
// See [Query2] for a usage example.
1024
type Query6[A any, B any, C any, D any, E any, F any] struct {
1025
        world      *World
1026
        filter     *filter
1027
        relations  []RelationID
1028
        lock       uint8
1029
        cursor     cursor
1030
        tables     []tableID
1031
        table      *table
1032
        cache      *cacheEntry
1033
        components []*componentStorage
1034
        columnA    *column
1035
        columnB    *column
1036
        columnC    *column
1037
        columnD    *column
1038
        columnE    *column
1039
        columnF    *column
1040
}
1041

1042
func newQuery6[A any, B any, C any, D any, E any, F any](world *World, filter *filter, ids []ID, relations []RelationID,
1043
        cacheID cacheID, components []*componentStorage) Query6[A, B, C, D, E, F] {
13✔
1044
        var cache *cacheEntry
13✔
1045
        if cacheID != maxCacheID {
16✔
1046
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
1047
        }
3✔
1048

1049
        return Query6[A, B, C, D, E, F]{
13✔
1050
                world:      world,
13✔
1051
                filter:     filter,
13✔
1052
                relations:  relations,
13✔
1053
                cache:      cache,
13✔
1054
                lock:       world.lock(),
13✔
1055
                components: components,
13✔
1056
                cursor: cursor{
13✔
1057
                        archetype: -1,
13✔
1058
                        table:     -1,
13✔
1059
                        index:     0,
13✔
1060
                        maxIndex:  -1,
13✔
1061
                },
13✔
1062
        }
13✔
1063
}
1064

1065
// Next advances the query's cursor to the next entity.
1066
func (q *Query6[A, B, C, D, E, F]) Next() bool {
216✔
1067
        q.world.checkQueryNext(&q.cursor)
216✔
1068
        if int64(q.cursor.index) < q.cursor.maxIndex {
403✔
1069
                q.cursor.index++
187✔
1070
                return true
187✔
1071
        }
187✔
1072
        return q.nextTableOrArchetype()
29✔
1073
}
1074

1075
// Entity returns the current entity.
1076
func (q *Query6[A, B, C, D, E, F]) Entity() Entity {
204✔
1077
        q.world.checkQueryGet(&q.cursor)
204✔
1078
        return q.table.GetEntity(q.cursor.index)
204✔
1079
}
204✔
1080

1081
// Get returns the queried components of the current entity.
1082
//
1083
// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)!
1084
func (q *Query6[A, B, C, D, E, F]) Get() (*A, *B, *C, *D, *E, *F) {
204✔
1085
        q.world.checkQueryGet(&q.cursor)
204✔
1086
        return (*A)(q.columnA.Get(q.cursor.index)),
204✔
1087
                (*B)(q.columnB.Get(q.cursor.index)),
204✔
1088
                (*C)(q.columnC.Get(q.cursor.index)),
204✔
1089
                (*D)(q.columnD.Get(q.cursor.index)),
204✔
1090
                (*E)(q.columnE.Get(q.cursor.index)),
204✔
1091
                (*F)(q.columnF.Get(q.cursor.index))
204✔
1092
}
204✔
1093

1094
// GetRelation returns the entity relation target of the component at the given index.
1095
func (q *Query6[A, B, C, D, E, F]) GetRelation(index int) Entity {
40✔
1096
        return q.components[index].columns[q.table.id].target
40✔
1097
}
40✔
1098

1099
// Count counts the entities matching this query.
1100
//
1101
// Has some overhead of iterating through archetypes.
1102
// However, this is still much faster than manual counting via iteration.
1103
//
1104
// Does not iterate or close the query.
1105
func (q *Query6[A, B, C, D, E, F]) Count() int {
11✔
1106
        if q.cache == nil {
19✔
1107
                return countQuery(&q.world.storage, q.filter, q.relations)
8✔
1108
        }
8✔
1109
        return countQueryCache(&q.world.storage, q.cache, q.relations)
3✔
1110
}
1111

1112
// Close closes the Query and unlocks the world.
1113
//
1114
// Automatically called when iteration completes.
1115
// Needs to be called only if breaking out of the query iteration or not iterating at all.
1116
func (q *Query6[A, B, C, D, E, F]) Close() {
13✔
1117
        q.cursor.archetype = -2
13✔
1118
        q.cursor.table = -2
13✔
1119
        q.tables = nil
13✔
1120
        q.table = nil
13✔
1121
        q.cache = nil
13✔
1122
        q.columnA = nil
13✔
1123
        q.columnB = nil
13✔
1124
        q.columnC = nil
13✔
1125
        q.columnD = nil
13✔
1126
        q.columnE = nil
13✔
1127
        q.columnF = nil
13✔
1128
        q.world.unlock(q.lock)
13✔
1129
}
13✔
1130

1131
func (q *Query6[A, B, C, D, E, F]) nextTableOrArchetype() bool {
29✔
1132
        if q.cache != nil {
36✔
1133
                return q.nextTable(q.cache.tables)
7✔
1134
        }
7✔
1135
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
23✔
1136
                return true
1✔
1137
        }
1✔
1138
        return q.nextArchetype()
21✔
1139
}
1140

1141
func (q *Query6[A, B, C, D, E, F]) nextArchetype() bool {
21✔
1142
        maxArchIndex := len(q.world.storage.archetypes) - 1
21✔
1143
        for q.cursor.archetype < maxArchIndex {
50✔
1144
                q.cursor.archetype++
29✔
1145
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
29✔
1146
                if !q.filter.matches(&archetype.mask) {
47✔
1147
                        continue
18✔
1148
                }
1149

1150
                if !archetype.HasRelations() {
17✔
1151
                        table := &q.world.storage.tables[archetype.tables[0]]
7✔
1152
                        if table.Len() > 0 {
14✔
1153
                                q.setTable(0, table)
7✔
1154
                                return true
7✔
1155
                        }
7✔
1156
                        continue
×
1157
                }
1158

1159
                q.tables = archetype.GetTables(q.relations)
3✔
1160
                q.cursor.table = -1
3✔
1161
                if q.nextTable(q.tables) {
6✔
1162
                        return true
3✔
1163
                }
3✔
1164
        }
1165
        q.Close()
10✔
1166
        return false
10✔
1167
}
1168

1169
func (q *Query6[A, B, C, D, E, F]) nextTable(tables []tableID) bool {
21✔
1170
        maxTableIndex := len(tables) - 1
21✔
1171
        for q.cursor.table < maxTableIndex {
33✔
1172
                q.cursor.table++
12✔
1173
                table := &q.world.storage.tables[tables[q.cursor.table]]
12✔
1174
                if table.Len() == 0 {
15✔
1175
                        continue
3✔
1176
                }
1177
                if !table.Matches(q.relations) {
10✔
1178
                        continue
1✔
1179
                }
1180
                q.setTable(q.cursor.table, table)
8✔
1181
                return true
8✔
1182
        }
1183
        if q.cache != nil {
16✔
1184
                q.Close()
3✔
1185
        }
3✔
1186
        return false
13✔
1187
}
1188

1189
func (q *Query6[A, B, C, D, E, F]) setTable(index int, table *table) {
15✔
1190
        q.cursor.table = index
15✔
1191
        q.table = table
15✔
1192
        q.columnA = q.components[0].columns[q.table.id]
15✔
1193
        q.columnB = q.components[1].columns[q.table.id]
15✔
1194
        q.columnC = q.components[2].columns[q.table.id]
15✔
1195
        q.columnD = q.components[3].columns[q.table.id]
15✔
1196
        q.columnE = q.components[4].columns[q.table.id]
15✔
1197
        q.columnF = q.components[5].columns[q.table.id]
15✔
1198
        q.cursor.index = 0
15✔
1199
        q.cursor.maxIndex = int64(q.table.Len() - 1)
15✔
1200
}
15✔
1201

1202
// Query7 is a query for 7 components.
1203
// Use a [Filter7] to create one.
1204
//
1205
// Queries are one-time use iterators and must be re-created each time before iterating.
1206
//
1207
// See [Query2] for a usage example.
1208
type Query7[A any, B any, C any, D any, E any, F any, G any] struct {
1209
        world      *World
1210
        filter     *filter
1211
        relations  []RelationID
1212
        lock       uint8
1213
        cursor     cursor
1214
        tables     []tableID
1215
        table      *table
1216
        cache      *cacheEntry
1217
        components []*componentStorage
1218
        columnA    *column
1219
        columnB    *column
1220
        columnC    *column
1221
        columnD    *column
1222
        columnE    *column
1223
        columnF    *column
1224
        columnG    *column
1225
}
1226

1227
func newQuery7[A any, B any, C any, D any, E any, F any, G any](world *World, filter *filter, ids []ID, relations []RelationID,
1228
        cacheID cacheID, components []*componentStorage) Query7[A, B, C, D, E, F, G] {
13✔
1229
        var cache *cacheEntry
13✔
1230
        if cacheID != maxCacheID {
16✔
1231
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
1232
        }
3✔
1233

1234
        return Query7[A, B, C, D, E, F, G]{
13✔
1235
                world:      world,
13✔
1236
                filter:     filter,
13✔
1237
                relations:  relations,
13✔
1238
                cache:      cache,
13✔
1239
                lock:       world.lock(),
13✔
1240
                components: components,
13✔
1241
                cursor: cursor{
13✔
1242
                        archetype: -1,
13✔
1243
                        table:     -1,
13✔
1244
                        index:     0,
13✔
1245
                        maxIndex:  -1,
13✔
1246
                },
13✔
1247
        }
13✔
1248
}
1249

1250
// Next advances the query's cursor to the next entity.
1251
func (q *Query7[A, B, C, D, E, F, G]) Next() bool {
216✔
1252
        q.world.checkQueryNext(&q.cursor)
216✔
1253
        if int64(q.cursor.index) < q.cursor.maxIndex {
403✔
1254
                q.cursor.index++
187✔
1255
                return true
187✔
1256
        }
187✔
1257
        return q.nextTableOrArchetype()
29✔
1258
}
1259

1260
// Entity returns the current entity.
1261
func (q *Query7[A, B, C, D, E, F, G]) Entity() Entity {
204✔
1262
        q.world.checkQueryGet(&q.cursor)
204✔
1263
        return q.table.GetEntity(q.cursor.index)
204✔
1264
}
204✔
1265

1266
// Get returns the queried components of the current entity.
1267
//
1268
// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)!
1269
func (q *Query7[A, B, C, D, E, F, G]) Get() (*A, *B, *C, *D, *E, *F, *G) {
204✔
1270
        q.world.checkQueryGet(&q.cursor)
204✔
1271
        return (*A)(q.columnA.Get(q.cursor.index)),
204✔
1272
                (*B)(q.columnB.Get(q.cursor.index)),
204✔
1273
                (*C)(q.columnC.Get(q.cursor.index)),
204✔
1274
                (*D)(q.columnD.Get(q.cursor.index)),
204✔
1275
                (*E)(q.columnE.Get(q.cursor.index)),
204✔
1276
                (*F)(q.columnF.Get(q.cursor.index)),
204✔
1277
                (*G)(q.columnG.Get(q.cursor.index))
204✔
1278
}
204✔
1279

1280
// GetRelation returns the entity relation target of the component at the given index.
1281
func (q *Query7[A, B, C, D, E, F, G]) GetRelation(index int) Entity {
40✔
1282
        return q.components[index].columns[q.table.id].target
40✔
1283
}
40✔
1284

1285
// Count counts the entities matching this query.
1286
//
1287
// Has some overhead of iterating through archetypes.
1288
// However, this is still much faster than manual counting via iteration.
1289
//
1290
// Does not iterate or close the query.
1291
func (q *Query7[A, B, C, D, E, F, G]) Count() int {
11✔
1292
        if q.cache == nil {
19✔
1293
                return countQuery(&q.world.storage, q.filter, q.relations)
8✔
1294
        }
8✔
1295
        return countQueryCache(&q.world.storage, q.cache, q.relations)
3✔
1296
}
1297

1298
// Close closes the Query and unlocks the world.
1299
//
1300
// Automatically called when iteration completes.
1301
// Needs to be called only if breaking out of the query iteration or not iterating at all.
1302
func (q *Query7[A, B, C, D, E, F, G]) Close() {
13✔
1303
        q.cursor.archetype = -2
13✔
1304
        q.cursor.table = -2
13✔
1305
        q.tables = nil
13✔
1306
        q.table = nil
13✔
1307
        q.cache = nil
13✔
1308
        q.columnA = nil
13✔
1309
        q.columnB = nil
13✔
1310
        q.columnC = nil
13✔
1311
        q.columnD = nil
13✔
1312
        q.columnE = nil
13✔
1313
        q.columnF = nil
13✔
1314
        q.columnG = nil
13✔
1315
        q.world.unlock(q.lock)
13✔
1316
}
13✔
1317

1318
func (q *Query7[A, B, C, D, E, F, G]) nextTableOrArchetype() bool {
29✔
1319
        if q.cache != nil {
36✔
1320
                return q.nextTable(q.cache.tables)
7✔
1321
        }
7✔
1322
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
23✔
1323
                return true
1✔
1324
        }
1✔
1325
        return q.nextArchetype()
21✔
1326
}
1327

1328
func (q *Query7[A, B, C, D, E, F, G]) nextArchetype() bool {
21✔
1329
        maxArchIndex := len(q.world.storage.archetypes) - 1
21✔
1330
        for q.cursor.archetype < maxArchIndex {
50✔
1331
                q.cursor.archetype++
29✔
1332
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
29✔
1333
                if !q.filter.matches(&archetype.mask) {
47✔
1334
                        continue
18✔
1335
                }
1336

1337
                if !archetype.HasRelations() {
17✔
1338
                        table := &q.world.storage.tables[archetype.tables[0]]
7✔
1339
                        if table.Len() > 0 {
14✔
1340
                                q.setTable(0, table)
7✔
1341
                                return true
7✔
1342
                        }
7✔
1343
                        continue
×
1344
                }
1345

1346
                q.tables = archetype.GetTables(q.relations)
3✔
1347
                q.cursor.table = -1
3✔
1348
                if q.nextTable(q.tables) {
6✔
1349
                        return true
3✔
1350
                }
3✔
1351
        }
1352
        q.Close()
10✔
1353
        return false
10✔
1354
}
1355

1356
func (q *Query7[A, B, C, D, E, F, G]) nextTable(tables []tableID) bool {
21✔
1357
        maxTableIndex := len(tables) - 1
21✔
1358
        for q.cursor.table < maxTableIndex {
33✔
1359
                q.cursor.table++
12✔
1360
                table := &q.world.storage.tables[tables[q.cursor.table]]
12✔
1361
                if table.Len() == 0 {
15✔
1362
                        continue
3✔
1363
                }
1364
                if !table.Matches(q.relations) {
10✔
1365
                        continue
1✔
1366
                }
1367
                q.setTable(q.cursor.table, table)
8✔
1368
                return true
8✔
1369
        }
1370
        if q.cache != nil {
16✔
1371
                q.Close()
3✔
1372
        }
3✔
1373
        return false
13✔
1374
}
1375

1376
func (q *Query7[A, B, C, D, E, F, G]) setTable(index int, table *table) {
15✔
1377
        q.cursor.table = index
15✔
1378
        q.table = table
15✔
1379
        q.columnA = q.components[0].columns[q.table.id]
15✔
1380
        q.columnB = q.components[1].columns[q.table.id]
15✔
1381
        q.columnC = q.components[2].columns[q.table.id]
15✔
1382
        q.columnD = q.components[3].columns[q.table.id]
15✔
1383
        q.columnE = q.components[4].columns[q.table.id]
15✔
1384
        q.columnF = q.components[5].columns[q.table.id]
15✔
1385
        q.columnG = q.components[6].columns[q.table.id]
15✔
1386
        q.cursor.index = 0
15✔
1387
        q.cursor.maxIndex = int64(q.table.Len() - 1)
15✔
1388
}
15✔
1389

1390
// Query8 is a query for 8 components.
1391
// Use a [Filter8] to create one.
1392
//
1393
// Queries are one-time use iterators and must be re-created each time before iterating.
1394
//
1395
// See [Query2] for a usage example.
1396
type Query8[A any, B any, C any, D any, E any, F any, G any, H any] struct {
1397
        world      *World
1398
        filter     *filter
1399
        relations  []RelationID
1400
        lock       uint8
1401
        cursor     cursor
1402
        tables     []tableID
1403
        table      *table
1404
        cache      *cacheEntry
1405
        components []*componentStorage
1406
        columnA    *column
1407
        columnB    *column
1408
        columnC    *column
1409
        columnD    *column
1410
        columnE    *column
1411
        columnF    *column
1412
        columnG    *column
1413
        columnH    *column
1414
}
1415

1416
func newQuery8[A any, B any, C any, D any, E any, F any, G any, H any](world *World, filter *filter, ids []ID, relations []RelationID,
1417
        cacheID cacheID, components []*componentStorage) Query8[A, B, C, D, E, F, G, H] {
13✔
1418
        var cache *cacheEntry
13✔
1419
        if cacheID != maxCacheID {
16✔
1420
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
1421
        }
3✔
1422

1423
        return Query8[A, B, C, D, E, F, G, H]{
13✔
1424
                world:      world,
13✔
1425
                filter:     filter,
13✔
1426
                relations:  relations,
13✔
1427
                cache:      cache,
13✔
1428
                lock:       world.lock(),
13✔
1429
                components: components,
13✔
1430
                cursor: cursor{
13✔
1431
                        archetype: -1,
13✔
1432
                        table:     -1,
13✔
1433
                        index:     0,
13✔
1434
                        maxIndex:  -1,
13✔
1435
                },
13✔
1436
        }
13✔
1437
}
1438

1439
// Next advances the query's cursor to the next entity.
1440
func (q *Query8[A, B, C, D, E, F, G, H]) Next() bool {
216✔
1441
        q.world.checkQueryNext(&q.cursor)
216✔
1442
        if int64(q.cursor.index) < q.cursor.maxIndex {
403✔
1443
                q.cursor.index++
187✔
1444
                return true
187✔
1445
        }
187✔
1446
        return q.nextTableOrArchetype()
29✔
1447
}
1448

1449
// Entity returns the current entity.
1450
func (q *Query8[A, B, C, D, E, F, G, H]) Entity() Entity {
204✔
1451
        q.world.checkQueryGet(&q.cursor)
204✔
1452
        return q.table.GetEntity(q.cursor.index)
204✔
1453
}
204✔
1454

1455
// Get returns the queried components of the current entity.
1456
//
1457
// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)!
1458
func (q *Query8[A, B, C, D, E, F, G, H]) Get() (*A, *B, *C, *D, *E, *F, *G, *H) {
204✔
1459
        q.world.checkQueryGet(&q.cursor)
204✔
1460
        return (*A)(q.columnA.Get(q.cursor.index)),
204✔
1461
                (*B)(q.columnB.Get(q.cursor.index)),
204✔
1462
                (*C)(q.columnC.Get(q.cursor.index)),
204✔
1463
                (*D)(q.columnD.Get(q.cursor.index)),
204✔
1464
                (*E)(q.columnE.Get(q.cursor.index)),
204✔
1465
                (*F)(q.columnF.Get(q.cursor.index)),
204✔
1466
                (*G)(q.columnG.Get(q.cursor.index)),
204✔
1467
                (*H)(q.columnH.Get(q.cursor.index))
204✔
1468
}
204✔
1469

1470
// GetRelation returns the entity relation target of the component at the given index.
1471
func (q *Query8[A, B, C, D, E, F, G, H]) GetRelation(index int) Entity {
40✔
1472
        return q.components[index].columns[q.table.id].target
40✔
1473
}
40✔
1474

1475
// Count counts the entities matching this query.
1476
//
1477
// Has some overhead of iterating through archetypes.
1478
// However, this is still much faster than manual counting via iteration.
1479
//
1480
// Does not iterate or close the query.
1481
func (q *Query8[A, B, C, D, E, F, G, H]) Count() int {
11✔
1482
        if q.cache == nil {
19✔
1483
                return countQuery(&q.world.storage, q.filter, q.relations)
8✔
1484
        }
8✔
1485
        return countQueryCache(&q.world.storage, q.cache, q.relations)
3✔
1486
}
1487

1488
// Close closes the Query and unlocks the world.
1489
//
1490
// Automatically called when iteration completes.
1491
// Needs to be called only if breaking out of the query iteration or not iterating at all.
1492
func (q *Query8[A, B, C, D, E, F, G, H]) Close() {
13✔
1493
        q.cursor.archetype = -2
13✔
1494
        q.cursor.table = -2
13✔
1495
        q.tables = nil
13✔
1496
        q.table = nil
13✔
1497
        q.cache = nil
13✔
1498
        q.columnA = nil
13✔
1499
        q.columnB = nil
13✔
1500
        q.columnC = nil
13✔
1501
        q.columnD = nil
13✔
1502
        q.columnE = nil
13✔
1503
        q.columnF = nil
13✔
1504
        q.columnG = nil
13✔
1505
        q.columnH = nil
13✔
1506
        q.world.unlock(q.lock)
13✔
1507
}
13✔
1508

1509
func (q *Query8[A, B, C, D, E, F, G, H]) nextTableOrArchetype() bool {
29✔
1510
        if q.cache != nil {
36✔
1511
                return q.nextTable(q.cache.tables)
7✔
1512
        }
7✔
1513
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
23✔
1514
                return true
1✔
1515
        }
1✔
1516
        return q.nextArchetype()
21✔
1517
}
1518

1519
func (q *Query8[A, B, C, D, E, F, G, H]) nextArchetype() bool {
21✔
1520
        maxArchIndex := len(q.world.storage.archetypes) - 1
21✔
1521
        for q.cursor.archetype < maxArchIndex {
50✔
1522
                q.cursor.archetype++
29✔
1523
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
29✔
1524
                if !q.filter.matches(&archetype.mask) {
47✔
1525
                        continue
18✔
1526
                }
1527

1528
                if !archetype.HasRelations() {
17✔
1529
                        table := &q.world.storage.tables[archetype.tables[0]]
7✔
1530
                        if table.Len() > 0 {
14✔
1531
                                q.setTable(0, table)
7✔
1532
                                return true
7✔
1533
                        }
7✔
1534
                        continue
×
1535
                }
1536

1537
                q.tables = archetype.GetTables(q.relations)
3✔
1538
                q.cursor.table = -1
3✔
1539
                if q.nextTable(q.tables) {
6✔
1540
                        return true
3✔
1541
                }
3✔
1542
        }
1543
        q.Close()
10✔
1544
        return false
10✔
1545
}
1546

1547
func (q *Query8[A, B, C, D, E, F, G, H]) nextTable(tables []tableID) bool {
21✔
1548
        maxTableIndex := len(tables) - 1
21✔
1549
        for q.cursor.table < maxTableIndex {
33✔
1550
                q.cursor.table++
12✔
1551
                table := &q.world.storage.tables[tables[q.cursor.table]]
12✔
1552
                if table.Len() == 0 {
15✔
1553
                        continue
3✔
1554
                }
1555
                if !table.Matches(q.relations) {
10✔
1556
                        continue
1✔
1557
                }
1558
                q.setTable(q.cursor.table, table)
8✔
1559
                return true
8✔
1560
        }
1561
        if q.cache != nil {
16✔
1562
                q.Close()
3✔
1563
        }
3✔
1564
        return false
13✔
1565
}
1566

1567
func (q *Query8[A, B, C, D, E, F, G, H]) setTable(index int, table *table) {
15✔
1568
        q.cursor.table = index
15✔
1569
        q.table = table
15✔
1570
        q.columnA = q.components[0].columns[q.table.id]
15✔
1571
        q.columnB = q.components[1].columns[q.table.id]
15✔
1572
        q.columnC = q.components[2].columns[q.table.id]
15✔
1573
        q.columnD = q.components[3].columns[q.table.id]
15✔
1574
        q.columnE = q.components[4].columns[q.table.id]
15✔
1575
        q.columnF = q.components[5].columns[q.table.id]
15✔
1576
        q.columnG = q.components[6].columns[q.table.id]
15✔
1577
        q.columnH = q.components[7].columns[q.table.id]
15✔
1578
        q.cursor.index = 0
15✔
1579
        q.cursor.maxIndex = int64(q.table.Len() - 1)
15✔
1580
}
15✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc