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

mlange-42 / ark / 13605379170

01 Mar 2025 01:41PM CUT coverage: 97.11%. Remained the same
13605379170

push

github

web-flow
Update README for ark-serde feature (#84)

3831 of 3945 relevant lines covered (97.11%)

46743.07 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 {
122✔
21
        entities := make([]Entity, reserved, initialCapacity+reserved)
122✔
22
        // Reserved zero and wildcard entities.
122✔
23
        for i := range reserved {
366✔
24
                entities[i] = Entity{entityID(i), math.MaxUint32}
244✔
25
        }
244✔
26
        return entityPool{
122✔
27
                entities:  entities,
122✔
28
                next:      0,
122✔
29
                available: 0,
122✔
30
                pointer:   unsafe.Pointer(&entities[0]),
122✔
31
                reserved:  entityID(reserved),
122✔
32
        }
122✔
33
}
34

35
// Get returns a fresh or recycled entity.
36
func (p *entityPool) Get() Entity {
498,003✔
37
        if p.available == 0 {
503,936✔
38
                return p.getNew()
5,933✔
39
        }
5,933✔
40
        curr := p.next
492,070✔
41
        p.next, p.entities[p.next].id = p.entities[p.next].id, p.next
492,070✔
42
        p.available--
492,070✔
43
        return p.entities[curr]
492,070✔
44
}
45

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

54
// Recycle hands an entity back for recycling.
55
func (p *entityPool) Recycle(e Entity) {
496,104✔
56
        if e.id < p.reserved {
496,106✔
57
                panic("can't recycle reserved zero or wildcard entity")
2✔
58
        }
59
        p.entities[e.id].gen++
496,102✔
60
        p.next, p.entities[e.id].id = e.id, p.next
496,102✔
61
        p.available++
496,102✔
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 {
997,265✔
73
        return e.gen == (*Entity)(unsafe.Add(p.pointer, entitySize*uintptr(e.id))).gen
997,265✔
74
}
997,265✔
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,632✔
108
        if p.available == 0 {
2,204✔
109
                return p.getNew()
572✔
110
        }
572✔
111
        curr := p.next
1,060✔
112
        p.next, p.bits[p.next] = p.bits[p.next], p.next
1,060✔
113
        p.available--
1,060✔
114
        return p.bits[curr]
1,060✔
115
}
116

117
// Allocates and returns a new bit. For internal use.
118
func (p *bitPool) getNew() uint8 {
572✔
119
        if p.length >= MaskTotalBits {
575✔
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)
569✔
125
        p.bits[p.length] = b
569✔
126
        p.length++
569✔
127
        return b
569✔
128
}
129

130
// Recycle hands a bit back for recycling.
131
func (p *bitPool) Recycle(b uint8) {
1,117✔
132
        p.next, p.bits[b] = b, p.next
1,117✔
133
        p.available++
1,117✔
134
}
1,117✔
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