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

mlange-42 / ark / 13742253133

08 Mar 2025 10:59PM CUT coverage: 99.43%. Remained the same
13742253133

push

github

web-flow
Update CHANGELOG for v0.3.0 release (#166)

6456 of 6493 relevant lines covered (99.43%)

28632.4 hits per line

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

99.05
/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
// Close closes the Query and unlocks the world.
70
//
71
// Automatically called when iteration completes.
72
// Needs to be called only if breaking out of the query iteration or not iterating at all.
73
func (q *Query0) Close() {
10✔
74
        q.cursor.archetype = -2
10✔
75
        q.cursor.table = -2
10✔
76
        q.tables = nil
10✔
77
        q.table = nil
10✔
78
        q.cache = nil
10✔
79
        q.world.unlock(q.lock)
10✔
80
}
10✔
81

82
func (q *Query0) nextTableOrArchetype() bool {
26✔
83
        if q.cache != nil {
31✔
84
                return q.nextTable(q.cache.tables)
5✔
85
        }
5✔
86
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
23✔
87
                return true
2✔
88
        }
2✔
89
        return q.nextArchetype()
19✔
90
}
91

92
func (q *Query0) nextArchetype() bool {
19✔
93
        maxArchIndex := len(q.world.storage.archetypes) - 1
19✔
94
        for q.cursor.archetype < maxArchIndex {
40✔
95
                q.cursor.archetype++
21✔
96
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
21✔
97
                if !q.filter.matches(&archetype.mask) {
25✔
98
                        continue
4✔
99
                }
100

101
                if !archetype.HasRelations() {
31✔
102
                        table := &q.world.storage.tables[archetype.tables[0]]
15✔
103
                        if table.Len() > 0 {
23✔
104
                                q.setTable(0, table)
8✔
105
                                return true
8✔
106
                        }
8✔
107
                        continue
7✔
108
                }
109

110
                q.tables = archetype.GetTables(q.relations)
1✔
111
                q.cursor.table = -1
1✔
112
                if q.nextTable(q.tables) {
2✔
113
                        return true
1✔
114
                }
1✔
115
        }
116
        q.Close()
9✔
117
        return false
9✔
118
}
119

120
func (q *Query0) nextTable(tables []tableID) bool {
17✔
121
        maxTableIndex := len(tables) - 1
17✔
122
        for q.cursor.table < maxTableIndex {
24✔
123
                q.cursor.table++
7✔
124
                table := &q.world.storage.tables[tables[q.cursor.table]]
7✔
125
                if table.Len() == 0 {
7✔
126
                        continue
×
127
                }
128
                if !table.Matches(q.relations) {
7✔
129
                        continue
×
130
                }
131
                q.setTable(q.cursor.table, table)
7✔
132
                return true
7✔
133
        }
134
        if q.cache != nil {
11✔
135
                q.Close()
1✔
136
        }
1✔
137
        return false
10✔
138
}
139

140
func (q *Query0) setTable(index int, table *table) {
15✔
141
        q.cursor.table = index
15✔
142
        q.table = table
15✔
143
        q.cursor.index = 0
15✔
144
        q.cursor.maxIndex = int64(q.table.Len() - 1)
15✔
145
}
15✔
146

147
// Query1 is a query for 1 components.
148
// Use a [Filter1] to create one.
149
//
150
// Queries are one-time use iterators and must be re-created each time before iterating.
151
//
152
// See [Query2] for a usage example.
153
type Query1[A any] struct {
154
        world      *World
155
        filter     *filter
156
        relations  []RelationID
157
        lock       uint8
158
        cursor     cursor
159
        tables     []tableID
160
        table      *table
161
        cache      *cacheEntry
162
        components []*componentStorage
163
        columnA    *column
164
}
165

166
func newQuery1[A any](world *World, filter *filter, ids []ID, relations []RelationID,
167
        cacheID cacheID, components []*componentStorage) Query1[A] {
1,118✔
168
        var cache *cacheEntry
1,118✔
169
        if cacheID != maxCacheID {
1,121✔
170
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
171
        }
3✔
172

173
        return Query1[A]{
1,118✔
174
                world:      world,
1,118✔
175
                filter:     filter,
1,118✔
176
                relations:  relations,
1,118✔
177
                cache:      cache,
1,118✔
178
                lock:       world.lock(),
1,118✔
179
                components: components,
1,118✔
180
                cursor: cursor{
1,118✔
181
                        archetype: -1,
1,118✔
182
                        table:     -1,
1,118✔
183
                        index:     0,
1,118✔
184
                        maxIndex:  -1,
1,118✔
185
                },
1,118✔
186
        }
1,118✔
187
}
188

189
// Next advances the query's cursor to the next entity.
190
func (q *Query1[A]) Next() bool {
1,058,546✔
191
        q.world.checkQueryNext(&q.cursor)
1,058,546✔
192
        if int64(q.cursor.index) < q.cursor.maxIndex {
2,114,846✔
193
                q.cursor.index++
1,056,300✔
194
                return true
1,056,300✔
195
        }
1,056,300✔
196
        return q.nextTableOrArchetype()
2,246✔
197
}
198

199
// Entity returns the current entity.
200
func (q *Query1[A]) Entity() Entity {
2,112,948✔
201
        q.world.checkQueryGet(&q.cursor)
2,112,948✔
202
        return q.table.GetEntity(q.cursor.index)
2,112,948✔
203
}
2,112,948✔
204

205
// Get returns the queried components of the current entity.
206
//
207
// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)!
208
func (q *Query1[A]) Get() *A {
1,056,611✔
209
        q.world.checkQueryGet(&q.cursor)
1,056,611✔
210
        return (*A)(q.columnA.Get(q.cursor.index))
1,056,611✔
211
}
1,056,611✔
212

213
// GetRelation returns the entity relation target of the component at the given index.
214
func (q *Query1[A]) GetRelation(index int) Entity {
42✔
215
        return q.components[index].columns[q.table.id].target
42✔
216
}
42✔
217

218
// Close closes the Query and unlocks the world.
219
//
220
// Automatically called when iteration completes.
221
// Needs to be called only if breaking out of the query iteration or not iterating at all.
222
func (q *Query1[A]) Close() {
1,118✔
223
        q.cursor.archetype = -2
1,118✔
224
        q.cursor.table = -2
1,118✔
225
        q.tables = nil
1,118✔
226
        q.table = nil
1,118✔
227
        q.cache = nil
1,118✔
228
        q.columnA = nil
1,118✔
229
        q.world.unlock(q.lock)
1,118✔
230
}
1,118✔
231

232
func (q *Query1[A]) nextTableOrArchetype() bool {
2,246✔
233
        if q.cache != nil {
2,253✔
234
                return q.nextTable(q.cache.tables)
7✔
235
        }
7✔
236
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
2,240✔
237
                return true
1✔
238
        }
1✔
239
        return q.nextArchetype()
2,238✔
240
}
241

