Created
November 7, 2019 13:25
-
-
Save ppanyukov/5507ef0c221bb6d7488a350013d77ff4 to your computer and use it in GitHub Desktop.
Go Hacks for Performance and Fun
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"unsafe" | |
) | |
// A demo of things you can do with strings and []byte slices | |
// in a dangerous and exciting ways. I got here by having to verify | |
// if two given strings point to the same storage in memory. | |
// You can do all sorts of interesting things in performance-critical paths | |
// to avoid allocs, re-allocs, mem copies and such like | |
// | |
// For inspiration see: | |
// https://golang.org/src/runtime/string.go | |
// https://golang.org/src/runtime/slie.go | |
// internal representation of slices | |
// https://golang.org/src/runtime/slice.go | |
type slice struct { | |
array unsafe.Pointer | |
len int | |
cap int | |
} | |
// internal representation of string | |
// https://golang.org/src/runtime/string.go | |
type stringStruct struct { | |
str unsafe.Pointer | |
len int | |
} | |
// convert string to its struct | |
// https://golang.org/src/runtime/string.go | |
func stringStructOf(sp *string) *stringStruct { | |
return (*stringStruct)(unsafe.Pointer(sp)) | |
} | |
// convert string to byte slice without copy | |
func stringToSlice(sp *string) []byte { | |
strPtr := stringStructOf(sp) | |
rawSlice := slice{strPtr.str, strPtr.len, strPtr.len} | |
return *(*[]byte)(unsafe.Pointer(&rawSlice)) | |
} | |
// quick demo of thigs we can do | |
func main(){ | |
// Make sure the string is on the heap, not a constant so we can | |
// modify it in place. If we had `var s = "hello"`, we would seg fault | |
// if we tried to write to it. | |
var s string = string([]byte("hello")) | |
sPtr := stringStructOf(&s) | |
sBytes := []byte(s) // this will copy the string's contents | |
sBytesNC := stringToSlice(&s) // this will not copy | |
// modify the first char of the string | |
sBytesNC[0] = 'X' | |
// print info about our objects | |
fmt.Printf("String: %s\n", s) | |
fmt.Printf(" len: %d\n", sPtr.len) | |
fmt.Printf(" ptr: %p\n", sPtr.str) | |
fmt.Printf("Bytes std: %v\n", sBytes) | |
fmt.Printf(" len: %d\n", len(sBytes)) | |
fmt.Printf(" ptr: %p\n", unsafe.Pointer(&sBytes[0])) | |
fmt.Printf("Bytes nocopy: %v\n", sBytesNC) | |
fmt.Printf(" len: %d\n", len(sBytesNC)) | |
fmt.Printf(" ptr: %p\n", unsafe.Pointer(&sBytesNC[0])) | |
fmt.Printf("========\n") | |
fmt.Printf("sPtr and sBytes point to same storage: %t\n", sPtr.str == unsafe.Pointer(&sBytes[0])) | |
fmt.Printf("sPtr and sBytesNC point to same storage: %t\n", sPtr.str == unsafe.Pointer(&sBytesNC[0])) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment