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

mlange-42 / ark / 13528862241

25 Feb 2025 07:00PM CUT coverage: 94.795% (+0.008%) from 94.787%
13528862241

push

github

web-flow
Add Map.GetRelationUnchecked (#75)

6 of 6 new or added lines in 2 files covered. (100.0%)

3406 of 3593 relevant lines covered (94.8%)

51323.81 hits per line

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

92.41
/ecs/pool.go
1
package ecs
2

3
import (
4
        "fmt"
5
        "math"
6
        "unsafe"
7
)
8

9
// entityPool is an implementation using implicit linked lists.
10
// Implements https://skypjack.github.io/2019-05-06-ecs-baf-part-3/
11
type entityPool struct {
12
        entities  []Entity
13
        next      entityID
14
        available uint32
15
        pointer   unsafe.Pointer
16
        reserved  entityID
17
}
18

19
// newEntityPool creates a new, initialized Entity pool.
20
func newEntityPool(initialCapacity uint32, reserved uint32) entityPool {
96✔
21
        entities := make([]Entity, reserved, initialCapacity+reserved)
96✔
22
        // Reserved zero and wildcard entities.
96✔
23
        for i := range reserved {
288✔
24
                entities[i] = Entity{entityID(i), math.MaxUint32}
192✔
25
        }
192✔
26
        return entityPool{
96✔
27
                entities:  entities,
96✔
28
                next:      0,
96✔
29
                available: 0,
96✔
30
                pointer:   unsafe.Pointer(&entities[0]),
96✔
31
                reserved:  entityID(reserved),
96✔
32
        }
96✔
33
}
34

35
// Get returns a fresh or recycled entity.
36
func (p *entityPool) Get() Entity {
497,336✔
37
        if p.available == 0 {
503,441✔
38
                return p.getNew()
6,105✔
39
        }
6,105✔
40
        curr := p.next
491,231✔
41
        p.next, p.entities[p.next].id = p.entities[p.next].id, p.next
491,231✔
42
        p.available--
491,231✔
43
        return p.entities[curr]
491,231✔
44
}
45

46
// Allocates and returns a new entity. For internal use.
47
func (p *entityPool) getNew() Entity {
6,105✔
48
        e := Entity{id: entityID(len(p.entities)), gen: 0}
6,105✔
49
        p.entities = append(p.entities, e)
6,105✔
50
        p.pointer = unsafe.Pointer(&p.entities[0])
6,105✔
51
        return e
6,105✔
52
}
6,105✔
53

54
// Recycle hands an entity back for recycling.
55
func (p *entityPool) Recycle(e Entity) {
495,032✔
56
        if e.id < p.reserved {
495,034✔
57
                panic("can't recycle reserved zero or wildcard entity")
2✔
58
        }
59
        p.entities[e.id].gen++
495,030✔
60
        p.next, p.entities[e.id].id = e.id, p.next
495,030✔
61
        p.available++
495,030✔
62
}
63

64
// Reset recycles all entities. Does NOT free the reserved memory.
65
func (p *entityPool) Reset() {
32✔
66
        p.entities = p.entities[:p.reserved]
32✔
67
        p.next = 0
32✔
68
        p.available = 0
32✔
69
}
32✔
70

71
// Alive returns whether an entity is still alive, based on the entity's generations.
72
func (p *entityPool) Alive(e Entity) bool {
995,700✔
73
        return e.gen == (*Entity)(unsafe.Add(p.pointer, entitySize*uintptr(e.id))).gen
995,700✔
74
}
995,700✔
75

76
// Len returns the current number of used entities.
77
func (p *entityPool) Len() int {
32✔
78
        return len(p.entities) - int(p.reserved) - int(p.available)
32✔
79
}
32✔
80

81
// Cap returns the current capacity (used and recycled entities).
82
func (p *entityPool) Cap() int {
×
83
        return len(p.entities) - int(p.reserved)
×
84
}
×
85

86
// TotalCap returns the current capacity in terms of reserved memory.
87
func (p *entityPool) TotalCap() int {
×
88
        return cap(p.entities)
×
89
}
×
90

91
// Available returns the current number of available/recycled entities.
92
func (p *entityPool) Available() int {
32✔
93
        return int(p.available)
32✔
94
}
32✔
95

96
// bitPool is a pool of bits that makes it possible to obtain an un-set bit,
97
// and to recycle that bit for later use.
98
// This implementation uses an implicit list.
99
type bitPool struct {
100
        length    uint16
101
        bits      [MaskTotalBits]uint8
102
        next      uint8
103
        available uint8
104
}
105

106
// Get returns a fresh or recycled bit.
107
func (p *bitPool) Get() uint8 {
1,613✔
108
        if p.available == 0 {
2,177✔
109
                return p.getNew()
564✔
110
        }
564✔
111
        curr := p.next
1,049✔
112
        p.next, p.bits[p.next] = p.bits[p.next], p.next
1,049✔
113
        p.available--
1,049✔
114
        return p.bits[curr]
1,049✔
115
}
116

117
// Allocates and returns a new bit. For internal use.
118
func (p *bitPool) getNew() uint8 {
564✔
119
        if p.length >= MaskTotalBits {
567✔
120
                panic(fmt.Sprintf("run out of the maximum of %d bits. "+
3✔
121
                        "This is likely caused by unclosed queries that lock the world. "+
3✔
122
                        "Make sure that all queries finish their iteration or are closed manually", MaskTotalBits))
3✔
123
        }
124
        b := uint8(p.length)
561✔
125
        p.bits[p.length] = b
561✔
126
        p.length++
561✔
127
        return b
561✔
128
}
129

130
// Recycle hands a bit back for recycling.
131
func (p *bitPool) Recycle(b uint8) {
1,098✔
132
        p.next, p.bits[b] = b, p.next
1,098✔
133
        p.available++
1,098✔
134
}
1,098✔
135

136
// Reset recycles all bits.
137
func (p *bitPool) Reset() {
1✔
138
        p.next = 0
1✔
139
        p.length = 0
1✔
140
        p.available = 0
1✔
141
}
1✔
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