242
func (q *Query1[A]) nextArchetype() bool {
2,238✔
243
        maxArchIndex := len(q.world.storage.archetypes) - 1
2,238✔
244
        for q.cursor.archetype < maxArchIndex {
4,753✔
245
                q.cursor.archetype++
2,515✔
246
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
2,515✔
247
                if !q.filter.matches(&archetype.mask) {
3,830✔
248
                        continue
1,315✔
249
                }
250

251
                if !archetype.HasRelations() {
2,376✔
252
                        table := &q.world.storage.tables[archetype.tables[0]]
1,177✔
253
                        if table.Len() > 0 {
2,286✔
254
                                q.setTable(0, table)
1,109✔
255
                                return true
1,109✔
256
                        }
1,109✔
257
                        continue
68✔
258
                }
259

260
                q.tables = archetype.GetTables(q.relations)
22✔
261
                q.cursor.table = -1
22✔
262
                if q.nextTable(q.tables) {
35✔
263
                        return true
13✔
264
                }
13✔
265
        }
266
        q.Close()
1,115✔
267
        return false
1,115✔
268
}
269

270
func (q *Query1[A]) nextTable(tables []tableID) bool {
1,152✔
271
        maxTableIndex := len(tables) - 1
1,152✔
272
        for q.cursor.table < maxTableIndex {
1,183✔
273
                q.cursor.table++
31✔
274
                table := &q.world.storage.tables[tables[q.cursor.table]]
31✔
275
                if table.Len() == 0 {
43✔
276
                        continue
12✔
277
                }
278
                if !table.Matches(q.relations) {
20✔
279
                        continue
1✔
280
                }
281
                q.setTable(q.cursor.table, table)
18✔
282
                return true
18✔
283
        }
284
        if q.cache != nil {
1,137✔
285
                q.Close()
3✔
286
        }
3✔
287
        return false
1,134✔
288
}
289

290
func (q *Query1[A]) setTable(index int, table *table) {
1,127✔
291
        q.cursor.table = index
1,127✔
292
        q.table = table
1,127✔
293
        q.columnA = q.components[0].columns[q.table.id]
1,127✔
294
        q.cursor.index = 0
1,127✔
295
        q.cursor.maxIndex = int64(q.table.Len() - 1)
1,127✔
296
}
1,127✔
297

298
// Query2 is a query for 2 components.
299
// Use a [Filter2] to create one.
300
//
301
// Queries are one-time use iterators and must be re-created each time before iterating.
302
type Query2[A any, B any] struct {
303
        world      *World
304
        filter     *filter
305
        relations  []RelationID
306
        lock       uint8
307
        cursor     cursor
308
        tables     []tableID
309
        table      *table
310
        cache      *cacheEntry
311
        components []*componentStorage
312
        columnA    *column
313
        columnB    *column
314
}
315

316
func newQuery2[A any, B any](world *World, filter *filter, ids []ID, relations []RelationID,
317
        cacheID cacheID, components []*componentStorage) Query2[A, B] {
16✔
318
        var cache *cacheEntry
16✔
319
        if cacheID != maxCacheID {
19✔
320
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
321
        }
3✔
322

323
        return Query2[A, B]{
16✔
324
                world:      world,
16✔
325
                filter:     filter,
16✔
326
                relations:  relations,
16✔
327
                cache:      cache,
16✔
328
                lock:       world.lock(),
16✔
329
                components: components,
16✔
330
                cursor: cursor{
16✔
331
                        archetype: -1,
16✔
332
                        table:     -1,
16✔
333
                        index:     0,
16✔
334
                        maxIndex:  -1,
16✔
335
                },
16✔
336
        }
16✔
337
}
338

339
// Next advances the query's cursor to the next entity.
340
func (q *Query2[A, B]) Next() bool {
251✔
341
        q.world.checkQueryNext(&q.cursor)
251✔
342
        if int64(q.cursor.index) < q.cursor.maxIndex {
469✔
343
                q.cursor.index++
218✔
344
                return true
218✔
345
        }
218✔
346
        return q.nextTableOrArchetype()
33✔
347
}
348

349
// Entity returns the current entity.
350
func (q *Query2[A, B]) Entity() Entity {
204✔
351
        q.world.checkQueryGet(&q.cursor)
204✔
352
        return q.table.GetEntity(q.cursor.index)
204✔
353
}
204✔
354

355
// Get returns the queried components of the current entity.
356
//
357
// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)!
358
func (q *Query2[A, B]) Get() (*A, *B) {
236✔
359
        q.world.checkQueryGet(&q.cursor)
236✔
360
        return (*A)(q.columnA.Get(q.cursor.index)),
236✔
361
                (*B)(q.columnB.Get(q.cursor.index))
236✔
362
}
236✔
363

364
// GetRelation returns the entity relation target of the component at the given index.
365
func (q *Query2[A, B]) GetRelation(index int) Entity {
40✔
366
        return q.components[index].columns[q.table.id].target
40✔
367
}
40✔
368

369
// Close closes the Query and unlocks the world.
370
//
371
// Automatically called when iteration completes.
372
// Needs to be called only if breaking out of the query iteration or not iterating at all.
373
func (q *Query2[A, B]) Close() {
16✔
374
        q.cursor.archetype = -2
16✔
375
        q.cursor.table = -2
16✔
376
        q.tables = nil
16✔
377
        q.table = nil
16✔
378
        q.cache = nil
16✔
379
        q.columnA = nil
16✔
380
        q.columnB = nil
16✔
381
        q.world.unlock(q.lock)
16✔
382
}
16✔
383

384
func (q *Query2[A, B]) nextTableOrArchetype() bool {
33✔
385
        if q.cache != nil {
40✔
386
                return q.nextTable(q.cache.tables)
7✔
387
        }
7✔
388
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
27✔
389
                return true
1✔
390
        }
1✔
391
        return q.nextArchetype()
25✔
392
}
393

394
func (q *Query2[A, B]) nextArchetype() bool {
25✔
395
        maxArchIndex := len(q.world.storage.archetypes) - 1
25✔
396
        for q.cursor.archetype < maxArchIndex {
58✔
397
                q.cursor.archetype++
33✔
398
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
33✔
399
                if !q.filter.matches(&archetype.mask) {
54✔
400
                        continue
21✔
401
                }
402

403
                if !archetype.HasRelations() {
18✔
404
                        table := &q.world.storage.tables[archetype.tables[0]]
7✔
405
                        if table.Len() > 0 {
14✔
406
                                q.setTable(0, table)
7✔
407
                                return true
7✔
408
                        }
7✔
409
                        continue
×
410
                }
411

412
                q.tables = archetype.GetTables(q.relations)
4✔
413
                q.cursor.table = -1
4✔
414
                if q.nextTable(q.tables) {
8✔
415
                        return true
4✔
416
                }
4✔
417
        }
418
        q.Close()
13✔
419
        return false
13✔
420
}
421

422
func (q *Query2[A, B]) nextTable(tables []tableID) bool {
23✔
423
        maxTableIndex := len(tables) - 1
23✔
424
        for q.cursor.table < maxTableIndex {
36✔
425
                q.cursor.table++
13✔
426
                table := &q.world.storage.tables[tables[q.cursor.table]]
13✔
427
                if table.Len() == 0 {
16✔
428
                        continue
3✔
429
                }
430
                if !table.Matches(q.relations) {
11✔
431
                        continue
1✔
432
                }
433
                q.setTable(q.cursor.table, table)
9✔
434
                return true
9✔
435
        }
436
        if q.cache != nil {
17✔
437
                q.Close()
3✔
438
        }
3✔
439
        return false
14✔
440
}
441

