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

mlange-42 / ark / 13595480058

28 Feb 2025 07:53PM CUT coverage: 96.821% (-0.06%) from 96.882%
13595480058

Pull #81

github

web-flow
Merge 310e5e240 into 9b17c8beb
Pull Request #81: Unsafe API

19 of 22 new or added lines in 2 files covered. (86.36%)

39 existing lines in 3 files now uncovered.

3594 of 3712 relevant lines covered (96.82%)

49525.14 hits per line

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

90.85
/ecs/world_internal.go
1
package ecs
2

3
import (
4
        "reflect"
5
        "unsafe"
6
)
7

8
func (w *World) newEntityWith(ids []ID, comps []unsafe.Pointer, relations []RelationID) Entity {
495,789✔
9
        w.checkLocked()
495,789✔
10

495,789✔
11
        mask := All(ids...)
495,789✔
12
        newTable := w.storage.findOrCreateTable(&w.storage.tables[0], &mask, relations)
495,789✔
13
        entity, idx := w.storage.createEntity(newTable.id)
495,789✔
14

495,789✔
15
        if comps != nil {
991,576✔
16
                if len(ids) != len(comps) {
495,787✔
17
                        panic("lengths of IDs and components to add do not match")
×
18
                }
19
                for i, id := range ids {
994,528✔
20
                        newTable.Set(id, idx, comps[i])
498,741✔
21
                }
498,741✔
22
        }
23
        w.storage.registerTargets(relations)
495,789✔
24
        return entity
495,789✔
25
}
26

27
func (w *World) newEntitiesWith(count int, ids []ID, comps []unsafe.Pointer, relations []RelationID) {
8✔
28
        w.checkLocked()
8✔
29

8✔
30
        mask := All(ids...)
8✔
31
        newTable := w.storage.findOrCreateTable(&w.storage.tables[0], &mask, relations)
8✔
32

8✔
33
        startIdx := newTable.Len()
8✔
34
        w.storage.createEntities(newTable, count)
8✔
35

8✔
36
        if comps != nil {
16✔
37
                if len(ids) != len(comps) {
8✔
38
                        panic("lengths of IDs and components to add do not match")
×
39
                }
40
                for i := range count {
200✔
41
                        for j, id := range ids {
1,056✔
42
                                newTable.Set(id, uint32(startIdx+i), comps[j])
864✔
43
                        }
864✔
44
                }
45
        }
46
        w.storage.registerTargets(relations)
8✔
47
}
48

49
func (w *World) newEntities(count int, ids []ID, relations []RelationID) (tableID, int) {
8✔
50
        w.checkLocked()
8✔
51

8✔
52
        mask := All(ids...)
8✔
53
        newTable := w.storage.findOrCreateTable(&w.storage.tables[0], &mask, relations)
8✔
54

8✔
55
        startIdx := newTable.Len()
8✔
56
        w.storage.createEntities(newTable, count)
8✔
57
        w.storage.registerTargets(relations)
8✔
58

8✔
59
        return newTable.id, startIdx
8✔
60
}
8✔
61

62
func (w *World) get(entity Entity, component ID) unsafe.Pointer {
3✔
63
        if !w.storage.entityPool.Alive(entity) {
3✔
UNCOV
64
                panic("can't get component of a dead entity")
×
65
        }
66
        return w.getUnchecked(entity, component)
3✔
67
}
68

69
func (w *World) getUnchecked(entity Entity, component ID) unsafe.Pointer {
4✔
70
        index := w.storage.entities[entity.id]
4✔
71
        return w.storage.tables[index.table].Get(component, uintptr(index.row))
4✔
72
}
4✔
73

74
func (w *World) has(entity Entity, component ID) bool {
10✔
75
        if !w.storage.entityPool.Alive(entity) {
10✔
UNCOV
76
                panic("can't get component of a dead entity")
×
77
        }
78
        return w.hasUnchecked(entity, component)
10✔
79
}
80

81
func (w *World) hasUnchecked(entity Entity, component ID) bool {
12✔
82
        index := w.storage.entities[entity.id]
12✔
83
        return w.storage.tables[index.table].Has(component)
12✔
84
}
12✔
85

