github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/internal/bytealg/bytealg.go (about)

     1  // Copyright 2018 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package bytealg
     6  
     7  import (
     8  	"unsafe"
     9  
    10  	"github.com/hxx258456/ccgo/internal/cpu"
    11  )
    12  
    13  // Offsets into internal/cpu records for use in assembly.
    14  const (
    15  	offsetX86HasSSE2   = unsafe.Offsetof(cpu.X86.HasSSE2)
    16  	offsetX86HasSSE42  = unsafe.Offsetof(cpu.X86.HasSSE42)
    17  	offsetX86HasAVX2   = unsafe.Offsetof(cpu.X86.HasAVX2)
    18  	offsetX86HasPOPCNT = unsafe.Offsetof(cpu.X86.HasPOPCNT)
    19  
    20  	offsetS390xHasVX = unsafe.Offsetof(cpu.S390X.HasVX)
    21  
    22  	offsetPPC64HasPOWER9 = unsafe.Offsetof(cpu.PPC64.IsPOWER9)
    23  )
    24  
    25  // MaxLen is the maximum length of the string to be searched for (argument b) in Index.
    26  // If MaxLen is not 0, make sure MaxLen >= 4.
    27  var MaxLen int
    28  
    29  // FIXME: the logic of HashStrBytes, HashStrRevBytes, IndexRabinKarpBytes and HashStr, HashStrRev,
    30  // IndexRabinKarp are exactly the same, except that the types are different. Can we eliminate
    31  // three of them without causing allocation?
    32  
    33  // PrimeRK is the prime base used in Rabin-Karp algorithm.
    34  const PrimeRK = 16777619
    35  
    36  // HashStrBytes returns the hash and the appropriate multiplicative
    37  // factor for use in Rabin-Karp algorithm.
    38  func HashStrBytes(sep []byte) (uint32, uint32) {
    39  	hash := uint32(0)
    40  	for i := 0; i < len(sep); i++ {
    41  		hash = hash*PrimeRK + uint32(sep[i])
    42  	}
    43  	var pow, sq uint32 = 1, PrimeRK
    44  	for i := len(sep); i > 0; i >>= 1 {
    45  		if i&1 != 0 {
    46  			pow *= sq
    47  		}
    48  		sq *= sq
    49  	}
    50  	return hash, pow
    51  }
    52  
    53  // HashStr returns the hash and the appropriate multiplicative
    54  // factor for use in Rabin-Karp algorithm.
    55  func HashStr(sep string) (uint32, uint32) {
    56  	hash := uint32(0)
    57  	for i := 0; i < len(sep); i++ {
    58  		hash = hash*PrimeRK + uint32(sep[i])
    59  	}
    60  	var pow, sq uint32 = 1, PrimeRK
    61  	for i := len(sep); i > 0; i >>= 1 {
    62  		if i&1 != 0 {
    63  			pow *= sq
    64  		}
    65  		sq *= sq
    66  	}
    67  	return hash, pow
    68  }
    69  
    70  // HashStrRevBytes returns the hash of the reverse of sep and the
    71  // appropriate multiplicative factor for use in Rabin-Karp algorithm.
    72  func HashStrRevBytes(sep []byte) (uint32, uint32) {
    73  	hash := uint32(0)
    74  	for i := len(sep) - 1; i >= 0; i-- {
    75  		hash = hash*PrimeRK + uint32(sep[i])
    76  	}
    77  	var pow, sq uint32 = 1, PrimeRK
    78  	for i := len(sep); i > 0; i >>= 1 {
    79  		if i&1 != 0 {
    80  			pow *= sq
    81  		}
    82  		sq *= sq
    83  	}
    84  	return hash, pow
    85  }
    86  
    87  // HashStrRev returns the hash of the reverse of sep and the
    88  // appropriate multiplicative factor for use in Rabin-Karp algorithm.
    89  func HashStrRev(sep string) (uint32, uint32) {
    90  	hash := uint32(0)
    91  	for i := len(sep) - 1; i >= 0; i-- {
    92  		hash = hash*PrimeRK + uint32(sep[i])
    93  	}
    94  	var pow, sq uint32 = 1, PrimeRK
    95  	for i := len(sep); i > 0; i >>= 1 {
    96  		if i&1 != 0 {
    97  			pow *= sq
    98  		}
    99  		sq *= sq
   100  	}
   101  	return hash, pow
   102  }
   103  
   104  // IndexRabinKarpBytes uses the Rabin-Karp search algorithm to return the index of the
   105  // first occurrence of substr in s, or -1 if not present.
   106  func IndexRabinKarpBytes(s, sep []byte) int {
   107  	// Rabin-Karp search
   108  	hashsep, pow := HashStrBytes(sep)
   109  	n := len(sep)
   110  	var h uint32
   111  	for i := 0; i < n; i++ {
   112  		h = h*PrimeRK + uint32(s[i])
   113  	}
   114  	if h == hashsep && Equal(s[:n], sep) {
   115  		return 0
   116  	}
   117  	for i := n; i < len(s); {
   118  		h *= PrimeRK
   119  		h += uint32(s[i])
   120  		h -= pow * uint32(s[i-n])
   121  		i++
   122  		if h == hashsep && Equal(s[i-n:i], sep) {
   123  			return i - n
   124  		}
   125  	}
   126  	return -1
   127  }
   128  
   129  // IndexRabinKarp uses the Rabin-Karp search algorithm to return the index of the
   130  // first occurrence of substr in s, or -1 if not present.
   131  func IndexRabinKarp(s, substr string) int {
   132  	// Rabin-Karp search
   133  	hashss, pow := HashStr(substr)
   134  	n := len(substr)
   135  	var h uint32
   136  	for i := 0; i < n; i++ {
   137  		h = h*PrimeRK + uint32(s[i])
   138  	}
   139  	if h == hashss && s[:n] == substr {
   140  		return 0
   141  	}
   142  	for i := n; i < len(s); {
   143  		h *= PrimeRK
   144  		h += uint32(s[i])
   145  		h -= pow * uint32(s[i-n])
   146  		i++
   147  		if h == hashss && s[i-n:i] == substr {
   148  			return i - n
   149  		}
   150  	}
   151  	return -1
   152  }