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

mlange-42 / arche / 4873167893

03 May 2023 02:36PM CUT coverage: 100.0%. Remained the same
4873167893

push

github

GitHub
Batch-exchange and add with target (#264)

163 of 163 new or added lines in 7 files covered. (100.0%)

3657 of 3657 relevant lines covered (100.0%)

100168.69 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
        archetype         *archetype            // The single archetype for nodes without entity
19
        archetypes        pagedSlice[archetype] // Storage for archetypes in nodes with entity relation
20
        archetypeMap      map[Entity]*archetype // Mapping from relation targets to archetypes
21
        freeIndices       []int32               // Indices of free/inactive archetypes
22
        TransitionAdd     idMap[*archetypeNode] // Mapping from component ID to add to the resulting archetype
23
        TransitionRemove  idMap[*archetypeNode] // Mapping from component ID to remove to the resulting archetype
24
        relation          int8                  // The node's relation component ID. Negative value stands for no relation
25
        zeroValue         []byte                // Used as source for setting storage to zero
26
        zeroPointer       unsafe.Pointer        // Points to zeroValue for fast access
27
        capacityIncrement uint32                // Capacity increment
28
}
29

30
// Creates a new archetypeNode
31
func newArchetypeNode(mask Mask, relation int8, capacityIncrement int) archetypeNode {
1,239✔
32
        var arch map[Entity]*archetype
1,239✔
33
        if relation >= 0 {
1,263✔
34
                arch = map[Entity]*archetype{}
24✔
35
        }
24✔
36
        return archetypeNode{
1,239✔
37
                mask:              mask,
1,239✔
38
                archetypeMap:      arch,
1,239✔
39
                TransitionAdd:     newIDMap[*archetypeNode](),
1,239✔
40
                TransitionRemove:  newIDMap[*archetypeNode](),
1,239✔
41
                relation:          relation,
1,239✔
42
                capacityIncrement: uint32(capacityIncrement),
1,239✔
43
        }
1,239✔
44
}
45

46
// Matches the archetype node against a filter.
47
// Ignores the relation target.
48
func (a *archetypeNode) Matches(f Filter) bool {
76,702✔
49
        return f.Matches(a.mask, nil)
76,702✔
50
}
76,702✔
51

52
// Archetypes of the node.
53
// Returns a single wrapped archetype if there are no relations.
54
// Returns nil if the node has no archetype(s).
55
func (a *archetypeNode) Archetypes() archetypes {
176,833✔
56
        if a.HasRelation() {
251,951✔
57
                return &a.archetypes
75,118✔
58
        }
75,118✔
59
        if a.archetype == nil {
101,855✔
60
                return nil
140✔
61
        }
140✔
62
        return singleArchetype{Archetype: a.archetype}
101,575✔
63
}
64

65
// GetArchetype returns the archetype for the given relation target.
66
//
67
// The target is ignored if the node has no relation component.
68
func (a *archetypeNode) GetArchetype(target Entity) *archetype {
60,741✔
69
        if a.relation >= 0 {
93,734✔
70
                return a.archetypeMap[target]
32,993✔
71
        }
32,993✔
72
        return a.archetype
27,748✔
73
}
74

75
// SetArchetype sets the archetype for a node without a relation.
76
//
77
// Do not use on nodes without a relation component!
78
func (a *archetypeNode) SetArchetype(arch *archetype) {
1,185✔
79
        a.archetype = arch
1,185✔
80
}
1,185✔
81

82
// CreateArchetype creates a new archetype in nodes with relation component.
83
func (a *archetypeNode) CreateArchetype(target Entity, components ...componentType) *archetype {
27,567✔
84
        var arch *archetype
27,567✔
85
        var archIndex int32
27,567✔
86
        lenFree := len(a.freeIndices)
27,567✔
87
        if lenFree > 0 {
54,969✔
88
                archIndex = a.freeIndices[lenFree-1]
27,402✔
89
                arch = a.archetypes.Get(archIndex)
27,402✔
90
                a.freeIndices = a.freeIndices[:lenFree-1]
27,402✔
91
                arch.Activate(target, archIndex)
27,402✔
92
        } else {
27,567✔
93
                a.archetypes.Add(archetype{})
165✔
94
                archIndex := a.archetypes.Len() - 1
165✔
95
                arch = a.archetypes.Get(archIndex)
165✔
96
                arch.Init(a, archIndex, true, target, components...)
165✔
97
        }
165✔
98
        a.archetypeMap[target] = arch
27,567✔
99
        return arch
27,567✔
100
}
101

