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

mlange-42 / ark / 13732588874

08 Mar 2025 01:39AM CUT coverage: 99.425%. Remained the same
13732588874

push

github

web-flow
Add warnings on storing pointers, extend docs (#162)

6393 of 6430 relevant lines covered (99.42%)

28801.99 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 [NewFilter0] to create one.
14
//
15
// Queries are one-time use iterators and must be re-created each time before iterating.
16
type Query0 struct {
17
        world      *World
18
        filter     *filter
19
        relations  []RelationID
20
        lock       uint8
21
        cursor     cursor
22
        tables     []tableID
23
        table      *table
24
        cache      *cacheEntry
25
        components []*componentStorage
26
}
27

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

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

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

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

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

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

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

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

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

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

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

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

162
func newQuery1[A any](world *World, filter *filter, ids []ID, relations []RelationID,
163
        cacheID cacheID, components []*componentStorage) Query1[A] {
1,112✔
164
        var cache *cacheEntry
1,112✔
165
        if cacheID != maxCacheID {
1,115✔
166
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
167
        }
3✔
168

169
        return Query1[A]{
1,112✔
170
                world:      world,
1,112✔
171
                filter:     filter,
1,112✔
172
                relations:  relations,
1,112✔
173
                cache:      cache,
1,112✔
174
                lock:       world.lock(),
1,112✔
175
                components: components,
1,112✔
176
                cursor: cursor{
1,112✔
177
                        archetype: -1,
1,112✔
178
                        table:     -1,
1,112✔
179
                        index:     0,
1,112✔
180
                        maxIndex:  -1,
1,112✔
181
                },
1,112✔
182
        }
1,112✔
183
}
184

185
// Next advances the query's cursor to the next entity.
186
func (q *Query1[A]) Next() bool {
1,002,519✔
187
        q.world.checkQueryNext(&q.cursor)
1,002,519✔
188
        if int64(q.cursor.index) < q.cursor.maxIndex {
2,002,804✔
189
                q.cursor.index++
1,000,285✔
190
                return true
1,000,285✔
191
        }
1,000,285✔
192
        return q.nextTableOrArchetype()
2,234✔
193
}
194

195
// Entity returns the current entity.
196
func (q *Query1[A]) Entity() Entity {
2,001,026✔
197
        q.world.checkQueryGet(&q.cursor)
2,001,026✔
198
        return q.table.GetEntity(q.cursor.index)
2,001,026✔
199
}
2,001,026✔
200

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

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

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

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

238
func (q *Query1[A]) nextArchetype() bool {
2,226✔
239
        maxArchIndex := len(q.world.storage.archetypes) - 1
2,226✔
240
        for q.cursor.archetype < maxArchIndex {
4,717✔
241
                q.cursor.archetype++
2,491✔
242
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
2,491✔
243
                if !q.filter.matches(&archetype.mask) {
3,792✔
244
                        continue
1,301✔
245
                }
246

247
                if !archetype.HasRelations() {
2,356✔
248
                        table := &q.world.storage.tables[archetype.tables[0]]
1,167✔
249
                        if table.Len() > 0 {
2,270✔
250
                                q.setTable(0, table)
1,103✔
251
                                return true
1,103✔
252
                        }
1,103✔
253
                        continue
64✔
254
                }
255

256
                q.tables = archetype.GetTables(q.relations)
22✔
257
                q.cursor.table = -1
22✔
258
                if q.nextTable(q.tables) {
35✔
259
                        return true
13✔
260
                }
13✔
261
        }
262
        q.Close()
1,109✔
263
        return false
1,109✔
264
}
265

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

286
func (q *Query1[A]) setTable(index int, table *table) {
1,121✔
287
        q.cursor.table = index
1,121✔
288
        q.table = table
1,121✔
289
        q.columnA = q.components[0].columns[q.table.id]
1,121✔
290
        q.cursor.index = 0
1,121✔
291
        q.cursor.maxIndex = int64(q.table.Len() - 1)
1,121✔
292
}
1,121✔
293

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

312
func newQuery2[A any, B any](world *World, filter *filter, ids []ID, relations []RelationID,
313
        cacheID cacheID, components []*componentStorage) Query2[A, B] {
14✔
314
        var cache *cacheEntry
14✔
315
        if cacheID != maxCacheID {
17✔
316
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
317
        }
3✔
318

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

335
// Next advances the query's cursor to the next entity.
336
func (q *Query2[A, B]) Next() bool {
249✔
337
        q.world.checkQueryNext(&q.cursor)
249✔
338
        if int64(q.cursor.index) < q.cursor.maxIndex {
467✔
339
                q.cursor.index++
218✔
340
                return true
218✔
341
        }
218✔
342
        return q.nextTableOrArchetype()
31✔
343
}
344

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

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

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

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

380
func (q *Query2[A, B]) nextTableOrArchetype() bool {
31✔
381
        if q.cache != nil {
38✔
382
                return q.nextTable(q.cache.tables)
7✔
383
        }
7✔
384
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
25✔
385
                return true
1✔
386
        }
1✔
387
        return q.nextArchetype()
23✔
388
}
389

390
func (q *Query2[A, B]) nextArchetype() bool {
23✔
391
        maxArchIndex := len(q.world.storage.archetypes) - 1
23✔
392
        for q.cursor.archetype < maxArchIndex {
54✔
393
                q.cursor.archetype++
31✔
394
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
31✔
395
                if !q.filter.matches(&archetype.mask) {
50✔
396
                        continue
19✔
397
                }
398

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

408
                q.tables = archetype.GetTables(q.relations)
4✔
409
                q.cursor.table = -1
4✔
410
                if q.nextTable(q.tables) {
8✔
411
                        return true
4✔
412
                }
4✔
413
        }
414
        q.Close()
11✔
415
        return false
11✔
416
}
417

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

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

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

466
func newQuery3[A any, B any, C any](world *World, filter *filter, ids []ID, relations []RelationID,
467
        cacheID cacheID, components []*componentStorage) Query3[A, B, C] {
16✔
468
        var cache *cacheEntry
16✔
469
        if cacheID != maxCacheID {
19✔
470
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
471
        }
3✔
472

473
        return Query3[A, B, C]{
16✔
474
                world:      world,
16✔
475
                filter:     filter,
16✔
476
                relations:  relations,
16✔
477
                cache:      cache,
16✔
478
                lock:       world.lock(),
16✔
479
                components: components,
16✔
480
                cursor: cursor{
16✔
481
                        archetype: -1,
16✔
482
                        table:     -1,
16✔
483
                        index:     0,
16✔
484
                        maxIndex:  -1,
16✔
485
                },
16✔
486
        }
16✔
487
}
488

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

499
// Entity returns the current entity.
500
func (q *Query3[A, B, C]) Entity() Entity {
204✔
501
        q.world.checkQueryGet(&q.cursor)
204✔
502
        return q.table.GetEntity(q.cursor.index)
204✔
503
}
204✔
504

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

515
// GetRelation returns the entity relation target of the component at the given index.
516
func (q *Query3[A, B, C]) GetRelation(index int) Entity {
40✔
517
        return q.components[index].columns[q.table.id].target
40✔
518
}
40✔
519

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

536
func (q *Query3[A, B, C]) nextTableOrArchetype() bool {
39✔
537
        if q.cache != nil {
46✔
538
                return q.nextTable(q.cache.tables)
7✔
539
        }
7✔
540
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
37✔
541
                return true
5✔
542
        }
5✔
543
        return q.nextArchetype()
27✔
544
}
545

