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

mlange-42 / arche / 4882379906

04 May 2023 11:47AM CUT coverage: 100.0%. Remained the same
4882379906

push

github

GitHub
Add examples for Batch and Builder types (#267)

3636 of 3636 relevant lines covered (100.0%)

96025.43 hits per line

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

100.0
/ecs/archetype.go
1
package ecs
2

3
import (
4
        "math"
5
        "reflect"
6
        "unsafe"
7

8
        "github.com/mlange-42/arche/ecs/stats"
9
)
10

11
// layoutSize is the size of an archetype column layout in bytes.
12
var layoutSize = unsafe.Sizeof(layout{})
13

14
// archetypeNode is a node in the archetype graph.
15
type archetypeNode struct {
16
        Mask              Mask                  // Mask of the archetype
17
        Ids               []ID                  // List of component IDs
18
        Types             []reflect.Type        // Component type per column
19
        archetype         *archetype            // The single archetype for nodes without entity
20
        archetypes        pagedSlice[archetype] // Storage for archetypes in nodes with entity relation
21
        archetypeMap      map[Entity]*archetype // Mapping from relation targets to archetypes
22
        freeIndices       []int32               // Indices of free/inactive archetypes
23
        TransitionAdd     idMap[*archetypeNode] // Mapping from component ID to add to the resulting archetype
24
        TransitionRemove  idMap[*archetypeNode] // Mapping from component ID to remove to the resulting archetype
25
        Relation          int8                  // The node's relation component ID. Negative value stands for no relation
26
        zeroValue         []byte                // Used as source for setting storage to zero
27
        zeroPointer       unsafe.Pointer        // Points to zeroValue for fast access
28
        capacityIncrement uint32                // Capacity increment
29
        IsActive          bool
30
}
31

32
// Creates a new archetypeNode
33
func newArchetypeNode(mask Mask, relation int8, capacityIncrement int, components []componentType) archetypeNode {
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
        return archetypeNode{
1,269✔
66
                Mask:              mask,
1,269✔
67
                Ids:               ids,
1,269✔
68
                Types:             types,
1,269✔
69
                archetypeMap:      arch,
1,269✔
70
                TransitionAdd:     newIDMap[*archetypeNode](),
1,269✔
71
                TransitionRemove:  newIDMap[*archetypeNode](),
1,269✔
72
                Relation:          relation,
1,269✔
73
                capacityIncrement: uint32(capacityIncrement),
1,269✔
74
                zeroValue:         zeroValue,
1,269✔
75
                zeroPointer:       zeroPointer,
1,269✔
76
        }
1,269✔
77
}
78

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

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

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

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

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

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

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

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

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

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

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

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

204
        arches := a.Archetypes()
150,021✔
205

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

212
        cap := 0
150,020✔
213
        count := 0
150,020✔
214
        memory := 0
150,020✔
215

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

234
        stats.IsActive = true
150,020✔
235
        stats.ArchetypeCount = int(cntNew)
150,020✔
236
        stats.ActiveArchetypeCount = int(cntNew) - len(a.freeIndices)
150,020✔
237
        stats.Capacity = cap
150,020✔
238
        stats.Size = count
150,020✔
239
        stats.Memory = memory
150,020✔
240
}
241

242
// Helper for accessing data from an archetype
243
type archetypeAccess struct {
244
        Mask              Mask           // Archetype's mask
245
        basePointer       unsafe.Pointer // Pointer to the first component column layout.
246
        entityPointer     unsafe.Pointer // Pointer to the entity storage
247
        RelationTarget    Entity
248
        RelationComponent int8
249
}
250

251
// Matches checks if the archetype matches the given mask.
252
func (a *archetype) Matches(f Filter) bool {
2,500,545✔
253
        return f.Matches(a.Mask, &a.RelationTarget)
2,500,545✔
254
}
2,500,545✔
255

