authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-09-26 01:45:07-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-09-26 01:45:07-07:00
log3b365a1f9b277dd2cf7f7dac51e71647e164ff3c
tree4be6d39eeb3327d8023ef5f2153ac0dcf92a3154
parentad80a8b5529ab70d49feaffc82fcd9a990a05332
parent14e227d8a6dd692ba0707aa070b8bac22a9a822e
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #25351 from ziglang/chomp

std.mem: introduce cut functions; rename "index of" to "find"

2 files changed, 327 insertions(+), 203 deletions(-)

lib/std/mem.zig+220-71
......@@ -806,9 +806,12 @@ fn eqlBytes(a: []const u8, b: []const u8) bool {
806806 return !Scan.isNotEqual(last_a_chunk, last_b_chunk);
807807}
808808
809/// Deprecated in favor of `findDiff`.
810pub const indexOfDiff = findDiff;
811
809812/// Compares two slices and returns the index of the first inequality.
810813/// Returns null if the slices are equal.
811pub fn indexOfDiff(comptime T: type, a: []const T, b: []const T) ?usize {
814pub fn findDiff(comptime T: type, a: []const T, b: []const T) ?usize {
812815 const shortest = @min(a.len, b.len);
813816 if (a.ptr == b.ptr)
814817 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 {
817820 return if (a.len == b.len) null else shortest;
818821}
819822
820test indexOfDiff {
821 try testing.expectEqual(indexOfDiff(u8, "one", "one"), null);
822 try testing.expectEqual(indexOfDiff(u8, "one two", "one"), 3);
823 try testing.expectEqual(indexOfDiff(u8, "one", "one two"), 3);
824 try testing.expectEqual(indexOfDiff(u8, "one twx", "one two"), 6);
825 try testing.expectEqual(indexOfDiff(u8, "xne", "one"), 0);
823test findDiff {
824 try testing.expectEqual(findDiff(u8, "one", "one"), null);
825 try testing.expectEqual(findDiff(u8, "one two", "one"), 3);
826 try testing.expectEqual(findDiff(u8, "one", "one two"), 3);
827 try testing.expectEqual(findDiff(u8, "one twx", "one two"), 6);
828 try testing.expectEqual(findDiff(u8, "xne", "one"), 0);
826829}
827830
828831/// 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 {
10141017 return indexOfSentinel(array_info.child, end, ptr);
10151018 }
10161019 }
1017 return indexOfScalar(array_info.child, ptr, end) orelse array_info.len;
1020 return findScalar(array_info.child, ptr, end) orelse array_info.len;
10181021 },
10191022 else => {},
10201023 },
......@@ -1039,7 +1042,7 @@ fn lenSliceTo(ptr: anytype, comptime end: std.meta.Elem(@TypeOf(ptr))) usize {
10391042 return indexOfSentinel(ptr_info.child, s, ptr);
10401043 }
10411044 }
1042 return indexOfScalar(ptr_info.child, ptr, end) orelse ptr.len;
1045 return findScalar(ptr_info.child, ptr, end) orelse ptr.len;
10431046 },
10441047 },
10451048 else => {},
......@@ -1109,9 +1112,12 @@ test len {
11091112 try testing.expect(len(c_ptr) == 2);
11101113}
11111114
1115/// Deprecated in favor of `findSentinel`.
1116pub const indexOfSentinel = findSentinel;
1117
11121118/// Returns the index of the sentinel value in a sentinel-terminated pointer.
11131119/// Linear search through memory until the sentinel is found.
1114pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]const T) usize {
1120pub fn findSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]const T) usize {
11151121 var i: usize = 0;
11161122
11171123 if (use_vectors_for_comparison and
......@@ -1223,7 +1229,7 @@ pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool {
12231229/// Remove a set of values from the beginning of a slice.
12241230pub fn trimStart(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
12251231 var begin: usize = 0;
1226 while (begin < slice.len and indexOfScalar(T, values_to_strip, slice[begin]) != null) : (begin += 1) {}
1232 while (begin < slice.len and findScalar(T, values_to_strip, slice[begin]) != null) : (begin += 1) {}
12271233 return slice[begin..];
12281234}
12291235
......@@ -1237,7 +1243,7 @@ pub const trimLeft = trimStart;
12371243/// Remove a set of values from the end of a slice.
12381244pub fn trimEnd(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
12391245 var end: usize = slice.len;
1240 while (end > 0 and indexOfScalar(T, values_to_strip, slice[end - 1]) != null) : (end -= 1) {}
1246 while (end > 0 and findScalar(T, values_to_strip, slice[end - 1]) != null) : (end -= 1) {}
12411247 return slice[0..end];
12421248}
12431249
......@@ -1252,8 +1258,8 @@ pub const trimRight = trimEnd;
12521258pub fn trim(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
12531259 var begin: usize = 0;
12541260 var end: usize = slice.len;
1255 while (begin < end and indexOfScalar(T, values_to_strip, slice[begin]) != null) : (begin += 1) {}
1256 while (end > begin and indexOfScalar(T, values_to_strip, slice[end - 1]) != null) : (end -= 1) {}
1261 while (begin < end and findScalar(T, values_to_strip, slice[begin]) != null) : (begin += 1) {}
1262 while (end > begin and findScalar(T, values_to_strip, slice[end - 1]) != null) : (end -= 1) {}
12571263 return slice[begin..end];
12581264}
12591265
......@@ -1262,13 +1268,19 @@ test trim {
12621268 try testing.expectEqualSlices(u8, "foo", trim(u8, "foo", " \n"));
12631269}
12641270
1271/// Deprecated in favor of `findScalar`.
1272pub const indexOfScalar = findScalar;
1273
12651274/// Linear search for the index of a scalar value inside a slice.
1266pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {
1275pub fn findScalar(comptime T: type, slice: []const T, value: T) ?usize {
12671276 return indexOfScalarPos(T, slice, 0, value);
12681277}
12691278
1279/// Deprecated in favor of `findScalarLast`.
1280pub const lastIndexOfScalar = findScalarLast;
1281
12701282/// Linear search for the last index of a scalar value inside a slice.
1271pub fn lastIndexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {
1283pub fn findScalarLast(comptime T: type, slice: []const T, value: T) ?usize {
12721284 var i: usize = slice.len;
12731285 while (i != 0) {
12741286 i -= 1;
......@@ -1277,9 +1289,12 @@ pub fn lastIndexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {
12771289 return null;
12781290}
12791291
1292/// Deprecated in favor of `findScalarPos`.
1293pub const indexOfScalarPos = findScalarPos;
1294
12801295/// Linear search for the index of a scalar value inside a slice, starting from a given position.
12811296/// Returns null if the value is not found.
1282pub fn indexOfScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize {
1297pub fn findScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize {
12831298 if (start_index >= slice.len) return null;
12841299
12851300 var i: usize = start_index;
......@@ -1355,15 +1370,21 @@ test indexOfScalarPos {
13551370 }
13561371}
13571372
1373/// Deprecated in favor of `findAny`.
1374pub const indexOfAny = findAny;
1375
13581376/// Linear search for the index of any value in the provided list inside a slice.
13591377/// Returns null if no values are found.
1360pub fn indexOfAny(comptime T: type, slice: []const T, values: []const T) ?usize {
1378pub fn findAny(comptime T: type, slice: []const T, values: []const T) ?usize {
13611379 return indexOfAnyPos(T, slice, 0, values);
13621380}
13631381
1382/// Deprecated in favor of `findLastAny`.
1383pub const lastIndexOfAny = findLastAny;
1384
13641385/// Linear search for the last index of any value in the provided list inside a slice.
13651386/// Returns null if no values are found.
1366pub fn lastIndexOfAny(comptime T: type, slice: []const T, values: []const T) ?usize {
1387pub fn findLastAny(comptime T: type, slice: []const T, values: []const T) ?usize {
13671388 var i: usize = slice.len;
13681389 while (i != 0) {
13691390 i -= 1;
......@@ -1374,9 +1395,12 @@ pub fn lastIndexOfAny(comptime T: type, slice: []const T, values: []const T) ?us
13741395 return null;
13751396}
13761397
1398/// Deprecated in favor of `findAnyPos`.
1399pub const indexOfAnyPos = findAnyPos;
1400
13771401/// Linear search for the index of any value in the provided list inside a slice, starting from a given position.
13781402/// Returns null if no values are found.
1379pub fn indexOfAnyPos(comptime T: type, slice: []const T, start_index: usize, values: []const T) ?usize {
1403pub fn findAnyPos(comptime T: type, slice: []const T, start_index: usize, values: []const T) ?usize {
13801404 if (start_index >= slice.len) return null;
13811405 for (slice[start_index..], start_index..) |c, i| {
13821406 for (values) |value| {
......@@ -1386,17 +1410,34 @@ pub fn indexOfAnyPos(comptime T: type, slice: []const T, start_index: usize, val
13861410 return null;
13871411}
13881412
1413/// Deprecated in favor of `findNone`.
1414pub const indexOfNone = findNone;
1415
13891416/// Find the first item in `slice` which is not contained in `values`.
13901417///
13911418/// Comparable to `strspn` in the C standard library.
1392pub fn indexOfNone(comptime T: type, slice: []const T, values: []const T) ?usize {
1419pub fn findNone(comptime T: type, slice: []const T, values: []const T) ?usize {
13931420 return indexOfNonePos(T, slice, 0, values);
13941421}
13951422
1423test findNone {
1424 try testing.expect(findNone(u8, "abc123", "123").? == 0);
1425 try testing.expect(findLastNone(u8, "abc123", "123").? == 2);
1426 try testing.expect(findNone(u8, "123abc", "123").? == 3);
1427 try testing.expect(findLastNone(u8, "123abc", "123").? == 5);
1428 try testing.expect(findNone(u8, "123123", "123") == null);
1429 try testing.expect(findNone(u8, "333333", "123") == null);
1430
1431 try testing.expect(indexOfNonePos(u8, "abc123", 3, "321") == null);
1432}
1433
1434/// Deprecated in favor of `findLastNone`.
1435pub const lastIndexOfNone = findLastNone;
1436
13961437/// Find the last item in `slice` which is not contained in `values`.
13971438///
13981439/// Like `strspn` in the C standard library, but searches from the end.
1399pub fn lastIndexOfNone(comptime T: type, slice: []const T, values: []const T) ?usize {
1440pub fn findLastNone(comptime T: type, slice: []const T, values: []const T) ?usize {
14001441 var i: usize = slice.len;
14011442 outer: while (i != 0) {
14021443 i -= 1;
......@@ -1408,11 +1449,13 @@ pub fn lastIndexOfNone(comptime T: type, slice: []const T, values: []const T) ?u
14081449 return null;
14091450}
14101451
1452pub const indexOfNonePos = findNonePos;
1453
14111454/// Find the first item in `slice[start_index..]` which is not contained in `values`.
14121455/// The returned index will be relative to the start of `slice`, and never less than `start_index`.
14131456///
14141457/// Comparable to `strspn` in the C standard library.
1415pub fn indexOfNonePos(comptime T: type, slice: []const T, start_index: usize, values: []const T) ?usize {
1458pub fn findNonePos(comptime T: type, slice: []const T, start_index: usize, values: []const T) ?usize {
14161459 if (start_index >= slice.len) return null;
14171460 outer: for (slice[start_index..], start_index..) |c, i| {
14181461 for (values) |value| {
......@@ -1423,29 +1466,24 @@ pub fn indexOfNonePos(comptime T: type, slice: []const T, start_index: usize, va
14231466 return null;
14241467}
14251468
1426test indexOfNone {
1427 try testing.expect(indexOfNone(u8, "abc123", "123").? == 0);
1428 try testing.expect(lastIndexOfNone(u8, "abc123", "123").? == 2);
1429 try testing.expect(indexOfNone(u8, "123abc", "123").? == 3);
1430 try testing.expect(lastIndexOfNone(u8, "123abc", "123").? == 5);
1431 try testing.expect(indexOfNone(u8, "123123", "123") == null);
1432 try testing.expect(indexOfNone(u8, "333333", "123") == null);
1433
1434 try testing.expect(indexOfNonePos(u8, "abc123", 3, "321") == null);
1435}
1469/// Deprecated in favor of `find`.
1470pub const indexOf = find;
14361471
14371472/// Search for needle in haystack and return the index of the first occurrence.
14381473/// Uses Boyer-Moore-Horspool algorithm on large inputs; linear search on small inputs.
14391474/// Returns null if needle is not found.
1440pub fn indexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize {
1475pub fn find(comptime T: type, haystack: []const T, needle: []const T) ?usize {
14411476 return indexOfPos(T, haystack, 0, needle);
14421477}
14431478
1479/// Deprecated in favor of `findLastLinear`.
1480pub const lastIndexOfLinear = findLastLinear;
1481
14441482/// Find the index in a slice of a sub-slice, searching from the end backwards.
14451483/// To start looking at a different index, slice the haystack first.
14461484/// Consider using `lastIndexOf` instead of this, which will automatically use a
14471485/// more sophisticated algorithm on larger inputs.
1448pub fn lastIndexOfLinear(comptime T: type, haystack: []const T, needle: []const T) ?usize {
1486pub fn findLastLinear(comptime T: type, haystack: []const T, needle: []const T) ?usize {
14491487 if (needle.len > haystack.len) return null;
14501488 var i: usize = haystack.len - needle.len;
14511489 while (true) : (i -= 1) {
......@@ -1454,9 +1492,11 @@ pub fn lastIndexOfLinear(comptime T: type, haystack: []const T, needle: []const
14541492 }
14551493}
14561494
1495pub const indexOfPosLinear = findPosLinear;
1496
14571497/// Consider using `indexOfPos` instead of this, which will automatically use a
14581498/// more sophisticated algorithm on larger inputs.
1459pub fn indexOfPosLinear(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize {
1499pub fn findPosLinear(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize {
14601500 if (needle.len > haystack.len) return null;
14611501 var i: usize = start_index;
14621502 const end = haystack.len - needle.len;
......@@ -1466,24 +1506,24 @@ pub fn indexOfPosLinear(comptime T: type, haystack: []const T, start_index: usiz
14661506 return null;
14671507}
14681508
1469test indexOfPosLinear {
1470 try testing.expectEqual(0, indexOfPosLinear(u8, "", 0, ""));
1471 try testing.expectEqual(0, indexOfPosLinear(u8, "123", 0, ""));
1509test findPosLinear {
1510 try testing.expectEqual(0, findPosLinear(u8, "", 0, ""));
1511 try testing.expectEqual(0, findPosLinear(u8, "123", 0, ""));
14721512
1473 try testing.expectEqual(null, indexOfPosLinear(u8, "", 0, "1"));
1474 try testing.expectEqual(0, indexOfPosLinear(u8, "1", 0, "1"));
1475 try testing.expectEqual(null, indexOfPosLinear(u8, "2", 0, "1"));
1476 try testing.expectEqual(1, indexOfPosLinear(u8, "21", 0, "1"));
1477 try testing.expectEqual(null, indexOfPosLinear(u8, "222", 0, "1"));
1513 try testing.expectEqual(null, findPosLinear(u8, "", 0, "1"));
1514 try testing.expectEqual(0, findPosLinear(u8, "1", 0, "1"));
1515 try testing.expectEqual(null, findPosLinear(u8, "2", 0, "1"));
1516 try testing.expectEqual(1, findPosLinear(u8, "21", 0, "1"));
1517 try testing.expectEqual(null, findPosLinear(u8, "222", 0, "1"));
14781518
1479 try testing.expectEqual(null, indexOfPosLinear(u8, "", 0, "12"));
1480 try testing.expectEqual(null, indexOfPosLinear(u8, "1", 0, "12"));
1481 try testing.expectEqual(null, indexOfPosLinear(u8, "2", 0, "12"));
1482 try testing.expectEqual(0, indexOfPosLinear(u8, "12", 0, "12"));
1483 try testing.expectEqual(null, indexOfPosLinear(u8, "21", 0, "12"));
1484 try testing.expectEqual(1, indexOfPosLinear(u8, "212", 0, "12"));
1485 try testing.expectEqual(0, indexOfPosLinear(u8, "122", 0, "12"));
1486 try testing.expectEqual(1, indexOfPosLinear(u8, "212112", 0, "12"));
1519 try testing.expectEqual(null, findPosLinear(u8, "", 0, "12"));
1520 try testing.expectEqual(null, findPosLinear(u8, "1", 0, "12"));
1521 try testing.expectEqual(null, findPosLinear(u8, "2", 0, "12"));
1522 try testing.expectEqual(0, findPosLinear(u8, "12", 0, "12"));
1523 try testing.expectEqual(null, findPosLinear(u8, "21", 0, "12"));
1524 try testing.expectEqual(1, findPosLinear(u8, "212", 0, "12"));
1525 try testing.expectEqual(0, findPosLinear(u8, "122", 0, "12"));
1526 try testing.expectEqual(1, findPosLinear(u8, "212112", 0, "12"));
14871527}
14881528
14891529fn boyerMooreHorspoolPreprocessReverse(pattern: []const u8, table: *[256]usize) void {
......@@ -1512,11 +1552,14 @@ fn boyerMooreHorspoolPreprocess(pattern: []const u8, table: *[256]usize) void {
15121552 }
15131553}
15141554
1555/// Deprecated in favor of `find`.
1556pub const lastIndexOf = findLast;
1557
15151558/// Find the index in a slice of a sub-slice, searching from the end backwards.
15161559/// To start looking at a different index, slice the haystack first.
15171560/// Uses the Reverse Boyer-Moore-Horspool algorithm on large inputs;
15181561/// `lastIndexOfLinear` on small inputs.
1519pub fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize {
1562pub fn findLast(comptime T: type, haystack: []const T, needle: []const T) ?usize {
15201563 if (needle.len > haystack.len) return null;
15211564 if (needle.len == 0) return haystack.len;
15221565
......@@ -1542,8 +1585,11 @@ pub fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?us
15421585 return null;
15431586}
15441587
1588/// Deprecated in favor of `findPos`.
1589pub const indexOfPos = findPos;
1590
15451591/// Uses Boyer-Moore-Horspool algorithm on large inputs; `indexOfPosLinear` on small inputs.
1546pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize {
1592pub fn findPos(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize {
15471593 if (needle.len > haystack.len) return null;
15481594 if (needle.len < 2) {
15491595 if (needle.len == 0) return start_index;
......@@ -1593,7 +1639,7 @@ test indexOf {
15931639 try testing.expect(indexOf(u8, "foo foo", "foo").? == 0);
15941640 try testing.expect(lastIndexOf(u8, "foo foo", "foo").? == 4);
15951641 try testing.expect(lastIndexOfAny(u8, "boo, cat", "abo").? == 6);
1596 try testing.expect(lastIndexOfScalar(u8, "boo", 'o').? == 2);
1642 try testing.expect(findScalarLast(u8, "boo", 'o').? == 2);
15971643}
15981644
15991645test "indexOf multibyte" {
......@@ -3079,6 +3125,101 @@ test endsWith {
30793125 try testing.expect(!endsWith(u8, "Bob", "Bo"));
30803126}
30813127
3128/// If `slice` starts with `prefix`, returns the rest of `slice` starting at `prefix.len`.
3129pub fn cutPrefix(comptime T: type, slice: []const T, prefix: []const T) ?[]const T {
3130 return if (startsWith(T, slice, prefix)) slice[prefix.len..] else null;
3131}
3132
3133test cutPrefix {
3134 try testing.expectEqualStrings("foo", cutPrefix(u8, "--example=foo", "--example=").?);
3135 try testing.expectEqual(null, cutPrefix(u8, "--example=foo", "-example="));
3136}
3137
3138/// If `slice` ends with `suffix`, returns `slice` from beginning to start of `suffix`.
3139pub fn cutSuffix(comptime T: type, slice: []const T, suffix: []const T) ?[]const T {
3140 return if (endsWith(T, slice, suffix)) slice[0 .. slice.len - suffix.len] else null;
3141}
3142
3143test cutSuffix {
3144 try testing.expectEqualStrings("foo", cutSuffix(u8, "foobar", "bar").?);
3145 try testing.expectEqual(null, cutSuffix(u8, "foobar", "baz"));
3146}
3147
3148/// Returns slice of `haystack` before and after first occurrence of `needle`,
3149/// or `null` if not found.
3150///
3151/// See also:
3152/// * `cutScalar`
3153/// * `split`
3154/// * `tokenizeAny`
3155pub fn cut(comptime T: type, haystack: []const T, needle: []const T) ?struct { []const T, []const T } {
3156 const index = find(T, haystack, needle) orelse return null;
3157 return .{ haystack[0..index], haystack[index + needle.len ..] };
3158}
3159
3160test cut {
3161 try testing.expectEqual(null, cut(u8, "a b c", "B"));
3162 const before, const after = cut(u8, "a be c", "be") orelse return error.TestFailed;
3163 try testing.expectEqualStrings("a ", before);
3164 try testing.expectEqualStrings(" c", after);
3165}
3166
3167/// Returns slice of `haystack` before and after last occurrence of `needle`,
3168/// or `null` if not found.
3169///
3170/// See also:
3171/// * `cut`
3172/// * `cutScalarLast`
3173pub fn cutLast(comptime T: type, haystack: []const T, needle: []const T) ?struct { []const T, []const T } {
3174 const index = findLast(T, haystack, needle) orelse return null;
3175 return .{ haystack[0..index], haystack[index + needle.len ..] };
3176}
3177
3178test cutLast {
3179 try testing.expectEqual(null, cutLast(u8, "a b c", "B"));
3180 const before, const after = cutLast(u8, "a be c be d", "be") orelse return error.TestFailed;
3181 try testing.expectEqualStrings("a be c ", before);
3182 try testing.expectEqualStrings(" d", after);
3183}
3184
3185/// Returns slice of `haystack` before and after first occurrence `needle`, or
3186/// `null` if not found.
3187///
3188/// See also:
3189/// * `cut`
3190/// * `splitScalar`
3191/// * `tokenizeScalar`
3192pub fn cutScalar(comptime T: type, haystack: []const T, needle: T) ?struct { []const T, []const T } {
3193 const index = findScalar(T, haystack, needle) orelse return null;
3194 return .{ haystack[0..index], haystack[index + 1 ..] };
3195}
3196
3197test cutScalar {
3198 try testing.expectEqual(null, cutScalar(u8, "a b c", 'B'));
3199 const before, const after = cutScalar(u8, "a b c", 'b') orelse return error.TestFailed;
3200 try testing.expectEqualStrings("a ", before);
3201 try testing.expectEqualStrings(" c", after);
3202}
3203
3204/// Returns slice of `haystack` before and after last occurrence of `needle`,
3205/// or `null` if not found.
3206///
3207/// See also:
3208/// * `cut`
3209/// * `splitScalar`
3210/// * `tokenizeScalar`
3211pub fn cutScalarLast(comptime T: type, haystack: []const T, needle: T) ?struct { []const T, []const T } {
3212 const index = findScalarLast(T, haystack, needle) orelse return null;
3213 return .{ haystack[0..index], haystack[index + 1 ..] };
3214}
3215
3216test cutScalarLast {
3217 try testing.expectEqual(null, cutScalarLast(u8, "a b c", 'B'));
3218 const before, const after = cutScalarLast(u8, "a b c b d", 'b') orelse return error.TestFailed;
3219 try testing.expectEqualStrings("a b c ", before);
3220 try testing.expectEqualStrings(" d", after);
3221}
3222
30823223/// Delimiter type for tokenization and splitting operations.
30833224pub const DelimiterType = enum { sequence, any, scalar };
30843225
......@@ -3248,7 +3389,7 @@ pub fn SplitBackwardsIterator(comptime T: type, comptime delimiter_type: Delimit
32483389 const start = if (switch (delimiter_type) {
32493390 .sequence => lastIndexOf(T, self.buffer[0..end], self.delimiter),
32503391 .any => lastIndexOfAny(T, self.buffer[0..end], self.delimiter),
3251 .scalar => lastIndexOfScalar(T, self.buffer[0..end], self.delimiter),
3392 .scalar => findScalarLast(T, self.buffer[0..end], self.delimiter),
32523393 }) |delim_start| blk: {
32533394 self.index = delim_start;
32543395 break :blk delim_start + switch (delimiter_type) {
......@@ -3562,9 +3703,12 @@ test minMax {
35623703 }
35633704}
35643705
3706/// Deprecated in favor of `findMin`.
3707pub const indexOfMin = findMin;
3708
35653709/// Returns the index of the smallest number in a slice. O(n).
35663710/// `slice` must not be empty.
3567pub fn indexOfMin(comptime T: type, slice: []const T) usize {
3711pub fn findMin(comptime T: type, slice: []const T) usize {
35683712 assert(slice.len > 0);
35693713 var best = slice[0];
35703714 var index: usize = 0;
......@@ -3577,15 +3721,17 @@ pub fn indexOfMin(comptime T: type, slice: []const T) usize {
35773721 return index;
35783722}
35793723
3580test indexOfMin {
3581 try testing.expectEqual(indexOfMin(u8, "abcdefg"), 0);
3582 try testing.expectEqual(indexOfMin(u8, "bcdefga"), 6);
3583 try testing.expectEqual(indexOfMin(u8, "a"), 0);
3724test findMin {
3725 try testing.expectEqual(findMin(u8, "abcdefg"), 0);
3726 try testing.expectEqual(findMin(u8, "bcdefga"), 6);
3727 try testing.expectEqual(findMin(u8, "a"), 0);
35843728}
35853729
3730pub const indexOfMax = findMax;
3731
35863732/// Returns the index of the largest number in a slice. O(n).
35873733/// `slice` must not be empty.
3588pub fn indexOfMax(comptime T: type, slice: []const T) usize {
3734pub fn findMax(comptime T: type, slice: []const T) usize {
35893735 assert(slice.len > 0);
35903736 var best = slice[0];
35913737 var index: usize = 0;
......@@ -3598,16 +3744,19 @@ pub fn indexOfMax(comptime T: type, slice: []const T) usize {
35983744 return index;
35993745}
36003746
3601test indexOfMax {
3602 try testing.expectEqual(indexOfMax(u8, "abcdefg"), 6);
3603 try testing.expectEqual(indexOfMax(u8, "gabcdef"), 0);
3604 try testing.expectEqual(indexOfMax(u8, "a"), 0);
3747test findMax {
3748 try testing.expectEqual(findMax(u8, "abcdefg"), 6);
3749 try testing.expectEqual(findMax(u8, "gabcdef"), 0);
3750 try testing.expectEqual(findMax(u8, "a"), 0);
36053751}
36063752
3753/// Deprecated in favor of `findMinMax`.
3754pub const indexOfMinMax = findMinMax;
3755
36073756/// Finds the indices of the smallest and largest number in a slice. O(n).
36083757/// Returns the indices of the smallest and largest numbers in that order.
36093758/// `slice` must not be empty.
3610pub fn indexOfMinMax(comptime T: type, slice: []const T) struct { usize, usize } {
3759pub fn findMinMax(comptime T: type, slice: []const T) struct { usize, usize } {
36113760 assert(slice.len > 0);
36123761 var minVal = slice[0];
36133762 var maxVal = slice[0];
......@@ -3626,10 +3775,10 @@ pub fn indexOfMinMax(comptime T: type, slice: []const T) struct { usize, usize }
36263775 return .{ minIdx, maxIdx };
36273776}
36283777
3629test indexOfMinMax {
3630 try testing.expectEqual(.{ 0, 6 }, indexOfMinMax(u8, "abcdefg"));
3631 try testing.expectEqual(.{ 1, 0 }, indexOfMinMax(u8, "gabcdef"));
3632 try testing.expectEqual(.{ 0, 0 }, indexOfMinMax(u8, "a"));
3778test findMinMax {
3779 try testing.expectEqual(.{ 0, 6 }, findMinMax(u8, "abcdefg"));
3780 try testing.expectEqual(.{ 1, 0 }, findMinMax(u8, "gabcdef"));
3781 try testing.expectEqual(.{ 0, 0 }, findMinMax(u8, "a"));
36333782}
36343783
36353784/// Exchanges contents of two memory locations.
src/main.zig+107-132
......@@ -1022,10 +1022,9 @@ fn buildOutputType(
10221022
10231023 var file_ext: ?Compilation.FileExt = null;
10241024 args_loop: while (args_iter.next()) |arg| {
1025 if (mem.startsWith(u8, arg, "@")) {
1025 if (mem.cutPrefix(u8, arg, "@")) |resp_file_path| {
10261026 // This is a "compiler response file". We must parse the file and treat its
10271027 // contents as command line parameters.
1028 const resp_file_path = arg[1..];
10291028 args_iter.resp_file = initArgIteratorResponseFile(arena, resp_file_path) catch |err| {
10301029 fatal("unable to read response file '{s}': {s}", .{ resp_file_path, @errorName(err) });
10311030 };
......@@ -1043,9 +1042,8 @@ fn buildOutputType(
10431042 fatal("unexpected end-of-parameter mark: --", .{});
10441043 }
10451044 } else if (mem.eql(u8, arg, "--dep")) {
1046 var it = mem.splitScalar(u8, args_iter.nextOrFatal(), '=');
1047 const key = it.first();
1048 const value = if (it.peek() != null) it.rest() else key;
1045 const next_arg = args_iter.nextOrFatal();
1046 const key, const value = mem.cutScalar(u8, next_arg, '=') orelse .{ next_arg, next_arg };
10491047 if (mem.eql(u8, key, "std") and !mem.eql(u8, value, "std")) {
10501048 fatal("unable to import as '{s}': conflicts with builtin module", .{
10511049 key,
......@@ -1062,10 +1060,8 @@ fn buildOutputType(
10621060 .key = key,
10631061 .value = value,
10641062 });
1065 } else if (mem.startsWith(u8, arg, "-M")) {
1066 var it = mem.splitScalar(u8, arg["-M".len..], '=');
1067 const mod_name = it.first();
1068 const root_src_orig = if (it.peek() != null) it.rest() else null;
1063 } else if (mem.cutPrefix(u8, arg, "-M")) |rest| {
1064 const mod_name, const root_src_orig = mem.cutScalar(u8, rest, '=') orelse .{ rest, null };
10691065 try handleModArg(
10701066 arena,
10711067 mod_name,
......@@ -1096,8 +1092,8 @@ fn buildOutputType(
10961092 }
10971093 } else if (mem.eql(u8, arg, "-rcincludes")) {
10981094 rc_includes = parseRcIncludes(args_iter.nextOrFatal());
1099 } else if (mem.startsWith(u8, arg, "-rcincludes=")) {
1100 rc_includes = parseRcIncludes(arg["-rcincludes=".len..]);
1095 } else if (mem.cutPrefix(u8, arg, "-rcincludes=")) |rest| {
1096 rc_includes = parseRcIncludes(rest);
11011097 } else if (mem.eql(u8, arg, "-rcflags")) {
11021098 extra_rcflags.shrinkRetainingCapacity(0);
11031099 while (true) {
......@@ -1107,9 +1103,9 @@ fn buildOutputType(
11071103 if (mem.eql(u8, next_arg, "--")) break;
11081104 try extra_rcflags.append(arena, next_arg);
11091105 }
1110 } else if (mem.startsWith(u8, arg, "-fstructured-cfg")) {
1106 } else if (mem.eql(u8, arg, "-fstructured-cfg")) {
11111107 mod_opts.structured_cfg = true;
1112 } else if (mem.startsWith(u8, arg, "-fno-structured-cfg")) {
1108 } else if (mem.eql(u8, arg, "-fno-structured-cfg")) {
11131109 mod_opts.structured_cfg = false;
11141110 } else if (mem.eql(u8, arg, "--color")) {
11151111 const next_arg = args_iter.next() orelse {
......@@ -1118,8 +1114,7 @@ fn buildOutputType(
11181114 color = std.meta.stringToEnum(Color, next_arg) orelse {
11191115 fatal("expected [auto|on|off] after --color, found '{s}'", .{next_arg});
11201116 };
1121 } else if (mem.startsWith(u8, arg, "-j")) {
1122 const str = arg["-j".len..];
1117 } else if (mem.cutPrefix(u8, arg, "-j")) |str| {
11231118 const num = std.fmt.parseUnsigned(u32, str, 10) catch |err| {
11241119 fatal("unable to parse jobs count '{s}': {s}", .{
11251120 str, @errorName(err),
......@@ -1133,8 +1128,8 @@ fn buildOutputType(
11331128 subsystem = try parseSubSystem(args_iter.nextOrFatal());
11341129 } else if (mem.eql(u8, arg, "-O")) {
11351130 mod_opts.optimize_mode = parseOptimizeMode(args_iter.nextOrFatal());
1136 } else if (mem.startsWith(u8, arg, "-fentry=")) {
1137 entry = .{ .named = arg["-fentry=".len..] };
1131 } else if (mem.cutPrefix(u8, arg, "-fentry=")) |rest| {
1132 entry = .{ .named = rest };
11381133 } else if (mem.eql(u8, arg, "--force_undefined")) {
11391134 try force_undefined_symbols.put(arena, args_iter.nextOrFatal(), {});
11401135 } else if (mem.eql(u8, arg, "--discard-all")) {
......@@ -1161,8 +1156,7 @@ fn buildOutputType(
11611156 try create_module.frameworks.put(arena, args_iter.nextOrFatal(), .{ .needed = true });
11621157 } else if (mem.eql(u8, arg, "-install_name")) {
11631158 install_name = args_iter.nextOrFatal();
1164 } else if (mem.startsWith(u8, arg, "--compress-debug-sections=")) {
1165 const param = arg["--compress-debug-sections=".len..];
1159 } else if (mem.cutPrefix(u8, arg, "--compress-debug-sections=")) |param| {
11661160 linker_compress_debug_sections = std.meta.stringToEnum(link.File.Lld.Elf.CompressDebugSections, param) orelse {
11671161 fatal("expected --compress-debug-sections=[none|zlib|zstd], found '{s}'", .{param});
11681162 };
......@@ -1260,8 +1254,8 @@ fn buildOutputType(
12601254 try cc_argv.appendSlice(arena, &.{ arg, args_iter.nextOrFatal() });
12611255 } else if (mem.eql(u8, arg, "-I")) {
12621256 try cssan.addIncludePath(arena, &cc_argv, .I, arg, args_iter.nextOrFatal(), false);
1263 } else if (mem.startsWith(u8, arg, "--embed-dir=")) {
1264 try cssan.addIncludePath(arena, &cc_argv, .embed_dir, arg, arg["--embed-dir=".len..], true);
1257 } else if (mem.cutPrefix(u8, arg, "--embed-dir=")) |rest| {
1258 try cssan.addIncludePath(arena, &cc_argv, .embed_dir, arg, rest, true);
12651259 } else if (mem.eql(u8, arg, "-isystem")) {
12661260 try cssan.addIncludePath(arena, &cc_argv, .isystem, arg, args_iter.nextOrFatal(), false);
12671261 } else if (mem.eql(u8, arg, "-iwithsysroot")) {
......@@ -1288,14 +1282,14 @@ fn buildOutputType(
12881282 target_mcpu = args_iter.nextOrFatal();
12891283 } else if (mem.eql(u8, arg, "-mcmodel")) {
12901284 mod_opts.code_model = parseCodeModel(args_iter.nextOrFatal());
1291 } else if (mem.startsWith(u8, arg, "-mcmodel=")) {
1292 mod_opts.code_model = parseCodeModel(arg["-mcmodel=".len..]);
1293 } else if (mem.startsWith(u8, arg, "-ofmt=")) {
1294 create_module.object_format = arg["-ofmt=".len..];
1295 } else if (mem.startsWith(u8, arg, "-mcpu=")) {
1296 target_mcpu = arg["-mcpu=".len..];
1297 } else if (mem.startsWith(u8, arg, "-O")) {
1298 mod_opts.optimize_mode = parseOptimizeMode(arg["-O".len..]);
1285 } else if (mem.cutPrefix(u8, arg, "-mcmodel=")) |rest| {
1286 mod_opts.code_model = parseCodeModel(rest);
1287 } else if (mem.cutPrefix(u8, arg, "-ofmt=")) |rest| {
1288 create_module.object_format = rest;
1289 } else if (mem.cutPrefix(u8, arg, "-mcpu=")) |rest| {
1290 target_mcpu = rest;
1291 } else if (mem.cutPrefix(u8, arg, "-O")) |rest| {
1292 mod_opts.optimize_mode = parseOptimizeMode(rest);
12991293 } else if (mem.eql(u8, arg, "--dynamic-linker")) {
13001294 create_module.dynamic_linker = args_iter.nextOrFatal();
13011295 } else if (mem.eql(u8, arg, "--sysroot")) {
......@@ -1331,9 +1325,7 @@ fn buildOutputType(
13311325 } else {
13321326 dev.check(.network_listen);
13331327 // example: --listen 127.0.0.1:9000
1334 var it = std.mem.splitScalar(u8, next_arg, ':');
1335 const host = it.next().?;
1336 const port_text = it.next() orelse "14735";
1328 const host, const port_text = mem.cutScalar(u8, next_arg, ':') orelse .{ next_arg, "14735" };
13371329 const port = std.fmt.parseInt(u16, port_text, 10) catch |err|
13381330 fatal("invalid port number: '{s}': {s}", .{ port_text, @errorName(err) });
13391331 listen = .{ .ip4 = std.net.Ip4Address.parse(host, port) catch |err|
......@@ -1393,8 +1385,7 @@ fn buildOutputType(
13931385 create_module.opts.pie = false;
13941386 } else if (mem.eql(u8, arg, "-flto")) {
13951387 create_module.opts.lto = .full;
1396 } else if (mem.startsWith(u8, arg, "-flto=")) {
1397 const mode = arg["-flto=".len..];
1388 } else if (mem.cutPrefix(u8, arg, "-flto=")) |mode| {
13981389 if (mem.eql(u8, mode, "full")) {
13991390 create_module.opts.lto = .full;
14001391 } else if (mem.eql(u8, mode, "thin")) {
......@@ -1428,8 +1419,7 @@ fn buildOutputType(
14281419 mod_opts.omit_frame_pointer = false;
14291420 } else if (mem.eql(u8, arg, "-fsanitize-c")) {
14301421 mod_opts.sanitize_c = .full;
1431 } else if (mem.startsWith(u8, arg, "-fsanitize-c=")) {
1432 const mode = arg["-fsanitize-c=".len..];
1422 } else if (mem.cutPrefix(u8, arg, "-fsanitize-c=")) |mode| {
14331423 if (mem.eql(u8, mode, "trap")) {
14341424 mod_opts.sanitize_c = .trap;
14351425 } else if (mem.eql(u8, mode, "full")) {
......@@ -1477,8 +1467,7 @@ fn buildOutputType(
14771467 create_module.opts.san_cov_trace_pc_guard = false;
14781468 } else if (mem.eql(u8, arg, "-freference-trace")) {
14791469 reference_trace = 256;
1480 } else if (mem.startsWith(u8, arg, "-freference-trace=")) {
1481 const num = arg["-freference-trace=".len..];
1470 } else if (mem.cutPrefix(u8, arg, "-freference-trace=")) |num| {
14821471 reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
14831472 fatal("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) });
14841473 };
......@@ -1492,51 +1481,51 @@ fn buildOutputType(
14921481 create_module.opts.rdynamic = true;
14931482 } else if (mem.eql(u8, arg, "-fsoname")) {
14941483 soname = .yes_default_value;
1495 } else if (mem.startsWith(u8, arg, "-fsoname=")) {
1496 soname = .{ .yes = arg["-fsoname=".len..] };
1484 } else if (mem.cutPrefix(u8, arg, "-fsoname=")) |rest| {
1485 soname = .{ .yes = rest };
14971486 } else if (mem.eql(u8, arg, "-fno-soname")) {
14981487 soname = .no;
14991488 } else if (mem.eql(u8, arg, "-femit-bin")) {
15001489 emit_bin = .yes_default_path;
1501 } else if (mem.startsWith(u8, arg, "-femit-bin=")) {
1502 emit_bin = .{ .yes = arg["-femit-bin=".len..] };
1490 } else if (mem.cutPrefix(u8, arg, "-femit-bin=")) |rest| {
1491 emit_bin = .{ .yes = rest };
15031492 } else if (mem.eql(u8, arg, "-fno-emit-bin")) {
15041493 emit_bin = .no;
15051494 } else if (mem.eql(u8, arg, "-femit-h")) {
15061495 emit_h = .yes_default_path;
1507 } else if (mem.startsWith(u8, arg, "-femit-h=")) {
1508 emit_h = .{ .yes = arg["-femit-h=".len..] };
1496 } else if (mem.cutPrefix(u8, arg, "-femit-h=")) |rest| {
1497 emit_h = .{ .yes = rest };
15091498 } else if (mem.eql(u8, arg, "-fno-emit-h")) {
15101499 emit_h = .no;
15111500 } else if (mem.eql(u8, arg, "-femit-asm")) {
15121501 emit_asm = .yes_default_path;
1513 } else if (mem.startsWith(u8, arg, "-femit-asm=")) {
1514 emit_asm = .{ .yes = arg["-femit-asm=".len..] };
1502 } else if (mem.cutPrefix(u8, arg, "-femit-asm=")) |rest| {
1503 emit_asm = .{ .yes = rest };
15151504 } else if (mem.eql(u8, arg, "-fno-emit-asm")) {
15161505 emit_asm = .no;
15171506 } else if (mem.eql(u8, arg, "-femit-llvm-ir")) {
15181507 emit_llvm_ir = .yes_default_path;
1519 } else if (mem.startsWith(u8, arg, "-femit-llvm-ir=")) {
1520 emit_llvm_ir = .{ .yes = arg["-femit-llvm-ir=".len..] };
1508 } else if (mem.cutPrefix(u8, arg, "-femit-llvm-ir=")) |rest| {
1509 emit_llvm_ir = .{ .yes = rest };
15211510 } else if (mem.eql(u8, arg, "-fno-emit-llvm-ir")) {
15221511 emit_llvm_ir = .no;
15231512 } else if (mem.eql(u8, arg, "-femit-llvm-bc")) {
15241513 emit_llvm_bc = .yes_default_path;
1525 } else if (mem.startsWith(u8, arg, "-femit-llvm-bc=")) {
1526 emit_llvm_bc = .{ .yes = arg["-femit-llvm-bc=".len..] };
1514 } else if (mem.cutPrefix(u8, arg, "-femit-llvm-bc=")) |rest| {
1515 emit_llvm_bc = .{ .yes = rest };
15271516 } else if (mem.eql(u8, arg, "-fno-emit-llvm-bc")) {
15281517 emit_llvm_bc = .no;
15291518 } else if (mem.eql(u8, arg, "-femit-docs")) {
15301519 emit_docs = .yes_default_path;
1531 } else if (mem.startsWith(u8, arg, "-femit-docs=")) {
1532 emit_docs = .{ .yes = arg["-femit-docs=".len..] };
1520 } else if (mem.cutPrefix(u8, arg, "-femit-docs=")) |rest| {
1521 emit_docs = .{ .yes = rest };
15331522 } else if (mem.eql(u8, arg, "-fno-emit-docs")) {
15341523 emit_docs = .no;
15351524 } else if (mem.eql(u8, arg, "-femit-implib")) {
15361525 emit_implib = .yes_default_path;
15371526 emit_implib_arg_provided = true;
1538 } else if (mem.startsWith(u8, arg, "-femit-implib=")) {
1539 emit_implib = .{ .yes = arg["-femit-implib=".len..] };
1527 } else if (mem.cutPrefix(u8, arg, "-femit-implib=")) |rest| {
1528 emit_implib = .{ .yes = rest };
15401529 emit_implib_arg_provided = true;
15411530 } else if (mem.eql(u8, arg, "-fno-emit-implib")) {
15421531 emit_implib = .no;
......@@ -1586,8 +1575,7 @@ fn buildOutputType(
15861575 mod_opts.no_builtin = false;
15871576 } else if (mem.eql(u8, arg, "-fno-builtin")) {
15881577 mod_opts.no_builtin = true;
1589 } else if (mem.startsWith(u8, arg, "-fopt-bisect-limit=")) {
1590 const next_arg = arg["-fopt-bisect-limit=".len..];
1578 } else if (mem.cutPrefix(u8, arg, "-fopt-bisect-limit=")) |next_arg| {
15911579 llvm_opt_bisect_limit = std.fmt.parseInt(c_int, next_arg, 0) catch |err|
15921580 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
15931581 } else if (mem.eql(u8, arg, "--eh-frame-hdr")) {
......@@ -1630,10 +1618,10 @@ fn buildOutputType(
16301618 linker_z_relro = true;
16311619 } else if (mem.eql(u8, z_arg, "norelro")) {
16321620 linker_z_relro = false;
1633 } else if (mem.startsWith(u8, z_arg, "common-page-size=")) {
1634 linker_z_common_page_size = parseIntSuffix(z_arg, "common-page-size=".len);
1635 } else if (mem.startsWith(u8, z_arg, "max-page-size=")) {
1636 linker_z_max_page_size = parseIntSuffix(z_arg, "max-page-size=".len);
1621 } else if (prefixedIntArg(z_arg, "common-page-size=")) |int| {
1622 linker_z_common_page_size = int;
1623 } else if (prefixedIntArg(z_arg, "max-page-size=")) |int| {
1624 linker_z_max_page_size = int;
16371625 } else {
16381626 fatal("unsupported linker extension flag: -z {s}", .{z_arg});
16391627 }
......@@ -1654,16 +1642,16 @@ fn buildOutputType(
16541642 linker_import_table = true;
16551643 } else if (mem.eql(u8, arg, "--export-table")) {
16561644 linker_export_table = true;
1657 } else if (mem.startsWith(u8, arg, "--initial-memory=")) {
1658 linker_initial_memory = parseIntSuffix(arg, "--initial-memory=".len);
1659 } else if (mem.startsWith(u8, arg, "--max-memory=")) {
1660 linker_max_memory = parseIntSuffix(arg, "--max-memory=".len);
1645 } else if (prefixedIntArg(arg, "--initial-memory=")) |int| {
1646 linker_initial_memory = int;
1647 } else if (prefixedIntArg(arg, "--max-memory=")) |int| {
1648 linker_max_memory = int;
16611649 } else if (mem.eql(u8, arg, "--shared-memory")) {
16621650 create_module.opts.shared_memory = true;
1663 } else if (mem.startsWith(u8, arg, "--global-base=")) {
1664 linker_global_base = parseIntSuffix(arg, "--global-base=".len);
1665 } else if (mem.startsWith(u8, arg, "--export=")) {
1666 try linker_export_symbol_names.append(arena, arg["--export=".len..]);
1651 } else if (prefixedIntArg(arg, "--global-base=")) |int| {
1652 linker_global_base = int;
1653 } else if (mem.cutPrefix(u8, arg, "--export=")) |rest| {
1654 try linker_export_symbol_names.append(arena, rest);
16671655 } else if (mem.eql(u8, arg, "-Bsymbolic")) {
16681656 linker_bind_global_refs_locally = true;
16691657 } else if (mem.eql(u8, arg, "--gc-sections")) {
......@@ -1672,8 +1660,7 @@ fn buildOutputType(
16721660 linker_gc_sections = false;
16731661 } else if (mem.eql(u8, arg, "--build-id")) {
16741662 build_id = .fast;
1675 } else if (mem.startsWith(u8, arg, "--build-id=")) {
1676 const style = arg["--build-id=".len..];
1663 } else if (mem.cutPrefix(u8, arg, "--build-id=")) |style| {
16771664 build_id = std.zig.BuildId.parse(style) catch |err| {
16781665 fatal("unable to parse --build-id style '{s}': {s}", .{
16791666 style, @errorName(err),
......@@ -1697,26 +1684,26 @@ fn buildOutputType(
16971684 verbose_generic_instances = true;
16981685 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
16991686 verbose_llvm_ir = "-";
1700 } else if (mem.startsWith(u8, arg, "--verbose-llvm-ir=")) {
1701 verbose_llvm_ir = arg["--verbose-llvm-ir=".len..];
1702 } else if (mem.startsWith(u8, arg, "--verbose-llvm-bc=")) {
1703 verbose_llvm_bc = arg["--verbose-llvm-bc=".len..];
1687 } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-ir=")) |rest| {
1688 verbose_llvm_ir = rest;
1689 } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-bc=")) |rest| {
1690 verbose_llvm_bc = rest;
17041691 } else if (mem.eql(u8, arg, "--verbose-cimport")) {
17051692 verbose_cimport = true;
17061693 } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) {
17071694 verbose_llvm_cpu_features = true;
1708 } else if (mem.startsWith(u8, arg, "-T")) {
1709 linker_script = arg[2..];
1710 } else if (mem.startsWith(u8, arg, "-L")) {
1711 try create_module.lib_dir_args.append(arena, arg[2..]);
1712 } else if (mem.startsWith(u8, arg, "-F")) {
1713 try create_module.framework_dirs.append(arena, arg[2..]);
1714 } else if (mem.startsWith(u8, arg, "-l")) {
1695 } else if (mem.cutPrefix(u8, arg, "-T")) |rest| {
1696 linker_script = rest;
1697 } else if (mem.cutPrefix(u8, arg, "-L")) |rest| {
1698 try create_module.lib_dir_args.append(arena, rest);
1699 } else if (mem.cutPrefix(u8, arg, "-F")) |rest| {
1700 try create_module.framework_dirs.append(arena, rest);
1701 } else if (mem.cutPrefix(u8, arg, "-l")) |name| {
17151702 // We don't know whether this library is part of libc
17161703 // or libc++ until we resolve the target, so we append
17171704 // to the list for now.
17181705 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
1719 .name = arg["-l".len..],
1706 .name = name,
17201707 .query = .{
17211708 .needed = false,
17221709 .weak = false,
......@@ -1725,9 +1712,9 @@ fn buildOutputType(
17251712 .allow_so_scripts = allow_so_scripts,
17261713 },
17271714 } });
1728 } else if (mem.startsWith(u8, arg, "-needed-l")) {
1715 } else if (mem.cutPrefix(u8, arg, "-needed-l")) |name| {
17291716 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
1730 .name = arg["-needed-l".len..],
1717 .name = name,
17311718 .query = .{
17321719 .needed = true,
17331720 .weak = false,
......@@ -1736,9 +1723,9 @@ fn buildOutputType(
17361723 .allow_so_scripts = allow_so_scripts,
17371724 },
17381725 } });
1739 } else if (mem.startsWith(u8, arg, "-weak-l")) {
1726 } else if (mem.cutPrefix(u8, arg, "-weak-l")) |name| {
17401727 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
1741 .name = arg["-weak-l".len..],
1728 .name = name,
17421729 .query = .{
17431730 .needed = false,
17441731 .weak = true,
......@@ -1749,13 +1736,10 @@ fn buildOutputType(
17491736 } });
17501737 } else if (mem.startsWith(u8, arg, "-D")) {
17511738 try cc_argv.append(arena, arg);
1752 } else if (mem.startsWith(u8, arg, "-I")) {
1753 try cssan.addIncludePath(arena, &cc_argv, .I, arg, arg[2..], true);
1754 } else if (mem.startsWith(u8, arg, "-x")) {
1755 const lang = if (arg.len == "-x".len)
1756 args_iter.nextOrFatal()
1757 else
1758 arg["-x".len..];
1739 } else if (mem.cutPrefix(u8, arg, "-I")) |rest| {
1740 try cssan.addIncludePath(arena, &cc_argv, .I, arg, rest, true);
1741 } else if (mem.cutPrefix(u8, arg, "-x")) |rest| {
1742 const lang = if (rest.len == 0) args_iter.nextOrFatal() else rest;
17591743 if (mem.eql(u8, lang, "none")) {
17601744 file_ext = null;
17611745 } else if (Compilation.LangToExt.get(lang)) |got_ext| {
......@@ -1763,8 +1747,8 @@ fn buildOutputType(
17631747 } else {
17641748 fatal("language not recognized: '{s}'", .{lang});
17651749 }
1766 } else if (mem.startsWith(u8, arg, "-mexec-model=")) {
1767 create_module.opts.wasi_exec_model = parseWasiExecModel(arg["-mexec-model=".len..]);
1750 } else if (mem.cutPrefix(u8, arg, "-mexec-model=")) |rest| {
1751 create_module.opts.wasi_exec_model = parseWasiExecModel(rest);
17681752 } else if (mem.eql(u8, arg, "-municode")) {
17691753 mingw_unicode_entry_point = true;
17701754 } else {
......@@ -2442,8 +2426,8 @@ fn buildOutputType(
24422426 linker_enable_new_dtags = false;
24432427 } else if (mem.eql(u8, arg, "-O")) {
24442428 linker_optimization = linker_args_it.nextOrFatal();
2445 } else if (mem.startsWith(u8, arg, "-O")) {
2446 linker_optimization = arg["-O".len..];
2429 } else if (mem.cutPrefix(u8, arg, "-O")) |rest| {
2430 linker_optimization = rest;
24472431 } else if (mem.eql(u8, arg, "-pagezero_size")) {
24482432 const next_arg = linker_args_it.nextOrFatal();
24492433 pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| {
......@@ -2525,11 +2509,8 @@ fn buildOutputType(
25252509 linker_compress_debug_sections = std.meta.stringToEnum(link.File.Lld.Elf.CompressDebugSections, arg1) orelse {
25262510 fatal("expected [none|zlib|zstd] after --compress-debug-sections, found '{s}'", .{arg1});
25272511 };
2528 } else if (mem.startsWith(u8, arg, "-z")) {
2529 var z_arg = arg[2..];
2530 if (z_arg.len == 0) {
2531 z_arg = linker_args_it.nextOrFatal();
2532 }
2512 } else if (mem.cutPrefix(u8, arg, "-z")) |z_rest| {
2513 const z_arg = if (z_rest.len == 0) linker_args_it.nextOrFatal() else z_rest;
25332514 if (mem.eql(u8, z_arg, "nodelete")) {
25342515 linker_z_nodelete = true;
25352516 } else if (mem.eql(u8, z_arg, "notext")) {
......@@ -2552,12 +2533,12 @@ fn buildOutputType(
25522533 linker_z_relro = true;
25532534 } else if (mem.eql(u8, z_arg, "norelro")) {
25542535 linker_z_relro = false;
2555 } else if (mem.startsWith(u8, z_arg, "stack-size=")) {
2556 stack_size = parseStackSize(z_arg["stack-size=".len..]);
2557 } else if (mem.startsWith(u8, z_arg, "common-page-size=")) {
2558 linker_z_common_page_size = parseIntSuffix(z_arg, "common-page-size=".len);
2559 } else if (mem.startsWith(u8, z_arg, "max-page-size=")) {
2560 linker_z_max_page_size = parseIntSuffix(z_arg, "max-page-size=".len);
2536 } else if (mem.cutPrefix(u8, z_arg, "stack-size=")) |rest| {
2537 stack_size = parseStackSize(rest);
2538 } else if (prefixedIntArg(z_arg, "common-page-size=")) |int| {
2539 linker_z_common_page_size = int;
2540 } else if (prefixedIntArg(z_arg, "max-page-size=")) |int| {
2541 linker_z_max_page_size = int;
25612542 } else {
25622543 fatal("unsupported linker extension flag: -z {s}", .{z_arg});
25632544 }
......@@ -2671,9 +2652,9 @@ fn buildOutputType(
26712652 .allow_so_scripts = allow_so_scripts,
26722653 },
26732654 } });
2674 } else if (mem.startsWith(u8, arg, "-weak-l")) {
2655 } else if (mem.cutPrefix(u8, arg, "-weak-l")) |rest| {
26752656 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
2676 .name = arg["-weak-l".len..],
2657 .name = rest,
26772658 .query = .{
26782659 .weak = true,
26792660 .needed = false,
......@@ -3768,8 +3749,7 @@ fn createModule(
37683749 try mcpu_buffer.appendSlice(cli_mod.target_mcpu orelse "baseline");
37693750
37703751 for (create_module.llvm_m_args.items) |llvm_m_arg| {
3771 if (mem.startsWith(u8, llvm_m_arg, "mno-")) {
3772 const llvm_name = llvm_m_arg["mno-".len..];
3752 if (mem.cutPrefix(u8, llvm_m_arg, "mno-")) |llvm_name| {
37733753 const zig_name = llvm_to_zig_name.get(llvm_name) orelse {
37743754 fatal("target architecture {s} has no LLVM CPU feature named '{s}'", .{
37753755 @tagName(cpu_arch), llvm_name,
......@@ -3777,8 +3757,7 @@ fn createModule(
37773757 };
37783758 try mcpu_buffer.append('-');
37793759 try mcpu_buffer.appendSlice(zig_name);
3780 } else if (mem.startsWith(u8, llvm_m_arg, "m")) {
3781 const llvm_name = llvm_m_arg["m".len..];
3760 } else if (mem.cutPrefix(u8, llvm_m_arg, "m")) |llvm_name| {
37823761 const zig_name = llvm_to_zig_name.get(llvm_name) orelse {
37833762 fatal("target architecture {s} has no LLVM CPU feature named '{s}'", .{
37843763 @tagName(cpu_arch), llvm_name,
......@@ -4850,9 +4829,8 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
48504829 reference_trace = 256;
48514830 } else if (mem.eql(u8, arg, "--fetch")) {
48524831 fetch_only = true;
4853 } else if (mem.startsWith(u8, arg, "--fetch=")) {
4832 } else if (mem.cutPrefix(u8, arg, "--fetch=")) |sub_arg| {
48544833 fetch_only = true;
4855 const sub_arg = arg["--fetch=".len..];
48564834 fetch_mode = std.meta.stringToEnum(Package.Fetch.JobQueue.Mode, sub_arg) orelse
48574835 fatal("expected [needed|all] after '--fetch=', found '{s}'", .{
48584836 sub_arg,
......@@ -4863,8 +4841,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
48634841 system_pkg_dir_path = args[i];
48644842 try child_argv.append("--system");
48654843 continue;
4866 } else if (mem.startsWith(u8, arg, "-freference-trace=")) {
4867 const num = arg["-freference-trace=".len..];
4844 } else if (mem.cutPrefix(u8, arg, "-freference-trace=")) |num| {
48684845 reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
48694846 fatal("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) });
48704847 };
......@@ -4914,10 +4891,10 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
49144891 verbose_generic_instances = true;
49154892 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
49164893 verbose_llvm_ir = "-";
4917 } else if (mem.startsWith(u8, arg, "--verbose-llvm-ir=")) {
4918 verbose_llvm_ir = arg["--verbose-llvm-ir=".len..];
4919 } else if (mem.startsWith(u8, arg, "--verbose-llvm-bc=")) {
4920 verbose_llvm_bc = arg["--verbose-llvm-bc=".len..];
4894 } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-ir=")) |rest| {
4895 verbose_llvm_ir = rest;
4896 } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-bc=")) |rest| {
4897 verbose_llvm_bc = rest;
49214898 } else if (mem.eql(u8, arg, "--verbose-cimport")) {
49224899 verbose_cimport = true;
49234900 } 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 {
49304907 };
49314908 try child_argv.appendSlice(&.{ arg, args[i] });
49324909 continue;
4933 } else if (mem.startsWith(u8, arg, "-j")) {
4934 const str = arg["-j".len..];
4910 } else if (mem.cutPrefix(u8, arg, "-j")) |str| {
49354911 const num = std.fmt.parseUnsigned(u32, str, 10) catch |err| {
49364912 fatal("unable to parse jobs count '{s}': {s}", .{
49374913 str, @errorName(err),
......@@ -6507,10 +6483,9 @@ fn eatIntPrefix(arg: []const u8, base: u8) []const u8 {
65076483 return arg;
65086484}
65096485
6510fn parseIntSuffix(arg: []const u8, prefix_len: usize) u64 {
6511 return std.fmt.parseUnsigned(u64, arg[prefix_len..], 0) catch |err| {
6512 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
6513 };
6486fn prefixedIntArg(arg: []const u8, prefix: []const u8) ?u64 {
6487 const number = mem.cutPrefix(u8, arg, prefix) orelse return null;
6488 return std.fmt.parseUnsigned(u64, number, 0) catch |err| fatal("unable to parse '{s}': {t}", .{ arg, err });
65146489}
65156490
65166491fn warnAboutForeignBinaries(
......@@ -6837,12 +6812,12 @@ fn cmdFetch(
68376812 debug_hash = true;
68386813 } else if (mem.eql(u8, arg, "--save")) {
68396814 save = .{ .yes = null };
6840 } else if (mem.startsWith(u8, arg, "--save=")) {
6841 save = .{ .yes = arg["--save=".len..] };
6815 } else if (mem.cutPrefix(u8, arg, "--save=")) |rest| {
6816 save = .{ .yes = rest };
68426817 } else if (mem.eql(u8, arg, "--save-exact")) {
68436818 save = .{ .exact = null };
6844 } else if (mem.startsWith(u8, arg, "--save-exact=")) {
6845 save = .{ .exact = arg["--save-exact=".len..] };
6819 } else if (mem.cutPrefix(u8, arg, "--save-exact=")) |rest| {
6820 save = .{ .exact = rest };
68466821 } else {
68476822 fatal("unrecognized parameter: '{s}'", .{arg});
68486823 }