442
func (q *Query2[A, B]) setTable(index int, table *table) {
16✔
443
        q.cursor.table = index
16✔
444
        q.table = table
16✔
445
        q.columnA = q.components[0].columns[q.table.id]
16✔
446
        q.columnB = q.components[1].columns[q.table.id]
16✔
447
        q.cursor.index = 0
16✔
448
        q.cursor.maxIndex = int64(q.table.Len() - 1)
16✔
449
}
16✔
450

451
// Query3 is a query for 3 components.
452
// Use a [Filter3] to create one.
453
//
454
// Queries are one-time use iterators and must be re-created each time before iterating.
455
//
456
// See [Query2] for a usage example.
457
type Query3[A any, B any, C any] struct {
458
        world      *World
459
        filter     *filter
460
        relations  []RelationID
461
        lock       uint8
462
        cursor     cursor
463
        tables     []tableID
464
        table      *table
465
        cache      *cacheEntry
466
        components []*componentStorage
467
        columnA    *column
468
        columnB    *column
469
        columnC    *column
470
}
471

472
func newQuery3[A any, B any, C any](world *World, filter *filter, ids []ID, relations []RelationID,
473
        cacheID cacheID, components []*componentStorage) Query3[A, B, C] {
16✔
474
        var cache *cacheEntry
16✔
475
        if cacheID != maxCacheID {
19✔
476
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
477
        }
3✔
478

479
        return Query3[A, B, C]{
16✔
480
                world:      world,
16✔
481
                filter:     filter,
16✔
482
                relations:  relations,
16✔
483
                cache:      cache,
16✔
484
                lock:       world.lock(),
16✔
485
                components: components,
16✔
486
                cursor: cursor{
16✔
487
                        archetype: -1,
16✔
488
                        table:     -1,
16✔
489
                        index:     0,
16✔
490
                        maxIndex:  -1,
16✔
491
                },
16✔
492
        }
16✔
493
}
494

495
// Next advances the query's cursor to the next entity.
496
func (q *Query3[A, B, C]) Next() bool {
289✔
497
        q.world.checkQueryNext(&q.cursor)
289✔
498
        if int64(q.cursor.index) < q.cursor.maxIndex {
539✔
499
                q.cursor.index++
250✔
500
                return true
250✔
501
        }
250✔
502
        return q.nextTableOrArchetype()
39✔
503
}
504

505
// Entity returns the current entity.
506
func (q *Query3[A, B, C]) Entity() Entity {
204✔
507
        q.world.checkQueryGet(&q.cursor)
204✔
508
        return q.table.GetEntity(q.cursor.index)
204✔
509
}
204✔
510

511
// Get returns the queried components of the current entity.
512
//
513
// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)!
514
func (q *Query3[A, B, C]) Get() (*A, *B, *C) {
204✔
515
        q.world.checkQueryGet(&q.cursor)
204✔
516
        return (*A)(q.columnA.Get(q.cursor.index)),
204✔
517
                (*B)(q.columnB.Get(q.cursor.index)),
204✔
518
                (*C)(q.columnC.Get(q.cursor.index))
204✔
519
}
204✔
520

521
// GetRelation returns the entity relation target of the component at the given index.
522
func (q *Query3[A, B, C]) GetRelation(index int) Entity {
40✔
523
        return q.components[index].columns[q.table.id].target
40✔
524
}
40✔
525

526
// Close closes the Query and unlocks the world.
527
//
528
// Automatically called when iteration completes.
529
// Needs to be called only if breaking out of the query iteration or not iterating at all.
530
func (q *Query3[A, B, C]) Close() {
16✔
531
        q.cursor.archetype = -2
16✔
532
        q.cursor.table = -2
16✔
533
        q.tables = nil
16✔
534
        q.table = nil
16✔
535
        q.cache = nil
16✔
536
        q.columnA = nil
16✔
537
        q.columnB = nil
16✔
538
        q.columnC = nil
16✔
539
        q.world.unlock(q.lock)
16✔
540
}
16✔
541

542
func (q *Query3[A, B, C]) nextTableOrArchetype() bool {
39✔
543
        if q.cache != nil {
46✔
544
                return q.nextTable(q.cache.tables)
7✔
545
        }
7✔
546
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
37✔
547
                return true
5✔
548
        }
5✔
549
        return q.nextArchetype()
27✔
550
}
551

552
func (q *Query3[A, B, C]) nextArchetype() bool {
27✔
553
        maxArchIndex := len(q.world.storage.archetypes) - 1
27✔
554
        for q.cursor.archetype < maxArchIndex {
62✔
555
                q.cursor.archetype++
35✔
556
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
35✔
557
                if !q.filter.matches(&archetype.mask) {
56✔
558
                        continue
21✔
559
                }
560

561
                if !archetype.HasRelations() {
20✔
562
                        table := &q.world.storage.tables[archetype.tables[0]]
7✔
563
                        if table.Len() > 0 {
14✔
564
                                q.setTable(0, table)
7✔
565
                                return true
7✔
566
                        }
7✔
567
                        continue
×
568
                }
569

570
                q.tables = archetype.GetTables(q.relations)
6✔
571
                q.cursor.table = -1
6✔
572
                if q.nextTable(q.tables) {
12✔
573
                        return true
6✔
574
                }
6✔
575
        }
576
        q.Close()
13✔
577
        return false
13✔
578
}
579

580
func (q *Query3[A, B, C]) nextTable(tables []tableID) bool {
31✔
581
        maxTableIndex := len(tables) - 1
31✔
582
        for q.cursor.table < maxTableIndex {
51✔
583
                q.cursor.table++
20✔
584
                table := &q.world.storage.tables[tables[q.cursor.table]]
20✔
585
                if table.Len() == 0 {
23✔
586
                        continue
3✔
587
                }
588
                if !table.Matches(q.relations) {
19✔
589
                        continue
2✔
590
                }
591
                q.setTable(q.cursor.table, table)
15✔
592
                return true
15✔
593
        }
594
        if q.cache != nil {
19✔
595
                q.Close()
3✔
596
        }
3✔
597
        return false
16✔
598
}
599

600
func (q *Query3[A, B, C]) setTable(index int, table *table) {
22✔
601
        q.cursor.table = index
22✔
602
        q.table = table
22✔
603
        q.columnA = q.components[0].columns[q.table.id]
22✔
604
        q.columnB = q.components[1].columns[q.table.id]
22✔
605
        q.columnC = q.components[2].columns[q.table.id]
22✔
606
        q.cursor.index = 0
22✔
607
        q.cursor.maxIndex = int64(q.table.Len() - 1)
22✔
608
}
22✔
609