256
// GetEntity returns the entity at the given index
257
func (a *archetypeAccess) GetEntity(index uintptr) Entity {
2,534,326✔
258
        return *(*Entity)(unsafe.Add(a.entityPointer, entitySize*index))
2,534,326✔
259
}
2,534,326✔
260

261
// Get returns the component with the given ID at the given index
262
func (a *archetypeAccess) Get(index uintptr, id ID) unsafe.Pointer {
23,507✔
263
        return a.getLayout(id).Get(index)
23,507✔
264
}
23,507✔
265

266
// HasComponent returns whether the archetype contains the given component ID.
267
func (a *archetypeAccess) HasComponent(id ID) bool {
1,773✔
268
        return a.getLayout(id).pointer != nil
1,773✔
269
}
1,773✔
270

271
// HasRelation returns whether the archetype has a relation component.
272
func (a *archetypeAccess) HasRelation() bool {
2,461✔
273
        return a.RelationComponent >= 0
2,461✔
274
}
2,461✔
275

276
// GetLayout returns the column layout for a component.
277
func (a *archetypeAccess) getLayout(id ID) *layout {
86,257✔
278
        return (*layout)(unsafe.Add(a.basePointer, layoutSize*uintptr(id)))
86,257✔
279
}
86,257✔
280

281
// layout specification of a component column.
282
type layout struct {
283
        pointer  unsafe.Pointer // Pointer to the first element in the component column.
284
        itemSize uintptr        // Component/step size
285
}
286

287
// Get returns a pointer to the item at the given index.
288
func (l *layout) Get(index uintptr) unsafe.Pointer {
23,505✔
289
        if l.pointer == nil {
23,506✔
290
                return nil
1✔
291
        }
1✔
292
        return unsafe.Add(l.pointer, l.itemSize*index)
23,504✔
293
}
294

295
// archetype represents an ECS archetype
296
type archetype struct {
297
        archetypeAccess                 // Access helper, passed to queries.
298
        graphNode       *archetypeNode  // Node in the archetype graph.
299
        layouts         []layout        // Column layouts by ID.
300
        indices         idMap[uint32]   // Mapping from IDs to buffer indices.
301
        buffers         []reflect.Value // Reflection arrays containing component data.
302
        entityBuffer    reflect.Value   // Reflection array containing entity data.
303
        index           int32           // Index of the archetype in the world.
304
        len             uint32          // Current number of entities
305
        cap             uint32          // Current capacity
306
}
307

308
// Init initializes an archetype
309
func (a *archetype) Init(node *archetypeNode, index int32, forStorage bool, relation Entity) {
1,383✔
310
        if !node.IsActive {
2,617✔
311
                node.IsActive = true
1,234✔
312
        }
1,234✔
313

314
        a.buffers = make([]reflect.Value, len(node.Ids))
1,383✔
315
        a.layouts = make([]layout, MaskTotalBits)
1,383✔
316
        a.indices = newIDMap[uint32]()
1,383✔
317
        a.index = index
1,383✔
318

1,383✔
319
        cap := 1
1,383✔
320
        if forStorage {
2,669✔
321
                cap = int(node.capacityIncrement)
1,286✔
322
        }
1,286✔
323

324
        for i, id := range node.Ids {
6,854✔
325
                tp := node.Types[i]
5,471✔
326
                size, align := tp.Size(), uintptr(tp.Align())
5,471✔
327
                size = (size + (align - 1)) / align * align
5,471✔
328

5,471✔
329
                a.buffers[i] = reflect.New(reflect.ArrayOf(cap, tp)).Elem()
5,471✔
330
                a.layouts[id] = layout{
5,471✔
331
                        a.buffers[i].Addr().UnsafePointer(),
5,471✔
332
                        size,
5,471✔
333
                }
5,471✔
334
                a.indices.Set(id, uint32(i))
5,471✔
335
        }
5,471✔
336
        a.entityBuffer = reflect.New(reflect.ArrayOf(cap, entityType)).Elem()
1,383✔
337

1,383✔
338
        a.archetypeAccess = archetypeAccess{
1,383✔
339
                basePointer:       unsafe.Pointer(&a.layouts[0]),
1,383✔
340
                entityPointer:     a.entityBuffer.Addr().UnsafePointer(),
1,383✔
341
                Mask:              node.Mask,
1,383✔
342
                RelationTarget:    relation,
1,383✔
343
                RelationComponent: node.Relation,
1,383✔
344
        }
1,383✔
345

1,383✔
346
        a.graphNode = node
1,383✔
347

1,383✔
348
        a.len = 0
1,383✔
349
        a.cap = uint32(cap)
1,383✔
350
}
351

