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

mlange-42 / arche / 4863457196

02 May 2023 04:21PM CUT coverage: 100.0%. Remained the same
4863457196

Pull #259

github

GitHub
Merge fce938980 into 5d4828799
Pull Request #259: Unchecked relation access, relation benchmarks

57 of 57 new or added lines in 5 files covered. (100.0%)

3541 of 3541 relevant lines covered (100.0%)

1816.12 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,226✔
32
        var arch map[Entity]*archetype
1,226✔
33
        if relation >= 0 {
1,243✔
34
                arch = map[Entity]*archetype{}
17✔
35
        }
17✔
36
        return archetypeNode{
1,226✔
37
                mask:              mask,
1,226✔
38
                archetypeMap:      arch,
1,226✔
39
                TransitionAdd:     newIDMap[*archetypeNode](),
1,226✔
40
                TransitionRemove:  newIDMap[*archetypeNode](),
1,226✔
41
                relation:          relation,
1,226✔
42
                capacityIncrement: uint32(capacityIncrement),
1,226✔
43
        }
1,226✔
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 {
7,597✔
69
        if a.relation >= 0 {
12,679✔
70
                return a.archetypeMap[target]
5,082✔
71
        }
5,082✔
72
        return a.archetype
2,515✔
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,179✔
79
        a.archetype = arch
1,179✔
80
}
1,179✔
81

82
// CreateArchetype creates a new archetype in nodes with relation component.
83
func (a *archetypeNode) CreateArchetype(target Entity, components ...componentType) *archetype {
58✔
84
        var arch *archetype
58✔
85
        var archIndex int32
58✔
86
        lenFree := len(a.freeIndices)
58✔
87
        if lenFree > 0 {
60✔
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 {
58✔
93
                a.archetypes.Add(archetype{})
56✔
94
                archIndex := a.archetypes.Len() - 1
56✔
95
                arch = a.archetypes.Get(archIndex)
56✔
96
                arch.Init(a, archIndex, true, target, a.relation, components...)
56✔
97
        }
56✔
98
        a.archetypeMap[target] = arch
58✔
99
        return arch
58✔
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,673✔
113
        return a.relation >= 0
6,673✔
114
}
6,673✔
115

116
// IsActive returns whether the node is active, i.e. has archetypes.
117
func (a *archetypeNode) IsActive() bool {
1,519✔
118
        return a.Ids != nil
1,519✔
119
}
1,519✔
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.Capacity = cap
23✔
208
        stats.Size = count
23✔
209
        stats.Memory = memory
23✔
210
}
211

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

221
// Matches checks if the archetype matches the given mask.
222
func (a *archetype) Matches(f Filter) bool {
509✔
223
        return f.Matches(a.Mask, &a.Relation)
509✔
224
}
509✔
225

226
// GetEntity returns the entity at the given index
227
func (a *archetypeAccess) GetEntity(index uintptr) Entity {
1,752✔
228
        return *(*Entity)(unsafe.Add(a.entityPointer, entitySize*index))
1,752✔
229
}
1,752✔
230

231
// Get returns the component with the given ID at the given index
232
func (a *archetypeAccess) Get(index uintptr, id ID) unsafe.Pointer {
16,902✔
233
        return a.getLayout(id).Get(index)
16,902✔
234
}
16,902✔
235

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

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

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

251
// GetLayout returns the column layout for a component.
252
func (a *archetypeAccess) getLayout(id ID) *layout {
31,668✔
253
        return (*layout)(unsafe.Add(a.basePointer, layoutSize*uintptr(id)))
31,668✔
254
}
31,668✔
255

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

262
// Get returns a pointer to the item at the given index.
263
func (l *layout) Get(index uintptr) unsafe.Pointer {
16,900✔
264
        if l.pointer == nil {
16,901✔
265
                return nil
1✔
266
        }
1✔
267
        return unsafe.Add(l.pointer, l.itemSize*index)
16,899✔
268
}
269

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