610
// Query4 is a query for 4 components.
611
// Use a [Filter4] to create one.
612
//
613
// Queries are one-time use iterators and must be re-created each time before iterating.
614
//
615
// See [Query2] for a usage example.
616
type Query4[A any, B any, C any, D any] struct {
617
        world      *World
618
        filter     *filter
619
        relations  []RelationID
620
        lock       uint8
621
        cursor     cursor
622
        tables     []tableID
623
        table      *table
624
        cache      *cacheEntry
625
        components []*componentStorage
626
        columnA    *column
627
        columnB    *column
628
        columnC    *column
629
        columnD    *column
630
}
631

632
func newQuery4[A any, B any, C any, D any](world *World, filter *filter, ids []ID, relations []RelationID,
633
        cacheID cacheID, components []*componentStorage) Query4[A, B, C, D] {
13✔
634
        var cache *cacheEntry
13✔
635
        if cacheID != maxCacheID {
16✔
636
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
637
        }
3✔
638

639
        return Query4[A, B, C, D]{
13✔
640
                world:      world,
13✔
641
                filter:     filter,
13✔
642
                relations:  relations,
13✔
643
                cache:      cache,
13✔
644
                lock:       world.lock(),
13✔
645
                components: components,
13✔
646
                cursor: cursor{
13✔
647
                        archetype: -1,
13✔
648
                        table:     -1,
13✔
649
                        index:     0,
13✔
650
                        maxIndex:  -1,
13✔
651
                },
13✔
652
        }
13✔
653
}
654

655
// Next advances the query's cursor to the next entity.
656
func (q *Query4[A, B, C, D]) Next() bool {
216✔
657
        q.world.checkQueryNext(&q.cursor)
216✔
658
        if int64(q.cursor.index) < q.cursor.maxIndex {
403✔
659
                q.cursor.index++
187✔
660
                return true
187✔
661
        }
187✔
662
        return q.nextTableOrArchetype()
29✔
663
}
664

665
// Entity returns the current entity.
666
func (q *Query4[A, B, C, D]) Entity() Entity {
204✔
667
        q.world.checkQueryGet(&q.cursor)
204✔
668
        return q.table.GetEntity(q.cursor.index)
204✔
669
}
204✔
670

671
// Get returns the queried components of the current entity.
672
//
673
// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)!
674
func (q *Query4[A, B, C, D]) Get() (*A, *B, *C, *D) {
204✔
675
        q.world.checkQueryGet(&q.cursor)
204✔
676
        return (*A)(q.columnA.Get(q.cursor.index)),
204✔
677
                (*B)(q.columnB.Get(q.cursor.index)),
204✔
678
                (*C)(q.columnC.Get(q.cursor.index)),
204✔
679
                (*D)(q.columnD.Get(q.cursor.index))
204✔
680
}
204✔
681

682
// GetRelation returns the entity relation target of the component at the given index.
683
func (q *Query4[A, B, C, D]) GetRelation(index int) Entity {
40✔
684
        return q.components[index].columns[q.table.id].target
40✔
685
}
40✔
686

687
// Close closes the Query and unlocks the world.
688
//
689
// Automatically called when iteration completes.
690
// Needs to be called only if breaking out of the query iteration or not iterating at all.
691
func (q *Query4[A, B, C, D]) Close() {
13✔
692
        q.cursor.archetype = -2
13✔
693
        q.cursor.table = -2
13✔
694
        q.tables = nil
13✔
695
        q.table = nil
13✔
696
        q.cache = nil
13✔
697
        q.columnA = nil
13✔
698
        q.columnB = nil
13✔
699
        q.columnC = nil
13✔
700
        q.columnD = nil
13✔
701
        q.world.unlock(q.lock)
13✔
702
}
13✔
703

704
func (q *Query4[A, B, C, D]) nextTableOrArchetype() bool {
29✔
705
        if q.cache != nil {
36✔
706
                return q.nextTable(q.cache.tables)
7✔
707
        }
7✔
708
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
23✔
709
                return true
1✔
710
        }
1✔
711
        return q.nextArchetype()
21✔
712
}
713

714
func (q *Query4[A, B, C, D]) nextArchetype() bool {
21✔
715
        maxArchIndex := len(q.world.storage.archetypes) - 1
21✔
716
        for q.cursor.archetype < maxArchIndex {
50✔
717
                q.cursor.archetype++
29✔
718
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
29✔
719
                if !q.filter.matches(&archetype.mask) {
47✔
720
                        continue
18✔
721
                }
722

723
                if !archetype.HasRelations() {
17✔
724
                        table := &q.world.storage.tables[archetype.tables[0]]
7✔
725
                        if table.Len() > 0 {
14✔
726
                                q.setTable(0, table)
7✔
727
                                return true
7✔
728
                        }
7✔
729
                        continue
×
730
                }
731

732
                q.tables = archetype.GetTables(q.relations)
3✔
733
                q.cursor.table = -1
3✔
734
                if q.nextTable(q.tables) {
6✔
735
                        return true
3✔
736
                }
3✔
737
        }
738
        q.Close()
10✔
739
        return false
10✔
740
}
741

742
func (q *Query4[A, B, C, D]) nextTable(tables []tableID) bool {
21✔
743
        maxTableIndex := len(tables) - 1
21✔
744
        for q.cursor.table < maxTableIndex {
33✔
745
                q.cursor.table++
12✔
746
                table := &q.world.storage.tables[tables[q.cursor.table]]
12✔
747
                if table.Len() == 0 {
15✔
748
                        continue
3✔
749
                }
750
                if !table.Matches(q.relations) {
10✔
751
                        continue
1✔
752
                }
753
                q.setTable(q.cursor.table, table)
8✔
754
                return true
8✔
755
        }
756
        if q.cache != nil {
16✔
757
                q.Close()
3✔
758
        }
3✔
759
        return false
13✔
760
}
761

762
func (q *Query4[A, B, C, D]) setTable(index int, table *table) {
15✔
763
        q.cursor.table = index
15✔
764
        q.table = table
15✔
765
        q.columnA = q.components[0].columns[q.table.id]
15✔
766
        q.columnB = q.components[1].columns[q.table.id]
15✔
767
        q.columnC = q.components[2].columns[q.table.id]
15✔
768
        q.columnD = q.components[3].columns[q.table.id]
15✔
769
        q.cursor.index = 0
15✔
770
        q.cursor.maxIndex = int64(q.table.Len() - 1)
15✔
771
}
15✔
772

773
// Query5 is a query for 5 components.
774
// Use a [Filter5] to create one.
775
//
776
// Queries are one-time use iterators and must be re-created each time before iterating.
777
//
778
// See [Query2] for a usage example.
779
type Query5[A any, B any, C any, D any, E any] struct {
780
        world      *World
781
        filter     *filter
782
        relations  []RelationID
783
        lock       uint8
784
        cursor     cursor
785
        tables     []tableID
786
        table      *table
787
        cache      *cacheEntry
788
        components []*componentStorage
789
        columnA    *column
790
        columnB    *column
791
        columnC    *column
792
        columnD    *column
793
        columnE    *column
794
}
795