546
func (q *Query3[A, B, C]) nextArchetype() bool {
27✔
547
        maxArchIndex := len(q.world.storage.archetypes) - 1
27✔
548
        for q.cursor.archetype < maxArchIndex {
62✔
549
                q.cursor.archetype++
35✔
550
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
35✔
551
                if !q.filter.matches(&archetype.mask) {
56✔
552
                        continue
21✔
553
                }
554

555
                if !archetype.HasRelations() {
20✔
556
                        table := &q.world.storage.tables[archetype.tables[0]]
7✔
557
                        if table.Len() > 0 {
14✔
558
                                q.setTable(0, table)
7✔
559
                                return true
7✔
560
                        }
7✔
561
                        continue
×
562
                }
563

564
                q.tables = archetype.GetTables(q.relations)
6✔
565
                q.cursor.table = -1
6✔
566
                if q.nextTable(q.tables) {
12✔
567
                        return true
6✔
568
                }
6✔
569
        }
570
        q.Close()
13✔
571
        return false
13✔
572
}
573

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

594
func (q *Query3[A, B, C]) setTable(index int, table *table) {
22✔
595
        q.cursor.table = index
22✔
596
        q.table = table
22✔
597
        q.columnA = q.components[0].columns[q.table.id]
22✔
598
        q.columnB = q.components[1].columns[q.table.id]
22✔
599
        q.columnC = q.components[2].columns[q.table.id]
22✔
600
        q.cursor.index = 0
22✔
601
        q.cursor.maxIndex = int64(q.table.Len() - 1)
22✔
602
}
22✔
603

604
// Query4 is a query for 4 components.
605
// Use a [NewFilter4] to create one.
606
//
607
// Queries are one-time use iterators and must be re-created each time before iterating.
608
type Query4[A any, B any, C any, D any] struct {
609
        world      *World
610
        filter     *filter
611
        relations  []RelationID
612
        lock       uint8
613
        cursor     cursor
614
        tables     []tableID
615
        table      *table
616
        cache      *cacheEntry
617
        components []*componentStorage
618
        columnA    *column
619
        columnB    *column
620
        columnC    *column
621
        columnD    *column
622
}
623

624
func newQuery4[A any, B any, C any, D any](world *World, filter *filter, ids []ID, relations []RelationID,
625
        cacheID cacheID, components []*componentStorage) Query4[A, B, C, D] {
13✔
626
        var cache *cacheEntry
13✔
627
        if cacheID != maxCacheID {
16✔
628
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
629
        }
3✔
630

631
        return Query4[A, B, C, D]{
13✔
632
                world:      world,
13✔
633
                filter:     filter,
13✔
634
                relations:  relations,
13✔
635
                cache:      cache,
13✔
636
                lock:       world.lock(),
13✔
637
                components: components,
13✔
638
                cursor: cursor{
13✔
639
                        archetype: -1,
13✔
640
                        table:     -1,
13✔
641
                        index:     0,
13✔
642
                        maxIndex:  -1,
13✔
643
                },
13✔
644
        }
13✔
645
}
646

647
// Next advances the query's cursor to the next entity.
648
func (q *Query4[A, B, C, D]) Next() bool {
216✔
649
        q.world.checkQueryNext(&q.cursor)
216✔
650
        if int64(q.cursor.index) < q.cursor.maxIndex {
403✔
651
                q.cursor.index++
187✔
652
                return true
187✔
653
        }
187✔
654
        return q.nextTableOrArchetype()
29✔
655
}
656