86
func (w *World) exchange(entity Entity, add []ID, rem []ID, addComps []unsafe.Pointer, relations []RelationID) {
612✔
87
        w.checkLocked()
612✔
88

612✔
89
        if !w.Alive(entity) {
612✔
UNCOV
90
                panic("can't exchange components on a dead entity")
×
91
        }
92
        if len(add) == 0 && len(rem) == 0 {
612✔
UNCOV
93
                return
×
UNCOV
94
        }
×
95

96
        index := &w.storage.entities[entity.id]
612✔
97
        oldTable := &w.storage.tables[index.table]
612✔
98
        oldArchetype := &w.storage.archetypes[oldTable.archetype]
612✔
99

612✔
100
        mask := oldArchetype.mask
612✔
101
        w.storage.getExchangeMask(&mask, add, rem)
612✔
102

612✔
103
        oldIDs := oldArchetype.components
612✔
104

612✔
105
        newTable := w.storage.findOrCreateTable(oldTable, &mask, relations)
612✔
106
        newIndex := newTable.Add(entity)
612✔
107

612✔
108
        for _, id := range oldIDs {
2,252✔
109
                if mask.Get(id) {
2,302✔
110
                        comp := oldTable.Get(id, uintptr(index.row))
662✔
111
                        newTable.Set(id, newIndex, comp)
662✔
112
                }
662✔
113
        }
114
        if addComps != nil {
939✔
115
                if len(add) != len(addComps) {
327✔
UNCOV
116
                        panic("lengths of IDs and components to add do not match")
×
117
                }
118
                for i, id := range add {
1,046✔
119
                        newTable.Set(id, newIndex, addComps[i])
719✔
120
                }
719✔
121
        }
122

123
        swapped := oldTable.Remove(index.row)
612✔
124

612✔
125
        if swapped {
710✔
126
                swapEntity := oldTable.GetEntity(uintptr(index.row))
98✔
127
                w.storage.entities[swapEntity.id].row = index.row
98✔
128
        }
98✔
129
        w.storage.entities[entity.id] = entityIndex{table: newTable.id, row: newIndex}
612✔
130

612✔
131
        w.storage.registerTargets(relations)
612✔
132
}
133

134
// setRelations sets the target entities for an entity relations.
135
func (w *World) setRelations(entity Entity, relations []RelationID) {
42✔
136
        w.checkLocked()
42✔
137

42✔
138
        if !w.storage.entityPool.Alive(entity) {
42✔
UNCOV
139
                panic("can't set relation for a dead entity")
×
140
        }
141

142
        index := &w.storage.entities[entity.id]
42✔
143
        oldTable := &w.storage.tables[index.table]
42✔
144

42✔
145
        newRelations, changed := w.storage.getExchangeTargets(oldTable, relations)
42✔
146
        if !changed {
42✔
UNCOV
147
                return
×
UNCOV
148
        }
×
149

150
        oldArch := &w.storage.archetypes[oldTable.archetype]
42✔
151
        newTable, ok := oldArch.GetTable(&w.storage, newRelations)
42✔
152
        if !ok {
53✔
153
                newTable = w.storage.createTable(oldArch, newRelations)
11✔
154
        }
11✔
155
        newIndex := newTable.Add(entity)
42✔
156

42✔
157
        for _, id := range oldArch.components {
145✔
158
                comp := oldTable.Get(id, uintptr(index.row))
103✔
159
                newTable.Set(id, newIndex, comp)
103✔
160
        }
103✔
161

162
        swapped := oldTable.Remove(index.row)
42✔
163

42✔
164
        if swapped {
58✔
165
                swapEntity := oldTable.GetEntity(uintptr(index.row))
16✔
166
                w.storage.entities[swapEntity.id].row = index.row
16✔
167
        }
16✔
168
        w.storage.entities[entity.id] = entityIndex{table: newTable.id, row: newIndex}
42✔
169

42✔
170
        w.storage.registerTargets(relations)
42✔
171
}
172

173
func (w *World) componentID(tp reflect.Type) ID {
1,941✔
174
        id, newID := w.storage.registry.ComponentID(tp)
1,941✔
175
        if newID {
2,400✔
176
                if w.IsLocked() {
459✔
UNCOV
177
                        w.storage.registry.unregisterLastComponent()
×
UNCOV
178
                        panic("attempt to register a new component in a locked world")
×
179
                }
180
                w.storage.AddComponent(id)
459✔
181
        }
182
        return ID{id: id}
1,941✔
183
}
184

185
func (w *World) resourceID(tp reflect.Type) ResID {
3✔
186
        id, _ := w.resources.registry.ComponentID(tp)
3✔
187
        return ResID{id: id}
3✔
188
}
3✔
189

190
// lock the world and get the lock bit for later unlocking.
191
func (w *World) lock() uint8 {
1,084✔
192
        return w.locks.Lock()
1,084✔
193
}
1,084✔
194

195
// unlock unlocks the given lock bit.
196
func (w *World) unlock(l uint8) {
1,084✔
197
        w.locks.Unlock(l)
1,084✔
198
}
1,084✔
199

200
// checkLocked checks if the world is locked, and panics if so.
201
func (w *World) checkLocked() {
991,424✔
202
        if w.IsLocked() {
991,424✔
UNCOV
203
                panic("attempt to modify a locked world")
×
204
        }
205
}
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