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

mlange-42 / ark / 13639292298

03 Mar 2025 07:56PM CUT coverage: 98.495%. Remained the same
13639292298

push

github

web-flow
Optimize matching of tables against relations (#115)

1 of 1 new or added line in 1 file covered. (100.0%)

5694 of 5781 relevant lines covered (98.5%)

34789.79 hits per line

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

93.65
/ecs/map.go
1
package ecs
2

3
import "unsafe"
4

5
// Map is a mapper to access and manipulate components of an entity.
6
type Map[T any] struct {
7
        world     *World
8
        id        ID
9
        storage   *componentStorage
10
        relations []RelationID
11
}
12

13
// NewMap creates a new [Map].
14
func NewMap[T any](w *World) Map[T] {
45✔
15
        id := ComponentID[T](w)
45✔
16
        return Map[T]{
45✔
17
                world:   w,
45✔
18
                id:      id,
45✔
19
                storage: &w.storage.components[id.id],
45✔
20
        }
45✔
21
}
45✔
22

23
// NewEntity creates a new entity with the mapped component.
24
func (m *Map[T]) NewEntity(comp *T, rel ...Entity) Entity {
501,592✔
25
        m.relations = relationEntities(rel).toRelation(m.id, m.relations)
501,592✔
26
        return m.world.newEntityWith([]ID{m.id}, []unsafe.Pointer{unsafe.Pointer(comp)}, m.relations)
501,592✔
27
}
501,592✔
28

29
// Get returns the mapped component for the given entity.
30
func (m *Map[T]) Get(entity Entity) *T {
501,592✔
31
        if !m.world.Alive(entity) {
501,592✔
32
                panic("can't get a component of a dead entity")
×
33
        }
34
        return m.GetUnchecked(entity)
501,592✔
35
}
36

37
// GetUnchecked returns the mapped component for the given entity.
38
// In contrast to [Map.Get], it does not check whether the entity is alive.
39
// Can be used as an optimization when it is certain that the entity is alive.
40
func (m *Map[T]) GetUnchecked(entity Entity) *T {
501,592✔
41
        m.world.storage.checkHasComponent(entity, m.id)
501,592✔
42
        index := m.world.storage.entities[entity.id]
501,592✔
43
        return (*T)(m.storage.columns[index.table].Get(uintptr(index.row)))
501,592✔
44
}
501,592✔
45

46
// Has return whether the given entity has the mapped component.
47
func (m *Map[T]) Has(entity Entity) bool {
3✔
48
        if !m.world.Alive(entity) {
3✔
49
                panic("can't get a component of a dead entity")
×
50
        }
51
        return m.HasUnchecked(entity)
3✔
52
}
53

54
// HasUnchecked return whether the given entity has the mapped component.
55
// In contrast to [Map.Has], it does not check whether the entity is alive.
56
// Can be used as an optimization when it is certain that the entity is alive.
57
func (m *Map[T]) HasUnchecked(entity Entity) bool {
3✔
58
        index := m.world.storage.entities[entity.id]
3✔
59
        return m.storage.columns[index.table] != nil
3✔
60
}
3✔
61

62
// Add the mapped component to the given entity.
63
func (m *Map[T]) Add(entity Entity, comp *T, rel ...Entity) {
214✔
64
        if !m.world.Alive(entity) {
214✔
65
                panic("can't add a component to a dead entity")
×
66
        }
67
        m.relations = relationEntities(rel).toRelation(m.id, m.relations)
214✔
68
        m.world.exchange(entity, []ID{m.id}, nil, []unsafe.Pointer{unsafe.Pointer(comp)}, m.relations)
214✔
69
}
70

71
// Remove the mapped component from the given entity.
72
func (m *Map[T]) Remove(entity Entity) {
81✔
73
        if !m.world.Alive(entity) {
81✔
74
                panic("can't remove a component from a dead entity")
×
75
        }
76
        m.world.exchange(entity, nil, []ID{m.id}, nil, nil)
81✔
77
}
78

79
// GetRelation returns the relation target for the entity and the mapped component.
80
func (m *Map[T]) GetRelation(entity Entity) Entity {
317✔
81
        return m.world.storage.getRelation(entity, m.id)
317✔
82
}
317✔
83

84
// GetRelationUnchecked returns the relation target for the entity and the mapped component.
85
// In contrast to [Map.GetRelation], it does not check whether the entity is alive.
86
// Can be used as an optimization when it is certain that the entity is alive.
87
func (m *Map[T]) GetRelationUnchecked(entity Entity) Entity {
2✔
88
        return m.world.storage.getRelationUnchecked(entity, m.id)
2✔
89
}
2✔
90

91
// SetRelation sets the relation target for the entity and the mapped component.
92
func (m *Map[T]) SetRelation(entity Entity, target Entity) {
34✔
93
        m.relations = target.toRelation(m.id, m.relations)
34✔
94
        m.world.setRelations(entity, m.relations)
34✔
95
}
34✔
96

97
// SetRelationBatch sets the relation target for all entities matching the given batch filter.
98
func (m *Map[T]) SetRelationBatch(batch *Batch, target Entity, fn func(entity Entity)) {
1✔
99
        m.relations = target.toRelation(m.id, m.relations)
1✔
100

1✔
101
        var process func(tableID tableID, start, len int)
1✔
102
        if fn != nil {
2✔
103
                process = func(tableID tableID, start, len int) {
2✔
104
                        table := &m.world.storage.tables[tableID]
1✔
105

1✔
106
                        lock := m.world.lock()
1✔
107
                        for i := range len {
25✔
108
                                index := uintptr(start + i)
24✔
109
                                fn(table.GetEntity(index))
24✔
110
                        }
24✔
111
                        m.world.unlock(lock)
1✔
112
                }
113
        }
114
        m.world.setRelationsBatch(batch, m.relations, process)
1✔
115
}
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