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

mlange-42 / arche / 4969448132

13 May 2023 11:51PM CUT coverage: 100.0%. Remained the same
4969448132

push

github

GitHub
Simplify names of XxxQuery methods to XxxQ (#298)

16 of 16 new or added lines in 5 files covered. (100.0%)

3834 of 3834 relevant lines covered (100.0%)

83135.94 hits per line

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

100.0
/ecs/archetype_node.go
1
package ecs
2

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

7
        "github.com/mlange-42/arche/ecs/stats"
8
)
9

10
// archNode is a node in the archetype graph.
11
type archNode struct {
12
        *nodeData
13
        Mask             Mask             // Mask of the archetype
14
        TransitionAdd    idMap[*archNode] // Mapping from component ID to add to the resulting archetype
15
        TransitionRemove idMap[*archNode] // Mapping from component ID to remove to the resulting archetype
16
        Relation         int8             // The node's relation component ID. Negative value stands for no relation
17
        IsActive         bool
18
        HasRelation      bool
19
}
20

21
type nodeData struct {
22
        Ids               []ID                  // List of component IDs
23
        Types             []reflect.Type        // Component type per column
24
        archetype         *archetype            // The single archetype for nodes without entity
25
        archetypes        pagedSlice[archetype] // Storage for archetypes in nodes with entity relation
26
        archetypeMap      map[Entity]*archetype // Mapping from relation targets to archetypes
27
        freeIndices       []int32               // Indices of free/inactive archetypes
28
        zeroValue         []byte                // Used as source for setting storage to zero
29
        zeroPointer       unsafe.Pointer        // Points to zeroValue for fast access
30
        capacityIncrement uint32                // Capacity increment
31
}
32

33
// Creates a new archNode
34
func newArchNode(mask Mask, data *nodeData, relation int8, capacityIncrement int, components []componentType) archNode {
1,286✔
35
        var arch map[Entity]*archetype
1,286✔
36
        if relation >= 0 {
1,319✔
37
                arch = map[Entity]*archetype{}
33✔
38
        }
33✔
39
        ids := make([]ID, len(components))
1,286✔
40
        types := make([]reflect.Type, len(components))
1,286✔
41

1,286✔
42
        var maxSize uintptr = 0
1,286✔
43
        prev := -1
1,286✔
44
        for i, c := range components {
6,650✔
45
                if int(c.ID) <= prev {
5,365✔
46
                        panic("component arguments must be sorted by ID")
1✔
47
                }
48
                prev = int(c.ID)
5,363✔
49

5,363✔
50
                ids[i] = c.ID
5,363✔
51
                types[i] = c.Type
5,363✔
52
                size, align := c.Type.Size(), uintptr(c.Type.Align())
5,363✔
53
                size = (size + (align - 1)) / align * align
5,363✔
54
                if size > maxSize {
6,534✔
55
                        maxSize = size
1,171✔
56
                }
1,171✔
57
        }
58

59
        var zeroValue []byte
1,285✔
60
        var zeroPointer unsafe.Pointer
1,285✔
61
        if maxSize > 0 {
2,454✔
62
                zeroValue = make([]byte, maxSize)
1,169✔
63
                zeroPointer = unsafe.Pointer(&zeroValue[0])
1,169✔
64
        }
1,169✔
65

66
        data.Ids = ids
1,285✔
67
        data.Types = types
1,285✔
68
        data.archetypeMap = arch
1,285✔
69
        data.capacityIncrement = uint32(capacityIncrement)
1,285✔
70
        data.zeroValue = zeroValue
1,285✔
71
        data.zeroPointer = zeroPointer
1,285✔
72

1,285✔
73
        return archNode{
1,285✔
74
                nodeData:         data,
1,285✔
75
                Mask:             mask,
1,285✔
76
                TransitionAdd:    newIDMap[*archNode](),
1,285✔
77
                TransitionRemove: newIDMap[*archNode](),
1,285✔
78
                Relation:         relation,
1,285✔
79
                HasRelation:      relation >= 0,
1,285✔
80
        }
1,285✔
81
}
82