352
// Add adds an entity with optionally zeroed components to the archetype
353
func (a *archetype) Alloc(entity Entity) uintptr {
35,394✔
354
        idx := uintptr(a.len)
35,394✔
355
        a.extend(1)
35,394✔
356
        a.addEntity(idx, &entity)
35,394✔
357
        a.len++
35,394✔
358
        return idx
35,394✔
359
}
35,394✔
360

361
// AllocN allocates storage for the given number of entities.
362
func (a *archetype) AllocN(count uint32) {
27,581✔
363
        a.extend(count)
27,581✔
364
        a.len += count
27,581✔
365
}
27,581✔
366

367
// Add adds an entity with components to the archetype.
368
func (a *archetype) Add(entity Entity, components ...Component) uintptr {
9✔
369
        if len(components) != len(a.graphNode.Ids) {
10✔
370
                panic("Invalid number of components")
1✔
371
        }
372
        idx := uintptr(a.len)
8✔
373

8✔
374
        a.extend(1)
8✔
375
        a.addEntity(idx, &entity)
8✔
376
        for _, c := range components {
24✔
377
                lay := a.getLayout(c.ID)
16✔
378
                size := lay.itemSize
16✔
379
                if size == 0 {
18✔
380
                        continue
2✔
381
                }
382
                src := reflect.ValueOf(c.Comp).UnsafePointer()
14✔
383
                dst := a.Get(uintptr(idx), c.ID)
14✔
384
                a.copy(src, dst, size)
14✔
385
        }
386
        a.len++
8✔
387
        return idx
8✔
388
}
389

390
// Remove removes an entity and its components from the archetype.
391
//
392
// Performs a swap-remove and reports whether a swap was necessary
393
// (i.e. not the last entity that was removed).
394
func (a *archetype) Remove(index uintptr) bool {
30,553✔
395
        swapped := a.removeEntity(index)
30,553✔
396

30,553✔
397
        old := uintptr(a.len - 1)
30,553✔
398

30,553✔
399
        if index != old {
55,799✔
400
                for _, id := range a.graphNode.Ids {
50,640✔
401
                        lay := a.getLayout(id)
25,394✔
402
                        size := lay.itemSize
25,394✔
403
                        if size == 0 {
25,703✔
404
                                continue
309✔
405
                        }
406
                        src := unsafe.Add(lay.pointer, old*size)
25,085✔
407
                        dst := unsafe.Add(lay.pointer, index*size)
25,085✔
408
                        a.copy(src, dst, size)
25,085✔
409
                }
410
        }
411
        a.ZeroAll(old)
30,553✔
412
        a.len--
30,553✔
413

30,553✔
414
        return swapped
30,553✔
415
}
416

417
// ZeroAll resets a block of storage in all buffers.
418
func (a *archetype) ZeroAll(index uintptr) {
30,553✔
419
        for _, id := range a.graphNode.Ids {
59,258✔
420
                a.Zero(index, id)
28,705✔
421
        }
28,705✔
422
}
423

424
// ZeroAll resets a block of storage in one buffer.
425
func (a *archetype) Zero(index uintptr, id ID) {
28,705✔
426
        lay := a.getLayout(id)
28,705✔
427
        size := lay.itemSize
28,705✔
428
        if size == 0 {
31,847✔
429
                return
3,142✔
430
        }
3,142✔
431
        dst := unsafe.Add(lay.pointer, index*size)
25,563✔
432
        a.copy(a.graphNode.zeroPointer, dst, size)
25,563✔
433
}
434

