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

mlange-42 / arche / 4866344964

02 May 2023 10:26PM CUT coverage: 100.0%. Remained the same
4866344964

push

github

GitHub
Better document RelationsUnchecked et al. methods (#261)

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

3543 of 3543 relevant lines covered (100.0%)

1860.39 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,229✔
32
        var arch map[Entity]*archetype
1,229✔
33
        if relation >= 0 {
1,248✔
34
                arch = map[Entity]*archetype{}
19✔
35
        }
19✔
36
        return archetypeNode{
1,229✔
37
                mask:              mask,
1,229✔
38
                archetypeMap:      arch,
1,229✔
39
                TransitionAdd:     newIDMap[*archetypeNode](),
1,229✔
40
                TransitionRemove:  newIDMap[*archetypeNode](),
1,229✔
41
                relation:          relation,
1,229✔
42
                capacityIncrement: uint32(capacityIncrement),
1,229✔
43
        }
1,229✔
44
}
45

46
// Matches the archetype node against a filter.
47
// Ignores the relation target.
48
func (a *archetypeNode) Matches(f Filter) bool {
1,659✔
49
        return f.Matches(a.mask, nil)
1,659✔
50
}
1,659✔
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 {
1,740✔
56
        if a.HasRelation() {
1,820✔
57
                return &a.archetypes
80✔
58
        }
80✔
59
        if a.archetype == nil {
1,800✔
60
                return nil
140✔
61
        }
140✔
62
        return batchArchetype{Archetype: a.archetype, StartIndex: 0}
1,520✔
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 {
8,199✔
69
        if a.relation >= 0 {
13,683✔
70
                return a.archetypeMap[target]
5,484✔
71
        }
5,484✔
72
        return a.archetype
2,715✔
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,180✔
79
        a.archetype = arch
1,180✔
80
}
1,180✔
81

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

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

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

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

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

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

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

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

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

176
        arches := a.Archetypes()
24✔
177

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

184
        cap := 0
23✔
185
        count := 0
23✔
186
        memory := 0
23✔
187

23✔
188
        cntOld := int32(len(stats.Archetypes))
23✔
189
        cntNew := int32(arches.Len())
23✔
190
        var i int32
23✔
191
        for i = 0; i < cntOld; i++ {
49✔
192
                arch := &stats.Archetypes[i]
26✔
193
                arches.Get(i).UpdateStats(stats, arch, reg)
26✔
194
                cap += arch.Capacity
26✔
195
                count += arch.Size
26✔
196
                memory += arch.Memory
26✔
197
        }
26✔
198
        for i = cntOld; i < cntNew; i++ {
24✔
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
23✔
207
        stats.ArchetypeCount = int(cntNew)
23✔
208
        stats.ActiveArchetypeCount = int(cntNew) - len(a.freeIndices)
23✔
209
        stats.Capacity = cap
23✔
210
        stats.Size = count
23✔
211
        stats.Memory = memory
23✔
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 {
509✔
225
        return f.Matches(a.Mask, &a.Relation)
509✔
226
}
509✔
227

228
// GetEntity returns the entity at the given index
229
func (a *archetypeAccess) GetEntity(index uintptr) Entity {
2,450✔
230
        return *(*Entity)(unsafe.Add(a.entityPointer, entitySize*index))
2,450✔
231
}
2,450✔
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 {
17,702✔
235
        return a.getLayout(id).Get(index)
17,702✔
236
}
17,702✔
237

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

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

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

253
// GetLayout returns the column layout for a component.
254
func (a *archetypeAccess) getLayout(id ID) *layout {
34,666✔
255
        return (*layout)(unsafe.Add(a.basePointer, layoutSize*uintptr(id)))
34,666✔
256
}
34,666✔
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 {
17,700✔
266
        if l.pointer == nil {
17,701✔
267
                return nil
1✔
268
        }
1✔
269
        return unsafe.Add(l.pointer, l.itemSize*index)
17,699✔
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,249✔
287
        var mask Mask
1,249✔
288
        if !node.IsActive() {
2,453✔
289
                node.Ids = make([]ID, len(components))
1,204✔
290

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

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

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

1,249✔
312
        cap := 1
1,249✔
313
        if forStorage {
2,414✔
314
                cap = int(node.capacityIncrement)
1,165✔
315
        }
1,165✔
316

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

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

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

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

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

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

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

360
// Add adds storage to the archetype
361
func (a *archetype) AllocN(count uint32) {
35✔
362
        a.extend(count)
35✔
363
        a.len += count
35✔
364
}
35✔
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 {
5,546✔
394
        swapped := a.removeEntity(index)
5,546✔
395

5,546✔
396
        old := uintptr(a.len - 1)
5,546✔
397

5,546✔
398
        if index != old {
6,026✔
399
                for _, id := range a.graphNode.Ids {
1,108✔
400
                        lay := a.getLayout(id)
628✔
401
                        size := lay.itemSize
628✔
402
                        if size == 0 {
937✔
403
                                continue
309✔
404
                        }
405
                        src := unsafe.Add(lay.pointer, old*size)
319✔
406
                        dst := unsafe.Add(lay.pointer, index*size)
319✔
407
                        a.copy(src, dst, size)
319✔
408
                }
409
        }
410
        a.ZeroAll(old)
5,546✔
411
        a.len--
5,546✔
412

5,546✔
413
        return swapped
5,546✔
414
}
415

416
// ZeroAll resets a block of storage in all buffers.
417
func (a *archetype) ZeroAll(index uintptr) {
5,546✔
418
        for _, id := range a.graphNode.Ids {
9,249✔
419
                a.Zero(index, id)
3,703✔
420
        }
3,703✔
421
}
422

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

434
// SetEntity overwrites an entity
435
func (a *archetype) SetEntity(index uintptr, entity Entity) {
1,287✔
436
        a.addEntity(index, &entity)
1,287✔
437
}
1,287✔
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 {
832✔
441
        lay := a.getLayout(id)
832✔
442
        dst := a.Get(index, id)
832✔
443
        size := lay.itemSize
832✔
444
        if size == 0 {
861✔
445
                return dst
29✔
446
        }
29✔
447
        rValue := reflect.ValueOf(comp)
803✔
448

803✔
449
        src := rValue.UnsafePointer()
803✔
450
        a.copy(src, dst, size)
803✔
451
        return dst
803✔
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 {
2,959✔
456
        lay := a.getLayout(id)
2,959✔
457
        dst := a.Get(index, id)
2,959✔
458
        size := lay.itemSize
2,959✔
459
        if size == 0 {
5,893✔
460
                return dst
2,934✔
461
        }
2,934✔
462

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

467
// Reset removes all entities and components.
468
//
469
// Does NOT free the reserved memory.
470
func (a *archetype) Reset() {
37✔
471
        if a.len == 0 {
54✔
472
                return
17✔
473
        }
17✔
474
        a.len = 0
20✔
475
        for _, buf := range a.buffers {
44✔
476
                buf.SetZero()
24✔
477
        }
24✔
478
}
479

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

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

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

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

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

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

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

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

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

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

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

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

556
// extend the memory buffers if necessary for adding an entity.
557
func (a *archetype) extend(by uint32) {
10,414✔
558
        required := a.len + by
10,414✔
559
        if a.cap >= required {
20,790✔
560
                return
10,376✔
561
        }
10,376✔
562
        a.cap = capacityU32(required, a.graphNode.capacityIncrement)
38✔
563

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

38✔
569
        for _, id := range a.graphNode.Ids {
78✔
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) {
11,663✔
584
        dst := unsafe.Add(a.entityPointer, entitySize*index)
11,663✔
585
        src := unsafe.Pointer(entity)
11,663✔
586
        a.copy(src, dst, entitySize)
11,663✔
587
}
11,663✔
588

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

5,546✔
594
        if index == old {
10,612✔
595
                return false
5,066✔
596
        }
5,066✔
597

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

480✔
602
        return true
480✔
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