gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

bytes.go (2003B)


      1 package byteutil
      2 
      3 import (
      4 	"reflect"
      5 	"unsafe"
      6 )
      7 
      8 // Copy returns a copy of []byte.
      9 func Copy(b []byte) []byte {
     10 	if b == nil {
     11 		return nil
     12 	}
     13 	p := make([]byte, len(b))
     14 	copy(p, b)
     15 	return p
     16 }
     17 
     18 // B2S returns a string representation of []byte without allocation.
     19 //
     20 // According to the Go spec strings are immutable and byte slices are not. The way this gets implemented is strings under the hood are:
     21 //
     22 //	type StringHeader struct {
     23 //		Data uintptr
     24 //		Len  int
     25 //	}
     26 //
     27 // while slices are:
     28 //
     29 //	type SliceHeader struct {
     30 //		Data uintptr
     31 //		Len  int
     32 //		Cap  int
     33 //	}
     34 //
     35 // because being mutable, you can change the data, length etc, but the string has to promise to be read-only to all who get copies of it.
     36 //
     37 // So in practice when you do a conversion of `string(byteSlice)` it actually performs an allocation because it has to copy the contents of the byte slice into a safe read-only state.
     38 //
     39 // Being that the shared fields are in the same struct indices (no different offsets), means that if you have a byte slice you can "forcibly" cast it to a string. Which in a lot of situations can be risky, because then it means you have a string that is NOT immutable, as if someone changes the data in the originating byte slice then the string will reflect that change! Now while this does seem hacky, and it _kind_ of is, it is something that you see performed in the standard library. If you look at the definition for `strings.Builder{}.String()` you'll see this :)
     40 func B2S(b []byte) string {
     41 	return *(*string)(unsafe.Pointer(&b))
     42 }
     43 
     44 // S2B returns a []byte representation of string without allocation (minus slice header).
     45 // See B2S() code comment, and this function's implementation for a better understanding.
     46 func S2B(s string) []byte {
     47 	var b []byte
     48 
     49 	// Get byte + string headers
     50 	bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
     51 	sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
     52 
     53 	// Manually set bytes to string
     54 	bh.Data = sh.Data
     55 	bh.Len = sh.Len
     56 	bh.Cap = sh.Len
     57 
     58 	return b
     59 }