796
func newQuery5[A any, B any, C any, D any, E any](world *World, filter *filter, ids []ID, relations []RelationID,
797
        cacheID cacheID, components []*componentStorage) Query5[A, B, C, D, E] {
13✔
798
        var cache *cacheEntry
13✔
799
        if cacheID != maxCacheID {
16✔
800
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
801
        }
3✔
802

803
        return Query5[A, B, C, D, E]{
13✔
804
                world:      world,
13✔
805
                filter:     filter,
13✔
806
                relations:  relations,
13✔
807
                cache:      cache,
13✔
808
                lock:       world.lock(),
13✔
809
                components: components,
13✔
810
                cursor: cursor{
13✔
811
                        archetype: -1,
13✔
812
                        table:     -1,
13✔
813
                        index:     0,
13✔
814
                        maxIndex:  -1,
13✔
815
                },
13✔
816
        }
13✔
817
}
818

819
// Next advances the query's cursor to the next entity.
820
func (q *Query5[A, B, C, D, E]) Next() bool {
216✔
821
        q.world.checkQueryNext(&q.cursor)
216✔
822
        if int64(q.cursor.index) < q.cursor.maxIndex {
403✔
823
                q.cursor.index++
187✔
824
                return true
187✔
825
        }
187✔
826
        return q.nextTableOrArchetype()
29✔
827
}
828

829
// Entity returns the current entity.
830
func (q *Query5[A, B, C, D, E]) Entity() Entity {
204✔
831
        q.world.checkQueryGet(&q.cursor)
204✔
832
        return q.table.GetEntity(q.cursor.index)
204✔
833
}
204✔
834

835
// Get returns the queried components of the current entity.
836
//
837
// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)!
838
func (q *Query5[A, B, C, D, E]) Get() (*A, *B, *C, *D, *E) {
204✔
839
        q.world.checkQueryGet(&q.cursor)
204✔
840
        return (*A)(q.columnA.Get(q.cursor.index)),
204✔
841
                (*B)(q.columnB.Get(q.cursor.index)),
204✔
842
                (*C)(q.columnC.Get(q.cursor.index)),
204✔
843
                (*D)(q.columnD.Get(q.cursor.index)),
204✔
844
                (*E)(q.columnE.Get(q.cursor.index))
204✔
845
}
204✔
846

847
// GetRelation returns the entity relation target of the component at the given index.
848
func (q *Query5[A, B, C, D, E]) GetRelation(index int) Entity {
40✔
849
        return q.components[index].columns[q.table.id].target
40✔
850
}
40✔
851

852
// Close closes the Query and unlocks the world.
853
//
854
// Automatically called when iteration completes.
855
// Needs to be called only if breaking out of the query iteration or not iterating at all.
856
func (q *Query5[A, B, C, D, E]) Close() {
13✔
857
        q.cursor.archetype = -2
13✔
858
        q.cursor.table = -2
13✔
859
        q.tables = nil
13✔
860
        q.table = nil
13✔
861
        q.cache = nil
13✔
862
        q.columnA = nil
13✔
863
        q.columnB = nil
13✔
864
        q.columnC = nil
13✔
865
        q.columnD = nil
13✔
866
        q.columnE = nil
13✔
867
        q.world.unlock(q.lock)
13✔
868
}
13✔
869

870
func (q *Query5[A, B, C, D, E]) nextTableOrArchetype() bool {
29✔
871
        if q.cache != nil {
36✔
872
                return q.nextTable(q.cache.tables)
7✔
873
        }
7✔
874
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
23✔
875
                return true
1✔
876
        }
1✔
877
        return q.nextArchetype()
21✔
878
}
879

880
func (q *Query5[A, B, C, D, E]) nextArchetype() bool {
21✔
881
        maxArchIndex := len(q.world.storage.archetypes) - 1
21✔
882
        for q.cursor.archetype < maxArchIndex {
50✔
883
                q.cursor.archetype++
29✔
884
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
29✔
885
                if !q.filter.matches(&archetype.mask) {
47✔
886
                        continue
18✔
887
                }
888

889
                if !archetype.HasRelations() {
17✔
890
                        table := &q.world.storage.tables[archetype.tables[0]]
7✔
891
                        if table.Len() > 0 {
14✔
892
                                q.setTable(0, table)
7✔
893
                                return true
7✔
894
                        }
7✔
895
                        continue
×
896
                }
897

898
                q.tables = archetype.GetTables(q.relations)
3✔
899
                q.cursor.table = -1
3✔
900
                if q.nextTable(q.tables) {
6✔
901
                        return true
3✔
902
                }
3✔
903
        }
904
        q.Close()
10✔
905
        return false
10✔
906
}
907

908
func (q *Query5[A, B, C, D, E]) nextTable(tables []tableID) bool {
21✔
909
        maxTableIndex := len(tables) - 1
21✔
910
        for q.cursor.table < maxTableIndex {
33✔
911
                q.cursor.table++
12✔
912
                table := &q.world.storage.tables[tables[q.cursor.table]]
12✔
913
                if table.Len() == 0 {
15✔
914
                        continue
3✔
915
                }
916
                if !table.Matches(q.relations) {
10✔
917
                        continue
1✔
918
                }
919
                q.setTable(q.cursor.table, table)
8✔
920
                return true
8✔
921
        }
922
        if q.cache != nil {
16✔
923
                q.Close()
3✔
924
        }
3✔
925
        return false
13✔
926
}
927

928
func (q *Query5[A, B, C, D, E]) setTable(index int, table *table) {
15✔
929
        q.cursor.table = index
15✔
930
        q.table = table
15✔
931
        q.columnA = q.components[0].columns[q.table.id]
15✔
932
        q.columnB = q.components[1].columns[q.table.id]
15✔
933
        q.columnC = q.components[2].columns[q.table.id]
15✔
934
        q.columnD = q.components[3].columns[q.table.id]
15✔
935
        q.columnE = q.components[4].columns[q.table.id]
15✔
936
        q.cursor.index = 0
15✔
937
        q.cursor.maxIndex = int64(q.table.Len() - 1)
15✔
938
}
15✔
939

940
// Query6 is a query for 6 components.
941
// Use a [Filter6] to create one.
942
//
943
// Queries are one-time use iterators and must be re-created each time before iterating.
944
//
945
// See [Query2] for a usage example.
946
type Query6[A any, B any, C any, D any, E any, F any] struct {
947
        world      *World
948
        filter     *filter
949
        relations  []RelationID
950
        lock       uint8
951
        cursor     cursor
952
        tables     []tableID
953
        table      *table
954
        cache      *cacheEntry
955
        components []*componentStorage
956
        columnA    *column
957
        columnB    *column
958
        columnC    *column
959
        columnD    *column
960
        columnE    *column
961
        columnF    *column
962
}
963

964
func newQuery6[A any, B any, C any, D any, E any, F any](world *World, filter *filter, ids []ID, relations []RelationID,
965
        cacheID cacheID, components []*componentStorage) Query6[A, B, C, D, E, F] {
13✔
966
        var cache *cacheEntry
13✔
967
        if cacheID != maxCacheID {
16✔
968
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
969
        }
3✔
970

971
        return Query6[A, B, C, D, E, F]{
13✔
972
                world:      world,
13✔
973
                filter:     filter,
13✔
974
                relations:  relations,
13✔
975
                cache:      cache,
13✔
976
                lock:       world.lock(),
13✔
977
                components: components,
13✔
978
                cursor: cursor{
13✔
979
                        archetype: -1,
13✔
980
                        table:     -1,
13✔
981
                        index:     0,
13✔
982
                        maxIndex:  -1,
13✔
983
                },
13✔
984
        }
13✔
985
}
986