435
// SetEntity overwrites an entity
436
func (a *archetype) SetEntity(index uintptr, entity Entity) {
2,758,393✔
437
        a.addEntity(index, &entity)
2,758,393✔
438
}
2,758,393✔
439

440
// Set overwrites a component with the data behind the given pointer
441
func (a *archetype) Set(index uintptr, id ID, comp interface{}) unsafe.Pointer {
837✔
442
        lay := a.getLayout(id)
837✔
443
        dst := a.Get(index, id)
837✔
444
        size := lay.itemSize
837✔
445
        if size == 0 {
867✔
446
                return dst
30✔
447
        }
30✔
448
        rValue := reflect.ValueOf(comp)
807✔
449

807✔
450
        src := rValue.UnsafePointer()
807✔
451
        a.copy(src, dst, size)
807✔
452
        return dst
807✔
453
}
454

455
// SetPointer overwrites a component with the data behind the given pointer
456
func (a *archetype) SetPointer(index uintptr, id ID, comp unsafe.Pointer) unsafe.Pointer {
5,859✔
457
        lay := a.getLayout(id)
5,859✔
458
        dst := a.Get(index, id)
5,859✔
459
        size := lay.itemSize
5,859✔
460
        if size == 0 {
10,293✔
461
                return dst
4,434✔
462
        }
4,434✔
463

464
        a.copy(comp, dst, size)
1,425✔
465
        return dst
1,425✔
466
}
467

468
// Reset removes all entities and components.
469
//
470
// Does NOT free the reserved memory.
471
func (a *archetype) Reset() {
52,503✔
472
        if a.len == 0 {
77,548✔
473
                return
25,045✔
474
        }
25,045✔
475
        a.len = 0
27,458✔
476
        for _, buf := range a.buffers {
54,929✔
477
                buf.SetZero()
27,471✔
478
        }
27,471✔
479
}
480

481
// Deactivate the archetype for later re-use.
482
func (a *archetype) Deactivate() {
27,413✔
483
        a.Reset()
27,413✔
484
        a.index = -1
27,413✔
485
}
27,413✔
486

487
// Activate reactivates a de-activated archetype.
488
func (a *archetype) Activate(target Entity, index int32) {
27,402✔
489
        a.index = index
27,402✔
490
        a.RelationTarget = target
27,402✔
491
}
27,402✔
492

493
// IsActive returns whether the archetype is active.
494
// Otherwise, it is eligible for re-use.
495
func (a *archetype) IsActive() bool {
7,603,095✔
496
        return a.index >= 0
7,603,095✔
497
}
7,603,095✔
498

499
// Components returns the component IDs for this archetype
500
func (a *archetype) Components() []ID {
2,955✔
501
        return a.graphNode.Ids
2,955✔
502
}
2,955✔
503

504
// Len reports the number of entities in the archetype
505
func (a *archetype) Len() uint32 {
5,261,516✔
506
        return a.len
5,261,516✔
507
}
5,261,516✔
508

509
// Cap reports the current capacity of the archetype
510
func (a *archetype) Cap() uint32 {
5,100,047✔
511
        return a.cap
5,100,047✔
512
}
5,100,047✔
513

514
// Stats generates statistics for an archetype
515
func (a *archetype) Stats(reg *componentRegistry[ID]) stats.ArchetypeStats {
113✔
516
        ids := a.Components()
113✔
517
        aCompCount := len(ids)
113✔
518
        aTypes := make([]reflect.Type, aCompCount)
113✔
519
        for j, id := range ids {
225✔
520
                aTypes[j], _ = reg.ComponentType(id)
112✔
521
        }
112✔
522

523
        cap := int(a.Cap())
113✔
524
        memPerEntity := 0
113✔
525
        for _, id := range a.graphNode.Ids {
225✔
526
                lay := a.getLayout(id)
112✔
527
                memPerEntity += int(lay.itemSize)
112✔
528
        }
112✔
529
        memory := cap * (int(entitySize) + memPerEntity)
113✔
530

113✔
531
        return stats.ArchetypeStats{
113✔
532
                IsActive: a.IsActive(),
113✔
533
                Size:     int(a.Len()),
113✔
534
                Capacity: cap,
113✔
535
                Memory:   memory,
113✔
536
        }
113✔
537
}
538

