Class ByteScan
\r\n\r\n header-terminator search (SWAR-accelerated), case-insensitive comparison,
comma-separated token-list scanning (Connection: a, b, c), RFC 9110 tchar
validation, and the case-insensitive header-name hash Http1HeaderMap's
Every method here is static and allocates nothing. Every SWAR method has a plain
scalar counterpart (*Scalar) that exists for two reasons: it is what the tests use as
the correctness oracle (property-tested against the SWAR version on randomized inputs — see
ByteScanTest/ByteScanFuzzTest), and it is the documented fallback if a future
measurement ever shows the SWAR path is not worth its complexity on some path (none has been
The SWAR technique used throughout
BothindexOf(byte[], int, int, byte) and indexOfCrLfCrLf(byte[], int, int) use the classic "does this word contain
byte b" bit trick (Bit Twiddling Hacks, "Determine if a word has a byte equal to n"):
XOR the 8-byte word against b broadcast into every lane (turning matching lanes to
0x00), then test for any zero lane with
(v - 0x0101010101010101L) & ~v & 0x8080808080808080L — non-zero exactly when some lane
was 0x00 before the subtraction, i.e. some original lane equalled b. This finds
*that a* matching lane exists in one word-sized read plus a handful of ALU ops, touching every
byte only once per 8-byte stride in the common (no-match-yet) case, instead of once per byte.
Reading the word uses MethodHandles.byteArrayViewVarHandle(java.lang.Class<?>, java.nio.ByteOrder) with
ByteOrder.nativeOrder() — deliberately native rather than a fixed order (contrast
fpr-core's ByteCompare, which fixes LITTLE_ENDIAN because it compares
two independently-read words for bit-exact equality and so needs a byte order both reads
agree on; nothing here compares across two separately-decoded words, so the fastest order for
the host CPU is free to use). Byte-equality detection itself (finding that a matching lane
exists in the mask) does not depend on which order was used to assemble the word — XOR and the
haszero test are lane-wise operations, indifferent to how lanes map to memory offsets.
Position extraction does depend on it: converting "which bit of the 64-bit mask is set"
back into "which array index did that byte come from" requires knowing whether array byte 0
became the long's least-significant byte (little-endian) or most-significant byte
(big-endian) — laneIndexOf(long) branches on NATIVE_IS_LITTLE once, at class-init
time, precisely to get this right on either host.
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final longSentinel returned byparseDecimalStrict(byte[], int, int)on any malformed or out-of-range input. -
Method Summary
Modifier and TypeMethodDescriptionstatic booleanequalsIgnoreCase(dev.relism.fpr.core.ByteView view, int start, int end, String target) Case-insensitive (ASCII) equality ofview[start, end)againsttarget.static booleanequalsIgnoreCaseAscii(byte[] a, int aStart, int aLen, byte[] b, int bStart, int bLen) Case-insensitive (ASCII) equality of two byte-array ranges.static booleanequalsIgnoreCaseAscii(byte[] buf, int start, int end, String target) Case-insensitive (ASCII) equality ofbuf[start, end)againsttarget.static inthashNameIgnoreCaseAscii(byte[] buf, int start, int len) Case-insensitive (ASCII fold) 32-bit FNV-1a hash ofbuf[start, start + len).static intSame hash ashashNameIgnoreCaseAscii(byte[], int, int), computed directly from a lookup-keyString(e.g.static intindexOf(byte[] buf, int from, int to, byte target) Index of the first occurrence oftargetinbuf[from, to), or-1.static intindexOfCrLfCrLf(byte[] buf, int from, int to) Index of the first"\r\n\r\n"inbuf[from, to), or-1.static booleanisTChar(byte b) Whetherbis a valid RFC 9110 §5.6.2tchar(a legal header-name byte).static longparseDecimalStrict(byte[] buf, int start, int end) Strict, overflow-safe unsigned decimal parse ofbuf[start, end): rejects an empty range, any non-'0'..'9'byte, more than 19 digits, and arithmetic overflow pastLong.MAX_VALUE.static longparseHexStrict(byte[] buf, int start, int end, int maxDigits) Parses up tomaxDigitshex digits (ASCII, either case) frombuf[start, end)as an unsigned value.static booleantokenEqualsIgnoreCase(dev.relism.fpr.core.ByteView view, int start, int end, String token) Case-insensitive compare ofview[start, end), trimming trailing spaces, againsttoken.static booleantokenListContains(dev.relism.fpr.core.ByteView view, String token) Whether the comma-separated, OWS-tolerant token listviewcontainstoken(case-insensitive).
-
Field Details
-
PARSE_INVALID
public static final long PARSE_INVALIDSentinel returned byparseDecimalStrict(byte[], int, int)on any malformed or out-of-range input.- See Also:
-
-
Method Details
-
isTChar
public static boolean isTChar(byte b) Whetherbis a valid RFC 9110 §5.6.2tchar(a legal header-name byte). -
indexOf
public static int indexOf(byte[] buf, int from, int to, byte target) Index of the first occurrence oftargetinbuf[from, to), or-1. SWAR-accelerated: touches 8 bytes per word while no match has been found, falling back to a byte-at-a-time tail once fewer than 8 bytes remain. -
indexOfCrLfCrLf
public static int indexOfCrLfCrLf(byte[] buf, int from, int to) Index of the first"\r\n\r\n"inbuf[from, to), or-1. SWAR pre-filter (find a candidateCRbyte 8 at a time) plus a cheap scalar 3-byte verify at each candidate — see the class Javadoc for the technique and -
equalsIgnoreCaseAscii
Case-insensitive (ASCII) equality ofbuf[start, end)againsttarget. -
equalsIgnoreCaseAscii
public static boolean equalsIgnoreCaseAscii(byte[] a, int aStart, int aLen, byte[] b, int bStart, int bLen) Case-insensitive (ASCII) equality of two byte-array ranges. -
equalsIgnoreCase
public static boolean equalsIgnoreCase(dev.relism.fpr.core.ByteView view, int start, int end, String target) Case-insensitive (ASCII) equality ofview[start, end)againsttarget. -
tokenListContains
Whether the comma-separated, OWS-tolerant token listviewcontainstoken(case-insensitive). The shared scanner behind bothHttp1KeepAlive.isKeepAliveand drift apart the way a whole-valueequalscheck once did. -
tokenEqualsIgnoreCase
public static boolean tokenEqualsIgnoreCase(dev.relism.fpr.core.ByteView view, int start, int end, String token) Case-insensitive compare ofview[start, end), trimming trailing spaces, againsttoken. -
hashNameIgnoreCaseAscii
public static int hashNameIgnoreCaseAscii(byte[] buf, int start, int len) Case-insensitive (ASCII fold) 32-bit FNV-1a hash ofbuf[start, start + len). Used byHttp1HeaderMap's per-request index to compare a cheap hash before falling back to a full case-insensitivememcmp-equivalent (equalsIgnoreCaseAscii(byte[], int, int, java.lang.String)) — two header names that differ anywhere hash differently with overwhelming probability, so the common "not the header I'm looking for" case resolves in one hash compare instead of a byte-by-byte scan. -
hashNameIgnoreCaseAscii
Same hash ashashNameIgnoreCaseAscii(byte[], int, int), computed directly from a lookup-keyString(e.g."Content-Type") instead of already-scanned bytes — the two must agree bit-for-bit on equivalent ASCII content forHttp1HeaderMap's index (hash the request-declared bytes once atreset(); hash the caller's lookup key once perfirst()/all()call; compare the two cheap hashes before ever touching a full case-insensitive comparison). -
parseDecimalStrict
public static long parseDecimalStrict(byte[] buf, int start, int end) Strict, overflow-safe unsigned decimal parse ofbuf[start, end): rejects an empty range, any non-'0'..'9'byte, more than 19 digits, and arithmetic overflow pastLong.MAX_VALUE. ReturnsPARSE_INVALIDrather than throwing — the same shapeRequestParser's ownContent-Lengthparser already hand-rolls (kept separate there since it also needs to throw a specific, differently-wordedMalformedRequestExceptionper failure mode); this is the general-purpose version for callers (HPACK integer decoding, frame-length fields) that just need a valid/invalid signal. -
parseHexStrict
public static long parseHexStrict(byte[] buf, int start, int end, int maxDigits) Parses up tomaxDigitshex digits (ASCII, either case) frombuf[start, end)as an unsigned value. ReturnsPARSE_INVALIDif the range is empty, contains a non-hex-digit byte, or would need more thanmaxDigitsdigits to represent (the caller's bound against, e.g., a chunk-size line with an implausible number of digits).
-