zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

blob bbdcfef3 (196218B) - Raw


      1 const std = @import("std.zig");
      2 const builtin = @import("builtin");
      3 const debug = std.debug;
      4 const assert = debug.assert;
      5 const math = std.math;
      6 const mem = @This();
      7 const testing = std.testing;
      8 const Endian = std.builtin.Endian;
      9 const native_endian = builtin.cpu.arch.endian();
     10 
     11 /// The standard library currently thoroughly depends on byte size
     12 /// being 8 bits.  (see the use of u8 throughout allocation code as
     13 /// the "byte" type.)  Code which depends on this can reference this
     14 /// declaration.  If we ever try to port the standard library to a
     15 /// non-8-bit-byte platform, this will allow us to search for things
     16 /// which need to be updated.
     17 pub const byte_size_in_bits = 8;
     18 
     19 pub const Allocator = @import("mem/Allocator.zig");
     20 
     21 /// Stored as a power-of-two.
     22 pub const Alignment = enum(math.Log2Int(usize)) {
     23     @"1" = 0,
     24     @"2" = 1,
     25     @"4" = 2,
     26     @"8" = 3,
     27     @"16" = 4,
     28     @"32" = 5,
     29     @"64" = 6,
     30     _,
     31 
     32     pub fn toByteUnits(a: Alignment) usize {
     33         return @as(usize, 1) << @intFromEnum(a);
     34     }
     35 
     36     pub fn fromByteUnits(n: usize) Alignment {
     37         assert(std.math.isPowerOfTwo(n));
     38         return @enumFromInt(@ctz(n));
     39     }
     40 
     41     pub fn fromByteUnitsOptional(maybe_n: ?usize) ?Alignment {
     42         return if (maybe_n) |n| .fromByteUnits(n) else null;
     43     }
     44 
     45     pub inline fn of(comptime T: type) Alignment {
     46         return comptime fromByteUnits(@alignOf(T));
     47     }
     48 
     49     pub fn order(lhs: Alignment, rhs: Alignment) std.math.Order {
     50         return std.math.order(@intFromEnum(lhs), @intFromEnum(rhs));
     51     }
     52 
     53     pub fn compare(lhs: Alignment, op: std.math.CompareOperator, rhs: Alignment) bool {
     54         return std.math.compare(@intFromEnum(lhs), op, @intFromEnum(rhs));
     55     }
     56 
     57     pub fn max(lhs: Alignment, rhs: Alignment) Alignment {
     58         return @enumFromInt(@max(@intFromEnum(lhs), @intFromEnum(rhs)));
     59     }
     60 
     61     pub fn min(lhs: Alignment, rhs: Alignment) Alignment {
     62         return @enumFromInt(@min(@intFromEnum(lhs), @intFromEnum(rhs)));
     63     }
     64 
     65     /// Return next address with this alignment.
     66     pub fn forward(a: Alignment, address: usize) usize {
     67         const x = (@as(usize, 1) << @intFromEnum(a)) - 1;
     68         return (address + x) & ~x;
     69     }
     70 
     71     /// Return previous address with this alignment.
     72     pub fn backward(a: Alignment, address: usize) usize {
     73         const x = (@as(usize, 1) << @intFromEnum(a)) - 1;
     74         return address & ~x;
     75     }
     76 
     77     /// Return whether address is aligned to this amount.
     78     pub fn check(a: Alignment, address: usize) bool {
     79         return @ctz(address) >= @intFromEnum(a);
     80     }
     81 };
     82 
     83 /// Detects and asserts if the std.mem.Allocator interface is violated by the caller
     84 /// or the allocator.
     85 pub fn ValidationAllocator(comptime T: type) type {
     86     return struct {
     87         const Self = @This();
     88 
     89         underlying_allocator: T,
     90 
     91         pub fn init(underlying_allocator: T) @This() {
     92             return .{
     93                 .underlying_allocator = underlying_allocator,
     94             };
     95         }
     96 
     97         pub fn allocator(self: *Self) Allocator {
     98             return .{
     99                 .ptr = self,
    100                 .vtable = &.{
    101                     .alloc = alloc,
    102                     .resize = resize,
    103                     .remap = remap,
    104                     .free = free,
    105                 },
    106             };
    107         }
    108 
    109         fn getUnderlyingAllocatorPtr(self: *Self) Allocator {
    110             if (T == Allocator) return self.underlying_allocator;
    111             return self.underlying_allocator.allocator();
    112         }
    113 
    114         pub fn alloc(
    115             ctx: *anyopaque,
    116             n: usize,
    117             alignment: mem.Alignment,
    118             ret_addr: usize,
    119         ) ?[*]u8 {
    120             assert(n > 0);
    121             const self: *Self = @ptrCast(@alignCast(ctx));
    122             const underlying = self.getUnderlyingAllocatorPtr();
    123             const result = underlying.rawAlloc(n, alignment, ret_addr) orelse
    124                 return null;
    125             assert(alignment.check(@intFromPtr(result)));
    126             return result;
    127         }
    128 
    129         pub fn resize(
    130             ctx: *anyopaque,
    131             buf: []u8,
    132             alignment: Alignment,
    133             new_len: usize,
    134             ret_addr: usize,
    135         ) bool {
    136             const self: *Self = @ptrCast(@alignCast(ctx));
    137             assert(buf.len > 0);
    138             const underlying = self.getUnderlyingAllocatorPtr();
    139             return underlying.rawResize(buf, alignment, new_len, ret_addr);
    140         }
    141 
    142         pub fn remap(
    143             ctx: *anyopaque,
    144             buf: []u8,
    145             alignment: Alignment,
    146             new_len: usize,
    147             ret_addr: usize,
    148         ) ?[*]u8 {
    149             const self: *Self = @ptrCast(@alignCast(ctx));
    150             assert(buf.len > 0);
    151             const underlying = self.getUnderlyingAllocatorPtr();
    152             return underlying.rawRemap(buf, alignment, new_len, ret_addr);
    153         }
    154 
    155         pub fn free(
    156             ctx: *anyopaque,
    157             buf: []u8,
    158             alignment: Alignment,
    159             ret_addr: usize,
    160         ) void {
    161             const self: *Self = @ptrCast(@alignCast(ctx));
    162             assert(buf.len > 0);
    163             const underlying = self.getUnderlyingAllocatorPtr();
    164             underlying.rawFree(buf, alignment, ret_addr);
    165         }
    166 
    167         pub fn reset(self: *Self) void {
    168             self.underlying_allocator.reset();
    169         }
    170     };
    171 }
    172 
    173 /// Wraps an allocator with basic validation checks.
    174 /// Asserts that allocation sizes are greater than zero and returned pointers have correct alignment.
    175 pub fn validationWrap(allocator: anytype) ValidationAllocator(@TypeOf(allocator)) {
    176     return ValidationAllocator(@TypeOf(allocator)).init(allocator);
    177 }
    178 
    179 test "Allocator basics" {
    180     try testing.expectError(error.OutOfMemory, testing.failing_allocator.alloc(u8, 1));
    181     try testing.expectError(error.OutOfMemory, testing.failing_allocator.allocSentinel(u8, 1, 0));
    182 }
    183 
    184 test "Allocator.resize" {
    185     const primitiveIntTypes = .{
    186         i8,
    187         u8,
    188         i16,
    189         u16,
    190         i32,
    191         u32,
    192         i64,
    193         u64,
    194         i128,
    195         u128,
    196         isize,
    197         usize,
    198     };
    199     inline for (primitiveIntTypes) |T| {
    200         var values = try testing.allocator.alloc(T, 100);
    201         defer testing.allocator.free(values);
    202 
    203         for (values, 0..) |*v, i| v.* = @as(T, @intCast(i));
    204         if (!testing.allocator.resize(values, values.len + 10)) return error.OutOfMemory;
    205         values = values.ptr[0 .. values.len + 10];
    206         try testing.expect(values.len == 110);
    207     }
    208 
    209     const primitiveFloatTypes = .{
    210         f16,
    211         f32,
    212         f64,
    213         f128,
    214     };
    215     inline for (primitiveFloatTypes) |T| {
    216         var values = try testing.allocator.alloc(T, 100);
    217         defer testing.allocator.free(values);
    218 
    219         for (values, 0..) |*v, i| v.* = @as(T, @floatFromInt(i));
    220         if (!testing.allocator.resize(values, values.len + 10)) return error.OutOfMemory;
    221         values = values.ptr[0 .. values.len + 10];
    222         try testing.expect(values.len == 110);
    223     }
    224 }
    225 
    226 test "Allocator alloc and remap with zero-bit type" {
    227     var values = try testing.allocator.alloc(void, 10);
    228     defer testing.allocator.free(values);
    229 
    230     try testing.expectEqual(10, values.len);
    231     const remaped = testing.allocator.remap(values, 200);
    232     try testing.expect(remaped != null);
    233 
    234     values = remaped.?;
    235     try testing.expectEqual(200, values.len);
    236 }
    237 
    238 /// Copy all of source into dest at position 0.
    239 /// dest.len must be >= source.len.
    240 /// If the slices overlap, dest.ptr must be <= src.ptr.
    241 /// This function is deprecated; use @memmove instead.
    242 pub fn copyForwards(comptime T: type, dest: []T, source: []const T) void {
    243     for (dest[0..source.len], source) |*d, s| d.* = s;
    244 }
    245 
    246 /// Copy all of source into dest at position 0.
    247 /// dest.len must be >= source.len.
    248 /// If the slices overlap, dest.ptr must be >= src.ptr.
    249 /// This function is deprecated; use @memmove instead.
    250 pub fn copyBackwards(comptime T: type, dest: []T, source: []const T) void {
    251     // TODO instead of manually doing this check for the whole array
    252     // and turning off runtime safety, the compiler should detect loops like
    253     // this and automatically omit safety checks for loops
    254     @setRuntimeSafety(false);
    255     assert(dest.len >= source.len);
    256     var i = source.len;
    257     while (i > 0) {
    258         i -= 1;
    259         dest[i] = source[i];
    260     }
    261 }
    262 
    263 /// Generally, Zig users are encouraged to explicitly initialize all fields of a struct explicitly rather than using this function.
    264 /// However, it is recognized that there are sometimes use cases for initializing all fields to a "zero" value. For example, when
    265 /// interfacing with a C API where this practice is more common and relied upon. If you are performing code review and see this
    266 /// function used, examine closely - it may be a code smell.
    267 /// Zero initializes the type.
    268 /// This can be used to zero-initialize any type for which it makes sense. Structs will be initialized recursively.
    269 pub fn zeroes(comptime T: type) T {
    270     switch (@typeInfo(T)) {
    271         .comptime_int, .int, .comptime_float, .float => {
    272             return @as(T, 0);
    273         },
    274         .@"enum" => {
    275             return @as(T, @enumFromInt(0));
    276         },
    277         .void => {
    278             return {};
    279         },
    280         .bool => {
    281             return false;
    282         },
    283         .optional, .null => {
    284             return null;
    285         },
    286         .@"struct" => |struct_info| {
    287             if (@sizeOf(T) == 0) return undefined;
    288             if (struct_info.layout == .@"extern") {
    289                 var item: T = undefined;
    290                 @memset(asBytes(&item), 0);
    291                 return item;
    292             } else {
    293                 var structure: T = undefined;
    294                 inline for (struct_info.fields) |field| {
    295                     if (!field.is_comptime) {
    296                         @field(structure, field.name) = zeroes(field.type);
    297                     }
    298                 }
    299                 return structure;
    300             }
    301         },
    302         .pointer => |ptr_info| {
    303             switch (ptr_info.size) {
    304                 .slice => {
    305                     if (ptr_info.sentinel()) |sentinel| {
    306                         if (ptr_info.child == u8 and sentinel == 0) {
    307                             return ""; // A special case for the most common use-case: null-terminated strings.
    308                         }
    309                         @compileError("Can't set a sentinel slice to zero. This would require allocating memory.");
    310                     } else {
    311                         return &[_]ptr_info.child{};
    312                     }
    313                 },
    314                 .c => {
    315                     return null;
    316                 },
    317                 .one, .many => {
    318                     if (ptr_info.is_allowzero) return @ptrFromInt(0);
    319                     @compileError("Only nullable and allowzero pointers can be set to zero.");
    320                 },
    321             }
    322         },
    323         .array => |info| {
    324             return @splat(zeroes(info.child));
    325         },
    326         .vector => |info| {
    327             return @splat(zeroes(info.child));
    328         },
    329         .@"union" => |info| {
    330             if (info.layout == .@"extern") {
    331                 var item: T = undefined;
    332                 @memset(asBytes(&item), 0);
    333                 return item;
    334             }
    335             @compileError("Can't set a " ++ @typeName(T) ++ " to zero.");
    336         },
    337         .enum_literal,
    338         .error_union,
    339         .error_set,
    340         .@"fn",
    341         .type,
    342         .noreturn,
    343         .undefined,
    344         .@"opaque",
    345         .frame,
    346         .@"anyframe",
    347         => {
    348             @compileError("Can't set a " ++ @typeName(T) ++ " to zero.");
    349         },
    350     }
    351 }
    352 
    353 test zeroes {
    354     const C_struct = extern struct {
    355         x: u32,
    356         y: u32 align(128),
    357     };
    358 
    359     var a = zeroes(C_struct);
    360 
    361     // Extern structs should have padding zeroed out.
    362     try testing.expectEqualSlices(u8, &[_]u8{0} ** @sizeOf(@TypeOf(a)), asBytes(&a));
    363 
    364     a.y += 10;
    365 
    366     try testing.expect(a.x == 0);
    367     try testing.expect(a.y == 10);
    368 
    369     const ZigStruct = struct {
    370         comptime comptime_field: u8 = 5,
    371 
    372         integral_types: struct {
    373             integer_0: i0,
    374             integer_8: i8,
    375             integer_16: i16,
    376             integer_32: i32,
    377             integer_64: i64,
    378             integer_128: i128,
    379             unsigned_0: u0,
    380             unsigned_8: u8,
    381             unsigned_16: u16,
    382             unsigned_32: u32,
    383             unsigned_64: u64,
    384             unsigned_128: u128,
    385 
    386             float_32: f32,
    387             float_64: f64,
    388         },
    389 
    390         pointers: struct {
    391             optional: ?*u8,
    392             c_pointer: [*c]u8,
    393             slice: []u8,
    394             nullTerminatedString: [:0]const u8,
    395         },
    396 
    397         array: [2]u32,
    398         vector_u32: @Vector(2, u32),
    399         vector_f32: @Vector(2, f32),
    400         vector_bool: @Vector(2, bool),
    401         optional_int: ?u8,
    402         empty: void,
    403         sentinel: [3:0]u8,
    404     };
    405 
    406     const b = zeroes(ZigStruct);
    407     try testing.expectEqual(@as(u8, 5), b.comptime_field);
    408     try testing.expectEqual(@as(i8, 0), b.integral_types.integer_0);
    409     try testing.expectEqual(@as(i8, 0), b.integral_types.integer_8);
    410     try testing.expectEqual(@as(i16, 0), b.integral_types.integer_16);
    411     try testing.expectEqual(@as(i32, 0), b.integral_types.integer_32);
    412     try testing.expectEqual(@as(i64, 0), b.integral_types.integer_64);
    413     try testing.expectEqual(@as(i128, 0), b.integral_types.integer_128);
    414     try testing.expectEqual(@as(u8, 0), b.integral_types.unsigned_0);
    415     try testing.expectEqual(@as(u8, 0), b.integral_types.unsigned_8);
    416     try testing.expectEqual(@as(u16, 0), b.integral_types.unsigned_16);
    417     try testing.expectEqual(@as(u32, 0), b.integral_types.unsigned_32);
    418     try testing.expectEqual(@as(u64, 0), b.integral_types.unsigned_64);
    419     try testing.expectEqual(@as(u128, 0), b.integral_types.unsigned_128);
    420     try testing.expectEqual(@as(f32, 0), b.integral_types.float_32);
    421     try testing.expectEqual(@as(f64, 0), b.integral_types.float_64);
    422     try testing.expectEqual(@as(?*u8, null), b.pointers.optional);
    423     try testing.expectEqual(@as([*c]u8, null), b.pointers.c_pointer);
    424     try testing.expectEqual(@as([]u8, &[_]u8{}), b.pointers.slice);
    425     try testing.expectEqual(@as([:0]const u8, ""), b.pointers.nullTerminatedString);
    426     for (b.array) |e| {
    427         try testing.expectEqual(@as(u32, 0), e);
    428     }
    429     try testing.expectEqual(@as(@TypeOf(b.vector_u32), @splat(0)), b.vector_u32);
    430     try testing.expectEqual(@as(@TypeOf(b.vector_f32), @splat(0.0)), b.vector_f32);
    431     if (!(builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon)) {
    432         try testing.expectEqual(@as(@TypeOf(b.vector_bool), @splat(false)), b.vector_bool);
    433     }
    434     try testing.expectEqual(@as(?u8, null), b.optional_int);
    435     for (b.sentinel) |e| {
    436         try testing.expectEqual(@as(u8, 0), e);
    437     }
    438 
    439     const C_union = extern union {
    440         a: u8,
    441         b: u32,
    442     };
    443 
    444     const c = zeroes(C_union);
    445     try testing.expectEqual(@as(u8, 0), c.a);
    446     try testing.expectEqual(@as(u32, 0), c.b);
    447 
    448     const comptime_union = comptime zeroes(C_union);
    449     try testing.expectEqual(@as(u8, 0), comptime_union.a);
    450     try testing.expectEqual(@as(u32, 0), comptime_union.b);
    451 
    452     // Ensure zero sized struct with fields is initialized correctly.
    453     _ = zeroes(struct { handle: void });
    454 }
    455 
    456 /// Initializes all fields of the struct with their default value, or zero values if no default value is present.
    457 /// If the field is present in the provided initial values, it will have that value instead.
    458 /// Structs are initialized recursively.
    459 pub fn zeroInit(comptime T: type, init: anytype) T {
    460     const Init = @TypeOf(init);
    461 
    462     switch (@typeInfo(T)) {
    463         .@"struct" => |struct_info| {
    464             switch (@typeInfo(Init)) {
    465                 .@"struct" => |init_info| {
    466                     if (init_info.is_tuple) {
    467                         if (init_info.fields.len > struct_info.fields.len) {
    468                             @compileError("Tuple initializer has more elements than there are fields in `" ++ @typeName(T) ++ "`");
    469                         }
    470                     } else {
    471                         inline for (init_info.fields) |field| {
    472                             if (!@hasField(T, field.name)) {
    473                                 @compileError("Encountered an initializer for `" ++ field.name ++ "`, but it is not a field of " ++ @typeName(T));
    474                             }
    475                         }
    476                     }
    477 
    478                     var value: T = if (struct_info.layout == .@"extern") zeroes(T) else undefined;
    479 
    480                     inline for (struct_info.fields, 0..) |field, i| {
    481                         if (field.is_comptime) {
    482                             continue;
    483                         }
    484 
    485                         if (init_info.is_tuple and init_info.fields.len > i) {
    486                             @field(value, field.name) = @field(init, init_info.fields[i].name);
    487                         } else if (@hasField(@TypeOf(init), field.name)) {
    488                             switch (@typeInfo(field.type)) {
    489                                 .@"struct" => {
    490                                     @field(value, field.name) = zeroInit(field.type, @field(init, field.name));
    491                                 },
    492                                 else => {
    493                                     @field(value, field.name) = @field(init, field.name);
    494                                 },
    495                             }
    496                         } else if (field.defaultValue()) |val| {
    497                             @field(value, field.name) = val;
    498                         } else {
    499                             switch (@typeInfo(field.type)) {
    500                                 .@"struct" => {
    501                                     @field(value, field.name) = std.mem.zeroInit(field.type, .{});
    502                                 },
    503                                 else => {
    504                                     @field(value, field.name) = std.mem.zeroes(@TypeOf(@field(value, field.name)));
    505                                 },
    506                             }
    507                         }
    508                     }
    509 
    510                     return value;
    511                 },
    512                 else => {
    513                     @compileError("The initializer must be a struct");
    514                 },
    515             }
    516         },
    517         else => {
    518             @compileError("Can't default init a " ++ @typeName(T));
    519         },
    520     }
    521 }
    522 
    523 test zeroInit {
    524     const I = struct {
    525         d: f64,
    526     };
    527 
    528     const S = struct {
    529         a: u32,
    530         b: ?bool,
    531         c: I,
    532         e: [3]u8,
    533         f: i64 = -1,
    534     };
    535 
    536     const s = zeroInit(S, .{
    537         .a = 42,
    538     });
    539 
    540     try testing.expectEqual(S{
    541         .a = 42,
    542         .b = null,
    543         .c = .{
    544             .d = 0,
    545         },
    546         .e = [3]u8{ 0, 0, 0 },
    547         .f = -1,
    548     }, s);
    549 
    550     const Color = struct {
    551         r: u8,
    552         g: u8,
    553         b: u8,
    554         a: u8,
    555     };
    556 
    557     const c = zeroInit(Color, .{ 255, 255 });
    558     try testing.expectEqual(Color{
    559         .r = 255,
    560         .g = 255,
    561         .b = 0,
    562         .a = 0,
    563     }, c);
    564 
    565     const Foo = struct {
    566         foo: u8 = 69,
    567         bar: u8,
    568     };
    569 
    570     const f = zeroInit(Foo, .{});
    571     try testing.expectEqual(Foo{
    572         .foo = 69,
    573         .bar = 0,
    574     }, f);
    575 
    576     const Bar = struct {
    577         foo: u32 = 666,
    578         bar: u32 = 420,
    579     };
    580 
    581     const b = zeroInit(Bar, .{69});
    582     try testing.expectEqual(Bar{
    583         .foo = 69,
    584         .bar = 420,
    585     }, b);
    586 
    587     const Baz = struct {
    588         foo: [:0]const u8 = "bar",
    589     };
    590 
    591     const baz1 = zeroInit(Baz, .{});
    592     try testing.expectEqual(Baz{}, baz1);
    593 
    594     const baz2 = zeroInit(Baz, .{ .foo = "zab" });
    595     try testing.expectEqualSlices(u8, "zab", baz2.foo);
    596 
    597     const NestedBaz = struct {
    598         bbb: Baz,
    599     };
    600     const nested_baz = zeroInit(NestedBaz, .{});
    601     try testing.expectEqual(NestedBaz{
    602         .bbb = Baz{},
    603     }, nested_baz);
    604 }
    605 
    606 /// Sorts a slice in-place using a stable algorithm (maintains relative order of equal elements).
    607 /// Average time complexity: O(n log n), worst case: O(n log n)
    608 /// Space complexity: O(log n) for recursive calls
    609 ///
    610 /// For slice of primitives with default ordering, consider using `std.sort.block` directly.
    611 /// For unstable but potentially faster sorting, see `sortUnstable`.
    612 pub fn sort(
    613     comptime T: type,
    614     items: []T,
    615     context: anytype,
    616     comptime lessThanFn: fn (@TypeOf(context), lhs: T, rhs: T) bool,
    617 ) void {
    618     std.sort.block(T, items, context, lessThanFn);
    619 }
    620 
    621 /// Sorts a slice in-place using an unstable algorithm (does not preserve relative order of equal elements).
    622 /// Time complexity: O(n) best case, O(n log n) worst case and average case.
    623 /// Generally faster than stable sort but order of equal elements is undefined.
    624 ///
    625 /// Uses pattern-defeating quicksort (PDQ) algorithm which performs well on many data patterns.
    626 /// For stable sorting that preserves equal element order, use `sort`.
    627 pub fn sortUnstable(
    628     comptime T: type,
    629     items: []T,
    630     context: anytype,
    631     comptime lessThanFn: fn (@TypeOf(context), lhs: T, rhs: T) bool,
    632 ) void {
    633     std.sort.pdq(T, items, context, lessThanFn);
    634 }
    635 
    636 /// TODO: currently this just calls `insertionSortContext`. The block sort implementation
    637 /// in this file needs to be adapted to use the sort context.
    638 pub fn sortContext(a: usize, b: usize, context: anytype) void {
    639     std.sort.insertionContext(a, b, context);
    640 }
    641 
    642 /// Sorts a range [a, b) using an unstable algorithm with custom context.
    643 /// This is a lower-level interface for sorting that works with indices instead of slices.
    644 /// Does not preserve relative order of equal elements.
    645 ///
    646 /// The context must provide lessThan(a_idx, b_idx) and swap(a_idx, b_idx) methods.
    647 /// Uses pattern-defeating quicksort (PDQ) algorithm.
    648 pub fn sortUnstableContext(a: usize, b: usize, context: anytype) void {
    649     std.sort.pdqContext(a, b, context);
    650 }
    651 
    652 /// Compares two slices of numbers lexicographically. O(n).
    653 pub fn order(comptime T: type, lhs: []const T, rhs: []const T) math.Order {
    654     if (lhs.ptr != rhs.ptr) {
    655         const n = @min(lhs.len, rhs.len);
    656         for (lhs[0..n], rhs[0..n]) |lhs_elem, rhs_elem| {
    657             switch (math.order(lhs_elem, rhs_elem)) {
    658                 .eq => continue,
    659                 .lt => return .lt,
    660                 .gt => return .gt,
    661             }
    662         }
    663     }
    664     return math.order(lhs.len, rhs.len);
    665 }
    666 
    667 /// Compares two many-item pointers with NUL-termination lexicographically.
    668 pub fn orderZ(comptime T: type, lhs: [*:0]const T, rhs: [*:0]const T) math.Order {
    669     return boundedOrderZ(T, lhs, rhs, std.math.maxInt(usize));
    670 }
    671 
    672 /// Compares two many-item pointers with NUL-termination lexicographically until some specified bound.
    673 pub fn boundedOrderZ(comptime T: type, lhs: [*:0]const T, rhs: [*:0]const T, bound: usize) math.Order {
    674     if (lhs == rhs) return .eq;
    675     var i: usize = 0;
    676     while (lhs[i] == rhs[i] and lhs[i] != 0 and i < bound) : (i += 1) {}
    677     return if (i < bound) math.order(lhs[i], rhs[i]) else .eq;
    678 }
    679 
    680 test order {
    681     try testing.expect(order(u8, "abcd", "bee") == .lt);
    682     try testing.expect(order(u8, "abc", "abc") == .eq);
    683     try testing.expect(order(u8, "abc", "abc0") == .lt);
    684     try testing.expect(order(u8, "", "") == .eq);
    685     try testing.expect(order(u8, "", "a") == .lt);
    686 
    687     const s: []const u8 = "abc";
    688     try testing.expect(order(u8, s, s) == .eq);
    689     try testing.expect(order(u8, s[0..2], s) == .lt);
    690 }
    691 
    692 test orderZ {
    693     try testing.expect(orderZ(u8, "abcd", "bee") == .lt);
    694     try testing.expect(orderZ(u8, "abc", "abc") == .eq);
    695     try testing.expect(orderZ(u8, "abc", "abc0") == .lt);
    696     try testing.expect(orderZ(u8, "", "") == .eq);
    697     try testing.expect(orderZ(u8, "", "a") == .lt);
    698 
    699     const s: [*:0]const u8 = "abc";
    700     try testing.expect(orderZ(u8, s, s) == .eq);
    701 }
    702 
    703 /// Returns true if lhs < rhs, false otherwise
    704 pub fn lessThan(comptime T: type, lhs: []const T, rhs: []const T) bool {
    705     return order(T, lhs, rhs) == .lt;
    706 }
    707 
    708 test lessThan {
    709     try testing.expect(lessThan(u8, "abcd", "bee"));
    710     try testing.expect(!lessThan(u8, "abc", "abc"));
    711     try testing.expect(lessThan(u8, "abc", "abc0"));
    712     try testing.expect(!lessThan(u8, "", ""));
    713     try testing.expect(lessThan(u8, "", "a"));
    714 }
    715 
    716 const use_vectors = switch (builtin.zig_backend) {
    717     // These backends don't support vectors yet.
    718     .stage2_aarch64,
    719     .stage2_powerpc,
    720     .stage2_riscv64,
    721     => false,
    722     // The SPIR-V backend does not support the optimized path yet.
    723     .stage2_spirv => false,
    724     else => true,
    725 };
    726 
    727 // The naive memory comparison implementation is more useful for fuzzers to find interesting inputs.
    728 const use_vectors_for_comparison = use_vectors and !builtin.fuzz;
    729 
    730 /// Returns true if and only if the slices have the same length and all elements
    731 /// compare true using equality operator.
    732 pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
    733     if (!@inComptime() and @sizeOf(T) != 0 and std.meta.hasUniqueRepresentation(T) and
    734         use_vectors_for_comparison)
    735     {
    736         return eqlBytes(sliceAsBytes(a), sliceAsBytes(b));
    737     }
    738 
    739     if (a.len != b.len) return false;
    740     if (a.len == 0 or a.ptr == b.ptr) return true;
    741 
    742     for (a, b) |a_elem, b_elem| {
    743         if (a_elem != b_elem) return false;
    744     }
    745     return true;
    746 }
    747 
    748 test eql {
    749     try testing.expect(eql(u8, "abcd", "abcd"));
    750     try testing.expect(!eql(u8, "abcdef", "abZdef"));
    751     try testing.expect(!eql(u8, "abcdefg", "abcdef"));
    752 
    753     comptime {
    754         try testing.expect(eql(type, &.{ bool, f32 }, &.{ bool, f32 }));
    755         try testing.expect(!eql(type, &.{ bool, f32 }, &.{ f32, bool }));
    756         try testing.expect(!eql(type, &.{ bool, f32 }, &.{bool}));
    757 
    758         try testing.expect(eql(comptime_int, &.{ 1, 2, 3 }, &.{ 1, 2, 3 }));
    759         try testing.expect(!eql(comptime_int, &.{ 1, 2, 3 }, &.{ 3, 2, 1 }));
    760         try testing.expect(!eql(comptime_int, &.{1}, &.{ 1, 2 }));
    761     }
    762 
    763     try testing.expect(eql(void, &.{ {}, {} }, &.{ {}, {} }));
    764     try testing.expect(!eql(void, &.{{}}, &.{ {}, {} }));
    765 }
    766 
    767 /// std.mem.eql heavily optimized for slices of bytes.
    768 fn eqlBytes(a: []const u8, b: []const u8) bool {
    769     comptime assert(use_vectors_for_comparison);
    770 
    771     if (a.len != b.len) return false;
    772     if (a.len == 0 or a.ptr == b.ptr) return true;
    773 
    774     if (a.len <= 16) {
    775         if (a.len < 4) {
    776             const x = (a[0] ^ b[0]) | (a[a.len - 1] ^ b[a.len - 1]) | (a[a.len / 2] ^ b[a.len / 2]);
    777             return x == 0;
    778         }
    779         var x: u32 = 0;
    780         for ([_]usize{ 0, a.len - 4, (a.len / 8) * 4, a.len - 4 - ((a.len / 8) * 4) }) |n| {
    781             x |= @as(u32, @bitCast(a[n..][0..4].*)) ^ @as(u32, @bitCast(b[n..][0..4].*));
    782         }
    783         return x == 0;
    784     }
    785 
    786     // Figure out the fastest way to scan through the input in chunks.
    787     // Uses vectors when supported and falls back to usize/words when not.
    788     const Scan = if (std.simd.suggestVectorLength(u8)) |vec_size|
    789         struct {
    790             pub const size = vec_size;
    791             pub const Chunk = @Vector(size, u8);
    792             pub inline fn isNotEqual(chunk_a: Chunk, chunk_b: Chunk) bool {
    793                 return @reduce(.Or, chunk_a != chunk_b);
    794             }
    795         }
    796     else
    797         struct {
    798             pub const size = @sizeOf(usize);
    799             pub const Chunk = usize;
    800             pub inline fn isNotEqual(chunk_a: Chunk, chunk_b: Chunk) bool {
    801                 return chunk_a != chunk_b;
    802             }
    803         };
    804 
    805     inline for (1..6) |s| {
    806         const n = 16 << s;
    807         if (n <= Scan.size and a.len <= n) {
    808             const V = @Vector(n / 2, u8);
    809             var x = @as(V, a[0 .. n / 2].*) ^ @as(V, b[0 .. n / 2].*);
    810             x |= @as(V, a[a.len - n / 2 ..][0 .. n / 2].*) ^ @as(V, b[a.len - n / 2 ..][0 .. n / 2].*);
    811             const zero: V = @splat(0);
    812             return !@reduce(.Or, x != zero);
    813         }
    814     }
    815     // Compare inputs in chunks at a time (excluding the last chunk).
    816     for (0..(a.len - 1) / Scan.size) |i| {
    817         const a_chunk: Scan.Chunk = @bitCast(a[i * Scan.size ..][0..Scan.size].*);
    818         const b_chunk: Scan.Chunk = @bitCast(b[i * Scan.size ..][0..Scan.size].*);
    819         if (Scan.isNotEqual(a_chunk, b_chunk)) return false;
    820     }
    821 
    822     // Compare the last chunk using an overlapping read (similar to the previous size strategies).
    823     const last_a_chunk: Scan.Chunk = @bitCast(a[a.len - Scan.size ..][0..Scan.size].*);
    824     const last_b_chunk: Scan.Chunk = @bitCast(b[a.len - Scan.size ..][0..Scan.size].*);
    825     return !Scan.isNotEqual(last_a_chunk, last_b_chunk);
    826 }
    827 
    828 /// Deprecated in favor of `findDiff`.
    829 pub const indexOfDiff = findDiff;
    830 
    831 /// Compares two slices and returns the index of the first inequality.
    832 /// Returns null if the slices are equal.
    833 pub fn findDiff(comptime T: type, a: []const T, b: []const T) ?usize {
    834     const shortest = @min(a.len, b.len);
    835     if (a.ptr == b.ptr)
    836         return if (a.len == b.len) null else shortest;
    837     var index: usize = 0;
    838     while (index < shortest) : (index += 1) if (a[index] != b[index]) return index;
    839     return if (a.len == b.len) null else shortest;
    840 }
    841 
    842 test findDiff {
    843     try testing.expectEqual(findDiff(u8, "one", "one"), null);
    844     try testing.expectEqual(findDiff(u8, "one two", "one"), 3);
    845     try testing.expectEqual(findDiff(u8, "one", "one two"), 3);
    846     try testing.expectEqual(findDiff(u8, "one twx", "one two"), 6);
    847     try testing.expectEqual(findDiff(u8, "xne", "one"), 0);
    848 }
    849 
    850 /// Takes a sentinel-terminated pointer and returns a slice preserving pointer attributes.
    851 /// `[*c]` pointers are assumed to be 0-terminated and assumed to not be allowzero.
    852 fn Span(comptime T: type) type {
    853     switch (@typeInfo(T)) {
    854         .optional => |optional_info| {
    855             return ?Span(optional_info.child);
    856         },
    857         .pointer => |ptr_info| {
    858             const new_sentinel: ?ptr_info.child = switch (ptr_info.size) {
    859                 .one, .slice => @compileError("invalid type given to std.mem.span: " ++ @typeName(T)),
    860                 .many => ptr_info.sentinel() orelse @compileError("invalid type given to std.mem.span: " ++ @typeName(T)),
    861                 .c => 0,
    862             };
    863             return @Pointer(.slice, .{
    864                 .@"const" = ptr_info.is_const,
    865                 .@"volatile" = ptr_info.is_volatile,
    866                 .@"allowzero" = ptr_info.is_allowzero and ptr_info.size != .c,
    867                 .@"align" = ptr_info.alignment,
    868                 .@"addrspace" = ptr_info.address_space,
    869             }, ptr_info.child, new_sentinel);
    870         },
    871         else => {},
    872     }
    873     @compileError("invalid type given to std.mem.span: " ++ @typeName(T));
    874 }
    875 
    876 test Span {
    877     try testing.expect(Span([*:1]u16) == [:1]u16);
    878     try testing.expect(Span(?[*:1]u16) == ?[:1]u16);
    879     try testing.expect(Span([*:1]const u8) == [:1]const u8);
    880     try testing.expect(Span(?[*:1]const u8) == ?[:1]const u8);
    881     try testing.expect(Span([*c]u16) == [:0]u16);
    882     try testing.expect(Span(?[*c]u16) == ?[:0]u16);
    883     try testing.expect(Span([*c]const u8) == [:0]const u8);
    884     try testing.expect(Span(?[*c]const u8) == ?[:0]const u8);
    885 }
    886 
    887 /// Takes a sentinel-terminated pointer and returns a slice, iterating over the
    888 /// memory to find the sentinel and determine the length.
    889 /// Pointer attributes such as const are preserved.
    890 /// `[*c]` pointers are assumed to be non-null and 0-terminated.
    891 pub fn span(ptr: anytype) Span(@TypeOf(ptr)) {
    892     if (@typeInfo(@TypeOf(ptr)) == .optional) {
    893         if (ptr) |non_null| {
    894             return span(non_null);
    895         } else {
    896             return null;
    897         }
    898     }
    899     const Result = Span(@TypeOf(ptr));
    900     const l = len(ptr);
    901     const ptr_info = @typeInfo(Result).pointer;
    902     if (ptr_info.sentinel()) |s| {
    903         return ptr[0..l :s];
    904     } else {
    905         return ptr[0..l];
    906     }
    907 }
    908 
    909 test span {
    910     var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
    911     const ptr = @as([*:3]u16, array[0..2 :3]);
    912     try testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 }));
    913     try testing.expectEqual(@as(?[:0]u16, null), span(@as(?[*:0]u16, null)));
    914 }
    915 
    916 /// Helper for the return type of sliceTo()
    917 fn SliceTo(comptime T: type, comptime end: std.meta.Elem(T)) type {
    918     switch (@typeInfo(T)) {
    919         .optional => |optional_info| {
    920             return ?SliceTo(optional_info.child, end);
    921         },
    922         .pointer => |ptr_info| {
    923             const Elem = std.meta.Elem(T);
    924             const have_sentinel: bool = switch (ptr_info.size) {
    925                 .one, .slice => if (std.meta.sentinel(T)) |s| s == end else false,
    926                 .many => if (std.meta.sentinel(T)) |s| s == end else true,
    927                 .c => true,
    928             };
    929             return @Pointer(.slice, .{
    930                 .@"const" = ptr_info.is_const,
    931                 .@"volatile" = ptr_info.is_volatile,
    932                 .@"allowzero" = ptr_info.is_allowzero and ptr_info.size != .c,
    933                 .@"align" = ptr_info.alignment,
    934                 .@"addrspace" = ptr_info.address_space,
    935             }, Elem, if (have_sentinel) end else null);
    936         },
    937         else => {},
    938     }
    939     @compileError("invalid type given to std.mem.sliceTo: " ++ @typeName(T));
    940 }
    941 
    942 /// Takes a pointer to an array, a many-item pointer, or a slice, and returns a
    943 /// slice of the items up to the first occurrence of `end`.
    944 /// If `end` is not found, the resulting slice will include all items up to the
    945 /// input's length or sentinel.
    946 /// If the pointer type is unbounded (no length or sentinel), `end` will be the
    947 /// sentinel for the resulting slice.
    948 /// If the pointer type is sentinel-terminated by `end`, the resulting slice
    949 /// will also be sentinel-terminated by `end`.
    950 /// Pointer properties such as mutability and alignment are preserved.
    951 /// C pointers are assumed to be non-null.
    952 pub fn sliceTo(ptr: anytype, comptime end: std.meta.Elem(@TypeOf(ptr))) SliceTo(@TypeOf(ptr), end) {
    953     if (@typeInfo(@TypeOf(ptr)) == .optional) {
    954         const non_null = ptr orelse return null;
    955         return sliceTo(non_null, end);
    956     }
    957     const Result = SliceTo(@TypeOf(ptr), end);
    958     const length = lenSliceTo(ptr, end);
    959     const ptr_info = @typeInfo(Result).pointer;
    960     if (ptr_info.sentinel()) |s| {
    961         return ptr[0..length :s];
    962     } else {
    963         return ptr[0..length];
    964     }
    965 }
    966 
    967 test sliceTo {
    968     try testing.expectEqualSlices(u8, "aoeu", sliceTo("aoeu", 0));
    969 
    970     {
    971         var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
    972         try testing.expectEqualSlices(u16, &array, sliceTo(&array, 0));
    973         try testing.expectEqualSlices(u16, array[0..3], sliceTo(array[0..3], 0));
    974         try testing.expectEqualSlices(u16, array[0..2], sliceTo(&array, 3));
    975         try testing.expectEqualSlices(u16, array[0..2], sliceTo(array[0..3], 3));
    976 
    977         const many_ptr: [*]u16 = &array;
    978         try testing.expectEqualSlices(u16, array[0..2], sliceTo(many_ptr, 3));
    979         try testing.expectEqual([:3]u16, @TypeOf(sliceTo(many_ptr, 3)));
    980 
    981         const sentinel_ptr = @as([*:5]u16, @ptrCast(&array));
    982         try testing.expectEqualSlices(u16, array[0..2], sliceTo(sentinel_ptr, 3));
    983         try testing.expectEqual([]u16, @TypeOf(sliceTo(sentinel_ptr, 3)));
    984         try testing.expectEqualSlices(u16, array[0..4], sliceTo(sentinel_ptr, 5));
    985         try testing.expectEqual([:5]u16, @TypeOf(sliceTo(sentinel_ptr, 5)));
    986         try testing.expectEqualSlices(u16, array[0..4], sliceTo(sentinel_ptr, 99));
    987 
    988         const optional_sentinel_ptr = @as(?[*:5]u16, @ptrCast(&array));
    989         try testing.expectEqualSlices(u16, array[0..2], sliceTo(optional_sentinel_ptr, 3).?);
    990         try testing.expectEqualSlices(u16, array[0..4], sliceTo(optional_sentinel_ptr, 99).?);
    991 
    992         const c_ptr = @as([*c]u16, &array);
    993         try testing.expectEqualSlices(u16, array[0..2], sliceTo(c_ptr, 3));
    994         try testing.expectEqual([:3]u16, @TypeOf(sliceTo(c_ptr, 3)));
    995 
    996         const slice: []u16 = &array;
    997         try testing.expectEqualSlices(u16, array[0..2], sliceTo(slice, 3));
    998         try testing.expectEqualSlices(u16, &array, sliceTo(slice, 99));
    999 
   1000         const sentinel_slice: [:5]u16 = array[0..4 :5];
   1001         try testing.expectEqualSlices(u16, array[0..2], sliceTo(sentinel_slice, 3));
   1002         try testing.expectEqualSlices(u16, array[0..4], sliceTo(sentinel_slice, 99));
   1003     }
   1004     {
   1005         var sentinel_array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 };
   1006         try testing.expectEqualSlices(u16, sentinel_array[0..2], sliceTo(&sentinel_array, 3));
   1007         try testing.expectEqualSlices(u16, &sentinel_array, sliceTo(&sentinel_array, 0));
   1008         try testing.expectEqualSlices(u16, &sentinel_array, sliceTo(&sentinel_array, 99));
   1009     }
   1010 
   1011     try testing.expectEqual(@as(?[]u8, null), sliceTo(@as(?[]u8, null), 0));
   1012 }
   1013 
   1014 /// Private helper for sliceTo(). If you want the length, use sliceTo(foo, x).len
   1015 fn lenSliceTo(ptr: anytype, comptime end: std.meta.Elem(@TypeOf(ptr))) usize {
   1016     switch (@typeInfo(@TypeOf(ptr))) {
   1017         .pointer => |ptr_info| switch (ptr_info.size) {
   1018             .one => switch (@typeInfo(ptr_info.child)) {
   1019                 .array => |array_info| {
   1020                     if (array_info.sentinel()) |s| {
   1021                         if (s == end) {
   1022                             return findSentinel(array_info.child, end, ptr);
   1023                         }
   1024                     }
   1025                     return findScalar(array_info.child, ptr, end) orelse array_info.len;
   1026                 },
   1027                 else => {},
   1028             },
   1029             .many => if (ptr_info.sentinel()) |s| {
   1030                 if (s == end) {
   1031                     return findSentinel(ptr_info.child, end, ptr);
   1032                 }
   1033                 // We're looking for something other than the sentinel,
   1034                 // but iterating past the sentinel would be a bug so we need
   1035                 // to check for both.
   1036                 var i: usize = 0;
   1037                 while (ptr[i] != end and ptr[i] != s) i += 1;
   1038                 return i;
   1039             } else {
   1040                 return findSentinel(ptr_info.child, end, @ptrCast(ptr));
   1041             },
   1042             .c => {
   1043                 assert(ptr != null);
   1044                 return findSentinel(ptr_info.child, end, ptr);
   1045             },
   1046             .slice => {
   1047                 if (ptr_info.sentinel()) |s| {
   1048                     if (s == end) {
   1049                         return findSentinel(ptr_info.child, s, ptr);
   1050                     }
   1051                 }
   1052                 return findScalar(ptr_info.child, ptr, end) orelse ptr.len;
   1053             },
   1054         },
   1055         else => {},
   1056     }
   1057     @compileError("invalid type given to std.mem.sliceTo: " ++ @typeName(@TypeOf(ptr)));
   1058 }
   1059 
   1060 test lenSliceTo {
   1061     try testing.expect(lenSliceTo("aoeu", 0) == 4);
   1062 
   1063     {
   1064         var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
   1065         try testing.expectEqual(@as(usize, 5), lenSliceTo(&array, 0));
   1066         try testing.expectEqual(@as(usize, 3), lenSliceTo(array[0..3], 0));
   1067         try testing.expectEqual(@as(usize, 2), lenSliceTo(&array, 3));
   1068         try testing.expectEqual(@as(usize, 2), lenSliceTo(array[0..3], 3));
   1069 
   1070         const sentinel_ptr = @as([*:5]u16, @ptrCast(&array));
   1071         try testing.expectEqual(@as(usize, 2), lenSliceTo(sentinel_ptr, 3));
   1072         try testing.expectEqual(@as(usize, 4), lenSliceTo(sentinel_ptr, 99));
   1073 
   1074         const c_ptr = @as([*c]u16, &array);
   1075         try testing.expectEqual(@as(usize, 2), lenSliceTo(c_ptr, 3));
   1076 
   1077         const slice: []u16 = &array;
   1078         try testing.expectEqual(@as(usize, 2), lenSliceTo(slice, 3));
   1079         try testing.expectEqual(@as(usize, 5), lenSliceTo(slice, 99));
   1080 
   1081         const sentinel_slice: [:5]u16 = array[0..4 :5];
   1082         try testing.expectEqual(@as(usize, 2), lenSliceTo(sentinel_slice, 3));
   1083         try testing.expectEqual(@as(usize, 4), lenSliceTo(sentinel_slice, 99));
   1084     }
   1085     {
   1086         var sentinel_array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 };
   1087         try testing.expectEqual(@as(usize, 2), lenSliceTo(&sentinel_array, 3));
   1088         try testing.expectEqual(@as(usize, 5), lenSliceTo(&sentinel_array, 0));
   1089         try testing.expectEqual(@as(usize, 5), lenSliceTo(&sentinel_array, 99));
   1090     }
   1091 }
   1092 
   1093 /// Takes a sentinel-terminated pointer and iterates over the memory to find the
   1094 /// sentinel and determine the length.
   1095 /// `[*c]` pointers are assumed to be non-null and 0-terminated.
   1096 pub fn len(value: anytype) usize {
   1097     switch (@typeInfo(@TypeOf(value))) {
   1098         .pointer => |info| switch (info.size) {
   1099             .many => {
   1100                 const sentinel = info.sentinel() orelse
   1101                     @compileError("invalid type given to std.mem.len: " ++ @typeName(@TypeOf(value)));
   1102                 return findSentinel(info.child, sentinel, value);
   1103             },
   1104             .c => {
   1105                 assert(value != null);
   1106                 return findSentinel(info.child, 0, value);
   1107             },
   1108             else => @compileError("invalid type given to std.mem.len: " ++ @typeName(@TypeOf(value))),
   1109         },
   1110         else => @compileError("invalid type given to std.mem.len: " ++ @typeName(@TypeOf(value))),
   1111     }
   1112 }
   1113 
   1114 test len {
   1115     var array: [5]u16 = [_]u16{ 1, 2, 0, 4, 5 };
   1116     const ptr = @as([*:4]u16, array[0..3 :4]);
   1117     try testing.expect(len(ptr) == 3);
   1118     const c_ptr = @as([*c]u16, ptr);
   1119     try testing.expect(len(c_ptr) == 2);
   1120 }
   1121 
   1122 /// Deprecated in favor of `findSentinel`.
   1123 pub const indexOfSentinel = findSentinel;
   1124 
   1125 /// Returns the index of the sentinel value in a sentinel-terminated pointer.
   1126 /// Linear search through memory until the sentinel is found.
   1127 pub fn findSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]const T) usize {
   1128     var i: usize = 0;
   1129     while (p[i] != sentinel) {
   1130         i += 1;
   1131     }
   1132     return i;
   1133 }
   1134 
   1135 test "findSentinel vector paths" {
   1136     const Types = [_]type{ u8, u16, u32, u64 };
   1137     const allocator = std.testing.allocator;
   1138     const page_size = std.heap.page_size_min;
   1139 
   1140     inline for (Types) |T| {
   1141         const block_len = std.simd.suggestVectorLength(T) orelse continue;
   1142 
   1143         // Allocate three pages so we guarantee a page-crossing address with a full page after
   1144         const memory = try allocator.alloc(T, 3 * page_size / @sizeOf(T));
   1145         defer allocator.free(memory);
   1146         @memset(memory, 0xaa);
   1147 
   1148         // Find starting page-alignment = 0
   1149         var start: usize = 0;
   1150         const start_addr = @intFromPtr(&memory);
   1151         start += (std.mem.alignForward(usize, start_addr, page_size) - start_addr) / @sizeOf(T);
   1152         try testing.expect(start < page_size / @sizeOf(T));
   1153 
   1154         // Validate all sub-block alignments
   1155         const search_len = page_size / @sizeOf(T);
   1156         memory[start + search_len] = 0;
   1157         for (0..block_len) |offset| {
   1158             try testing.expectEqual(search_len - offset, findSentinel(T, 0, @ptrCast(&memory[start + offset])));
   1159         }
   1160         memory[start + search_len] = 0xaa;
   1161 
   1162         // Validate page boundary crossing
   1163         const start_page_boundary = start + (page_size / @sizeOf(T));
   1164         memory[start_page_boundary + block_len] = 0;
   1165         for (0..block_len) |offset| {
   1166             try testing.expectEqual(2 * block_len - offset, findSentinel(T, 0, @ptrCast(&memory[start_page_boundary - block_len + offset])));
   1167         }
   1168     }
   1169 }
   1170 
   1171 /// Returns true if all elements in a slice are equal to the scalar value provided
   1172 pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool {
   1173     for (slice) |item| {
   1174         if (item != scalar) return false;
   1175     }
   1176     return true;
   1177 }
   1178 
   1179 /// Remove a set of values from the beginning of a slice.
   1180 pub fn trimStart(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
   1181     var begin: usize = 0;
   1182     while (begin < slice.len and findScalar(T, values_to_strip, slice[begin]) != null) : (begin += 1) {}
   1183     return slice[begin..];
   1184 }
   1185 
   1186 test trimStart {
   1187     try testing.expectEqualSlices(u8, "foo\n ", trimStart(u8, " foo\n ", " \n"));
   1188 }
   1189 
   1190 /// Remove a set of values from the end of a slice.
   1191 pub fn trimEnd(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
   1192     var end: usize = slice.len;
   1193     while (end > 0 and findScalar(T, values_to_strip, slice[end - 1]) != null) : (end -= 1) {}
   1194     return slice[0..end];
   1195 }
   1196 
   1197 test trimEnd {
   1198     try testing.expectEqualSlices(u8, " foo", trimEnd(u8, " foo\n ", " \n"));
   1199 }
   1200 
   1201 /// Remove a set of values from the beginning and end of a slice.
   1202 pub fn trim(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
   1203     var begin: usize = 0;
   1204     var end: usize = slice.len;
   1205     while (begin < end and findScalar(T, values_to_strip, slice[begin]) != null) : (begin += 1) {}
   1206     while (end > begin and findScalar(T, values_to_strip, slice[end - 1]) != null) : (end -= 1) {}
   1207     return slice[begin..end];
   1208 }
   1209 
   1210 test trim {
   1211     try testing.expectEqualSlices(u8, "foo", trim(u8, " foo\n ", " \n"));
   1212     try testing.expectEqualSlices(u8, "foo", trim(u8, "foo", " \n"));
   1213 }
   1214 
   1215 /// Deprecated in favor of `findScalar`.
   1216 pub const indexOfScalar = findScalar;
   1217 
   1218 /// Linear search for the index of a scalar value inside a slice.
   1219 pub fn findScalar(comptime T: type, slice: []const T, value: T) ?usize {
   1220     return findScalarPos(T, slice, 0, value);
   1221 }
   1222 
   1223 /// Deprecated in favor of `findScalarLast`.
   1224 pub const lastIndexOfScalar = findScalarLast;
   1225 
   1226 /// Linear search for the last index of a scalar value inside a slice.
   1227 pub fn findScalarLast(comptime T: type, slice: []const T, value: T) ?usize {
   1228     var i: usize = slice.len;
   1229     while (i != 0) {
   1230         i -= 1;
   1231         if (slice[i] == value) return i;
   1232     }
   1233     return null;
   1234 }
   1235 
   1236 /// Deprecated in favor of `findScalarPos`.
   1237 pub const indexOfScalarPos = findScalarPos;
   1238 
   1239 /// Linear search for the index of a scalar value inside a slice, starting from a given position.
   1240 /// Returns null if the value is not found.
   1241 pub fn findScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize {
   1242     if (start_index >= slice.len) return null;
   1243 
   1244     var i: usize = start_index;
   1245     if (use_vectors_for_comparison and
   1246         !std.debug.inValgrind() and // https://github.com/ziglang/zig/issues/17717
   1247         !@inComptime() and
   1248         (@typeInfo(T) == .int or @typeInfo(T) == .float) and std.math.isPowerOfTwo(@bitSizeOf(T)))
   1249     {
   1250         if (std.simd.suggestVectorLength(T)) |block_len| {
   1251             // For Intel Nehalem (2009) and AMD Bulldozer (2012) or later, unaligned loads on aligned data result
   1252             // in the same execution as aligned loads. We ignore older arch's here and don't bother pre-aligning.
   1253             //
   1254             // Use `std.simd.suggestVectorLength(T)` to get the same alignment as used in this function
   1255             // however this usually isn't necessary unless your arch has a performance penalty due to this.
   1256             //
   1257             // This may differ for other arch's. Arm for example costs a cycle when loading across a cache
   1258             // line so explicit alignment prologues may be worth exploration.
   1259 
   1260             // Unrolling here is ~10% improvement. We can then do one bounds check every 2 blocks
   1261             // instead of one which adds up.
   1262             const Block = @Vector(block_len, T);
   1263             if (i + 2 * block_len < slice.len) {
   1264                 const mask: Block = @splat(value);
   1265                 while (true) {
   1266                     inline for (0..2) |_| {
   1267                         const block: Block = slice[i..][0..block_len].*;
   1268                         const matches = block == mask;
   1269                         if (@reduce(.Or, matches)) {
   1270                             return i + std.simd.firstTrue(matches).?;
   1271                         }
   1272                         i += block_len;
   1273                     }
   1274                     if (i + 2 * block_len >= slice.len) break;
   1275                 }
   1276             }
   1277 
   1278             // {block_len, block_len / 2} check
   1279             inline for (0..2) |j| {
   1280                 const block_x_len = block_len / (1 << j);
   1281                 comptime if (block_x_len < 4) break;
   1282 
   1283                 const BlockX = @Vector(block_x_len, T);
   1284                 if (i + block_x_len < slice.len) {
   1285                     const mask: BlockX = @splat(value);
   1286                     const block: BlockX = slice[i..][0..block_x_len].*;
   1287                     const matches = block == mask;
   1288                     if (@reduce(.Or, matches)) {
   1289                         return i + std.simd.firstTrue(matches).?;
   1290                     }
   1291                     i += block_x_len;
   1292                 }
   1293             }
   1294         }
   1295     }
   1296 
   1297     for (slice[i..], i..) |c, j| {
   1298         if (c == value) return j;
   1299     }
   1300     return null;
   1301 }
   1302 
   1303 test findScalarPos {
   1304     const Types = [_]type{ u8, u16, u32, u64 };
   1305 
   1306     inline for (Types) |T| {
   1307         var memory: [64 / @sizeOf(T)]T = undefined;
   1308         @memset(&memory, 0xaa);
   1309         memory[memory.len - 1] = 0;
   1310 
   1311         for (0..memory.len) |i| {
   1312             try testing.expectEqual(memory.len - i - 1, findScalarPos(T, memory[i..], 0, 0).?);
   1313         }
   1314     }
   1315 }
   1316 
   1317 /// Deprecated in favor of `findAny`.
   1318 pub const indexOfAny = findAny;
   1319 
   1320 /// Linear search for the index of any value in the provided list inside a slice.
   1321 /// Returns null if no values are found.
   1322 pub fn findAny(comptime T: type, slice: []const T, values: []const T) ?usize {
   1323     return findAnyPos(T, slice, 0, values);
   1324 }
   1325 
   1326 /// Deprecated in favor of `findLastAny`.
   1327 pub const lastIndexOfAny = findLastAny;
   1328 
   1329 /// Linear search for the last index of any value in the provided list inside a slice.
   1330 /// Returns null if no values are found.
   1331 pub fn findLastAny(comptime T: type, slice: []const T, values: []const T) ?usize {
   1332     var i: usize = slice.len;
   1333     while (i != 0) {
   1334         i -= 1;
   1335         for (values) |value| {
   1336             if (slice[i] == value) return i;
   1337         }
   1338     }
   1339     return null;
   1340 }
   1341 
   1342 /// Deprecated in favor of `findAnyPos`.
   1343 pub const indexOfAnyPos = findAnyPos;
   1344 
   1345 /// Linear search for the index of any value in the provided list inside a slice, starting from a given position.
   1346 /// Returns null if no values are found.
   1347 pub fn findAnyPos(comptime T: type, slice: []const T, start_index: usize, values: []const T) ?usize {
   1348     if (start_index >= slice.len) return null;
   1349     for (slice[start_index..], start_index..) |c, i| {
   1350         for (values) |value| {
   1351             if (c == value) return i;
   1352         }
   1353     }
   1354     return null;
   1355 }
   1356 
   1357 /// Deprecated in favor of `findNone`.
   1358 pub const indexOfNone = findNone;
   1359 
   1360 /// Find the first item in `slice` which is not contained in `values`.
   1361 ///
   1362 /// Comparable to `strspn` in the C standard library.
   1363 pub fn findNone(comptime T: type, slice: []const T, values: []const T) ?usize {
   1364     return findNonePos(T, slice, 0, values);
   1365 }
   1366 
   1367 test findNone {
   1368     try testing.expect(findNone(u8, "abc123", "123").? == 0);
   1369     try testing.expect(findLastNone(u8, "abc123", "123").? == 2);
   1370     try testing.expect(findNone(u8, "123abc", "123").? == 3);
   1371     try testing.expect(findLastNone(u8, "123abc", "123").? == 5);
   1372     try testing.expect(findNone(u8, "123123", "123") == null);
   1373     try testing.expect(findNone(u8, "333333", "123") == null);
   1374 
   1375     try testing.expect(findNonePos(u8, "abc123", 3, "321") == null);
   1376 }
   1377 
   1378 /// Deprecated in favor of `findLastNone`.
   1379 pub const lastIndexOfNone = findLastNone;
   1380 
   1381 /// Find the last item in `slice` which is not contained in `values`.
   1382 ///
   1383 /// Like `strspn` in the C standard library, but searches from the end.
   1384 pub fn findLastNone(comptime T: type, slice: []const T, values: []const T) ?usize {
   1385     var i: usize = slice.len;
   1386     outer: while (i != 0) {
   1387         i -= 1;
   1388         for (values) |value| {
   1389             if (slice[i] == value) continue :outer;
   1390         }
   1391         return i;
   1392     }
   1393     return null;
   1394 }
   1395 
   1396 pub const indexOfNonePos = findNonePos;
   1397 
   1398 /// Find the first item in `slice[start_index..]` which is not contained in `values`.
   1399 /// The returned index will be relative to the start of `slice`, and never less than `start_index`.
   1400 ///
   1401 /// Comparable to `strspn` in the C standard library.
   1402 pub fn findNonePos(comptime T: type, slice: []const T, start_index: usize, values: []const T) ?usize {
   1403     if (start_index >= slice.len) return null;
   1404     outer: for (slice[start_index..], start_index..) |c, i| {
   1405         for (values) |value| {
   1406             if (c == value) continue :outer;
   1407         }
   1408         return i;
   1409     }
   1410     return null;
   1411 }
   1412 
   1413 /// Deprecated in favor of `find`.
   1414 pub const indexOf = find;
   1415 
   1416 /// Search for needle in haystack and return the index of the first occurrence.
   1417 /// Uses Boyer-Moore-Horspool algorithm on large inputs; linear search on small inputs.
   1418 /// Returns null if needle is not found.
   1419 pub fn find(comptime T: type, haystack: []const T, needle: []const T) ?usize {
   1420     return findPos(T, haystack, 0, needle);
   1421 }
   1422 
   1423 /// Deprecated in favor of `findLastLinear`.
   1424 pub const lastIndexOfLinear = findLastLinear;
   1425 
   1426 /// Find the index in a slice of a sub-slice, searching from the end backwards.
   1427 /// To start looking at a different index, slice the haystack first.
   1428 /// Consider using `lastIndexOf` instead of this, which will automatically use a
   1429 /// more sophisticated algorithm on larger inputs.
   1430 pub fn findLastLinear(comptime T: type, haystack: []const T, needle: []const T) ?usize {
   1431     if (needle.len > haystack.len) return null;
   1432     var i: usize = haystack.len - needle.len;
   1433     while (true) : (i -= 1) {
   1434         if (mem.eql(T, haystack[i..][0..needle.len], needle)) return i;
   1435         if (i == 0) return null;
   1436     }
   1437 }
   1438 
   1439 pub const indexOfPosLinear = findPosLinear;
   1440 
   1441 /// Consider using `findPos` instead of this, which will automatically use a
   1442 /// more sophisticated algorithm on larger inputs.
   1443 pub fn findPosLinear(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize {
   1444     if (needle.len > haystack.len) return null;
   1445     var i: usize = start_index;
   1446     const end = haystack.len - needle.len;
   1447     while (i <= end) : (i += 1) {
   1448         if (eql(T, haystack[i..][0..needle.len], needle)) return i;
   1449     }
   1450     return null;
   1451 }
   1452 
   1453 test findPosLinear {
   1454     try testing.expectEqual(0, findPosLinear(u8, "", 0, ""));
   1455     try testing.expectEqual(0, findPosLinear(u8, "123", 0, ""));
   1456 
   1457     try testing.expectEqual(null, findPosLinear(u8, "", 0, "1"));
   1458     try testing.expectEqual(0, findPosLinear(u8, "1", 0, "1"));
   1459     try testing.expectEqual(null, findPosLinear(u8, "2", 0, "1"));
   1460     try testing.expectEqual(1, findPosLinear(u8, "21", 0, "1"));
   1461     try testing.expectEqual(null, findPosLinear(u8, "222", 0, "1"));
   1462 
   1463     try testing.expectEqual(null, findPosLinear(u8, "", 0, "12"));
   1464     try testing.expectEqual(null, findPosLinear(u8, "1", 0, "12"));
   1465     try testing.expectEqual(null, findPosLinear(u8, "2", 0, "12"));
   1466     try testing.expectEqual(0, findPosLinear(u8, "12", 0, "12"));
   1467     try testing.expectEqual(null, findPosLinear(u8, "21", 0, "12"));
   1468     try testing.expectEqual(1, findPosLinear(u8, "212", 0, "12"));
   1469     try testing.expectEqual(0, findPosLinear(u8, "122", 0, "12"));
   1470     try testing.expectEqual(1, findPosLinear(u8, "212112", 0, "12"));
   1471 }
   1472 
   1473 fn boyerMooreHorspoolPreprocessReverse(pattern: []const u8, table: *[256]usize) void {
   1474     for (table) |*c| {
   1475         c.* = pattern.len;
   1476     }
   1477 
   1478     var i: usize = pattern.len - 1;
   1479     // The first item is intentionally ignored and the skip size will be pattern.len.
   1480     // This is the standard way Boyer-Moore-Horspool is implemented.
   1481     while (i > 0) : (i -= 1) {
   1482         table[pattern[i]] = i;
   1483     }
   1484 }
   1485 
   1486 fn boyerMooreHorspoolPreprocess(pattern: []const u8, table: *[256]usize) void {
   1487     for (table) |*c| {
   1488         c.* = pattern.len;
   1489     }
   1490 
   1491     var i: usize = 0;
   1492     // The last item is intentionally ignored and the skip size will be pattern.len.
   1493     // This is the standard way Boyer-Moore-Horspool is implemented.
   1494     while (i < pattern.len - 1) : (i += 1) {
   1495         table[pattern[i]] = pattern.len - 1 - i;
   1496     }
   1497 }
   1498 
   1499 /// Deprecated in favor of `find`.
   1500 pub const lastIndexOf = findLast;
   1501 
   1502 /// Find the index in a slice of a sub-slice, searching from the end backwards.
   1503 /// To start looking at a different index, slice the haystack first.
   1504 /// Uses the Reverse Boyer-Moore-Horspool algorithm on large inputs;
   1505 /// `lastIndexOfLinear` on small inputs.
   1506 pub fn findLast(comptime T: type, haystack: []const T, needle: []const T) ?usize {
   1507     if (needle.len > haystack.len) return null;
   1508     if (needle.len == 0) return haystack.len;
   1509 
   1510     if (!std.meta.hasUniqueRepresentation(T) or haystack.len < 52 or needle.len <= 4)
   1511         return lastIndexOfLinear(T, haystack, needle);
   1512 
   1513     const haystack_bytes = sliceAsBytes(haystack);
   1514     const needle_bytes = sliceAsBytes(needle);
   1515 
   1516     var skip_table: [256]usize = undefined;
   1517     boyerMooreHorspoolPreprocessReverse(needle_bytes, skip_table[0..]);
   1518 
   1519     var i: usize = haystack_bytes.len - needle_bytes.len;
   1520     while (true) {
   1521         if (i % @sizeOf(T) == 0 and mem.eql(u8, haystack_bytes[i .. i + needle_bytes.len], needle_bytes)) {
   1522             return @divExact(i, @sizeOf(T));
   1523         }
   1524         const skip = skip_table[haystack_bytes[i]];
   1525         if (skip > i) break;
   1526         i -= skip;
   1527     }
   1528 
   1529     return null;
   1530 }
   1531 
   1532 /// Deprecated in favor of `findPos`.
   1533 pub const indexOfPos = findPos;
   1534 
   1535 /// Uses Boyer-Moore-Horspool algorithm on large inputs; `findPosLinear` on small inputs.
   1536 pub fn findPos(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize {
   1537     if (needle.len > haystack.len) return null;
   1538     if (needle.len < 2) {
   1539         if (needle.len == 0) return start_index;
   1540         // findScalarPos is significantly faster than findPosLinear
   1541         return findScalarPos(T, haystack, start_index, needle[0]);
   1542     }
   1543 
   1544     if (!std.meta.hasUniqueRepresentation(T) or haystack.len < 52 or needle.len <= 4)
   1545         return findPosLinear(T, haystack, start_index, needle);
   1546 
   1547     const haystack_bytes = sliceAsBytes(haystack);
   1548     const needle_bytes = sliceAsBytes(needle);
   1549 
   1550     var skip_table: [256]usize = undefined;
   1551     boyerMooreHorspoolPreprocess(needle_bytes, skip_table[0..]);
   1552 
   1553     var i: usize = start_index * @sizeOf(T);
   1554     while (i <= haystack_bytes.len - needle_bytes.len) {
   1555         if (i % @sizeOf(T) == 0 and mem.eql(u8, haystack_bytes[i .. i + needle_bytes.len], needle_bytes)) {
   1556             return @divExact(i, @sizeOf(T));
   1557         }
   1558         i += skip_table[haystack_bytes[i + needle_bytes.len - 1]];
   1559     }
   1560 
   1561     return null;
   1562 }
   1563 
   1564 test find {
   1565     try testing.expect(find(u8, "one two three four five six seven eight nine ten eleven", "three four").? == 8);
   1566     try testing.expect(lastIndexOf(u8, "one two three four five six seven eight nine ten eleven", "three four").? == 8);
   1567     try testing.expect(find(u8, "one two three four five six seven eight nine ten eleven", "two two") == null);
   1568     try testing.expect(lastIndexOf(u8, "one two three four five six seven eight nine ten eleven", "two two") == null);
   1569 
   1570     try testing.expect(find(u8, "one two three four five six seven eight nine ten", "").? == 0);
   1571     try testing.expect(lastIndexOf(u8, "one two three four five six seven eight nine ten", "").? == 48);
   1572 
   1573     try testing.expect(find(u8, "one two three four", "four").? == 14);
   1574     try testing.expect(lastIndexOf(u8, "one two three two four", "two").? == 14);
   1575     try testing.expect(find(u8, "one two three four", "gour") == null);
   1576     try testing.expect(lastIndexOf(u8, "one two three four", "gour") == null);
   1577     try testing.expect(find(u8, "foo", "foo").? == 0);
   1578     try testing.expect(lastIndexOf(u8, "foo", "foo").? == 0);
   1579     try testing.expect(find(u8, "foo", "fool") == null);
   1580     try testing.expect(lastIndexOf(u8, "foo", "lfoo") == null);
   1581     try testing.expect(lastIndexOf(u8, "foo", "fool") == null);
   1582 
   1583     try testing.expect(find(u8, "foo foo", "foo").? == 0);
   1584     try testing.expect(lastIndexOf(u8, "foo foo", "foo").? == 4);
   1585     try testing.expect(lastIndexOfAny(u8, "boo, cat", "abo").? == 6);
   1586     try testing.expect(findScalarLast(u8, "boo", 'o').? == 2);
   1587 }
   1588 
   1589 test "find multibyte" {
   1590     {
   1591         // make haystack and needle long enough to trigger Boyer-Moore-Horspool algorithm
   1592         const haystack = [1]u16{0} ** 100 ++ [_]u16{ 0xbbaa, 0xccbb, 0xddcc, 0xeedd, 0xffee, 0x00ff };
   1593         const needle = [_]u16{ 0xbbaa, 0xccbb, 0xddcc, 0xeedd, 0xffee };
   1594         try testing.expectEqual(findPos(u16, &haystack, 0, &needle), 100);
   1595 
   1596         // check for misaligned false positives (little and big endian)
   1597         const needleLE = [_]u16{ 0xbbbb, 0xcccc, 0xdddd, 0xeeee, 0xffff };
   1598         try testing.expectEqual(findPos(u16, &haystack, 0, &needleLE), null);
   1599         const needleBE = [_]u16{ 0xaacc, 0xbbdd, 0xccee, 0xddff, 0xee00 };
   1600         try testing.expectEqual(findPos(u16, &haystack, 0, &needleBE), null);
   1601     }
   1602 
   1603     {
   1604         // make haystack and needle long enough to trigger Boyer-Moore-Horspool algorithm
   1605         const haystack = [_]u16{ 0xbbaa, 0xccbb, 0xddcc, 0xeedd, 0xffee, 0x00ff } ++ [1]u16{0} ** 100;
   1606         const needle = [_]u16{ 0xbbaa, 0xccbb, 0xddcc, 0xeedd, 0xffee };
   1607         try testing.expectEqual(lastIndexOf(u16, &haystack, &needle), 0);
   1608 
   1609         // check for misaligned false positives (little and big endian)
   1610         const needleLE = [_]u16{ 0xbbbb, 0xcccc, 0xdddd, 0xeeee, 0xffff };
   1611         try testing.expectEqual(lastIndexOf(u16, &haystack, &needleLE), null);
   1612         const needleBE = [_]u16{ 0xaacc, 0xbbdd, 0xccee, 0xddff, 0xee00 };
   1613         try testing.expectEqual(lastIndexOf(u16, &haystack, &needleBE), null);
   1614     }
   1615 }
   1616 
   1617 test "findPos empty needle" {
   1618     try testing.expectEqual(findPos(u8, "abracadabra", 5, ""), 5);
   1619 }
   1620 
   1621 /// Returns the number of needles inside the haystack
   1622 /// needle.len must be > 0
   1623 /// does not count overlapping needles
   1624 pub fn count(comptime T: type, haystack: []const T, needle: []const T) usize {
   1625     if (needle.len == 1) return countScalar(T, haystack, needle[0]);
   1626     assert(needle.len > 0);
   1627     var i: usize = 0;
   1628     var found: usize = 0;
   1629 
   1630     while (findPos(T, haystack, i, needle)) |idx| {
   1631         i = idx + needle.len;
   1632         found += 1;
   1633     }
   1634 
   1635     return found;
   1636 }
   1637 
   1638 test count {
   1639     try testing.expect(count(u8, "", "h") == 0);
   1640     try testing.expect(count(u8, "h", "h") == 1);
   1641     try testing.expect(count(u8, "hh", "h") == 2);
   1642     try testing.expect(count(u8, "world!", "hello") == 0);
   1643     try testing.expect(count(u8, "hello world!", "hello") == 1);
   1644     try testing.expect(count(u8, "   abcabc   abc", "abc") == 3);
   1645     try testing.expect(count(u8, "udexdcbvbruhasdrw", "bruh") == 1);
   1646     try testing.expect(count(u8, "foo bar", "o bar") == 1);
   1647     try testing.expect(count(u8, "foofoofoo", "foo") == 3);
   1648     try testing.expect(count(u8, "fffffff", "ff") == 3);
   1649     try testing.expect(count(u8, "owowowu", "owowu") == 1);
   1650 }
   1651 
   1652 /// Returns the number of times `element` appears in a slice of memory.
   1653 pub fn countScalar(comptime T: type, list: []const T, element: T) usize {
   1654     const n = list.len;
   1655     var i: usize = 0;
   1656     var found: usize = 0;
   1657 
   1658     if (use_vectors_for_comparison and
   1659         (@typeInfo(T) == .int or @typeInfo(T) == .float) and std.math.isPowerOfTwo(@bitSizeOf(T)))
   1660     {
   1661         if (std.simd.suggestVectorLength(T)) |block_size| {
   1662             const Block = @Vector(block_size, T);
   1663 
   1664             const letter_mask: Block = @splat(element);
   1665             while (n - i >= block_size) : (i += block_size) {
   1666                 const haystack_block: Block = list[i..][0..block_size].*;
   1667                 found += std.simd.countTrues(letter_mask == haystack_block);
   1668             }
   1669         }
   1670     }
   1671 
   1672     for (list[i..n]) |item| {
   1673         found += @intFromBool(item == element);
   1674     }
   1675 
   1676     return found;
   1677 }
   1678 
   1679 test countScalar {
   1680     try testing.expectEqual(0, countScalar(u8, "", 'h'));
   1681     try testing.expectEqual(1, countScalar(u8, "h", 'h'));
   1682     try testing.expectEqual(2, countScalar(u8, "hh", 'h'));
   1683     try testing.expectEqual(2, countScalar(u8, "ahhb", 'h'));
   1684     try testing.expectEqual(3, countScalar(u8, "   abcabc   abc", 'b'));
   1685 }
   1686 
   1687 /// Returns true if the haystack contains expected_count or more needles
   1688 /// needle.len must be > 0
   1689 /// does not count overlapping needles
   1690 //
   1691 /// See also: `containsAtLeastScalar`
   1692 pub fn containsAtLeast(comptime T: type, haystack: []const T, expected_count: usize, needle: []const T) bool {
   1693     if (needle.len == 1) return containsAtLeastScalar(T, haystack, expected_count, needle[0]);
   1694     assert(needle.len > 0);
   1695     if (expected_count == 0) return true;
   1696 
   1697     var i: usize = 0;
   1698     var found: usize = 0;
   1699 
   1700     while (findPos(T, haystack, i, needle)) |idx| {
   1701         i = idx + needle.len;
   1702         found += 1;
   1703         if (found == expected_count) return true;
   1704     }
   1705     return false;
   1706 }
   1707 
   1708 test containsAtLeast {
   1709     try testing.expect(containsAtLeast(u8, "aa", 0, "a"));
   1710     try testing.expect(containsAtLeast(u8, "aa", 1, "a"));
   1711     try testing.expect(containsAtLeast(u8, "aa", 2, "a"));
   1712     try testing.expect(!containsAtLeast(u8, "aa", 3, "a"));
   1713 
   1714     try testing.expect(containsAtLeast(u8, "radaradar", 1, "radar"));
   1715     try testing.expect(!containsAtLeast(u8, "radaradar", 2, "radar"));
   1716 
   1717     try testing.expect(containsAtLeast(u8, "radarradaradarradar", 3, "radar"));
   1718     try testing.expect(!containsAtLeast(u8, "radarradaradarradar", 4, "radar"));
   1719 
   1720     try testing.expect(containsAtLeast(u8, "   radar      radar   ", 2, "radar"));
   1721     try testing.expect(!containsAtLeast(u8, "   radar      radar   ", 3, "radar"));
   1722 }
   1723 
   1724 /// Deprecated in favor of `containsAtLeastScalar2`.
   1725 pub fn containsAtLeastScalar(comptime T: type, list: []const T, minimum: usize, element: T) bool {
   1726     return containsAtLeastScalar2(T, list, element, minimum);
   1727 }
   1728 
   1729 /// Returns true if `element` appears at least `minimum` number of times in `list`.
   1730 //
   1731 /// Related:
   1732 /// * `containsAtLeast`
   1733 /// * `countScalar`
   1734 pub fn containsAtLeastScalar2(comptime T: type, list: []const T, element: T, minimum: usize) bool {
   1735     const n = list.len;
   1736     var i: usize = 0;
   1737     var found: usize = 0;
   1738 
   1739     if (use_vectors_for_comparison and
   1740         (@typeInfo(T) == .int or @typeInfo(T) == .float) and std.math.isPowerOfTwo(@bitSizeOf(T)))
   1741     {
   1742         if (std.simd.suggestVectorLength(T)) |block_size| {
   1743             const Block = @Vector(block_size, T);
   1744 
   1745             const letter_mask: Block = @splat(element);
   1746             while (n - i >= block_size) : (i += block_size) {
   1747                 const haystack_block: Block = list[i..][0..block_size].*;
   1748                 found += std.simd.countTrues(letter_mask == haystack_block);
   1749                 if (found >= minimum) return true;
   1750             }
   1751         }
   1752     }
   1753 
   1754     for (list[i..n]) |item| {
   1755         found += @intFromBool(item == element);
   1756         if (found >= minimum) return true;
   1757     }
   1758 
   1759     return false;
   1760 }
   1761 
   1762 test containsAtLeastScalar2 {
   1763     try testing.expect(containsAtLeastScalar2(u8, "aa", 'a', 0));
   1764     try testing.expect(containsAtLeastScalar2(u8, "aa", 'a', 1));
   1765     try testing.expect(containsAtLeastScalar2(u8, "aa", 'a', 2));
   1766     try testing.expect(!containsAtLeastScalar2(u8, "aa", 'a', 3));
   1767 
   1768     try testing.expect(containsAtLeastScalar2(u8, "adadda", 'd', 3));
   1769     try testing.expect(!containsAtLeastScalar2(u8, "adadda", 'd', 4));
   1770 }
   1771 
   1772 /// Reads an integer from memory with size equal to bytes.len.
   1773 /// ReturnType specifies the return type, which must be large enough to store
   1774 /// the result.
   1775 pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: Endian) ReturnType {
   1776     assert(@typeInfo(ReturnType).int.bits >= bytes.len * 8);
   1777     const bits = @typeInfo(ReturnType).int.bits;
   1778     const signedness = @typeInfo(ReturnType).int.signedness;
   1779     const WorkType = std.meta.Int(signedness, @max(16, bits));
   1780     var result: WorkType = 0;
   1781     switch (endian) {
   1782         .big => {
   1783             for (bytes) |b| {
   1784                 result = (result << 8) | b;
   1785             }
   1786         },
   1787         .little => {
   1788             const ShiftType = math.Log2Int(WorkType);
   1789             for (bytes, 0..) |b, index| {
   1790                 result = result | (@as(WorkType, b) << @as(ShiftType, @intCast(index * 8)));
   1791             }
   1792         },
   1793     }
   1794     return @truncate(result);
   1795 }
   1796 
   1797 test readVarInt {
   1798     try testing.expect(readVarInt(u0, &[_]u8{}, .big) == 0x0);
   1799     try testing.expect(readVarInt(u0, &[_]u8{}, .little) == 0x0);
   1800     try testing.expect(readVarInt(u8, &[_]u8{0x12}, .big) == 0x12);
   1801     try testing.expect(readVarInt(u8, &[_]u8{0xde}, .little) == 0xde);
   1802     try testing.expect(readVarInt(u16, &[_]u8{ 0x12, 0x34 }, .big) == 0x1234);
   1803     try testing.expect(readVarInt(u16, &[_]u8{ 0x12, 0x34 }, .little) == 0x3412);
   1804 
   1805     try testing.expect(readVarInt(i8, &[_]u8{0xff}, .big) == -1);
   1806     try testing.expect(readVarInt(i8, &[_]u8{0xfe}, .little) == -2);
   1807     try testing.expect(readVarInt(i16, &[_]u8{ 0xff, 0xfd }, .big) == -3);
   1808     try testing.expect(readVarInt(i16, &[_]u8{ 0xfc, 0xff }, .little) == -4);
   1809 
   1810     // Return type can be oversized (bytes.len * 8 < @typeInfo(ReturnType).int.bits)
   1811     try testing.expect(readVarInt(u9, &[_]u8{0x12}, .little) == 0x12);
   1812     try testing.expect(readVarInt(u9, &[_]u8{0xde}, .big) == 0xde);
   1813     try testing.expect(readVarInt(u80, &[_]u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }, .big) == 0x123456789abcdef024);
   1814     try testing.expect(readVarInt(u80, &[_]u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }, .little) == 0xfedcba9876543210ec);
   1815 
   1816     try testing.expect(readVarInt(i9, &[_]u8{0xff}, .big) == 0xff);
   1817     try testing.expect(readVarInt(i9, &[_]u8{0xfe}, .little) == 0xfe);
   1818 }
   1819 
   1820 /// Loads an integer from packed memory with provided bit_count, bit_offset, and signedness.
   1821 /// Asserts that T is large enough to store the read value.
   1822 pub fn readVarPackedInt(
   1823     comptime T: type,
   1824     bytes: []const u8,
   1825     bit_offset: usize,
   1826     bit_count: usize,
   1827     endian: std.builtin.Endian,
   1828     signedness: std.builtin.Signedness,
   1829 ) T {
   1830     const uN = std.meta.Int(.unsigned, @bitSizeOf(T));
   1831     const iN = std.meta.Int(.signed, @bitSizeOf(T));
   1832     const Log2N = std.math.Log2Int(T);
   1833 
   1834     const read_size = (bit_count + (bit_offset % 8) + 7) / 8;
   1835     const bit_shift = @as(u3, @intCast(bit_offset % 8));
   1836     const pad = @as(Log2N, @intCast(@bitSizeOf(T) - bit_count));
   1837 
   1838     const lowest_byte = switch (endian) {
   1839         .big => bytes.len - (bit_offset / 8) - read_size,
   1840         .little => bit_offset / 8,
   1841     };
   1842     const read_bytes = bytes[lowest_byte..][0..read_size];
   1843 
   1844     if (@bitSizeOf(T) <= 8) {
   1845         // These are the same shifts/masks we perform below, but adds `@truncate`/`@intCast`
   1846         // where needed since int is smaller than a byte.
   1847         const value = if (read_size == 1) b: {
   1848             break :b @as(uN, @truncate(read_bytes[0] >> bit_shift));
   1849         } else b: {
   1850             const i: u1 = @intFromBool(endian == .big);
   1851             const head = @as(uN, @truncate(read_bytes[i] >> bit_shift));
   1852             const tail_shift = @as(Log2N, @intCast(@as(u4, 8) - bit_shift));
   1853             const tail = @as(uN, @truncate(read_bytes[1 - i]));
   1854             break :b (tail << tail_shift) | head;
   1855         };
   1856         switch (signedness) {
   1857             .signed => return @as(T, @intCast((@as(iN, @bitCast(value)) << pad) >> pad)),
   1858             .unsigned => return @as(T, @intCast((@as(uN, @bitCast(value)) << pad) >> pad)),
   1859         }
   1860     }
   1861 
   1862     // Copy the value out (respecting endianness), accounting for bit_shift
   1863     var int: uN = 0;
   1864     switch (endian) {
   1865         .big => {
   1866             for (read_bytes[0 .. read_size - 1]) |elem| {
   1867                 int = elem | (int << 8);
   1868             }
   1869             int = (read_bytes[read_size - 1] >> bit_shift) | (int << (@as(u4, 8) - bit_shift));
   1870         },
   1871         .little => {
   1872             int = read_bytes[0] >> bit_shift;
   1873             for (read_bytes[1..], 0..) |elem, i| {
   1874                 int |= (@as(uN, elem) << @as(Log2N, @intCast((8 * (i + 1) - bit_shift))));
   1875             }
   1876         },
   1877     }
   1878     switch (signedness) {
   1879         .signed => return @as(T, @intCast((@as(iN, @bitCast(int)) << pad) >> pad)),
   1880         .unsigned => return @as(T, @intCast((@as(uN, @bitCast(int)) << pad) >> pad)),
   1881     }
   1882 }
   1883 
   1884 test readVarPackedInt {
   1885     const T = packed struct(u16) { a: u3, b: u7, c: u6 };
   1886     var st = T{ .a = 1, .b = 2, .c = 4 };
   1887     const b_field = readVarPackedInt(u64, std.mem.asBytes(&st), @bitOffsetOf(T, "b"), 7, builtin.cpu.arch.endian(), .unsigned);
   1888     try std.testing.expectEqual(st.b, b_field);
   1889 }
   1890 
   1891 /// Reads an integer from memory with bit count specified by T.
   1892 /// The bit count of T must be evenly divisible by 8.
   1893 /// This function cannot fail and cannot cause undefined behavior.
   1894 pub inline fn readInt(comptime T: type, buffer: *const [@divExact(@typeInfo(T).int.bits, 8)]u8, endian: Endian) T {
   1895     const value: T = @bitCast(buffer.*);
   1896     return if (endian == native_endian) value else @byteSwap(value);
   1897 }
   1898 
   1899 test readInt {
   1900     try testing.expect(readInt(u0, &[_]u8{}, .big) == 0x0);
   1901     try testing.expect(readInt(u0, &[_]u8{}, .little) == 0x0);
   1902 
   1903     try testing.expect(readInt(u8, &[_]u8{0x32}, .big) == 0x32);
   1904     try testing.expect(readInt(u8, &[_]u8{0x12}, .little) == 0x12);
   1905 
   1906     try testing.expect(readInt(u16, &[_]u8{ 0x12, 0x34 }, .big) == 0x1234);
   1907     try testing.expect(readInt(u16, &[_]u8{ 0x12, 0x34 }, .little) == 0x3412);
   1908 
   1909     try testing.expect(readInt(u72, &[_]u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }, .big) == 0x123456789abcdef024);
   1910     try testing.expect(readInt(u72, &[_]u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }, .little) == 0xfedcba9876543210ec);
   1911 
   1912     try testing.expect(readInt(i8, &[_]u8{0xff}, .big) == -1);
   1913     try testing.expect(readInt(i8, &[_]u8{0xfe}, .little) == -2);
   1914 
   1915     try testing.expect(readInt(i16, &[_]u8{ 0xff, 0xfd }, .big) == -3);
   1916     try testing.expect(readInt(i16, &[_]u8{ 0xfc, 0xff }, .little) == -4);
   1917 
   1918     try moreReadIntTests();
   1919     try comptime moreReadIntTests();
   1920 }
   1921 
   1922 fn readPackedIntLittle(comptime T: type, bytes: []const u8, bit_offset: usize) T {
   1923     const uN = std.meta.Int(.unsigned, @bitSizeOf(T));
   1924     const Log2N = std.math.Log2Int(T);
   1925 
   1926     const bit_count = @as(usize, @bitSizeOf(T));
   1927     const bit_shift = @as(u3, @intCast(bit_offset % 8));
   1928 
   1929     const load_size = (bit_count + 7) / 8;
   1930     const load_tail_bits = @as(u3, @intCast((load_size * 8) - bit_count));
   1931     const LoadInt = std.meta.Int(.unsigned, load_size * 8);
   1932 
   1933     if (bit_count == 0)
   1934         return 0;
   1935 
   1936     // Read by loading a LoadInt, and then follow it up with a 1-byte read
   1937     // of the tail if bit_offset pushed us over a byte boundary.
   1938     const read_bytes = bytes[bit_offset / 8 ..];
   1939     const val = @as(uN, @truncate(readInt(LoadInt, read_bytes[0..load_size], .little) >> bit_shift));
   1940     if (bit_shift > load_tail_bits) {
   1941         const tail_bits = @as(Log2N, @intCast(bit_shift - load_tail_bits));
   1942         const tail_byte = read_bytes[load_size];
   1943         const tail_truncated = if (bit_count < 8) @as(uN, @truncate(tail_byte)) else @as(uN, tail_byte);
   1944         return @as(T, @bitCast(val | (tail_truncated << (@as(Log2N, @truncate(bit_count)) -% tail_bits))));
   1945     } else return @as(T, @bitCast(val));
   1946 }
   1947 
   1948 fn readPackedIntBig(comptime T: type, bytes: []const u8, bit_offset: usize) T {
   1949     const uN = std.meta.Int(.unsigned, @bitSizeOf(T));
   1950     const Log2N = std.math.Log2Int(T);
   1951 
   1952     const bit_count = @as(usize, @bitSizeOf(T));
   1953     const bit_shift = @as(u3, @intCast(bit_offset % 8));
   1954     const byte_count = (@as(usize, bit_shift) + bit_count + 7) / 8;
   1955 
   1956     const load_size = (bit_count + 7) / 8;
   1957     const load_tail_bits = @as(u3, @intCast((load_size * 8) - bit_count));
   1958     const LoadInt = std.meta.Int(.unsigned, load_size * 8);
   1959 
   1960     if (bit_count == 0)
   1961         return 0;
   1962 
   1963     // Read by loading a LoadInt, and then follow it up with a 1-byte read
   1964     // of the tail if bit_offset pushed us over a byte boundary.
   1965     const end = bytes.len - (bit_offset / 8);
   1966     const read_bytes = bytes[(end - byte_count)..end];
   1967     const val = @as(uN, @truncate(readInt(LoadInt, bytes[(end - load_size)..end][0..load_size], .big) >> bit_shift));
   1968     if (bit_shift > load_tail_bits) {
   1969         const tail_bits = @as(Log2N, @intCast(bit_shift - load_tail_bits));
   1970         const tail_byte = if (bit_count < 8) @as(uN, @truncate(read_bytes[0])) else @as(uN, read_bytes[0]);
   1971         return @as(T, @bitCast(val | (tail_byte << (@as(Log2N, @truncate(bit_count)) -% tail_bits))));
   1972     } else return @as(T, @bitCast(val));
   1973 }
   1974 
   1975 /// Deprecated: use readPackedInt(T, bytes, bit_offset, value, .native)
   1976 pub const readPackedIntNative = switch (native_endian) {
   1977     .little => readPackedIntLittle,
   1978     .big => readPackedIntBig,
   1979 };
   1980 
   1981 /// Deprecated: use readPackedInt(T, bytes, bit_offset, value, .foreign)
   1982 pub const readPackedIntForeign = switch (native_endian) {
   1983     .little => readPackedIntBig,
   1984     .big => readPackedIntLittle,
   1985 };
   1986 
   1987 /// Loads an integer from packed memory.
   1988 /// Asserts that buffer contains at least bit_offset + @bitSizeOf(T) bits.
   1989 pub fn readPackedInt(comptime T: type, bytes: []const u8, bit_offset: usize, endian: Endian) T {
   1990     switch (endian) {
   1991         .little => return readPackedIntLittle(T, bytes, bit_offset),
   1992         .big => return readPackedIntBig(T, bytes, bit_offset),
   1993     }
   1994 }
   1995 
   1996 test readPackedInt {
   1997     const T = packed struct(u16) { a: u3, b: u7, c: u6 };
   1998     var st = T{ .a = 1, .b = 2, .c = 4 };
   1999     const b_field = readPackedInt(u7, std.mem.asBytes(&st), @bitOffsetOf(T, "b"), builtin.cpu.arch.endian());
   2000     try std.testing.expectEqual(st.b, b_field);
   2001 }
   2002 
   2003 test "comptime read/write int" {
   2004     comptime {
   2005         var bytes: [2]u8 = undefined;
   2006         writeInt(u16, &bytes, 0x1234, .little);
   2007         const result = readInt(u16, &bytes, .big);
   2008         try testing.expect(result == 0x3412);
   2009     }
   2010     comptime {
   2011         var bytes: [2]u8 = undefined;
   2012         writeInt(u16, &bytes, 0x1234, .big);
   2013         const result = readInt(u16, &bytes, .little);
   2014         try testing.expect(result == 0x3412);
   2015     }
   2016 }
   2017 
   2018 /// Writes an integer to memory, storing it in twos-complement.
   2019 /// This function always succeeds, has defined behavior for all inputs, but
   2020 /// the integer bit width must be divisible by 8.
   2021 pub inline fn writeInt(comptime T: type, buffer: *[@divExact(@typeInfo(T).int.bits, 8)]u8, value: T, endian: Endian) void {
   2022     buffer.* = @bitCast(if (endian == native_endian) value else @byteSwap(value));
   2023 }
   2024 
   2025 test writeInt {
   2026     var buf0: [0]u8 = undefined;
   2027     var buf1: [1]u8 = undefined;
   2028     var buf2: [2]u8 = undefined;
   2029     var buf9: [9]u8 = undefined;
   2030 
   2031     writeInt(u0, &buf0, 0x0, .big);
   2032     try testing.expect(eql(u8, buf0[0..], &[_]u8{}));
   2033     writeInt(u0, &buf0, 0x0, .little);
   2034     try testing.expect(eql(u8, buf0[0..], &[_]u8{}));
   2035 
   2036     writeInt(u8, &buf1, 0x12, .big);
   2037     try testing.expect(eql(u8, buf1[0..], &[_]u8{0x12}));
   2038     writeInt(u8, &buf1, 0x34, .little);
   2039     try testing.expect(eql(u8, buf1[0..], &[_]u8{0x34}));
   2040 
   2041     writeInt(u16, &buf2, 0x1234, .big);
   2042     try testing.expect(eql(u8, buf2[0..], &[_]u8{ 0x12, 0x34 }));
   2043     writeInt(u16, &buf2, 0x5678, .little);
   2044     try testing.expect(eql(u8, buf2[0..], &[_]u8{ 0x78, 0x56 }));
   2045 
   2046     writeInt(u72, &buf9, 0x123456789abcdef024, .big);
   2047     try testing.expect(eql(u8, buf9[0..], &[_]u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }));
   2048     writeInt(u72, &buf9, 0xfedcba9876543210ec, .little);
   2049     try testing.expect(eql(u8, buf9[0..], &[_]u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }));
   2050 
   2051     writeInt(i8, &buf1, -1, .big);
   2052     try testing.expect(eql(u8, buf1[0..], &[_]u8{0xff}));
   2053     writeInt(i8, &buf1, -2, .little);
   2054     try testing.expect(eql(u8, buf1[0..], &[_]u8{0xfe}));
   2055 
   2056     writeInt(i16, &buf2, -3, .big);
   2057     try testing.expect(eql(u8, buf2[0..], &[_]u8{ 0xff, 0xfd }));
   2058     writeInt(i16, &buf2, -4, .little);
   2059     try testing.expect(eql(u8, buf2[0..], &[_]u8{ 0xfc, 0xff }));
   2060 }
   2061 
   2062 fn writePackedIntLittle(comptime T: type, bytes: []u8, bit_offset: usize, value: T) void {
   2063     const uN = std.meta.Int(.unsigned, @bitSizeOf(T));
   2064     const Log2N = std.math.Log2Int(T);
   2065 
   2066     const bit_count = @as(usize, @bitSizeOf(T));
   2067     const bit_shift = @as(u3, @intCast(bit_offset % 8));
   2068 
   2069     const store_size = (@bitSizeOf(T) + 7) / 8;
   2070     const store_tail_bits = @as(u3, @intCast((store_size * 8) - bit_count));
   2071     const StoreInt = std.meta.Int(.unsigned, store_size * 8);
   2072 
   2073     if (bit_count == 0)
   2074         return;
   2075 
   2076     // Write by storing a StoreInt, and then follow it up with a 1-byte tail
   2077     // if bit_offset pushed us over a byte boundary.
   2078     const write_bytes = bytes[bit_offset / 8 ..];
   2079     const head = write_bytes[0] & ((@as(u8, 1) << bit_shift) - 1);
   2080 
   2081     var write_value = (@as(StoreInt, @as(uN, @bitCast(value))) << bit_shift) | @as(StoreInt, @intCast(head));
   2082     if (bit_shift > store_tail_bits) {
   2083         const tail_len = @as(Log2N, @intCast(bit_shift - store_tail_bits));
   2084         write_bytes[store_size] &= ~((@as(u8, 1) << @as(u3, @intCast(tail_len))) - 1);
   2085         write_bytes[store_size] |= @as(u8, @intCast((@as(uN, @bitCast(value)) >> (@as(Log2N, @truncate(bit_count)) -% tail_len))));
   2086     } else if (bit_shift < store_tail_bits) {
   2087         const tail_len = store_tail_bits - bit_shift;
   2088         const tail = write_bytes[store_size - 1] & (@as(u8, 0xfe) << (7 - tail_len));
   2089         write_value |= @as(StoreInt, tail) << (8 * (store_size - 1));
   2090     }
   2091 
   2092     writeInt(StoreInt, write_bytes[0..store_size], write_value, .little);
   2093 }
   2094 
   2095 fn writePackedIntBig(comptime T: type, bytes: []u8, bit_offset: usize, value: T) void {
   2096     const uN = std.meta.Int(.unsigned, @bitSizeOf(T));
   2097     const Log2N = std.math.Log2Int(T);
   2098 
   2099     const bit_count = @as(usize, @bitSizeOf(T));
   2100     const bit_shift = @as(u3, @intCast(bit_offset % 8));
   2101     const byte_count = (bit_shift + bit_count + 7) / 8;
   2102 
   2103     const store_size = (@bitSizeOf(T) + 7) / 8;
   2104     const store_tail_bits = @as(u3, @intCast((store_size * 8) - bit_count));
   2105     const StoreInt = std.meta.Int(.unsigned, store_size * 8);
   2106 
   2107     if (bit_count == 0)
   2108         return;
   2109 
   2110     // Write by storing a StoreInt, and then follow it up with a 1-byte tail
   2111     // if bit_offset pushed us over a byte boundary.
   2112     const end = bytes.len - (bit_offset / 8);
   2113     const write_bytes = bytes[(end - byte_count)..end];
   2114     const head = write_bytes[byte_count - 1] & ((@as(u8, 1) << bit_shift) - 1);
   2115 
   2116     var write_value = (@as(StoreInt, @as(uN, @bitCast(value))) << bit_shift) | @as(StoreInt, @intCast(head));
   2117     if (bit_shift > store_tail_bits) {
   2118         const tail_len = @as(Log2N, @intCast(bit_shift - store_tail_bits));
   2119         write_bytes[0] &= ~((@as(u8, 1) << @as(u3, @intCast(tail_len))) - 1);
   2120         write_bytes[0] |= @as(u8, @intCast((@as(uN, @bitCast(value)) >> (@as(Log2N, @truncate(bit_count)) -% tail_len))));
   2121     } else if (bit_shift < store_tail_bits) {
   2122         const tail_len = store_tail_bits - bit_shift;
   2123         const tail = write_bytes[0] & (@as(u8, 0xfe) << (7 - tail_len));
   2124         write_value |= @as(StoreInt, tail) << (8 * (store_size - 1));
   2125     }
   2126 
   2127     writeInt(StoreInt, write_bytes[(byte_count - store_size)..][0..store_size], write_value, .big);
   2128 }
   2129 
   2130 /// Deprecated: use writePackedInt(T, bytes, bit_offset, value, .native)
   2131 pub const writePackedIntNative = switch (native_endian) {
   2132     .little => writePackedIntLittle,
   2133     .big => writePackedIntBig,
   2134 };
   2135 
   2136 /// Deprecated: use writePackedInt(T, bytes, bit_offset, value, .foreign)
   2137 pub const writePackedIntForeign = switch (native_endian) {
   2138     .little => writePackedIntBig,
   2139     .big => writePackedIntLittle,
   2140 };
   2141 
   2142 /// Stores an integer to packed memory.
   2143 /// Asserts that buffer contains at least bit_offset + @bitSizeOf(T) bits.
   2144 pub fn writePackedInt(comptime T: type, bytes: []u8, bit_offset: usize, value: T, endian: Endian) void {
   2145     switch (endian) {
   2146         .little => writePackedIntLittle(T, bytes, bit_offset, value),
   2147         .big => writePackedIntBig(T, bytes, bit_offset, value),
   2148     }
   2149 }
   2150 
   2151 test writePackedInt {
   2152     const T = packed struct(u16) { a: u3, b: u7, c: u6 };
   2153     var st = T{ .a = 1, .b = 2, .c = 4 };
   2154     writePackedInt(u7, std.mem.asBytes(&st), @bitOffsetOf(T, "b"), 0x7f, builtin.cpu.arch.endian());
   2155     try std.testing.expectEqual(T{ .a = 1, .b = 0x7f, .c = 4 }, st);
   2156 }
   2157 
   2158 /// Stores an integer to packed memory with provided bit_offset, bit_count, and signedness.
   2159 /// If negative, the written value is sign-extended.
   2160 pub fn writeVarPackedInt(bytes: []u8, bit_offset: usize, bit_count: usize, value: anytype, endian: std.builtin.Endian) void {
   2161     const T = @TypeOf(value);
   2162     const uN = std.meta.Int(.unsigned, @bitSizeOf(T));
   2163 
   2164     const bit_shift = @as(u3, @intCast(bit_offset % 8));
   2165     const write_size = (bit_count + bit_shift + 7) / 8;
   2166     const lowest_byte = switch (endian) {
   2167         .big => bytes.len - (bit_offset / 8) - write_size,
   2168         .little => bit_offset / 8,
   2169     };
   2170     const write_bytes = bytes[lowest_byte..][0..write_size];
   2171 
   2172     if (write_size == 0) {
   2173         return;
   2174     } else if (write_size == 1) {
   2175         // Single byte writes are handled specially, since we need to mask bits
   2176         // on both ends of the byte.
   2177         const mask = (@as(u8, 0xff) >> @as(u3, @intCast(8 - bit_count)));
   2178         const new_bits = @as(u8, @intCast(@as(uN, @bitCast(value)) & mask)) << bit_shift;
   2179         write_bytes[0] = (write_bytes[0] & ~(mask << bit_shift)) | new_bits;
   2180         return;
   2181     }
   2182 
   2183     var remaining: T = value;
   2184 
   2185     // Iterate bytes forward for Little-endian, backward for Big-endian
   2186     const delta: i2 = if (endian == .big) -1 else 1;
   2187     const start = if (endian == .big) @as(isize, @intCast(write_bytes.len - 1)) else 0;
   2188 
   2189     var i: isize = start; // isize for signed index arithmetic
   2190 
   2191     // Write first byte, using a mask to protects bits preceding bit_offset
   2192     const head_mask = @as(u8, 0xff) >> bit_shift;
   2193     write_bytes[@intCast(i)] &= ~(head_mask << bit_shift);
   2194     write_bytes[@intCast(i)] |= @as(u8, @intCast(@as(uN, @bitCast(remaining)) & head_mask)) << bit_shift;
   2195     remaining = math.shr(T, remaining, @as(u4, 8) - bit_shift);
   2196     i += delta;
   2197 
   2198     // Write bytes[1..bytes.len - 1]
   2199     if (@bitSizeOf(T) > 8) {
   2200         const loop_end = start + delta * (@as(isize, @intCast(write_size)) - 1);
   2201         while (i != loop_end) : (i += delta) {
   2202             write_bytes[@as(usize, @intCast(i))] = @as(u8, @truncate(@as(uN, @bitCast(remaining))));
   2203             remaining >>= 8;
   2204         }
   2205     }
   2206 
   2207     // Write last byte, using a mask to protect bits following bit_offset + bit_count
   2208     const following_bits = -%@as(u3, @truncate(bit_shift + bit_count));
   2209     const tail_mask = (@as(u8, 0xff) << following_bits) >> following_bits;
   2210     write_bytes[@as(usize, @intCast(i))] &= ~tail_mask;
   2211     write_bytes[@as(usize, @intCast(i))] |= @as(u8, @intCast(@as(uN, @bitCast(remaining)) & tail_mask));
   2212 }
   2213 
   2214 test writeVarPackedInt {
   2215     const T = packed struct(u16) { a: u3, b: u7, c: u6 };
   2216     var st = T{ .a = 1, .b = 2, .c = 4 };
   2217     const value: u64 = 0x7f;
   2218     writeVarPackedInt(std.mem.asBytes(&st), @bitOffsetOf(T, "b"), 7, value, builtin.cpu.arch.endian());
   2219     try testing.expectEqual(T{ .a = 1, .b = value, .c = 4 }, st);
   2220 }
   2221 
   2222 /// Swap the byte order of all the members of the fields of a struct
   2223 /// (Changing their endianness)
   2224 pub fn byteSwapAllFields(comptime S: type, ptr: *S) void {
   2225     byteSwapAllFieldsAligned(S, .of(S), ptr);
   2226 }
   2227 
   2228 /// Swap the byte order of all the members of the fields of a struct
   2229 /// (Changing their endianness)
   2230 pub fn byteSwapAllFieldsAligned(comptime S: type, comptime a: Alignment, ptr: *align(a.toByteUnits()) S) void {
   2231     switch (@typeInfo(S)) {
   2232         .@"struct" => |struct_info| {
   2233             if (struct_info.backing_integer) |Int| {
   2234                 ptr.* = @bitCast(@byteSwap(@as(Int, @bitCast(ptr.*))));
   2235             } else inline for (std.meta.fields(S)) |f| {
   2236                 switch (@typeInfo(f.type)) {
   2237                     .@"struct" => byteSwapAllFieldsAligned(f.type, .fromByteUnits(f.alignment orelse @alignOf(f.type)), &@field(ptr, f.name)),
   2238                     .@"union", .array => byteSwapAllFieldsAligned(f.type, .fromByteUnits(f.alignment orelse @alignOf(f.type)), &@field(ptr, f.name)),
   2239                     .@"enum" => {
   2240                         @field(ptr, f.name) = @enumFromInt(@byteSwap(@intFromEnum(@field(ptr, f.name))));
   2241                     },
   2242                     .bool => {},
   2243                     .float => |float_info| {
   2244                         @field(ptr, f.name) = @bitCast(@byteSwap(@as(std.meta.Int(.unsigned, float_info.bits), @bitCast(@field(ptr, f.name)))));
   2245                     },
   2246                     else => {
   2247                         @field(ptr, f.name) = @byteSwap(@field(ptr, f.name));
   2248                     },
   2249                 }
   2250             }
   2251         },
   2252         .@"union" => |union_info| {
   2253             if (union_info.tag_type != null) {
   2254                 @compileError("byteSwapAllFields expects an untagged union");
   2255             }
   2256 
   2257             const first_size = @bitSizeOf(union_info.fields[0].type);
   2258             inline for (union_info.fields) |field| {
   2259                 if (@bitSizeOf(field.type) != first_size) {
   2260                     @compileError("Unable to byte-swap unions with varying field sizes");
   2261                 }
   2262             }
   2263 
   2264             const BackingInt = std.meta.Int(.unsigned, @bitSizeOf(S));
   2265             ptr.* = @bitCast(@byteSwap(@as(BackingInt, @bitCast(ptr.*))));
   2266         },
   2267         .array => |info| {
   2268             byteSwapAllElements(info.child, ptr);
   2269         },
   2270         else => {
   2271             ptr.* = @byteSwap(ptr.*);
   2272         },
   2273     }
   2274 }
   2275 
   2276 test byteSwapAllFields {
   2277     const T = extern struct {
   2278         f0: u8,
   2279         f1: u16,
   2280         f2: u32,
   2281         f3: [1]u8,
   2282         f4: bool,
   2283         f5: f32,
   2284         f6: extern union { f0: u16, f1: u16 },
   2285     };
   2286     const K = extern struct {
   2287         f0: u8,
   2288         f1: T,
   2289         f2: u16,
   2290         f3: [1]u8,
   2291         f4: bool,
   2292         f5: f32,
   2293     };
   2294     const P = packed struct(u32) {
   2295         f0: u1,
   2296         f1: u7,
   2297         f2: u4,
   2298         f3: u4,
   2299         f4: u16,
   2300     };
   2301     const A = extern struct {
   2302         f0: u32,
   2303         f1: extern struct {
   2304             f0: u64,
   2305         } align(4),
   2306         f2: u32,
   2307     };
   2308     var s = T{
   2309         .f0 = 0x12,
   2310         .f1 = 0x1234,
   2311         .f2 = 0x12345678,
   2312         .f3 = .{0x12},
   2313         .f4 = true,
   2314         .f5 = @as(f32, @bitCast(@as(u32, 0x4640e400))),
   2315         .f6 = .{ .f0 = 0x1234 },
   2316     };
   2317     var k = K{
   2318         .f0 = 0x12,
   2319         .f1 = s,
   2320         .f2 = 0x1234,
   2321         .f3 = .{0x12},
   2322         .f4 = false,
   2323         .f5 = @as(f32, @bitCast(@as(u32, 0x45d42800))),
   2324     };
   2325     var p: P = @bitCast(@as(u32, 0x01234567));
   2326     var a: A = A{
   2327         .f0 = 0x12345678,
   2328         .f1 = .{ .f0 = 0x123456789ABCDEF0 },
   2329         .f2 = 0x87654321,
   2330     };
   2331     byteSwapAllFields(T, &s);
   2332     byteSwapAllFields(K, &k);
   2333     byteSwapAllFields(P, &p);
   2334     byteSwapAllFields(A, &a);
   2335     try std.testing.expectEqual(T{
   2336         .f0 = 0x12,
   2337         .f1 = 0x3412,
   2338         .f2 = 0x78563412,
   2339         .f3 = .{0x12},
   2340         .f4 = true,
   2341         .f5 = @as(f32, @bitCast(@as(u32, 0x00e44046))),
   2342         .f6 = .{ .f0 = 0x3412 },
   2343     }, s);
   2344     try std.testing.expectEqual(K{
   2345         .f0 = 0x12,
   2346         .f1 = s,
   2347         .f2 = 0x3412,
   2348         .f3 = .{0x12},
   2349         .f4 = false,
   2350         .f5 = @as(f32, @bitCast(@as(u32, 0x0028d445))),
   2351     }, k);
   2352     try std.testing.expectEqual(@as(P, @bitCast(@as(u32, 0x67452301))), p);
   2353     try std.testing.expectEqual(A{
   2354         .f0 = 0x78563412,
   2355         .f1 = .{ .f0 = 0xF0DEBC9A78563412 },
   2356         .f2 = 0x21436587,
   2357     }, a);
   2358 }
   2359 
   2360 /// Reverses the byte order of all elements in a slice.
   2361 /// Handles structs, unions, arrays, enums, floats, and integers recursively.
   2362 /// Useful for converting between little-endian and big-endian representations.
   2363 pub fn byteSwapAllElements(comptime Elem: type, slice: []Elem) void {
   2364     for (slice) |*elem| {
   2365         switch (@typeInfo(@TypeOf(elem.*))) {
   2366             .@"struct", .@"union", .array => byteSwapAllFields(@TypeOf(elem.*), elem),
   2367             .@"enum" => {
   2368                 elem.* = @enumFromInt(@byteSwap(@intFromEnum(elem.*)));
   2369             },
   2370             .bool => {},
   2371             .float => |float_info| {
   2372                 elem.* = @bitCast(@byteSwap(@as(std.meta.Int(.unsigned, float_info.bits), @bitCast(elem.*))));
   2373             },
   2374             else => {
   2375                 elem.* = @byteSwap(elem.*);
   2376             },
   2377         }
   2378     }
   2379 }
   2380 
   2381 /// Returns an iterator that iterates over the slices of `buffer` that are not
   2382 /// any of the items in `delimiters`.
   2383 ///
   2384 /// `tokenizeAny(u8, "   abc|def ||  ghi  ", " |")` will return slices
   2385 /// for "abc", "def", "ghi", null, in that order.
   2386 ///
   2387 /// If `buffer` is empty, the iterator will return null.
   2388 /// If none of `delimiters` exist in buffer,
   2389 /// the iterator will return `buffer`, null, in that order.
   2390 ///
   2391 /// See also: `tokenizeSequence`, `tokenizeScalar`,
   2392 ///           `splitSequence`,`splitAny`, `splitScalar`,
   2393 ///           `splitBackwardsSequence`, `splitBackwardsAny`, and `splitBackwardsScalar`
   2394 pub fn tokenizeAny(comptime T: type, buffer: []const T, delimiters: []const T) TokenIterator(T, .any) {
   2395     return .{
   2396         .index = 0,
   2397         .buffer = buffer,
   2398         .delimiter = delimiters,
   2399     };
   2400 }
   2401 
   2402 /// Returns an iterator that iterates over the slices of `buffer` that are not
   2403 /// the sequence in `delimiter`.
   2404 ///
   2405 /// `tokenizeSequence(u8, "<>abc><def<><>ghi", "<>")` will return slices
   2406 /// for "abc><def", "ghi", null, in that order.
   2407 ///
   2408 /// If `buffer` is empty, the iterator will return null.
   2409 /// If `delimiter` does not exist in buffer,
   2410 /// the iterator will return `buffer`, null, in that order.
   2411 /// The delimiter length must not be zero.
   2412 ///
   2413 /// See also: `tokenizeAny`, `tokenizeScalar`,
   2414 ///           `splitSequence`,`splitAny`, and `splitScalar`
   2415 ///           `splitBackwardsSequence`, `splitBackwardsAny`, and `splitBackwardsScalar`
   2416 pub fn tokenizeSequence(comptime T: type, buffer: []const T, delimiter: []const T) TokenIterator(T, .sequence) {
   2417     assert(delimiter.len != 0);
   2418     return .{
   2419         .index = 0,
   2420         .buffer = buffer,
   2421         .delimiter = delimiter,
   2422     };
   2423 }
   2424 
   2425 /// Returns an iterator that iterates over the slices of `buffer` that are not
   2426 /// `delimiter`.
   2427 ///
   2428 /// `tokenizeScalar(u8, "   abc def     ghi  ", ' ')` will return slices
   2429 /// for "abc", "def", "ghi", null, in that order.
   2430 ///
   2431 /// If `buffer` is empty, the iterator will return null.
   2432 /// If `delimiter` does not exist in buffer,
   2433 /// the iterator will return `buffer`, null, in that order.
   2434 ///
   2435 /// See also: `tokenizeAny`, `tokenizeSequence`,
   2436 ///           `splitSequence`,`splitAny`, and `splitScalar`
   2437 ///           `splitBackwardsSequence`, `splitBackwardsAny`, and `splitBackwardsScalar`
   2438 pub fn tokenizeScalar(comptime T: type, buffer: []const T, delimiter: T) TokenIterator(T, .scalar) {
   2439     return .{
   2440         .index = 0,
   2441         .buffer = buffer,
   2442         .delimiter = delimiter,
   2443     };
   2444 }
   2445 
   2446 test tokenizeScalar {
   2447     var it = tokenizeScalar(u8, "   abc def   ghi  ", ' ');
   2448     try testing.expect(eql(u8, it.next().?, "abc"));
   2449     try testing.expect(eql(u8, it.peek().?, "def"));
   2450     try testing.expect(eql(u8, it.next().?, "def"));
   2451     try testing.expect(eql(u8, it.next().?, "ghi"));
   2452     try testing.expect(it.next() == null);
   2453 
   2454     it = tokenizeScalar(u8, "..\\bob", '\\');
   2455     try testing.expect(eql(u8, it.next().?, ".."));
   2456     try testing.expect(eql(u8, "..", "..\\bob"[0..it.index]));
   2457     try testing.expect(eql(u8, it.next().?, "bob"));
   2458     try testing.expect(it.next() == null);
   2459 
   2460     it = tokenizeScalar(u8, "//a/b", '/');
   2461     try testing.expect(eql(u8, it.next().?, "a"));
   2462     try testing.expect(eql(u8, it.next().?, "b"));
   2463     try testing.expect(eql(u8, "//a/b", "//a/b"[0..it.index]));
   2464     try testing.expect(it.next() == null);
   2465 
   2466     it = tokenizeScalar(u8, "|", '|');
   2467     try testing.expect(it.next() == null);
   2468     try testing.expect(it.peek() == null);
   2469 
   2470     it = tokenizeScalar(u8, "", '|');
   2471     try testing.expect(it.next() == null);
   2472     try testing.expect(it.peek() == null);
   2473 
   2474     it = tokenizeScalar(u8, "hello", ' ');
   2475     try testing.expect(eql(u8, it.next().?, "hello"));
   2476     try testing.expect(it.next() == null);
   2477 
   2478     var it16 = tokenizeScalar(
   2479         u16,
   2480         std.unicode.utf8ToUtf16LeStringLiteral("hello"),
   2481         ' ',
   2482     );
   2483     try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("hello")));
   2484     try testing.expect(it16.next() == null);
   2485 }
   2486 
   2487 test tokenizeAny {
   2488     var it = tokenizeAny(u8, "a|b,c/d e", " /,|");
   2489     try testing.expect(eql(u8, it.next().?, "a"));
   2490     try testing.expect(eql(u8, it.peek().?, "b"));
   2491     try testing.expect(eql(u8, it.next().?, "b"));
   2492     try testing.expect(eql(u8, it.next().?, "c"));
   2493     try testing.expect(eql(u8, it.next().?, "d"));
   2494     try testing.expect(eql(u8, it.next().?, "e"));
   2495     try testing.expect(it.next() == null);
   2496     try testing.expect(it.peek() == null);
   2497 
   2498     it = tokenizeAny(u8, "hello", "");
   2499     try testing.expect(eql(u8, it.next().?, "hello"));
   2500     try testing.expect(it.next() == null);
   2501 
   2502     var it16 = tokenizeAny(
   2503         u16,
   2504         std.unicode.utf8ToUtf16LeStringLiteral("a|b,c/d e"),
   2505         std.unicode.utf8ToUtf16LeStringLiteral(" /,|"),
   2506     );
   2507     try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("a")));
   2508     try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("b")));
   2509     try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("c")));
   2510     try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("d")));
   2511     try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("e")));
   2512     try testing.expect(it16.next() == null);
   2513 }
   2514 
   2515 test tokenizeSequence {
   2516     var it = tokenizeSequence(u8, "a<>b<><>c><>d><", "<>");
   2517     try testing.expectEqualStrings("a", it.next().?);
   2518     try testing.expectEqualStrings("b", it.peek().?);
   2519     try testing.expectEqualStrings("b", it.next().?);
   2520     try testing.expectEqualStrings("c>", it.next().?);
   2521     try testing.expectEqualStrings("d><", it.next().?);
   2522     try testing.expect(it.next() == null);
   2523     try testing.expect(it.peek() == null);
   2524 
   2525     var it16 = tokenizeSequence(
   2526         u16,
   2527         std.unicode.utf8ToUtf16LeStringLiteral("a<>b<><>c><>d><"),
   2528         std.unicode.utf8ToUtf16LeStringLiteral("<>"),
   2529     );
   2530     try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("a")));
   2531     try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("b")));
   2532     try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("c>")));
   2533     try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("d><")));
   2534     try testing.expect(it16.next() == null);
   2535 }
   2536 
   2537 test "tokenize (reset)" {
   2538     {
   2539         var it = tokenizeAny(u8, "   abc def   ghi  ", " ");
   2540         try testing.expect(eql(u8, it.next().?, "abc"));
   2541         try testing.expect(eql(u8, it.next().?, "def"));
   2542         try testing.expect(eql(u8, it.next().?, "ghi"));
   2543 
   2544         it.reset();
   2545 
   2546         try testing.expect(eql(u8, it.next().?, "abc"));
   2547         try testing.expect(eql(u8, it.next().?, "def"));
   2548         try testing.expect(eql(u8, it.next().?, "ghi"));
   2549         try testing.expect(it.next() == null);
   2550     }
   2551     {
   2552         var it = tokenizeSequence(u8, "<><>abc<>def<><>ghi<>", "<>");
   2553         try testing.expect(eql(u8, it.next().?, "abc"));
   2554         try testing.expect(eql(u8, it.next().?, "def"));
   2555         try testing.expect(eql(u8, it.next().?, "ghi"));
   2556 
   2557         it.reset();
   2558 
   2559         try testing.expect(eql(u8, it.next().?, "abc"));
   2560         try testing.expect(eql(u8, it.next().?, "def"));
   2561         try testing.expect(eql(u8, it.next().?, "ghi"));
   2562         try testing.expect(it.next() == null);
   2563     }
   2564     {
   2565         var it = tokenizeScalar(u8, "   abc def   ghi  ", ' ');
   2566         try testing.expect(eql(u8, it.next().?, "abc"));
   2567         try testing.expect(eql(u8, it.next().?, "def"));
   2568         try testing.expect(eql(u8, it.next().?, "ghi"));
   2569 
   2570         it.reset();
   2571 
   2572         try testing.expect(eql(u8, it.next().?, "abc"));
   2573         try testing.expect(eql(u8, it.next().?, "def"));
   2574         try testing.expect(eql(u8, it.next().?, "ghi"));
   2575         try testing.expect(it.next() == null);
   2576     }
   2577 }
   2578 
   2579 /// Returns an iterator that iterates over the slices of `buffer` that
   2580 /// are separated by the byte sequence in `delimiter`.
   2581 ///
   2582 /// `splitSequence(u8, "abc||def||||ghi", "||")` will return slices
   2583 /// for "abc", "def", "", "ghi", null, in that order.
   2584 ///
   2585 /// If `delimiter` does not exist in buffer,
   2586 /// the iterator will return `buffer`, null, in that order.
   2587 /// The delimiter length must not be zero.
   2588 ///
   2589 /// See also: `splitAny`, `splitScalar`, `splitBackwardsSequence`,
   2590 ///           `splitBackwardsAny`,`splitBackwardsScalar`,
   2591 ///           `tokenizeAny`, `tokenizeSequence`, and `tokenizeScalar`.
   2592 pub fn splitSequence(comptime T: type, buffer: []const T, delimiter: []const T) SplitIterator(T, .sequence) {
   2593     assert(delimiter.len != 0);
   2594     return .{
   2595         .index = 0,
   2596         .buffer = buffer,
   2597         .delimiter = delimiter,
   2598     };
   2599 }
   2600 
   2601 /// Returns an iterator that iterates over the slices of `buffer` that
   2602 /// are separated by any item in `delimiters`.
   2603 ///
   2604 /// `splitAny(u8, "abc,def||ghi", "|,")` will return slices
   2605 /// for "abc", "def", "", "ghi", null, in that order.
   2606 ///
   2607 /// If none of `delimiters` exist in buffer,
   2608 /// the iterator will return `buffer`, null, in that order.
   2609 ///
   2610 /// See also: `splitSequence`, `splitScalar`, `splitBackwardsSequence`,
   2611 ///           `splitBackwardsAny`,`splitBackwardsScalar`,
   2612 ///           `tokenizeAny`, `tokenizeSequence`, and `tokenizeScalar`.
   2613 pub fn splitAny(comptime T: type, buffer: []const T, delimiters: []const T) SplitIterator(T, .any) {
   2614     return .{
   2615         .index = 0,
   2616         .buffer = buffer,
   2617         .delimiter = delimiters,
   2618     };
   2619 }
   2620 
   2621 /// Returns an iterator that iterates over the slices of `buffer` that
   2622 /// are separated by `delimiter`.
   2623 ///
   2624 /// `splitScalar(u8, "abc|def||ghi", '|')` will return slices
   2625 /// for "abc", "def", "", "ghi", null, in that order.
   2626 ///
   2627 /// If `delimiter` does not exist in buffer,
   2628 /// the iterator will return `buffer`, null, in that order.
   2629 ///
   2630 /// See also: `splitSequence`, `splitAny`, `splitBackwardsSequence`,
   2631 ///           `splitBackwardsAny`,`splitBackwardsScalar`,
   2632 ///           `tokenizeAny`, `tokenizeSequence`, and `tokenizeScalar`.
   2633 pub fn splitScalar(comptime T: type, buffer: []const T, delimiter: T) SplitIterator(T, .scalar) {
   2634     return .{
   2635         .index = 0,
   2636         .buffer = buffer,
   2637         .delimiter = delimiter,
   2638     };
   2639 }
   2640 
   2641 test splitScalar {
   2642     var it = splitScalar(u8, "abc|def||ghi", '|');
   2643     try testing.expectEqualSlices(u8, it.rest(), "abc|def||ghi");
   2644     try testing.expectEqualSlices(u8, it.first(), "abc");
   2645 
   2646     try testing.expectEqualSlices(u8, it.rest(), "def||ghi");
   2647     try testing.expectEqualSlices(u8, it.peek().?, "def");
   2648     try testing.expectEqualSlices(u8, it.next().?, "def");
   2649 
   2650     try testing.expectEqualSlices(u8, it.rest(), "|ghi");
   2651     try testing.expectEqualSlices(u8, it.next().?, "");
   2652 
   2653     try testing.expectEqualSlices(u8, it.rest(), "ghi");
   2654     try testing.expectEqualSlices(u8, it.peek().?, "ghi");
   2655     try testing.expectEqualSlices(u8, it.next().?, "ghi");
   2656 
   2657     try testing.expectEqualSlices(u8, it.rest(), "");
   2658     try testing.expect(it.peek() == null);
   2659     try testing.expect(it.next() == null);
   2660 
   2661     it = splitScalar(u8, "", '|');
   2662     try testing.expectEqualSlices(u8, it.first(), "");
   2663     try testing.expect(it.next() == null);
   2664 
   2665     it = splitScalar(u8, "|", '|');
   2666     try testing.expectEqualSlices(u8, it.first(), "");
   2667     try testing.expectEqualSlices(u8, it.next().?, "");
   2668     try testing.expect(it.peek() == null);
   2669     try testing.expect(it.next() == null);
   2670 
   2671     it = splitScalar(u8, "hello", ' ');
   2672     try testing.expectEqualSlices(u8, it.first(), "hello");
   2673     try testing.expect(it.next() == null);
   2674 
   2675     var it16 = splitScalar(
   2676         u16,
   2677         std.unicode.utf8ToUtf16LeStringLiteral("hello"),
   2678         ' ',
   2679     );
   2680     try testing.expectEqualSlices(u16, it16.first(), std.unicode.utf8ToUtf16LeStringLiteral("hello"));
   2681     try testing.expect(it16.next() == null);
   2682 }
   2683 
   2684 test splitSequence {
   2685     var it = splitSequence(u8, "a, b ,, c, d, e", ", ");
   2686     try testing.expectEqualSlices(u8, it.first(), "a");
   2687     try testing.expectEqualSlices(u8, it.rest(), "b ,, c, d, e");
   2688     try testing.expectEqualSlices(u8, it.next().?, "b ,");
   2689     try testing.expectEqualSlices(u8, it.next().?, "c");
   2690     try testing.expectEqualSlices(u8, it.next().?, "d");
   2691     try testing.expectEqualSlices(u8, it.next().?, "e");
   2692     try testing.expect(it.next() == null);
   2693 
   2694     var it16 = splitSequence(
   2695         u16,
   2696         std.unicode.utf8ToUtf16LeStringLiteral("a, b ,, c, d, e"),
   2697         std.unicode.utf8ToUtf16LeStringLiteral(", "),
   2698     );
   2699     try testing.expectEqualSlices(u16, it16.first(), std.unicode.utf8ToUtf16LeStringLiteral("a"));
   2700     try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("b ,"));
   2701     try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("c"));
   2702     try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("d"));
   2703     try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("e"));
   2704     try testing.expect(it16.next() == null);
   2705 }
   2706 
   2707 test splitAny {
   2708     var it = splitAny(u8, "a,b, c d e", ", ");
   2709     try testing.expectEqualSlices(u8, it.first(), "a");
   2710     try testing.expectEqualSlices(u8, it.rest(), "b, c d e");
   2711     try testing.expectEqualSlices(u8, it.next().?, "b");
   2712     try testing.expectEqualSlices(u8, it.next().?, "");
   2713     try testing.expectEqualSlices(u8, it.next().?, "c");
   2714     try testing.expectEqualSlices(u8, it.next().?, "d");
   2715     try testing.expectEqualSlices(u8, it.next().?, "e");
   2716     try testing.expect(it.next() == null);
   2717 
   2718     it = splitAny(u8, "hello", "");
   2719     try testing.expect(eql(u8, it.next().?, "hello"));
   2720     try testing.expect(it.next() == null);
   2721 
   2722     var it16 = splitAny(
   2723         u16,
   2724         std.unicode.utf8ToUtf16LeStringLiteral("a,b, c d e"),
   2725         std.unicode.utf8ToUtf16LeStringLiteral(", "),
   2726     );
   2727     try testing.expectEqualSlices(u16, it16.first(), std.unicode.utf8ToUtf16LeStringLiteral("a"));
   2728     try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("b"));
   2729     try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral(""));
   2730     try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("c"));
   2731     try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("d"));
   2732     try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("e"));
   2733     try testing.expect(it16.next() == null);
   2734 }
   2735 
   2736 test "split (reset)" {
   2737     {
   2738         var it = splitSequence(u8, "abc def ghi", " ");
   2739         try testing.expect(eql(u8, it.first(), "abc"));
   2740         try testing.expect(eql(u8, it.next().?, "def"));
   2741         try testing.expect(eql(u8, it.next().?, "ghi"));
   2742 
   2743         it.reset();
   2744 
   2745         try testing.expect(eql(u8, it.first(), "abc"));
   2746         try testing.expect(eql(u8, it.next().?, "def"));
   2747         try testing.expect(eql(u8, it.next().?, "ghi"));
   2748         try testing.expect(it.next() == null);
   2749     }
   2750     {
   2751         var it = splitAny(u8, "abc def,ghi", " ,");
   2752         try testing.expect(eql(u8, it.first(), "abc"));
   2753         try testing.expect(eql(u8, it.next().?, "def"));
   2754         try testing.expect(eql(u8, it.next().?, "ghi"));
   2755 
   2756         it.reset();
   2757 
   2758         try testing.expect(eql(u8, it.first(), "abc"));
   2759         try testing.expect(eql(u8, it.next().?, "def"));
   2760         try testing.expect(eql(u8, it.next().?, "ghi"));
   2761         try testing.expect(it.next() == null);
   2762     }
   2763     {
   2764         var it = splitScalar(u8, "abc def ghi", ' ');
   2765         try testing.expect(eql(u8, it.first(), "abc"));
   2766         try testing.expect(eql(u8, it.next().?, "def"));
   2767         try testing.expect(eql(u8, it.next().?, "ghi"));
   2768 
   2769         it.reset();
   2770 
   2771         try testing.expect(eql(u8, it.first(), "abc"));
   2772         try testing.expect(eql(u8, it.next().?, "def"));
   2773         try testing.expect(eql(u8, it.next().?, "ghi"));
   2774         try testing.expect(it.next() == null);
   2775     }
   2776 }
   2777 
   2778 /// Returns an iterator that iterates backwards over the slices of `buffer` that
   2779 /// are separated by the sequence in `delimiter`.
   2780 ///
   2781 /// `splitBackwardsSequence(u8, "abc||def||||ghi", "||")` will return slices
   2782 /// for "ghi", "", "def", "abc", null, in that order.
   2783 ///
   2784 /// If `delimiter` does not exist in buffer,
   2785 /// the iterator will return `buffer`, null, in that order.
   2786 /// The delimiter length must not be zero.
   2787 ///
   2788 /// See also: `splitBackwardsAny`, `splitBackwardsScalar`,
   2789 ///           `splitSequence`, `splitAny`,`splitScalar`,
   2790 ///           `tokenizeAny`, `tokenizeSequence`, and `tokenizeScalar`.
   2791 pub fn splitBackwardsSequence(comptime T: type, buffer: []const T, delimiter: []const T) SplitBackwardsIterator(T, .sequence) {
   2792     assert(delimiter.len != 0);
   2793     return .{
   2794         .index = buffer.len,
   2795         .buffer = buffer,
   2796         .delimiter = delimiter,
   2797     };
   2798 }
   2799 
   2800 /// Returns an iterator that iterates backwards over the slices of `buffer` that
   2801 /// are separated by any item in `delimiters`.
   2802 ///
   2803 /// `splitBackwardsAny(u8, "abc,def||ghi", "|,")` will return slices
   2804 /// for "ghi", "", "def", "abc", null, in that order.
   2805 ///
   2806 /// If none of `delimiters` exist in buffer,
   2807 /// the iterator will return `buffer`, null, in that order.
   2808 ///
   2809 /// See also: `splitBackwardsSequence`, `splitBackwardsScalar`,
   2810 ///           `splitSequence`, `splitAny`,`splitScalar`,
   2811 ///           `tokenizeAny`, `tokenizeSequence`, and `tokenizeScalar`.
   2812 pub fn splitBackwardsAny(comptime T: type, buffer: []const T, delimiters: []const T) SplitBackwardsIterator(T, .any) {
   2813     return .{
   2814         .index = buffer.len,
   2815         .buffer = buffer,
   2816         .delimiter = delimiters,
   2817     };
   2818 }
   2819 
   2820 /// Returns an iterator that iterates backwards over the slices of `buffer` that
   2821 /// are separated by `delimiter`.
   2822 ///
   2823 /// `splitBackwardsScalar(u8, "abc|def||ghi", '|')` will return slices
   2824 /// for "ghi", "", "def", "abc", null, in that order.
   2825 ///
   2826 /// If `delimiter` does not exist in buffer,
   2827 /// the iterator will return `buffer`, null, in that order.
   2828 ///
   2829 /// See also: `splitBackwardsSequence`, `splitBackwardsAny`,
   2830 ///           `splitSequence`, `splitAny`,`splitScalar`,
   2831 ///           `tokenizeAny`, `tokenizeSequence`, and `tokenizeScalar`.
   2832 pub fn splitBackwardsScalar(comptime T: type, buffer: []const T, delimiter: T) SplitBackwardsIterator(T, .scalar) {
   2833     return .{
   2834         .index = buffer.len,
   2835         .buffer = buffer,
   2836         .delimiter = delimiter,
   2837     };
   2838 }
   2839 
   2840 test splitBackwardsScalar {
   2841     var it = splitBackwardsScalar(u8, "abc|def||ghi", '|');
   2842     try testing.expectEqualSlices(u8, it.rest(), "abc|def||ghi");
   2843     try testing.expectEqualSlices(u8, it.first(), "ghi");
   2844 
   2845     try testing.expectEqualSlices(u8, it.rest(), "abc|def|");
   2846     try testing.expectEqualSlices(u8, it.next().?, "");
   2847 
   2848     try testing.expectEqualSlices(u8, it.rest(), "abc|def");
   2849     try testing.expectEqualSlices(u8, it.next().?, "def");
   2850 
   2851     try testing.expectEqualSlices(u8, it.rest(), "abc");
   2852     try testing.expectEqualSlices(u8, it.next().?, "abc");
   2853 
   2854     try testing.expectEqualSlices(u8, it.rest(), "");
   2855     try testing.expect(it.next() == null);
   2856 
   2857     it = splitBackwardsScalar(u8, "", '|');
   2858     try testing.expectEqualSlices(u8, it.first(), "");
   2859     try testing.expect(it.next() == null);
   2860 
   2861     it = splitBackwardsScalar(u8, "|", '|');
   2862     try testing.expectEqualSlices(u8, it.first(), "");
   2863     try testing.expectEqualSlices(u8, it.next().?, "");
   2864     try testing.expect(it.next() == null);
   2865 
   2866     it = splitBackwardsScalar(u8, "hello", ' ');
   2867     try testing.expectEqualSlices(u8, it.first(), "hello");
   2868     try testing.expect(it.next() == null);
   2869 
   2870     var it16 = splitBackwardsScalar(
   2871         u16,
   2872         std.unicode.utf8ToUtf16LeStringLiteral("hello"),
   2873         ' ',
   2874     );
   2875     try testing.expectEqualSlices(u16, it16.first(), std.unicode.utf8ToUtf16LeStringLiteral("hello"));
   2876     try testing.expect(it16.next() == null);
   2877 }
   2878 
   2879 test splitBackwardsSequence {
   2880     var it = splitBackwardsSequence(u8, "a, b ,, c, d, e", ", ");
   2881     try testing.expectEqualSlices(u8, it.rest(), "a, b ,, c, d, e");
   2882     try testing.expectEqualSlices(u8, it.first(), "e");
   2883 
   2884     try testing.expectEqualSlices(u8, it.rest(), "a, b ,, c, d");
   2885     try testing.expectEqualSlices(u8, it.next().?, "d");
   2886 
   2887     try testing.expectEqualSlices(u8, it.rest(), "a, b ,, c");
   2888     try testing.expectEqualSlices(u8, it.next().?, "c");
   2889 
   2890     try testing.expectEqualSlices(u8, it.rest(), "a, b ,");
   2891     try testing.expectEqualSlices(u8, it.next().?, "b ,");
   2892 
   2893     try testing.expectEqualSlices(u8, it.rest(), "a");
   2894     try testing.expectEqualSlices(u8, it.next().?, "a");
   2895 
   2896     try testing.expectEqualSlices(u8, it.rest(), "");
   2897     try testing.expect(it.next() == null);
   2898 
   2899     var it16 = splitBackwardsSequence(
   2900         u16,
   2901         std.unicode.utf8ToUtf16LeStringLiteral("a, b ,, c, d, e"),
   2902         std.unicode.utf8ToUtf16LeStringLiteral(", "),
   2903     );
   2904     try testing.expectEqualSlices(u16, it16.first(), std.unicode.utf8ToUtf16LeStringLiteral("e"));
   2905     try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("d"));
   2906     try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("c"));
   2907     try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("b ,"));
   2908     try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("a"));
   2909     try testing.expect(it16.next() == null);
   2910 }
   2911 
   2912 test splitBackwardsAny {
   2913     var it = splitBackwardsAny(u8, "a,b, c d e", ", ");
   2914     try testing.expectEqualSlices(u8, it.rest(), "a,b, c d e");
   2915     try testing.expectEqualSlices(u8, it.first(), "e");
   2916 
   2917     try testing.expectEqualSlices(u8, it.rest(), "a,b, c d");
   2918     try testing.expectEqualSlices(u8, it.next().?, "d");
   2919 
   2920     try testing.expectEqualSlices(u8, it.rest(), "a,b, c");
   2921     try testing.expectEqualSlices(u8, it.next().?, "c");
   2922 
   2923     try testing.expectEqualSlices(u8, it.rest(), "a,b,");
   2924     try testing.expectEqualSlices(u8, it.next().?, "");
   2925 
   2926     try testing.expectEqualSlices(u8, it.rest(), "a,b");
   2927     try testing.expectEqualSlices(u8, it.next().?, "b");
   2928 
   2929     try testing.expectEqualSlices(u8, it.rest(), "a");
   2930     try testing.expectEqualSlices(u8, it.next().?, "a");
   2931 
   2932     try testing.expectEqualSlices(u8, it.rest(), "");
   2933     try testing.expect(it.next() == null);
   2934 
   2935     var it16 = splitBackwardsAny(
   2936         u16,
   2937         std.unicode.utf8ToUtf16LeStringLiteral("a,b, c d e"),
   2938         std.unicode.utf8ToUtf16LeStringLiteral(", "),
   2939     );
   2940     try testing.expectEqualSlices(u16, it16.first(), std.unicode.utf8ToUtf16LeStringLiteral("e"));
   2941     try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("d"));
   2942     try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("c"));
   2943     try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral(""));
   2944     try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("b"));
   2945     try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("a"));
   2946     try testing.expect(it16.next() == null);
   2947 }
   2948 
   2949 test "splitBackwards (reset)" {
   2950     {
   2951         var it = splitBackwardsSequence(u8, "abc def ghi", " ");
   2952         try testing.expect(eql(u8, it.first(), "ghi"));
   2953         try testing.expect(eql(u8, it.next().?, "def"));
   2954         try testing.expect(eql(u8, it.next().?, "abc"));
   2955 
   2956         it.reset();
   2957 
   2958         try testing.expect(eql(u8, it.first(), "ghi"));
   2959         try testing.expect(eql(u8, it.next().?, "def"));
   2960         try testing.expect(eql(u8, it.next().?, "abc"));
   2961         try testing.expect(it.next() == null);
   2962     }
   2963     {
   2964         var it = splitBackwardsAny(u8, "abc def,ghi", " ,");
   2965         try testing.expect(eql(u8, it.first(), "ghi"));
   2966         try testing.expect(eql(u8, it.next().?, "def"));
   2967         try testing.expect(eql(u8, it.next().?, "abc"));
   2968 
   2969         it.reset();
   2970 
   2971         try testing.expect(eql(u8, it.first(), "ghi"));
   2972         try testing.expect(eql(u8, it.next().?, "def"));
   2973         try testing.expect(eql(u8, it.next().?, "abc"));
   2974         try testing.expect(it.next() == null);
   2975     }
   2976     {
   2977         var it = splitBackwardsScalar(u8, "abc def ghi", ' ');
   2978         try testing.expect(eql(u8, it.first(), "ghi"));
   2979         try testing.expect(eql(u8, it.next().?, "def"));
   2980         try testing.expect(eql(u8, it.next().?, "abc"));
   2981 
   2982         it.reset();
   2983 
   2984         try testing.expect(eql(u8, it.first(), "ghi"));
   2985         try testing.expect(eql(u8, it.next().?, "def"));
   2986         try testing.expect(eql(u8, it.next().?, "abc"));
   2987         try testing.expect(it.next() == null);
   2988     }
   2989 }
   2990 
   2991 /// Returns an iterator with a sliding window of slices for `buffer`.
   2992 /// The sliding window has length `size` and on every iteration moves
   2993 /// forward by `advance`.
   2994 ///
   2995 /// Extract data for moving average with:
   2996 /// `window(u8, "abcdefg", 3, 1)` will return slices
   2997 /// "abc", "bcd", "cde", "def", "efg", null, in that order.
   2998 ///
   2999 /// Chunk or split every N items with:
   3000 /// `window(u8, "abcdefg", 3, 3)` will return slices
   3001 /// "abc", "def", "g", null, in that order.
   3002 ///
   3003 /// Pick every even index with:
   3004 /// `window(u8, "abcdefg", 1, 2)` will return slices
   3005 /// "a", "c", "e", "g" null, in that order.
   3006 ///
   3007 /// The `size` and `advance` must be not be zero.
   3008 pub fn window(comptime T: type, buffer: []const T, size: usize, advance: usize) WindowIterator(T) {
   3009     assert(size != 0);
   3010     assert(advance != 0);
   3011     return .{
   3012         .index = if (buffer.len > 0) 0 else null,
   3013         .buffer = buffer,
   3014         .size = size,
   3015         .advance = advance,
   3016     };
   3017 }
   3018 
   3019 test window {
   3020     {
   3021         // moving average size 3
   3022         var it = window(u8, "abcdefg", 3, 1);
   3023         try testing.expectEqualSlices(u8, "abc", it.next().?);
   3024         try testing.expectEqualSlices(u8, "bcd", it.next().?);
   3025         try testing.expectEqualSlices(u8, "cde", it.next().?);
   3026         try testing.expectEqualSlices(u8, "def", it.next().?);
   3027         try testing.expectEqualSlices(u8, "efg", it.next().?);
   3028         try testing.expectEqual(null, it.next());
   3029 
   3030         // multibyte
   3031         var it16 = window(u16, std.unicode.utf8ToUtf16LeStringLiteral("abcdefg"), 3, 1);
   3032         try testing.expectEqualSlices(u16, std.unicode.utf8ToUtf16LeStringLiteral("abc"), it16.next().?);
   3033         try testing.expectEqualSlices(u16, std.unicode.utf8ToUtf16LeStringLiteral("bcd"), it16.next().?);
   3034         try testing.expectEqualSlices(u16, std.unicode.utf8ToUtf16LeStringLiteral("cde"), it16.next().?);
   3035         try testing.expectEqualSlices(u16, std.unicode.utf8ToUtf16LeStringLiteral("def"), it16.next().?);
   3036         try testing.expectEqualSlices(u16, std.unicode.utf8ToUtf16LeStringLiteral("efg"), it16.next().?);
   3037         try testing.expectEqual(it16.next(), null);
   3038     }
   3039 
   3040     {
   3041         // chunk/split every 3
   3042         var it = window(u8, "abcdefg", 3, 3);
   3043         try testing.expectEqualSlices(u8, "abc", it.next().?);
   3044         try testing.expectEqualSlices(u8, "def", it.next().?);
   3045         try testing.expectEqualSlices(u8, "g", it.next().?);
   3046         try testing.expectEqual(null, it.next());
   3047     }
   3048 
   3049     {
   3050         // pick even
   3051         var it = window(u8, "abcdefg", 1, 2);
   3052         try testing.expectEqualSlices(u8, "a", it.next().?);
   3053         try testing.expectEqualSlices(u8, "c", it.next().?);
   3054         try testing.expectEqualSlices(u8, "e", it.next().?);
   3055         try testing.expectEqualSlices(u8, "g", it.next().?);
   3056         try testing.expectEqual(null, it.next());
   3057 
   3058         it = window(u8, "abcdefgh", 1, 2);
   3059         try testing.expectEqualSlices(u8, "a", it.next().?);
   3060         try testing.expectEqualSlices(u8, "c", it.next().?);
   3061         try testing.expectEqualSlices(u8, "e", it.next().?);
   3062         try testing.expectEqualSlices(u8, "g", it.next().?);
   3063         try testing.expectEqual(null, it.next());
   3064     }
   3065 
   3066     {
   3067         // empty
   3068         var it = window(u8, "", 1, 1);
   3069         try testing.expectEqual(null, it.next());
   3070 
   3071         it = window(u8, "", 10, 1);
   3072         try testing.expectEqual(null, it.next());
   3073 
   3074         it = window(u8, "", 1, 10);
   3075         try testing.expectEqual(null, it.next());
   3076 
   3077         it = window(u8, "", 10, 10);
   3078         try testing.expectEqual(null, it.next());
   3079     }
   3080 
   3081     {
   3082         // first
   3083         var it = window(u8, "abcdefg", 3, 3);
   3084         try testing.expectEqualSlices(u8, "abc", it.next().?);
   3085         it.reset();
   3086         try testing.expectEqualSlices(u8, "abc", it.next().?);
   3087     }
   3088 
   3089     {
   3090         // reset
   3091         var it = window(u8, "abcdefg", 3, 3);
   3092         try testing.expectEqualSlices(u8, "abc", it.next().?);
   3093         try testing.expectEqualSlices(u8, "def", it.next().?);
   3094         try testing.expectEqualSlices(u8, "g", it.next().?);
   3095         try testing.expectEqual(null, it.next());
   3096 
   3097         it.reset();
   3098         try testing.expectEqualSlices(u8, "abc", it.next().?);
   3099         try testing.expectEqualSlices(u8, "def", it.next().?);
   3100         try testing.expectEqualSlices(u8, "g", it.next().?);
   3101         try testing.expectEqual(null, it.next());
   3102     }
   3103 
   3104     {
   3105         // size > buffer.len
   3106         var it = window(u8, "abcdefg", 100, 1);
   3107         try testing.expectEqualSlices(u8, "abcdefg", it.next().?);
   3108         try testing.expectEqual(null, it.next());
   3109     }
   3110 
   3111     {
   3112         // advance >= buffer.len
   3113         var it = window(u8, "abcdefg", 1, 7);
   3114         try testing.expectEqualSlices(u8, "a", it.next().?);
   3115         try testing.expectEqual(null, it.next());
   3116     }
   3117 
   3118     {
   3119         // advance == 1 and size == 1
   3120         var it = window(u8, "abcdefg", 1, 1);
   3121         try testing.expectEqualSlices(u8, "a", it.next().?);
   3122         try testing.expectEqualSlices(u8, "b", it.next().?);
   3123         try testing.expectEqualSlices(u8, "c", it.next().?);
   3124         try testing.expectEqualSlices(u8, "d", it.next().?);
   3125         try testing.expectEqualSlices(u8, "e", it.next().?);
   3126         try testing.expectEqualSlices(u8, "f", it.next().?);
   3127         try testing.expectEqualSlices(u8, "g", it.next().?);
   3128         try testing.expectEqual(null, it.next());
   3129     }
   3130 
   3131     {
   3132         // advance > size
   3133         var it = window(u8, "abcdefg", 2, 3);
   3134         try testing.expectEqualSlices(u8, "ab", it.next().?);
   3135         try testing.expectEqualSlices(u8, "de", it.next().?);
   3136         try testing.expectEqualSlices(u8, "g", it.next().?);
   3137         try testing.expectEqual(null, it.next());
   3138     }
   3139 }
   3140 
   3141 /// Iterator type returned by the `window` function for sliding window operations.
   3142 pub fn WindowIterator(comptime T: type) type {
   3143     return struct {
   3144         buffer: []const T,
   3145         index: ?usize,
   3146         size: usize,
   3147         advance: usize,
   3148 
   3149         const Self = @This();
   3150 
   3151         /// Returns a slice of the next window, or null if window is at end.
   3152         pub fn next(self: *Self) ?[]const T {
   3153             const start = self.index orelse return null;
   3154             const next_index = start + self.advance;
   3155             const end = if (start + self.size < self.buffer.len) blk: {
   3156                 self.index = if (next_index < self.buffer.len) next_index else null;
   3157                 break :blk start + self.size;
   3158             } else blk: {
   3159                 self.index = null;
   3160                 break :blk self.buffer.len;
   3161             };
   3162             return self.buffer[start..end];
   3163         }
   3164 
   3165         /// Resets the iterator to the initial window.
   3166         pub fn reset(self: *Self) void {
   3167             self.index = 0;
   3168         }
   3169     };
   3170 }
   3171 
   3172 /// Returns true if haystack starts with needle.
   3173 /// Time complexity: O(needle.len)
   3174 pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
   3175     return if (needle.len > haystack.len) false else eql(T, haystack[0..needle.len], needle);
   3176 }
   3177 
   3178 test startsWith {
   3179     try testing.expect(startsWith(u8, "Bob", "Bo"));
   3180     try testing.expect(!startsWith(u8, "Needle in haystack", "haystack"));
   3181 }
   3182 
   3183 /// Returns true if haystack ends with needle.
   3184 /// Time complexity: O(needle.len)
   3185 pub fn endsWith(comptime T: type, haystack: []const T, needle: []const T) bool {
   3186     return if (needle.len > haystack.len) false else eql(T, haystack[haystack.len - needle.len ..], needle);
   3187 }
   3188 
   3189 test endsWith {
   3190     try testing.expect(endsWith(u8, "Needle in haystack", "haystack"));
   3191     try testing.expect(!endsWith(u8, "Bob", "Bo"));
   3192 }
   3193 
   3194 /// If `slice` starts with `prefix`, returns the rest of `slice` starting at `prefix.len`.
   3195 pub fn cutPrefix(comptime T: type, slice: []const T, prefix: []const T) ?[]const T {
   3196     return if (startsWith(T, slice, prefix)) slice[prefix.len..] else null;
   3197 }
   3198 
   3199 test cutPrefix {
   3200     try testing.expectEqualStrings("foo", cutPrefix(u8, "--example=foo", "--example=").?);
   3201     try testing.expectEqual(null, cutPrefix(u8, "--example=foo", "-example="));
   3202 }
   3203 
   3204 /// If `slice` ends with `suffix`, returns `slice` from beginning to start of `suffix`.
   3205 pub fn cutSuffix(comptime T: type, slice: []const T, suffix: []const T) ?[]const T {
   3206     return if (endsWith(T, slice, suffix)) slice[0 .. slice.len - suffix.len] else null;
   3207 }
   3208 
   3209 test cutSuffix {
   3210     try testing.expectEqualStrings("foo", cutSuffix(u8, "foobar", "bar").?);
   3211     try testing.expectEqual(null, cutSuffix(u8, "foobar", "baz"));
   3212 }
   3213 
   3214 /// Returns slice of `haystack` before and after first occurrence of `needle`,
   3215 /// or `null` if not found.
   3216 ///
   3217 /// See also:
   3218 /// * `cutScalar`
   3219 /// * `split`
   3220 /// * `tokenizeAny`
   3221 pub fn cut(comptime T: type, haystack: []const T, needle: []const T) ?struct { []const T, []const T } {
   3222     const index = find(T, haystack, needle) orelse return null;
   3223     return .{ haystack[0..index], haystack[index + needle.len ..] };
   3224 }
   3225 
   3226 test cut {
   3227     try testing.expectEqual(null, cut(u8, "a b c", "B"));
   3228     const before, const after = cut(u8, "a be c", "be") orelse return error.TestFailed;
   3229     try testing.expectEqualStrings("a ", before);
   3230     try testing.expectEqualStrings(" c", after);
   3231 }
   3232 
   3233 /// Returns slice of `haystack` before and after last occurrence of `needle`,
   3234 /// or `null` if not found.
   3235 ///
   3236 /// See also:
   3237 /// * `cut`
   3238 /// * `cutScalarLast`
   3239 pub fn cutLast(comptime T: type, haystack: []const T, needle: []const T) ?struct { []const T, []const T } {
   3240     const index = findLast(T, haystack, needle) orelse return null;
   3241     return .{ haystack[0..index], haystack[index + needle.len ..] };
   3242 }
   3243 
   3244 test cutLast {
   3245     try testing.expectEqual(null, cutLast(u8, "a b c", "B"));
   3246     const before, const after = cutLast(u8, "a be c be d", "be") orelse return error.TestFailed;
   3247     try testing.expectEqualStrings("a be c ", before);
   3248     try testing.expectEqualStrings(" d", after);
   3249 }
   3250 
   3251 /// Returns slice of `haystack` before and after first occurrence `needle`, or
   3252 /// `null` if not found.
   3253 ///
   3254 /// See also:
   3255 /// * `cut`
   3256 /// * `splitScalar`
   3257 /// * `tokenizeScalar`
   3258 pub fn cutScalar(comptime T: type, haystack: []const T, needle: T) ?struct { []const T, []const T } {
   3259     const index = findScalar(T, haystack, needle) orelse return null;
   3260     return .{ haystack[0..index], haystack[index + 1 ..] };
   3261 }
   3262 
   3263 test cutScalar {
   3264     try testing.expectEqual(null, cutScalar(u8, "a b c", 'B'));
   3265     const before, const after = cutScalar(u8, "a b c", 'b') orelse return error.TestFailed;
   3266     try testing.expectEqualStrings("a ", before);
   3267     try testing.expectEqualStrings(" c", after);
   3268 }
   3269 
   3270 /// Returns slice of `haystack` before and after last occurrence of `needle`,
   3271 /// or `null` if not found.
   3272 ///
   3273 /// See also:
   3274 /// * `cut`
   3275 /// * `splitScalar`
   3276 /// * `tokenizeScalar`
   3277 pub fn cutScalarLast(comptime T: type, haystack: []const T, needle: T) ?struct { []const T, []const T } {
   3278     const index = findScalarLast(T, haystack, needle) orelse return null;
   3279     return .{ haystack[0..index], haystack[index + 1 ..] };
   3280 }
   3281 
   3282 test cutScalarLast {
   3283     try testing.expectEqual(null, cutScalarLast(u8, "a b c", 'B'));
   3284     const before, const after = cutScalarLast(u8, "a b c b d", 'b') orelse return error.TestFailed;
   3285     try testing.expectEqualStrings("a b c ", before);
   3286     try testing.expectEqualStrings(" d", after);
   3287 }
   3288 
   3289 /// Delimiter type for tokenization and splitting operations.
   3290 pub const DelimiterType = enum { sequence, any, scalar };
   3291 
   3292 /// Iterator type for tokenization operations, skipping empty sequences and delimiter sequences.
   3293 pub fn TokenIterator(comptime T: type, comptime delimiter_type: DelimiterType) type {
   3294     return struct {
   3295         buffer: []const T,
   3296         delimiter: switch (delimiter_type) {
   3297             .sequence, .any => []const T,
   3298             .scalar => T,
   3299         },
   3300         index: usize,
   3301 
   3302         const Self = @This();
   3303 
   3304         /// Returns a slice of the current token, or null if tokenization is
   3305         /// complete, and advances to the next token.
   3306         pub fn next(self: *Self) ?[]const T {
   3307             const result = self.peek() orelse return null;
   3308             self.index += result.len;
   3309             return result;
   3310         }
   3311 
   3312         /// Returns a slice of the current token, or null if tokenization is
   3313         /// complete. Does not advance to the next token.
   3314         pub fn peek(self: *Self) ?[]const T {
   3315             // move to beginning of token
   3316             while (self.index < self.buffer.len and self.isDelimiter(self.index)) : (self.index += switch (delimiter_type) {
   3317                 .sequence => self.delimiter.len,
   3318                 .any, .scalar => 1,
   3319             }) {}
   3320             const start = self.index;
   3321             if (start == self.buffer.len) {
   3322                 return null;
   3323             }
   3324 
   3325             // move to end of token
   3326             var end = start;
   3327             while (end < self.buffer.len and !self.isDelimiter(end)) : (end += 1) {}
   3328 
   3329             return self.buffer[start..end];
   3330         }
   3331 
   3332         /// Returns a slice of the remaining bytes. Does not affect iterator state.
   3333         pub fn rest(self: Self) []const T {
   3334             // move to beginning of token
   3335             var index: usize = self.index;
   3336             while (index < self.buffer.len and self.isDelimiter(index)) : (index += switch (delimiter_type) {
   3337                 .sequence => self.delimiter.len,
   3338                 .any, .scalar => 1,
   3339             }) {}
   3340             return self.buffer[index..];
   3341         }
   3342 
   3343         /// Resets the iterator to the initial token.
   3344         pub fn reset(self: *Self) void {
   3345             self.index = 0;
   3346         }
   3347 
   3348         fn isDelimiter(self: Self, index: usize) bool {
   3349             switch (delimiter_type) {
   3350                 .sequence => return startsWith(T, self.buffer[index..], self.delimiter),
   3351                 .any => {
   3352                     const item = self.buffer[index];
   3353                     for (self.delimiter) |delimiter_item| {
   3354                         if (item == delimiter_item) {
   3355                             return true;
   3356                         }
   3357                     }
   3358                     return false;
   3359                 },
   3360                 .scalar => return self.buffer[index] == self.delimiter,
   3361             }
   3362         }
   3363     };
   3364 }
   3365 
   3366 /// Iterator type for splitting operations, including empty sequences between delimiters.
   3367 pub fn SplitIterator(comptime T: type, comptime delimiter_type: DelimiterType) type {
   3368     return struct {
   3369         buffer: []const T,
   3370         index: ?usize,
   3371         delimiter: switch (delimiter_type) {
   3372             .sequence, .any => []const T,
   3373             .scalar => T,
   3374         },
   3375 
   3376         const Self = @This();
   3377 
   3378         /// Returns a slice of the first field.
   3379         /// Call this only to get the first field and then use `next` to get all subsequent fields.
   3380         /// Asserts that iteration has not begun.
   3381         pub fn first(self: *Self) []const T {
   3382             assert(self.index.? == 0);
   3383             return self.next().?;
   3384         }
   3385 
   3386         /// Returns a slice of the next field, or null if splitting is complete.
   3387         pub fn next(self: *Self) ?[]const T {
   3388             const start = self.index orelse return null;
   3389             const end = if (switch (delimiter_type) {
   3390                 .sequence => findPos(T, self.buffer, start, self.delimiter),
   3391                 .any => findAnyPos(T, self.buffer, start, self.delimiter),
   3392                 .scalar => findScalarPos(T, self.buffer, start, self.delimiter),
   3393             }) |delim_start| blk: {
   3394                 self.index = delim_start + switch (delimiter_type) {
   3395                     .sequence => self.delimiter.len,
   3396                     .any, .scalar => 1,
   3397                 };
   3398                 break :blk delim_start;
   3399             } else blk: {
   3400                 self.index = null;
   3401                 break :blk self.buffer.len;
   3402             };
   3403             return self.buffer[start..end];
   3404         }
   3405 
   3406         /// Returns a slice of the next field, or null if splitting is complete.
   3407         /// This method does not alter self.index.
   3408         pub fn peek(self: *const Self) ?[]const T {
   3409             const start = self.index orelse return null;
   3410             const end = if (switch (delimiter_type) {
   3411                 .sequence => findPos(T, self.buffer, start, self.delimiter),
   3412                 .any => findAnyPos(T, self.buffer, start, self.delimiter),
   3413                 .scalar => findScalarPos(T, self.buffer, start, self.delimiter),
   3414             }) |delim_start| delim_start else self.buffer.len;
   3415             return self.buffer[start..end];
   3416         }
   3417 
   3418         /// Returns a slice of the remaining bytes. Does not affect iterator state.
   3419         pub fn rest(self: Self) []const T {
   3420             const end = self.buffer.len;
   3421             const start = self.index orelse end;
   3422             return self.buffer[start..end];
   3423         }
   3424 
   3425         /// Resets the iterator to the initial slice.
   3426         pub fn reset(self: *Self) void {
   3427             self.index = 0;
   3428         }
   3429     };
   3430 }
   3431 
   3432 /// Iterator type for splitting operations from the end backwards, including empty sequences.
   3433 pub fn SplitBackwardsIterator(comptime T: type, comptime delimiter_type: DelimiterType) type {
   3434     return struct {
   3435         buffer: []const T,
   3436         index: ?usize,
   3437         delimiter: switch (delimiter_type) {
   3438             .sequence, .any => []const T,
   3439             .scalar => T,
   3440         },
   3441 
   3442         const Self = @This();
   3443 
   3444         /// Returns a slice of the first field.
   3445         /// Call this only to get the first field and then use `next` to get all subsequent fields.
   3446         /// Asserts that iteration has not begun.
   3447         pub fn first(self: *Self) []const T {
   3448             assert(self.index.? == self.buffer.len);
   3449             return self.next().?;
   3450         }
   3451 
   3452         /// Returns a slice of the next field, or null if splitting is complete.
   3453         pub fn next(self: *Self) ?[]const T {
   3454             const end = self.index orelse return null;
   3455             const start = if (switch (delimiter_type) {
   3456                 .sequence => lastIndexOf(T, self.buffer[0..end], self.delimiter),
   3457                 .any => lastIndexOfAny(T, self.buffer[0..end], self.delimiter),
   3458                 .scalar => findScalarLast(T, self.buffer[0..end], self.delimiter),
   3459             }) |delim_start| blk: {
   3460                 self.index = delim_start;
   3461                 break :blk delim_start + switch (delimiter_type) {
   3462                     .sequence => self.delimiter.len,
   3463                     .any, .scalar => 1,
   3464                 };
   3465             } else blk: {
   3466                 self.index = null;
   3467                 break :blk 0;
   3468             };
   3469             return self.buffer[start..end];
   3470         }
   3471 
   3472         /// Returns a slice of the remaining bytes. Does not affect iterator state.
   3473         pub fn rest(self: Self) []const T {
   3474             const end = self.index orelse 0;
   3475             return self.buffer[0..end];
   3476         }
   3477 
   3478         /// Resets the iterator to the initial slice.
   3479         pub fn reset(self: *Self) void {
   3480             self.index = self.buffer.len;
   3481         }
   3482     };
   3483 }
   3484 
   3485 /// Naively combines a series of slices with a separator.
   3486 /// Allocates memory for the result, which must be freed by the caller.
   3487 pub fn join(allocator: Allocator, separator: []const u8, slices: []const []const u8) Allocator.Error![]u8 {
   3488     return joinMaybeZ(allocator, separator, slices, false);
   3489 }
   3490 
   3491 /// Naively combines a series of slices with a separator and null terminator.
   3492 /// Allocates memory for the result, which must be freed by the caller.
   3493 pub fn joinZ(allocator: Allocator, separator: []const u8, slices: []const []const u8) Allocator.Error![:0]u8 {
   3494     const out = try joinMaybeZ(allocator, separator, slices, true);
   3495     return out[0 .. out.len - 1 :0];
   3496 }
   3497 
   3498 fn joinMaybeZ(allocator: Allocator, separator: []const u8, slices: []const []const u8, zero: bool) Allocator.Error![]u8 {
   3499     if (slices.len == 0) return if (zero) try allocator.dupe(u8, &[1]u8{0}) else &[0]u8{};
   3500 
   3501     const total_len = blk: {
   3502         var sum: usize = separator.len * (slices.len - 1);
   3503         for (slices) |slice| sum += slice.len;
   3504         if (zero) sum += 1;
   3505         break :blk sum;
   3506     };
   3507 
   3508     const buf = try allocator.alloc(u8, total_len);
   3509     errdefer allocator.free(buf);
   3510 
   3511     @memcpy(buf[0..slices[0].len], slices[0]);
   3512     var buf_index: usize = slices[0].len;
   3513     for (slices[1..]) |slice| {
   3514         @memcpy(buf[buf_index .. buf_index + separator.len], separator);
   3515         buf_index += separator.len;
   3516         @memcpy(buf[buf_index .. buf_index + slice.len], slice);
   3517         buf_index += slice.len;
   3518     }
   3519 
   3520     if (zero) buf[buf.len - 1] = 0;
   3521 
   3522     // No need for shrink since buf is exactly the correct size.
   3523     return buf;
   3524 }
   3525 
   3526 test join {
   3527     {
   3528         const str = try join(testing.allocator, ",", &[_][]const u8{});
   3529         defer testing.allocator.free(str);
   3530         try testing.expect(eql(u8, str, ""));
   3531     }
   3532     {
   3533         const str = try join(testing.allocator, ",", &[_][]const u8{ "a", "b", "c" });
   3534         defer testing.allocator.free(str);
   3535         try testing.expect(eql(u8, str, "a,b,c"));
   3536     }
   3537     {
   3538         const str = try join(testing.allocator, ",", &[_][]const u8{"a"});
   3539         defer testing.allocator.free(str);
   3540         try testing.expect(eql(u8, str, "a"));
   3541     }
   3542     {
   3543         const str = try join(testing.allocator, ",", &[_][]const u8{ "a", "", "b", "", "c" });
   3544         defer testing.allocator.free(str);
   3545         try testing.expect(eql(u8, str, "a,,b,,c"));
   3546     }
   3547 }
   3548 
   3549 test joinZ {
   3550     {
   3551         const str = try joinZ(testing.allocator, ",", &[_][]const u8{});
   3552         defer testing.allocator.free(str);
   3553         try testing.expect(eql(u8, str, ""));
   3554         try testing.expectEqual(str[str.len], 0);
   3555     }
   3556     {
   3557         const str = try joinZ(testing.allocator, ",", &[_][]const u8{ "a", "b", "c" });
   3558         defer testing.allocator.free(str);
   3559         try testing.expect(eql(u8, str, "a,b,c"));
   3560         try testing.expectEqual(str[str.len], 0);
   3561     }
   3562     {
   3563         const str = try joinZ(testing.allocator, ",", &[_][]const u8{"a"});
   3564         defer testing.allocator.free(str);
   3565         try testing.expect(eql(u8, str, "a"));
   3566         try testing.expectEqual(str[str.len], 0);
   3567     }
   3568     {
   3569         const str = try joinZ(testing.allocator, ",", &[_][]const u8{ "a", "", "b", "", "c" });
   3570         defer testing.allocator.free(str);
   3571         try testing.expect(eql(u8, str, "a,,b,,c"));
   3572         try testing.expectEqual(str[str.len], 0);
   3573     }
   3574 }
   3575 
   3576 /// Copies each T from slices into a new slice that exactly holds all the elements.
   3577 pub fn concat(allocator: Allocator, comptime T: type, slices: []const []const T) Allocator.Error![]T {
   3578     return concatMaybeSentinel(allocator, T, slices, null);
   3579 }
   3580 
   3581 /// Copies each T from slices into a new slice that exactly holds all the elements.
   3582 pub fn concatWithSentinel(allocator: Allocator, comptime T: type, slices: []const []const T, comptime s: T) Allocator.Error![:s]T {
   3583     const ret = try concatMaybeSentinel(allocator, T, slices, s);
   3584     return ret[0 .. ret.len - 1 :s];
   3585 }
   3586 
   3587 /// Copies each T from slices into a new slice that exactly holds all the elements as well as the sentinel.
   3588 pub fn concatMaybeSentinel(allocator: Allocator, comptime T: type, slices: []const []const T, comptime s: ?T) Allocator.Error![]T {
   3589     if (slices.len == 0) return if (s) |sentinel| try allocator.dupe(T, &[1]T{sentinel}) else &[0]T{};
   3590 
   3591     const total_len = blk: {
   3592         var sum: usize = 0;
   3593         for (slices) |slice| {
   3594             sum += slice.len;
   3595         }
   3596 
   3597         if (s) |_| {
   3598             sum += 1;
   3599         }
   3600 
   3601         break :blk sum;
   3602     };
   3603 
   3604     const buf = try allocator.alloc(T, total_len);
   3605     errdefer allocator.free(buf);
   3606 
   3607     var buf_index: usize = 0;
   3608     for (slices) |slice| {
   3609         @memcpy(buf[buf_index .. buf_index + slice.len], slice);
   3610         buf_index += slice.len;
   3611     }
   3612 
   3613     if (s) |sentinel| {
   3614         buf[buf.len - 1] = sentinel;
   3615     }
   3616 
   3617     // No need for shrink since buf is exactly the correct size.
   3618     return buf;
   3619 }
   3620 
   3621 test concat {
   3622     {
   3623         const str = try concat(testing.allocator, u8, &[_][]const u8{ "abc", "def", "ghi" });
   3624         defer testing.allocator.free(str);
   3625         try testing.expect(eql(u8, str, "abcdefghi"));
   3626     }
   3627     {
   3628         const str = try concat(testing.allocator, u32, &[_][]const u32{
   3629             &[_]u32{ 0, 1 },
   3630             &[_]u32{ 2, 3, 4 },
   3631             &[_]u32{},
   3632             &[_]u32{5},
   3633         });
   3634         defer testing.allocator.free(str);
   3635         try testing.expect(eql(u32, str, &[_]u32{ 0, 1, 2, 3, 4, 5 }));
   3636     }
   3637     {
   3638         const str = try concatWithSentinel(testing.allocator, u8, &[_][]const u8{ "abc", "def", "ghi" }, 0);
   3639         defer testing.allocator.free(str);
   3640         try testing.expectEqualSentinel(u8, 0, str, "abcdefghi");
   3641     }
   3642     {
   3643         const slice = try concatWithSentinel(testing.allocator, u8, &[_][]const u8{}, 0);
   3644         defer testing.allocator.free(slice);
   3645         try testing.expectEqualSentinel(u8, 0, slice, &[_:0]u8{});
   3646     }
   3647     {
   3648         const slice = try concatWithSentinel(testing.allocator, u32, &[_][]const u32{
   3649             &[_]u32{ 0, 1 },
   3650             &[_]u32{ 2, 3, 4 },
   3651             &[_]u32{},
   3652             &[_]u32{5},
   3653         }, 2);
   3654         defer testing.allocator.free(slice);
   3655         try testing.expectEqualSentinel(u32, 2, slice, &[_:2]u32{ 0, 1, 2, 3, 4, 5 });
   3656     }
   3657 }
   3658 
   3659 fn moreReadIntTests() !void {
   3660     {
   3661         const bytes = [_]u8{
   3662             0x12,
   3663             0x34,
   3664             0x56,
   3665             0x78,
   3666         };
   3667         try testing.expect(readInt(u32, &bytes, .big) == 0x12345678);
   3668         try testing.expect(readInt(u32, &bytes, .big) == 0x12345678);
   3669         try testing.expect(readInt(i32, &bytes, .big) == 0x12345678);
   3670         try testing.expect(readInt(u32, &bytes, .little) == 0x78563412);
   3671         try testing.expect(readInt(u32, &bytes, .little) == 0x78563412);
   3672         try testing.expect(readInt(i32, &bytes, .little) == 0x78563412);
   3673     }
   3674     {
   3675         const buf = [_]u8{
   3676             0x00,
   3677             0x00,
   3678             0x12,
   3679             0x34,
   3680         };
   3681         const answer = readInt(u32, &buf, .big);
   3682         try testing.expect(answer == 0x00001234);
   3683     }
   3684     {
   3685         const buf = [_]u8{
   3686             0x12,
   3687             0x34,
   3688             0x00,
   3689             0x00,
   3690         };
   3691         const answer = readInt(u32, &buf, .little);
   3692         try testing.expect(answer == 0x00003412);
   3693     }
   3694     {
   3695         const bytes = [_]u8{
   3696             0xff,
   3697             0xfe,
   3698         };
   3699         try testing.expect(readInt(u16, &bytes, .big) == 0xfffe);
   3700         try testing.expect(readInt(i16, &bytes, .big) == -0x0002);
   3701         try testing.expect(readInt(u16, &bytes, .little) == 0xfeff);
   3702         try testing.expect(readInt(i16, &bytes, .little) == -0x0101);
   3703     }
   3704 }
   3705 
   3706 /// Returns the smallest number in a slice. O(n).
   3707 /// `slice` must not be empty.
   3708 pub fn min(comptime T: type, slice: []const T) T {
   3709     assert(slice.len > 0);
   3710     var best = slice[0];
   3711     for (slice[1..]) |item| {
   3712         best = @min(best, item);
   3713     }
   3714     return best;
   3715 }
   3716 
   3717 test min {
   3718     try testing.expectEqual(min(u8, "abcdefg"), 'a');
   3719     try testing.expectEqual(min(u8, "bcdefga"), 'a');
   3720     try testing.expectEqual(min(u8, "a"), 'a');
   3721 }
   3722 
   3723 /// Returns the largest number in a slice. O(n).
   3724 /// `slice` must not be empty.
   3725 pub fn max(comptime T: type, slice: []const T) T {
   3726     assert(slice.len > 0);
   3727     var best = slice[0];
   3728     for (slice[1..]) |item| {
   3729         best = @max(best, item);
   3730     }
   3731     return best;
   3732 }
   3733 
   3734 test max {
   3735     try testing.expectEqual(max(u8, "abcdefg"), 'g');
   3736     try testing.expectEqual(max(u8, "gabcdef"), 'g');
   3737     try testing.expectEqual(max(u8, "g"), 'g');
   3738 }
   3739 
   3740 /// Finds the smallest and largest number in a slice. O(n).
   3741 /// Returns an anonymous struct with the fields `min` and `max`.
   3742 /// `slice` must not be empty.
   3743 pub fn minMax(comptime T: type, slice: []const T) struct { T, T } {
   3744     assert(slice.len > 0);
   3745     var running_minimum = slice[0];
   3746     var running_maximum = slice[0];
   3747     for (slice[1..]) |item| {
   3748         running_minimum = @min(running_minimum, item);
   3749         running_maximum = @max(running_maximum, item);
   3750     }
   3751     return .{ running_minimum, running_maximum };
   3752 }
   3753 
   3754 test minMax {
   3755     {
   3756         const actual_min, const actual_max = minMax(u8, "abcdefg");
   3757         try testing.expectEqual(@as(u8, 'a'), actual_min);
   3758         try testing.expectEqual(@as(u8, 'g'), actual_max);
   3759     }
   3760     {
   3761         const actual_min, const actual_max = minMax(u8, "bcdefga");
   3762         try testing.expectEqual(@as(u8, 'a'), actual_min);
   3763         try testing.expectEqual(@as(u8, 'g'), actual_max);
   3764     }
   3765     {
   3766         const actual_min, const actual_max = minMax(u8, "a");
   3767         try testing.expectEqual(@as(u8, 'a'), actual_min);
   3768         try testing.expectEqual(@as(u8, 'a'), actual_max);
   3769     }
   3770 }
   3771 
   3772 /// Deprecated in favor of `findMin`.
   3773 pub const indexOfMin = findMin;
   3774 
   3775 /// Returns the index of the smallest number in a slice. O(n).
   3776 /// `slice` must not be empty.
   3777 pub fn findMin(comptime T: type, slice: []const T) usize {
   3778     assert(slice.len > 0);
   3779     var best = slice[0];
   3780     var index: usize = 0;
   3781     for (slice[1..], 0..) |item, i| {
   3782         if (item < best) {
   3783             best = item;
   3784             index = i + 1;
   3785         }
   3786     }
   3787     return index;
   3788 }
   3789 
   3790 test findMin {
   3791     try testing.expectEqual(findMin(u8, "abcdefg"), 0);
   3792     try testing.expectEqual(findMin(u8, "bcdefga"), 6);
   3793     try testing.expectEqual(findMin(u8, "a"), 0);
   3794 }
   3795 
   3796 pub const indexOfMax = findMax;
   3797 
   3798 /// Returns the index of the largest number in a slice. O(n).
   3799 /// `slice` must not be empty.
   3800 pub fn findMax(comptime T: type, slice: []const T) usize {
   3801     assert(slice.len > 0);
   3802     var best = slice[0];
   3803     var index: usize = 0;
   3804     for (slice[1..], 0..) |item, i| {
   3805         if (item > best) {
   3806             best = item;
   3807             index = i + 1;
   3808         }
   3809     }
   3810     return index;
   3811 }
   3812 
   3813 test findMax {
   3814     try testing.expectEqual(findMax(u8, "abcdefg"), 6);
   3815     try testing.expectEqual(findMax(u8, "gabcdef"), 0);
   3816     try testing.expectEqual(findMax(u8, "a"), 0);
   3817 }
   3818 
   3819 /// Deprecated in favor of `findMinMax`.
   3820 pub const indexOfMinMax = findMinMax;
   3821 
   3822 /// Finds the indices of the smallest and largest number in a slice. O(n).
   3823 /// Returns the indices of the smallest and largest numbers in that order.
   3824 /// `slice` must not be empty.
   3825 pub fn findMinMax(comptime T: type, slice: []const T) struct { usize, usize } {
   3826     assert(slice.len > 0);
   3827     var minVal = slice[0];
   3828     var maxVal = slice[0];
   3829     var minIdx: usize = 0;
   3830     var maxIdx: usize = 0;
   3831     for (slice[1..], 0..) |item, i| {
   3832         if (item < minVal) {
   3833             minVal = item;
   3834             minIdx = i + 1;
   3835         }
   3836         if (item > maxVal) {
   3837             maxVal = item;
   3838             maxIdx = i + 1;
   3839         }
   3840     }
   3841     return .{ minIdx, maxIdx };
   3842 }
   3843 
   3844 test findMinMax {
   3845     try testing.expectEqual(.{ 0, 6 }, findMinMax(u8, "abcdefg"));
   3846     try testing.expectEqual(.{ 1, 0 }, findMinMax(u8, "gabcdef"));
   3847     try testing.expectEqual(.{ 0, 0 }, findMinMax(u8, "a"));
   3848 }
   3849 
   3850 /// Exchanges contents of two memory locations.
   3851 pub fn swap(comptime T: type, noalias a: *T, noalias b: *T) void {
   3852     if (@inComptime()) {
   3853         // In comptime, accessing bytes of values with no defined layout is a compile error.
   3854         const tmp = a.*;
   3855         a.* = b.*;
   3856         b.* = tmp;
   3857     } else {
   3858         // Swapping in streaming nature from start to end instead of swapping
   3859         // everything in one step allows easier optimizations and less stack usage.
   3860         const a_bytes: []align(@alignOf(T)) u8 = @ptrCast(a);
   3861         const b_bytes: []align(@alignOf(T)) u8 = @ptrCast(b);
   3862         for (a_bytes, b_bytes) |*ab, *bb| {
   3863             const tmp = ab.*;
   3864             ab.* = bb.*;
   3865             bb.* = tmp;
   3866         }
   3867     }
   3868 }
   3869 
   3870 test "swap works at comptime with types with no defined layout" {
   3871     comptime {
   3872         const T = struct { val: u64 };
   3873         var a: T = .{ .val = 0 };
   3874         var b: T = .{ .val = 1 };
   3875         swap(T, &a, &b);
   3876         try testing.expectEqual(T{ .val = 1 }, a);
   3877         try testing.expectEqual(T{ .val = 0 }, b);
   3878     }
   3879 }
   3880 
   3881 inline fn reverseVector(comptime N: usize, comptime T: type, a: []T) [N]T {
   3882     var res: [N]T = undefined;
   3883     inline for (0..N) |i| {
   3884         res[i] = a[N - i - 1];
   3885     }
   3886     return res;
   3887 }
   3888 
   3889 /// In-place order reversal of a slice
   3890 pub fn reverse(comptime T: type, items: []T) void {
   3891     var i: usize = 0;
   3892     const end = items.len / 2;
   3893     if (use_vectors and
   3894         !@inComptime() and
   3895         @bitSizeOf(T) > 0 and
   3896         std.math.isPowerOfTwo(@bitSizeOf(T)))
   3897     {
   3898         if (std.simd.suggestVectorLength(T)) |simd_size| {
   3899             if (simd_size <= end) {
   3900                 const simd_end = end - (simd_size - 1);
   3901                 while (i < simd_end) : (i += simd_size) {
   3902                     const left_slice = items[i .. i + simd_size];
   3903                     const right_slice = items[items.len - i - simd_size .. items.len - i];
   3904 
   3905                     const left_shuffled: [simd_size]T = reverseVector(simd_size, T, left_slice);
   3906                     const right_shuffled: [simd_size]T = reverseVector(simd_size, T, right_slice);
   3907 
   3908                     @memcpy(right_slice, &left_shuffled);
   3909                     @memcpy(left_slice, &right_shuffled);
   3910                 }
   3911             }
   3912         }
   3913     }
   3914 
   3915     while (i < end) : (i += 1) {
   3916         swap(T, &items[i], &items[items.len - i - 1]);
   3917     }
   3918 }
   3919 
   3920 test reverse {
   3921     {
   3922         var arr = [_]i32{ 5, 3, 1, 2, 4 };
   3923         reverse(i32, arr[0..]);
   3924         try testing.expectEqualSlices(i32, &arr, &.{ 4, 2, 1, 3, 5 });
   3925     }
   3926     {
   3927         var arr = [_]u0{};
   3928         reverse(u0, arr[0..]);
   3929         try testing.expectEqualSlices(u0, &arr, &.{});
   3930     }
   3931     {
   3932         var arr = [_]i64{ 19, 17, 15, 13, 11, 9, 7, 5, 3, 1, 2, 4, 6, 8, 10, 12, 14, 16, 18 };
   3933         reverse(i64, arr[0..]);
   3934         try testing.expectEqualSlices(i64, &arr, &.{ 18, 16, 14, 12, 10, 8, 6, 4, 2, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 });
   3935     }
   3936     {
   3937         var arr = [_][]const u8{ "a", "b", "c", "d" };
   3938         reverse([]const u8, arr[0..]);
   3939         try testing.expectEqualSlices([]const u8, &arr, &.{ "d", "c", "b", "a" });
   3940     }
   3941     {
   3942         const MyType = union(enum) {
   3943             a: [3]u8,
   3944             b: u24,
   3945             c,
   3946         };
   3947         var arr = [_]MyType{ .{ .a = .{ 0, 0, 0 } }, .{ .b = 0 }, .c };
   3948         reverse(MyType, arr[0..]);
   3949         try testing.expectEqualSlices(MyType, &arr, &([_]MyType{ .c, .{ .b = 0 }, .{ .a = .{ 0, 0, 0 } } }));
   3950     }
   3951 }
   3952 
   3953 /// Returned by `reverseIterator`.
   3954 pub fn ReverseIterator(comptime T: type) type {
   3955     const ptr = switch (@typeInfo(T)) {
   3956         .pointer => |ptr| ptr,
   3957         else => @compileError("expected slice or pointer to array, found '" ++ @typeName(T) ++ "'"),
   3958     };
   3959     switch (ptr.size) {
   3960         .slice => {},
   3961         .one => if (@typeInfo(ptr.child) != .array) @compileError("expected slice or pointer to array, found '" ++ @typeName(T) ++ "'"),
   3962         .many, .c => @compileError("expected slice or pointer to array, found '" ++ @typeName(T) ++ "'"),
   3963     }
   3964     const Element = std.meta.Elem(T);
   3965     const attrs: std.builtin.Type.Pointer.Attributes = .{
   3966         .@"const" = ptr.is_const,
   3967         .@"volatile" = ptr.is_volatile,
   3968         .@"allowzero" = ptr.is_allowzero,
   3969         .@"align" = ptr.alignment,
   3970         .@"addrspace" = ptr.address_space,
   3971     };
   3972     const Pointer = @Pointer(.many, attrs, Element, std.meta.sentinel(T));
   3973     const ElementPointer = @Pointer(.one, attrs, Element, null);
   3974     return struct {
   3975         ptr: Pointer,
   3976         index: usize,
   3977         pub fn next(self: *@This()) ?Element {
   3978             if (self.index == 0) return null;
   3979             self.index -= 1;
   3980             return self.ptr[self.index];
   3981         }
   3982         pub fn nextPtr(self: *@This()) ?ElementPointer {
   3983             if (self.index == 0) return null;
   3984             self.index -= 1;
   3985             return &self.ptr[self.index];
   3986         }
   3987     };
   3988 }
   3989 
   3990 /// Iterates over a slice in reverse.
   3991 pub fn reverseIterator(slice: anytype) ReverseIterator(@TypeOf(slice)) {
   3992     return .{ .ptr = slice.ptr, .index = slice.len };
   3993 }
   3994 
   3995 test reverseIterator {
   3996     {
   3997         var it = reverseIterator("abc");
   3998         try testing.expectEqual(@as(?u8, 'c'), it.next());
   3999         try testing.expectEqual(@as(?u8, 'b'), it.next());
   4000         try testing.expectEqual(@as(?u8, 'a'), it.next());
   4001         try testing.expectEqual(@as(?u8, null), it.next());
   4002     }
   4003     {
   4004         var array = [2]i32{ 3, 7 };
   4005         const slice: []const i32 = &array;
   4006         var it = reverseIterator(slice);
   4007         try testing.expectEqual(@as(?i32, 7), it.next());
   4008         try testing.expectEqual(@as(?i32, 3), it.next());
   4009         try testing.expectEqual(@as(?i32, null), it.next());
   4010 
   4011         it = reverseIterator(slice);
   4012         try testing.expect(*const i32 == @TypeOf(it.nextPtr().?));
   4013         try testing.expectEqual(@as(?i32, 7), it.nextPtr().?.*);
   4014         try testing.expectEqual(@as(?i32, 3), it.nextPtr().?.*);
   4015         try testing.expectEqual(@as(?*const i32, null), it.nextPtr());
   4016 
   4017         const mut_slice: []i32 = &array;
   4018         var mut_it = reverseIterator(mut_slice);
   4019         mut_it.nextPtr().?.* += 1;
   4020         mut_it.nextPtr().?.* += 2;
   4021         try testing.expectEqual([2]i32{ 5, 8 }, array);
   4022     }
   4023     {
   4024         var array = [2]i32{ 3, 7 };
   4025         const ptr_to_array: *const [2]i32 = &array;
   4026         var it = reverseIterator(ptr_to_array);
   4027         try testing.expectEqual(@as(?i32, 7), it.next());
   4028         try testing.expectEqual(@as(?i32, 3), it.next());
   4029         try testing.expectEqual(@as(?i32, null), it.next());
   4030 
   4031         it = reverseIterator(ptr_to_array);
   4032         try testing.expect(*const i32 == @TypeOf(it.nextPtr().?));
   4033         try testing.expectEqual(@as(?i32, 7), it.nextPtr().?.*);
   4034         try testing.expectEqual(@as(?i32, 3), it.nextPtr().?.*);
   4035         try testing.expectEqual(@as(?*const i32, null), it.nextPtr());
   4036 
   4037         const mut_ptr_to_array: *[2]i32 = &array;
   4038         var mut_it = reverseIterator(mut_ptr_to_array);
   4039         mut_it.nextPtr().?.* += 1;
   4040         mut_it.nextPtr().?.* += 2;
   4041         try testing.expectEqual([2]i32{ 5, 8 }, array);
   4042     }
   4043 }
   4044 
   4045 /// In-place rotation of the values in an array ([0 1 2 3] becomes [1 2 3 0] if we rotate by 1)
   4046 /// Assumes 0 <= amount <= items.len
   4047 pub fn rotate(comptime T: type, items: []T, amount: usize) void {
   4048     reverse(T, items[0..amount]);
   4049     reverse(T, items[amount..]);
   4050     reverse(T, items);
   4051 }
   4052 
   4053 test rotate {
   4054     var arr = [_]i32{ 5, 3, 1, 2, 4 };
   4055     rotate(i32, arr[0..], 2);
   4056 
   4057     try testing.expect(eql(i32, &arr, &[_]i32{ 1, 2, 4, 5, 3 }));
   4058 }
   4059 
   4060 /// Replace needle with replacement as many times as possible, writing to an output buffer which is assumed to be of
   4061 /// appropriate size. Use replacementSize to calculate an appropriate buffer size.
   4062 /// The `input` and `output` slices must not overlap.
   4063 /// The needle must not be empty.
   4064 /// Returns the number of replacements made.
   4065 pub fn replace(comptime T: type, input: []const T, needle: []const T, replacement: []const T, output: []T) usize {
   4066     // Empty needle will loop until output buffer overflows.
   4067     assert(needle.len > 0);
   4068 
   4069     var i: usize = 0;
   4070     var slide: usize = 0;
   4071     var replacements: usize = 0;
   4072     while (slide < input.len) {
   4073         if (mem.startsWith(T, input[slide..], needle)) {
   4074             @memcpy(output[i..][0..replacement.len], replacement);
   4075             i += replacement.len;
   4076             slide += needle.len;
   4077             replacements += 1;
   4078         } else {
   4079             output[i] = input[slide];
   4080             i += 1;
   4081             slide += 1;
   4082         }
   4083     }
   4084 
   4085     return replacements;
   4086 }
   4087 
   4088 test replace {
   4089     var output: [29]u8 = undefined;
   4090     var replacements = replace(u8, "All your base are belong to us", "base", "Zig", output[0..]);
   4091     var expected: []const u8 = "All your Zig are belong to us";
   4092     try testing.expect(replacements == 1);
   4093     try testing.expectEqualStrings(expected, output[0..expected.len]);
   4094 
   4095     replacements = replace(u8, "Favor reading code over writing code.", "code", "", output[0..]);
   4096     expected = "Favor reading  over writing .";
   4097     try testing.expect(replacements == 2);
   4098     try testing.expectEqualStrings(expected, output[0..expected.len]);
   4099 
   4100     // Empty needle is not allowed but input may be empty.
   4101     replacements = replace(u8, "", "x", "y", output[0..0]);
   4102     expected = "";
   4103     try testing.expect(replacements == 0);
   4104     try testing.expectEqualStrings(expected, output[0..expected.len]);
   4105 
   4106     // Adjacent replacements.
   4107 
   4108     replacements = replace(u8, "\\n\\n", "\\n", "\n", output[0..]);
   4109     expected = "\n\n";
   4110     try testing.expect(replacements == 2);
   4111     try testing.expectEqualStrings(expected, output[0..expected.len]);
   4112 
   4113     replacements = replace(u8, "abbba", "b", "cd", output[0..]);
   4114     expected = "acdcdcda";
   4115     try testing.expect(replacements == 3);
   4116     try testing.expectEqualStrings(expected, output[0..expected.len]);
   4117 }
   4118 
   4119 /// Replace all occurrences of `match` with `replacement`.
   4120 pub fn replaceScalar(comptime T: type, slice: []T, match: T, replacement: T) void {
   4121     for (slice) |*e| {
   4122         if (e.* == match)
   4123             e.* = replacement;
   4124     }
   4125 }
   4126 
   4127 /// Collapse consecutive duplicate elements into one entry.
   4128 pub fn collapseRepeatsLen(comptime T: type, slice: []T, elem: T) usize {
   4129     if (slice.len == 0) return 0;
   4130     var write_idx: usize = 1;
   4131     var read_idx: usize = 1;
   4132     while (read_idx < slice.len) : (read_idx += 1) {
   4133         if (slice[read_idx - 1] != elem or slice[read_idx] != elem) {
   4134             slice[write_idx] = slice[read_idx];
   4135             write_idx += 1;
   4136         }
   4137     }
   4138     return write_idx;
   4139 }
   4140 
   4141 /// Collapse consecutive duplicate elements into one entry.
   4142 pub fn collapseRepeats(comptime T: type, slice: []T, elem: T) []T {
   4143     return slice[0..collapseRepeatsLen(T, slice, elem)];
   4144 }
   4145 
   4146 fn testCollapseRepeats(str: []const u8, elem: u8, expected: []const u8) !void {
   4147     const mutable = try std.testing.allocator.dupe(u8, str);
   4148     defer std.testing.allocator.free(mutable);
   4149     try testing.expect(std.mem.eql(u8, collapseRepeats(u8, mutable, elem), expected));
   4150 }
   4151 test collapseRepeats {
   4152     try testCollapseRepeats("", '/', "");
   4153     try testCollapseRepeats("a", '/', "a");
   4154     try testCollapseRepeats("/", '/', "/");
   4155     try testCollapseRepeats("//", '/', "/");
   4156     try testCollapseRepeats("/a", '/', "/a");
   4157     try testCollapseRepeats("//a", '/', "/a");
   4158     try testCollapseRepeats("a/", '/', "a/");
   4159     try testCollapseRepeats("a//", '/', "a/");
   4160     try testCollapseRepeats("a/a", '/', "a/a");
   4161     try testCollapseRepeats("a//a", '/', "a/a");
   4162     try testCollapseRepeats("//a///a////", '/', "/a/a/");
   4163 }
   4164 
   4165 /// Calculate the size needed in an output buffer to perform a replacement.
   4166 /// The needle must not be empty.
   4167 pub fn replacementSize(comptime T: type, input: []const T, needle: []const T, replacement: []const T) usize {
   4168     // Empty needle will loop forever.
   4169     assert(needle.len > 0);
   4170 
   4171     var i: usize = 0;
   4172     var size: usize = input.len;
   4173     while (i < input.len) {
   4174         if (mem.startsWith(T, input[i..], needle)) {
   4175             size = size - needle.len + replacement.len;
   4176             i += needle.len;
   4177         } else {
   4178             i += 1;
   4179         }
   4180     }
   4181 
   4182     return size;
   4183 }
   4184 
   4185 test replacementSize {
   4186     try testing.expect(replacementSize(u8, "All your base are belong to us", "base", "Zig") == 29);
   4187     try testing.expect(replacementSize(u8, "Favor reading code over writing code.", "code", "") == 29);
   4188     try testing.expect(replacementSize(u8, "Only one obvious way to do things.", "things.", "things in Zig.") == 41);
   4189 
   4190     // Empty needle is not allowed but input may be empty.
   4191     try testing.expect(replacementSize(u8, "", "x", "y") == 0);
   4192 
   4193     // Adjacent replacements.
   4194     try testing.expect(replacementSize(u8, "\\n\\n", "\\n", "\n") == 2);
   4195     try testing.expect(replacementSize(u8, "abbba", "b", "cd") == 8);
   4196 }
   4197 
   4198 /// Perform a replacement on an allocated buffer of pre-determined size. Caller must free returned memory.
   4199 pub fn replaceOwned(comptime T: type, allocator: Allocator, input: []const T, needle: []const T, replacement: []const T) Allocator.Error![]T {
   4200     const output = try allocator.alloc(T, replacementSize(T, input, needle, replacement));
   4201     _ = replace(T, input, needle, replacement, output);
   4202     return output;
   4203 }
   4204 
   4205 test replaceOwned {
   4206     const gpa = std.testing.allocator;
   4207 
   4208     const base_replace = replaceOwned(u8, gpa, "All your base are belong to us", "base", "Zig") catch @panic("out of memory");
   4209     defer gpa.free(base_replace);
   4210     try testing.expect(eql(u8, base_replace, "All your Zig are belong to us"));
   4211 
   4212     const zen_replace = replaceOwned(u8, gpa, "Favor reading code over writing code.", " code", "") catch @panic("out of memory");
   4213     defer gpa.free(zen_replace);
   4214     try testing.expect(eql(u8, zen_replace, "Favor reading over writing."));
   4215 }
   4216 
   4217 /// Converts a little-endian integer to host endianness.
   4218 pub fn littleToNative(comptime T: type, x: T) T {
   4219     return switch (native_endian) {
   4220         .little => x,
   4221         .big => @byteSwap(x),
   4222     };
   4223 }
   4224 
   4225 /// Converts a big-endian integer to host endianness.
   4226 pub fn bigToNative(comptime T: type, x: T) T {
   4227     return switch (native_endian) {
   4228         .little => @byteSwap(x),
   4229         .big => x,
   4230     };
   4231 }
   4232 
   4233 /// Converts an integer from specified endianness to host endianness.
   4234 pub fn toNative(comptime T: type, x: T, endianness_of_x: Endian) T {
   4235     return switch (endianness_of_x) {
   4236         .little => littleToNative(T, x),
   4237         .big => bigToNative(T, x),
   4238     };
   4239 }
   4240 
   4241 /// Converts an integer which has host endianness to the desired endianness.
   4242 pub fn nativeTo(comptime T: type, x: T, desired_endianness: Endian) T {
   4243     return switch (desired_endianness) {
   4244         .little => nativeToLittle(T, x),
   4245         .big => nativeToBig(T, x),
   4246     };
   4247 }
   4248 
   4249 /// Converts an integer which has host endianness to little endian.
   4250 pub fn nativeToLittle(comptime T: type, x: T) T {
   4251     return switch (native_endian) {
   4252         .little => x,
   4253         .big => @byteSwap(x),
   4254     };
   4255 }
   4256 
   4257 /// Converts an integer which has host endianness to big endian.
   4258 pub fn nativeToBig(comptime T: type, x: T) T {
   4259     return switch (native_endian) {
   4260         .little => @byteSwap(x),
   4261         .big => x,
   4262     };
   4263 }
   4264 
   4265 /// Returns the number of elements that, if added to the given pointer, align it
   4266 /// to a multiple of the given quantity, or `null` if one of the following
   4267 /// conditions is met:
   4268 /// - The aligned pointer would not fit the address space,
   4269 /// - The delta required to align the pointer is not a multiple of the pointee's
   4270 ///   type.
   4271 pub fn alignPointerOffset(ptr: anytype, align_to: usize) ?usize {
   4272     assert(isValidAlign(align_to));
   4273 
   4274     const T = @TypeOf(ptr);
   4275     const info = @typeInfo(T);
   4276     if (info != .pointer or info.pointer.size != .many)
   4277         @compileError("expected many item pointer, got " ++ @typeName(T));
   4278 
   4279     // Do nothing if the pointer is already well-aligned.
   4280     if (align_to <= info.pointer.alignment orelse @alignOf(info.pointer.child))
   4281         return 0;
   4282 
   4283     // Calculate the aligned base address with an eye out for overflow.
   4284     const addr = @intFromPtr(ptr);
   4285     var ov = @addWithOverflow(addr, align_to - 1);
   4286     if (ov[1] != 0) return null;
   4287     ov[0] &= ~@as(usize, align_to - 1);
   4288 
   4289     // The delta is expressed in terms of bytes, turn it into a number of child
   4290     // type elements.
   4291     const delta = ov[0] - addr;
   4292     const pointee_size = @sizeOf(info.pointer.child);
   4293     if (delta % pointee_size != 0) return null;
   4294     return delta / pointee_size;
   4295 }
   4296 
   4297 /// Aligns a given pointer value to a specified alignment factor.
   4298 /// Returns an aligned pointer or null if one of the following conditions is
   4299 /// met:
   4300 /// - The aligned pointer would not fit the address space,
   4301 /// - The delta required to align the pointer is not a multiple of the pointee's
   4302 ///   type.
   4303 pub fn alignPointer(ptr: anytype, align_to: usize) ?@TypeOf(ptr) {
   4304     const adjust_off = alignPointerOffset(ptr, align_to) orelse return null;
   4305     // Avoid the use of ptrFromInt to avoid losing the pointer provenance info.
   4306     return @alignCast(ptr + adjust_off);
   4307 }
   4308 
   4309 test alignPointer {
   4310     const S = struct {
   4311         fn checkAlign(comptime T: type, base: usize, align_to: usize, expected: usize) !void {
   4312             const ptr: T = @ptrFromInt(base);
   4313             const aligned = alignPointer(ptr, align_to);
   4314             try testing.expectEqual(expected, @intFromPtr(aligned));
   4315         }
   4316     };
   4317 
   4318     try S.checkAlign([*]u8, 0x123, 0x200, 0x200);
   4319     try S.checkAlign([*]align(4) u8, 0x10, 2, 0x10);
   4320     try S.checkAlign([*]u32, 0x10, 2, 0x10);
   4321     try S.checkAlign([*]u32, 0x4, 16, 0x10);
   4322     // Misaligned.
   4323     try S.checkAlign([*]align(1) u32, 0x3, 2, 0);
   4324     // Overflow.
   4325     try S.checkAlign([*]u32, math.maxInt(usize) - 3, 8, 0);
   4326 }
   4327 
   4328 fn CopyPtrAttrs(
   4329     comptime source: type,
   4330     comptime size: std.builtin.Type.Pointer.Size,
   4331     comptime child: type,
   4332 ) type {
   4333     const ptr = @typeInfo(source).pointer;
   4334     return @Pointer(size, .{
   4335         .@"const" = ptr.is_const,
   4336         .@"volatile" = ptr.is_volatile,
   4337         .@"allowzero" = ptr.is_allowzero,
   4338         .@"align" = ptr.alignment orelse a: {
   4339             // If the new child is aligned differently than the old one, explicitly align the type.
   4340             const want = @alignOf(ptr.child);
   4341             break :a if (@alignOf(child) == want) null else want;
   4342         },
   4343         .@"addrspace" = ptr.address_space,
   4344     }, child, null);
   4345 }
   4346 
   4347 fn AsBytesReturnType(comptime P: type) type {
   4348     const pointer = @typeInfo(P).pointer;
   4349     assert(pointer.size == .one);
   4350     const size = @sizeOf(pointer.child);
   4351     return CopyPtrAttrs(P, .one, [size]u8);
   4352 }
   4353 
   4354 /// Given a pointer to a single item, returns a slice of the underlying bytes, preserving pointer attributes.
   4355 pub fn asBytes(ptr: anytype) AsBytesReturnType(@TypeOf(ptr)) {
   4356     return @ptrCast(@alignCast(ptr));
   4357 }
   4358 
   4359 test asBytes {
   4360     const deadbeef = @as(u32, 0xDEADBEEF);
   4361     const deadbeef_bytes = switch (native_endian) {
   4362         .big => "\xDE\xAD\xBE\xEF",
   4363         .little => "\xEF\xBE\xAD\xDE",
   4364     };
   4365 
   4366     try testing.expect(eql(u8, asBytes(&deadbeef), deadbeef_bytes));
   4367 
   4368     var codeface = @as(u32, 0xC0DEFACE);
   4369     for (asBytes(&codeface)) |*b|
   4370         b.* = 0;
   4371     try testing.expect(codeface == 0);
   4372 
   4373     const S = packed struct {
   4374         a: u8,
   4375         b: u8,
   4376         c: u8,
   4377         d: u8,
   4378     };
   4379 
   4380     const inst = S{
   4381         .a = 0xBE,
   4382         .b = 0xEF,
   4383         .c = 0xDE,
   4384         .d = 0xA1,
   4385     };
   4386     switch (native_endian) {
   4387         .little => {
   4388             try testing.expect(eql(u8, asBytes(&inst), "\xBE\xEF\xDE\xA1"));
   4389         },
   4390         .big => {
   4391             try testing.expect(eql(u8, asBytes(&inst), "\xA1\xDE\xEF\xBE"));
   4392         },
   4393     }
   4394 
   4395     const ZST = struct {};
   4396     const zero = ZST{};
   4397     try testing.expect(eql(u8, asBytes(&zero), ""));
   4398 }
   4399 
   4400 test "asBytes preserves pointer attributes" {
   4401     const inArr: u32 align(16) = 0xDEADBEEF;
   4402     const inPtr = @as(*align(16) const volatile u32, @ptrCast(&inArr));
   4403     const outSlice = asBytes(inPtr);
   4404 
   4405     const in = @typeInfo(@TypeOf(inPtr)).pointer;
   4406     const out = @typeInfo(@TypeOf(outSlice)).pointer;
   4407 
   4408     try testing.expectEqual(in.is_const, out.is_const);
   4409     try testing.expectEqual(in.is_volatile, out.is_volatile);
   4410     try testing.expectEqual(in.is_allowzero, out.is_allowzero);
   4411     try testing.expectEqual(in.alignment, out.alignment);
   4412 }
   4413 
   4414 /// Given any value, returns a copy of its bytes in an array.
   4415 pub fn toBytes(value: anytype) [@sizeOf(@TypeOf(value))]u8 {
   4416     return asBytes(&value).*;
   4417 }
   4418 
   4419 test toBytes {
   4420     var my_bytes = toBytes(@as(u32, 0x12345678));
   4421     switch (native_endian) {
   4422         .big => try testing.expect(eql(u8, &my_bytes, "\x12\x34\x56\x78")),
   4423         .little => try testing.expect(eql(u8, &my_bytes, "\x78\x56\x34\x12")),
   4424     }
   4425 
   4426     my_bytes[0] = '\x99';
   4427     switch (native_endian) {
   4428         .big => try testing.expect(eql(u8, &my_bytes, "\x99\x34\x56\x78")),
   4429         .little => try testing.expect(eql(u8, &my_bytes, "\x99\x56\x34\x12")),
   4430     }
   4431 }
   4432 
   4433 fn BytesAsValueReturnType(comptime T: type, comptime B: type) type {
   4434     return CopyPtrAttrs(B, .one, T);
   4435 }
   4436 
   4437 /// Given a pointer to an array of bytes, returns a pointer to a value of the specified type
   4438 /// backed by those bytes, preserving pointer attributes.
   4439 pub fn bytesAsValue(comptime T: type, bytes: anytype) BytesAsValueReturnType(T, @TypeOf(bytes)) {
   4440     return @ptrCast(bytes);
   4441 }
   4442 
   4443 test bytesAsValue {
   4444     const deadbeef = @as(u32, 0xDEADBEEF);
   4445     const deadbeef_bytes = switch (native_endian) {
   4446         .big => "\xDE\xAD\xBE\xEF",
   4447         .little => "\xEF\xBE\xAD\xDE",
   4448     };
   4449 
   4450     try testing.expect(deadbeef == bytesAsValue(u32, deadbeef_bytes).*);
   4451 
   4452     var codeface_bytes: [4]u8 = switch (native_endian) {
   4453         .big => "\xC0\xDE\xFA\xCE",
   4454         .little => "\xCE\xFA\xDE\xC0",
   4455     }.*;
   4456     const codeface = bytesAsValue(u32, &codeface_bytes);
   4457     try testing.expect(codeface.* == 0xC0DEFACE);
   4458     codeface.* = 0;
   4459     for (codeface_bytes) |b|
   4460         try testing.expect(b == 0);
   4461 
   4462     const S = packed struct {
   4463         a: u8,
   4464         b: u8,
   4465         c: u8,
   4466         d: u8,
   4467     };
   4468 
   4469     const inst = S{
   4470         .a = 0xBE,
   4471         .b = 0xEF,
   4472         .c = 0xDE,
   4473         .d = 0xA1,
   4474     };
   4475     const inst_bytes = switch (native_endian) {
   4476         .little => "\xBE\xEF\xDE\xA1",
   4477         .big => "\xA1\xDE\xEF\xBE",
   4478     };
   4479     const inst2 = bytesAsValue(S, inst_bytes);
   4480     try testing.expect(std.meta.eql(inst, inst2.*));
   4481 }
   4482 
   4483 test "bytesAsValue preserves pointer attributes" {
   4484     const inArr align(16) = [4]u8{ 0xDE, 0xAD, 0xBE, 0xEF };
   4485     const inSlice = @as(*align(16) const volatile [4]u8, @ptrCast(&inArr))[0..];
   4486     const outPtr = bytesAsValue(u32, inSlice);
   4487 
   4488     const in = @typeInfo(@TypeOf(inSlice)).pointer;
   4489     const out = @typeInfo(@TypeOf(outPtr)).pointer;
   4490 
   4491     try testing.expectEqual(in.is_const, out.is_const);
   4492     try testing.expectEqual(in.is_volatile, out.is_volatile);
   4493     try testing.expectEqual(in.is_allowzero, out.is_allowzero);
   4494     try testing.expectEqual(in.alignment, out.alignment);
   4495 }
   4496 
   4497 /// Given a pointer to an array of bytes, returns a value of the specified type backed by a
   4498 /// copy of those bytes.
   4499 pub fn bytesToValue(comptime T: type, bytes: anytype) T {
   4500     return bytesAsValue(T, bytes).*;
   4501 }
   4502 test bytesToValue {
   4503     const deadbeef_bytes = switch (native_endian) {
   4504         .big => "\xDE\xAD\xBE\xEF",
   4505         .little => "\xEF\xBE\xAD\xDE",
   4506     };
   4507 
   4508     const deadbeef = bytesToValue(u32, deadbeef_bytes);
   4509     try testing.expect(deadbeef == @as(u32, 0xDEADBEEF));
   4510 }
   4511 
   4512 fn BytesAsSliceReturnType(comptime T: type, comptime bytesType: type) type {
   4513     return CopyPtrAttrs(bytesType, .slice, T);
   4514 }
   4515 
   4516 /// Given a slice of bytes, returns a slice of the specified type
   4517 /// backed by those bytes, preserving pointer attributes.
   4518 /// If `T` is zero-bytes sized, the returned slice has a len of zero.
   4519 pub fn bytesAsSlice(comptime T: type, bytes: anytype) BytesAsSliceReturnType(T, @TypeOf(bytes)) {
   4520     // let's not give an undefined pointer to @ptrCast
   4521     // it may be equal to zero and fail a null check
   4522     if (bytes.len == 0 or @sizeOf(T) == 0) {
   4523         return &[0]T{};
   4524     }
   4525 
   4526     const cast_target = CopyPtrAttrs(@TypeOf(bytes), .many, T);
   4527 
   4528     return @as(cast_target, @ptrCast(bytes))[0..@divExact(bytes.len, @sizeOf(T))];
   4529 }
   4530 
   4531 test bytesAsSlice {
   4532     {
   4533         const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF };
   4534         const slice = bytesAsSlice(u16, bytes[0..]);
   4535         try testing.expect(slice.len == 2);
   4536         try testing.expect(bigToNative(u16, slice[0]) == 0xDEAD);
   4537         try testing.expect(bigToNative(u16, slice[1]) == 0xBEEF);
   4538     }
   4539     {
   4540         const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF };
   4541         var runtime_zero: usize = 0;
   4542         _ = &runtime_zero;
   4543         const slice = bytesAsSlice(u16, bytes[runtime_zero..]);
   4544         try testing.expect(slice.len == 2);
   4545         try testing.expect(bigToNative(u16, slice[0]) == 0xDEAD);
   4546         try testing.expect(bigToNative(u16, slice[1]) == 0xBEEF);
   4547     }
   4548 }
   4549 
   4550 test "bytesAsSlice keeps pointer alignment" {
   4551     {
   4552         var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 };
   4553         const numbers = bytesAsSlice(u32, bytes[0..]);
   4554         try comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32);
   4555     }
   4556     {
   4557         var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 };
   4558         var runtime_zero: usize = 0;
   4559         _ = &runtime_zero;
   4560         const numbers = bytesAsSlice(u32, bytes[runtime_zero..]);
   4561         try comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32);
   4562     }
   4563 }
   4564 
   4565 test "bytesAsSlice on a packed struct" {
   4566     const F = packed struct {
   4567         a: u8,
   4568     };
   4569 
   4570     const b: [1]u8 = .{9};
   4571     const f = bytesAsSlice(F, &b);
   4572     try testing.expect(f[0].a == 9);
   4573 }
   4574 
   4575 test "bytesAsSlice with specified alignment" {
   4576     var bytes align(4) = [_]u8{
   4577         0x33,
   4578         0x33,
   4579         0x33,
   4580         0x33,
   4581     };
   4582     const slice: []u32 = std.mem.bytesAsSlice(u32, bytes[0..]);
   4583     try testing.expect(slice[0] == 0x33333333);
   4584 }
   4585 
   4586 test "bytesAsSlice preserves pointer attributes" {
   4587     const inArr align(16) = [4]u8{ 0xDE, 0xAD, 0xBE, 0xEF };
   4588     const inSlice = @as(*align(16) const volatile [4]u8, @ptrCast(&inArr))[0..];
   4589     const outSlice = bytesAsSlice(u16, inSlice);
   4590 
   4591     const in = @typeInfo(@TypeOf(inSlice)).pointer;
   4592     const out = @typeInfo(@TypeOf(outSlice)).pointer;
   4593 
   4594     try testing.expectEqual(in.is_const, out.is_const);
   4595     try testing.expectEqual(in.is_volatile, out.is_volatile);
   4596     try testing.expectEqual(in.is_allowzero, out.is_allowzero);
   4597     try testing.expectEqual(in.alignment, out.alignment);
   4598 }
   4599 
   4600 test "bytesAsSlice with zero-bit element type" {
   4601     {
   4602         const bytes = [_]u8{};
   4603         const slice = bytesAsSlice(void, &bytes);
   4604         try testing.expectEqual(0, slice.len);
   4605     }
   4606     {
   4607         const bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 };
   4608         const slice = bytesAsSlice(u0, &bytes);
   4609         try testing.expectEqual(0, slice.len);
   4610     }
   4611 }
   4612 
   4613 fn SliceAsBytesReturnType(comptime Slice: type) type {
   4614     return CopyPtrAttrs(Slice, .slice, u8);
   4615 }
   4616 
   4617 /// Given a slice, returns a slice of the underlying bytes, preserving pointer attributes.
   4618 pub fn sliceAsBytes(slice: anytype) SliceAsBytesReturnType(@TypeOf(slice)) {
   4619     const Slice = @TypeOf(slice);
   4620 
   4621     // a slice of zero-bit values always occupies zero bytes
   4622     if (@sizeOf(std.meta.Elem(Slice)) == 0) return &[0]u8{};
   4623 
   4624     // let's not give an undefined pointer to @ptrCast
   4625     // it may be equal to zero and fail a null check
   4626     if (slice.len == 0 and std.meta.sentinel(Slice) == null) return &[0]u8{};
   4627 
   4628     const cast_target = CopyPtrAttrs(Slice, .many, u8);
   4629 
   4630     return @as(cast_target, @ptrCast(slice))[0 .. slice.len * @sizeOf(std.meta.Elem(Slice))];
   4631 }
   4632 
   4633 test sliceAsBytes {
   4634     const bytes = [_]u16{ 0xDEAD, 0xBEEF };
   4635     const slice = sliceAsBytes(bytes[0..]);
   4636     try testing.expect(slice.len == 4);
   4637     try testing.expect(eql(u8, slice, switch (native_endian) {
   4638         .big => "\xDE\xAD\xBE\xEF",
   4639         .little => "\xAD\xDE\xEF\xBE",
   4640     }));
   4641 }
   4642 
   4643 test "sliceAsBytes with sentinel slice" {
   4644     const empty_string: [:0]const u8 = "";
   4645     const bytes = sliceAsBytes(empty_string);
   4646     try testing.expect(bytes.len == 0);
   4647 }
   4648 
   4649 test "sliceAsBytes with zero-bit element type" {
   4650     const lots_of_nothing = [1]void{{}} ** 10_000;
   4651     const bytes = sliceAsBytes(&lots_of_nothing);
   4652     try testing.expect(bytes.len == 0);
   4653 }
   4654 
   4655 test "sliceAsBytes packed struct at runtime and comptime" {
   4656     const Foo = packed struct {
   4657         a: u4,
   4658         b: u4,
   4659     };
   4660     const S = struct {
   4661         fn doTheTest() !void {
   4662             var foo: Foo = undefined;
   4663             var slice = sliceAsBytes(@as(*[1]Foo, &foo)[0..1]);
   4664             slice[0] = 0x13;
   4665             try testing.expect(foo.a == 0x3);
   4666             try testing.expect(foo.b == 0x1);
   4667         }
   4668     };
   4669     try S.doTheTest();
   4670     try comptime S.doTheTest();
   4671 }
   4672 
   4673 test "sliceAsBytes and bytesAsSlice back" {
   4674     try testing.expect(@sizeOf(i32) == 4);
   4675 
   4676     var big_thing_array = [_]i32{ 1, 2, 3, 4 };
   4677     const big_thing_slice: []i32 = big_thing_array[0..];
   4678 
   4679     const bytes = sliceAsBytes(big_thing_slice);
   4680     try testing.expect(bytes.len == 4 * 4);
   4681 
   4682     bytes[4] = 0;
   4683     bytes[5] = 0;
   4684     bytes[6] = 0;
   4685     bytes[7] = 0;
   4686     try testing.expect(big_thing_slice[1] == 0);
   4687 
   4688     const big_thing_again = bytesAsSlice(i32, bytes);
   4689     try testing.expect(big_thing_again[2] == 3);
   4690 
   4691     big_thing_again[2] = -1;
   4692     try testing.expect(bytes[8] == math.maxInt(u8));
   4693     try testing.expect(bytes[9] == math.maxInt(u8));
   4694     try testing.expect(bytes[10] == math.maxInt(u8));
   4695     try testing.expect(bytes[11] == math.maxInt(u8));
   4696 }
   4697 
   4698 test "sliceAsBytes preserves pointer attributes" {
   4699     const inArr align(16) = [2]u16{ 0xDEAD, 0xBEEF };
   4700     const inSlice = @as(*align(16) const volatile [2]u16, @ptrCast(&inArr))[0..];
   4701     const outSlice = sliceAsBytes(inSlice);
   4702 
   4703     const in = @typeInfo(@TypeOf(inSlice)).pointer;
   4704     const out = @typeInfo(@TypeOf(outSlice)).pointer;
   4705 
   4706     try testing.expectEqual(in.is_const, out.is_const);
   4707     try testing.expectEqual(in.is_volatile, out.is_volatile);
   4708     try testing.expectEqual(in.is_allowzero, out.is_allowzero);
   4709     try testing.expectEqual(in.alignment, out.alignment);
   4710 }
   4711 
   4712 /// Round an address down to the next (or current) aligned address.
   4713 /// Unlike `alignForward`, `alignment` can be any positive number, not just a power of 2.
   4714 pub fn alignForwardAnyAlign(comptime T: type, addr: T, alignment: T) T {
   4715     if (isValidAlignGeneric(T, alignment))
   4716         return alignForward(T, addr, alignment);
   4717     assert(alignment != 0);
   4718     return alignBackwardAnyAlign(T, addr + (alignment - 1), alignment);
   4719 }
   4720 
   4721 /// Round an address up to the next (or current) aligned address.
   4722 /// The alignment must be a power of 2 and greater than 0.
   4723 /// Asserts that rounding up the address does not cause integer overflow.
   4724 pub fn alignForward(comptime T: type, addr: T, alignment: T) T {
   4725     assert(isValidAlignGeneric(T, alignment));
   4726     return alignBackward(T, addr + (alignment - 1), alignment);
   4727 }
   4728 
   4729 /// Rounds an address up to the next alignment boundary using log2 representation.
   4730 /// Equivalent to alignForward with alignment = 1 << log2_alignment.
   4731 /// More efficient when alignment is known to be a power of 2.
   4732 pub fn alignForwardLog2(addr: usize, log2_alignment: u8) usize {
   4733     const alignment = @as(usize, 1) << @as(math.Log2Int(usize), @intCast(log2_alignment));
   4734     return alignForward(usize, addr, alignment);
   4735 }
   4736 
   4737 /// Force an evaluation of the expression; this tries to prevent
   4738 /// the compiler from optimizing the computation away even if the
   4739 /// result eventually gets discarded.
   4740 // TODO: use @declareSideEffect() when it is available - https://github.com/ziglang/zig/issues/6168
   4741 pub fn doNotOptimizeAway(val: anytype) void {
   4742     if (@inComptime()) return;
   4743 
   4744     const max_gp_register_bits = @bitSizeOf(c_long);
   4745     const t = @typeInfo(@TypeOf(val));
   4746     switch (t) {
   4747         .void, .null, .comptime_int, .comptime_float => return,
   4748         .@"enum" => doNotOptimizeAway(@intFromEnum(val)),
   4749         .bool => doNotOptimizeAway(@intFromBool(val)),
   4750         .int => {
   4751             const bits = t.int.bits;
   4752             if (bits <= max_gp_register_bits and builtin.zig_backend != .stage2_c) {
   4753                 const val2 = @as(
   4754                     std.meta.Int(t.int.signedness, @max(8, std.math.ceilPowerOfTwoAssert(u16, bits))),
   4755                     val,
   4756                 );
   4757                 asm volatile (""
   4758                     :
   4759                     : [_] "r" (val2),
   4760                 );
   4761             } else doNotOptimizeAway(&val);
   4762         },
   4763         .float => {
   4764             // https://github.com/llvm/llvm-project/issues/159200
   4765             if ((t.float.bits == 32 or t.float.bits == 64) and builtin.zig_backend != .stage2_c and !builtin.cpu.arch.isLoongArch()) {
   4766                 asm volatile (""
   4767                     :
   4768                     : [_] "rm" (val),
   4769                 );
   4770             } else doNotOptimizeAway(&val);
   4771         },
   4772         .pointer => {
   4773             if (builtin.zig_backend == .stage2_c) {
   4774                 doNotOptimizeAwayC(val);
   4775             } else {
   4776                 asm volatile (""
   4777                     :
   4778                     : [_] "m" (val),
   4779                     : .{ .memory = true });
   4780             }
   4781         },
   4782         .array => {
   4783             if (t.array.len * @sizeOf(t.array.child) <= 64) {
   4784                 for (val) |v| doNotOptimizeAway(v);
   4785             } else doNotOptimizeAway(&val);
   4786         },
   4787         else => doNotOptimizeAway(&val),
   4788     }
   4789 }
   4790 
   4791 /// .stage2_c doesn't support asm blocks yet, so use volatile stores instead
   4792 var deopt_target: if (builtin.zig_backend == .stage2_c) u8 else void = undefined;
   4793 fn doNotOptimizeAwayC(ptr: anytype) void {
   4794     const dest = @as(*volatile u8, @ptrCast(&deopt_target));
   4795     for (asBytes(ptr)) |b| {
   4796         dest.* = b;
   4797     }
   4798     dest.* = 0;
   4799 }
   4800 
   4801 test doNotOptimizeAway {
   4802     comptime doNotOptimizeAway("test");
   4803 
   4804     doNotOptimizeAway(null);
   4805     doNotOptimizeAway(true);
   4806     doNotOptimizeAway(0);
   4807     doNotOptimizeAway(0.0);
   4808     doNotOptimizeAway(@as(u1, 0));
   4809     doNotOptimizeAway(@as(u3, 0));
   4810     doNotOptimizeAway(@as(u8, 0));
   4811     doNotOptimizeAway(@as(u16, 0));
   4812     doNotOptimizeAway(@as(u32, 0));
   4813     doNotOptimizeAway(@as(u64, 0));
   4814     doNotOptimizeAway(@as(u128, 0));
   4815     doNotOptimizeAway(@as(u13, 0));
   4816     doNotOptimizeAway(@as(u37, 0));
   4817     doNotOptimizeAway(@as(u96, 0));
   4818     doNotOptimizeAway(@as(u200, 0));
   4819     doNotOptimizeAway(@as(f32, 0.0));
   4820     doNotOptimizeAway(@as(f64, 0.0));
   4821     doNotOptimizeAway([_]u8{0} ** 4);
   4822     doNotOptimizeAway([_]u8{0} ** 100);
   4823     doNotOptimizeAway(@as(std.builtin.Endian, .little));
   4824 }
   4825 
   4826 test alignForward {
   4827     try testing.expect(alignForward(usize, 1, 1) == 1);
   4828     try testing.expect(alignForward(usize, 2, 1) == 2);
   4829     try testing.expect(alignForward(usize, 1, 2) == 2);
   4830     try testing.expect(alignForward(usize, 2, 2) == 2);
   4831     try testing.expect(alignForward(usize, 3, 2) == 4);
   4832     try testing.expect(alignForward(usize, 4, 2) == 4);
   4833     try testing.expect(alignForward(usize, 7, 8) == 8);
   4834     try testing.expect(alignForward(usize, 8, 8) == 8);
   4835     try testing.expect(alignForward(usize, 9, 8) == 16);
   4836     try testing.expect(alignForward(usize, 15, 8) == 16);
   4837     try testing.expect(alignForward(usize, 16, 8) == 16);
   4838     try testing.expect(alignForward(usize, 17, 8) == 24);
   4839 }
   4840 
   4841 /// Round an address down to the previous (or current) aligned address.
   4842 /// Unlike `alignBackward`, `alignment` can be any positive number, not just a power of 2.
   4843 pub fn alignBackwardAnyAlign(comptime T: type, addr: T, alignment: T) T {
   4844     if (isValidAlignGeneric(T, alignment))
   4845         return alignBackward(T, addr, alignment);
   4846     assert(alignment != 0);
   4847     return addr - @mod(addr, alignment);
   4848 }
   4849 
   4850 /// Round an address down to the previous (or current) aligned address.
   4851 /// The alignment must be a power of 2 and greater than 0.
   4852 pub fn alignBackward(comptime T: type, addr: T, alignment: T) T {
   4853     assert(isValidAlignGeneric(T, alignment));
   4854     // 000010000 // example alignment
   4855     // 000001111 // subtract 1
   4856     // 111110000 // binary not
   4857     return addr & ~(alignment - 1);
   4858 }
   4859 
   4860 /// Returns whether `alignment` is a valid alignment, meaning it is
   4861 /// a positive power of 2.
   4862 pub fn isValidAlign(alignment: usize) bool {
   4863     return isValidAlignGeneric(usize, alignment);
   4864 }
   4865 
   4866 /// Returns whether `alignment` is a valid alignment, meaning it is
   4867 /// a positive power of 2.
   4868 pub fn isValidAlignGeneric(comptime T: type, alignment: T) bool {
   4869     return alignment > 0 and std.math.isPowerOfTwo(alignment);
   4870 }
   4871 
   4872 /// Returns true if i is aligned to the given alignment.
   4873 /// Works with any positive alignment value, not just powers of 2.
   4874 /// For power-of-2 alignments, `isAligned` is more efficient.
   4875 pub fn isAlignedAnyAlign(i: usize, alignment: usize) bool {
   4876     if (isValidAlign(alignment))
   4877         return isAligned(i, alignment);
   4878     assert(alignment != 0);
   4879     return 0 == @mod(i, alignment);
   4880 }
   4881 
   4882 /// Returns true if addr is aligned to 2^log2_alignment.
   4883 /// More efficient than `isAligned` when alignment is known to be a power of 2.
   4884 /// log2_alignment must be < @bitSizeOf(usize).
   4885 pub fn isAlignedLog2(addr: usize, log2_alignment: u8) bool {
   4886     return @ctz(addr) >= log2_alignment;
   4887 }
   4888 
   4889 /// Given an address and an alignment, return true if the address is a multiple of the alignment
   4890 /// The alignment must be a power of 2 and greater than 0.
   4891 pub fn isAligned(addr: usize, alignment: usize) bool {
   4892     return isAlignedGeneric(u64, addr, alignment);
   4893 }
   4894 
   4895 /// Generic version of `isAligned` that works with any integer type.
   4896 /// Returns true if addr is aligned to the given alignment.
   4897 /// Alignment must be a power of 2 and greater than 0.
   4898 pub fn isAlignedGeneric(comptime T: type, addr: T, alignment: T) bool {
   4899     return alignBackward(T, addr, alignment) == addr;
   4900 }
   4901 
   4902 test isAligned {
   4903     try testing.expect(isAligned(0, 4));
   4904     try testing.expect(isAligned(1, 1));
   4905     try testing.expect(isAligned(2, 1));
   4906     try testing.expect(isAligned(2, 2));
   4907     try testing.expect(!isAligned(2, 4));
   4908     try testing.expect(isAligned(3, 1));
   4909     try testing.expect(!isAligned(3, 2));
   4910     try testing.expect(!isAligned(3, 4));
   4911     try testing.expect(isAligned(4, 4));
   4912     try testing.expect(isAligned(4, 2));
   4913     try testing.expect(isAligned(4, 1));
   4914     try testing.expect(!isAligned(4, 8));
   4915     try testing.expect(!isAligned(4, 16));
   4916 }
   4917 
   4918 test "freeing empty string with null-terminated sentinel" {
   4919     const empty_string = try testing.allocator.dupeZ(u8, "");
   4920     testing.allocator.free(empty_string);
   4921 }
   4922 
   4923 /// Returns a slice with the given new alignment,
   4924 /// all other pointer attributes copied from `AttributeSource`.
   4925 fn AlignedSlice(comptime AttributeSource: type, comptime new_alignment: usize) type {
   4926     const ptr = @typeInfo(AttributeSource).pointer;
   4927     return @Pointer(.slice, .{
   4928         .@"const" = ptr.is_const,
   4929         .@"volatile" = ptr.is_volatile,
   4930         .@"allowzero" = ptr.is_allowzero,
   4931         .@"align" = new_alignment,
   4932         .@"addrspace" = ptr.address_space,
   4933     }, ptr.child, null);
   4934 }
   4935 
   4936 /// Returns the largest slice in the given bytes that conforms to the new alignment,
   4937 /// or `null` if the given bytes contain no conforming address.
   4938 pub fn alignInBytes(bytes: []u8, comptime new_alignment: usize) ?[]align(new_alignment) u8 {
   4939     const begin_address = @intFromPtr(bytes.ptr);
   4940     const end_address = begin_address + bytes.len;
   4941 
   4942     const begin_address_aligned = mem.alignForward(usize, begin_address, new_alignment);
   4943     const new_length = std.math.sub(usize, end_address, begin_address_aligned) catch |e| switch (e) {
   4944         error.Overflow => return null,
   4945     };
   4946     const alignment_offset = begin_address_aligned - begin_address;
   4947     return @alignCast(bytes[alignment_offset .. alignment_offset + new_length]);
   4948 }
   4949 
   4950 /// Returns the largest sub-slice within the given slice that conforms to the new alignment,
   4951 /// or `null` if the given slice contains no conforming address.
   4952 pub fn alignInSlice(slice: anytype, comptime new_alignment: usize) ?AlignedSlice(@TypeOf(slice), new_alignment) {
   4953     const bytes = sliceAsBytes(slice);
   4954     const aligned_bytes = alignInBytes(bytes, new_alignment) orelse return null;
   4955 
   4956     const Element = @TypeOf(slice[0]);
   4957     const slice_length_bytes = aligned_bytes.len - (aligned_bytes.len % @sizeOf(Element));
   4958     const aligned_slice = bytesAsSlice(Element, aligned_bytes[0..slice_length_bytes]);
   4959     return @alignCast(aligned_slice);
   4960 }
   4961 
   4962 test "read/write(Var)PackedInt" {
   4963     switch (builtin.cpu.arch) {
   4964         // This test generates too much code to execute on WASI.
   4965         // LLVM backend fails with "too many locals: locals exceed maximum"
   4966         .wasm32, .wasm64 => return error.SkipZigTest,
   4967         else => {},
   4968     }
   4969 
   4970     const foreign_endian: Endian = if (native_endian == .big) .little else .big;
   4971     const expect = std.testing.expect;
   4972     var prng = std.Random.DefaultPrng.init(1234);
   4973     const random = prng.random();
   4974 
   4975     @setEvalBranchQuota(10_000);
   4976     inline for ([_]type{ u8, u16, u32, u128 }) |BackingType| {
   4977         for ([_]BackingType{
   4978             @as(BackingType, 0), // all zeros
   4979             -%@as(BackingType, 1), // all ones
   4980             random.int(BackingType), // random
   4981             random.int(BackingType), // random
   4982             random.int(BackingType), // random
   4983         }) |init_value| {
   4984             const uTs = [_]type{ u1, u3, u7, u8, u9, u10, u15, u16, u86 };
   4985             const iTs = [_]type{ i1, i3, i7, i8, i9, i10, i15, i16, i86 };
   4986             inline for (uTs ++ iTs) |PackedType| {
   4987                 if (@bitSizeOf(PackedType) > @bitSizeOf(BackingType))
   4988                     continue;
   4989 
   4990                 const iPackedType = std.meta.Int(.signed, @bitSizeOf(PackedType));
   4991                 const uPackedType = std.meta.Int(.unsigned, @bitSizeOf(PackedType));
   4992                 const Log2T = std.math.Log2Int(BackingType);
   4993 
   4994                 const offset_at_end = @bitSizeOf(BackingType) - @bitSizeOf(PackedType);
   4995                 for ([_]usize{ 0, 1, 7, 8, 9, 10, 15, 16, 86, offset_at_end }) |offset| {
   4996                     if (offset > offset_at_end or offset == @bitSizeOf(BackingType))
   4997                         continue;
   4998 
   4999                     for ([_]PackedType{
   5000                         ~@as(PackedType, 0), // all ones: -1 iN / maxInt uN
   5001                         @as(PackedType, 0), // all zeros: 0 iN / 0 uN
   5002                         @as(PackedType, @bitCast(@as(iPackedType, math.maxInt(iPackedType)))), // maxInt iN
   5003                         @as(PackedType, @bitCast(@as(iPackedType, math.minInt(iPackedType)))), // maxInt iN
   5004                         random.int(PackedType), // random
   5005                         random.int(PackedType), // random
   5006                     }) |write_value| {
   5007                         { // Fixed-size Read/Write (Native-endian)
   5008 
   5009                             // Initialize Value
   5010                             var value: BackingType = init_value;
   5011 
   5012                             // Read
   5013                             const read_value1 = readPackedInt(PackedType, asBytes(&value), offset, native_endian);
   5014                             try expect(read_value1 == @as(PackedType, @bitCast(@as(uPackedType, @truncate(value >> @as(Log2T, @intCast(offset)))))));
   5015 
   5016                             // Write
   5017                             writePackedInt(PackedType, asBytes(&value), offset, write_value, native_endian);
   5018                             try expect(write_value == @as(PackedType, @bitCast(@as(uPackedType, @truncate(value >> @as(Log2T, @intCast(offset)))))));
   5019 
   5020                             // Read again
   5021                             const read_value2 = readPackedInt(PackedType, asBytes(&value), offset, native_endian);
   5022                             try expect(read_value2 == write_value);
   5023 
   5024                             // Verify bits outside of the target integer are unmodified
   5025                             const diff_bits = init_value ^ value;
   5026                             if (offset != offset_at_end)
   5027                                 try expect(diff_bits >> @as(Log2T, @intCast(offset + @bitSizeOf(PackedType))) == 0);
   5028                             if (offset != 0)
   5029                                 try expect(diff_bits << @as(Log2T, @intCast(@bitSizeOf(BackingType) - offset)) == 0);
   5030                         }
   5031 
   5032                         { // Fixed-size Read/Write (Foreign-endian)
   5033 
   5034                             // Initialize Value
   5035                             var value: BackingType = @byteSwap(init_value);
   5036 
   5037                             // Read
   5038                             const read_value1 = readPackedInt(PackedType, asBytes(&value), offset, foreign_endian);
   5039                             try expect(read_value1 == @as(PackedType, @bitCast(@as(uPackedType, @truncate(@byteSwap(value) >> @as(Log2T, @intCast(offset)))))));
   5040 
   5041                             // Write
   5042                             writePackedInt(PackedType, asBytes(&value), offset, write_value, foreign_endian);
   5043                             try expect(write_value == @as(PackedType, @bitCast(@as(uPackedType, @truncate(@byteSwap(value) >> @as(Log2T, @intCast(offset)))))));
   5044 
   5045                             // Read again
   5046                             const read_value2 = readPackedInt(PackedType, asBytes(&value), offset, foreign_endian);
   5047                             try expect(read_value2 == write_value);
   5048 
   5049                             // Verify bits outside of the target integer are unmodified
   5050                             const diff_bits = init_value ^ @byteSwap(value);
   5051                             if (offset != offset_at_end)
   5052                                 try expect(diff_bits >> @as(Log2T, @intCast(offset + @bitSizeOf(PackedType))) == 0);
   5053                             if (offset != 0)
   5054                                 try expect(diff_bits << @as(Log2T, @intCast(@bitSizeOf(BackingType) - offset)) == 0);
   5055                         }
   5056 
   5057                         const signedness = @typeInfo(PackedType).int.signedness;
   5058                         const NextPowerOfTwoInt = std.meta.Int(signedness, try comptime std.math.ceilPowerOfTwo(u16, @bitSizeOf(PackedType)));
   5059                         const ui64 = std.meta.Int(signedness, 64);
   5060                         inline for ([_]type{ PackedType, NextPowerOfTwoInt, ui64 }) |U| {
   5061                             { // Variable-size Read/Write (Native-endian)
   5062 
   5063                                 if (@bitSizeOf(U) < @bitSizeOf(PackedType))
   5064                                     continue;
   5065 
   5066                                 // Initialize Value
   5067                                 var value: BackingType = init_value;
   5068 
   5069                                 // Read
   5070                                 const read_value1 = readVarPackedInt(U, asBytes(&value), offset, @bitSizeOf(PackedType), native_endian, signedness);
   5071                                 try expect(read_value1 == @as(PackedType, @bitCast(@as(uPackedType, @truncate(value >> @as(Log2T, @intCast(offset)))))));
   5072 
   5073                                 // Write
   5074                                 writeVarPackedInt(asBytes(&value), offset, @bitSizeOf(PackedType), @as(U, write_value), native_endian);
   5075                                 try expect(write_value == @as(PackedType, @bitCast(@as(uPackedType, @truncate(value >> @as(Log2T, @intCast(offset)))))));
   5076 
   5077                                 // Read again
   5078                                 const read_value2 = readVarPackedInt(U, asBytes(&value), offset, @bitSizeOf(PackedType), native_endian, signedness);
   5079                                 try expect(read_value2 == write_value);
   5080 
   5081                                 // Verify bits outside of the target integer are unmodified
   5082                                 const diff_bits = init_value ^ value;
   5083                                 if (offset != offset_at_end)
   5084                                     try expect(diff_bits >> @as(Log2T, @intCast(offset + @bitSizeOf(PackedType))) == 0);
   5085                                 if (offset != 0)
   5086                                     try expect(diff_bits << @as(Log2T, @intCast(@bitSizeOf(BackingType) - offset)) == 0);
   5087                             }
   5088 
   5089                             { // Variable-size Read/Write (Foreign-endian)
   5090 
   5091                                 if (@bitSizeOf(U) < @bitSizeOf(PackedType))
   5092                                     continue;
   5093 
   5094                                 // Initialize Value
   5095                                 var value: BackingType = @byteSwap(init_value);
   5096 
   5097                                 // Read
   5098                                 const read_value1 = readVarPackedInt(U, asBytes(&value), offset, @bitSizeOf(PackedType), foreign_endian, signedness);
   5099                                 try expect(read_value1 == @as(PackedType, @bitCast(@as(uPackedType, @truncate(@byteSwap(value) >> @as(Log2T, @intCast(offset)))))));
   5100 
   5101                                 // Write
   5102                                 writeVarPackedInt(asBytes(&value), offset, @bitSizeOf(PackedType), @as(U, write_value), foreign_endian);
   5103                                 try expect(write_value == @as(PackedType, @bitCast(@as(uPackedType, @truncate(@byteSwap(value) >> @as(Log2T, @intCast(offset)))))));
   5104 
   5105                                 // Read again
   5106                                 const read_value2 = readVarPackedInt(U, asBytes(&value), offset, @bitSizeOf(PackedType), foreign_endian, signedness);
   5107                                 try expect(read_value2 == write_value);
   5108 
   5109                                 // Verify bits outside of the target integer are unmodified
   5110                                 const diff_bits = init_value ^ @byteSwap(value);
   5111                                 if (offset != offset_at_end)
   5112                                     try expect(diff_bits >> @as(Log2T, @intCast(offset + @bitSizeOf(PackedType))) == 0);
   5113                                 if (offset != 0)
   5114                                     try expect(diff_bits << @as(Log2T, @intCast(@bitSizeOf(BackingType) - offset)) == 0);
   5115                             }
   5116                         }
   5117                     }
   5118                 }
   5119             }
   5120         }
   5121     }
   5122 }