83
// Matches the archetype node against a filter.
84
// Ignores the relation target.
85
func (a *archNode) Matches(f Filter) bool {
76,762✔
86
        return f.Matches(a.Mask)
76,762✔
87
}
76,762✔
88

89
// Archetypes of the node.
90
// Returns a single wrapped archetype if there are no relations.
91
// Returns nil if the node has no archetype(s).
92
func (a *archNode) Archetypes() archetypes {
150,591✔
93
        if a.archetype == nil {
200,657✔
94
                return &a.archetypes
50,066✔
95
        }
50,066✔
96
        return singleArchetype{Archetype: a.archetype}
100,525✔
97
}
98

99
// GetArchetype returns the archetype for the given relation target.
100
//
101
// The target is ignored if the node has no relation component.
102
func (a *archNode) GetArchetype(target Entity) *archetype {
60,781✔
103
        if a.Relation >= 0 {
93,795✔
104
                return a.archetypeMap[target]
33,014✔
105
        }
33,014✔
106
        return a.archetype
27,767✔
107
}
108

109
// SetArchetype sets the archetype for a node without a relation.
110
//
111
// Do not use on nodes without a relation component!
112
func (a *archNode) SetArchetype(arch *archetype) {
1,213✔
113
        a.archetype = arch
1,213✔
114
}
1,213✔
115

116
// CreateArchetype creates a new archetype in nodes with relation component.
117
func (a *archNode) CreateArchetype(target Entity) *archetype {
27,584✔
118
        var arch *archetype
27,584✔
119
        var archIndex int32
27,584✔
120
        lenFree := len(a.freeIndices)
27,584✔
121
        if lenFree > 0 {
54,988✔
122
                archIndex = a.freeIndices[lenFree-1]
27,404✔
123
                arch = a.archetypes.Get(archIndex)
27,404✔
124
                a.freeIndices = a.freeIndices[:lenFree-1]
27,404✔
125
                arch.Activate(target, archIndex)
27,404✔
126
        } else {
27,584✔
127
                a.archetypes.Add(archetype{})
180✔
128
                archIndex := a.archetypes.Len() - 1
180✔
129
                arch = a.archetypes.Get(archIndex)
180✔
130
                arch.Init(a, archIndex, true, target)
180✔
131
        }
180✔
132
        a.archetypeMap[target] = arch
27,584✔
133
        return arch
27,584✔
134
}
135

136
// RemoveArchetype de-activates an archetype.
137
// The archetype will be re-used by CreateArchetype.
138
func (a *archNode) RemoveArchetype(arch *archetype) {
27,427✔
139
        delete(a.archetypeMap, arch.RelationTarget)
27,427✔
140
        idx := arch.index
27,427✔
141
        a.freeIndices = append(a.freeIndices, idx)
27,427✔
142
        a.archetypes.Get(idx).Deactivate()
27,427✔
143
}
27,427✔
144

145
// Reset resets the archetypes in this node.
146
// Relation archetypes with non-zero target are de-activated for re-use.
147
func (a *archNode) Reset(cache *Cache) {
97✔
148
        if !a.IsActive {
102✔
149
                return
5✔
150
        }
5✔
151
        if !a.HasRelation {
156✔
152
                a.archetype.Reset()
64✔
153
                return
64✔
154
        }
64✔
155

156
        lenArches := a.archetypes.Len()
28✔
157
        var j int32
28✔
158
        for j = 0; j < lenArches; j++ {
2,439✔
159
                arch := a.archetypes.Get(j)
2,411✔
160
                if !arch.IsActive() {
2,413✔
161
                        continue
2✔
162
                }
163
                if !arch.RelationTarget.IsZero() {
4,816✔
164
                        a.RemoveArchetype(arch)
2,407✔
165
                        cache.removeArchetype(arch)
2,407✔
166
                } else {
2,409✔
167
                        arch.Reset()
2✔
168
                }
2✔
169
        }
170
}
171

