-
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy patharray.go
More file actions
159 lines (138 loc) · 5.28 KB
/
Copy patharray.go
File metadata and controls
159 lines (138 loc) · 5.28 KB
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package ffmpeg
/*
#include <stddef.h>
#include <stdint.h>
*/
import "C"
import (
"unsafe"
)
const (
ptrSize = uintptr(C.sizeof_size_t)
intSize = uintptr(C.sizeof_int)
int8Size = uintptr(C.sizeof_int8_t)
int16Size = uintptr(C.sizeof_int16_t)
int32Size = uintptr(C.sizeof_int32_t)
int64Size = uintptr(C.sizeof_int64_t)
float64Size = uintptr(C.sizeof_double)
)
// Array is a helper utility for accessing arrays of FFmpeg types. You can not directly allocate this type, and you must
// use one of the inbuilt constructors, such as AllocAVCodecIDArray.
//
// Arrays carry no length, matching the behaviour of C code: the constructors take only a pointer, so the bound is never
// known to the Array itself. There is therefore no bounds checking on Get or Set. The caller is wholly responsible for
// tracking the valid length and never indexing past it — an out-of-bounds index reads or writes arbitrary process
// memory, exactly like an over-run C pointer, with no panic to stop you. This is a raw, unsafe accessor; treat every
// index as if you were dereferencing the pointer by hand.
type Array[T any] struct {
ptr unsafe.Pointer
elemSize uintptr
loadPtr func(pointer unsafe.Pointer) T
storePtr func(pointer unsafe.Pointer, value T)
}
// Get returns the element at the ith offset. There is no bounds check: passing an index outside the array reads
// arbitrary process memory and is undefined behaviour. The caller must guarantee i is within the known length.
func (a *Array[T]) Get(i uintptr) T {
ptr := unsafe.Add(a.ptr, i*a.elemSize)
return a.loadPtr(ptr)
}
// Set sets the element at the ith offset. There is no bounds check: passing an index outside the array writes
// arbitrary process memory and is undefined behaviour. The caller must guarantee i is within the known length.
func (a *Array[T]) Set(i uintptr, value T) {
ptr := unsafe.Add(a.ptr, i*a.elemSize)
a.storePtr(ptr, value)
}
// Free deallocates the underlying memory. You should only call this if you own the array.
func (a *Array[T]) Free() {
AVFree(a.ptr)
a.ptr = nil
}
// RawPtr returns a raw handle the underlying allocation.
func (a *Array[T]) RawPtr() unsafe.Pointer {
return a.ptr
}
// newArray creates an Array wrapper for a C array pointer.
// This is a factory function that encapsulates the common nil-check and Array construction pattern.
func newArray[T any](ptr unsafe.Pointer, elemSize uintptr, load func(unsafe.Pointer) T, store func(unsafe.Pointer, T)) *Array[T] {
if ptr == nil {
return nil
}
return &Array[T]{
ptr: ptr,
elemSize: elemSize,
loadPtr: load,
storePtr: store,
}
}
func ToIntArray(ptr unsafe.Pointer) *Array[int] {
return newArray(ptr, intSize,
func(p unsafe.Pointer) int { return int(*(*C.int)(p)) },
func(p unsafe.Pointer, v int) { *(*C.int)(p) = C.int(v) },
)
}
func ToUintArray(ptr unsafe.Pointer) *Array[uint] {
return newArray(ptr, intSize,
func(p unsafe.Pointer) uint { return uint(*(*C.uint)(p)) },
func(p unsafe.Pointer, v uint) { *(*C.uint)(p) = C.uint(v) },
)
}
func ToUint8Array(ptr unsafe.Pointer) *Array[uint8] {
return newArray(ptr, int8Size,
func(p unsafe.Pointer) uint8 { return uint8(*(*C.uint8_t)(p)) },
func(p unsafe.Pointer, v uint8) { *(*C.uint8_t)(p) = C.uint8_t(v) },
)
}
func ToInt8Array(ptr unsafe.Pointer) *Array[int8] {
return newArray(ptr, int8Size,
func(p unsafe.Pointer) int8 { return int8(*(*C.int8_t)(p)) },
func(p unsafe.Pointer, v int8) { *(*C.int8_t)(p) = C.int8_t(v) },
)
}
func ToUint16Array(ptr unsafe.Pointer) *Array[uint16] {
return newArray(ptr, int16Size,
func(p unsafe.Pointer) uint16 { return uint16(*(*C.uint16_t)(p)) },
func(p unsafe.Pointer, v uint16) { *(*C.uint16_t)(p) = C.uint16_t(v) },
)
}
func ToInt16Array(ptr unsafe.Pointer) *Array[int16] {
return newArray(ptr, int16Size,
func(p unsafe.Pointer) int16 { return int16(*(*C.int16_t)(p)) },
func(p unsafe.Pointer, v int16) { *(*C.int16_t)(p) = C.int16_t(v) },
)
}
func ToUint32Array(ptr unsafe.Pointer) *Array[uint32] {
return newArray(ptr, int32Size,
func(p unsafe.Pointer) uint32 { return uint32(*(*C.uint32_t)(p)) },
func(p unsafe.Pointer, v uint32) { *(*C.uint32_t)(p) = C.uint32_t(v) },
)
}
func ToInt32Array(ptr unsafe.Pointer) *Array[int32] {
return newArray(ptr, int32Size,
func(p unsafe.Pointer) int32 { return int32(*(*C.int32_t)(p)) },
func(p unsafe.Pointer, v int32) { *(*C.int32_t)(p) = C.int32_t(v) },
)
}
func ToInt64Array(ptr unsafe.Pointer) *Array[int64] {
return newArray(ptr, int64Size,
func(p unsafe.Pointer) int64 { return int64(*(*C.int64_t)(p)) },
func(p unsafe.Pointer, v int64) { *(*C.int64_t)(p) = C.int64_t(v) },
)
}
func ToUint64Array(ptr unsafe.Pointer) *Array[uint64] {
return newArray(ptr, int64Size,
func(p unsafe.Pointer) uint64 { return uint64(*(*C.uint64_t)(p)) },
func(p unsafe.Pointer, v uint64) { *(*C.uint64_t)(p) = C.uint64_t(v) },
)
}
func ToFloat64Array(ptr unsafe.Pointer) *Array[float64] {
return newArray(ptr, float64Size,
func(p unsafe.Pointer) float64 { return float64(*(*C.double)(p)) },
func(p unsafe.Pointer, v float64) { *(*C.double)(p) = C.double(v) },
)
}
func ToUint8PtrArray(ptr unsafe.Pointer) *Array[unsafe.Pointer] {
return newArray(ptr, ptrSize,
func(p unsafe.Pointer) unsafe.Pointer { return *(*unsafe.Pointer)(p) },
func(p unsafe.Pointer, v unsafe.Pointer) { *(*unsafe.Pointer)(p) = v },
)
}