987
// Next advances the query's cursor to the next entity.
988
func (q *Query6[A, B, C, D, E, F]) Next() bool {
216✔
989
        q.world.checkQueryNext(&q.cursor)
216✔
990
        if int64(q.cursor.index) < q.cursor.maxIndex {
403✔
991
                q.cursor.index++
187✔
992
                return true
187✔
993
        }
187✔
994
        return q.nextTableOrArchetype()
29✔
995
}
996

997
// Entity returns the current entity.
998
func (q *Query6[A, B, C, D, E, F]) Entity() Entity {
204✔
999
        q.world.checkQueryGet(&q.cursor)
204✔
1000
        return q.table.GetEntity(q.cursor.index)
204✔
1001
}
204✔
1002

1003
// Get returns the queried components of the current entity.
1004
//
1005
// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)!
1006
func (q *Query6[A, B, C, D, E, F]) Get() (*A, *B, *C, *D, *E, *F) {
204✔
1007
        q.world.checkQueryGet(&q.cursor)
204✔
1008
        return (*A)(q.columnA.Get(q.cursor.index)),
204✔
1009
                (*B)(q.columnB.Get(q.cursor.index)),
204✔
1010
                (*C)(q.columnC.Get(q.cursor.index)),
204✔
1011
                (*D)(q.columnD.Get(q.cursor.index)),
204✔
1012
                (*E)(q.columnE.Get(q.cursor.index)),
204✔
1013
                (*F)(q.columnF.Get(q.cursor.index))
204✔
1014
}
204✔
1015

1016
// GetRelation returns the entity relation target of the component at the given index.
1017
func (q *Query6[A, B, C, D, E, F]) GetRelation(index int) Entity {
40✔
1018
        return q.components[index].columns[q.table.id].target
40✔
1019
}
40✔
1020

1021
// Close closes the Query and unlocks the world.
1022
//
1023
// Automatically called when iteration completes.
1024
// Needs to be called only if breaking out of the query iteration or not iterating at all.
1025
func (q *Query6[A, B, C, D, E, F]) Close() {
13✔
1026
        q.cursor.archetype = -2
13✔
1027
        q.cursor.table = -2
13✔
1028
        q.tables = nil
13✔
1029
        q.table = nil
13✔
1030
        q.cache = nil
13✔
1031
        q.columnA = nil
13✔
1032
        q.columnB = nil
13✔
1033
        q.columnC = nil
13✔
1034
        q.columnD = nil
13✔
1035
        q.columnE = nil
13✔
1036
        q.columnF = nil
13✔
1037
        q.world.unlock(q.lock)
13✔
1038
}
13✔
1039

1040
func (q *Query6[A, B, C, D, E, F]) nextTableOrArchetype() bool {
29✔
1041
        if q.cache != nil {
36✔
1042
                return q.nextTable(q.cache.tables)
7✔
1043
        }
7✔
1044
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
23✔
1045
                return true
1✔
1046
        }
1✔
1047
        return q.nextArchetype()
21✔
1048
}
1049

1050
func (q *Query6[A, B, C, D, E, F]) nextArchetype() bool {
21✔
1051
        maxArchIndex := len(q.world.storage.archetypes) - 1
21✔
1052
        for q.cursor.archetype < maxArchIndex {
50✔
1053
                q.cursor.archetype++
29✔
1054
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
29✔
1055
                if !q.filter.matches(&archetype.mask) {
47✔
1056
                        continue
18✔
1057
                }
1058

1059
                if !archetype.HasRelations() {
17✔
1060
                        table := &q.world.storage.tables[archetype.tables[0]]
7✔
1061
                        if table.Len() > 0 {
14✔
1062
                                q.setTable(0, table)
7✔
1063
                                return true
7✔
1064
                        }
7✔
1065
                        continue
×
1066
                }
1067

1068
                q.tables = archetype.GetTables(q.relations)
3✔
1069
                q.cursor.table = -1
3✔
1070
                if q.nextTable(q.tables) {
6✔
1071
                        return true
3✔
1072
                }
3✔
1073
        }
1074
        q.Close()
10✔
1075
        return false
10✔
1076
}
1077

1078
func (q *Query6[A, B, C, D, E, F]) nextTable(tables []tableID) bool {
21✔
1079
        maxTableIndex := len(tables) - 1
21✔
1080
        for q.cursor.table < maxTableIndex {
33✔
1081
                q.cursor.table++
12✔
1082
                table := &q.world.storage.tables[tables[q.cursor.table]]
12✔
1083
                if table.Len() == 0 {
15✔
1084
                        continue
3✔
1085
                }
1086
                if !table.Matches(q.relations) {
10✔
1087
                        continue
1✔
1088
                }
1089
                q.setTable(q.cursor.table, table)
8✔
1090
                return true
8✔
1091
        }
1092
        if q.cache != nil {
16✔
1093
                q.Close()
3✔
1094
        }
3✔
1095
        return false
13✔
1096
}
1097

1098
func (q *Query6[A, B, C, D, E, F]) setTable(index int, table *table) {
15✔
1099
        q.cursor.table = index
15✔
1100
        q.table = table
15✔
1101
        q.columnA = q.components[0].columns[q.table.id]
15✔
1102
        q.columnB = q.components[1].columns[q.table.id]
15✔
1103
        q.columnC = q.components[2].columns[q.table.id]
15✔
1104
        q.columnD = q.components[3].columns[q.table.id]
15✔
1105
        q.columnE = q.components[4].columns[q.table.id]
15✔
1106
        q.columnF = q.components[5].columns[q.table.id]
15✔
1107
        q.cursor.index = 0
15✔
1108
        q.cursor.maxIndex = int64(q.table.Len() - 1)
15✔
1109
}
15✔
1110

1111
// Query7 is a query for 7 components.
1112
// Use a [Filter7] to create one.
1113
//
1114
// Queries are one-time use iterators and must be re-created each time before iterating.
1115
//
1116
// See [Query2] for a usage example.
1117
type Query7[A any, B any, C any, D any, E any, F any, G any] struct {
1118
        world      *World
1119
        filter     *filter
1120
        relations  []RelationID
1121
        lock       uint8
1122
        cursor     cursor
1123
        tables     []tableID
1124
        table      *table
1125
        cache      *cacheEntry
1126
        components []*componentStorage
1127
        columnA    *column
1128
        columnB    *column
1129
        columnC    *column
1130
        columnD    *column
1131
        columnE    *column
1132
        columnF    *column
1133
        columnG    *column
1134
}
1135

