github.com/vc42/parquet-go@v0.0.0-20240320194221-1a9adb5f23f5/internal/unsafecast/unsafecast_go18.go (about)

     1  //go:build go1.18
     2  
     3  // Package unsafecast exposes functions to bypass the Go type system and perform
     4  // conversions between types that would otherwise not be possible.
     5  //
     6  // The functions of this package are mostly useful as optimizations to avoid
     7  // memory copies when converting between compatible memory layouts; for example,
     8  // casting a [][16]byte to a []byte in order to use functions of the standard
     9  // bytes package on the slices.
    10  //
    11  //		With great power comes great responsibility.
    12  //
    13  package unsafecast
    14  
    15  import (
    16  	"reflect"
    17  	"unsafe"
    18  )
    19  
    20  // AddressOf returns the address to the first element in data, even if the slice
    21  // has length zero.
    22  func AddressOf[T any](data []T) *T {
    23  	return *(**T)(unsafe.Pointer(&data))
    24  }
    25  
    26  // AddressOfBytes returns the address of the first byte in data.
    27  func AddressOfBytes(data []byte) *byte {
    28  	return AddressOf(data)
    29  }
    30  
    31  // AddressOfString returns the address of the first byte in data.
    32  func AddressOfString(data string) *byte {
    33  	return *(**byte)(unsafe.Pointer(&data))
    34  }
    35  
    36  // PointerOf is like AddressOf but returns an unsafe.Pointer, losing type
    37  // information about the underlying data.
    38  func PointerOf[T any](data []T) unsafe.Pointer {
    39  	return unsafe.Pointer(AddressOf(data))
    40  }
    41  
    42  // PointerOfString is like AddressOfString but returns an unsafe.Pointer, losing
    43  // type information about the underlying data.
    44  func PointerOfString(data string) unsafe.Pointer {
    45  	return unsafe.Pointer(AddressOfString(data))
    46  }
    47  
    48  // PointerOfValue returns the address of the object packed in the given value.
    49  //
    50  // This function is like value.UnsafePointer but works for any underlying type,
    51  // bypassing the safety checks done by the reflect package.
    52  func PointerOfValue(value reflect.Value) unsafe.Pointer {
    53  	return (*[2]unsafe.Pointer)(unsafe.Pointer(&value))[1]
    54  }
    55  
    56  // The slice type represents the memory layout of slices in Go. It is similar to
    57  // reflect.SliceHeader but uses a unsafe.Pointer instead of uintptr to for the
    58  // backing array to allow the garbage collector to track track the reference.
    59  type slice struct {
    60  	ptr unsafe.Pointer
    61  	len int
    62  	cap int
    63  }
    64  
    65  // Slice converts the data slice of type []From to a slice of type []To sharing
    66  // the same backing array. The length and capacity of the returned slice are
    67  // scaled according to the size difference between the source and destination
    68  // types.
    69  //
    70  // Note that the function does not perform any checks to ensure that the memory
    71  // layouts of the types are compatible, it is possible to cause memory
    72  // corruption if the layouts mismatch (e.g. the pointers in the From are different
    73  // than the pointers in To).
    74  func Slice[To, From any](data []From) []To {
    75  	// This function could use unsafe.Slice but it would drop the capacity
    76  	// information, so instead we implement the type conversion.
    77  	var zf From
    78  	var zt To
    79  	var s = (*slice)(unsafe.Pointer(&data))
    80  	s.len = int((uintptr(s.len) * unsafe.Sizeof(zf)) / unsafe.Sizeof(zt))
    81  	s.cap = int((uintptr(s.cap) * unsafe.Sizeof(zf)) / unsafe.Sizeof(zt))
    82  	return *(*[]To)(unsafe.Pointer(s))
    83  }
    84  
    85  // BytesToString converts a byte slice to a string value. The returned string
    86  // shares the backing array of the byte slice.
    87  //
    88  // Programs using this function are responsible for ensuring that the data slice
    89  // is not modified while the returned string is in use, otherwise the guarantee
    90  // of immutability of Go string values will be violated, resulting in undefined
    91  // behavior.
    92  func BytesToString(data []byte) string {
    93  	return *(*string)(unsafe.Pointer(&data))
    94  }
    95  
    96  // StringToBytes applies the inverse conversion of BytesToString.
    97  func StringToBytes(data string) []byte {
    98  	return *(*[]byte)(unsafe.Pointer(&slice{
    99  		ptr: PointerOfString(data),
   100  		len: len(data),
   101  		cap: len(data),
   102  	}))
   103  }
   104  
   105  // -----------------------------------------------------------------------------
   106  // TODO: the functions below are used for backward compatibility with Go 1.17
   107  // where generics weren't available. We should remove them and inline calls to
   108  // unsafecast.Slice when we change our minimum supported Go version to 1.18.
   109  // -----------------------------------------------------------------------------
   110  
   111  func BoolToBytes(data []bool) []byte { return Slice[byte](data) }
   112  
   113  func Int8ToBytes(data []int8) []byte { return Slice[byte](data) }
   114  
   115  func Int16ToBytes(data []int16) []byte { return Slice[byte](data) }
   116  
   117  func Int32ToBytes(data []int32) []byte { return Slice[byte](data) }
   118  
   119  func Int64ToBytes(data []int64) []byte { return Slice[byte](data) }
   120  
   121  func Float32ToBytes(data []float32) []byte { return Slice[byte](data) }
   122  
   123  func Float64ToBytes(data []float64) []byte { return Slice[byte](data) }
   124  
   125  func Uint32ToBytes(data []uint32) []byte { return Slice[byte](data) }
   126  
   127  func Uint64ToBytes(data []uint64) []byte { return Slice[byte](data) }
   128  
   129  func Uint128ToBytes(data [][16]byte) []byte { return Slice[byte](data) }
   130  
   131  func Int16ToUint16(data []int16) []uint16 { return Slice[uint16](data) }
   132  
   133  func Int32ToUint32(data []int32) []uint32 { return Slice[uint32](data) }
   134  
   135  func Int64ToUint64(data []int64) []uint64 { return Slice[uint64](data) }
   136  
   137  func Float32ToUint32(data []float32) []uint32 { return Slice[uint32](data) }
   138  
   139  func Float64ToUint64(data []float64) []uint64 { return Slice[uint64](data) }
   140  
   141  func Uint32ToInt32(data []uint32) []int32 { return Slice[int32](data) }
   142  
   143  func Uint32ToInt64(data []uint32) []int64 { return Slice[int64](data) }
   144  
   145  func Uint64ToInt64(data []uint64) []int64 { return Slice[int64](data) }
   146  
   147  func BytesToBool(data []byte) []bool { return Slice[bool](data) }
   148  
   149  func BytesToInt8(data []byte) []int8 { return Slice[int8](data) }
   150  
   151  func BytesToInt16(data []byte) []int16 { return Slice[int16](data) }
   152  
   153  func BytesToInt32(data []byte) []int32 { return Slice[int32](data) }
   154  
   155  func BytesToInt64(data []byte) []int64 { return Slice[int64](data) }
   156  
   157  func BytesToUint32(data []byte) []uint32 { return Slice[uint32](data) }
   158  
   159  func BytesToUint64(data []byte) []uint64 { return Slice[uint64](data) }
   160  
   161  func BytesToUint128(data []byte) [][16]byte { return Slice[[16]byte](data) }
   162  
   163  func BytesToFloat32(data []byte) []float32 { return Slice[float32](data) }
   164  
   165  func BytesToFloat64(data []byte) []float64 { return Slice[float64](data) }