Skip to content

Instantly share code, notes, and snippets.

@bgadrian
Created May 14, 2020 21:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bgadrian/a4f56313ef38b11efed6ea387818e8b9 to your computer and use it in GitHub Desktop.
Save bgadrian/a4f56313ef38b11efed6ea387818e8b9 to your computer and use it in GitHub Desktop.
go slices more tricks
// StringToImmutableBytes returns a slice of bytes from a string without allocating memory
// it is the caller's responsibility not to mutate the bytes returned.
func StringToImmutableBytes(s string) []byte {
if len(s) == 0 {
return nil
}
// NB(xichen): We need to declare a real byte slice so internally the compiler
// knows to use an unsafe.Pointer to keep track of the underlying memory so that
// once the slice's array pointer is updated with the pointer to the string's
// underlying bytes, the compiler won't prematurely GC the memory when the string
// goes out of scope.
var b []byte
byteHeader := (*reflect.SliceHeader)(unsafe.Pointer(&b))
// NB(xichen): This makes sure that even if GC relocates the string's underlying
// memory after this assignment, the corresponding unsafe.Pointer in the internal
// slice struct will be updated accordingly to reflect the memory relocation.
byteHeader.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
// NB(xichen): It is important that we access s after we assign the Data
// pointer of the string header to the Data pointer of the slice header to
// make sure the string (and the underlying bytes backing the string) don't get
// GC'ed before the assignment happens.
l := len(s)
byteHeader.Len = l
byteHeader.Cap = l
return b
}
func concatSlices(slices ...[]byte) []byte {
var totalLen int
for _, s := range slices {
totalLen += len(s)
}
tmp := make([]byte, totalLen)
var i int
for _, s := range slices {
i += copy(tmp[i:], s)
}
return tmp
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment