Skip to content

Instantly share code, notes, and snippets.

@ppanyukov
Created November 7, 2019 13:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ppanyukov/5507ef0c221bb6d7488a350013d77ff4 to your computer and use it in GitHub Desktop.
Save ppanyukov/5507ef0c221bb6d7488a350013d77ff4 to your computer and use it in GitHub Desktop.
Go Hacks for Performance and Fun
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