github.com/grailbio/bigslice@v0.0.0-20230519005545-30c4c12152ad/frame/unsafe.go (about)

     1  // Copyright 2018 GRAIL, Inc. All rights reserved.
     2  // Use of this source code is governed by the Apache 2.0
     3  // license that can be found in the LICENSE file.
     4  
     5  package frame
     6  
     7  import (
     8  	"reflect"
     9  	"unsafe"
    10  )
    11  
    12  const ptrSize = 4 << (^uintptr(0) >> 63)
    13  
    14  // Pointers reports whether type t contains any pointers. It is used
    15  // to decide whether write barriers need to be applied in memory
    16  // operations.
    17  func pointers(t reflect.Type) bool {
    18  	switch t.Kind() {
    19  	case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
    20  		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
    21  		reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
    22  		return false
    23  	case reflect.Array:
    24  		return pointers(t.Elem())
    25  	case reflect.Struct:
    26  		for i := 0; i < t.NumField(); i++ {
    27  			if pointers(t.Field(i).Type) {
    28  				return true
    29  			}
    30  		}
    31  		return false
    32  	default:
    33  		return true
    34  	}
    35  }
    36  
    37  // sliceHeader is a safe version of SliceHeader used within this package.
    38  type sliceHeader struct {
    39  	Data unsafe.Pointer
    40  	Len  int
    41  	Cap  int
    42  }
    43  
    44  // Assign copies src to dst where the data are the provided type.
    45  func assign(typ dataType, dst, src unsafe.Pointer) {
    46  	if typ.pointers {
    47  		if typ.size == ptrSize {
    48  			*(*unsafe.Pointer)(dst) = *(*unsafe.Pointer)(src)
    49  			return
    50  		}
    51  	} else {
    52  		switch typ.size {
    53  		case 8:
    54  			*(*int64)(dst) = *(*int64)(src)
    55  			return
    56  		case 4:
    57  			*(*int32)(dst) = *(*int32)(src)
    58  			return
    59  		case 2:
    60  			*(*int16)(dst) = *(*int16)(src)
    61  			return
    62  		case 1:
    63  			*(*int8)(dst) = *(*int8)(src)
    64  			return
    65  		}
    66  		// TODO(marius): see if using copy() is cheaper than typedmemove
    67  		// in these cases.
    68  	}
    69  	typedmemmove(typ.ptr, dst, src)
    70  }
    71  
    72  func add(base unsafe.Pointer, off uintptr) unsafe.Pointer {
    73  	return unsafe.Pointer(uintptr(base) + off)
    74  }
    75  
    76  //go:linkname typedslicecopy reflect.typedslicecopy
    77  func typedslicecopy(elemType unsafe.Pointer, dst, src sliceHeader) int
    78  
    79  //go:linkname typedmemmove reflect.typedmemmove
    80  func typedmemmove(t unsafe.Pointer, dst, src unsafe.Pointer)