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

mlange-42 / ark / 14191219880

01 Apr 2025 08:44AM CUT coverage: 99.832%. Remained the same
14191219880

push

github

web-flow
Add awesome-go badge (#229)

8298 of 8312 relevant lines covered (99.83%)

20284.26 hits per line

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

98.72
/ecs/query.go
1
package ecs
2

3
import "unsafe"
4

5
// UnsafeQuery is an unsafe query.
6
// It is significantly slower than type-safe generic queries like [Query2],
7
// and should only be used when component types are not known at compile time.
8
type UnsafeQuery struct {
9
        world     *World
10
        table     *table
11
        relations []RelationID
12
        tables    []tableID
13
        filter    filter
14
        cursor    cursor
15
        lock      uint8
16
}
17

18
// Next advances the query's cursor to the next entity.
19
func (q *UnsafeQuery) Next() bool {
285✔
20
        q.cursor.checkQueryNext()
285✔
21
        if int64(q.cursor.index) < q.cursor.maxIndex {
549✔
22
                q.cursor.index++
264✔
23
                return true
264✔
24
        }
264✔
25
        return q.nextTableOrArchetype()
21✔
26
}
27

28
// Entity returns the current entity.
29
func (q *UnsafeQuery) Entity() Entity {
76✔
30
        q.cursor.checkQueryGet()
76✔
31
        return q.table.GetEntity(q.cursor.index)
76✔
32
}
76✔
33

34
// Get returns the queried components of the current entity.
35
//
36
// ⚠️ Do not store the obtained pointer outside of the current context (i.e. the query loop)!
37
func (q *UnsafeQuery) Get(comp ID) unsafe.Pointer {
72✔
38
        q.cursor.checkQueryGet()
72✔
39
        return q.table.Get(comp, uintptr(q.cursor.index))
72✔
40
}
72✔
41

42
// Has returns whether the current entity has the given component.
43
func (q *UnsafeQuery) Has(comp ID) bool {
40✔
44
        return q.table.Has(comp)
40✔
45
}
40✔
46

47
// GetRelation returns the entity relation target of the component at the given index.
48
func (q *UnsafeQuery) GetRelation(comp ID) Entity {
10✔
49
        return q.table.GetRelation(comp)
10✔
50
}
10✔
51

52
// Count returns the number of entities matching this query.
53
func (q *UnsafeQuery) Count() int {
10✔
54
        return countQuery(&q.world.storage, &q.filter, q.relations)
10✔
55
}
10✔
56

57
// IDs returns the IDs of all component of the current [Entity]n.
58
func (q *UnsafeQuery) IDs() IDs {
10✔
59
        return newIDs(q.table.ids)
10✔
60
}
10✔
61

62
// Close closes the Query and unlocks the world.
63
//
64
// Automatically called when iteration completes.
65
// Needs to be called only if breaking out of the query iteration or not iterating at all.
66
func (q *UnsafeQuery) Close() {
14✔
67
        q.cursor.archetype = -2
14✔
68
        q.cursor.table = -2
14✔
69
        q.tables = nil
14✔
70
        q.table = nil
14✔
71
        q.world.unlock(q.lock)
14✔
72
}
14✔
73

74
func (q *UnsafeQuery) nextTableOrArchetype() bool {
21✔
75
        if q.cursor.archetype >= 0 && q.nextTable() {
22✔
76
                return true
1✔
77
        }
1✔
78
        return q.nextArchetype()
20✔
79
}
80

81
func (q *UnsafeQuery) nextArchetype() bool {
20✔
82
        maxArchIndex := int32(len(q.world.storage.archetypes) - 1)
20✔
83
        for q.cursor.archetype < maxArchIndex {
43✔
84
                q.cursor.archetype++
23✔
85
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
23✔
86
                if !q.filter.matches(archetype.mask) {
35✔
87
                        continue
12✔
88
                }
89

90
                if !archetype.HasRelations() {
18✔
91
                        table := &q.world.storage.tables[archetype.tables[0]]
8✔
92
                        if table.Len() > 0 {
15✔
93
                                q.setTable(0, table)
7✔
94
                                return true
7✔
95
                        }
7✔
96
                        continue
1✔
97
                }
98

99
                q.tables = archetype.GetTables(q.relations)
2✔
100
                q.cursor.table = -1
2✔
101
                if q.nextTable() {
4✔
102
                        return true
2✔
103
                }
2✔
104
        }
105
        q.Close()
10✔
106
        return false
10✔
107
}
108

109
func (q *UnsafeQuery) nextTable() bool {
12✔
110
        maxTableIndex := int32(len(q.tables) - 1)
12✔
111
        for q.cursor.table < maxTableIndex {
16✔
112
                q.cursor.table++
4✔
113
                table := &q.world.storage.tables[q.tables[q.cursor.table]]
4✔
114
                if table.Len() == 0 {
5✔
115
                        continue
1✔
116
                }
117
                if !table.Matches(q.relations) {
3✔
118
                        continue
×
119
                }
120
                q.setTable(q.cursor.table, table)
3✔
121
                return true
3✔
122
        }
123
        return false
9✔
124
}
125

126
func (q *UnsafeQuery) setTable(index int32, table *table) {
10✔
127
        q.cursor.table = index
10✔
128
        q.table = table
10✔
129
        q.cursor.index = 0
10✔
130
        q.cursor.maxIndex = int64(q.table.Len() - 1)
10✔
131
}
10✔
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