102
// RemoveArchetype de-activates an archetype.
103
// The archetype will be re-used by CreateArchetype.
104
func (a *archetypeNode) RemoveArchetype(arch *archetype) {
27,412✔
105
        delete(a.archetypeMap, arch.Relation)
27,412✔
106
        idx := arch.index
27,412✔
107
        a.freeIndices = append(a.freeIndices, idx)
27,412✔
108
        a.archetypes.Get(idx).Deactivate()
27,412✔
109
}
27,412✔
110

111
// HasRelation returns whether the node has a relation component.
112
func (a *archetypeNode) HasRelation() bool {
234,301✔
113
        return a.relation >= 0
234,301✔
114
}
234,301✔
115

116
// IsActive returns whether the node is active, i.e. has archetypes.
117
func (a *archetypeNode) IsActive() bool {
376,765✔
118
        return a.Ids != nil
376,765✔
119
}
376,765✔
120

121
// Stats generates statistics for an archetype node.
122
func (a *archetypeNode) Stats(reg *componentRegistry[ID]) stats.NodeStats {
13✔
123
        ids := a.Ids
13✔
124
        aCompCount := len(ids)
13✔
125
        aTypes := make([]reflect.Type, aCompCount)
13✔
126
        for j, id := range ids {
22✔
127
                aTypes[j], _ = reg.ComponentType(id)
9✔
128
        }
9✔
129

130
        arches := a.Archetypes()
13✔
131
        var numArches int32
13✔
132
        cap := 0
13✔
133
        count := 0
13✔
134
        memory := 0
13✔
135
        var archStats []stats.ArchetypeStats
13✔
136
        if arches != nil {
25✔
137
                numArches = arches.Len()
12✔
138
                archStats = make([]stats.ArchetypeStats, numArches)
12✔
139
                var i int32
12✔
140
                for i = 0; i < numArches; i++ {
124✔
141
                        archStats[i] = arches.Get(i).Stats(reg)
112✔
142
                        stats := &archStats[i]
112✔
143
                        cap += stats.Capacity
112✔
144
                        count += stats.Size
112✔
145
                        memory += stats.Memory
112✔
146
                }
112✔
147
        }
148

149
        memPerEntity := 0
13✔
150
        for j := range ids {
22✔
151
                memPerEntity += int(aTypes[j].Size())
9✔
152
        }
9✔
153

154
        return stats.NodeStats{
13✔
155
                ArchetypeCount:       int(numArches),
13✔
156
                ActiveArchetypeCount: int(numArches) - len(a.freeIndices),
13✔
157
                IsActive:             a.IsActive(),
13✔
158
                HasRelation:          a.HasRelation(),
13✔
159
                Components:           aCompCount,
13✔
160
                ComponentIDs:         ids,
13✔
161
                ComponentTypes:       aTypes,
13✔
162
                Memory:               memory,
13✔
163
                MemoryPerEntity:      memPerEntity,
13✔
164
                Size:                 count,
13✔
165
                Capacity:             cap,
13✔
166
                Archetypes:           archStats,
13✔
167
        }
13✔
168
}
169

