indexOfSentinel
Function parameters
Parameters
- T:type
- sentinel:T
- p:[*:sentinel]const T
Type definitions in this namespace
Types
- Alignment
- Stored as a power-of-two.
Detects and asserts if the std.mem.Allocator interface is violated by the caller
Functions
- ValidationAllocator
- Detects and asserts if the std.mem.Allocator interface is violated by the caller
- copyForwards
- Copy all of source into dest at position 0.
- copyBackwards
- Copy all of source into dest at position 0.
- zeroes
- Generally, Zig users are encouraged to explicitly initialize all fields of a struct explicitly rather than using this function.
- zeroInit
- Initializes all fields of the struct with their default value, or zero values if no default value is present.
- sortContext
- TODO: currently this just calls `insertionSortContext`.
- order
- Compares two slices of numbers lexicographically.
- orderZ
- Compares two many-item pointers with NUL-termination lexicographically.
- lessThan
- Returns true if lhs < rhs, false otherwise
- eql
- Returns true if and only if the slices have the same length and all elements
- indexOfDiff
- Compares two slices and returns the index of the first inequality.
- span
- Takes a sentinel-terminated pointer and returns a slice, iterating over the
- sliceTo
- Takes a pointer to an array, a sentinel-terminated pointer, or a slice and iterates searching for
- len
- Takes a sentinel-terminated pointer and iterates over the memory to find the
- allEqual
- Returns true if all elements in a slice are equal to the scalar value provided
- trimStart
- Remove a set of values from the beginning of a slice.
- trimLeft
- Deprecated: use `trimStart` instead.
- trimEnd
- Remove a set of values from the end of a slice.
- trimRight
- Deprecated: use `trimEnd` instead.
- trim
- Remove a set of values from the beginning and end of a slice.
- indexOfScalar
- Linear search for the index of a scalar value inside a slice.
- lastIndexOfScalar
- Linear search for the last index of a scalar value inside a slice.
- indexOfNone
- Find the first item in `slice` which is not contained in `values`.
- lastIndexOfNone
- Find the last item in `slice` which is not contained in `values`.
- indexOfNonePos
- Find the first item in `slice[start_index..]` which is not contained in `values`.
- lastIndexOfLinear
- Find the index in a slice of a sub-slice, searching from the end backwards.
- indexOfPosLinear
- Consider using `indexOfPos` instead of this, which will automatically use a
- lastIndexOf
- Find the index in a slice of a sub-slice, searching from the end backwards.
- indexOfPos
- Uses Boyer-Moore-Horspool algorithm on large inputs; `indexOfPosLinear` on small inputs.
- count
- Returns the number of needles inside the haystack
- containsAtLeast
- Returns true if the haystack contains expected_count or more needles
- containsAtLeastScalar
- Returns true if the haystack contains expected_count or more needles
- readVarInt
- Reads an integer from memory with size equal to bytes.len.
- readVarPackedInt
- Loads an integer from packed memory with provided bit_count, bit_offset, and signedness.
- readInt
- Reads an integer from memory with bit count specified by T.
- readPackedInt
- Loads an integer from packed memory.
- writeInt
- Writes an integer to memory, storing it in twos-complement.
- writePackedInt
- Stores an integer to packed memory.
- writeVarPackedInt
- Stores an integer to packed memory with provided bit_offset, bit_count, and signedness.
- byteSwapAllFields
- Swap the byte order of all the members of the fields of a struct
- tokenizeAny
- Returns an iterator that iterates over the slices of `buffer` that are not
- tokenizeSequence
- Returns an iterator that iterates over the slices of `buffer` that are not
- tokenizeScalar
- Returns an iterator that iterates over the slices of `buffer` that are not
- splitSequence
- Returns an iterator that iterates over the slices of `buffer` that
- splitAny
- Returns an iterator that iterates over the slices of `buffer` that
- splitScalar
- Returns an iterator that iterates over the slices of `buffer` that
- splitBackwardsSequence
- Returns an iterator that iterates backwards over the slices of `buffer` that
- splitBackwardsAny
- Returns an iterator that iterates backwards over the slices of `buffer` that
- splitBackwardsScalar
- Returns an iterator that iterates backwards over the slices of `buffer` that
- window
- Returns an iterator with a sliding window of slices for `buffer`.
- join
- Naively combines a series of slices with a separator.
- joinZ
- Naively combines a series of slices with a separator and null terminator.
- concat
- Copies each T from slices into a new slice that exactly holds all the elements.
- concatWithSentinel
- Copies each T from slices into a new slice that exactly holds all the elements.
- concatMaybeSentinel
- Copies each T from slices into a new slice that exactly holds all the elements as well as the sentinel.
- min
- Returns the smallest number in a slice.
- max
- Returns the largest number in a slice.
- minMax
- Finds the smallest and largest number in a slice.
- indexOfMin
- Returns the index of the smallest number in a slice.
- indexOfMax
- Returns the index of the largest number in a slice.
- indexOfMinMax
- Finds the indices of the smallest and largest number in a slice.
- reverse
- In-place order reversal of a slice
- reverseIterator
- Iterates over a slice in reverse.
- rotate
- In-place rotation of the values in an array ([0 1 2 3] becomes [1 2 3 0] if we rotate by 1)
- replace
- Replace needle with replacement as many times as possible, writing to an output buffer which is assumed to be of
- replaceScalar
- Replace all occurrences of `match` with `replacement`.
- collapseRepeatsLen
- Collapse consecutive duplicate elements into one entry.
- collapseRepeats
- Collapse consecutive duplicate elements into one entry.
- replacementSize
- Calculate the size needed in an output buffer to perform a replacement.
- replaceOwned
- Perform a replacement on an allocated buffer of pre-determined size.
- littleToNative
- Converts a little-endian integer to host endianness.
- bigToNative
- Converts a big-endian integer to host endianness.
- toNative
- Converts an integer from specified endianness to host endianness.
- nativeTo
- Converts an integer which has host endianness to the desired endianness.
- nativeToLittle
- Converts an integer which has host endianness to little endian.
- nativeToBig
- Converts an integer which has host endianness to big endian.
- alignPointerOffset
- Returns the number of elements that, if added to the given pointer, align it
- alignPointer
- Aligns a given pointer value to a specified alignment factor.
- asBytes
- Given a pointer to a single item, returns a slice of the underlying bytes, preserving pointer attributes.
- toBytes
- Given any value, returns a copy of its bytes in an array.
- bytesAsValue
- Given a pointer to an array of bytes, returns a pointer to a value of the specified type
- bytesToValue
- Given a pointer to an array of bytes, returns a value of the specified type backed by a
- bytesAsSlice
- Given a slice of bytes, returns a slice of the specified type
- sliceAsBytes
- Given a slice, returns a slice of the underlying bytes, preserving pointer attributes.
- alignForwardAnyAlign
- Round an address down to the next (or current) aligned address.
- alignForward
- Round an address up to the next (or current) aligned address.
- doNotOptimizeAway
- Force an evaluation of the expression; this tries to prevent
- alignBackwardAnyAlign
- Round an address down to the previous (or current) aligned address.
- alignBackward
- Round an address down to the previous (or current) aligned address.
- isValidAlign
- Returns whether `alignment` is a valid alignment, meaning it is
- isValidAlignGeneric
- Returns whether `alignment` is a valid alignment, meaning it is
- isAligned
- Given an address and an alignment, return true if the address is a multiple of the alignment
- alignInBytes
- Returns the largest slice in the given bytes that conforms to the new alignment,
- alignInSlice
- Returns the largest sub-slice within the given slice that conforms to the new alignment,
The standard library currently thoroughly depends on byte size
Values
- byte_size_in_bits
- The standard library currently thoroughly depends on byte size
- readPackedIntNative
- = switch (native_endian) { .little => readPackedIntLittle, .big => readPackedIntBig, }
- readPackedIntForeign
- = switch (native_endian) { .little => readPackedIntBig, .big => readPackedIntLittle, }
- writePackedIntNative
- = switch (native_endian) { .little => writePackedIntLittle, .big => writePackedIntBig, }
- writePackedIntForeign
- = switch (native_endian) { .little => writePackedIntBig, .big => writePackedIntLittle, }
Source
Implementation
pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]const T) usize {
var i: usize = 0;
if (use_vectors_for_comparison and
!std.debug.inValgrind() and // https://github.com/ziglang/zig/issues/17717
!@inComptime() and
(@typeInfo(T) == .int or @typeInfo(T) == .float) and std.math.isPowerOfTwo(@bitSizeOf(T)))
{
switch (@import("builtin").cpu.arch) {
// The below branch assumes that reading past the end of the buffer is valid, as long
// as we don't read into a new page. This should be the case for most architectures
// which use paged memory, however should be confirmed before adding a new arch below.
.aarch64, .x86, .x86_64 => if (std.simd.suggestVectorLength(T)) |block_len| {
const page_size = std.heap.page_size_min;
const block_size = @sizeOf(T) * block_len;
const Block = @Vector(block_len, T);
const mask: Block = @splat(sentinel);
comptime assert(std.heap.page_size_min % @sizeOf(Block) == 0);
assert(page_size % @sizeOf(Block) == 0);
// First block may be unaligned
const start_addr = @intFromPtr(&p[i]);
const offset_in_page = start_addr & (page_size - 1);
if (offset_in_page <= page_size - @sizeOf(Block)) {
// Will not read past the end of a page, full block.
const block: Block = p[i..][0..block_len].*;
const matches = block == mask;
if (@reduce(.Or, matches)) {
return i + std.simd.firstTrue(matches).?;
}
i += @divExact(std.mem.alignForward(usize, start_addr, block_size) - start_addr, @sizeOf(T));
} else {
@branchHint(.unlikely);
// Would read over a page boundary. Per-byte at a time until aligned or found.
// 0.39% chance this branch is taken for 4K pages at 16b block length.
//
// An alternate strategy is to do read a full block (the last in the page) and
// mask the entries before the pointer.
while ((@intFromPtr(&p[i]) & (block_size - 1)) != 0) : (i += 1) {
if (p[i] == sentinel) return i;
}
}
assert(std.mem.isAligned(@intFromPtr(&p[i]), block_size));
while (true) {
const block: *const Block = @ptrCast(@alignCast(p[i..][0..block_len]));
const matches = block.* == mask;
if (@reduce(.Or, matches)) {
return i + std.simd.firstTrue(matches).?;
}
i += block_len;
}
},
else => {},
}
}
while (p[i] != sentinel) {
i += 1;
}
return i;
}