I have two structs:
type struct1 struct{
arr [num1]byte
}
type struct2 struct{
b1 [n1]uint64
b2 [n2]uint64
b3 [n3]uint64
}
Now, I have two pointers to these structs:
p1 := new(struct1);
p2 := new(struct2);
and after some computations, I want to copy p2 to a specified part of p1. Something like:
copy(p1.arr[k:], p2);
Where k is a positive integer. It can be easily done in C using memcpy
, but I could not find an easy way to do it in GO without using any external libraries. Does anyone have any suggestions? I'll really appreciate it.
You want to bypass the Go type system, which is unsafe. Therefore, you should be very careful. Implement this as a function and use the Go testing package to write tests. Check for errors. Write simple, readable code. Don't be clever.
For example,
package main
import (
"fmt"
"unsafe"
)
const num1 = 42
type struct1 struct {
arr [num1]byte
}
const (
n1 = 1
n2 = 2
n3 = 1
)
type struct2 struct {
b1 [n1]uint64
b2 [n2]uint64
b3 [n3]uint64
}
func arrInsert(p1 *struct1, i1 int, p2 *struct2) int {
if p1 == nil || p2 == nil {
return 0
}
if i1 < 0 || i1 >= len(p1.arr) {
return 0
}
s1 := p1.arr[i1:]
s2 := (*[unsafe.Sizeof(*p2)]byte)(unsafe.Pointer(p2))[:]
return copy(s1, s2)
}
func main() {
p1 := new(struct1)
p2 := new(struct2)
for i := range p2.b1 {
p2.b1[i] = uint64(i + 10)
}
for i := range p2.b2 {
p2.b2[i] = uint64(i + 20)
}
for i := range p2.b3 {
p2.b3[i] = uint64(i + 30)
}
n := arrInsert(p1, 1, p2)
fmt.Println(n)
fmt.Println(*p1)
fmt.Println((*[unsafe.Sizeof(*p2)]byte)(unsafe.Pointer(p2))[:])
fmt.Println(*p2)
}
Playground: https://play.golang.org/p/KA0B0xpFR6l
Output:
32
{[0 10 0 0 0 0 0 0 0 20 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 30 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]}
[10 0 0 0 0 0 0 0 20 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 30 0 0 0 0 0 0 0]
{[10] [20 21] [30]}
The problem as you have stated it doesn't make sense in terms of Go's types. Unlike in C, Go enforces its types and doesn't allow you access to the underlying bytes (without using unsafe).
For your problem, you need to restate it as wanting to copy each array from p2 into p1 in order. For that, you need to copy each individually like so:
k += copy(p1.arr[k:], p2.b1)
k += copy(p1.arr[k:], p2.b2)
k += copy(p1.arr[k:], p2.b3)
It is possible through unsafe to break type safety and copy the bytes directly. The problem is that there is no guarantee it will actually do what you want. The compiler could have placed b2 before b1 in the actual memory layout and caused it to do something you did not intend. This is unlikely, but compiler people have done much weirder things in pursuit of performance. C people like to call those things "undefined behavior". Use of unsafe in Go essentially triggers UB and I would not recommend it. However, for completeness, here is how you would memcopy in Go:
p2Slice = (*(*[unsafe.Sizeof(*p2)]byte)(unsafe.Pointer(p2)))[:]
copy(p1.arr[k:], p2Slice)
If that looks ugly... well that is intentional because you shouldn't do it! But in all seriousness, you could split what I did on one line into multiple lines to make it more readable.
const s = unsafe.Sizeof(*p2)
p2Arr = *(*[s]byte)(unsafe.Pointer(p2))
copy(p1.arr[k:], p2Arr[:])