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 }