github.com/Nigel2392/go-datastructures@v1.1.5/fastcompare.go (about)

     1  package datastructures
     2  
     3  import "unsafe"
     4  
     5  // Inspiration from https://github.com/golang/go/blob/master/src/runtime/map_faststr.go
     6  //
     7  //go:linkname memequal runtime.memequal
     8  func memequal(a, b unsafe.Pointer, n uintptr) bool
     9  
    10  // Inspiration from https://github.com/golang/go/blob/master/src/runtime/map_faststr.go
    11  type _string struct {
    12  	str unsafe.Pointer
    13  	len int
    14  }
    15  
    16  type stringType interface {
    17  	~string
    18  }
    19  
    20  // A fast string comparison function.
    21  //
    22  // Can compare any type which is a direct or indirect subtype of string.
    23  //
    24  // This function is based on the map_faststr.go implementation in the Go runtime.
    25  //
    26  // Returns true if the strings are equal, false otherwise.
    27  func FastStrCmp[T stringType](a, b T) bool {
    28  	var (
    29  		aStr = (*_string)(unsafe.Pointer(&a))
    30  		bStr = (*_string)(unsafe.Pointer(&b))
    31  	)
    32  	if aStr.len != bStr.len {
    33  		return false
    34  	}
    35  	// if len < 32 a lot of comparisons wont matter, or so the documentation says.
    36  	if aStr.len < 32 {
    37  		return aStr.str == bStr.str || memequal(aStr.str, bStr.str, uintptr(aStr.len))
    38  	}
    39  
    40  	// Check if the first 4 bytes are equal
    41  	if *((*[4]byte)(unsafe.Pointer(aStr.str))) != *((*[4]byte)(unsafe.Pointer(bStr.str))) {
    42  		return false
    43  	}
    44  	// Check if the last 4 bytes are equal
    45  	if *((*[4]byte)(unsafe.Pointer(uintptr(aStr.str) + uintptr(aStr.len) - 4))) != *((*[4]byte)(unsafe.Pointer(uintptr(bStr.str) + uintptr(bStr.len) - 4))) {
    46  		return false
    47  	}
    48  
    49  	// compare the whole string
    50  	return memequal(aStr.str, bStr.str, uintptr(aStr.len))
    51  }
    52  
    53  func FastStrHash[T stringType](s T) uint64 {
    54  	// return murmurHash3_64(s, 0)
    55  	var (
    56  		str = (*_string)(unsafe.Pointer(&s))
    57  		h   = uint64(0)
    58  	)
    59  	for i := 0; i < str.len; i++ {
    60  		h = 63*h + uint64(*(*byte)(unsafe.Pointer(uintptr(str.str) + uintptr(i))))
    61  	}
    62  	return h
    63  }