1136
func newQuery7[A any, B any, C any, D any, E any, F any, G any](world *World, filter *filter, ids []ID, relations []RelationID,
1137
        cacheID cacheID, components []*componentStorage) Query7[A, B, C, D, E, F, G] {
13✔
1138
        var cache *cacheEntry
13✔
1139
        if cacheID != maxCacheID {
16✔
1140
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
1141
        }
3✔
1142

1143
        return Query7[A, B, C, D, E, F, G]{
13✔
1144
                world:      world,
13✔
1145
                filter:     filter,
13✔
1146
                relations:  relations,
13✔
1147
                cache:      cache,
13✔
1148
                lock:       world.lock(),
13✔
1149
                components: components,
13✔
1150
                cursor: cursor{
13✔
1151
                        archetype: -1,
13✔
1152
                        table:     -1,
13✔
1153
                        index:     0,
13✔
1154
                        maxIndex:  -1,
13✔
1155
                },
13✔
1156
        }
13✔
1157
}
1158

1159
// Next advances the query's cursor to the next entity.
1160
func (q *Query7[A, B, C, D, E, F, G]) Next() bool {
216✔
1161
        q.world.checkQueryNext(&q.cursor)
216✔
1162
        if int64(q.cursor.index) < q.cursor.maxIndex {
403✔
1163
                q.cursor.index++
187✔
1164
                return true
187✔
1165
        }
187✔
1166
        return q.nextTableOrArchetype()
29✔
1167
}
1168

1169
// Entity returns the current entity.
1170
func (q *Query7[A, B, C, D, E, F, G]) Entity() Entity {
204✔
1171
        q.world.checkQueryGet(&q.cursor)
204✔
1172
        return q.table.GetEntity(q.cursor.index)
204✔
1173
}
204✔
1174

1175
// Get returns the queried components of the current entity.
1176
//
1177
// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)!
1178
func (q *Query7[A, B, C, D, E, F, G]) Get() (*A, *B, *C, *D, *E, *F, *G) {
204✔
1179
        q.world.checkQueryGet(&q.cursor)
204✔
1180
        return (*A)(q.columnA.Get(q.cursor.index)),
204✔
1181
                (*B)(q.columnB.Get(q.cursor.index)),
204✔
1182
                (*C)(q.columnC.Get(q.cursor.index)),
204✔
1183
                (*D)(q.columnD.Get(q.cursor.index)),
204✔
1184
                (*E)(q.columnE.Get(q.cursor.index)),
204✔
1185
                (*F)(q.columnF.Get(q.cursor.index)),
204✔
1186
                (*G)(q.columnG.Get(q.cursor.index))
204✔
1187
}
204✔
1188

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

1194
// Close closes the Query and unlocks the world.
1195
//
1196
// Automatically called when iteration completes.
1197
// Needs to be called only if breaking out of the query iteration or not iterating at all.
1198
func (q *Query7[A, B, C, D, E, F, G]) Close() {
13✔
1199
        q.cursor.archetype = -2
13✔
1200
        q.cursor.table = -2
13✔
1201
        q.tables = nil
13✔
1202
        q.table = nil
13✔
1203
        q.cache = nil
13✔
1204
        q.columnA = nil
13✔
1205
        q.columnB = nil
13✔
1206
        q.columnC = nil
13✔
1207
        q.columnD = nil
13✔
1208
        q.columnE = nil
13✔
1209
        q.columnF = nil
13✔
1210
        q.columnG = nil
13✔
1211
        q.world.unlock(q.lock)
13✔
1212
}
13✔
1213

1214
func (q *Query7[A, B, C, D, E, F, G]) nextTableOrArchetype() bool {
29✔
1215
        if q.cache != nil {
36✔
1216
                return q.nextTable(q.cache.tables)
7✔
1217
        }
7✔
1218
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
23✔
1219
                return true
1✔
1220
        }
1✔
1221
        return q.nextArchetype()
21✔
1222
}
1223

1224
func (q *Query7[A, B, C, D, E, F, G]) nextArchetype() bool {
21✔
1225
        maxArchIndex := len(q.world.storage.archetypes) - 1
21✔
1226
        for q.cursor.archetype < maxArchIndex {
50✔
1227
                q.cursor.archetype++
29✔
1228
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
29✔
1229
                if !q.filter.matches(&archetype.mask) {
47✔
1230
                        continue
18✔
1231
                }
1232

1233
                if !archetype.HasRelations() {
17✔
1234
                        table := &q.world.storage.tables[archetype.tables[0]]
7✔
1235
                        if table.Len() > 0 {
14✔
1236
                                q.setTable(0, table)
7✔
1237
                                return true
7✔
1238
                        }
7✔
1239
                        continue
×
1240
                }
1241

1242
                q.tables = archetype.GetTables(q.relations)
3✔
1243
                q.cursor.table = -1
3✔
1244
                if q.nextTable(q.tables) {
6✔
1245
                        return true
3✔
1246
                }
3✔
1247
        }
1248
        q.Close()
10✔
1249
        return false
10✔
1250
}
1251

1252
func (q *Query7[A, B, C, D, E, F, G]) nextTable(tables []tableID) bool {
21✔
1253
        maxTableIndex := len(tables) - 1
21✔
1254
        for q.cursor.table < maxTableIndex {
33✔
1255
                q.cursor.table++
12✔
1256
                table := &q.world.storage.tables[tables[q.cursor.table]]
12✔
1257
                if table.Len() == 0 {
15✔
1258
                        continue
3✔
1259
                }
1260
                if !table.Matches(q.relations) {
10✔
1261
                        continue
1✔
1262
                }
1263
                q.setTable(q.cursor.table, table)
8✔
1264
                return true
8✔
1265
        }
1266
        if q.cache != nil {
16✔
1267
                q.Close()
3✔
1268
        }
3✔
1269
        return false
13✔
1270
}
1271

1272
func (q *Query7[A, B, C, D, E, F, G]) setTable(index int, table *table) {
15✔
1273
        q.cursor.table = index
15✔
1274
        q.table = table
15✔
1275
        q.columnA = q.components[0].columns[q.table.id]
15✔
1276
        q.columnB = q.components[1].columns[q.table.id]
15✔
1277
        q.columnC = q.components[2].columns[q.table.id]
15✔
1278
        q.columnD = q.components[3].columns[q.table.id]
15✔
1279
        q.columnE = q.components[4].columns[q.table.id]
15✔
1280
        q.columnF = q.components[5].columns[q.table.id]
15✔
1281
        q.columnG = q.components[6].columns[q.table.id]
15✔
1282
        q.cursor.index = 0
15✔
1283
        q.cursor.maxIndex = int64(q.table.Len() - 1)
15✔
1284
}
15✔
1285

1286
// Query8 is a query for 8 components.
1287
// Use a [Filter8] to create one.
1288
//
1289
// Queries are one-time use iterators and must be re-created each time before iterating.
1290
//
1291
// See [Query2] for a usage example.
1292
type Query8[A any, B any, C any, D any, E any, F any, G any, H any] struct {
1293
        world      *World
1294
        filter     *filter
1295
        relations  []RelationID
1296
        lock       uint8
1297
        cursor     cursor
1298
        tables     []tableID
1299
        table      *table
1300
        cache      *cacheEntry
1301
        components []*componentStorage
1302
        columnA    *column
1303
        columnB    *column
1304
        columnC    *column
1305
        columnD    *column
1306
        columnE    *column
1307
        columnF    *column
1308
        columnG    *column
1309
        columnH    *column
1310
}
1311