657
// Entity returns the current entity.
658
func (q *Query4[A, B, C, D]) Entity() Entity {
204✔
659
        q.world.checkQueryGet(&q.cursor)
204✔
660
        return q.table.GetEntity(q.cursor.index)
204✔
661
}
204✔
662

663
// Get returns the queried components of the current entity.
664
//
665
// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)!
666
func (q *Query4[A, B, C, D]) Get() (*A, *B, *C, *D) {
204✔
667
        q.world.checkQueryGet(&q.cursor)
204✔
668
        return (*A)(q.columnA.Get(q.cursor.index)),
204✔
669
                (*B)(q.columnB.Get(q.cursor.index)),
204✔
670
                (*C)(q.columnC.Get(q.cursor.index)),
204✔
671
                (*D)(q.columnD.Get(q.cursor.index))
204✔
672
}
204✔
673

674
// GetRelation returns the entity relation target of the component at the given index.
675
func (q *Query4[A, B, C, D]) GetRelation(index int) Entity {
40✔
676
        return q.components[index].columns[q.table.id].target
40✔
677
}
40✔
678

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

696
func (q *Query4[A, B, C, D]) nextTableOrArchetype() bool {
29✔
697
        if q.cache != nil {
36✔
698
                return q.nextTable(q.cache.tables)
7✔
699
        }
7✔
700
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
23✔
701
                return true
1✔
702
        }
1✔
703
        return q.nextArchetype()
21✔
704
}
705

706
func (q *Query4[A, B, C, D]) nextArchetype() bool {
21✔
707
        maxArchIndex := len(q.world.storage.archetypes) - 1
21✔
708
        for q.cursor.archetype < maxArchIndex {
50✔
709
                q.cursor.archetype++
29✔
710
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
29✔
711
                if !q.filter.matches(&archetype.mask) {
47✔
712
                        continue
18✔
713
                }
714

715
                if !archetype.HasRelations() {
17✔
716
                        table := &q.world.storage.tables[archetype.tables[0]]
7✔
717
                        if table.Len() > 0 {
14✔
718
                                q.setTable(0, table)
7✔
719
                                return true
7✔
720
                        }
7✔
721
                        continue
×
722
                }
723

724
                q.tables = archetype.GetTables(q.relations)
3✔
725
                q.cursor.table = -1
3✔
726
                if q.nextTable(q.tables) {
6✔
727
                        return true
3✔
728
                }
3✔
729
        }
730
        q.Close()
10✔
731
        return false
10✔
732
}
733

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

754
func (q *Query4[A, B, C, D]) setTable(index int, table *table) {
15✔
755
        q.cursor.table = index
15✔
756
        q.table = table
15✔
757
        q.columnA = q.components[0].columns[q.table.id]
15✔
758
        q.columnB = q.components[1].columns[q.table.id]
15✔
759
        q.columnC = q.components[2].columns[q.table.id]
15✔
760
        q.columnD = q.components[3].columns[q.table.id]
15✔
761
        q.cursor.index = 0
15✔
762
        q.cursor.maxIndex = int64(q.table.Len() - 1)
15✔
763
}
15✔
764

765
// Query5 is a query for 5 components.
766
// Use a [NewFilter5] to create one.
767
//
768
// Queries are one-time use iterators and must be re-created each time before iterating.
769
type Query5[A any, B any, C any, D any, E any] struct {
770
        world      *World
771
        filter     *filter
772
        relations  []RelationID
773
        lock       uint8
774
        cursor     cursor
775
        tables     []tableID
776
        table      *table
777
        cache      *cacheEntry
778
        components []*componentStorage
779
        columnA    *column
780
        columnB    *column
781
        columnC    *column
782
        columnD    *column
783
        columnE    *column
784
}
785

786
func newQuery5[A any, B any, C any, D any, E any](world *World, filter *filter, ids []ID, relations []RelationID,
787
        cacheID cacheID, components []*componentStorage) Query5[A, B, C, D, E] {
13✔
788
        var cache *cacheEntry
13✔
789
        if cacheID != maxCacheID {
16✔
790
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
791
        }
3✔
792

793
        return Query5[A, B, C, D, E]{
13✔
794
                world:      world,
13✔
795
                filter:     filter,
13✔
796
                relations:  relations,
13✔
797
                cache:      cache,
13✔
798
                lock:       world.lock(),
13✔
799
                components: components,
13✔
800
                cursor: cursor{
13✔
801
                        archetype: -1,
13✔
802
                        table:     -1,
13✔
803
                        index:     0,
13✔
804
                        maxIndex:  -1,
13✔
805
                },
13✔
806
        }
13✔
807
}
808

809
// Next advances the query's cursor to the next entity.
810
func (q *Query5[A, B, C, D, E]) Next() bool {
216✔
811
        q.world.checkQueryNext(&q.cursor)
216✔
812
        if int64(q.cursor.index) < q.cursor.maxIndex {
403✔
813
                q.cursor.index++
187✔
814
                return true
187✔
815
        }
187✔
816
        return q.nextTableOrArchetype()
29✔
817
}
818

819
// Entity returns the current entity.
820
func (q *Query5[A, B, C, D, E]) Entity() Entity {
204✔
821
        q.world.checkQueryGet(&q.cursor)
204✔
822
        return q.table.GetEntity(q.cursor.index)
204✔
823
}
204✔
824

