authorgravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2025-09-07 03:55:57+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-09-06 18:55:57-07:00
log02396f8d5c5ca32c1d2ab2e2f04afba4588f5944
treef7c777b9ecec5547c8c179e6175629957f654f3e
parentcc6d9fdbf40cc23d2ec47d2f7db74a84fbefd1ac
signaturebadge-check Signed by PGP key B5690EEEBB952194

Document std.mem.* functions (#25168)

* Document std.mem.* functions Functions in std.mem are essential for virtually all applications, yet many of them lacked documentation. Co-authored-by: Andrew Kelley <andrew@ziglang.org>

1 files changed, 58 insertions(+), 0 deletions(-)

lib/std/mem.zig+58
...@@ -166,6 +166,8 @@ pub fn ValidationAllocator(comptime T: type) type {...@@ -166,6 +166,8 @@ pub fn ValidationAllocator(comptime T: type) type {
166 };166 };
167}167}
168168
169/// Wraps an allocator with basic validation checks.
170/// Asserts that allocation sizes are greater than zero and returned pointers have correct alignment.
169pub fn validationWrap(allocator: anytype) ValidationAllocator(@TypeOf(allocator)) {171pub fn validationWrap(allocator: anytype) ValidationAllocator(@TypeOf(allocator)) {
170 return ValidationAllocator(@TypeOf(allocator)).init(allocator);172 return ValidationAllocator(@TypeOf(allocator)).init(allocator);
171}173}
...@@ -597,6 +599,12 @@ test zeroInit {...@@ -597,6 +599,12 @@ test zeroInit {
597 }, nested_baz);599 }, nested_baz);
598}600}
599601
602/// Sorts a slice in-place using a stable algorithm (maintains relative order of equal elements).
603/// Average time complexity: O(n log n), worst case: O(n log n)
604/// Space complexity: O(log n) for recursive calls
605///
606/// For slice of primitives with default ordering, consider using `std.sort.block` directly.
607/// For unstable but potentially faster sorting, see `sortUnstable`.
600pub fn sort(608pub fn sort(
601 comptime T: type,609 comptime T: type,
602 items: []T,610 items: []T,
...@@ -606,6 +614,12 @@ pub fn sort(...@@ -606,6 +614,12 @@ pub fn sort(
606 std.sort.block(T, items, context, lessThanFn);614 std.sort.block(T, items, context, lessThanFn);
607}615}
608616
617/// Sorts a slice in-place using an unstable algorithm (does not preserve relative order of equal elements).
618/// Time complexity: O(n) best case, O(n log n) worst case and average case.
619/// Generally faster than stable sort but order of equal elements is undefined.
620///
621/// Uses pattern-defeating quicksort (PDQ) algorithm which performs well on many data patterns.
622/// For stable sorting that preserves equal element order, use `sort`.
609pub fn sortUnstable(623pub fn sortUnstable(
610 comptime T: type,624 comptime T: type,
611 items: []T,625 items: []T,
...@@ -621,6 +635,12 @@ pub fn sortContext(a: usize, b: usize, context: anytype) void {...@@ -621,6 +635,12 @@ pub fn sortContext(a: usize, b: usize, context: anytype) void {
621 std.sort.insertionContext(a, b, context);635 std.sort.insertionContext(a, b, context);
622}636}
623637
638/// Sorts a range [a, b) using an unstable algorithm with custom context.
639/// This is a lower-level interface for sorting that works with indices instead of slices.
640/// Does not preserve relative order of equal elements.
641///
642/// The context must provide lessThan(a_idx, b_idx) and swap(a_idx, b_idx) methods.
643/// Uses pattern-defeating quicksort (PDQ) algorithm.
624pub fn sortUnstableContext(a: usize, b: usize, context: anytype) void {644pub fn sortUnstableContext(a: usize, b: usize, context: anytype) void {
625 std.sort.pdqContext(a, b, context);645 std.sort.pdqContext(a, b, context);
626}646}
...@@ -1089,6 +1109,8 @@ test len {...@@ -1089,6 +1109,8 @@ test len {
1089 try testing.expect(len(c_ptr) == 2);1109 try testing.expect(len(c_ptr) == 2);
1090}1110}
10911111
1112/// Returns the index of the sentinel value in a sentinel-terminated pointer.
1113/// Linear search through memory until the sentinel is found.
1092pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]const T) usize {1114pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]const T) usize {
1093 var i: usize = 0;1115 var i: usize = 0;
10941116
...@@ -1255,6 +1277,8 @@ pub fn lastIndexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {...@@ -1255,6 +1277,8 @@ pub fn lastIndexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {
1255 return null;1277 return null;
1256}1278}
12571279
1280/// Linear search for the index of a scalar value inside a slice, starting from a given position.
1281/// Returns null if the value is not found.
1258pub fn indexOfScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize {1282pub fn indexOfScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize {
1259 if (start_index >= slice.len) return null;1283 if (start_index >= slice.len) return null;
12601284
...@@ -1331,10 +1355,14 @@ test indexOfScalarPos {...@@ -1331,10 +1355,14 @@ test indexOfScalarPos {
1331 }1355 }
1332}1356}
13331357
1358/// Linear search for the index of any value in the provided list inside a slice.
1359/// Returns null if no values are found.
1334pub fn indexOfAny(comptime T: type, slice: []const T, values: []const T) ?usize {1360pub fn indexOfAny(comptime T: type, slice: []const T, values: []const T) ?usize {
1335 return indexOfAnyPos(T, slice, 0, values);1361 return indexOfAnyPos(T, slice, 0, values);
1336}1362}
13371363
1364/// Linear search for the last index of any value in the provided list inside a slice.
1365/// Returns null if no values are found.
1338pub fn lastIndexOfAny(comptime T: type, slice: []const T, values: []const T) ?usize {1366pub fn lastIndexOfAny(comptime T: type, slice: []const T, values: []const T) ?usize {
1339 var i: usize = slice.len;1367 var i: usize = slice.len;
1340 while (i != 0) {1368 while (i != 0) {
...@@ -1346,6 +1374,8 @@ pub fn lastIndexOfAny(comptime T: type, slice: []const T, values: []const T) ?us...@@ -1346,6 +1374,8 @@ pub fn lastIndexOfAny(comptime T: type, slice: []const T, values: []const T) ?us
1346 return null;1374 return null;
1347}1375}
13481376
1377/// Linear search for the index of any value in the provided list inside a slice, starting from a given position.
1378/// Returns null if no values are found.
1349pub fn indexOfAnyPos(comptime T: type, slice: []const T, start_index: usize, values: []const T) ?usize {1379pub fn indexOfAnyPos(comptime T: type, slice: []const T, start_index: usize, values: []const T) ?usize {
1350 if (start_index >= slice.len) return null;1380 if (start_index >= slice.len) return null;
1351 for (slice[start_index..], start_index..) |c, i| {1381 for (slice[start_index..], start_index..) |c, i| {
...@@ -1404,6 +1434,9 @@ test indexOfNone {...@@ -1404,6 +1434,9 @@ test indexOfNone {
1404 try testing.expect(indexOfNonePos(u8, "abc123", 3, "321") == null);1434 try testing.expect(indexOfNonePos(u8, "abc123", 3, "321") == null);
1405}1435}
14061436
1437/// Search for needle in haystack and return the index of the first occurrence.
1438/// Uses Boyer-Moore-Horspool algorithm on large inputs; linear search on small inputs.
1439/// Returns null if needle is not found.
1407pub fn indexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize {1440pub fn indexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize {
1408 return indexOfPos(T, haystack, 0, needle);1441 return indexOfPos(T, haystack, 0, needle);
1409}1442}
...@@ -2241,6 +2274,9 @@ test byteSwapAllFields {...@@ -2241,6 +2274,9 @@ test byteSwapAllFields {
2241 }, k);2274 }, k);
2242}2275}
22432276
2277/// Reverses the byte order of all elements in a slice.
2278/// Handles structs, unions, arrays, enums, floats, and integers recursively.
2279/// Useful for converting between little-endian and big-endian representations.
2244pub fn byteSwapAllElements(comptime Elem: type, slice: []Elem) void {2280pub fn byteSwapAllElements(comptime Elem: type, slice: []Elem) void {
2245 for (slice) |*elem| {2281 for (slice) |*elem| {
2246 switch (@typeInfo(@TypeOf(elem.*))) {2282 switch (@typeInfo(@TypeOf(elem.*))) {
...@@ -2980,6 +3016,7 @@ test window {...@@ -2980,6 +3016,7 @@ test window {
2980 }3016 }
2981}3017}
29823018
3019/// Iterator type returned by the `window` function for sliding window operations.
2983pub fn WindowIterator(comptime T: type) type {3020pub fn WindowIterator(comptime T: type) type {
2984 return struct {3021 return struct {
2985 buffer: []const T,3022 buffer: []const T,
...@@ -3020,6 +3057,8 @@ pub fn WindowIterator(comptime T: type) type {...@@ -3020,6 +3057,8 @@ pub fn WindowIterator(comptime T: type) type {
3020 };3057 };
3021}3058}
30223059
3060/// Returns true if haystack starts with needle.
3061/// Time complexity: O(needle.len)
3023pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool {3062pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
3024 return if (needle.len > haystack.len) false else eql(T, haystack[0..needle.len], needle);3063 return if (needle.len > haystack.len) false else eql(T, haystack[0..needle.len], needle);
3025}3064}
...@@ -3029,6 +3068,8 @@ test startsWith {...@@ -3029,6 +3068,8 @@ test startsWith {
3029 try testing.expect(!startsWith(u8, "Needle in haystack", "haystack"));3068 try testing.expect(!startsWith(u8, "Needle in haystack", "haystack"));
3030}3069}
30313070
3071/// Returns true if haystack ends with needle.
3072/// Time complexity: O(needle.len)
3032pub fn endsWith(comptime T: type, haystack: []const T, needle: []const T) bool {3073pub fn endsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
3033 return if (needle.len > haystack.len) false else eql(T, haystack[haystack.len - needle.len ..], needle);3074 return if (needle.len > haystack.len) false else eql(T, haystack[haystack.len - needle.len ..], needle);
3034}3075}
...@@ -3038,8 +3079,10 @@ test endsWith {...@@ -3038,8 +3079,10 @@ test endsWith {
3038 try testing.expect(!endsWith(u8, "Bob", "Bo"));3079 try testing.expect(!endsWith(u8, "Bob", "Bo"));
3039}3080}
30403081
3082/// Delimiter type for tokenization and splitting operations.
3041pub const DelimiterType = enum { sequence, any, scalar };3083pub const DelimiterType = enum { sequence, any, scalar };
30423084
3085/// Iterator type for tokenization operations, skipping empty sequences and delimiter sequences.
3043pub fn TokenIterator(comptime T: type, comptime delimiter_type: DelimiterType) type {3086pub fn TokenIterator(comptime T: type, comptime delimiter_type: DelimiterType) type {
3044 return struct {3087 return struct {
3045 buffer: []const T,3088 buffer: []const T,
...@@ -3113,6 +3156,7 @@ pub fn TokenIterator(comptime T: type, comptime delimiter_type: DelimiterType) t...@@ -3113,6 +3156,7 @@ pub fn TokenIterator(comptime T: type, comptime delimiter_type: DelimiterType) t
3113 };3156 };
3114}3157}
31153158
3159/// Iterator type for splitting operations, including empty sequences between delimiters.
3116pub fn SplitIterator(comptime T: type, comptime delimiter_type: DelimiterType) type {3160pub fn SplitIterator(comptime T: type, comptime delimiter_type: DelimiterType) type {
3117 return struct {3161 return struct {
3118 buffer: []const T,3162 buffer: []const T,
...@@ -3178,6 +3222,7 @@ pub fn SplitIterator(comptime T: type, comptime delimiter_type: DelimiterType) t...@@ -3178,6 +3222,7 @@ pub fn SplitIterator(comptime T: type, comptime delimiter_type: DelimiterType) t
3178 };3222 };
3179}3223}
31803224
3225/// Iterator type for splitting operations from the end backwards, including empty sequences.
3181pub fn SplitBackwardsIterator(comptime T: type, comptime delimiter_type: DelimiterType) type {3226pub fn SplitBackwardsIterator(comptime T: type, comptime delimiter_type: DelimiterType) type {
3182 return struct {3227 return struct {
3183 buffer: []const T,3228 buffer: []const T,
...@@ -3587,6 +3632,7 @@ test indexOfMinMax {...@@ -3587,6 +3632,7 @@ test indexOfMinMax {
3587 try testing.expectEqual(.{ 0, 0 }, indexOfMinMax(u8, "a"));3632 try testing.expectEqual(.{ 0, 0 }, indexOfMinMax(u8, "a"));
3588}3633}
35893634
3635/// Exchanges contents of two memory locations.
3590pub fn swap(comptime T: type, a: *T, b: *T) void {3636pub fn swap(comptime T: type, a: *T, b: *T) void {
3591 const tmp = a.*;3637 const tmp = a.*;
3592 a.* = b.*;3638 a.* = b.*;
...@@ -4452,6 +4498,9 @@ pub fn alignForward(comptime T: type, addr: T, alignment: T) T {...@@ -4452,6 +4498,9 @@ pub fn alignForward(comptime T: type, addr: T, alignment: T) T {
4452 return alignBackward(T, addr + (alignment - 1), alignment);4498 return alignBackward(T, addr + (alignment - 1), alignment);
4453}4499}
44544500
4501/// Rounds an address up to the next alignment boundary using log2 representation.
4502/// Equivalent to alignForward with alignment = 1 << log2_alignment.
4503/// More efficient when alignment is known to be a power of 2.
4455pub fn alignForwardLog2(addr: usize, log2_alignment: u8) usize {4504pub fn alignForwardLog2(addr: usize, log2_alignment: u8) usize {
4456 const alignment = @as(usize, 1) << @as(math.Log2Int(usize), @intCast(log2_alignment));4505 const alignment = @as(usize, 1) << @as(math.Log2Int(usize), @intCast(log2_alignment));
4457 return alignForward(usize, addr, alignment);4506 return alignForward(usize, addr, alignment);
...@@ -4591,6 +4640,9 @@ pub fn isValidAlignGeneric(comptime T: type, alignment: T) bool {...@@ -4591,6 +4640,9 @@ pub fn isValidAlignGeneric(comptime T: type, alignment: T) bool {
4591 return alignment > 0 and std.math.isPowerOfTwo(alignment);4640 return alignment > 0 and std.math.isPowerOfTwo(alignment);
4592}4641}
45934642
4643/// Returns true if i is aligned to the given alignment.
4644/// Works with any positive alignment value, not just powers of 2.
4645/// For power-of-2 alignments, `isAligned` is more efficient.
4594pub fn isAlignedAnyAlign(i: usize, alignment: usize) bool {4646pub fn isAlignedAnyAlign(i: usize, alignment: usize) bool {
4595 if (isValidAlign(alignment))4647 if (isValidAlign(alignment))
4596 return isAligned(i, alignment);4648 return isAligned(i, alignment);
...@@ -4598,6 +4650,9 @@ pub fn isAlignedAnyAlign(i: usize, alignment: usize) bool {...@@ -4598,6 +4650,9 @@ pub fn isAlignedAnyAlign(i: usize, alignment: usize) bool {
4598 return 0 == @mod(i, alignment);4650 return 0 == @mod(i, alignment);
4599}4651}
46004652
4653/// Returns true if addr is aligned to 2^log2_alignment.
4654/// More efficient than `isAligned` when alignment is known to be a power of 2.
4655/// log2_alignment must be < @bitSizeOf(usize).
4601pub fn isAlignedLog2(addr: usize, log2_alignment: u8) bool {4656pub fn isAlignedLog2(addr: usize, log2_alignment: u8) bool {
4602 return @ctz(addr) >= log2_alignment;4657 return @ctz(addr) >= log2_alignment;
4603}4658}
...@@ -4608,6 +4663,9 @@ pub fn isAligned(addr: usize, alignment: usize) bool {...@@ -4608,6 +4663,9 @@ pub fn isAligned(addr: usize, alignment: usize) bool {
4608 return isAlignedGeneric(u64, addr, alignment);4663 return isAlignedGeneric(u64, addr, alignment);
4609}4664}
46104665
4666/// Generic version of `isAligned` that works with any integer type.
4667/// Returns true if addr is aligned to the given alignment.
4668/// Alignment must be a power of 2 and greater than 0.
4611pub fn isAlignedGeneric(comptime T: type, addr: T, alignment: T) bool {4669pub fn isAlignedGeneric(comptime T: type, addr: T, alignment: T) bool {
4612 return alignBackward(T, addr, alignment) == addr;4670 return alignBackward(T, addr, alignment) == addr;
4613}4671}