172
// Stats generates statistics for an archetype node.
173
func (a *archNode) Stats(reg *componentRegistry[ID]) stats.NodeStats {
13✔
174
        ids := a.Ids
13✔
175
        aCompCount := len(ids)
13✔
176
        aTypes := make([]reflect.Type, aCompCount)
13✔
177
        for j, id := range ids {
24✔
178
                aTypes[j], _ = reg.ComponentType(id)
11✔
179
        }
11✔
180

181
        arches := a.Archetypes()
13✔
182
        var numArches int32
13✔
183
        cap := 0
13✔
184
        count := 0
13✔
185
        memory := 0
13✔
186
        var archStats []stats.ArchetypeStats
13✔
187
        if arches != nil {
26✔
188
                numArches = arches.Len()
13✔
189
                archStats = make([]stats.ArchetypeStats, numArches)
13✔
190
                var i int32
13✔
191
                for i = 0; i < numArches; i++ {
125✔
192
                        archStats[i] = arches.Get(i).Stats(reg)
112✔
193
                        stats := &archStats[i]
112✔
194
                        cap += stats.Capacity
112✔
195
                        count += stats.Size
112✔
196
                        memory += stats.Memory
112✔
197
                }
112✔
198
        }
199

200
        memPerEntity := 0
13✔
201
        for j := range ids {
24✔
202
                memPerEntity += int(aTypes[j].Size())
11✔
203
        }
11✔
204

205
        return stats.NodeStats{
13✔
206
                ArchetypeCount:       int(numArches),
13✔
207
                ActiveArchetypeCount: int(numArches) - len(a.freeIndices),
13✔
208
                IsActive:             a.IsActive,
13✔
209
                HasRelation:          a.HasRelation,
13✔
210
                Components:           aCompCount,
13✔
211
                ComponentIDs:         ids,
13✔
212
                ComponentTypes:       aTypes,
13✔
213
                Memory:               memory,
13✔
214
                MemoryPerEntity:      memPerEntity,
13✔
215
                Size:                 count,
13✔
216
                Capacity:             cap,
13✔
217
                Archetypes:           archStats,
13✔
218
        }
13✔
219
}
220

221
// UpdateStats updates statistics for an archetype node.
222
func (a *archNode) UpdateStats(stats *stats.NodeStats, reg *componentRegistry[ID]) {
150,022✔
223
        if !a.IsActive {
150,023✔
224
                return
1✔
225
        }
1✔
226

227
        arches := a.Archetypes()
150,021✔
228

150,021✔
229
        if !stats.IsActive {
150,022✔
230
                temp := a.Stats(reg)
1✔
231
                *stats = temp
1✔
232
                return
1✔
233
        }
1✔
234

235
        cap := 0
150,020✔
236
        count := 0
150,020✔
237
        memory := 0
150,020✔
238

150,020✔
239
        cntOld := int32(len(stats.Archetypes))
150,020✔
240
        cntNew := int32(arches.Len())
150,020✔
241
        var i int32
150,020✔
242
        for i = 0; i < cntOld; i++ {
5,249,944✔
243
                arch := &stats.Archetypes[i]
5,099,924✔
244
                arches.Get(i).UpdateStats(stats, arch, reg)
5,099,924✔
245
                cap += arch.Capacity
5,099,924✔
246
                count += arch.Size
5,099,924✔
247
                memory += arch.Memory
5,099,924✔
248
        }
5,099,924✔
249
        for i = cntOld; i < cntNew; i++ {
150,021✔
250
                arch := arches.Get(i).Stats(reg)
1✔
251
                stats.Archetypes = append(stats.Archetypes, arch)
1✔
252
                cap += arch.Capacity
1✔
253
                count += arch.Size
1✔
254
                memory += arch.Memory
1✔
255
        }
1✔
256

257
        stats.IsActive = true
150,020✔
258
        stats.ArchetypeCount = int(cntNew)
150,020✔
259
        stats.ActiveArchetypeCount = int(cntNew) - len(a.freeIndices)
150,020✔
260
        stats.Capacity = cap
150,020✔
261
        stats.Size = count
150,020✔
262
        stats.Memory = memory
150,020✔
263
}
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