825
// Get returns the queried components of the current entity.
826
//
827
// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)!
828
func (q *Query5[A, B, C, D, E]) Get() (*A, *B, *C, *D, *E) {
204✔
829
        q.world.checkQueryGet(&q.cursor)
204✔
830
        return (*A)(q.columnA.Get(q.cursor.index)),
204✔
831
                (*B)(q.columnB.Get(q.cursor.index)),
204✔
832
                (*C)(q.columnC.Get(q.cursor.index)),
204✔
833
                (*D)(q.columnD.Get(q.cursor.index)),
204✔
834
                (*E)(q.columnE.Get(q.cursor.index))
204✔
835
}
204✔
836

837
// GetRelation returns the entity relation target of the component at the given index.
838
func (q *Query5[A, B, C, D, E]) GetRelation(index int) Entity {
40✔
839
        return q.components[index].columns[q.table.id].target
40✔
840
}
40✔
841

842
// Close closes the Query and unlocks the world.
843
//
844
// Automatically called when iteration completes.
845
// Needs to be called only if breaking out of the query iteration or not iterating at all.
846
func (q *Query5[A, B, C, D, E]) Close() {
13✔
847
        q.cursor.archetype = -2
13✔
848
        q.cursor.table = -2
13✔
849
        q.tables = nil
13✔
850
        q.table = nil
13✔
851
        q.cache = nil
13✔
852
        q.columnA = nil
13✔
853
        q.columnB = nil
13✔
854
        q.columnC = nil
13✔
855
        q.columnD = nil
13✔
856
        q.columnE = nil
13✔
857
        q.world.unlock(q.lock)
13✔
858
}
13✔
859

860
func (q *Query5[A, B, C, D, E]) nextTableOrArchetype() bool {
29✔
861
        if q.cache != nil {
36✔
862
                return q.nextTable(q.cache.tables)
7✔
863
        }
7✔
864
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
23✔
865
                return true
1✔
866
        }
1✔
867
        return q.nextArchetype()
21✔
868
}
869

870
func (q *Query5[A, B, C, D, E]) nextArchetype() bool {
21✔
871
        maxArchIndex := len(q.world.storage.archetypes) - 1
21✔
872
        for q.cursor.archetype < maxArchIndex {
50✔
873
                q.cursor.archetype++
29✔
874
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
29✔
875
                if !q.filter.matches(&archetype.mask) {
47✔
876
                        continue
18✔
877
                }
878

879
                if !archetype.HasRelations() {
17✔
880
                        table := &q.world.storage.tables[archetype.tables[0]]
7✔
881
                        if table.Len() > 0 {
14✔
882
                                q.setTable(0, table)
7✔
883
                                return true
7✔
884
                        }
7✔
885
                        continue
×
886
                }
887

888
                q.tables = archetype.GetTables(q.relations)
3✔
889
                q.cursor.table = -1
3✔
890
                if q.nextTable(q.tables) {
6✔
891
                        return true
3✔
892
                }
3✔
893
        }
894
        q.Close()
10✔
895
        return false
10✔
896
}
897

898
func (q *Query5[A, B, C, D, E]) nextTable(tables []tableID) bool {
21✔
899
        maxTableIndex := len(tables) - 1
21✔
900
        for q.cursor.table < maxTableIndex {
33✔
901
                q.cursor.table++
12✔
902
                table := &q.world.storage.tables[tables[q.cursor.table]]
12✔
903
                if table.Len() == 0 {
15✔
904
                        continue
3✔
905
                }
906
                if !table.Matches(q.relations) {
10✔
907
                        continue
1✔
908
                }
909
                q.setTable(q.cursor.table, table)
8✔
910
                return true
8✔
911
        }
912
        if q.cache != nil {
16✔
913
                q.Close()
3✔
914
        }
3✔
915
        return false
13✔
916
}
917

918
func (q *Query5[A, B, C, D, E]) setTable(index int, table *table) {
15✔
919
        q.cursor.table = index
15✔
920
        q.table = table
15✔
921
        q.columnA = q.components[0].columns[q.table.id]
15✔
922
        q.columnB = q.components[1].columns[q.table.id]
15✔
923
        q.columnC = q.components[2].columns[q.table.id]
15✔
924
        q.columnD = q.components[3].columns[q.table.id]
15✔
925
        q.columnE = q.components[4].columns[q.table.id]
15✔
926
        q.cursor.index = 0
15✔
927
        q.cursor.maxIndex = int64(q.table.Len() - 1)
15✔
928
}
15✔
929

930
// Query6 is a query for 6 components.
931
// Use a [NewFilter6] to create one.
932
//
933
// Queries are one-time use iterators and must be re-created each time before iterating.
934
type Query6[A any, B any, C any, D any, E any, F any] struct {
935
        world      *World
936
        filter     *filter
937
        relations  []RelationID
938
        lock       uint8
939
        cursor     cursor
940
        tables     []tableID
941
        table      *table
942
        cache      *cacheEntry
943
        components []*componentStorage
944
        columnA    *column
945
        columnB    *column
946
        columnC    *column
947
        columnD    *column
948
        columnE    *column
949
        columnF    *column
950
}
951

