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

mlange-42 / ark / 15069999656

16 May 2025 01:48PM CUT coverage: 99.797%. First build
15069999656

Pull #249

github

web-flow
Merge 611a431d4 into 9f5dff38a
Pull Request #249: Use faster pointer copying for trivial component types

61 of 63 new or added lines in 6 files covered. (96.83%)

8349 of 8366 relevant lines covered (99.8%)

18499.32 hits per line

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

96.97
/ecs/util.go
1
package ecs
2

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

9
// Page size of pagedSlice type
10
const pageSize = 32
11

12
// copyPtr copies from one pointer to another.
13
func copyPtr(src, dst unsafe.Pointer, itemSize uintptr) {
1,523,758✔
14
        dstSlice := (*[math.MaxInt32]byte)(dst)[:itemSize:itemSize]
1,523,758✔
15
        srcSlice := (*[math.MaxInt32]byte)(src)[:itemSize:itemSize]
1,523,758✔
16
        copy(dstSlice, srcSlice)
1,523,758✔
17
}
1,523,758✔
18

19
func copyItem(src, dst reflect.Value, from, to int) {
493,344✔
20
        dst.Index(to).Set(src.Index(from))
493,344✔
21
}
493,344✔
22

23
func copyRange(src, dst reflect.Value, start, count int) {
215✔
24
        srcSlice := src.Slice(0, count)
215✔
25
        dstSlice := dst.Slice(start, start+count)
215✔
26
        reflect.Copy(dstSlice, srcSlice)
215✔
27
}
215✔
28

29
func sizeOf(tp reflect.Type) uintptr {
1,954✔
30
        size, align := tp.Size(), uintptr(tp.Align())
1,954✔
31
        return (size + (align - 1)) / align * align
1,954✔
32
}
1,954✔
33

34
// appends to a slice, but guaranties to return a new one and not alter the original.
35
func appendNew[T any](sl []T, elems ...T) []T {
2,685✔
36
        sl2 := make([]T, len(sl), len(sl)+len(elems))
2,685✔
37
        copy(sl2, sl)
2,685✔
38
        sl2 = append(sl2, elems...)
2,685✔
39
        return sl2
2,685✔
40
}
2,685✔
41

42
// isRelation determines whether a type is a relation component.
43
func isRelation(tp reflect.Type) bool {
1,330✔
44
        if tp.Kind() != reflect.Struct || tp.NumField() == 0 {
1,333✔
45
                return false
3✔
46
        }
3✔
47
        field := tp.Field(0)
1,327✔
48
        return field.Type == relationTp && field.Name == relationTp.Name()
1,327✔
49
}
50

51
// isTrivial checks if a type is "trivial" (contains no pointers, slices, maps, strings, or channels).
52
// It also returns false if the type itself is one of these.
53
func isTrivial(tp reflect.Type) bool {
3,931✔
54
        // Base case: If the type is invalid, return false
3,931✔
55
        if tp == nil {
3,931✔
NEW
56
                return false
×
NEW
57
        }
×
58

59
        // Check if the type itself is a pointer, slice, map, or channel
60
        switch tp.Kind() {
3,931✔
61
        case reflect.Ptr, reflect.Slice, reflect.Map, reflect.Chan, reflect.Interface, reflect.String:
9✔
62
                return false
9✔
63
        }
64

65
        // If it's a struct, check its fields recursively
66
        if tp.Kind() == reflect.Struct {
5,327✔
67
                for i := 0; i < tp.NumField(); i++ {
3,993✔
68
                        field := tp.Field(i).Type
2,588✔
69
                        if !isTrivial(field) {
2,596✔
70
                                return false
8✔
71
                        }
8✔
72
                }
73
        }
74

75
        // If it's an array, check its elements recursively
76
        if tp.Kind() == reflect.Array {
3,917✔
77
                elemType := tp.Elem()
3✔
78
                if !isTrivial(elemType) {
5✔
79
                        return false
2✔
80
                }
2✔
81
        }
82

83
        // If none of the above conditions matched, it's trivial
84
        return true
3,912✔
85
}
86

87
// pagedSlice is a paged collection working with pages of length 32 slices.
88
// its primary purpose is pointer persistence, which is not given using simple slices.
89
//
90
// Implements [archetypes].
91
type pagedSlice[T any] struct {
92
        pages   [][]T
93
        len     int32
94
        lenLast int32
95
}
96

97
// Add adds a value to the paged slice.
98
func (p *pagedSlice[T]) Add(value T) {
2,451✔
99
        if p.len == 0 || p.lenLast == pageSize {
2,729✔
100
                p.pages = append(p.pages, make([]T, pageSize))
278✔
101
                p.lenLast = 0
278✔
102
        }
278✔
103
        p.pages[len(p.pages)-1][p.lenLast] = value
2,451✔
104
        p.len++
2,451✔
105
        p.lenLast++
2,451✔
106
}
107

108
// Get returns the value at the given index.
109
func (p *pagedSlice[T]) Get(index int32) *T {
558,102✔
110
        return &p.pages[index/pageSize][index%pageSize]
558,102✔
111
}
558,102✔
112

113
// Set sets the value at the given index.
114
func (p *pagedSlice[T]) Set(index int32, value T) {
1✔
115
        p.pages[index/pageSize][index%pageSize] = value
1✔
116
}
1✔
117

118
// Len returns the current number of items in the paged slice.
119
func (p *pagedSlice[T]) Len() int32 {
2,252✔
120
        return p.len
2,252✔
121
}
2,252✔
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