283
// Init initializes an archetype
284
func (a *archetype) Init(node *archetypeNode, index int32, forStorage bool, relation Entity, relationComp int8, components ...componentType) {
1,244✔
285
        var mask Mask
1,244✔
286
        if !node.IsActive() {
2,445✔
287
                node.Ids = make([]ID, len(components))
1,201✔
288

1,201✔
289
                var maxSize uintptr = 0
1,201✔
290
                for i, c := range components {
6,476✔
291
                        node.Ids[i] = c.ID
5,275✔
292
                        size, align := c.Type.Size(), uintptr(c.Type.Align())
5,275✔
293
                        size = (size + (align - 1)) / align * align
5,275✔
294
                        if size > maxSize {
6,392✔
295
                                maxSize = size
1,117✔
296
                        }
1,117✔
297
                }
298

299
                if maxSize > 0 {
2,316✔
300
                        node.zeroValue = make([]byte, maxSize)
1,115✔
301
                        node.zeroPointer = unsafe.Pointer(&node.zeroValue[0])
1,115✔
302
                }
1,115✔
303
        }
304

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

1,244✔
310
        cap := 1
1,244✔
311
        if forStorage {
2,405✔
312
                cap = int(node.capacityIncrement)
1,161✔
313
        }
1,161✔
314

315
        prev := -1
1,244✔
316
        for i, c := range components {
6,573✔
317
                if int(c.ID) <= prev {
5,330✔
318
                        panic("component arguments must be sorted by ID")
1✔
319
                }
320
                prev = int(c.ID)
5,328✔
321
                mask.Set(c.ID, true)
5,328✔
322

5,328✔
323
                size, align := c.Type.Size(), uintptr(c.Type.Align())
5,328✔
324
                size = (size + (align - 1)) / align * align
5,328✔
325

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

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

1,243✔
343
        a.graphNode = node
1,243✔
344

1,243✔
345
        a.len = 0
1,243✔
346
        a.cap = uint32(cap)
1,243✔
347
}
348

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

358
// Add adds storage to the archetype
359
func (a *archetype) AllocN(count uint32) {
33✔
360
        a.extend(count)
33✔
361
        a.len += count
33✔
362
}
33✔
363

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

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

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

4,946✔
394
        old := uintptr(a.len - 1)
4,946✔
395

4,946✔
396
        if index != old {
5,128✔
397
                for _, id := range a.graphNode.Ids {
412✔
398
                        lay := a.getLayout(id)
230✔
399
                        size := lay.itemSize
230✔
400
                        if size == 0 {
239✔
401
                                continue
9✔
402
                        }
403
                        src := unsafe.Add(lay.pointer, old*size)
221✔
404
                        dst := unsafe.Add(lay.pointer, index*size)
221✔
405
                        a.copy(src, dst, size)
221✔
406
                }
407
        }
408
        a.ZeroAll(old)
4,946✔
409
        a.len--
4,946✔
410

4,946✔
411
        return swapped
4,946✔
412
}
413

414
// ZeroAll resets a block of storage in all buffers.
415
func (a *archetype) ZeroAll(index uintptr) {
4,946✔
416
        for _, id := range a.graphNode.Ids {
7,849✔
417
                a.Zero(index, id)
2,903✔
418
        }
2,903✔
419
}
420

421
// ZeroAll resets a block of storage in one buffer.
422
func (a *archetype) Zero(index uintptr, id ID) {
2,903✔
423
        lay := a.getLayout(id)
2,903✔
424
        size := lay.itemSize
2,903✔
425
        if size == 0 {
5,444✔
426
                return
2,541✔
427
        }
2,541✔
428
        dst := unsafe.Add(lay.pointer, index*size)
362✔
429
        a.copy(a.graphNode.zeroPointer, dst, size)
362✔
430
}
431

432
// SetEntity overwrites an entity
433
func (a *archetype) SetEntity(index uintptr, entity Entity) {
1,087✔
434
        a.addEntity(index, &entity)
1,087✔
435
}
1,087✔
436

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

803✔
447
        src := rValue.UnsafePointer()
803✔
448
        a.copy(src, dst, size)
803✔
449
        return dst
803✔
450
}
451

452
// SetPointer overwrites a component with the data behind the given pointer
453
func (a *archetype) SetPointer(index uintptr, id ID, comp unsafe.Pointer) unsafe.Pointer {
2,559✔
454
        lay := a.getLayout(id)
2,559✔
455
        dst := a.Get(index, id)
2,559✔
456
        size := lay.itemSize
2,559✔
457
        if size == 0 {
5,093✔
458
                return dst
2,534✔
459
        }
2,534✔
460

461
        a.copy(comp, dst, size)
25✔
462
        return dst
25✔
463
}
464

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

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

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

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

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

501
// Len reports the number of entities in the archetype
502
func (a *archetype) Len() uint32 {
5,696✔
503
        return a.len
5,696✔
504
}
5,696✔
505

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

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

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

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

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

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

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

554
// extend the memory buffers if necessary for adding an entity.
555
func (a *archetype) extend(by uint32) {
9,810✔
556
        required := a.len + by
9,810✔
557
        if a.cap >= required {
19,584✔
558
                return
9,774✔
559
        }
9,774✔
560
        a.cap = capacityU32(required, a.graphNode.capacityIncrement)
36✔
561

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

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

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

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

4,946✔
592
        if index == old {
9,710✔
593
                return false
4,764✔
594
        }
4,764✔
595

596
        src := unsafe.Add(a.entityPointer, old*entitySize)
182✔
597
        dst := unsafe.Add(a.entityPointer, index*entitySize)
182✔
598
        a.copy(src, dst, entitySize)
182✔
599

182✔
600
        return true
182✔
601
}
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