952
func newQuery6[A any, B any, C any, D any, E any, F any](world *World, filter *filter, ids []ID, relations []RelationID,
953
        cacheID cacheID, components []*componentStorage) Query6[A, B, C, D, E, F] {
13✔
954
        var cache *cacheEntry
13✔
955
        if cacheID != maxCacheID {
16✔
956
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
957
        }
3✔
958

959
        return Query6[A, B, C, D, E, F]{
13✔
960
                world:      world,
13✔
961
                filter:     filter,
13✔
962
                relations:  relations,
13✔
963
                cache:      cache,
13✔
964
                lock:       world.lock(),
13✔
965
                components: components,
13✔
966
                cursor: cursor{
13✔
967
                        archetype: -1,
13✔
968
                        table:     -1,
13✔
969
                        index:     0,
13✔
970
                        maxIndex:  -1,
13✔
971
                },
13✔
972
        }
13✔
973
}
974

975
// Next advances the query's cursor to the next entity.
976
func (q *Query6[A, B, C, D, E, F]) Next() bool {
216✔
977
        q.world.checkQueryNext(&q.cursor)
216✔
978
        if int64(q.cursor.index) < q.cursor.maxIndex {
403✔
979
                q.cursor.index++
187✔
980
                return true
187✔
981
        }
187✔
982
        return q.nextTableOrArchetype()
29✔
983
}
984

985
// Entity returns the current entity.
986
func (q *Query6[A, B, C, D, E, F]) Entity() Entity {
204✔
987
        q.world.checkQueryGet(&q.cursor)
204✔
988
        return q.table.GetEntity(q.cursor.index)
204✔
989
}
204✔
990

991
// Get returns the queried components of the current entity.
992
//
993
// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)!
994
func (q *Query6[A, B, C, D, E, F]) Get() (*A, *B, *C, *D, *E, *F) {
204✔
995
        q.world.checkQueryGet(&q.cursor)
204✔
996
        return (*A)(q.columnA.Get(q.cursor.index)),
204✔
997
                (*B)(q.columnB.Get(q.cursor.index)),
204✔
998
                (*C)(q.columnC.Get(q.cursor.index)),
204✔
999
                (*D)(q.columnD.Get(q.cursor.index)),
204✔
1000
                (*E)(q.columnE.Get(q.cursor.index)),
204✔
1001
                (*F)(q.columnF.Get(q.cursor.index))
204✔
1002
}
204✔
1003

1004
// GetRelation returns the entity relation target of the component at the given index.
1005
func (q *Query6[A, B, C, D, E, F]) GetRelation(index int) Entity {
40✔
1006
        return q.components[index].columns[q.table.id].target
40✔
1007
}
40✔
1008

1009
// Close closes the Query and unlocks the world.
1010
//
1011
// Automatically called when iteration completes.
1012
// Needs to be called only if breaking out of the query iteration or not iterating at all.
1013
func (q *Query6[A, B, C, D, E, F]) Close() {
13✔
1014
        q.cursor.archetype = -2
13✔
1015
        q.cursor.table = -2
13✔
1016
        q.tables = nil
13✔
1017
        q.table = nil
13✔
1018
        q.cache = nil
13✔
1019
        q.columnA = nil
13✔
1020
        q.columnB = nil
13✔
1021
        q.columnC = nil
13✔
1022
        q.columnD = nil
13✔
1023
        q.columnE = nil
13✔
1024
        q.columnF = nil
13✔
1025
        q.world.unlock(q.lock)
13✔
1026
}
13✔
1027

1028
func (q *Query6[A, B, C, D, E, F]) nextTableOrArchetype() bool {
29✔
1029
        if q.cache != nil {
36✔
1030
                return q.nextTable(q.cache.tables)
7✔
1031
        }
7✔
1032
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
23✔
1033
                return true
1✔
1034
        }
1✔
1035
        return q.nextArchetype()
21✔
1036
}
1037

1038
func (q *Query6[A, B, C, D, E, F]) nextArchetype() bool {
21✔
1039
        maxArchIndex := len(q.world.storage.archetypes) - 1
21✔
1040
        for q.cursor.archetype < maxArchIndex {
50✔
1041
                q.cursor.archetype++
29✔
1042
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
29✔
1043
                if !q.filter.matches(&archetype.mask) {
47✔
1044
                        continue
18✔
1045
                }
1046

1047
                if !archetype.HasRelations() {
17✔
1048
                        table := &q.world.storage.tables[archetype.tables[0]]
7✔
1049
                        if table.Len() > 0 {
14✔
1050
                                q.setTable(0, table)
7✔
1051
                                return true
7✔
1052
                        }
7✔
1053
                        continue
×
1054
                }
1055

1056
                q.tables = archetype.GetTables(q.relations)
3✔
1057
                q.cursor.table = -1
3✔
1058
                if q.nextTable(q.tables) {
6✔
1059
                        return true
3✔
1060
                }
3✔
1061
        }
1062
        q.Close()
10✔
1063
        return false
10✔
1064
}
1065

1066
func (q *Query6[A, B, C, D, E, F]) nextTable(tables []tableID) bool {
21✔
1067
        maxTableIndex := len(tables) - 1
21✔
1068
        for q.cursor.table < maxTableIndex {
33✔
1069
                q.cursor.table++
12✔
1070
                table := &q.world.storage.tables[tables[q.cursor.table]]
12✔
1071
                if table.Len() == 0 {
15✔
1072
                        continue
3✔
1073
                }
1074
                if !table.Matches(q.relations) {
10✔
1075
                        continue
1✔
1076
                }
1077
                q.setTable(q.cursor.table, table)
8✔
1078
                return true
8✔
1079
        }
1080
        if q.cache != nil {
16✔
1081
                q.Close()
3✔
1082
        }
3✔
1083
        return false
13✔
1084
}
1085