170
// UpdateStats updates statistics for an archetype node.
171
func (a *archetypeNode) UpdateStats(stats *stats.NodeStats, reg *componentRegistry[ID]) {
150,022✔
172
        if !a.IsActive() {
150,023✔
173
                return
1✔
174
        }
1✔
175

176
        arches := a.Archetypes()
150,021✔
177

150,021✔
178
        if !stats.IsActive {
150,022✔
179
                temp := a.Stats(reg)
1✔
180
                *stats = temp
1✔
181
                return
1✔
182
        }
1✔
183

184
        cap := 0
150,020✔
185
        count := 0
150,020✔
186
        memory := 0
150,020✔
187

150,020✔
188
        cntOld := int32(len(stats.Archetypes))
150,020✔
189
        cntNew := int32(arches.Len())
150,020✔
190
        var i int32
150,020✔
191
        for i = 0; i < cntOld; i++ {
5,249,944✔
192
                arch := &stats.Archetypes[i]
5,099,924✔
193
                arches.Get(i).UpdateStats(stats, arch, reg)
5,099,924✔
194
                cap += arch.Capacity
5,099,924✔
195
                count += arch.Size
5,099,924✔
196
                memory += arch.Memory
5,099,924✔
197
        }
5,099,924✔
198
        for i = cntOld; i < cntNew; i++ {
150,021✔
199
                arch := arches.Get(i).Stats(reg)
1✔
200
                stats.Archetypes = append(stats.Archetypes, arch)
1✔
201
                cap += arch.Capacity
1✔
202
                count += arch.Size
1✔
203
                memory += arch.Memory
1✔
204
        }
1✔
205

206
        stats.IsActive = true
150,020✔
207
        stats.ArchetypeCount = int(cntNew)
150,020✔
208
        stats.ActiveArchetypeCount = int(cntNew) - len(a.freeIndices)
150,020✔
209
        stats.Capacity = cap
150,020✔
210
        stats.Size = count
150,020✔
211
        stats.Memory = memory
150,020✔
212
}
213

214
// Helper for accessing data from an archetype
215
type archetypeAccess struct {
216
        Mask              Mask           // Archetype's mask
217
        basePointer       unsafe.Pointer // Pointer to the first component column layout.
218
        entityPointer     unsafe.Pointer // Pointer to the entity storage
219
        Relation          Entity
220
        RelationComponent int8
221
}
222

223
// Matches checks if the archetype matches the given mask.
224
func (a *archetype) Matches(f Filter) bool {
2,500,535✔
225
        return f.Matches(a.Mask, &a.Relation)
2,500,535✔
226
}
2,500,535✔
227

228
// GetEntity returns the entity at the given index
229
func (a *archetypeAccess) GetEntity(index uintptr) Entity {
2,531,419✔
230
        return *(*Entity)(unsafe.Add(a.entityPointer, entitySize*index))
2,531,419✔
231
}
2,531,419✔
232

233
// Get returns the component with the given ID at the given index
234
func (a *archetypeAccess) Get(index uintptr, id ID) unsafe.Pointer {
18,705✔
235
        return a.getLayout(id).Get(index)
18,705✔
236
}
18,705✔
237

238
// GetEntity returns the entity at the given index
239
func (a *archetypeAccess) GetRelation() Entity {
123✔
240
        return a.Relation
123✔
241
}
123✔
242

243
// HasComponent returns whether the archetype contains the given component ID.
244
func (a *archetypeAccess) HasComponent(id ID) bool {
9,701✔
245
        return a.getLayout(id).pointer != nil
9,701✔
246
}
9,701✔
247

248
// HasRelation returns whether the archetype has a relation component.
249
func (a *archetypeAccess) HasRelation() bool {
2,461✔
250
        return a.RelationComponent >= 0
2,461✔
251
}
2,461✔
252

253
// GetLayout returns the column layout for a component.
254
func (a *archetypeAccess) getLayout(id ID) *layout {
86,961✔
255
        return (*layout)(unsafe.Add(a.basePointer, layoutSize*uintptr(id)))
86,961✔
256
}
86,961✔
257

258
// layout specification of a component column.
259
type layout struct {
260
        pointer  unsafe.Pointer // Pointer to the first element in the component column.
261
        itemSize uintptr        // Component/step size
262
}
263

264
// Get returns a pointer to the item at the given index.
265
func (l *layout) Get(index uintptr) unsafe.Pointer {
18,703✔
266
        if l.pointer == nil {
18,704✔
267
                return nil
1✔
268
        }
1✔
269
        return unsafe.Add(l.pointer, l.itemSize*index)
18,702✔
270
}
271

272
// archetype represents an ECS archetype
273
type archetype struct {
274
        archetypeAccess                 // Access helper, passed to queries.
275
        graphNode       *archetypeNode  // Node in the archetype graph.
276
        layouts         []layout        // Column layouts by ID.
277
        indices         idMap[uint32]   // Mapping from IDs to buffer indices.
278
        buffers         []reflect.Value // Reflection arrays containing component data.
279
        entityBuffer    reflect.Value   // Reflection array containing entity data.
280
        index           int32           // Index of the archetype in the world.
281
        len             uint32          // Current number of entities
282
        cap             uint32          // Current capacity
283
}
284

