Merge pull request #25351 from ziglang/chomp

std.mem: introduce cut functions; rename "index of" to "find"
This commit is contained in:
Andrew Kelley 2025-09-26 01:45:07 -07:00 committed by GitHub
commit 3b365a1f9b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 327 additions and 203 deletions

View file

@ -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.

View file

@ -1022,10 +1022,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) });
};
@ -1043,9 +1042,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,
@ -1062,10 +1060,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,
@ -1096,8 +1092,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) {
@ -1107,9 +1103,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 {
@ -1118,8 +1114,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),
@ -1133,8 +1128,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")) {
@ -1161,8 +1156,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});
};
@ -1260,8 +1254,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")) {
@ -1288,14 +1282,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")) {
@ -1331,9 +1325,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|
@ -1393,8 +1385,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")) {
@ -1428,8 +1419,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")) {
@ -1477,8 +1467,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) });
};
@ -1492,51 +1481,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;
@ -1586,8 +1575,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")) {
@ -1630,10 +1618,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});
}
@ -1654,16 +1642,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")) {
@ -1672,8 +1660,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),
@ -1697,26 +1684,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,
@ -1725,9 +1712,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,
@ -1736,9 +1723,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,
@ -1749,13 +1736,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| {
@ -1763,8 +1747,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 {
@ -2442,8 +2426,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| {
@ -2525,11 +2509,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")) {
@ -2552,12 +2533,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});
}
@ -2671,9 +2652,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,
@ -3768,8 +3749,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,
@ -3777,8 +3757,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,
@ -4850,9 +4829,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,
@ -4863,8 +4841,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) });
};
@ -4914,10 +4891,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")) {
@ -4930,8 +4907,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),
@ -6507,10 +6483,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(
@ -6837,12 +6812,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});
}