1086
func (q *Query6[A, B, C, D, E, F]) setTable(index int, table *table) {
15✔
1087
        q.cursor.table = index
15✔
1088
        q.table = table
15✔
1089
        q.columnA = q.components[0].columns[q.table.id]
15✔
1090
        q.columnB = q.components[1].columns[q.table.id]
15✔
1091
        q.columnC = q.components[2].columns[q.table.id]
15✔
1092
        q.columnD = q.components[3].columns[q.table.id]
15✔
1093
        q.columnE = q.components[4].columns[q.table.id]
15✔
1094
        q.columnF = q.components[5].columns[q.table.id]
15✔
1095
        q.cursor.index = 0
15✔
1096
        q.cursor.maxIndex = int64(q.table.Len() - 1)
15✔
1097
}
15✔
1098

1099
// Query7 is a query for 7 components.
1100
// Use a [NewFilter7] to create one.
1101
//
1102
// Queries are one-time use iterators and must be re-created each time before iterating.
1103
type Query7[A any, B any, C any, D any, E any, F any, G any] struct {
1104
        world      *World
1105
        filter     *filter
1106
        relations  []RelationID
1107
        lock       uint8
1108
        cursor     cursor
1109
        tables     []tableID
1110
        table      *table
1111
        cache      *cacheEntry
1112
        components []*componentStorage
1113
        columnA    *column
1114
        columnB    *column
1115
        columnC    *column
1116
        columnD    *column
1117
        columnE    *column
1118
        columnF    *column
1119
        columnG    *column
1120
}
1121

1122
func newQuery7[A any, B any, C any, D any, E any, F any, G any](world *World, filter *filter, ids []ID, relations []RelationID,
1123
        cacheID cacheID, components []*componentStorage) Query7[A, B, C, D, E, F, G] {
13✔
1124
        var cache *cacheEntry
13✔
1125
        if cacheID != maxCacheID {
16✔
1126
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
1127
        }
3✔
1128

1129
        return Query7[A, B, C, D, E, F, G]{
13✔
1130
                world:      world,
13✔
1131
                filter:     filter,
13✔
1132
                relations:  relations,
13✔
1133
                cache:      cache,
13✔
1134
                lock:       world.lock(),
13✔
1135
                components: components,
13✔
1136
                cursor: cursor{
13✔
1137
                        archetype: -1,
13✔
1138
                        table:     -1,
13✔
1139
                        index:     0,
13✔
1140
                        maxIndex:  -1,
13✔
1141
                },
13✔
1142
        }
13✔
1143
}
1144

1145
// Next advances the query's cursor to the next entity.
1146
func (q *Query7[A, B, C, D, E, F, G]) Next() bool {
216✔
1147
        q.world.checkQueryNext(&q.cursor)
216✔
1148
        if int64(q.cursor.index) < q.cursor.maxIndex {
403✔
1149
                q.cursor.index++
187✔
1150
                return true
187✔
1151
        }
187✔
1152
        return q.nextTableOrArchetype()
29✔
1153
}
1154

1155
// Entity returns the current entity.
1156
func (q *Query7[A, B, C, D, E, F, G]) Entity() Entity {
204✔
1157
        q.world.checkQueryGet(&q.cursor)
204✔
1158
        return q.table.GetEntity(q.cursor.index)
204✔
1159
}
204✔
1160

1161
// Get returns the queried components of the current entity.
1162
//
1163
// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)!
1164
func (q *Query7[A, B, C, D, E, F, G]) Get() (*A, *B, *C, *D, *E, *F, *G) {
204✔
1165
        q.world.checkQueryGet(&q.cursor)
204✔
1166
        return (*A)(q.columnA.Get(q.cursor.index)),
204✔
1167
                (*B)(q.columnB.Get(q.cursor.index)),
204✔
1168
                (*C)(q.columnC.Get(q.cursor.index)),
204✔
1169
                (*D)(q.columnD.Get(q.cursor.index)),
204✔
1170
                (*E)(q.columnE.Get(q.cursor.index)),
204✔
1171
                (*F)(q.columnF.Get(q.cursor.index)),
204✔
1172
                (*G)(q.columnG.Get(q.cursor.index))
204✔
1173
}
204✔
1174

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

1180
// Close closes the Query and unlocks the world.
1181
//
1182
// Automatically called when iteration completes.
1183
// Needs to be called only if breaking out of the query iteration or not iterating at all.
1184
func (q *Query7[A, B, C, D, E, F, G]) Close() {
13✔
1185
        q.cursor.archetype = -2
13✔
1186
        q.cursor.table = -2
13✔
1187
        q.tables = nil
13✔
1188
        q.table = nil
13✔
1189
        q.cache = nil
13✔
1190
        q.columnA = nil
13✔
1191
        q.columnB = nil
13✔
1192
        q.columnC = nil
13✔
1193
        q.columnD = nil
13✔
1194
        q.columnE = nil
13✔
1195
        q.columnF = nil
13✔
1196
        q.columnG = nil
13✔
1197
        q.world.unlock(q.lock)
13✔
1198
}
13✔
1199

1200
func (q *Query7[A, B, C, D, E, F, G]) nextTableOrArchetype() bool {
29✔
1201
        if q.cache != nil {
36✔
1202
                return q.nextTable(q.cache.tables)
7✔
1203
        }
7✔
1204
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
23✔
1205
                return true
1✔
1206
        }
