Skip to content

Instantly share code, notes, and snippets.

@nicerobot
Last active December 11, 2023 02:09
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nicerobot/832cf3a388e54b44f1c5 to your computer and use it in GitHub Desktop.
Save nicerobot/832cf3a388e54b44f1c5 to your computer and use it in GitHub Desktop.
Alias a []float64 slice as a []byte slice
package main
import (
"encoding/binary"
"unsafe"
)
// Returns a slice of the bytes of the provided float64 slice.
// This allows highly performant access to large float64 slices for such things
// as computing hashes or simply writing the bytes to a file.
// BEWARE: this also means this []byte _is platform dependent_.
func float64SliceAsByteSlice(floats []float64) ([]byte, binary.ByteOrder) {
lf := 8 * len(floats)
// step by step
pf := &(floats[0]) // To pointer to the first byte of b
up := unsafe.Pointer(pf) // To *special* unsafe.Pointer, it can be converted to any pointer
pi := (*[1]byte)(up) // To pointer as byte array
buf := (*pi)[:] // Creates slice to our array of 1 byte
address := unsafe.Pointer(&buf) // Capture the address to the slice structure
lenAddr := uintptr(address) + uintptr(8) // Capture the address where the length and cap size is stored
capAddr := uintptr(address) + uintptr(16) // WARNING: This is fragile, depending on a go-internal structure.
lenPtr := (*int)(unsafe.Pointer(lenAddr)) // Create pointers to the length and cap size
capPtr := (*int)(unsafe.Pointer(capAddr)) //
*lenPtr = lf // Assign the actual slice size and cap
*capPtr = lf //
return buf, nativeEndianness
}
var nativeEndianness binary.ByteOrder
func init() {
var i int32 = 0x01020304
u := unsafe.Pointer(&i)
pb := (*byte)(u)
b := *pb
if b == 0x04 {
nativeEndianness = binary.LittleEndian
} else {
nativeEndianness = binary.BigEndian
}
}
package main
import (
"math"
"testing"
)
//
func TestUnsafeFloatToByte(t *testing.T) {
fa := make([]float64, 2)
fa[0] = math.MaxFloat64
fa[1] = -math.MaxFloat64
t.Logf("floats before: %v", fa)
ba, end := float64SliceAsByteSlice(fa)
t.Logf("%v", end)
t.Logf("floats as bytes before: %v", ba)
// This swaps the values in fa[0] and fa[1]
ba[7], ba[15] = ba[15], ba[7]
t.Logf("floats as bytes after: %v", ba)
t.Logf("floats after: %v", fa)
if fa[0] != -math.MaxFloat64 {
t.Error("fa[0] not negative")
}
if fa[1] != math.MaxFloat64 {
t.Error("fa[1] not positive")
}
}
.PHONY: test
test:
go test -v
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment