github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/internal/bytealg/bytealg.go (about)

     1  package bytealg
     2  
     3  // Some code in this file has been copied from the Go source code, and has
     4  // copyright of their original authors:
     5  //
     6  // Copyright 2020 The Go Authors. All rights reserved.
     7  // Use of this source code is governed by a BSD-style
     8  // license that can be found in the LICENSE file.
     9  //
    10  // This is indicated specifically in the file.
    11  
    12  const (
    13  	// Index can search any valid length of string.
    14  
    15  	MaxLen        = int(-1) >> 31
    16  	MaxBruteForce = MaxLen
    17  )
    18  
    19  // Compare two byte slices.
    20  // Returns -1 if the first differing byte is lower in a, or 1 if the first differing byte is greater in b.
    21  // If the byte slices are equal, returns 0.
    22  // If the lengths are different and there are no differing bytes, compares based on length.
    23  func Compare(a, b []byte) int {
    24  	// Compare for differing bytes.
    25  	for i := 0; i < len(a) && i < len(b); i++ {
    26  		switch {
    27  		case a[i] < b[i]:
    28  			return -1
    29  		case a[i] > b[i]:
    30  			return 1
    31  		}
    32  	}
    33  
    34  	// Compare lengths.
    35  	switch {
    36  	case len(a) > len(b):
    37  		return 1
    38  	case len(a) < len(b):
    39  		return -1
    40  	default:
    41  		return 0
    42  	}
    43  }
    44  
    45  // Count the number of instances of a byte in a slice.
    46  func Count(b []byte, c byte) int {
    47  	// Use a simple implementation, as there is no intrinsic that does this like we want.
    48  	n := 0
    49  	for _, v := range b {
    50  		if v == c {
    51  			n++
    52  		}
    53  	}
    54  	return n
    55  }
    56  
    57  // Count the number of instances of a byte in a string.
    58  func CountString(s string, c byte) int {
    59  	// Use a simple implementation, as there is no intrinsic that does this like we want.
    60  	// Currently, the compiler does not generate zero-copy byte-string conversions, so this needs to be seperate from Count.
    61  	n := 0
    62  	for i := 0; i < len(s); i++ {
    63  		if s[i] == c {
    64  			n++
    65  		}
    66  	}
    67  	return n
    68  }
    69  
    70  // Cutover is not reachable in TinyGo, but must exist as it is referenced.
    71  func Cutover(n int) int {
    72  	// Setting MaxLen and MaxBruteForce should force a different path to be taken.
    73  	// This should never be called.
    74  	panic("cutover is unreachable")
    75  }
    76  
    77  // Equal checks if two byte slices are equal.
    78  // It is equivalent to bytes.Equal.
    79  func Equal(a, b []byte) bool {
    80  	if len(a) != len(b) {
    81  		return false
    82  	}
    83  
    84  	for i, v := range a {
    85  		if v != b[i] {
    86  			return false
    87  		}
    88  	}
    89  
    90  	return true
    91  }
    92  
    93  // Index finds the base index of the first instance of the byte sequence b in a.
    94  // If a does not contain b, this returns -1.
    95  func Index(a, b []byte) int {
    96  	for i := 0; i <= len(a)-len(b); i++ {
    97  		if Equal(a[i:i+len(b)], b) {
    98  			return i
    99  		}
   100  	}
   101  	return -1
   102  }
   103  
   104  // Index finds the index of the first instance of the specified byte in the slice.
   105  // If the byte is not found, this returns -1.
   106  func IndexByte(b []byte, c byte) int {
   107  	for i, v := range b {
   108  		if v == c {
   109  			return i
   110  		}
   111  	}
   112  	return -1
   113  }
   114  
   115  // Index finds the index of the first instance of the specified byte in the string.
   116  // If the byte is not found, this returns -1.
   117  func IndexByteString(s string, c byte) int {
   118  	for i := 0; i < len(s); i++ {
   119  		if s[i] == c {
   120  			return i
   121  		}
   122  	}
   123  	return -1
   124  }
   125  
   126  // Index finds the base index of the first instance of a substring in a string.
   127  // If the substring is not found, this returns -1.
   128  func IndexString(str, sub string) int {
   129  	for i := 0; i <= len(str)-len(sub); i++ {
   130  		if str[i:i+len(sub)] == sub {
   131  			return i
   132  		}
   133  	}
   134  	return -1
   135  }
   136  
   137  // The following code has been copied from the Go 1.15 release tree.
   138  
   139  // PrimeRK is the prime base used in Rabin-Karp algorithm.
   140  const PrimeRK = 16777619
   141  
   142  // HashStrBytes returns the hash and the appropriate multiplicative
   143  // factor for use in Rabin-Karp algorithm.
   144  //
   145  // This function was removed in Go 1.22.
   146  func HashStrBytes(sep []byte) (uint32, uint32) {
   147  	hash := uint32(0)
   148  	for i := 0; i < len(sep); i++ {
   149  		hash = hash*PrimeRK + uint32(sep[i])
   150  	}
   151  	var pow, sq uint32 = 1, PrimeRK
   152  	for i := len(sep); i > 0; i >>= 1 {
   153  		if i&1 != 0 {
   154  			pow *= sq
   155  		}
   156  		sq *= sq
   157  	}
   158  	return hash, pow
   159  }
   160  
   161  // HashStr returns the hash and the appropriate multiplicative
   162  // factor for use in Rabin-Karp algorithm.
   163  //
   164  // This function was removed in Go 1.22.
   165  func HashStr[T string | []byte](sep T) (uint32, uint32) {
   166  	hash := uint32(0)
   167  	for i := 0; i < len(sep); i++ {
   168  		hash = hash*PrimeRK + uint32(sep[i])
   169  	}
   170  	var pow, sq uint32 = 1, PrimeRK
   171  	for i := len(sep); i > 0; i >>= 1 {
   172  		if i&1 != 0 {
   173  			pow *= sq
   174  		}
   175  		sq *= sq
   176  	}
   177  	return hash, pow
   178  }
   179  
   180  // HashStrRevBytes returns the hash of the reverse of sep and the
   181  // appropriate multiplicative factor for use in Rabin-Karp algorithm.
   182  //
   183  // This function was removed in Go 1.22.
   184  func HashStrRevBytes(sep []byte) (uint32, uint32) {
   185  	hash := uint32(0)
   186  	for i := len(sep) - 1; i >= 0; i-- {
   187  		hash = hash*PrimeRK + uint32(sep[i])
   188  	}
   189  	var pow, sq uint32 = 1, PrimeRK
   190  	for i := len(sep); i > 0; i >>= 1 {
   191  		if i&1 != 0 {
   192  			pow *= sq
   193  		}
   194  		sq *= sq
   195  	}
   196  	return hash, pow
   197  }
   198  
   199  // HashStrRev returns the hash of the reverse of sep and the
   200  // appropriate multiplicative factor for use in Rabin-Karp algorithm.
   201  //
   202  // Copied from the Go 1.22rc1 source tree.
   203  func HashStrRev[T string | []byte](sep T) (uint32, uint32) {
   204  	hash := uint32(0)
   205  	for i := len(sep) - 1; i >= 0; i-- {
   206  		hash = hash*PrimeRK + uint32(sep[i])
   207  	}
   208  	var pow, sq uint32 = 1, PrimeRK
   209  	for i := len(sep); i > 0; i >>= 1 {
   210  		if i&1 != 0 {
   211  			pow *= sq
   212  		}
   213  		sq *= sq
   214  	}
   215  	return hash, pow
   216  }
   217  
   218  // IndexRabinKarpBytes uses the Rabin-Karp search algorithm to return the index of the
   219  // first occurence of substr in s, or -1 if not present.
   220  //
   221  // This function was removed in Go 1.22.
   222  func IndexRabinKarpBytes(s, sep []byte) int {
   223  	// Rabin-Karp search
   224  	hashsep, pow := HashStrBytes(sep)
   225  	n := len(sep)
   226  	var h uint32
   227  	for i := 0; i < n; i++ {
   228  		h = h*PrimeRK + uint32(s[i])
   229  	}
   230  	if h == hashsep && Equal(s[:n], sep) {
   231  		return 0
   232  	}
   233  	for i := n; i < len(s); {
   234  		h *= PrimeRK
   235  		h += uint32(s[i])
   236  		h -= pow * uint32(s[i-n])
   237  		i++
   238  		if h == hashsep && Equal(s[i-n:i], sep) {
   239  			return i - n
   240  		}
   241  	}
   242  	return -1
   243  }
   244  
   245  // IndexRabinKarp uses the Rabin-Karp search algorithm to return the index of the
   246  // first occurrence of sep in s, or -1 if not present.
   247  //
   248  // Copied from the Go 1.22rc1 source tree.
   249  func IndexRabinKarp[T string | []byte](s, sep T) int {
   250  	// Rabin-Karp search
   251  	hashss, pow := HashStr(sep)
   252  	n := len(sep)
   253  	var h uint32
   254  	for i := 0; i < n; i++ {
   255  		h = h*PrimeRK + uint32(s[i])
   256  	}
   257  	if h == hashss && string(s[:n]) == string(sep) {
   258  		return 0
   259  	}
   260  	for i := n; i < len(s); {
   261  		h *= PrimeRK
   262  		h += uint32(s[i])
   263  		h -= pow * uint32(s[i-n])
   264  		i++
   265  		if h == hashss && string(s[i-n:i]) == string(sep) {
   266  			return i - n
   267  		}
   268  	}
   269  	return -1
   270  }
   271  
   272  // MakeNoZero makes a slice of length and capacity n without zeroing the bytes.
   273  // It is the caller's responsibility to ensure uninitialized bytes
   274  // do not leak to the end user.
   275  func MakeNoZero(n int) []byte {
   276  	// Note: this does zero the buffer even though that's not necessary.
   277  	// For performance reasons we might want to change this (similar to the
   278  	// malloc function implemented in the runtime).
   279  	return make([]byte, n)
   280  }
   281  
   282  // Copied from the Go 1.22rc1 source tree.
   283  func LastIndexByte(s []byte, c byte) int {
   284  	for i := len(s) - 1; i >= 0; i-- {
   285  		if s[i] == c {
   286  			return i
   287  		}
   288  	}
   289  	return -1
   290  }
   291  
   292  // Copied from the Go 1.22rc1 source tree.
   293  func LastIndexByteString(s string, c byte) int {
   294  	for i := len(s) - 1; i >= 0; i-- {
   295  		if s[i] == c {
   296  			return i
   297  		}
   298  	}
   299  	return -1
   300  }
   301  
   302  // LastIndexRabinKarp uses the Rabin-Karp search algorithm to return the last index of the
   303  // occurrence of sep in s, or -1 if not present.
   304  //
   305  // Copied from the Go 1.22rc1 source tree.
   306  func LastIndexRabinKarp[T string | []byte](s, sep T) int {
   307  	// Rabin-Karp search from the end of the string
   308  	hashss, pow := HashStrRev(sep)
   309  	n := len(sep)
   310  	last := len(s) - n
   311  	var h uint32
   312  	for i := len(s) - 1; i >= last; i-- {
   313  		h = h*PrimeRK + uint32(s[i])
   314  	}
   315  	if h == hashss && string(s[last:]) == string(sep) {
   316  		return last
   317  	}
   318  	for i := last - 1; i >= 0; i-- {
   319  		h *= PrimeRK
   320  		h += uint32(s[i])
   321  		h -= pow * uint32(s[i+n])
   322  		if h == hashss && string(s[i:i+n]) == string(sep) {
   323  			return i
   324  		}
   325  	}
   326  	return -1
   327  }