1✔
1207
        return q.nextArchetype()
21✔
1208
}
1209

1210
func (q *Query7[A, B, C, D, E, F, G]) nextArchetype() bool {
21✔
1211
        maxArchIndex := len(q.world.storage.archetypes) - 1
21✔
1212
        for q.cursor.archetype < maxArchIndex {
50✔
1213
                q.cursor.archetype++
29✔
1214
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
29✔
1215
                if !q.filter.matches(&archetype.mask) {
47✔
1216
                        continue
18✔
1217
                }
1218

1219
                if !archetype.HasRelations() {
17✔
1220
                        table := &q.world.storage.tables[archetype.tables[0]]
7✔
1221
                        if table.Len() > 0 {
14✔
1222
                                q.setTable(0, table)
7✔
1223
                                return true
7✔
1224
                        }
7✔
1225
                        continue
×
1226
                }
1227

1228
                q.tables = archetype.GetTables(q.relations)
3✔
1229
                q.cursor.table = -1
3✔
1230
                if q.nextTable(q.tables) {
6✔
1231
                        return true
3✔
1232
                }
3✔
1233
        }
1234
        q.Close()
10✔
1235
        return false
10✔
1236
}
1237

1238
func (q *Query7[A, B, C, D, E, F, G]) nextTable(tables []tableID) bool {
21✔
1239
        maxTableIndex := len(tables) - 1
21✔
1240
        for q.cursor.table < maxTableIndex {
33✔
1241
                q.cursor.table++
12✔
1242
                table := &q.world.storage.tables[tables[q.cursor.table]]
12✔
1243
                if table.Len() == 0 {
15✔
1244
                        continue
3✔
1245
                }
1246
                if !table.Matches(q.relations) {
10✔
1247
                        continue
1✔
1248
                }
1249
                q.setTable(q.cursor.table, table)
8✔
1250
                return true
8✔
1251
        }
1252
        if q.cache != nil {
16✔
1253
                q.Close()
3✔
1254
        }
3✔
1255
        return false
13✔
1256
}
1257

1258
func (q *Query7[A, B, C, D, E, F, G]) setTable(index int, table *table) {
15✔
1259
        q.cursor.table = index
15✔
1260
        q.table = table
15✔
1261
        q.columnA = q.components[0].columns[q.table.id]
15✔
1262
        q.columnB = q.components[1].columns[q.table.id]
15✔
1263
        q.columnC = q.components[2].columns[q.table.id]
15✔
1264
        q.columnD = q.components[3].columns[q.table.id]
15✔
1265
        q.columnE = q.components[4].columns[q.table.id]
15✔
1266
        q.columnF = q.components[5].columns[q.table.id]
15✔
1267
        q.columnG = q.components[6].columns[q.table.id]
15✔
1268
        q.cursor.index = 0
15✔
1269
        q.cursor.maxIndex = int64(q.table.Len() - 1)
15✔
1270
}
15✔
1271

1272
// Query8 is a query for 8 components.
1273
// Use a [NewFilter8] to create one.
1274
//
1275
// Queries are one-time use iterators and must be re-created each time before iterating.
1276
type Query8[A any, B any, C any, D any, E any, F any, G any, H any] struct {
1277
        world      *World
1278
        filter     *filter
1279
        relations  []RelationID
1280
        lock       uint8
1281
        cursor     cursor
1282
        tables     []tableID
1283
        table      *table
1284
        cache      *cacheEntry
1285
        components []*componentStorage
1286
        columnA    *column
1287
        columnB    *column
1288
        columnC    *column
1289
        columnD    *column
1290
        columnE    *column
1291
        columnF    *column
1292
        columnG    *column
1293
        columnH    *column
1294
}
1295

1296
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,
1297
        cacheID cacheID, components []*componentStorage) Query8[A, B, C, D, E, F, G, H] {
13✔
1298
        var cache *cacheEntry
13✔
1299
        if cacheID != maxCacheID {
16✔
1300
                cache = world.storage.getRegisteredFilter(cacheID)
3✔
1301
        }
3✔
1302

1303
        return Query8[A, B, C, D, E, F, G, H]{
13✔
1304
                world:      world,
13✔
1305
                filter:     filter,
13✔
1306
                relations:  relations,
13✔
1307
                cache:      cache,
13✔
1308
                lock:       world.lock(),
13✔
1309
                components: components,
13✔
1310
                cursor: cursor{
13✔
1311
                        archetype: -1,
13✔
1312
                        table:     -1,
13✔
1313
                        index:     0,
13✔
1314
                        maxIndex:  -1,
13✔
1315
                },
13✔
1316
        }
13✔
1317
}
1318

1319
// Next advances the query's cursor to the next entity.
1320
func (q *Query8[A, B, C, D, E, F, G, H]) Next() bool {
216✔
1321
        q.world.checkQueryNext(&q.cursor)
216✔
1322
        if int64(q.cursor.index) < q.cursor.maxIndex {
403✔
1323
                q.cursor.index++
187✔
1324
                return true
187✔
1325
        }
187✔
1326
        return q.nextTableOrArchetype()
29✔
1327
}
1328

1329
// Entity returns the current entity.
1330
func (q *Query8[A, B, C, D, E, F, G, H]) Entity() Entity {
204✔
1331
        q.world.checkQueryGet(&q.cursor)
204✔
1332
        return q.table.GetEntity(q.cursor.index)
204✔
1333
}
204✔
1334

