diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 4e6161b0ecb9..3cd0507bee95 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -806,9 +806,12 @@ fn eqlBytes(a: []const u8, b: []const u8) bool { return !Scan.isNotEqual(last_a_chunk, last_b_chunk); } +/// Deprecated in favor of `findDiff`. +pub const indexOfDiff = findDiff; + /// Compares two slices and returns the index of the first inequality. /// Returns null if the slices are equal. -pub fn indexOfDiff(comptime T: type, a: []const T, b: []const T) ?usize { +pub fn findDiff(comptime T: type, a: []const T, b: []const T) ?usize { const shortest = @min(a.len, b.len); if (a.ptr == b.ptr) return if (a.len == b.len) null else shortest; @@ -817,12 +820,12 @@ pub fn indexOfDiff(comptime T: type, a: []const T, b: []const T) ?usize { return if (a.len == b.len) null else shortest; } -test indexOfDiff { - try testing.expectEqual(indexOfDiff(u8, "one", "one"), null); - try testing.expectEqual(indexOfDiff(u8, "one two", "one"), 3); - try testing.expectEqual(indexOfDiff(u8, "one", "one two"), 3); - try testing.expectEqual(indexOfDiff(u8, "one twx", "one two"), 6); - try testing.expectEqual(indexOfDiff(u8, "xne", "one"), 0); +test findDiff { + try testing.expectEqual(findDiff(u8, "one", "one"), null); + try testing.expectEqual(findDiff(u8, "one two", "one"), 3); + try testing.expectEqual(findDiff(u8, "one", "one two"), 3); + try testing.expectEqual(findDiff(u8, "one twx", "one two"), 6); + try testing.expectEqual(findDiff(u8, "xne", "one"), 0); } /// Takes a sentinel-terminated pointer and returns a slice preserving pointer attributes. @@ -1014,7 +1017,7 @@ fn lenSliceTo(ptr: anytype, comptime end: std.meta.Elem(@TypeOf(ptr))) usize { return indexOfSentinel(array_info.child, end, ptr); } } - return indexOfScalar(array_info.child, ptr, end) orelse array_info.len; + return findScalar(array_info.child, ptr, end) orelse array_info.len; }, else => {}, }, @@ -1039,7 +1042,7 @@ fn lenSliceTo(ptr: anytype, comptime end: std.meta.Elem(@TypeOf(ptr))) usize { return indexOfSentinel(ptr_info.child, s, ptr); } } - return indexOfScalar(ptr_info.child, ptr, end) orelse ptr.len; + return findScalar(ptr_info.child, ptr, end) orelse ptr.len; }, }, else => {}, @@ -1109,9 +1112,12 @@ test len { try testing.expect(len(c_ptr) == 2); } +/// Deprecated in favor of `findSentinel`. +pub const indexOfSentinel = findSentinel; + /// Returns the index of the sentinel value in a sentinel-terminated pointer. /// Linear search through memory until the sentinel is found. -pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]const T) usize { +pub fn findSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]const T) usize { var i: usize = 0; if (use_vectors_for_comparison and @@ -1223,7 +1229,7 @@ pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool { /// Remove a set of values from the beginning of a slice. pub fn trimStart(comptime T: type, slice: []const T, values_to_strip: []const T) []const T { var begin: usize = 0; - while (begin < slice.len and indexOfScalar(T, values_to_strip, slice[begin]) != null) : (begin += 1) {} + while (begin < slice.len and findScalar(T, values_to_strip, slice[begin]) != null) : (begin += 1) {} return slice[begin..]; } @@ -1237,7 +1243,7 @@ pub const trimLeft = trimStart; /// Remove a set of values from the end of a slice. pub fn trimEnd(comptime T: type, slice: []const T, values_to_strip: []const T) []const T { var end: usize = slice.len; - while (end > 0 and indexOfScalar(T, values_to_strip, slice[end - 1]) != null) : (end -= 1) {} + while (end > 0 and findScalar(T, values_to_strip, slice[end - 1]) != null) : (end -= 1) {} return slice[0..end]; } @@ -1252,8 +1258,8 @@ pub const trimRight = trimEnd; pub fn trim(comptime T: type, slice: []const T, values_to_strip: []const T) []const T { var begin: usize = 0; var end: usize = slice.len; - while (begin < end and indexOfScalar(T, values_to_strip, slice[begin]) != null) : (begin += 1) {} - while (end > begin and indexOfScalar(T, values_to_strip, slice[end - 1]) != null) : (end -= 1) {} + while (begin < end and findScalar(T, values_to_strip, slice[begin]) != null) : (begin += 1) {} + while (end > begin and findScalar(T, values_to_strip, slice[end - 1]) != null) : (end -= 1) {} return slice[begin..end]; } @@ -1262,13 +1268,19 @@ test trim { try testing.expectEqualSlices(u8, "foo", trim(u8, "foo", " \n")); } +/// Deprecated in favor of `findScalar`. +pub const indexOfScalar = findScalar; + /// Linear search for the index of a scalar value inside a slice. -pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) ?usize { +pub fn findScalar(comptime T: type, slice: []const T, value: T) ?usize { return indexOfScalarPos(T, slice, 0, value); } +/// Deprecated in favor of `findScalarLast`. +pub const lastIndexOfScalar = findScalarLast; + /// Linear search for the last index of a scalar value inside a slice. -pub fn lastIndexOfScalar(comptime T: type, slice: []const T, value: T) ?usize { +pub fn findScalarLast(comptime T: type, slice: []const T, value: T) ?usize { var i: usize = slice.len; while (i != 0) { i -= 1; @@ -1277,9 +1289,12 @@ pub fn lastIndexOfScalar(comptime T: type, slice: []const T, value: T) ?usize { return null; } +/// Deprecated in favor of `findScalarPos`. +pub const indexOfScalarPos = findScalarPos; + /// Linear search for the index of a scalar value inside a slice, starting from a given position. /// Returns null if the value is not found. -pub fn indexOfScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize { +pub fn findScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize { if (start_index >= slice.len) return null; var i: usize = start_index; @@ -1355,15 +1370,21 @@ test indexOfScalarPos { } } +/// Deprecated in favor of `findAny`. +pub const indexOfAny = findAny; + /// Linear search for the index of any value in the provided list inside a slice. /// Returns null if no values are found. -pub fn indexOfAny(comptime T: type, slice: []const T, values: []const T) ?usize { +pub fn findAny(comptime T: type, slice: []const T, values: []const T) ?usize { return indexOfAnyPos(T, slice, 0, values); } +/// Deprecated in favor of `findLastAny`. +pub const lastIndexOfAny = findLastAny; + /// Linear search for the last index of any value in the provided list inside a slice. /// Returns null if no values are found. -pub fn lastIndexOfAny(comptime T: type, slice: []const T, values: []const T) ?usize { +pub fn findLastAny(comptime T: type, slice: []const T, values: []const T) ?usize { var i: usize = slice.len; while (i != 0) { i -= 1; @@ -1374,9 +1395,12 @@ pub fn lastIndexOfAny(comptime T: type, slice: []const T, values: []const T) ?us return null; } +/// Deprecated in favor of `findAnyPos`. +pub const indexOfAnyPos = findAnyPos; + /// Linear search for the index of any value in the provided list inside a slice, starting from a given position. /// Returns null if no values are found. -pub fn indexOfAnyPos(comptime T: type, slice: []const T, start_index: usize, values: []const T) ?usize { +pub fn findAnyPos(comptime T: type, slice: []const T, start_index: usize, values: []const T) ?usize { if (start_index >= slice.len) return null; for (slice[start_index..], start_index..) |c, i| { for (values) |value| { @@ -1386,17 +1410,34 @@ pub fn indexOfAnyPos(comptime T: type, slice: []const T, start_index: usize, val return null; } +/// Deprecated in favor of `findNone`. +pub const indexOfNone = findNone; + /// Find the first item in `slice` which is not contained in `values`. /// /// Comparable to `strspn` in the C standard library. -pub fn indexOfNone(comptime T: type, slice: []const T, values: []const T) ?usize { +pub fn findNone(comptime T: type, slice: []const T, values: []const T) ?usize { return indexOfNonePos(T, slice, 0, values); } +test findNone { + try testing.expect(findNone(u8, "abc123", "123").? == 0); + try testing.expect(findLastNone(u8, "abc123", "123").? == 2); + try testing.expect(findNone(u8, "123abc", "123").? == 3); + try testing.expect(findLastNone(u8, "123abc", "123").? == 5); + try testing.expect(findNone(u8, "123123", "123") == null); + try testing.expect(findNone(u8, "333333", "123") == null); + + try testing.expect(indexOfNonePos(u8, "abc123", 3, "321") == null); +} + +/// Deprecated in favor of `findLastNone`. +pub const lastIndexOfNone = findLastNone; + /// Find the last item in `slice` which is not contained in `values`. /// /// Like `strspn` in the C standard library, but searches from the end. -pub fn lastIndexOfNone(comptime T: type, slice: []const T, values: []const T) ?usize { +pub fn findLastNone(comptime T: type, slice: []const T, values: []const T) ?usize { var i: usize = slice.len; outer: while (i != 0) { i -= 1; @@ -1408,11 +1449,13 @@ pub fn lastIndexOfNone(comptime T: type, slice: []const T, values: []const T) ?u return null; } +pub const indexOfNonePos = findNonePos; + /// Find the first item in `slice[start_index..]` which is not contained in `values`. /// The returned index will be relative to the start of `slice`, and never less than `start_index`. /// /// Comparable to `strspn` in the C standard library. -pub fn indexOfNonePos(comptime T: type, slice: []const T, start_index: usize, values: []const T) ?usize { +pub fn findNonePos(comptime T: type, slice: []const T, start_index: usize, values: []const T) ?usize { if (start_index >= slice.len) return null; outer: for (slice[start_index..], start_index..) |c, i| { for (values) |value| { @@ -1423,29 +1466,24 @@ pub fn indexOfNonePos(comptime T: type, slice: []const T, start_index: usize, va return null; } -test indexOfNone { - try testing.expect(indexOfNone(u8, "abc123", "123").? == 0); - try testing.expect(lastIndexOfNone(u8, "abc123", "123").? == 2); - try testing.expect(indexOfNone(u8, "123abc", "123").? == 3); - try testing.expect(lastIndexOfNone(u8, "123abc", "123").? == 5); - try testing.expect(indexOfNone(u8, "123123", "123") == null); - try testing.expect(indexOfNone(u8, "333333", "123") == null); - - try testing.expect(indexOfNonePos(u8, "abc123", 3, "321") == null); -} +/// Deprecated in favor of `find`. +pub const indexOf = find; /// Search for needle in haystack and return the index of the first occurrence. /// Uses Boyer-Moore-Horspool algorithm on large inputs; linear search on small inputs. /// Returns null if needle is not found. -pub fn indexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize { +pub fn find(comptime T: type, haystack: []const T, needle: []const T) ?usize { return indexOfPos(T, haystack, 0, needle); } +/// Deprecated in favor of `findLastLinear`. +pub const lastIndexOfLinear = findLastLinear; + /// Find the index in a slice of a sub-slice, searching from the end backwards. /// To start looking at a different index, slice the haystack first. /// Consider using `lastIndexOf` instead of this, which will automatically use a /// more sophisticated algorithm on larger inputs. -pub fn lastIndexOfLinear(comptime T: type, haystack: []const T, needle: []const T) ?usize { +pub fn findLastLinear(comptime T: type, haystack: []const T, needle: []const T) ?usize { if (needle.len > haystack.len) return null; var i: usize = haystack.len - needle.len; while (true) : (i -= 1) { @@ -1454,9 +1492,11 @@ pub fn lastIndexOfLinear(comptime T: type, haystack: []const T, needle: []const } } +pub const indexOfPosLinear = findPosLinear; + /// Consider using `indexOfPos` instead of this, which will automatically use a /// more sophisticated algorithm on larger inputs. -pub fn indexOfPosLinear(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize { +pub fn findPosLinear(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize { if (needle.len > haystack.len) return null; var i: usize = start_index; const end = haystack.len - needle.len; @@ -1466,24 +1506,24 @@ pub fn indexOfPosLinear(comptime T: type, haystack: []const T, start_index: usiz return null; } -test indexOfPosLinear { - try testing.expectEqual(0, indexOfPosLinear(u8, "", 0, "")); - try testing.expectEqual(0, indexOfPosLinear(u8, "123", 0, "")); +test findPosLinear { + try testing.expectEqual(0, findPosLinear(u8, "", 0, "")); + try testing.expectEqual(0, findPosLinear(u8, "123", 0, "")); - try testing.expectEqual(null, indexOfPosLinear(u8, "", 0, "1")); - try testing.expectEqual(0, indexOfPosLinear(u8, "1", 0, "1")); - try testing.expectEqual(null, indexOfPosLinear(u8, "2", 0, "1")); - try testing.expectEqual(1, indexOfPosLinear(u8, "21", 0, "1")); - try testing.expectEqual(null, indexOfPosLinear(u8, "222", 0, "1")); + try testing.expectEqual(null, findPosLinear(u8, "", 0, "1")); + try testing.expectEqual(0, findPosLinear(u8, "1", 0, "1")); + try testing.expectEqual(null, findPosLinear(u8, "2", 0, "1")); + try testing.expectEqual(1, findPosLinear(u8, "21", 0, "1")); + try testing.expectEqual(null, findPosLinear(u8, "222", 0, "1")); - try testing.expectEqual(null, indexOfPosLinear(u8, "", 0, "12")); - try testing.expectEqual(null, indexOfPosLinear(u8, "1", 0, "12")); - try testing.expectEqual(null, indexOfPosLinear(u8, "2", 0, "12")); - try testing.expectEqual(0, indexOfPosLinear(u8, "12", 0, "12")); - try testing.expectEqual(null, indexOfPosLinear(u8, "21", 0, "12")); - try testing.expectEqual(1, indexOfPosLinear(u8, "212", 0, "12")); - try testing.expectEqual(0, indexOfPosLinear(u8, "122", 0, "12")); - try testing.expectEqual(1, indexOfPosLinear(u8, "212112", 0, "12")); + try testing.expectEqual(null, findPosLinear(u8, "", 0, "12")); + try testing.expectEqual(null, findPosLinear(u8, "1", 0, "12")); + try testing.expectEqual(null, findPosLinear(u8, "2", 0, "12")); + try testing.expectEqual(0, findPosLinear(u8, "12", 0, "12")); + try testing.expectEqual(null, findPosLinear(u8, "21", 0, "12")); + try testing.expectEqual(1, findPosLinear(u8, "212", 0, "12")); + try testing.expectEqual(0, findPosLinear(u8, "122", 0, "12")); + try testing.expectEqual(1, findPosLinear(u8, "212112", 0, "12")); } fn boyerMooreHorspoolPreprocessReverse(pattern: []const u8, table: *[256]usize) void { @@ -1512,11 +1552,14 @@ fn boyerMooreHorspoolPreprocess(pattern: []const u8, table: *[256]usize) void { } } +/// Deprecated in favor of `find`. +pub const lastIndexOf = findLast; + /// Find the index in a slice of a sub-slice, searching from the end backwards. /// To start looking at a different index, slice the haystack first. /// Uses the Reverse Boyer-Moore-Horspool algorithm on large inputs; /// `lastIndexOfLinear` on small inputs. -pub fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize { +pub fn findLast(comptime T: type, haystack: []const T, needle: []const T) ?usize { if (needle.len > haystack.len) return null; if (needle.len == 0) return haystack.len; @@ -1542,8 +1585,11 @@ pub fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?us return null; } +/// Deprecated in favor of `findPos`. +pub const indexOfPos = findPos; + /// Uses Boyer-Moore-Horspool algorithm on large inputs; `indexOfPosLinear` on small inputs. -pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize { +pub fn findPos(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize { if (needle.len > haystack.len) return null; if (needle.len < 2) { if (needle.len == 0) return start_index; @@ -1593,7 +1639,7 @@ test indexOf { try testing.expect(indexOf(u8, "foo foo", "foo").? == 0); try testing.expect(lastIndexOf(u8, "foo foo", "foo").? == 4); try testing.expect(lastIndexOfAny(u8, "boo, cat", "abo").? == 6); - try testing.expect(lastIndexOfScalar(u8, "boo", 'o').? == 2); + try testing.expect(findScalarLast(u8, "boo", 'o').? == 2); } test "indexOf multibyte" { @@ -3079,6 +3125,101 @@ test endsWith { try testing.expect(!endsWith(u8, "Bob", "Bo")); } +/// If `slice` starts with `prefix`, returns the rest of `slice` starting at `prefix.len`. +pub fn cutPrefix(comptime T: type, slice: []const T, prefix: []const T) ?[]const T { + return if (startsWith(T, slice, prefix)) slice[prefix.len..] else null; +} + +test cutPrefix { + try testing.expectEqualStrings("foo", cutPrefix(u8, "--example=foo", "--example=").?); + try testing.expectEqual(null, cutPrefix(u8, "--example=foo", "-example=")); +} + +/// If `slice` ends with `suffix`, returns `slice` from beginning to start of `suffix`. +pub fn cutSuffix(comptime T: type, slice: []const T, suffix: []const T) ?[]const T { + return if (endsWith(T, slice, suffix)) slice[0 .. slice.len - suffix.len] else null; +} + +test cutSuffix { + try testing.expectEqualStrings("foo", cutSuffix(u8, "foobar", "bar").?); + try testing.expectEqual(null, cutSuffix(u8, "foobar", "baz")); +} + +/// Returns slice of `haystack` before and after first occurrence of `needle`, +/// or `null` if not found. +/// +/// See also: +/// * `cutScalar` +/// * `split` +/// * `tokenizeAny` +pub fn cut(comptime T: type, haystack: []const T, needle: []const T) ?struct { []const T, []const T } { + const index = find(T, haystack, needle) orelse return null; + return .{ haystack[0..index], haystack[index + needle.len ..] }; +} + +test cut { + try testing.expectEqual(null, cut(u8, "a b c", "B")); + const before, const after = cut(u8, "a be c", "be") orelse return error.TestFailed; + try testing.expectEqualStrings("a ", before); + try testing.expectEqualStrings(" c", after); +} + +/// Returns slice of `haystack` before and after last occurrence of `needle`, +/// or `null` if not found. +/// +/// See also: +/// * `cut` +/// * `cutScalarLast` +pub fn cutLast(comptime T: type, haystack: []const T, needle: []const T) ?struct { []const T, []const T } { + const index = findLast(T, haystack, needle) orelse return null; + return .{ haystack[0..index], haystack[index + needle.len ..] }; +} + +test cutLast { + try testing.expectEqual(null, cutLast(u8, "a b c", "B")); + const before, const after = cutLast(u8, "a be c be d", "be") orelse return error.TestFailed; + try testing.expectEqualStrings("a be c ", before); + try testing.expectEqualStrings(" d", after); +} + +/// Returns slice of `haystack` before and after first occurrence `needle`, or +/// `null` if not found. +/// +/// See also: +/// * `cut` +/// * `splitScalar` +/// * `tokenizeScalar` +pub fn cutScalar(comptime T: type, haystack: []const T, needle: T) ?struct { []const T, []const T } { + const index = findScalar(T, haystack, needle) orelse return null; + return .{ haystack[0..index], haystack[index + 1 ..] }; +} + +test cutScalar { + try testing.expectEqual(null, cutScalar(u8, "a b c", 'B')); + const before, const after = cutScalar(u8, "a b c", 'b') orelse return error.TestFailed; + try testing.expectEqualStrings("a ", before); + try testing.expectEqualStrings(" c", after); +} + +/// Returns slice of `haystack` before and after last occurrence of `needle`, +/// or `null` if not found. +/// +/// See also: +/// * `cut` +/// * `splitScalar` +/// * `tokenizeScalar` +pub fn cutScalarLast(comptime T: type, haystack: []const T, needle: T) ?struct { []const T, []const T } { + const index = findScalarLast(T, haystack, needle) orelse return null; + return .{ haystack[0..index], haystack[index + 1 ..] }; +} + +test cutScalarLast { + try testing.expectEqual(null, cutScalarLast(u8, "a b c", 'B')); + const before, const after = cutScalarLast(u8, "a b c b d", 'b') orelse return error.TestFailed; + try testing.expectEqualStrings("a b c ", before); + try testing.expectEqualStrings(" d", after); +} + /// Delimiter type for tokenization and splitting operations. pub const DelimiterType = enum { sequence, any, scalar }; @@ -3248,7 +3389,7 @@ pub fn SplitBackwardsIterator(comptime T: type, comptime delimiter_type: Delimit const start = if (switch (delimiter_type) { .sequence => lastIndexOf(T, self.buffer[0..end], self.delimiter), .any => lastIndexOfAny(T, self.buffer[0..end], self.delimiter), - .scalar => lastIndexOfScalar(T, self.buffer[0..end], self.delimiter), + .scalar => findScalarLast(T, self.buffer[0..end], self.delimiter), }) |delim_start| blk: { self.index = delim_start; break :blk delim_start + switch (delimiter_type) { @@ -3562,9 +3703,12 @@ test minMax { } } +/// Deprecated in favor of `findMin`. +pub const indexOfMin = findMin; + /// Returns the index of the smallest number in a slice. O(n). /// `slice` must not be empty. -pub fn indexOfMin(comptime T: type, slice: []const T) usize { +pub fn findMin(comptime T: type, slice: []const T) usize { assert(slice.len > 0); var best = slice[0]; var index: usize = 0; @@ -3577,15 +3721,17 @@ pub fn indexOfMin(comptime T: type, slice: []const T) usize { return index; } -test indexOfMin { - try testing.expectEqual(indexOfMin(u8, "abcdefg"), 0); - try testing.expectEqual(indexOfMin(u8, "bcdefga"), 6); - try testing.expectEqual(indexOfMin(u8, "a"), 0); +test findMin { + try testing.expectEqual(findMin(u8, "abcdefg"), 0); + try testing.expectEqual(findMin(u8, "bcdefga"), 6); + try testing.expectEqual(findMin(u8, "a"), 0); } +pub const indexOfMax = findMax; + /// Returns the index of the largest number in a slice. O(n). /// `slice` must not be empty. -pub fn indexOfMax(comptime T: type, slice: []const T) usize { +pub fn findMax(comptime T: type, slice: []const T) usize { assert(slice.len > 0); var best = slice[0]; var index: usize = 0; @@ -3598,16 +3744,19 @@ pub fn indexOfMax(comptime T: type, slice: []const T) usize { return index; } -test indexOfMax { - try testing.expectEqual(indexOfMax(u8, "abcdefg"), 6); - try testing.expectEqual(indexOfMax(u8, "gabcdef"), 0); - try testing.expectEqual(indexOfMax(u8, "a"), 0); +test findMax { + try testing.expectEqual(findMax(u8, "abcdefg"), 6); + try testing.expectEqual(findMax(u8, "gabcdef"), 0); + try testing.expectEqual(findMax(u8, "a"), 0); } +/// Deprecated in favor of `findMinMax`. +pub const indexOfMinMax = findMinMax; + /// Finds the indices of the smallest and largest number in a slice. O(n). /// Returns the indices of the smallest and largest numbers in that order. /// `slice` must not be empty. -pub fn indexOfMinMax(comptime T: type, slice: []const T) struct { usize, usize } { +pub fn findMinMax(comptime T: type, slice: []const T) struct { usize, usize } { assert(slice.len > 0); var minVal = slice[0]; var maxVal = slice[0]; @@ -3626,10 +3775,10 @@ pub fn indexOfMinMax(comptime T: type, slice: []const T) struct { usize, usize } return .{ minIdx, maxIdx }; } -test indexOfMinMax { - try testing.expectEqual(.{ 0, 6 }, indexOfMinMax(u8, "abcdefg")); - try testing.expectEqual(.{ 1, 0 }, indexOfMinMax(u8, "gabcdef")); - try testing.expectEqual(.{ 0, 0 }, indexOfMinMax(u8, "a")); +test findMinMax { + try testing.expectEqual(.{ 0, 6 }, findMinMax(u8, "abcdefg")); + try testing.expectEqual(.{ 1, 0 }, findMinMax(u8, "gabcdef")); + try testing.expectEqual(.{ 0, 0 }, findMinMax(u8, "a")); } /// Exchanges contents of two memory locations. diff --git a/src/main.zig b/src/main.zig index 9d43e47ea2db..dc4c569cfc0b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1037,10 +1037,9 @@ fn buildOutputType( var file_ext: ?Compilation.FileExt = null; args_loop: while (args_iter.next()) |arg| { - if (mem.startsWith(u8, arg, "@")) { + if (mem.cutPrefix(u8, arg, "@")) |resp_file_path| { // This is a "compiler response file". We must parse the file and treat its // contents as command line parameters. - const resp_file_path = arg[1..]; args_iter.resp_file = initArgIteratorResponseFile(arena, resp_file_path) catch |err| { fatal("unable to read response file '{s}': {s}", .{ resp_file_path, @errorName(err) }); }; @@ -1058,9 +1057,8 @@ fn buildOutputType( fatal("unexpected end-of-parameter mark: --", .{}); } } else if (mem.eql(u8, arg, "--dep")) { - var it = mem.splitScalar(u8, args_iter.nextOrFatal(), '='); - const key = it.first(); - const value = if (it.peek() != null) it.rest() else key; + const next_arg = args_iter.nextOrFatal(); + const key, const value = mem.cutScalar(u8, next_arg, '=') orelse .{ next_arg, next_arg }; if (mem.eql(u8, key, "std") and !mem.eql(u8, value, "std")) { fatal("unable to import as '{s}': conflicts with builtin module", .{ key, @@ -1077,10 +1075,8 @@ fn buildOutputType( .key = key, .value = value, }); - } else if (mem.startsWith(u8, arg, "-M")) { - var it = mem.splitScalar(u8, arg["-M".len..], '='); - const mod_name = it.first(); - const root_src_orig = if (it.peek() != null) it.rest() else null; + } else if (mem.cutPrefix(u8, arg, "-M")) |rest| { + const mod_name, const root_src_orig = mem.cutScalar(u8, rest, '=') orelse .{ rest, null }; try handleModArg( arena, mod_name, @@ -1111,8 +1107,8 @@ fn buildOutputType( } } else if (mem.eql(u8, arg, "-rcincludes")) { rc_includes = parseRcIncludes(args_iter.nextOrFatal()); - } else if (mem.startsWith(u8, arg, "-rcincludes=")) { - rc_includes = parseRcIncludes(arg["-rcincludes=".len..]); + } else if (mem.cutPrefix(u8, arg, "-rcincludes=")) |rest| { + rc_includes = parseRcIncludes(rest); } else if (mem.eql(u8, arg, "-rcflags")) { extra_rcflags.shrinkRetainingCapacity(0); while (true) { @@ -1122,9 +1118,9 @@ fn buildOutputType( if (mem.eql(u8, next_arg, "--")) break; try extra_rcflags.append(arena, next_arg); } - } else if (mem.startsWith(u8, arg, "-fstructured-cfg")) { + } else if (mem.eql(u8, arg, "-fstructured-cfg")) { mod_opts.structured_cfg = true; - } else if (mem.startsWith(u8, arg, "-fno-structured-cfg")) { + } else if (mem.eql(u8, arg, "-fno-structured-cfg")) { mod_opts.structured_cfg = false; } else if (mem.eql(u8, arg, "--color")) { const next_arg = args_iter.next() orelse { @@ -1133,8 +1129,7 @@ fn buildOutputType( color = std.meta.stringToEnum(Color, next_arg) orelse { fatal("expected [auto|on|off] after --color, found '{s}'", .{next_arg}); }; - } else if (mem.startsWith(u8, arg, "-j")) { - const str = arg["-j".len..]; + } else if (mem.cutPrefix(u8, arg, "-j")) |str| { const num = std.fmt.parseUnsigned(u32, str, 10) catch |err| { fatal("unable to parse jobs count '{s}': {s}", .{ str, @errorName(err), @@ -1148,8 +1143,8 @@ fn buildOutputType( subsystem = try parseSubSystem(args_iter.nextOrFatal()); } else if (mem.eql(u8, arg, "-O")) { mod_opts.optimize_mode = parseOptimizeMode(args_iter.nextOrFatal()); - } else if (mem.startsWith(u8, arg, "-fentry=")) { - entry = .{ .named = arg["-fentry=".len..] }; + } else if (mem.cutPrefix(u8, arg, "-fentry=")) |rest| { + entry = .{ .named = rest }; } else if (mem.eql(u8, arg, "--force_undefined")) { try force_undefined_symbols.put(arena, args_iter.nextOrFatal(), {}); } else if (mem.eql(u8, arg, "--discard-all")) { @@ -1176,8 +1171,7 @@ fn buildOutputType( try create_module.frameworks.put(arena, args_iter.nextOrFatal(), .{ .needed = true }); } else if (mem.eql(u8, arg, "-install_name")) { install_name = args_iter.nextOrFatal(); - } else if (mem.startsWith(u8, arg, "--compress-debug-sections=")) { - const param = arg["--compress-debug-sections=".len..]; + } else if (mem.cutPrefix(u8, arg, "--compress-debug-sections=")) |param| { linker_compress_debug_sections = std.meta.stringToEnum(link.File.Lld.Elf.CompressDebugSections, param) orelse { fatal("expected --compress-debug-sections=[none|zlib|zstd], found '{s}'", .{param}); }; @@ -1275,8 +1269,8 @@ fn buildOutputType( try cc_argv.appendSlice(arena, &.{ arg, args_iter.nextOrFatal() }); } else if (mem.eql(u8, arg, "-I")) { try cssan.addIncludePath(arena, &cc_argv, .I, arg, args_iter.nextOrFatal(), false); - } else if (mem.startsWith(u8, arg, "--embed-dir=")) { - try cssan.addIncludePath(arena, &cc_argv, .embed_dir, arg, arg["--embed-dir=".len..], true); + } else if (mem.cutPrefix(u8, arg, "--embed-dir=")) |rest| { + try cssan.addIncludePath(arena, &cc_argv, .embed_dir, arg, rest, true); } else if (mem.eql(u8, arg, "-isystem")) { try cssan.addIncludePath(arena, &cc_argv, .isystem, arg, args_iter.nextOrFatal(), false); } else if (mem.eql(u8, arg, "-iwithsysroot")) { @@ -1303,14 +1297,14 @@ fn buildOutputType( target_mcpu = args_iter.nextOrFatal(); } else if (mem.eql(u8, arg, "-mcmodel")) { mod_opts.code_model = parseCodeModel(args_iter.nextOrFatal()); - } else if (mem.startsWith(u8, arg, "-mcmodel=")) { - mod_opts.code_model = parseCodeModel(arg["-mcmodel=".len..]); - } else if (mem.startsWith(u8, arg, "-ofmt=")) { - create_module.object_format = arg["-ofmt=".len..]; - } else if (mem.startsWith(u8, arg, "-mcpu=")) { - target_mcpu = arg["-mcpu=".len..]; - } else if (mem.startsWith(u8, arg, "-O")) { - mod_opts.optimize_mode = parseOptimizeMode(arg["-O".len..]); + } else if (mem.cutPrefix(u8, arg, "-mcmodel=")) |rest| { + mod_opts.code_model = parseCodeModel(rest); + } else if (mem.cutPrefix(u8, arg, "-ofmt=")) |rest| { + create_module.object_format = rest; + } else if (mem.cutPrefix(u8, arg, "-mcpu=")) |rest| { + target_mcpu = rest; + } else if (mem.cutPrefix(u8, arg, "-O")) |rest| { + mod_opts.optimize_mode = parseOptimizeMode(rest); } else if (mem.eql(u8, arg, "--dynamic-linker")) { create_module.dynamic_linker = args_iter.nextOrFatal(); } else if (mem.eql(u8, arg, "--sysroot")) { @@ -1346,9 +1340,7 @@ fn buildOutputType( } else { dev.check(.network_listen); // example: --listen 127.0.0.1:9000 - var it = std.mem.splitScalar(u8, next_arg, ':'); - const host = it.next().?; - const port_text = it.next() orelse "14735"; + const host, const port_text = mem.cutScalar(u8, next_arg, ':') orelse .{ next_arg, "14735" }; const port = std.fmt.parseInt(u16, port_text, 10) catch |err| fatal("invalid port number: '{s}': {s}", .{ port_text, @errorName(err) }); listen = .{ .ip4 = std.net.Ip4Address.parse(host, port) catch |err| @@ -1408,8 +1400,7 @@ fn buildOutputType( create_module.opts.pie = false; } else if (mem.eql(u8, arg, "-flto")) { create_module.opts.lto = .full; - } else if (mem.startsWith(u8, arg, "-flto=")) { - const mode = arg["-flto=".len..]; + } else if (mem.cutPrefix(u8, arg, "-flto=")) |mode| { if (mem.eql(u8, mode, "full")) { create_module.opts.lto = .full; } else if (mem.eql(u8, mode, "thin")) { @@ -1443,8 +1434,7 @@ fn buildOutputType( mod_opts.omit_frame_pointer = false; } else if (mem.eql(u8, arg, "-fsanitize-c")) { mod_opts.sanitize_c = .full; - } else if (mem.startsWith(u8, arg, "-fsanitize-c=")) { - const mode = arg["-fsanitize-c=".len..]; + } else if (mem.cutPrefix(u8, arg, "-fsanitize-c=")) |mode| { if (mem.eql(u8, mode, "trap")) { mod_opts.sanitize_c = .trap; } else if (mem.eql(u8, mode, "full")) { @@ -1492,8 +1482,7 @@ fn buildOutputType( create_module.opts.san_cov_trace_pc_guard = false; } else if (mem.eql(u8, arg, "-freference-trace")) { reference_trace = 256; - } else if (mem.startsWith(u8, arg, "-freference-trace=")) { - const num = arg["-freference-trace=".len..]; + } else if (mem.cutPrefix(u8, arg, "-freference-trace=")) |num| { reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| { fatal("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) }); }; @@ -1507,51 +1496,51 @@ fn buildOutputType( create_module.opts.rdynamic = true; } else if (mem.eql(u8, arg, "-fsoname")) { soname = .yes_default_value; - } else if (mem.startsWith(u8, arg, "-fsoname=")) { - soname = .{ .yes = arg["-fsoname=".len..] }; + } else if (mem.cutPrefix(u8, arg, "-fsoname=")) |rest| { + soname = .{ .yes = rest }; } else if (mem.eql(u8, arg, "-fno-soname")) { soname = .no; } else if (mem.eql(u8, arg, "-femit-bin")) { emit_bin = .yes_default_path; - } else if (mem.startsWith(u8, arg, "-femit-bin=")) { - emit_bin = .{ .yes = arg["-femit-bin=".len..] }; + } else if (mem.cutPrefix(u8, arg, "-femit-bin=")) |rest| { + emit_bin = .{ .yes = rest }; } else if (mem.eql(u8, arg, "-fno-emit-bin")) { emit_bin = .no; } else if (mem.eql(u8, arg, "-femit-h")) { emit_h = .yes_default_path; - } else if (mem.startsWith(u8, arg, "-femit-h=")) { - emit_h = .{ .yes = arg["-femit-h=".len..] }; + } else if (mem.cutPrefix(u8, arg, "-femit-h=")) |rest| { + emit_h = .{ .yes = rest }; } else if (mem.eql(u8, arg, "-fno-emit-h")) { emit_h = .no; } else if (mem.eql(u8, arg, "-femit-asm")) { emit_asm = .yes_default_path; - } else if (mem.startsWith(u8, arg, "-femit-asm=")) { - emit_asm = .{ .yes = arg["-femit-asm=".len..] }; + } else if (mem.cutPrefix(u8, arg, "-femit-asm=")) |rest| { + emit_asm = .{ .yes = rest }; } else if (mem.eql(u8, arg, "-fno-emit-asm")) { emit_asm = .no; } else if (mem.eql(u8, arg, "-femit-llvm-ir")) { emit_llvm_ir = .yes_default_path; - } else if (mem.startsWith(u8, arg, "-femit-llvm-ir=")) { - emit_llvm_ir = .{ .yes = arg["-femit-llvm-ir=".len..] }; + } else if (mem.cutPrefix(u8, arg, "-femit-llvm-ir=")) |rest| { + emit_llvm_ir = .{ .yes = rest }; } else if (mem.eql(u8, arg, "-fno-emit-llvm-ir")) { emit_llvm_ir = .no; } else if (mem.eql(u8, arg, "-femit-llvm-bc")) { emit_llvm_bc = .yes_default_path; - } else if (mem.startsWith(u8, arg, "-femit-llvm-bc=")) { - emit_llvm_bc = .{ .yes = arg["-femit-llvm-bc=".len..] }; + } else if (mem.cutPrefix(u8, arg, "-femit-llvm-bc=")) |rest| { + emit_llvm_bc = .{ .yes = rest }; } else if (mem.eql(u8, arg, "-fno-emit-llvm-bc")) { emit_llvm_bc = .no; } else if (mem.eql(u8, arg, "-femit-docs")) { emit_docs = .yes_default_path; - } else if (mem.startsWith(u8, arg, "-femit-docs=")) { - emit_docs = .{ .yes = arg["-femit-docs=".len..] }; + } else if (mem.cutPrefix(u8, arg, "-femit-docs=")) |rest| { + emit_docs = .{ .yes = rest }; } else if (mem.eql(u8, arg, "-fno-emit-docs")) { emit_docs = .no; } else if (mem.eql(u8, arg, "-femit-implib")) { emit_implib = .yes_default_path; emit_implib_arg_provided = true; - } else if (mem.startsWith(u8, arg, "-femit-implib=")) { - emit_implib = .{ .yes = arg["-femit-implib=".len..] }; + } else if (mem.cutPrefix(u8, arg, "-femit-implib=")) |rest| { + emit_implib = .{ .yes = rest }; emit_implib_arg_provided = true; } else if (mem.eql(u8, arg, "-fno-emit-implib")) { emit_implib = .no; @@ -1601,8 +1590,7 @@ fn buildOutputType( mod_opts.no_builtin = false; } else if (mem.eql(u8, arg, "-fno-builtin")) { mod_opts.no_builtin = true; - } else if (mem.startsWith(u8, arg, "-fopt-bisect-limit=")) { - const next_arg = arg["-fopt-bisect-limit=".len..]; + } else if (mem.cutPrefix(u8, arg, "-fopt-bisect-limit=")) |next_arg| { llvm_opt_bisect_limit = std.fmt.parseInt(c_int, next_arg, 0) catch |err| fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) }); } else if (mem.eql(u8, arg, "--eh-frame-hdr")) { @@ -1645,10 +1633,10 @@ fn buildOutputType( linker_z_relro = true; } else if (mem.eql(u8, z_arg, "norelro")) { linker_z_relro = false; - } else if (mem.startsWith(u8, z_arg, "common-page-size=")) { - linker_z_common_page_size = parseIntSuffix(z_arg, "common-page-size=".len); - } else if (mem.startsWith(u8, z_arg, "max-page-size=")) { - linker_z_max_page_size = parseIntSuffix(z_arg, "max-page-size=".len); + } else if (prefixedIntArg(z_arg, "common-page-size=")) |int| { + linker_z_common_page_size = int; + } else if (prefixedIntArg(z_arg, "max-page-size=")) |int| { + linker_z_max_page_size = int; } else { fatal("unsupported linker extension flag: -z {s}", .{z_arg}); } @@ -1669,16 +1657,16 @@ fn buildOutputType( linker_import_table = true; } else if (mem.eql(u8, arg, "--export-table")) { linker_export_table = true; - } else if (mem.startsWith(u8, arg, "--initial-memory=")) { - linker_initial_memory = parseIntSuffix(arg, "--initial-memory=".len); - } else if (mem.startsWith(u8, arg, "--max-memory=")) { - linker_max_memory = parseIntSuffix(arg, "--max-memory=".len); + } else if (prefixedIntArg(arg, "--initial-memory=")) |int| { + linker_initial_memory = int; + } else if (prefixedIntArg(arg, "--max-memory=")) |int| { + linker_max_memory = int; } else if (mem.eql(u8, arg, "--shared-memory")) { create_module.opts.shared_memory = true; - } else if (mem.startsWith(u8, arg, "--global-base=")) { - linker_global_base = parseIntSuffix(arg, "--global-base=".len); - } else if (mem.startsWith(u8, arg, "--export=")) { - try linker_export_symbol_names.append(arena, arg["--export=".len..]); + } else if (prefixedIntArg(arg, "--global-base=")) |int| { + linker_global_base = int; + } else if (mem.cutPrefix(u8, arg, "--export=")) |rest| { + try linker_export_symbol_names.append(arena, rest); } else if (mem.eql(u8, arg, "-Bsymbolic")) { linker_bind_global_refs_locally = true; } else if (mem.eql(u8, arg, "--gc-sections")) { @@ -1687,8 +1675,7 @@ fn buildOutputType( linker_gc_sections = false; } else if (mem.eql(u8, arg, "--build-id")) { build_id = .fast; - } else if (mem.startsWith(u8, arg, "--build-id=")) { - const style = arg["--build-id=".len..]; + } else if (mem.cutPrefix(u8, arg, "--build-id=")) |style| { build_id = std.zig.BuildId.parse(style) catch |err| { fatal("unable to parse --build-id style '{s}': {s}", .{ style, @errorName(err), @@ -1712,26 +1699,26 @@ fn buildOutputType( verbose_generic_instances = true; } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { verbose_llvm_ir = "-"; - } else if (mem.startsWith(u8, arg, "--verbose-llvm-ir=")) { - verbose_llvm_ir = arg["--verbose-llvm-ir=".len..]; - } else if (mem.startsWith(u8, arg, "--verbose-llvm-bc=")) { - verbose_llvm_bc = arg["--verbose-llvm-bc=".len..]; + } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-ir=")) |rest| { + verbose_llvm_ir = rest; + } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-bc=")) |rest| { + verbose_llvm_bc = rest; } else if (mem.eql(u8, arg, "--verbose-cimport")) { verbose_cimport = true; } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) { verbose_llvm_cpu_features = true; - } else if (mem.startsWith(u8, arg, "-T")) { - linker_script = arg[2..]; - } else if (mem.startsWith(u8, arg, "-L")) { - try create_module.lib_dir_args.append(arena, arg[2..]); - } else if (mem.startsWith(u8, arg, "-F")) { - try create_module.framework_dirs.append(arena, arg[2..]); - } else if (mem.startsWith(u8, arg, "-l")) { + } else if (mem.cutPrefix(u8, arg, "-T")) |rest| { + linker_script = rest; + } else if (mem.cutPrefix(u8, arg, "-L")) |rest| { + try create_module.lib_dir_args.append(arena, rest); + } else if (mem.cutPrefix(u8, arg, "-F")) |rest| { + try create_module.framework_dirs.append(arena, rest); + } else if (mem.cutPrefix(u8, arg, "-l")) |name| { // We don't know whether this library is part of libc // or libc++ until we resolve the target, so we append // to the list for now. try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ - .name = arg["-l".len..], + .name = name, .query = .{ .needed = false, .weak = false, @@ -1740,9 +1727,9 @@ fn buildOutputType( .allow_so_scripts = allow_so_scripts, }, } }); - } else if (mem.startsWith(u8, arg, "-needed-l")) { + } else if (mem.cutPrefix(u8, arg, "-needed-l")) |name| { try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ - .name = arg["-needed-l".len..], + .name = name, .query = .{ .needed = true, .weak = false, @@ -1751,9 +1738,9 @@ fn buildOutputType( .allow_so_scripts = allow_so_scripts, }, } }); - } else if (mem.startsWith(u8, arg, "-weak-l")) { + } else if (mem.cutPrefix(u8, arg, "-weak-l")) |name| { try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ - .name = arg["-weak-l".len..], + .name = name, .query = .{ .needed = false, .weak = true, @@ -1764,13 +1751,10 @@ fn buildOutputType( } }); } else if (mem.startsWith(u8, arg, "-D")) { try cc_argv.append(arena, arg); - } else if (mem.startsWith(u8, arg, "-I")) { - try cssan.addIncludePath(arena, &cc_argv, .I, arg, arg[2..], true); - } else if (mem.startsWith(u8, arg, "-x")) { - const lang = if (arg.len == "-x".len) - args_iter.nextOrFatal() - else - arg["-x".len..]; + } else if (mem.cutPrefix(u8, arg, "-I")) |rest| { + try cssan.addIncludePath(arena, &cc_argv, .I, arg, rest, true); + } else if (mem.cutPrefix(u8, arg, "-x")) |rest| { + const lang = if (rest.len == 0) args_iter.nextOrFatal() else rest; if (mem.eql(u8, lang, "none")) { file_ext = null; } else if (Compilation.LangToExt.get(lang)) |got_ext| { @@ -1778,8 +1762,8 @@ fn buildOutputType( } else { fatal("language not recognized: '{s}'", .{lang}); } - } else if (mem.startsWith(u8, arg, "-mexec-model=")) { - create_module.opts.wasi_exec_model = parseWasiExecModel(arg["-mexec-model=".len..]); + } else if (mem.cutPrefix(u8, arg, "-mexec-model=")) |rest| { + create_module.opts.wasi_exec_model = parseWasiExecModel(rest); } else if (mem.eql(u8, arg, "-municode")) { mingw_unicode_entry_point = true; } else { @@ -2457,8 +2441,8 @@ fn buildOutputType( linker_enable_new_dtags = false; } else if (mem.eql(u8, arg, "-O")) { linker_optimization = linker_args_it.nextOrFatal(); - } else if (mem.startsWith(u8, arg, "-O")) { - linker_optimization = arg["-O".len..]; + } else if (mem.cutPrefix(u8, arg, "-O")) |rest| { + linker_optimization = rest; } else if (mem.eql(u8, arg, "-pagezero_size")) { const next_arg = linker_args_it.nextOrFatal(); pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| { @@ -2540,11 +2524,8 @@ fn buildOutputType( linker_compress_debug_sections = std.meta.stringToEnum(link.File.Lld.Elf.CompressDebugSections, arg1) orelse { fatal("expected [none|zlib|zstd] after --compress-debug-sections, found '{s}'", .{arg1}); }; - } else if (mem.startsWith(u8, arg, "-z")) { - var z_arg = arg[2..]; - if (z_arg.len == 0) { - z_arg = linker_args_it.nextOrFatal(); - } + } else if (mem.cutPrefix(u8, arg, "-z")) |z_rest| { + const z_arg = if (z_rest.len == 0) linker_args_it.nextOrFatal() else z_rest; if (mem.eql(u8, z_arg, "nodelete")) { linker_z_nodelete = true; } else if (mem.eql(u8, z_arg, "notext")) { @@ -2567,12 +2548,12 @@ fn buildOutputType( linker_z_relro = true; } else if (mem.eql(u8, z_arg, "norelro")) { linker_z_relro = false; - } else if (mem.startsWith(u8, z_arg, "stack-size=")) { - stack_size = parseStackSize(z_arg["stack-size=".len..]); - } else if (mem.startsWith(u8, z_arg, "common-page-size=")) { - linker_z_common_page_size = parseIntSuffix(z_arg, "common-page-size=".len); - } else if (mem.startsWith(u8, z_arg, "max-page-size=")) { - linker_z_max_page_size = parseIntSuffix(z_arg, "max-page-size=".len); + } else if (mem.cutPrefix(u8, z_arg, "stack-size=")) |rest| { + stack_size = parseStackSize(rest); + } else if (prefixedIntArg(z_arg, "common-page-size=")) |int| { + linker_z_common_page_size = int; + } else if (prefixedIntArg(z_arg, "max-page-size=")) |int| { + linker_z_max_page_size = int; } else { fatal("unsupported linker extension flag: -z {s}", .{z_arg}); } @@ -2686,9 +2667,9 @@ fn buildOutputType( .allow_so_scripts = allow_so_scripts, }, } }); - } else if (mem.startsWith(u8, arg, "-weak-l")) { + } else if (mem.cutPrefix(u8, arg, "-weak-l")) |rest| { try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ - .name = arg["-weak-l".len..], + .name = rest, .query = .{ .weak = true, .needed = false, @@ -3783,8 +3764,7 @@ fn createModule( try mcpu_buffer.appendSlice(cli_mod.target_mcpu orelse "baseline"); for (create_module.llvm_m_args.items) |llvm_m_arg| { - if (mem.startsWith(u8, llvm_m_arg, "mno-")) { - const llvm_name = llvm_m_arg["mno-".len..]; + if (mem.cutPrefix(u8, llvm_m_arg, "mno-")) |llvm_name| { const zig_name = llvm_to_zig_name.get(llvm_name) orelse { fatal("target architecture {s} has no LLVM CPU feature named '{s}'", .{ @tagName(cpu_arch), llvm_name, @@ -3792,8 +3772,7 @@ fn createModule( }; try mcpu_buffer.append('-'); try mcpu_buffer.appendSlice(zig_name); - } else if (mem.startsWith(u8, llvm_m_arg, "m")) { - const llvm_name = llvm_m_arg["m".len..]; + } else if (mem.cutPrefix(u8, llvm_m_arg, "m")) |llvm_name| { const zig_name = llvm_to_zig_name.get(llvm_name) orelse { fatal("target architecture {s} has no LLVM CPU feature named '{s}'", .{ @tagName(cpu_arch), llvm_name, @@ -4980,9 +4959,8 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { reference_trace = 256; } else if (mem.eql(u8, arg, "--fetch")) { fetch_only = true; - } else if (mem.startsWith(u8, arg, "--fetch=")) { + } else if (mem.cutPrefix(u8, arg, "--fetch=")) |sub_arg| { fetch_only = true; - const sub_arg = arg["--fetch=".len..]; fetch_mode = std.meta.stringToEnum(Package.Fetch.JobQueue.Mode, sub_arg) orelse fatal("expected [needed|all] after '--fetch=', found '{s}'", .{ sub_arg, @@ -4993,8 +4971,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { system_pkg_dir_path = args[i]; try child_argv.append("--system"); continue; - } else if (mem.startsWith(u8, arg, "-freference-trace=")) { - const num = arg["-freference-trace=".len..]; + } else if (mem.cutPrefix(u8, arg, "-freference-trace=")) |num| { reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| { fatal("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) }); }; @@ -5044,10 +5021,10 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { verbose_generic_instances = true; } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { verbose_llvm_ir = "-"; - } else if (mem.startsWith(u8, arg, "--verbose-llvm-ir=")) { - verbose_llvm_ir = arg["--verbose-llvm-ir=".len..]; - } else if (mem.startsWith(u8, arg, "--verbose-llvm-bc=")) { - verbose_llvm_bc = arg["--verbose-llvm-bc=".len..]; + } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-ir=")) |rest| { + verbose_llvm_ir = rest; + } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-bc=")) |rest| { + verbose_llvm_bc = rest; } else if (mem.eql(u8, arg, "--verbose-cimport")) { verbose_cimport = true; } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) { @@ -5060,8 +5037,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { }; try child_argv.appendSlice(&.{ arg, args[i] }); continue; - } else if (mem.startsWith(u8, arg, "-j")) { - const str = arg["-j".len..]; + } else if (mem.cutPrefix(u8, arg, "-j")) |str| { const num = std.fmt.parseUnsigned(u32, str, 10) catch |err| { fatal("unable to parse jobs count '{s}': {s}", .{ str, @errorName(err), @@ -6636,10 +6612,9 @@ fn eatIntPrefix(arg: []const u8, base: u8) []const u8 { return arg; } -fn parseIntSuffix(arg: []const u8, prefix_len: usize) u64 { - return std.fmt.parseUnsigned(u64, arg[prefix_len..], 0) catch |err| { - fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) }); - }; +fn prefixedIntArg(arg: []const u8, prefix: []const u8) ?u64 { + const number = mem.cutPrefix(u8, arg, prefix) orelse return null; + return std.fmt.parseUnsigned(u64, number, 0) catch |err| fatal("unable to parse '{s}': {t}", .{ arg, err }); } fn warnAboutForeignBinaries( @@ -6966,12 +6941,12 @@ fn cmdFetch( debug_hash = true; } else if (mem.eql(u8, arg, "--save")) { save = .{ .yes = null }; - } else if (mem.startsWith(u8, arg, "--save=")) { - save = .{ .yes = arg["--save=".len..] }; + } else if (mem.cutPrefix(u8, arg, "--save=")) |rest| { + save = .{ .yes = rest }; } else if (mem.eql(u8, arg, "--save-exact")) { save = .{ .exact = null }; - } else if (mem.startsWith(u8, arg, "--save-exact=")) { - save = .{ .exact = arg["--save-exact=".len..] }; + } else if (mem.cutPrefix(u8, arg, "--save-exact=")) |rest| { + save = .{ .exact = rest }; } else { fatal("unrecognized parameter: '{s}'", .{arg}); }