github.com/Schaudge/grailbase@v0.0.0-20240223061707-44c758a471c0/simd/cmp_generic.go (about)

     1  // Copyright 2018 GRAIL, Inc.  All rights reserved.
     2  // Use of this source code is governed by the Apache-2.0
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build !amd64 appengine
     6  
     7  package simd
     8  
     9  // FirstUnequal8Unsafe scans arg1[startPos:] and arg2[startPos:] for the first
    10  // mismatching byte, returning its position if one is found, or the common
    11  // length if all bytes match (or startPos >= len).  This has essentially the
    12  // same speed as bytes.Compare().
    13  //
    14  // WARNING: This is a function designed to be used in inner loops, which makes
    15  // assumptions about length and capacity which aren't checked at runtime.  Use
    16  // the safe version of this function when that's a problem.
    17  // The second assumption is always satisfied when the last
    18  // potentially-size-increasing operation on arg1[] is {Re}makeUnsafe(),
    19  // ResizeUnsafe(), or XcapUnsafe(), and the same is true for arg2[].
    20  //
    21  // 1. len(arg1) == len(arg2).
    22  //
    23  // 2. Capacities are at least RoundUpPow2(len, bytesPerVec).
    24  func FirstUnequal8Unsafe(arg1, arg2 []byte, startPos int) int {
    25  	endPos := len(arg1)
    26  	for i := startPos; i < endPos; i++ {
    27  		if arg1[i] != arg2[i] {
    28  			return i
    29  		}
    30  	}
    31  	return endPos
    32  }
    33  
    34  // FirstUnequal8 scans arg1[startPos:] and arg2[startPos:] for the first
    35  // mismatching byte, returning its position if one is found, or the common
    36  // length if all bytes match (or startPos >= len).  It panics if the lengths
    37  // are not identical, or startPos is negative.
    38  //
    39  // This is essentially an extension of bytes.Compare().
    40  func FirstUnequal8(arg1, arg2 []byte, startPos int) int {
    41  	endPos := len(arg1)
    42  	if endPos != len(arg2) {
    43  		panic("FirstUnequal8() requires len(arg1) == len(arg2).")
    44  	}
    45  	if startPos < 0 {
    46  		panic("FirstUnequal8() requires nonnegative startPos.")
    47  	}
    48  	for pos := startPos; pos < endPos; pos++ {
    49  		if arg1[pos] != arg2[pos] {
    50  			return pos
    51  		}
    52  	}
    53  	return endPos
    54  }
    55  
    56  // FirstGreater8Unsafe scans arg[startPos:] for the first value larger than the
    57  // given constant, returning its position if one is found, or len(arg) if all
    58  // bytes are <= (or startPos >= len).
    59  //
    60  // This should only be used when greater values are usually present at ~5% or
    61  // lower frequency.  Above that, use a simple for loop.
    62  //
    63  // WARNING: This is a function designed to be used in inner loops, which makes
    64  // assumptions about length and capacity which aren't checked at runtime.  Use
    65  // the safe version of this function when that's a problem.
    66  // The second assumption is always satisfied when the last
    67  // potentially-size-increasing operation on arg[] is {Re}makeUnsafe(),
    68  // ResizeUnsafe(), or XcapUnsafe().
    69  //
    70  // 1. startPos is nonnegative.
    71  //
    72  // 2. cap(arg) >= RoundUpPow2(len, bytesPerVec).
    73  func FirstGreater8Unsafe(arg []byte, val byte, startPos int) int {
    74  	endPos := len(arg)
    75  	for pos := startPos; pos < endPos; pos++ {
    76  		if arg[pos] > val {
    77  			return pos
    78  		}
    79  	}
    80  	return endPos
    81  }
    82  
    83  // FirstGreater8 scans arg[startPos:] for the first value larger than the given
    84  // constant, returning its position if one is found, or len(arg) if all bytes
    85  // are <= (or startPos >= len).
    86  //
    87  // This should only be used when greater values are usually present at ~5% or
    88  // lower frequency.  Above that, use a simple for loop.
    89  func FirstGreater8(arg []byte, val byte, startPos int) int {
    90  	if startPos < 0 {
    91  		panic("FirstGreater8() requires nonnegative startPos.")
    92  	}
    93  	endPos := len(arg)
    94  	for pos := startPos; pos < endPos; pos++ {
    95  		if arg[pos] > val {
    96  			return pos
    97  		}
    98  	}
    99  	return endPos
   100  }
   101  
   102  // FirstLeq8Unsafe scans arg[startPos:] for the first value <= the given
   103  // constant, returning its position if one is found, or len(arg) if all bytes
   104  // are greater (or startPos >= len).
   105  //
   106  // This should only be used when <= values are usually present at ~5% or
   107  // lower frequency.  Above that, use a simple for loop.
   108  //
   109  // See warning for FirstGreater8Unsafe.
   110  func FirstLeq8Unsafe(arg []byte, val byte, startPos int) int {
   111  	endPos := len(arg)
   112  	for pos := startPos; pos < endPos; pos++ {
   113  		if arg[pos] <= val {
   114  			return pos
   115  		}
   116  	}
   117  	return endPos
   118  }
   119  
   120  // FirstLeq8 scans arg[startPos:] for the first value <= the given constant,
   121  // returning its position if one is found, or len(arg) if all bytes are greater
   122  // (or startPos >= len).
   123  //
   124  // This should only be used when <= values are usually present at ~5% or lower
   125  // frequency.  Above that, use a simple for loop.
   126  func FirstLeq8(arg []byte, val byte, startPos int) int {
   127  	// This currently has practically no performance penalty relative to the
   128  	// Unsafe version, since the implementation is identical except for the
   129  	// startPos check.
   130  	if startPos < 0 {
   131  		panic("FirstLeq8() requires nonnegative startPos.")
   132  	}
   133  	endPos := len(arg)
   134  	for pos := startPos; pos < endPos; pos++ {
   135  		if arg[pos] <= val {
   136  			return pos
   137  		}
   138  	}
   139  	return endPos
   140  }