1335
// Get returns the queried components of the current entity.
1336
//
1337
// ⚠️ Do not store the obtained pointers outside of the current context (i.e. the query loop)!
1338
func (q *Query8[A, B, C, D, E, F, G, H]) Get() (*A, *B, *C, *D, *E, *F, *G, *H) {
204✔
1339
        q.world.checkQueryGet(&q.cursor)
204✔
1340
        return (*A)(q.columnA.Get(q.cursor.index)),
204✔
1341
                (*B)(q.columnB.Get(q.cursor.index)),
204✔
1342
                (*C)(q.columnC.Get(q.cursor.index)),
204✔
1343
                (*D)(q.columnD.Get(q.cursor.index)),
204✔
1344
                (*E)(q.columnE.Get(q.cursor.index)),
204✔
1345
                (*F)(q.columnF.Get(q.cursor.index)),
204✔
1346
                (*G)(q.columnG.Get(q.cursor.index)),
204✔
1347
                (*H)(q.columnH.Get(q.cursor.index))
204✔
1348
}
204✔
1349

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

1355
// Close closes the Query and unlocks the world.
1356
//
1357
// Automatically called when iteration completes.
1358
// Needs to be called only if breaking out of the query iteration or not iterating at all.
1359
func (q *Query8[A, B, C, D, E, F, G, H]) Close() {
13✔
1360
        q.cursor.archetype = -2
13✔
1361
        q.cursor.table = -2
13✔
1362
        q.tables = nil
13✔
1363
        q.table = nil
13✔
1364
        q.cache = nil
13✔
1365
        q.columnA = nil
13✔
1366
        q.columnB = nil
13✔
1367
        q.columnC = nil
13✔
1368
        q.columnD = nil
13✔
1369
        q.columnE = nil
13✔
1370
        q.columnF = nil
13✔
1371
        q.columnG = nil
13✔
1372
        q.columnH = nil
13✔
1373
        q.world.unlock(q.lock)
13✔
1374
}
13✔
1375

1376
func (q *Query8[A, B, C, D, E, F, G, H]) nextTableOrArchetype() bool {
29✔
1377
        if q.cache != nil {
36✔
1378
                return q.nextTable(q.cache.tables)
7✔
1379
        }
7✔
1380
        if q.cursor.archetype >= 0 && q.nextTable(q.tables) {
23✔
1381
                return true
1✔
1382
        }
1✔
1383
        return q.nextArchetype()
21✔
1384
}
1385

1386
func (q *Query8[A, B, C, D, E, F, G, H]) nextArchetype() bool {
21✔
1387
        maxArchIndex := len(q.world.storage.archetypes) - 1
21✔
1388
        for q.cursor.archetype < maxArchIndex {
50✔
1389
                q.cursor.archetype++
29✔
1390
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
29✔
1391
                if !q.filter.matches(&archetype.mask) {
47✔
1392
                        continue
18✔
1393
                }
1394

1395
                if !archetype.HasRelations() {
17✔
1396
                        table := &q.world.storage.tables[archetype.tables[0]]
7✔
1397
                        if table.Len() > 0 {
14✔
1398
                                q.setTable(0, table)
7✔
1399
                                return true
7✔
1400
                        }
7✔
1401
                        continue
×
1402
                }
1403

1404
                q.tables = archetype.GetTables(q.relations)
3✔
1405
                q.cursor.table = -1
3✔
1406
                if q.nextTable(q.tables) {
6✔
1407
                        return true
3✔
1408
                }
3✔
1409
        }
1410
        q.Close()
10✔
1411
        return false
10✔
1412
}
1413

1414
func (q *Query8[A, B, C, D, E, F, G, H]) nextTable(tables []tableID) bool {
21✔
1415
        maxTableIndex := len(tables) - 1
21✔
1416
        for q.cursor.table < maxTableIndex {
33✔
1417
                q.cursor.table++
12✔
1418
                table := &q.world.storage.tables[tables[q.cursor.table]]
12✔
1419
                if table.Len() == 0 {
15✔
1420
                        continue
3✔
1421
                }
1422
                if !table.Matches(q.relations) {
10✔
1423
                        continue
1✔
1424
                }
1425
                q.setTable(q.cursor.table, table)
8✔
1426
                return true
8✔
1427
        }
1428
        if q.cache != nil {
16✔
1429
                q.Close()
3✔
1430
        }
3✔
1431
        return false
13✔
1432
}
1433

1434
func (q *Query8[A, B, C, D, E, F, G, H]) setTable(index int, table *table) {
15✔
1435
        q.cursor.table = index
15✔
1436
        q.table = table
15✔
1437
        q.columnA = q.components[0].columns[q.table.id]
15✔
1438
        q.columnB = q.components[1].columns[q.table.id]
15✔
1439
        q.columnC = q.components[2].columns[q.table.id]
15✔
1440
        q.columnD = q.components[3].columns[q.table.id]
15✔
1441
        q.columnE = q.components[4].columns[q.table.id]
15✔
1442
        q.columnF = q.components[5].columns[q.table.id]
15✔
1443
        q.columnG = q.components[6].columns[q.table.id]
15✔
1444
        q.columnH = q.components[7].columns[q.table.id]
15✔
1445
        q.cursor.index = 0
15✔
1446
        q.cursor.maxIndex = int64(q.table.Len() - 1)
15✔
1447
}
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