539
// UpdateStats updates statistics for an archetype
540
func (a *archetype) UpdateStats(node *stats.NodeStats, stats *stats.ArchetypeStats, reg *componentRegistry[ID]) {
5,099,924✔
541
        cap := int(a.Cap())
5,099,924✔
542
        memory := cap * (int(entitySize) + node.MemoryPerEntity)
5,099,924✔
543

5,099,924✔
544
        stats.IsActive = a.IsActive()
5,099,924✔
545
        stats.Size = int(a.Len())
5,099,924✔
546
        stats.Capacity = cap
5,099,924✔
547
        stats.Memory = memory
5,099,924✔
548
}
5,099,924✔
549

550
// copy from one pointer to another.
551
func (a *archetype) copy(src, dst unsafe.Pointer, itemSize uintptr) {
2,871,935✔
552
        dstSlice := (*[math.MaxInt32]byte)(dst)[:itemSize:itemSize]
2,871,935✔
553
        srcSlice := (*[math.MaxInt32]byte)(src)[:itemSize:itemSize]
2,871,935✔
554
        copy(dstSlice, srcSlice)
2,871,935✔
555
}
2,871,935✔
556

557
// extend the memory buffers if necessary for adding an entity.
558
func (a *archetype) extend(by uint32) {
62,986✔
559
        required := a.len + by
62,986✔
560
        if a.cap >= required {
125,925✔
561
                return
62,939✔
562
        }
62,939✔
563
        a.cap = capacityU32(required, a.graphNode.capacityIncrement)
47✔
564

47✔
565
        old := a.entityBuffer
47✔
566
        a.entityBuffer = reflect.New(reflect.ArrayOf(int(a.cap), entityType)).Elem()
47✔
567
        a.entityPointer = a.entityBuffer.Addr().UnsafePointer()
47✔
568
        reflect.Copy(a.entityBuffer, old)
47✔
569

47✔
570
        for _, id := range a.graphNode.Ids {
101✔
571
                lay := a.getLayout(id)
54✔
572
                if lay.itemSize == 0 {
60✔
573
                        continue
6✔
574
                }
575
                index, _ := a.indices.Get(id)
48✔
576
                old := a.buffers[index]
48✔
577
                a.buffers[index] = reflect.New(reflect.ArrayOf(int(a.cap), old.Type().Elem())).Elem()
48✔
578
                lay.pointer = a.buffers[index].Addr().UnsafePointer()
48✔
579
                reflect.Copy(a.buffers[index], old)
48✔
580
        }
581
}
582

583
// Adds an entity at the given index. Does not extend the entity buffer.
584
func (a *archetype) addEntity(index uintptr, entity *Entity) {
2,793,795✔
585
        dst := unsafe.Add(a.entityPointer, entitySize*index)
2,793,795✔
586
        src := unsafe.Pointer(entity)
2,793,795✔
587
        a.copy(src, dst, entitySize)
2,793,795✔
588
}
2,793,795✔
589

590
// removeEntity removes an entity from tne archetype.
591
// Components need to be removed separately.
592
func (a *archetype) removeEntity(index uintptr) bool {
30,553✔
593
        old := uintptr(a.len - 1)
30,553✔
594

30,553✔
595
        if index == old {
35,860✔
596
                return false
5,307✔
597
        }
5,307✔
598

599
        src := unsafe.Add(a.entityPointer, old*entitySize)
25,246✔
600
        dst := unsafe.Add(a.entityPointer, index*entitySize)
25,246✔
601
        a.copy(src, dst, entitySize)
25,246✔
602

25,246✔
603
        return true
25,246✔
604
}
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