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 }