1312
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,
1313
        cacheID cacheID, components []*componentStorage) Query8[A, B, C, D, E, F, G, H] {
13✔
1314
        var cache *cacheEntry
13✔
1315
        if cacheID != maxCacheID {
16✔
1316
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
1317
        }
3✔
1318

1319
        return Query8[A, B, C, D, E, F, G, H]{
13✔
1320
                world:      world,
13✔
1321
                filter:     filter,
13✔
1322
                relations:  relations,
13✔
1323
                cache:      cache,
13✔
1324
                lock:       world.lock(),
13✔
1325
                components: components,
13✔
1326
                cursor: cursor{
13✔
1327
                        archetype: -1,
13✔
1328
                        table:     -1,
13✔
1329
                        index:     0,
13✔
1330
                        maxIndex:  -1,
13✔
1331
                },
13✔
1332
        }
13✔
1333
}
1334

1335
// Next advances the query's cursor to the next entity.
1336
func (q *Query8[A, B, C, D, E, F, G, H]) Next() bool {
216✔
1337
        q.world.checkQueryNext(&q.cursor)
216✔
1338
        if int64(q.cursor.index) < q.cursor.maxIndex {
403✔
1339
                q.cursor.index++
187✔
1340
                return true
187✔
1341
        }
187✔
1342
        return q.nextTableOrArchetype()
29✔
1343
}
1344

1345
// Entity returns the current entity.
1346
func (q *Query8[A, B, C, D, E, F, G, H]) Entity() Entity {
204✔
1347
        q.world.checkQueryGet(&q.cursor)
204✔
1348
        return q.table.GetEntity(q.cursor.index)
204✔
1349
}
204✔
1350

1351
// Get returns the queried components of the current entity.
1352
//
1353
// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)!
1354
func (q *Query8[A, B, C, D, E, F, G, H]) Get() (*A, *B, *C, *D, *E, *F, *G, *H) {
204✔
1355
        q.world.checkQueryGet(&q.cursor)
204✔
1356
        return (*A)(q.columnA.Get(q.cursor.index)),
204✔
1357
                (*B)(q.columnB.Get(q.cursor.index)),
204✔
1358
                (*C)(q.columnC.Get(q.cursor.index)),
204✔
1359
                (*D)(q.columnD.Get(q.cursor.index)),
204✔
1360
                (*E)(q.columnE.Get(q.cursor.index)),
204✔
1361
                (*F)(q.columnF.Get(q.cursor.index)),
204✔
1362
                (*G)(q.columnG.Get(q.cursor.index)),
204✔
1363
                (*H)(q.columnH.Get(q.cursor.index))
204✔
1364
}
204✔
1365

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

1371
// Close closes the Query and unlocks the world.
1372
//
1373
// Automatically called when iteration completes.
1374
// Needs to be called only if breaking out of the query iteration or not iterating at all.
1375
func (q *Query8[A, B, C, D, E, F, G, H]) Close() {
13✔
1376
        q.cursor.archetype = -2
13✔
1377
        q.cursor.table = -2
13✔
1378
        q.tables = nil
13✔
1379
        q.table = nil
13✔
1380
        q.cache = nil
13✔
1381
        q.columnA = nil
13✔
1382
        q.columnB = nil
13✔
1383
        q.columnC = nil
13✔
1384
        q.columnD = nil
13✔
1385
        q.columnE = nil
13✔
1386
        q.columnF = nil
13✔
1387
        q.columnG = nil
13✔
1388
        q.columnH = nil
13✔
1389
        q.world.unlock(q.lock)
13✔
1390
}
13✔
1391

1392
func (q *Query8[A, B, C, D, E, F, G, H]) nextTableOrArchetype() bool {
29✔
1393
        if q.cache != nil {
36✔
1394
                return q.nextTable(q.cache.tables)
7✔
1395
        }
7✔
1396
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
23✔
1397
                return true
1✔
1398
        }
1✔
1399
        return q.nextArchetype()
21✔
1400
}
1401

1402
func (q *Query8[A, B, C, D, E, F, G, H]) nextArchetype() bool {
21✔
1403
        maxArchIndex := len(q.world.storage.archetypes) - 1
21✔
1404
        for q.cursor.archetype < maxArchIndex {
50✔
1405
                q.cursor.archetype++
29✔
1406
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
29✔
1407
                if !q.filter.matches(&archetype.mask) {
47✔
1408
                        continue
18✔
1409
                }
1410

1411
                if !archetype.HasRelations() {
17✔
1412
                        table := &q.world.storage.tables[archetype.tables[0]]
7✔
1413
                        if table.Len() > 0 {
14✔
1414
                                q.setTable(0, table)
7✔
1415
                                return true
7✔
1416
                        }
7✔
1417
                        continue
×
1418
                }
1419

1420
                q.tables = archetype.GetTables(q.relations)
3✔
1421
                q.cursor.table = -1
3✔
1422
                if q.nextTable(q.tables) {
6✔
1423
                        return true
3✔
1424
                }
3✔
1425
        }
1426
        q.Close()
10✔
1427
        return false
10✔
1428
}
1429

1430
func (q *Query8[A, B, C, D, E, F, G, H]) nextTable(tables []tableID) bool {
21✔
1431
        maxTableIndex := len(tables) - 1
21✔
1432
        for q.cursor.table < maxTableIndex {
33✔
1433
                q.cursor.table++
12✔
1434
                table := &q.world.storage.tables[tables[q.cursor.table]]
12✔
1435
                if table.Len() == 0 {
15✔
1436
                        continue
3✔
1437
                }
1438
                if !table.Matches(q.relations) {
10✔
1439
                        continue
1✔
1440
                }
1441
                q.setTable(q.cursor.table, table)
8✔
1442
                return true
8✔
1443
        }
1444
        if q.cache != nil {
16✔
1445
                q.Close()
3✔
1446
        }
3✔
1447
        return false
13✔
1448
}
1449

1450
func (q *Query8[A, B, C, D, E, F, G, H]) setTable(index int, table *table) {
15✔
1451
        q.cursor.table = index
15✔
1452
        q.table = table
15✔
1453
        q.columnA = q.components[0].columns[q.table.id]
15✔
1454
        q.columnB = q.components[1].columns[q.table.id]
15✔
1455
        q.columnC = q.components[2].columns[q.table.id]
15✔
1456
        q.columnD = q.components[3].columns[q.table.id]
15✔
1457
        q.columnE = q.components[4].columns[q.table.id]
15✔
1458
        q.columnF = q.components[5].columns[q.table.id]
15✔
1459
        q.columnG = q.components[6].columns[q.table.id]
15✔
1460
        q.columnH = q.components[7].columns[q.table.id]
15✔
1461
        q.cursor.index = 0
15✔
1462
        q.cursor.maxIndex = int64(q.table.Len() - 1)
15✔
1463
}
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