285
// Init initializes an archetype
286
func (a *archetype) Init(node *archetypeNode, index int32, forStorage bool, relation Entity, components ...componentType) {
1,359✔
287
        var mask Mask
1,359✔
288
        if !node.IsActive() {
2,572✔
289
                node.Ids = make([]ID, len(components))
1,213✔
290

1,213✔
291
                var maxSize uintptr = 0
1,213✔
292
                for i, c := range components {
6,500✔
293
                        node.Ids[i] = c.ID
5,287✔
294
                        size, align := c.Type.Size(), uintptr(c.Type.Align())
5,287✔
295
                        size = (size + (align - 1)) / align * align
5,287✔
296
                        if size > maxSize {
6,410✔
297
                                maxSize = size
1,123✔
298
                        }
1,123✔
299
                }
300

301
                if maxSize > 0 {
2,334✔
302
                        node.zeroValue = make([]byte, maxSize)
1,121✔
303
                        node.zeroPointer = unsafe.Pointer(&node.zeroValue[0])
1,121✔
304
                }
1,121✔
305
        }
306

307
        a.buffers = make([]reflect.Value, len(components))
1,359✔
308
        a.layouts = make([]layout, MaskTotalBits)
1,359✔
309
        a.indices = newIDMap[uint32]()
1,359✔
310
        a.index = index
1,359✔
311

1,359✔
312
        cap := 1
1,359✔
313
        if forStorage {
2,632✔
314
                cap = int(node.capacityIncrement)
1,273✔
315
        }
1,273✔
316

317
        prev := -1
1,359✔
318
        for i, c := range components {
6,806✔
319
                if int(c.ID) <= prev {
5,448✔
320
                        panic("component arguments must be sorted by ID")
1✔
321
                }
322
                prev = int(c.ID)
5,446✔
323
                mask.Set(c.ID, true)
5,446✔
324

5,446✔
325
                size, align := c.Type.Size(), uintptr(c.Type.Align())
5,446✔
326
                size = (size + (align - 1)) / align * align
5,446✔
327

5,446✔
328
                a.buffers[i] = reflect.New(reflect.ArrayOf(cap, c.Type)).Elem()
5,446✔
329
                a.layouts[c.ID] = layout{
5,446✔
330
                        a.buffers[i].Addr().UnsafePointer(),
5,446✔
331
                        size,
5,446✔
332
                }
5,446✔
333
                a.indices.Set(c.ID, uint32(i))
5,446✔
334
        }
335
        a.entityBuffer = reflect.New(reflect.ArrayOf(cap, entityType)).Elem()
1,358✔
336

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

1,358✔
345
        a.graphNode = node
1,358✔
346

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

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

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

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

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

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

30,551✔
396
        old := uintptr(a.len - 1)
30,551✔
397

30,551✔
398
        if index != old {
55,792✔
399
                for _, id := range a.graphNode.Ids {
50,630✔
400
                        lay := a.getLayout(id)
25,389✔
401
                        size := lay.itemSize
25,389✔
402
                        if size == 0 {
25,698✔
403
                                continue
309✔
404
                        }
405
                        src := unsafe.Add(lay.pointer, old*size)
25,080✔
406
                        dst := unsafe.Add(lay.pointer, index*size)
25,080✔
407
                        a.copy(src, dst, size)
25,080✔
408
                }
409
        }
410
        a.ZeroAll(old)
30,551✔
411
        a.len--
30,551✔
412

30,551✔
413
        return swapped
30,551✔
414
}
415

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

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

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

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

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

454
// SetPointer overwrites a component with the data behind the given pointer
455
func (a *archetype) SetPointer(index uintptr, id ID, comp unsafe.Pointer) unsafe.Pointer {
3,459✔
456
        lay := a.getLayout(id)
3,459✔
457
        dst := a.Get(index, id)
3,459✔
458
        size := lay.itemSize
3,459✔
459
        if size == 0 {
6,693✔
460
                return dst
3,234✔
461
        }
3,234✔
462

463
        a.copy(comp, dst, size)
225✔
464
        return dst
225✔
465
}
466

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

30,551✔
594
        if index == old {
35,861✔
595
                return false
5,310✔
596
        }
5,310✔
597

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

25,241✔
602
        return true
25,241✔
603
}
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