This repository was archived by the owner on Mar 14, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathunsafeslice.go
95 lines (84 loc) · 3.69 KB
/
unsafeslice.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package unsafeslice implements common unsafe transformations involving slices,
// based on the reflective prototype in github.com/bcmills/unsafeslice.
//
// unsafeslice uses the reflect package only for the SliceHeader type definition.
// That dependency could be eliminated using a local definition and regression
// test, as is done in the internal/unsafeheader package in Go 1.15.
package unsafeslice
import (
"fmt"
"reflect"
"unsafe"
)
// Of returns a slice of length and capacity n located at p.
//
// The caller must ensure that p points to a backing array containing at least n
// elements with an equivalent layout, size, and alignment to T.
//
// This implements one possible API for https://golang.org/issue/19367
// and https://golang.org/issue/13656.
func Of[T any](p *T, n int) []T {
return unsafe.Slice(p, n)
}
// Convert returns a slice that refers to the same memory region as the slice src,
// but at an arbitrary element type.
//
// At some call sites, ConvertAt may provide better type inference than Convert.
//
// The caller must ensure that the length and capacity in bytes of src are
// integer multiples of the size of T2, and that the fields at each byte offset
// in the resulting slices have equivalent layouts.
//
// This implements one possible API for https://golang.org/issue/38203.
func Convert[T1, T2 any](src []T1) []T2 {
srcElemSize := reflect.TypeOf(src).Elem().Size()
capBytes := uintptr(cap(src)) * srcElemSize
lenBytes := uintptr(len(src)) * srcElemSize
dstElemSize := reflect.TypeOf((*T2)(nil)).Elem().Size()
if capBytes%dstElemSize != 0 {
panic(fmt.Sprintf("Convert: src capacity (%d bytes) is not a multiple of dst element size (%T: %d bytes)", capBytes, *new(T2), dstElemSize))
}
dstCap := capBytes / dstElemSize
if int(dstCap) < 0 || uintptr(int(dstCap)) != dstCap {
panic(fmt.Sprintf("Convert: dst capacity (%d) overflows int", dstCap))
}
if lenBytes%dstElemSize != 0 {
panic(fmt.Sprintf("Convert: src length (%d bytes) is not a multiple of dst element size (%T: %d bytes)", lenBytes, *new(T2), dstElemSize))
}
dstLen := lenBytes / dstElemSize
if int(dstLen) < 0 || uintptr(int(dstLen)) != dstLen {
panic(fmt.Sprintf("ConvertAt: dst length (%d) overflows int", dstLen))
}
return unsafe.Slice((*T2)(unsafe.Pointer(unsafe.SliceData(src))), dstCap)[:dstLen]
}
// ConvertAt sets dst, which must be non-nil, to a slice that refers to the same
// memory region as the slice src, but possibly at a different type.
//
// The caller must ensure that the length and capacity in bytes of src are
// integer multiples of the size of T2, and that the fields at each byte offset
// in the resulting slices have equivalent layouts.
//
// This implements one possible API for https://golang.org/issue/38203.
func ConvertAt[T2, T1 any](dst *[]T2, src []T1) {
*dst = Convert[T1, T2](src)
}
// AsPointer returns a pointer to the array backing src[0:len(src)] as type *T.
//
// The caller must ensure that the length in bytes of src is an integer multiple
// of the size of T, and that the fields at each byte offset in the resulting
// slice have a layout equivalent to T.
//
// At some call sites, SetPointer may provide better type inference than
// AsPointer.
func AsPointer[E, T any](src []E) *T {
return unsafe.SliceData(Convert[E, T](src[:len(src):len(src)]))
}
// SetPointer sets dst, which must be non-nil, to a pointer that refers to the
// elements of src. Typically, dst should point to a pointer to an array with
// the same length and element type as src.
func SetPointer[T, E any](dst **T, src []E) {
*dst = AsPointer[E, T](src)
}