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

mlange-42 / arche / 4883995852

04 May 2023 02:28PM CUT coverage: 100.0%. Remained the same
4883995852

push

github

GitHub
Reduce size of `archNode` and `entityIndex` (#268)

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

3679 of 3679 relevant lines covered (100.0%)

103868.19 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
}
19

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

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

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

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

58
        var zeroValue []byte
1,269✔
59
        var zeroPointer unsafe.Pointer
1,269✔
60
        if maxSize > 0 {
2,430✔
61
                zeroValue = make([]byte, maxSize)
1,161✔
62
                zeroPointer = unsafe.Pointer(&zeroValue[0])
1,161✔
63
        }
1,161✔
64

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

1,269✔
72
        return archNode{
1,269✔
73
                nodeData:         data,
1,269✔
74
                Mask:             mask,
1,269✔
75
                TransitionAdd:    newIDMap[*archNode](),
1,269✔
76
                TransitionRemove: newIDMap[*archNode](),
1,269✔
77
                Relation:         relation,
1,269✔
78
        }
1,269✔
79
}
80

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

87
// Archetypes of the node.
88
// Returns a single wrapped archetype if there are no relations.
89
// Returns nil if the node has no archetype(s).
90
func (a *archNode) Archetypes() archetypes {
176,807✔
91
        if a.HasRelation() {
251,895✔
92
                return &a.archetypes
75,088✔
93
        }
75,088✔
94
        if a.archetype == nil {
101,859✔
95
                return nil
140✔
96
        }
140✔
97
        return singleArchetype{Archetype: a.archetype}
101,579✔
98
}
99

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

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

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

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

146
// HasRelation returns whether the node has a relation component.
147
func (a *archNode) HasRelation() bool {
234,310✔
148
        return a.Relation >= 0
234,310✔
149
}
234,310✔
150

151
// Stats generates statistics for an archetype node.
152
func (a *archNode) Stats(reg *componentRegistry[ID]) stats.NodeStats {
13✔
153
        ids := a.Ids
13✔
154
        aCompCount := len(ids)
13✔
155
        aTypes := make([]reflect.Type, aCompCount)
13✔
156
        for j, id := range ids {
24✔
157
                aTypes[j], _ = reg.ComponentType(id)
11✔
158
        }
11✔
159

160
        arches := a.Archetypes()
13✔
161
        var numArches int32
13✔
162
        cap := 0
13✔
163
        count := 0
13✔
164
        memory := 0
13✔
165
        var archStats []stats.ArchetypeStats
13✔
166
        if arches != nil {
25✔
167
                numArches = arches.Len()
12✔
168
                archStats = make([]stats.ArchetypeStats, numArches)
12✔
169
                var i int32
12✔
170
                for i = 0; i < numArches; i++ {
124✔
171
                        archStats[i] = arches.Get(i).Stats(reg)
112✔
172
                        stats := &archStats[i]
112✔
173
                        cap += stats.Capacity
112✔
174
                        count += stats.Size
112✔
175
                        memory += stats.Memory
112✔
176
                }
112✔
177
        }
178

179
        memPerEntity := 0
13✔
180
        for j := range ids {
24✔
181
                memPerEntity += int(aTypes[j].Size())
11✔
182
        }
11✔
183

184
        return stats.NodeStats{
13✔
185
                ArchetypeCount:       int(numArches),
13✔
186
                ActiveArchetypeCount: int(numArches) - len(a.freeIndices),
13✔
187
                IsActive:             a.IsActive,
13✔
188
                HasRelation:          a.HasRelation(),
13✔
189
                Components:           aCompCount,
13✔
190
                ComponentIDs:         ids,
13✔
191
                ComponentTypes:       aTypes,
13✔
192
                Memory:               memory,
13✔
193
                MemoryPerEntity:      memPerEntity,
13✔
194
                Size:                 count,
13✔
195
                Capacity:             cap,
13✔
196
                Archetypes:           archStats,
13✔
197
        }
13✔
198
}
199

200
// UpdateStats updates statistics for an archetype node.
201
func (a *archNode) UpdateStats(stats *stats.NodeStats, reg *componentRegistry[ID]) {
150,022✔
202
        if !a.IsActive {
150,023✔
203
                return
1✔
204
        }
1✔
205

206
        arches := a.Archetypes()
150,021✔
207

150,021✔
208
        if !stats.IsActive {
150,022✔
209
                temp := a.Stats(reg)
1✔
210
                *stats = temp
1✔
211
                return
1✔
212
        }
1✔
213

214
        cap := 0
150,020✔
215
        count := 0
150,020✔
216
        memory := 0
150,020✔
217

150,020✔
218
        cntOld := int32(len(stats.Archetypes))
150,020✔
219
        cntNew := int32(arches.Len())
150,020✔
220
        var i int32
150,020✔
221
        for i = 0; i < cntOld; i++ {
5,249,944✔
222
                arch := &stats.Archetypes[i]
5,099,924✔
223
                arches.Get(i).UpdateStats(stats, arch, reg)
5,099,924✔
224
                cap += arch.Capacity
5,099,924✔
225
                count += arch.Size
5,099,924✔
226
                memory += arch.Memory
5,099,924✔
227
        }
5,099,924✔
228
        for i = cntOld; i < cntNew; i++ {
150,021✔
229
                arch := arches.Get(i).Stats(reg)
1✔
230
                stats.Archetypes = append(stats.Archetypes, arch)
1✔
231
                cap += arch.Capacity
1✔
232
                count += arch.Size
1✔
233
                memory += arch.Memory
1✔
234
        }
1✔
235

236
        stats.IsActive = true
150,020✔
237
        stats.ArchetypeCount = int(cntNew)
150,020✔
238
        stats.ActiveArchetypeCount = int(cntNew) - len(a.freeIndices)
150,020✔
239
        stats.Capacity = cap
150,020✔
240
        stats.Size = count
150,020✔
241
        stats.Memory = memory
150,020✔
242
}
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