Skip to content
Snippets Groups Projects
bytealg.go 3.19 KiB
Newer Older
  • Learn to ignore specific revisions
  • // Copyright 2018 The Go Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style
    // license that can be found in the LICENSE file.
    
    package bytealg
    
    import (
    	"internal/cpu"
    	"unsafe"
    )
    
    // Offsets into internal/cpu records for use in assembly.
    const (
    
    	offsetX86HasSSE42  = unsafe.Offsetof(cpu.X86.HasSSE42)
    	offsetX86HasAVX2   = unsafe.Offsetof(cpu.X86.HasAVX2)
    	offsetX86HasPOPCNT = unsafe.Offsetof(cpu.X86.HasPOPCNT)
    
    
    	offsetLOONG64HasLSX  = unsafe.Offsetof(cpu.Loong64.HasLSX)
    	offsetLOONG64HasLASX = unsafe.Offsetof(cpu.Loong64.HasLASX)
    
    
    	offsetS390xHasVX = unsafe.Offsetof(cpu.S390X.HasVX)
    
    
    	offsetPPC64HasPOWER9 = unsafe.Offsetof(cpu.PPC64.IsPOWER9)
    
    )
    
    // MaxLen is the maximum length of the string to be searched for (argument b) in Index.
    
    // If MaxLen is not 0, make sure MaxLen >= 4.
    
    
    // PrimeRK is the prime base used in Rabin-Karp algorithm.
    const PrimeRK = 16777619
    
    // HashStr returns the hash and the appropriate multiplicative
    // factor for use in Rabin-Karp algorithm.
    
    func HashStr[T string | []byte](sep T) (uint32, uint32) {
    
    	hash := uint32(0)
    	for i := 0; i < len(sep); i++ {
    		hash = hash*PrimeRK + uint32(sep[i])
    	}
    	var pow, sq uint32 = 1, PrimeRK
    	for i := len(sep); i > 0; i >>= 1 {
    		if i&1 != 0 {
    			pow *= sq
    		}
    		sq *= sq
    	}
    	return hash, pow
    }
    
    // HashStrRev returns the hash of the reverse of sep and the
    // appropriate multiplicative factor for use in Rabin-Karp algorithm.
    
    func HashStrRev[T string | []byte](sep T) (uint32, uint32) {
    
    	hash := uint32(0)
    	for i := len(sep) - 1; i >= 0; i-- {
    		hash = hash*PrimeRK + uint32(sep[i])
    	}
    	var pow, sq uint32 = 1, PrimeRK
    	for i := len(sep); i > 0; i >>= 1 {
    		if i&1 != 0 {
    			pow *= sq
    		}
    		sq *= sq
    	}
    	return hash, pow
    }
    
    // IndexRabinKarp uses the Rabin-Karp search algorithm to return the index of the
    
    // first occurrence of sep in s, or -1 if not present.
    func IndexRabinKarp[T string | []byte](s, sep T) int {
    
    	hashss, pow := HashStr(sep)
    	n := len(sep)
    
    	var h uint32
    	for i := 0; i < n; i++ {
    		h = h*PrimeRK + uint32(s[i])
    	}
    
    	if h == hashss && string(s[:n]) == string(sep) {
    
    		return 0
    	}
    	for i := n; i < len(s); {
    		h *= PrimeRK
    		h += uint32(s[i])
    		h -= pow * uint32(s[i-n])
    		i++
    
    		if h == hashss && string(s[i-n:i]) == string(sep) {
    
    // LastIndexRabinKarp uses the Rabin-Karp search algorithm to return the last index of the
    // occurrence of sep in s, or -1 if not present.
    func LastIndexRabinKarp[T string | []byte](s, sep T) int {
    	// Rabin-Karp search from the end of the string
    	hashss, pow := HashStrRev(sep)
    	n := len(sep)
    	last := len(s) - n
    	var h uint32
    	for i := len(s) - 1; i >= last; i-- {
    		h = h*PrimeRK + uint32(s[i])
    	}
    	if h == hashss && string(s[last:]) == string(sep) {
    		return last
    	}
    	for i := last - 1; i >= 0; i-- {
    		h *= PrimeRK
    		h += uint32(s[i])
    		h -= pow * uint32(s[i+n])
    		if h == hashss && string(s[i:i+n]) == string(sep) {
    			return i
    		}
    	}
    	return -1
    }
    
    
    // MakeNoZero makes a slice of length n and capacity of at least n Bytes
    // without zeroing the bytes (including the bytes between len and cap).
    
    // It is the caller's responsibility to ensure uninitialized bytes
    // do not leak to the end user.
    func MakeNoZero(n int) []byte