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

mlange-42 / ark / 13636797181

03 Mar 2025 05:30PM CUT coverage: 97.422% (-0.3%) from 97.712%
13636797181

Pull #114

github

web-flow
Merge 74bc98fa8 into 0dcd540e6
Pull Request #114: Filter caching

426 of 470 new or added lines in 9 files covered. (90.64%)

41 existing lines in 4 files now uncovered.

5592 of 5740 relevant lines covered (97.42%)

35229.13 hits per line

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

97.5
/ecs/archetype.go
1
package ecs
2

3
import (
4
        "math"
5
        "slices"
6
)
7

8
type archetypeID uint32
9

10
// maxArchetypeID is used as unassigned archetype ID.
11
const maxArchetypeID = math.MaxUint32
12

13
type archetype struct {
14
        id             archetypeID
15
        node           nodeID
16
        mask           Mask
17
        components     []ID                     // components IDs of the archetype in arbitrary order
18
        componentsMap  []int16                  // mapping from component IDs to column indices; -1 indicates none
19
        isRelation     []bool                   // whether columns are relations components, indexed by column index
20
        relationTables []map[entityID]*tableIDs // lookup for relation targets of tables, indexed by column index
21
        tables         []tableID                // all active tables
22
        freeTables     []tableID                // all inactive/free tables
23
        numRelations   uint8                    // number of relation components
24
}
25

26
type tableIDs struct {
27
        tables []tableID
28
}
29

30
func newArchetype(id archetypeID, node nodeID, mask *Mask, components []ID, tables []tableID, reg *componentRegistry) archetype {
573✔
31
        componentsMap := make([]int16, MaskTotalBits)
573✔
32
        for i := range MaskTotalBits {
147,261✔
33
                componentsMap[i] = -1
146,688✔
34
        }
146,688✔
35
        for i, id := range components {
1,983✔
36
                componentsMap[id.id] = int16(i)
1,410✔
37
        }
1,410✔
38

39
        numRelations := uint8(0)
573✔
40
        isRelation := make([]bool, len(components))
573✔
41
        relationTables := make([]map[entityID]*tableIDs, len(components))
573✔
42
        for i, id := range components {
1,983✔
43
                if reg.IsRelation[id.id] {
1,458✔
44
                        isRelation[i] = true
48✔
45
                        relationTables[i] = map[entityID]*tableIDs{}
48✔
46
                        numRelations++
48✔
47
                }
48✔
48
        }
49
        return archetype{
573✔
50
                id:             id,
573✔
51
                node:           node,
573✔
52
                mask:           *mask,
573✔
53
                components:     components,
573✔
54
                componentsMap:  componentsMap,
573✔
55
                isRelation:     isRelation,
573✔
56
                tables:         tables,
573✔
57
                numRelations:   numRelations,
573✔
58
                relationTables: relationTables,
573✔
59
        }
573✔
60
}
61

62
func (a *archetype) HasRelations() bool {
507,062✔
63
        return a.numRelations > 0
507,062✔
64
}
507,062✔
65

66
func (a *archetype) GetTable(storage *storage, relations []RelationID) (*table, bool) {
504,552✔
67
        if len(a.tables) == 0 {
504,938✔
68
                return nil, false
386✔
69
        }
386✔
70
        if !a.HasRelations() {
1,007,674✔
71
                return &storage.tables[a.tables[0]], true
503,508✔
72
        }
503,508✔
73

74
        index := a.componentsMap[relations[0].component.id]
658✔
75
        tables, ok := a.relationTables[index][relations[0].target.id]
658✔
76
        if !ok {
729✔
77
                return nil, false
71✔
78
        }
71✔
79
        for _, t := range tables.tables {
1,193✔
80
                table := &storage.tables[t]
606✔
81
                if table.MatchesExact(relations) {
1,191✔
82
                        return table, true
585✔
83
                }
585✔
84
        }
85
        return nil, false
2✔
86
}
87

88
func (a *archetype) GetTables(relations []RelationID) []tableID {
87✔
89
        if !a.HasRelations() {
87✔
90
                return a.tables
×
91
        }
×
92
        if len(relations) == 0 {
118✔
93
                return a.tables
31✔
94
        }
31✔
95
        index := a.componentsMap[relations[0].component.id]
56✔
96
        if tables, ok := a.relationTables[index][relations[0].target.id]; ok {
112✔
97
                return tables.tables
56✔
98
        }
56✔
99
        return nil
×
100
}
101

102
func (a *archetype) GetFreeTable() (tableID, bool) {
459✔
103
        if len(a.freeTables) == 0 {
917✔
104
                return 0, false
458✔
105
        }
458✔
106
        last := len(a.freeTables) - 1
1✔
107
        table := a.freeTables[last]
1✔
108

1✔
109
        a.freeTables = a.freeTables[:last]
1✔
110

1✔
111
        return table, true
1✔
112
}
113

114
func (a *archetype) FreeTable(table tableID) {
4✔
115
        // TODO: can we speed this up for large numbers of relation targets?
4✔
116
        index := slices.Index(a.tables, table)
4✔
117
        last := len(a.tables) - 1
4✔
118

4✔
119
        a.tables[index], a.tables[last] = a.tables[last], a.tables[index]
4✔
120
        a.tables = a.tables[:last]
4✔
121

4✔
122
        a.freeTables = append(a.freeTables, table)
4✔
123
}
4✔
124

125
func (a *archetype) AddTable(table *table) {
459✔
126
        a.tables = append(a.tables, table.id)
459✔
127
        if !a.HasRelations() {
800✔
128
                return
341✔
129
        }
341✔
130

131
        for i := range table.ids {
579✔
132
                column := &table.columns[i]
461✔
133
                if !column.isRelation {
796✔
134
                        continue
335✔
135
                }
136
                target := column.target
126✔
137
                relations := a.relationTables[i]
126✔
138

126✔
139
                if tables, ok := relations[target.id]; ok {
131✔
140
                        tables.tables = append(tables.tables, table.id)
5✔
141
                } else {
126✔
142
                        relations[target.id] = &tableIDs{tables: []tableID{table.id}}
121✔
143
                }
121✔
144
        }
145
}
146

147
func (a *archetype) RemoveTarget(entity Entity) {
2✔
148
        for i := range a.relationTables {
6✔
149
                if !a.isRelation[i] {
6✔
150
                        continue
2✔
151
                }
152
                delete(a.relationTables[i], entity.id)
2✔
153
        }
154
}
155

156
func (a *archetype) Reset(storage *storage) {
4✔
157
        if !a.HasRelations() {
7✔
158
                storage.tables[a.tables[0]].Reset()
3✔
159
                return
3✔
160
        }
3✔
161

162
        for _, tab := range a.tables {
3✔
163
                table := &storage.tables[tab]
2✔
164
                table.Reset()
2✔
165
        }
2✔
166

167
        for i := len(a.tables) - 1; i >= 0; i-- {
3✔
168
                storage.cache.removeTable(storage, &storage.tables[a.tables[i]])
2✔
169
                a.FreeTable(a.tables[i])
2✔
170
        }
2✔
171

172
        for _, m := range a.relationTables {
3✔
173
                for key := range m {
4✔
174
                        delete(m, key)
2✔
175
                }
2✔
176
        }
177
}
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