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