swar

package
v0.26.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 24, 2026 License: MIT Imports: 3 Imported by: 0

Documentation

Overview

Package swar finds the first byte of a slice that belongs to a set, a word at a time: SIMD within a register (SWAR), on the standard library alone. It is a kernel primitive — stdlib-only and domain-neutral: a slice, two bytes, a bound, and no header, no escape and no token in a signature.

Three searches, each returning the index of the FIRST match or -1:

swar.IndexByte2(b, '\r', '\n')   // either of two bytes
swar.IndexLess(b, 0x20)           // a byte below a bound: a control byte
swar.NewSet('"', '\\', 0x20, true).Index(b)
                                  // a quote, a backslash, a control byte,
                                  // or a byte from 0x80 up

There is no search for one byte: bytes.IndexByte is an assembly loop over thirty-two bytes at a time, and on the machine it was measured on (an Apple M1, BENCH.md) it beat the word loop at every length but eight bytes. Use it for one byte; IndexByte2 with the byte passed twice also finds one.

How a word is searched

The slice is read eight bytes at a time as a little-endian word, and a lane test turns the word into one flag per byte. The tests are EXACT: a flag is set for a byte that matches and for no other, because the sum behind each test cannot carry out of its lane. The classic borrowing form (v - 0x01..) &^ v & 0x80.. is not used: it flags a byte above a true match too, so only its lowest bit can be trusted, and a caller that walks the others reads false hits. Here every flag is a real match, and the lowest is the first.

A comparison against a bound is exact for a bound of 128 or less. A larger one has no exact lane test, so IndexLess and a Set with such a bound read byte by byte: correct, and no faster than a loop.

What is read

Nothing past the length. Every load is a bounds-checked slice of eight bytes within len(b), the last bytes are read one at a time, and the capacity beyond len(b) is never touched — whatever it holds, a "\r\n" left by an earlier request included. There is no unsafe in the package.

The vector form

Built with GOEXPERIMENT=simd on amd64, the package also carries an AVX2 form of each search that reads thirty-two bytes at a time, used for a slice of thirty-two bytes or more on a CPU that reports AVX2 when the program starts. The SWAR form is in the same binary and takes every other call: a slice of under thirty-two bytes, any slice on a CPU without AVX2, and IndexLess with a bound of zero. Without AVX2 (and in a build without the experiment, which has only the SWAR form) IndexByte2 hands a slice of 64 bytes or more to two scans of bytes.IndexByte instead. Both forms answer alike, and the suite holds them to the same oracle. The experiment's package, simd/archsimd, is not covered by the Go 1 promise: the vector form may stop compiling on a new Go version, and a consumer that cannot afford that builds without the experiment.

Those scans read faster than the word loop from 64 bytes on.

Cost

Nothing here allocates. BENCH.md has the figures against the byte loop and bytes.IndexByte, and says for which lengths each form wins.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func IndexByte2

func IndexByte2(b []byte, c1, c2 byte) int

IndexByte2 returns the index of the first byte of b equal to c1 or to c2, or -1 when there is none: the search for a line end, '\r' or '\n'. A slice of 64 bytes or more goes to two scans of bytes.IndexByte where the build has no AVX2 form.

Example

ExampleIndexByte2 finds the first bare or paired line end, and searches for a single byte by passing it twice.

package main

import (
	"fmt"

	"github.com/kitsunium/sdk/internal/kernel/swar"
)

func main() {
	fmt.Println(swar.IndexByte2([]byte("Host: x\r\nAccept: */*"), '\r', '\n'))
	fmt.Println(swar.IndexByte2([]byte("Host: x\nAccept: */*"), '\r', '\n'))
	fmt.Println(swar.IndexByte2([]byte("GET /users/7 HTTP/1.1\r\n"), '\n', '\n'))
}
Output:
7
7
22

func IndexLess

func IndexLess(b []byte, n byte) int

IndexLess returns the index of the first byte of b below n, or -1 when there is none. A bound of zero holds no byte. The search is a word at a time for a bound of 128 or less, and byte by byte above it.

Example

ExampleIndexLess finds the first control byte of a header value.

package main

import (
	"fmt"

	"github.com/kitsunium/sdk/internal/kernel/swar"
)

func main() {
	fmt.Println(swar.IndexLess([]byte("text/plain; charset=utf-8"), 0x20))
	fmt.Println(swar.IndexLess([]byte("text/plain;\tcharset"), 0x20))
}
Output:
-1
11

Types

type Set

type Set struct {
	// contains filtered or unexported fields
}

Set is a set of byte values: the two bytes it was built with, the bytes below its bound, and optionally the bytes from 0x80 up. NewSet computes what a search reads once, and Set.Index only reads it, so a Set is safe for any number of goroutines. The zero Set holds the byte 0x00 alone.

func NewSet

func NewSet(first, second, below byte, upper bool) Set

NewSet returns the set of the bytes first and second, the bytes below below, and — when upper is true — the bytes from 0x80 up. Pass the same byte twice for a set of one, and a below of zero for none below.

A below above 128 is accepted; Set.Index then reads byte by byte.

func (Set) Index

func (s Set) Index(b []byte) int

Index returns the index of the first byte of b that is in the set, or -1 when there is none. It reads nothing past len(b).

Example

ExampleSet_Index finds the first byte a quoted string must escape: a quote, a backslash, a control byte, or a byte that starts a multi-byte character.

package main

import (
	"fmt"

	"github.com/kitsunium/sdk/internal/kernel/swar"
)

func main() {
	escape := swar.NewSet('"', '\\', 0x20, true)
	fmt.Println(escape.Index([]byte("plain ascii text")))
	fmt.Println(escape.Index([]byte(`say "hi"`)))
	fmt.Println(escape.Index([]byte("tab\there")))
	fmt.Println(escape.Index([]byte("café")))
}
Output:
-1
4
3
3

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL