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

mlange-42 / ark / 13604663297

01 Mar 2025 12:16PM CUT coverage: 94.752% (-2.3%) from 97.025%
13604663297

Pull #83

github

web-flow
Merge ca5080db9 into 3013a616a
Pull Request #83: Add functionality required for (de)-serialization

19 of 112 new or added lines in 4 files covered. (16.96%)

3737 of 3944 relevant lines covered (94.75%)

47657.17 hits per line

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

94.34
/ecs/query.go
1
package ecs
2

3
import "unsafe"
4

5
// Query is an unsafe query.
6
type Query struct {
7
        world     *World
8
        filter    Filter
9
        relations []RelationID
10
        lock      uint8
11
        cursor    cursor
12
        tables    []tableID
13
        table     *table
14
}
15

16
func newQuery(world *World, filter Filter, relations []RelationID) Query {
6✔
17
        return Query{
6✔
18
                world:     world,
6✔
19
                filter:    filter,
6✔
20
                relations: relations,
6✔
21
                lock:      world.lock(),
6✔
22
                cursor: cursor{
6✔
23
                        archetype: -1,
6✔
24
                        table:     -1,
6✔
25
                        index:     0,
6✔
26
                        maxIndex:  -1,
6✔
27
                },
6✔
28
        }
6✔
29
}
6✔
30

31
// Next advances the query's cursor to the next entity.
32
func (q *Query) Next() bool {
77✔
33
        q.world.checkQueryNext(&q.cursor)
77✔
34
        if int64(q.cursor.index) < q.cursor.maxIndex {
140✔
35
                q.cursor.index++
63✔
36
                return true
63✔
37
        }
63✔
38
        return q.nextTableOrArchetype()
14✔
39
}
40

41
// Entity returns the current entity.
42
func (q *Query) Entity() Entity {
72✔
43
        q.world.checkQueryGet(&q.cursor)
72✔
44
        return q.table.GetEntity(q.cursor.index)
72✔
45
}
72✔
46

47
// Get returns the queried components of the current entity.
48
func (q *Query) Get(comp ID) unsafe.Pointer {
72✔
49
        q.world.checkQueryGet(&q.cursor)
72✔
50
        return q.table.Get(comp, uintptr(q.cursor.index))
72✔
51
}
72✔
52

53
// Has returns whether the current entity has the given component.
54
func (q *Query) Has(comp ID) bool {
40✔
55
        return q.table.Has(comp)
40✔
56
}
40✔
57

58
// GetRelation returns the entity relation target of the component at the given index.
59
func (q *Query) GetRelation(comp ID) Entity {
10✔
60
        return q.table.GetRelation(comp)
10✔
61
}
10✔
62

63
// Count returns the number of entities matching this query.
64
func (q *Query) Count() int {
6✔
65
        count := 0
6✔
66
        for i := range q.world.storage.archetypes {
24✔
67
                archetype := &q.world.storage.archetypes[i]
18✔
68
                if !q.filter.matches(&archetype.mask) {
30✔
69
                        continue
12✔
70
                }
71

72
                if !archetype.HasRelations() {
10✔
73
                        table := &q.world.storage.tables[archetype.tables[0]]
4✔
74
                        count += table.Len()
4✔
75
                        continue
4✔
76
                }
77

78
                tables := archetype.GetTables(q.relations)
2✔
79
                for _, tab := range tables {
6✔
80
                        table := &q.world.storage.tables[tab]
4✔
81
                        if !table.Matches(q.relations) {
4✔
NEW
82
                                continue
×
83
                        }
84
                        count += table.Len()
4✔
85
                }
86
        }
87
        return count
6✔
88
}
89

90
// IDs returns the component IDs for the archetype of the [Entity] at the iterator's current position.
91
//
92
// Returns a copy of the archetype's component IDs slice, for safety.
93
// This means that the result can be manipulated safely,
94
// but also that calling the method may incur some significant cost.
NEW
95
func (q *Query) IDs() []ID {
×
NEW
96
        return append([]ID{}, q.table.ids...)
×
NEW
97
}
×
98

99
// Close closes the Query and unlocks the world.
100
//
101
// Automatically called when iteration finishes.
102
// Needs to be called only if breaking out of the query iteration or not iterating at all.
103
func (q *Query) Close() {
6✔
104
        q.cursor.archetype = -2
6✔
105
        q.cursor.table = -2
6✔
106
        q.tables = nil
6✔
107
        q.table = nil
6✔
108
        q.world.unlock(q.lock)
6✔
109
}
6✔
110

111
func (q *Query) nextTableOrArchetype() bool {
14✔
112
        if q.cursor.archetype >= 0 && q.nextTable() {
15✔
113
                return true
1✔
114
        }
1✔
115
        return q.nextArchetype()
13✔
116
}
117

118
func (q *Query) nextArchetype() bool {
13✔
119
        maxArchIndex := len(q.world.storage.archetypes) - 1
13✔
120
        for q.cursor.archetype < maxArchIndex {
32✔
121
                q.cursor.archetype++
19✔
122
                archetype := &q.world.storage.archetypes[q.cursor.archetype]
19✔
123
                if !q.filter.matches(&archetype.mask) {
31✔
124
                        continue
12✔
125
                }
126

127
                if !archetype.HasRelations() {
10✔
128
                        table := &q.world.storage.tables[archetype.tables[0]]
4✔
129
                        if table.Len() > 0 {
8✔
130
                                q.setTable(0, table)
4✔
131
                                return true
4✔
132
                        }
4✔
133
                        continue
×
134
                }
135

136
                q.tables = archetype.GetTables(q.relations)
2✔
137
                q.cursor.table = -1
2✔
138
                if q.nextTable() {
4✔
139
                        return true
2✔
140
                }
2✔
141
        }
142
        q.Close()
6✔
143
        return false
6✔
144
}
145

146
func (q *Query) nextTable() bool {
9✔
147
        maxTableIndex := len(q.tables) - 1
9✔
148
        for q.cursor.table < maxTableIndex {
13✔
149
                q.cursor.table++
4✔
150
                table := &q.world.storage.tables[q.tables[q.cursor.table]]
4✔
151
                if table.Len() == 0 {
5✔
152
                        continue
1✔
153
                }
154
                if !table.Matches(q.relations) {
3✔
155
                        continue
×
156
                }
157
                q.setTable(q.cursor.table, table)
3✔
158
                return true
3✔
159
        }
160
        return false
6✔
161
}
162

163
func (q *Query) setTable(index int, table *table) {
7✔
164
        q.cursor.table = index
7✔
165
        q.table = table
7✔
166
        q.cursor.index = 0
7✔
167
        q.cursor.maxIndex = int64(q.table.entities.Len() - 1)
7✔
168
}
7✔
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