Merge pull request #15579 from squeek502/mem-delimiters

Split `std.mem.split` and `tokenize` into `sequence`, `any`, and `scalar` versions
This commit is contained in:
Andrew Kelley 2023-06-03 13:51:02 -07:00 committed by GitHub
commit 629f0d23b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 591 additions and 239 deletions

View File

@ -235,7 +235,7 @@ pub fn build(b: *std.Build) !void {
}, },
2 => { 2 => {
// Untagged development build (e.g. 0.10.0-dev.2025+ecf0050a9). // Untagged development build (e.g. 0.10.0-dev.2025+ecf0050a9).
var it = mem.split(u8, git_describe, "-"); var it = mem.splitScalar(u8, git_describe, '-');
const tagged_ancestor = it.first(); const tagged_ancestor = it.first();
const commit_height = it.next().?; const commit_height = it.next().?;
const commit_id = it.next().?; const commit_id = it.next().?;
@ -280,7 +280,7 @@ pub fn build(b: *std.Build) !void {
// That means we also have to rely on stage1 compiled c++ files. We parse config.h to find // That means we also have to rely on stage1 compiled c++ files. We parse config.h to find
// the information passed on to us from cmake. // the information passed on to us from cmake.
if (cfg.cmake_prefix_path.len > 0) { if (cfg.cmake_prefix_path.len > 0) {
var it = mem.tokenize(u8, cfg.cmake_prefix_path, ";"); var it = mem.tokenizeScalar(u8, cfg.cmake_prefix_path, ';');
while (it.next()) |path| { while (it.next()) |path| {
b.addSearchPrefix(path); b.addSearchPrefix(path);
} }
@ -682,7 +682,7 @@ fn addCxxKnownPath(
if (!std.process.can_spawn) if (!std.process.can_spawn)
return error.RequiredLibraryNotFound; return error.RequiredLibraryNotFound;
const path_padded = b.exec(&.{ ctx.cxx_compiler, b.fmt("-print-file-name={s}", .{objname}) }); const path_padded = b.exec(&.{ ctx.cxx_compiler, b.fmt("-print-file-name={s}", .{objname}) });
var tokenizer = mem.tokenize(u8, path_padded, "\r\n"); var tokenizer = mem.tokenizeAny(u8, path_padded, "\r\n");
const path_unpadded = tokenizer.next().?; const path_unpadded = tokenizer.next().?;
if (mem.eql(u8, path_unpadded, objname)) { if (mem.eql(u8, path_unpadded, objname)) {
if (errtxt) |msg| { if (errtxt) |msg| {
@ -705,7 +705,7 @@ fn addCxxKnownPath(
} }
fn addCMakeLibraryList(exe: *std.Build.Step.Compile, list: []const u8) void { fn addCMakeLibraryList(exe: *std.Build.Step.Compile, list: []const u8) void {
var it = mem.tokenize(u8, list, ";"); var it = mem.tokenizeScalar(u8, list, ';');
while (it.next()) |lib| { while (it.next()) |lib| {
if (mem.startsWith(u8, lib, "-l")) { if (mem.startsWith(u8, lib, "-l")) {
exe.linkSystemLibrary(lib["-l".len..]); exe.linkSystemLibrary(lib["-l".len..]);
@ -850,18 +850,18 @@ fn parseConfigH(b: *std.Build, config_h_text: []const u8) ?CMakeConfig {
// .prefix = ZIG_LLVM_LINK_MODE parsed manually below // .prefix = ZIG_LLVM_LINK_MODE parsed manually below
}; };
var lines_it = mem.tokenize(u8, config_h_text, "\r\n"); var lines_it = mem.tokenizeAny(u8, config_h_text, "\r\n");
while (lines_it.next()) |line| { while (lines_it.next()) |line| {
inline for (mappings) |mapping| { inline for (mappings) |mapping| {
if (mem.startsWith(u8, line, mapping.prefix)) { if (mem.startsWith(u8, line, mapping.prefix)) {
var it = mem.split(u8, line, "\""); var it = mem.splitScalar(u8, line, '"');
_ = it.first(); // skip the stuff before the quote _ = it.first(); // skip the stuff before the quote
const quoted = it.next().?; // the stuff inside the quote const quoted = it.next().?; // the stuff inside the quote
@field(ctx, mapping.field) = toNativePathSep(b, quoted); @field(ctx, mapping.field) = toNativePathSep(b, quoted);
} }
} }
if (mem.startsWith(u8, line, "#define ZIG_LLVM_LINK_MODE ")) { if (mem.startsWith(u8, line, "#define ZIG_LLVM_LINK_MODE ")) {
var it = mem.split(u8, line, "\""); var it = mem.splitScalar(u8, line, '"');
_ = it.next().?; // skip the stuff before the quote _ = it.next().?; // skip the stuff before the quote
const quoted = it.next().?; // the stuff inside the quote const quoted = it.next().?; // the stuff inside the quote
ctx.llvm_linkage = if (mem.eql(u8, quoted, "shared")) .dynamic else .static; ctx.llvm_linkage = if (mem.eql(u8, quoted, "shared")) .dynamic else .static;

View File

@ -1223,7 +1223,7 @@ fn printShell(out: anytype, shell_content: []const u8, escape: bool) !void {
const trimmed_shell_content = mem.trim(u8, shell_content, " \n"); const trimmed_shell_content = mem.trim(u8, shell_content, " \n");
try out.writeAll("<figure><figcaption class=\"shell-cap\">Shell</figcaption><pre><samp>"); try out.writeAll("<figure><figcaption class=\"shell-cap\">Shell</figcaption><pre><samp>");
var cmd_cont: bool = false; var cmd_cont: bool = false;
var iter = std.mem.split(u8, trimmed_shell_content, "\n"); var iter = std.mem.splitScalar(u8, trimmed_shell_content, '\n');
while (iter.next()) |orig_line| { while (iter.next()) |orig_line| {
const line = mem.trimRight(u8, orig_line, " "); const line = mem.trimRight(u8, orig_line, " ");
if (!cmd_cont and line.len > 1 and mem.eql(u8, line[0..2], "$ ") and line[line.len - 1] != '\\') { if (!cmd_cont and line.len > 1 and mem.eql(u8, line[0..2], "$ ") and line[line.len - 1] != '\\') {

View File

@ -1388,7 +1388,7 @@ pub fn findProgram(self: *Build, names: []const []const u8, paths: []const []con
if (fs.path.isAbsolute(name)) { if (fs.path.isAbsolute(name)) {
return name; return name;
} }
var it = mem.tokenize(u8, PATH, &[_]u8{fs.path.delimiter}); var it = mem.tokenizeScalar(u8, PATH, fs.path.delimiter);
while (it.next()) |path| { while (it.next()) |path| {
const full_path = self.pathJoin(&.{ const full_path = self.pathJoin(&.{
path, path,

View File

@ -438,7 +438,7 @@ pub const Manifest = struct {
const input_file_count = self.files.items.len; const input_file_count = self.files.items.len;
var any_file_changed = false; var any_file_changed = false;
var line_iter = mem.tokenize(u8, file_contents, "\n"); var line_iter = mem.tokenizeScalar(u8, file_contents, '\n');
var idx: usize = 0; var idx: usize = 0;
if (if (line_iter.next()) |line| !std.mem.eql(u8, line, manifest_header) else true) { if (if (line_iter.next()) |line| !std.mem.eql(u8, line, manifest_header) else true) {
if (try self.upgradeToExclusiveLock()) continue; if (try self.upgradeToExclusiveLock()) continue;
@ -467,7 +467,7 @@ pub const Manifest = struct {
break :blk new; break :blk new;
}; };
var iter = mem.tokenize(u8, line, " "); var iter = mem.tokenizeScalar(u8, line, ' ');
const size = iter.next() orelse return error.InvalidFormat; const size = iter.next() orelse return error.InvalidFormat;
const inode = iter.next() orelse return error.InvalidFormat; const inode = iter.next() orelse return error.InvalidFormat;
const mtime_nsec_str = iter.next() orelse return error.InvalidFormat; const mtime_nsec_str = iter.next() orelse return error.InvalidFormat;

View File

@ -103,8 +103,8 @@ const Action = struct {
assert(act.tag == .match or act.tag == .not_present); assert(act.tag == .match or act.tag == .not_present);
const phrase = act.phrase.resolve(b, step); const phrase = act.phrase.resolve(b, step);
var candidate_var: ?struct { name: []const u8, value: u64 } = null; var candidate_var: ?struct { name: []const u8, value: u64 } = null;
var hay_it = mem.tokenize(u8, mem.trim(u8, haystack, " "), " "); var hay_it = mem.tokenizeScalar(u8, mem.trim(u8, haystack, " "), ' ');
var needle_it = mem.tokenize(u8, mem.trim(u8, phrase, " "), " "); var needle_it = mem.tokenizeScalar(u8, mem.trim(u8, phrase, " "), ' ');
while (needle_it.next()) |needle_tok| { while (needle_it.next()) |needle_tok| {
const hay_tok = hay_it.next() orelse return false; const hay_tok = hay_it.next() orelse return false;
@ -155,7 +155,7 @@ const Action = struct {
var op_stack = std.ArrayList(enum { add, sub, mod, mul }).init(gpa); var op_stack = std.ArrayList(enum { add, sub, mod, mul }).init(gpa);
var values = std.ArrayList(u64).init(gpa); var values = std.ArrayList(u64).init(gpa);
var it = mem.tokenize(u8, phrase, " "); var it = mem.tokenizeScalar(u8, phrase, ' ');
while (it.next()) |next| { while (it.next()) |next| {
if (mem.eql(u8, next, "+")) { if (mem.eql(u8, next, "+")) {
try op_stack.append(.add); try op_stack.append(.add);
@ -365,7 +365,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
var vars = std.StringHashMap(u64).init(gpa); var vars = std.StringHashMap(u64).init(gpa);
for (self.checks.items) |chk| { for (self.checks.items) |chk| {
var it = mem.tokenize(u8, output, "\r\n"); var it = mem.tokenizeAny(u8, output, "\r\n");
for (chk.actions.items) |act| { for (chk.actions.items) |act| {
switch (act.tag) { switch (act.tag) {
.match => { .match => {

View File

@ -853,7 +853,7 @@ fn runPkgConfig(self: *Compile, lib_name: []const u8) ![]const []const u8 {
var zig_args = ArrayList([]const u8).init(b.allocator); var zig_args = ArrayList([]const u8).init(b.allocator);
defer zig_args.deinit(); defer zig_args.deinit();
var it = mem.tokenize(u8, stdout, " \r\n\t"); var it = mem.tokenizeAny(u8, stdout, " \r\n\t");
while (it.next()) |tok| { while (it.next()) |tok| {
if (mem.eql(u8, tok, "-I")) { if (mem.eql(u8, tok, "-I")) {
const dir = it.next() orelse return error.PkgConfigInvalidOutput; const dir = it.next() orelse return error.PkgConfigInvalidOutput;
@ -2101,10 +2101,10 @@ fn execPkgConfigList(self: *std.Build, out_code: *u8) (PkgConfigError || ExecErr
const stdout = try self.execAllowFail(&[_][]const u8{ "pkg-config", "--list-all" }, out_code, .Ignore); const stdout = try self.execAllowFail(&[_][]const u8{ "pkg-config", "--list-all" }, out_code, .Ignore);
var list = ArrayList(PkgConfigPkg).init(self.allocator); var list = ArrayList(PkgConfigPkg).init(self.allocator);
errdefer list.deinit(); errdefer list.deinit();
var line_it = mem.tokenize(u8, stdout, "\r\n"); var line_it = mem.tokenizeAny(u8, stdout, "\r\n");
while (line_it.next()) |line| { while (line_it.next()) |line| {
if (mem.trim(u8, line, " \t").len == 0) continue; if (mem.trim(u8, line, " \t").len == 0) continue;
var tok_it = mem.tokenize(u8, line, " \t"); var tok_it = mem.tokenizeAny(u8, line, " \t");
try list.append(PkgConfigPkg{ try list.append(PkgConfigPkg{
.name = tok_it.next() orelse return error.PkgConfigInvalidOutput, .name = tok_it.next() orelse return error.PkgConfigInvalidOutput,
.desc = tok_it.rest(), .desc = tok_it.rest(),
@ -2224,7 +2224,7 @@ fn checkCompileErrors(self: *Compile) !void {
// Render the expected lines into a string that we can compare verbatim. // Render the expected lines into a string that we can compare verbatim.
var expected_generated = std.ArrayList(u8).init(arena); var expected_generated = std.ArrayList(u8).init(arena);
var actual_line_it = mem.split(u8, actual_stderr, "\n"); var actual_line_it = mem.splitScalar(u8, actual_stderr, '\n');
for (self.expect_errors) |expect_line| { for (self.expect_errors) |expect_line| {
const actual_line = actual_line_it.next() orelse { const actual_line = actual_line_it.next() orelse {
try expected_generated.appendSlice(expect_line); try expected_generated.appendSlice(expect_line);

View File

@ -250,14 +250,14 @@ fn render_autoconf(
var any_errors = false; var any_errors = false;
var line_index: u32 = 0; var line_index: u32 = 0;
var line_it = std.mem.split(u8, contents, "\n"); var line_it = std.mem.splitScalar(u8, contents, '\n');
while (line_it.next()) |line| : (line_index += 1) { while (line_it.next()) |line| : (line_index += 1) {
if (!std.mem.startsWith(u8, line, "#")) { if (!std.mem.startsWith(u8, line, "#")) {
try output.appendSlice(line); try output.appendSlice(line);
try output.appendSlice("\n"); try output.appendSlice("\n");
continue; continue;
} }
var it = std.mem.tokenize(u8, line[1..], " \t\r"); var it = std.mem.tokenizeAny(u8, line[1..], " \t\r");
const undef = it.next().?; const undef = it.next().?;
if (!std.mem.eql(u8, undef, "undef")) { if (!std.mem.eql(u8, undef, "undef")) {
try output.appendSlice(line); try output.appendSlice(line);
@ -297,14 +297,14 @@ fn render_cmake(
var any_errors = false; var any_errors = false;
var line_index: u32 = 0; var line_index: u32 = 0;
var line_it = std.mem.split(u8, contents, "\n"); var line_it = std.mem.splitScalar(u8, contents, '\n');
while (line_it.next()) |line| : (line_index += 1) { while (line_it.next()) |line| : (line_index += 1) {
if (!std.mem.startsWith(u8, line, "#")) { if (!std.mem.startsWith(u8, line, "#")) {
try output.appendSlice(line); try output.appendSlice(line);
try output.appendSlice("\n"); try output.appendSlice("\n");
continue; continue;
} }
var it = std.mem.tokenize(u8, line[1..], " \t\r"); var it = std.mem.tokenizeAny(u8, line[1..], " \t\r");
const cmakedefine = it.next().?; const cmakedefine = it.next().?;
if (!std.mem.eql(u8, cmakedefine, "cmakedefine") and if (!std.mem.eql(u8, cmakedefine, "cmakedefine") and
!std.mem.eql(u8, cmakedefine, "cmakedefine01")) !std.mem.eql(u8, cmakedefine, "cmakedefine01"))

View File

@ -42,8 +42,8 @@ pub fn order(lhs: Version, rhs: Version) std.math.Order {
if (lhs.pre == null and rhs.pre != null) return .gt; if (lhs.pre == null and rhs.pre != null) return .gt;
// Iterate over pre-release identifiers until a difference is found. // Iterate over pre-release identifiers until a difference is found.
var lhs_pre_it = std.mem.split(u8, lhs.pre.?, "."); var lhs_pre_it = std.mem.splitScalar(u8, lhs.pre.?, '.');
var rhs_pre_it = std.mem.split(u8, rhs.pre.?, "."); var rhs_pre_it = std.mem.splitScalar(u8, rhs.pre.?, '.');
while (true) { while (true) {
const next_lid = lhs_pre_it.next(); const next_lid = lhs_pre_it.next();
const next_rid = rhs_pre_it.next(); const next_rid = rhs_pre_it.next();
@ -86,7 +86,7 @@ pub fn parse(text: []const u8) !Version {
// Parse the required major, minor, and patch numbers. // Parse the required major, minor, and patch numbers.
const extra_index = std.mem.indexOfAny(u8, text, "-+"); const extra_index = std.mem.indexOfAny(u8, text, "-+");
const required = text[0..(extra_index orelse text.len)]; const required = text[0..(extra_index orelse text.len)];
var it = std.mem.split(u8, required, "."); var it = std.mem.splitScalar(u8, required, '.');
var ver = Version{ var ver = Version{
.major = try parseNum(it.first()), .major = try parseNum(it.first()),
.minor = try parseNum(it.next() orelse return error.InvalidVersion), .minor = try parseNum(it.next() orelse return error.InvalidVersion),
@ -108,7 +108,7 @@ pub fn parse(text: []const u8) !Version {
// Check validity of optional pre-release identifiers. // Check validity of optional pre-release identifiers.
// See: https://semver.org/#spec-item-9 // See: https://semver.org/#spec-item-9
if (ver.pre) |pre| { if (ver.pre) |pre| {
it = std.mem.split(u8, pre, "."); it = std.mem.splitScalar(u8, pre, '.');
while (it.next()) |id| { while (it.next()) |id| {
// Identifiers MUST NOT be empty. // Identifiers MUST NOT be empty.
if (id.len == 0) return error.InvalidVersion; if (id.len == 0) return error.InvalidVersion;
@ -127,7 +127,7 @@ pub fn parse(text: []const u8) !Version {
// Check validity of optional build metadata identifiers. // Check validity of optional build metadata identifiers.
// See: https://semver.org/#spec-item-10 // See: https://semver.org/#spec-item-10
if (ver.build) |build| { if (ver.build) |build| {
it = std.mem.split(u8, build, "."); it = std.mem.splitScalar(u8, build, '.');
while (it.next()) |id| { while (it.next()) |id| {
// Identifiers MUST NOT be empty. // Identifiers MUST NOT be empty.
if (id.len == 0) return error.InvalidVersion; if (id.len == 0) return error.InvalidVersion;

View File

@ -531,7 +531,7 @@ pub const Version = struct {
// found no digits or '.' before unexpected character // found no digits or '.' before unexpected character
if (end == 0) return error.InvalidVersion; if (end == 0) return error.InvalidVersion;
var it = std.mem.split(u8, text[0..end], "."); var it = std.mem.splitScalar(u8, text[0..end], '.');
// substring is not empty, first call will succeed // substring is not empty, first call will succeed
const major = it.first(); const major = it.first();
if (major.len == 0) return error.InvalidVersion; if (major.len == 0) return error.InvalidVersion;

View File

@ -850,7 +850,7 @@ pub const ChildProcess = struct {
return original_err; return original_err;
} }
var it = mem.tokenize(u16, PATH, &[_]u16{';'}); var it = mem.tokenizeScalar(u16, PATH, ';');
while (it.next()) |search_path| { while (it.next()) |search_path| {
dir_buf.clearRetainingCapacity(); dir_buf.clearRetainingCapacity();
try dir_buf.appendSlice(self.allocator, search_path); try dir_buf.appendSlice(self.allocator, search_path);
@ -1064,7 +1064,7 @@ fn windowsCreateProcessPathExt(
// Now we know that at least *a* file matching the wildcard exists, we can loop // Now we know that at least *a* file matching the wildcard exists, we can loop
// through PATHEXT in order and exec any that exist // through PATHEXT in order and exec any that exist
var ext_it = mem.tokenize(u16, pathext, &[_]u16{';'}); var ext_it = mem.tokenizeScalar(u16, pathext, ';');
while (ext_it.next()) |ext| { while (ext_it.next()) |ext| {
if (!windowsCreateProcessSupportsExtension(ext)) continue; if (!windowsCreateProcessSupportsExtension(ext)) continue;

View File

@ -337,8 +337,8 @@ pub const Parsed = struct {
return true; // exact match return true; // exact match
} }
var it_host = std.mem.split(u8, host_name, "."); var it_host = std.mem.splitScalar(u8, host_name, '.');
var it_dns = std.mem.split(u8, dns_name, "."); var it_dns = std.mem.splitScalar(u8, dns_name, '.');
const len_match = while (true) { const len_match = while (true) {
const host = it_host.next(); const host = it_host.next();

View File

@ -7,9 +7,12 @@ const mem = std.mem;
const meta = std.meta; const meta = std.meta;
const fields_delimiter = "$"; const fields_delimiter = "$";
const fields_delimiter_scalar = '$';
const version_param_name = "v"; const version_param_name = "v";
const params_delimiter = ","; const params_delimiter = ",";
const params_delimiter_scalar = ',';
const kv_delimiter = "="; const kv_delimiter = "=";
const kv_delimiter_scalar = '=';
pub const Error = std.crypto.errors.EncodingError || error{NoSpaceLeft}; pub const Error = std.crypto.errors.EncodingError || error{NoSpaceLeft};
@ -73,7 +76,7 @@ pub fn BinValue(comptime max_len: usize) type {
/// Other fields will also be deserialized from the function parameters section. /// Other fields will also be deserialized from the function parameters section.
pub fn deserialize(comptime HashResult: type, str: []const u8) Error!HashResult { pub fn deserialize(comptime HashResult: type, str: []const u8) Error!HashResult {
var out = mem.zeroes(HashResult); var out = mem.zeroes(HashResult);
var it = mem.split(u8, str, fields_delimiter); var it = mem.splitScalar(u8, str, fields_delimiter_scalar);
var set_fields: usize = 0; var set_fields: usize = 0;
while (true) { while (true) {
@ -104,7 +107,7 @@ pub fn deserialize(comptime HashResult: type, str: []const u8) Error!HashResult
// Read optional parameters // Read optional parameters
var has_params = false; var has_params = false;
var it_params = mem.split(u8, field, params_delimiter); var it_params = mem.splitScalar(u8, field, params_delimiter_scalar);
while (it_params.next()) |params| { while (it_params.next()) |params| {
const param = kvSplit(params) catch break; const param = kvSplit(params) catch break;
var found = false; var found = false;
@ -252,7 +255,7 @@ fn serializeTo(params: anytype, out: anytype) !void {
// Split a `key=value` string into `key` and `value` // Split a `key=value` string into `key` and `value`
fn kvSplit(str: []const u8) !struct { key: []const u8, value: []const u8 } { fn kvSplit(str: []const u8) !struct { key: []const u8, value: []const u8 } {
var it = mem.split(u8, str, kv_delimiter); var it = mem.splitScalar(u8, str, kv_delimiter_scalar);
const key = it.first(); const key = it.first();
const value = it.next() orelse return Error.InvalidEncoding; const value = it.next() orelse return Error.InvalidEncoding;
const ret = .{ .key = key, .value = value }; const ret = .{ .key = key, .value = value };

View File

@ -287,7 +287,7 @@ const crypt_format = struct {
out.r = try Codec.intDecode(u30, str[4..9]); out.r = try Codec.intDecode(u30, str[4..9]);
out.p = try Codec.intDecode(u30, str[9..14]); out.p = try Codec.intDecode(u30, str[9..14]);
var it = mem.split(u8, str[14..], "$"); var it = mem.splitScalar(u8, str[14..], '$');
const salt = it.first(); const salt = it.first();
if (@hasField(T, "salt")) out.salt = salt; if (@hasField(T, "salt")) out.salt = salt;

View File

@ -3021,7 +3021,7 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 {
} else if (argv0.len != 0) { } else if (argv0.len != 0) {
// argv[0] is not empty (and not a path): search it inside PATH // argv[0] is not empty (and not a path): search it inside PATH
const PATH = std.os.getenvZ("PATH") orelse return error.FileNotFound; const PATH = std.os.getenvZ("PATH") orelse return error.FileNotFound;
var path_it = mem.tokenize(u8, PATH, &[_]u8{path.delimiter}); var path_it = mem.tokenizeScalar(u8, PATH, path.delimiter);
while (path_it.next()) |a_path| { while (path_it.next()) |a_path| {
var resolved_path_buf: [MAX_PATH_BYTES - 1:0]u8 = undefined; var resolved_path_buf: [MAX_PATH_BYTES - 1:0]u8 = undefined;
const resolved_path = std.fmt.bufPrintZ(&resolved_path_buf, "{s}/{s}", .{ const resolved_path = std.fmt.bufPrintZ(&resolved_path_buf, "{s}/{s}", .{

View File

@ -358,7 +358,7 @@ pub fn windowsParsePath(path: []const u8) WindowsPath {
return relative_path; return relative_path;
} }
var it = mem.tokenize(u8, path, &[_]u8{this_sep}); var it = mem.tokenizeScalar(u8, path, this_sep);
_ = (it.next() orelse return relative_path); _ = (it.next() orelse return relative_path);
_ = (it.next() orelse return relative_path); _ = (it.next() orelse return relative_path);
return WindowsPath{ return WindowsPath{
@ -420,8 +420,8 @@ fn networkShareServersEql(ns1: []const u8, ns2: []const u8) bool {
const sep1 = ns1[0]; const sep1 = ns1[0];
const sep2 = ns2[0]; const sep2 = ns2[0];
var it1 = mem.tokenize(u8, ns1, &[_]u8{sep1}); var it1 = mem.tokenizeScalar(u8, ns1, sep1);
var it2 = mem.tokenize(u8, ns2, &[_]u8{sep2}); var it2 = mem.tokenizeScalar(u8, ns2, sep2);
// TODO ASCII is wrong, we actually need full unicode support to compare paths. // TODO ASCII is wrong, we actually need full unicode support to compare paths.
return ascii.eqlIgnoreCase(it1.next().?, it2.next().?); return ascii.eqlIgnoreCase(it1.next().?, it2.next().?);
@ -441,8 +441,8 @@ fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8
const sep1 = p1[0]; const sep1 = p1[0];
const sep2 = p2[0]; const sep2 = p2[0];
var it1 = mem.tokenize(u8, p1, &[_]u8{sep1}); var it1 = mem.tokenizeScalar(u8, p1, sep1);
var it2 = mem.tokenize(u8, p2, &[_]u8{sep2}); var it2 = mem.tokenizeScalar(u8, p2, sep2);
// TODO ASCII is wrong, we actually need full unicode support to compare paths. // TODO ASCII is wrong, we actually need full unicode support to compare paths.
return ascii.eqlIgnoreCase(it1.next().?, it2.next().?) and ascii.eqlIgnoreCase(it1.next().?, it2.next().?); return ascii.eqlIgnoreCase(it1.next().?, it2.next().?) and ascii.eqlIgnoreCase(it1.next().?, it2.next().?);
@ -535,7 +535,7 @@ pub fn resolveWindows(allocator: Allocator, paths: []const []const u8) ![]u8 {
break :l disk_designator.len; break :l disk_designator.len;
}, },
.NetworkShare => { .NetworkShare => {
var it = mem.tokenize(u8, paths[first_index], "/\\"); var it = mem.tokenizeAny(u8, paths[first_index], "/\\");
const server_name = it.next().?; const server_name = it.next().?;
const other_name = it.next().?; const other_name = it.next().?;
@ -570,7 +570,7 @@ pub fn resolveWindows(allocator: Allocator, paths: []const []const u8) ![]u8 {
if (!correct_disk_designator) { if (!correct_disk_designator) {
continue; continue;
} }
var it = mem.tokenize(u8, p[parsed.disk_designator.len..], "/\\"); var it = mem.tokenizeAny(u8, p[parsed.disk_designator.len..], "/\\");
while (it.next()) |component| { while (it.next()) |component| {
if (mem.eql(u8, component, ".")) { if (mem.eql(u8, component, ".")) {
continue; continue;
@ -657,7 +657,7 @@ pub fn resolvePosix(allocator: Allocator, paths: []const []const u8) Allocator.E
negative_count = 0; negative_count = 0;
result.clearRetainingCapacity(); result.clearRetainingCapacity();
} }
var it = mem.tokenize(u8, p, "/"); var it = mem.tokenizeScalar(u8, p, '/');
while (it.next()) |component| { while (it.next()) |component| {
if (mem.eql(u8, component, ".")) { if (mem.eql(u8, component, ".")) {
continue; continue;
@ -1078,8 +1078,8 @@ pub fn relativeWindows(allocator: Allocator, from: []const u8, to: []const u8) !
return resolved_to; return resolved_to;
} }
var from_it = mem.tokenize(u8, resolved_from, "/\\"); var from_it = mem.tokenizeAny(u8, resolved_from, "/\\");
var to_it = mem.tokenize(u8, resolved_to, "/\\"); var to_it = mem.tokenizeAny(u8, resolved_to, "/\\");
while (true) { while (true) {
const from_component = from_it.next() orelse return allocator.dupe(u8, to_it.rest()); const from_component = from_it.next() orelse return allocator.dupe(u8, to_it.rest());
const to_rest = to_it.rest(); const to_rest = to_it.rest();
@ -1102,7 +1102,7 @@ pub fn relativeWindows(allocator: Allocator, from: []const u8, to: []const u8) !
result_index += 3; result_index += 3;
} }
var rest_it = mem.tokenize(u8, to_rest, "/\\"); var rest_it = mem.tokenizeAny(u8, to_rest, "/\\");
while (rest_it.next()) |to_component| { while (rest_it.next()) |to_component| {
result[result_index] = '\\'; result[result_index] = '\\';
result_index += 1; result_index += 1;
@ -1124,8 +1124,8 @@ pub fn relativePosix(allocator: Allocator, from: []const u8, to: []const u8) ![]
const resolved_to = try resolvePosix(allocator, &[_][]const u8{ cwd, to }); const resolved_to = try resolvePosix(allocator, &[_][]const u8{ cwd, to });
defer allocator.free(resolved_to); defer allocator.free(resolved_to);
var from_it = mem.tokenize(u8, resolved_from, "/"); var from_it = mem.tokenizeScalar(u8, resolved_from, '/');
var to_it = mem.tokenize(u8, resolved_to, "/"); var to_it = mem.tokenizeScalar(u8, resolved_to, '/');
while (true) { while (true) {
const from_component = from_it.next() orelse return allocator.dupe(u8, to_it.rest()); const from_component = from_it.next() orelse return allocator.dupe(u8, to_it.rest());
const to_rest = to_it.rest(); const to_rest = to_it.rest();

View File

@ -331,7 +331,7 @@ pub const Response = struct {
}; };
pub fn parse(res: *Response, bytes: []const u8, trailing: bool) ParseError!void { pub fn parse(res: *Response, bytes: []const u8, trailing: bool) ParseError!void {
var it = mem.tokenize(u8, bytes[0 .. bytes.len - 4], "\r\n"); var it = mem.tokenizeAny(u8, bytes[0 .. bytes.len - 4], "\r\n");
const first_line = it.next() orelse return error.HttpHeadersInvalid; const first_line = it.next() orelse return error.HttpHeadersInvalid;
if (first_line.len < 12) if (first_line.len < 12)
@ -357,7 +357,7 @@ pub const Response = struct {
else => {}, else => {},
} }
var line_it = mem.tokenize(u8, line, ": "); var line_it = mem.tokenizeAny(u8, line, ": ");
const header_name = line_it.next() orelse return error.HttpHeadersInvalid; const header_name = line_it.next() orelse return error.HttpHeadersInvalid;
const header_value = line_it.rest(); const header_value = line_it.rest();
@ -371,7 +371,7 @@ pub const Response = struct {
} else if (std.ascii.eqlIgnoreCase(header_name, "transfer-encoding")) { } else if (std.ascii.eqlIgnoreCase(header_name, "transfer-encoding")) {
// Transfer-Encoding: second, first // Transfer-Encoding: second, first
// Transfer-Encoding: deflate, chunked // Transfer-Encoding: deflate, chunked
var iter = mem.splitBackwards(u8, header_value, ","); var iter = mem.splitBackwardsScalar(u8, header_value, ',');
if (iter.next()) |first| { if (iter.next()) |first| {
const trimmed = mem.trim(u8, first, " "); const trimmed = mem.trim(u8, first, " ");

View File

@ -178,7 +178,7 @@ pub const Request = struct {
}; };
pub fn parse(req: *Request, bytes: []const u8) ParseError!void { pub fn parse(req: *Request, bytes: []const u8) ParseError!void {
var it = mem.tokenize(u8, bytes[0 .. bytes.len - 4], "\r\n"); var it = mem.tokenizeAny(u8, bytes[0 .. bytes.len - 4], "\r\n");
const first_line = it.next() orelse return error.HttpHeadersInvalid; const first_line = it.next() orelse return error.HttpHeadersInvalid;
if (first_line.len < 10) if (first_line.len < 10)
@ -212,7 +212,7 @@ pub const Request = struct {
else => {}, else => {},
} }
var line_it = mem.tokenize(u8, line, ": "); var line_it = mem.tokenizeAny(u8, line, ": ");
const header_name = line_it.next() orelse return error.HttpHeadersInvalid; const header_name = line_it.next() orelse return error.HttpHeadersInvalid;
const header_value = line_it.rest(); const header_value = line_it.rest();
@ -224,7 +224,7 @@ pub const Request = struct {
} else if (std.ascii.eqlIgnoreCase(header_name, "transfer-encoding")) { } else if (std.ascii.eqlIgnoreCase(header_name, "transfer-encoding")) {
// Transfer-Encoding: second, first // Transfer-Encoding: second, first
// Transfer-Encoding: deflate, chunked // Transfer-Encoding: deflate, chunked
var iter = mem.splitBackwards(u8, header_value, ","); var iter = mem.splitBackwardsScalar(u8, header_value, ',');
if (iter.next()) |first| { if (iter.next()) |first| {
const trimmed = mem.trim(u8, first, " "); const trimmed = mem.trim(u8, first, " ");

View File

@ -1958,72 +1958,117 @@ test "byteSwapAllFields" {
}, k); }, k);
} }
/// Deprecated: use `tokenizeAny`, `tokenizeSequence`, or `tokenizeScalar`
pub const tokenize = tokenizeAny;
/// Returns an iterator that iterates over the slices of `buffer` that are not /// Returns an iterator that iterates over the slices of `buffer` that are not
/// any of the bytes in `delimiter_bytes`. /// any of the items in `delimiters`.
/// ///
/// `tokenize(u8, " abc def ghi ", " ")` will return slices /// `tokenizeAny(u8, " abc|def || ghi ", " |")` will return slices
/// for "abc", "def", "ghi", null, in that order. /// for "abc", "def", "ghi", null, in that order.
/// ///
/// If `buffer` is empty, the iterator will return null. /// If `buffer` is empty, the iterator will return null.
/// If `delimiter_bytes` does not exist in buffer, /// If none of `delimiters` exist in buffer,
/// the iterator will return `buffer`, null, in that order. /// the iterator will return `buffer`, null, in that order.
/// ///
/// See also: `split` and `splitBackwards`. /// See also: `tokenizeSequence`, `tokenizeScalar`,
pub fn tokenize(comptime T: type, buffer: []const T, delimiter_bytes: []const T) TokenIterator(T) { /// `splitSequence`,`splitAny`, `splitScalar`,
/// `splitBackwardsSequence`, `splitBackwardsAny`, and `splitBackwardsScalar`
pub fn tokenizeAny(comptime T: type, buffer: []const T, delimiters: []const T) TokenIterator(T, .any) {
return .{ return .{
.index = 0, .index = 0,
.buffer = buffer, .buffer = buffer,
.delimiter_bytes = delimiter_bytes, .delimiter = delimiters,
}; };
} }
test "tokenize" { /// Returns an iterator that iterates over the slices of `buffer` that are not
var it = tokenize(u8, " abc def ghi ", " "); /// the sequence in `delimiter`.
///
/// `tokenizeSequence(u8, "<>abc><def<><>ghi", "<>")` will return slices
/// for "abc><def", "ghi", null, in that order.
///
/// If `buffer` is empty, the iterator will return null.
/// If `delimiter` does not exist in buffer,
/// the iterator will return `buffer`, null, in that order.
/// The delimiter length must not be zero.
///
/// See also: `tokenizeAny`, `tokenizeScalar`,
/// `splitSequence`,`splitAny`, and `splitScalar`
/// `splitBackwardsSequence`, `splitBackwardsAny`, and `splitBackwardsScalar`
pub fn tokenizeSequence(comptime T: type, buffer: []const T, delimiter: []const T) TokenIterator(T, .sequence) {
assert(delimiter.len != 0);
return .{
.index = 0,
.buffer = buffer,
.delimiter = delimiter,
};
}
/// Returns an iterator that iterates over the slices of `buffer` that are not
/// `delimiter`.
///
/// `tokenizeScalar(u8, " abc def ghi ", ' ')` will return slices
/// for "abc", "def", "ghi", null, in that order.
///
/// If `buffer` is empty, the iterator will return null.
/// If `delimiter` does not exist in buffer,
/// the iterator will return `buffer`, null, in that order.
///
/// See also: `tokenizeAny`, `tokenizeSequence`,
/// `splitSequence`,`splitAny`, and `splitScalar`
/// `splitBackwardsSequence`, `splitBackwardsAny`, and `splitBackwardsScalar`
pub fn tokenizeScalar(comptime T: type, buffer: []const T, delimiter: T) TokenIterator(T, .scalar) {
return .{
.index = 0,
.buffer = buffer,
.delimiter = delimiter,
};
}
test "tokenizeScalar" {
var it = tokenizeScalar(u8, " abc def ghi ", ' ');
try testing.expect(eql(u8, it.next().?, "abc")); try testing.expect(eql(u8, it.next().?, "abc"));
try testing.expect(eql(u8, it.peek().?, "def")); try testing.expect(eql(u8, it.peek().?, "def"));
try testing.expect(eql(u8, it.next().?, "def")); try testing.expect(eql(u8, it.next().?, "def"));
try testing.expect(eql(u8, it.next().?, "ghi")); try testing.expect(eql(u8, it.next().?, "ghi"));
try testing.expect(it.next() == null); try testing.expect(it.next() == null);
it = tokenize(u8, "..\\bob", "\\"); it = tokenizeScalar(u8, "..\\bob", '\\');
try testing.expect(eql(u8, it.next().?, "..")); try testing.expect(eql(u8, it.next().?, ".."));
try testing.expect(eql(u8, "..", "..\\bob"[0..it.index])); try testing.expect(eql(u8, "..", "..\\bob"[0..it.index]));
try testing.expect(eql(u8, it.next().?, "bob")); try testing.expect(eql(u8, it.next().?, "bob"));
try testing.expect(it.next() == null); try testing.expect(it.next() == null);
it = tokenize(u8, "//a/b", "/"); it = tokenizeScalar(u8, "//a/b", '/');
try testing.expect(eql(u8, it.next().?, "a")); try testing.expect(eql(u8, it.next().?, "a"));
try testing.expect(eql(u8, it.next().?, "b")); try testing.expect(eql(u8, it.next().?, "b"));
try testing.expect(eql(u8, "//a/b", "//a/b"[0..it.index])); try testing.expect(eql(u8, "//a/b", "//a/b"[0..it.index]));
try testing.expect(it.next() == null); try testing.expect(it.next() == null);
it = tokenize(u8, "|", "|"); it = tokenizeScalar(u8, "|", '|');
try testing.expect(it.next() == null); try testing.expect(it.next() == null);
try testing.expect(it.peek() == null); try testing.expect(it.peek() == null);
it = tokenize(u8, "", "|"); it = tokenizeScalar(u8, "", '|');
try testing.expect(it.next() == null); try testing.expect(it.next() == null);
try testing.expect(it.peek() == null); try testing.expect(it.peek() == null);
it = tokenize(u8, "hello", ""); it = tokenizeScalar(u8, "hello", ' ');
try testing.expect(eql(u8, it.next().?, "hello")); try testing.expect(eql(u8, it.next().?, "hello"));
try testing.expect(it.next() == null); try testing.expect(it.next() == null);
it = tokenize(u8, "hello", " "); var it16 = tokenizeScalar(
try testing.expect(eql(u8, it.next().?, "hello"));
try testing.expect(it.next() == null);
var it16 = tokenize(
u16, u16,
std.unicode.utf8ToUtf16LeStringLiteral("hello"), std.unicode.utf8ToUtf16LeStringLiteral("hello"),
std.unicode.utf8ToUtf16LeStringLiteral(" "), ' ',
); );
try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("hello"))); try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("hello")));
try testing.expect(it16.next() == null); try testing.expect(it16.next() == null);
} }
test "tokenize (multibyte)" { test "tokenizeAny" {
var it = tokenize(u8, "a|b,c/d e", " /,|"); var it = tokenizeAny(u8, "a|b,c/d e", " /,|");
try testing.expect(eql(u8, it.next().?, "a")); try testing.expect(eql(u8, it.next().?, "a"));
try testing.expect(eql(u8, it.peek().?, "b")); try testing.expect(eql(u8, it.peek().?, "b"));
try testing.expect(eql(u8, it.next().?, "b")); try testing.expect(eql(u8, it.next().?, "b"));
@ -2033,7 +2078,11 @@ test "tokenize (multibyte)" {
try testing.expect(it.next() == null); try testing.expect(it.next() == null);
try testing.expect(it.peek() == null); try testing.expect(it.peek() == null);
var it16 = tokenize( it = tokenizeAny(u8, "hello", "");
try testing.expect(eql(u8, it.next().?, "hello"));
try testing.expect(it.next() == null);
var it16 = tokenizeAny(
u16, u16,
std.unicode.utf8ToUtf16LeStringLiteral("a|b,c/d e"), std.unicode.utf8ToUtf16LeStringLiteral("a|b,c/d e"),
std.unicode.utf8ToUtf16LeStringLiteral(" /,|"), std.unicode.utf8ToUtf16LeStringLiteral(" /,|"),
@ -2046,8 +2095,31 @@ test "tokenize (multibyte)" {
try testing.expect(it16.next() == null); try testing.expect(it16.next() == null);
} }
test "tokenizeSequence" {
var it = tokenizeSequence(u8, "a<>b<><>c><>d><", "<>");
try testing.expectEqualStrings("a", it.next().?);
try testing.expectEqualStrings("b", it.peek().?);
try testing.expectEqualStrings("b", it.next().?);
try testing.expectEqualStrings("c>", it.next().?);
try testing.expectEqualStrings("d><", it.next().?);
try testing.expect(it.next() == null);
try testing.expect(it.peek() == null);
var it16 = tokenizeSequence(
u16,
std.unicode.utf8ToUtf16LeStringLiteral("a<>b<><>c><>d><"),
std.unicode.utf8ToUtf16LeStringLiteral("<>"),
);
try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("a")));
try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("b")));
try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("c>")));
try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("d><")));
try testing.expect(it16.next() == null);
}
test "tokenize (reset)" { test "tokenize (reset)" {
var it = tokenize(u8, " abc def ghi ", " "); {
var it = tokenizeAny(u8, " abc def ghi ", " ");
try testing.expect(eql(u8, it.next().?, "abc")); try testing.expect(eql(u8, it.next().?, "abc"));
try testing.expect(eql(u8, it.next().?, "def")); try testing.expect(eql(u8, it.next().?, "def"));
try testing.expect(eql(u8, it.next().?, "ghi")); try testing.expect(eql(u8, it.next().?, "ghi"));
@ -2059,19 +2131,51 @@ test "tokenize (reset)" {
try testing.expect(eql(u8, it.next().?, "ghi")); try testing.expect(eql(u8, it.next().?, "ghi"));
try testing.expect(it.next() == null); try testing.expect(it.next() == null);
} }
{
var it = tokenizeSequence(u8, "<><>abc<>def<><>ghi<>", "<>");
try testing.expect(eql(u8, it.next().?, "abc"));
try testing.expect(eql(u8, it.next().?, "def"));
try testing.expect(eql(u8, it.next().?, "ghi"));
it.reset();
try testing.expect(eql(u8, it.next().?, "abc"));
try testing.expect(eql(u8, it.next().?, "def"));
try testing.expect(eql(u8, it.next().?, "ghi"));
try testing.expect(it.next() == null);
}
{
var it = tokenizeScalar(u8, " abc def ghi ", ' ');
try testing.expect(eql(u8, it.next().?, "abc"));
try testing.expect(eql(u8, it.next().?, "def"));
try testing.expect(eql(u8, it.next().?, "ghi"));
it.reset();
try testing.expect(eql(u8, it.next().?, "abc"));
try testing.expect(eql(u8, it.next().?, "def"));
try testing.expect(eql(u8, it.next().?, "ghi"));
try testing.expect(it.next() == null);
}
}
/// Deprecated: use `splitSequence`, `splitAny`, or `splitScalar`
pub const split = splitSequence;
/// Returns an iterator that iterates over the slices of `buffer` that /// Returns an iterator that iterates over the slices of `buffer` that
/// are separated by bytes in `delimiter`. /// are separated by the byte sequence in `delimiter`.
/// ///
/// `split(u8, "abc|def||ghi", "|")` will return slices /// `splitSequence(u8, "abc||def||||ghi", "||")` will return slices
/// for "abc", "def", "", "ghi", null, in that order. /// for "abc", "def", "", "ghi", null, in that order.
/// ///
/// If `delimiter` does not exist in buffer, /// If `delimiter` does not exist in buffer,
/// the iterator will return `buffer`, null, in that order. /// the iterator will return `buffer`, null, in that order.
/// The delimiter length must not be zero. /// The delimiter length must not be zero.
/// ///
/// See also: `tokenize` and `splitBackwards`. /// See also: `splitAny`, `splitScalar`, `splitBackwardsSequence`,
pub fn split(comptime T: type, buffer: []const T, delimiter: []const T) SplitIterator(T) { /// `splitBackwardsAny`,`splitBackwardsScalar`,
/// `tokenizeAny`, `tokenizeSequence`, and `tokenizeScalar`.
pub fn splitSequence(comptime T: type, buffer: []const T, delimiter: []const T) SplitIterator(T, .sequence) {
assert(delimiter.len != 0); assert(delimiter.len != 0);
return .{ return .{
.index = 0, .index = 0,
@ -2080,8 +2184,48 @@ pub fn split(comptime T: type, buffer: []const T, delimiter: []const T) SplitIte
}; };
} }
test "split" { /// Returns an iterator that iterates over the slices of `buffer` that
var it = split(u8, "abc|def||ghi", "|"); /// are separated by any item in `delimiters`.
///
/// `splitAny(u8, "abc,def||ghi", "|,")` will return slices
/// for "abc", "def", "", "ghi", null, in that order.
///
/// If none of `delimiters` exist in buffer,
/// the iterator will return `buffer`, null, in that order.
///
/// See also: `splitSequence`, `splitScalar`, `splitBackwardsSequence`,
/// `splitBackwardsAny`,`splitBackwardsScalar`,
/// `tokenizeAny`, `tokenizeSequence`, and `tokenizeScalar`.
pub fn splitAny(comptime T: type, buffer: []const T, delimiters: []const T) SplitIterator(T, .any) {
return .{
.index = 0,
.buffer = buffer,
.delimiter = delimiters,
};
}
/// Returns an iterator that iterates over the slices of `buffer` that
/// are separated by `delimiter`.
///
/// `splitScalar(u8, "abc|def||ghi", '|')` will return slices
/// for "abc", "def", "", "ghi", null, in that order.
///
/// If `delimiter` does not exist in buffer,
/// the iterator will return `buffer`, null, in that order.
///
/// See also: `splitSequence`, `splitAny`, `splitBackwardsSequence`,
/// `splitBackwardsAny`,`splitBackwardsScalar`,
/// `tokenizeAny`, `tokenizeSequence`, and `tokenizeScalar`.
pub fn splitScalar(comptime T: type, buffer: []const T, delimiter: T) SplitIterator(T, .scalar) {
return .{
.index = 0,
.buffer = buffer,
.delimiter = delimiter,
};
}
test "splitScalar" {
var it = splitScalar(u8, "abc|def||ghi", '|');
try testing.expectEqualSlices(u8, it.rest(), "abc|def||ghi"); try testing.expectEqualSlices(u8, it.rest(), "abc|def||ghi");
try testing.expectEqualSlices(u8, it.first(), "abc"); try testing.expectEqualSlices(u8, it.first(), "abc");
@ -2097,30 +2241,30 @@ test "split" {
try testing.expectEqualSlices(u8, it.rest(), ""); try testing.expectEqualSlices(u8, it.rest(), "");
try testing.expect(it.next() == null); try testing.expect(it.next() == null);
it = split(u8, "", "|"); it = splitScalar(u8, "", '|');
try testing.expectEqualSlices(u8, it.first(), ""); try testing.expectEqualSlices(u8, it.first(), "");
try testing.expect(it.next() == null); try testing.expect(it.next() == null);
it = split(u8, "|", "|"); it = splitScalar(u8, "|", '|');
try testing.expectEqualSlices(u8, it.first(), ""); try testing.expectEqualSlices(u8, it.first(), "");
try testing.expectEqualSlices(u8, it.next().?, ""); try testing.expectEqualSlices(u8, it.next().?, "");
try testing.expect(it.next() == null); try testing.expect(it.next() == null);
it = split(u8, "hello", " "); it = splitScalar(u8, "hello", ' ');
try testing.expectEqualSlices(u8, it.first(), "hello"); try testing.expectEqualSlices(u8, it.first(), "hello");
try testing.expect(it.next() == null); try testing.expect(it.next() == null);
var it16 = split( var it16 = splitScalar(
u16, u16,
std.unicode.utf8ToUtf16LeStringLiteral("hello"), std.unicode.utf8ToUtf16LeStringLiteral("hello"),
std.unicode.utf8ToUtf16LeStringLiteral(" "), ' ',
); );
try testing.expectEqualSlices(u16, it16.first(), std.unicode.utf8ToUtf16LeStringLiteral("hello")); try testing.expectEqualSlices(u16, it16.first(), std.unicode.utf8ToUtf16LeStringLiteral("hello"));
try testing.expect(it16.next() == null); try testing.expect(it16.next() == null);
} }
test "split (multibyte)" { test "splitSequence" {
var it = split(u8, "a, b ,, c, d, e", ", "); var it = splitSequence(u8, "a, b ,, c, d, e", ", ");
try testing.expectEqualSlices(u8, it.first(), "a"); try testing.expectEqualSlices(u8, it.first(), "a");
try testing.expectEqualSlices(u8, it.rest(), "b ,, c, d, e"); try testing.expectEqualSlices(u8, it.rest(), "b ,, c, d, e");
try testing.expectEqualSlices(u8, it.next().?, "b ,"); try testing.expectEqualSlices(u8, it.next().?, "b ,");
@ -2129,7 +2273,7 @@ test "split (multibyte)" {
try testing.expectEqualSlices(u8, it.next().?, "e"); try testing.expectEqualSlices(u8, it.next().?, "e");
try testing.expect(it.next() == null); try testing.expect(it.next() == null);
var it16 = split( var it16 = splitSequence(
u16, u16,
std.unicode.utf8ToUtf16LeStringLiteral("a, b ,, c, d, e"), std.unicode.utf8ToUtf16LeStringLiteral("a, b ,, c, d, e"),
std.unicode.utf8ToUtf16LeStringLiteral(", "), std.unicode.utf8ToUtf16LeStringLiteral(", "),
@ -2142,8 +2286,38 @@ test "split (multibyte)" {
try testing.expect(it16.next() == null); try testing.expect(it16.next() == null);
} }
test "splitAny" {
var it = splitAny(u8, "a,b, c d e", ", ");
try testing.expectEqualSlices(u8, it.first(), "a");
try testing.expectEqualSlices(u8, it.rest(), "b, c d e");
try testing.expectEqualSlices(u8, it.next().?, "b");
try testing.expectEqualSlices(u8, it.next().?, "");
try testing.expectEqualSlices(u8, it.next().?, "c");
try testing.expectEqualSlices(u8, it.next().?, "d");
try testing.expectEqualSlices(u8, it.next().?, "e");
try testing.expect(it.next() == null);
it = splitAny(u8, "hello", "");
try testing.expect(eql(u8, it.next().?, "hello"));
try testing.expect(it.next() == null);
var it16 = splitAny(
u16,
std.unicode.utf8ToUtf16LeStringLiteral("a,b, c d e"),
std.unicode.utf8ToUtf16LeStringLiteral(", "),
);
try testing.expectEqualSlices(u16, it16.first(), std.unicode.utf8ToUtf16LeStringLiteral("a"));
try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("b"));
try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral(""));
try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("c"));
try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("d"));
try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("e"));
try testing.expect(it16.next() == null);
}
test "split (reset)" { test "split (reset)" {
var it = split(u8, "abc def ghi", " "); {
var it = splitSequence(u8, "abc def ghi", " ");
try testing.expect(eql(u8, it.first(), "abc")); try testing.expect(eql(u8, it.first(), "abc"));
try testing.expect(eql(u8, it.next().?, "def")); try testing.expect(eql(u8, it.next().?, "def"));
try testing.expect(eql(u8, it.next().?, "ghi")); try testing.expect(eql(u8, it.next().?, "ghi"));
@ -2155,29 +2329,101 @@ test "split (reset)" {
try testing.expect(eql(u8, it.next().?, "ghi")); try testing.expect(eql(u8, it.next().?, "ghi"));
try testing.expect(it.next() == null); try testing.expect(it.next() == null);
} }
{
var it = splitAny(u8, "abc def,ghi", " ,");
try testing.expect(eql(u8, it.first(), "abc"));
try testing.expect(eql(u8, it.next().?, "def"));
try testing.expect(eql(u8, it.next().?, "ghi"));
/// Returns an iterator that iterates backwards over the slices of `buffer` it.reset();
/// that are separated by bytes in `delimiter`.
try testing.expect(eql(u8, it.first(), "abc"));
try testing.expect(eql(u8, it.next().?, "def"));
try testing.expect(eql(u8, it.next().?, "ghi"));
try testing.expect(it.next() == null);
}
{
var it = splitScalar(u8, "abc def ghi", ' ');
try testing.expect(eql(u8, it.first(), "abc"));
try testing.expect(eql(u8, it.next().?, "def"));
try testing.expect(eql(u8, it.next().?, "ghi"));
it.reset();
try testing.expect(eql(u8, it.first(), "abc"));
try testing.expect(eql(u8, it.next().?, "def"));
try testing.expect(eql(u8, it.next().?, "ghi"));
try testing.expect(it.next() == null);
}
}
/// Deprecated: use `splitBackwardsSequence`, `splitBackwardsAny`, or `splitBackwardsScalar`
pub const splitBackwards = splitBackwardsSequence;
/// Returns an iterator that iterates backwards over the slices of `buffer` that
/// are separated by the sequence in `delimiter`.
/// ///
/// `splitBackwards(u8, "abc|def||ghi", "|")` will return slices /// `splitBackwardsSequence(u8, "abc||def||||ghi", "||")` will return slices
/// for "ghi", "", "def", "abc", null, in that order. /// for "ghi", "", "def", "abc", null, in that order.
/// ///
/// If `delimiter` does not exist in buffer, /// If `delimiter` does not exist in buffer,
/// the iterator will return `buffer`, null, in that order. /// the iterator will return `buffer`, null, in that order.
/// The delimiter length must not be zero. /// The delimiter length must not be zero.
/// ///
/// See also: `tokenize` and `split`. /// See also: `splitBackwardsAny`, `splitBackwardsScalar`,
pub fn splitBackwards(comptime T: type, buffer: []const T, delimiter: []const T) SplitBackwardsIterator(T) { /// `splitSequence`, `splitAny`,`splitScalar`,
/// `tokenizeAny`, `tokenizeSequence`, and `tokenizeScalar`.
pub fn splitBackwardsSequence(comptime T: type, buffer: []const T, delimiter: []const T) SplitBackwardsIterator(T, .sequence) {
assert(delimiter.len != 0); assert(delimiter.len != 0);
return SplitBackwardsIterator(T){ return .{
.index = buffer.len, .index = buffer.len,
.buffer = buffer, .buffer = buffer,
.delimiter = delimiter, .delimiter = delimiter,
}; };
} }
test "splitBackwards" { /// Returns an iterator that iterates backwards over the slices of `buffer` that
var it = splitBackwards(u8, "abc|def||ghi", "|"); /// are separated by any item in `delimiters`.
///
/// `splitBackwardsAny(u8, "abc,def||ghi", "|,")` will return slices
/// for "ghi", "", "def", "abc", null, in that order.
///
/// If none of `delimiters` exist in buffer,
/// the iterator will return `buffer`, null, in that order.
///
/// See also: `splitBackwardsSequence`, `splitBackwardsScalar`,
/// `splitSequence`, `splitAny`,`splitScalar`,
/// `tokenizeAny`, `tokenizeSequence`, and `tokenizeScalar`.
pub fn splitBackwardsAny(comptime T: type, buffer: []const T, delimiters: []const T) SplitBackwardsIterator(T, .any) {
return .{
.index = buffer.len,
.buffer = buffer,
.delimiter = delimiters,
};
}
/// Returns an iterator that iterates backwards over the slices of `buffer` that
/// are separated by `delimiter`.
///
/// `splitBackwardsScalar(u8, "abc|def||ghi", '|')` will return slices
/// for "ghi", "", "def", "abc", null, in that order.
///
/// If `delimiter` does not exist in buffer,
/// the iterator will return `buffer`, null, in that order.
///
/// See also: `splitBackwardsSequence`, `splitBackwardsAny`,
/// `splitSequence`, `splitAny`,`splitScalar`,
/// `tokenizeAny`, `tokenizeSequence`, and `tokenizeScalar`.
pub fn splitBackwardsScalar(comptime T: type, buffer: []const T, delimiter: T) SplitBackwardsIterator(T, .scalar) {
return .{
.index = buffer.len,
.buffer = buffer,
.delimiter = delimiter,
};
}
test "splitBackwardsScalar" {
var it = splitBackwardsScalar(u8, "abc|def||ghi", '|');
try testing.expectEqualSlices(u8, it.rest(), "abc|def||ghi"); try testing.expectEqualSlices(u8, it.rest(), "abc|def||ghi");
try testing.expectEqualSlices(u8, it.first(), "ghi"); try testing.expectEqualSlices(u8, it.first(), "ghi");
@ -2193,30 +2439,30 @@ test "splitBackwards" {
try testing.expectEqualSlices(u8, it.rest(), ""); try testing.expectEqualSlices(u8, it.rest(), "");
try testing.expect(it.next() == null); try testing.expect(it.next() == null);
it = splitBackwards(u8, "", "|"); it = splitBackwardsScalar(u8, "", '|');
try testing.expectEqualSlices(u8, it.first(), ""); try testing.expectEqualSlices(u8, it.first(), "");
try testing.expect(it.next() == null); try testing.expect(it.next() == null);
it = splitBackwards(u8, "|", "|"); it = splitBackwardsScalar(u8, "|", '|');
try testing.expectEqualSlices(u8, it.first(), ""); try testing.expectEqualSlices(u8, it.first(), "");
try testing.expectEqualSlices(u8, it.next().?, ""); try testing.expectEqualSlices(u8, it.next().?, "");
try testing.expect(it.next() == null); try testing.expect(it.next() == null);
it = splitBackwards(u8, "hello", " "); it = splitBackwardsScalar(u8, "hello", ' ');
try testing.expectEqualSlices(u8, it.first(), "hello"); try testing.expectEqualSlices(u8, it.first(), "hello");
try testing.expect(it.next() == null); try testing.expect(it.next() == null);
var it16 = splitBackwards( var it16 = splitBackwardsScalar(
u16, u16,
std.unicode.utf8ToUtf16LeStringLiteral("hello"), std.unicode.utf8ToUtf16LeStringLiteral("hello"),
std.unicode.utf8ToUtf16LeStringLiteral(" "), ' ',
); );
try testing.expectEqualSlices(u16, it16.first(), std.unicode.utf8ToUtf16LeStringLiteral("hello")); try testing.expectEqualSlices(u16, it16.first(), std.unicode.utf8ToUtf16LeStringLiteral("hello"));
try testing.expect(it16.next() == null); try testing.expect(it16.next() == null);
} }
test "splitBackwards (multibyte)" { test "splitBackwardsSequence" {
var it = splitBackwards(u8, "a, b ,, c, d, e", ", "); var it = splitBackwardsSequence(u8, "a, b ,, c, d, e", ", ");
try testing.expectEqualSlices(u8, it.rest(), "a, b ,, c, d, e"); try testing.expectEqualSlices(u8, it.rest(), "a, b ,, c, d, e");
try testing.expectEqualSlices(u8, it.first(), "e"); try testing.expectEqualSlices(u8, it.first(), "e");
@ -2235,7 +2481,7 @@ test "splitBackwards (multibyte)" {
try testing.expectEqualSlices(u8, it.rest(), ""); try testing.expectEqualSlices(u8, it.rest(), "");
try testing.expect(it.next() == null); try testing.expect(it.next() == null);
var it16 = splitBackwards( var it16 = splitBackwardsSequence(
u16, u16,
std.unicode.utf8ToUtf16LeStringLiteral("a, b ,, c, d, e"), std.unicode.utf8ToUtf16LeStringLiteral("a, b ,, c, d, e"),
std.unicode.utf8ToUtf16LeStringLiteral(", "), std.unicode.utf8ToUtf16LeStringLiteral(", "),
@ -2248,8 +2494,46 @@ test "splitBackwards (multibyte)" {
try testing.expect(it16.next() == null); try testing.expect(it16.next() == null);
} }
test "splitBackwardsAny" {
var it = splitBackwardsAny(u8, "a,b, c d e", ", ");
try testing.expectEqualSlices(u8, it.rest(), "a,b, c d e");
try testing.expectEqualSlices(u8, it.first(), "e");
try testing.expectEqualSlices(u8, it.rest(), "a,b, c d");
try testing.expectEqualSlices(u8, it.next().?, "d");
try testing.expectEqualSlices(u8, it.rest(), "a,b, c");
try testing.expectEqualSlices(u8, it.next().?, "c");
try testing.expectEqualSlices(u8, it.rest(), "a,b,");
try testing.expectEqualSlices(u8, it.next().?, "");
try testing.expectEqualSlices(u8, it.rest(), "a,b");
try testing.expectEqualSlices(u8, it.next().?, "b");
try testing.expectEqualSlices(u8, it.rest(), "a");
try testing.expectEqualSlices(u8, it.next().?, "a");
try testing.expectEqualSlices(u8, it.rest(), "");
try testing.expect(it.next() == null);
var it16 = splitBackwardsAny(
u16,
std.unicode.utf8ToUtf16LeStringLiteral("a,b, c d e"),
std.unicode.utf8ToUtf16LeStringLiteral(", "),
);
try testing.expectEqualSlices(u16, it16.first(), std.unicode.utf8ToUtf16LeStringLiteral("e"));
try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("d"));
try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("c"));
try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral(""));
try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("b"));
try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("a"));
try testing.expect(it16.next() == null);
}
test "splitBackwards (reset)" { test "splitBackwards (reset)" {
var it = splitBackwards(u8, "abc def ghi", " "); {
var it = splitBackwardsSequence(u8, "abc def ghi", " ");
try testing.expect(eql(u8, it.first(), "ghi")); try testing.expect(eql(u8, it.first(), "ghi"));
try testing.expect(eql(u8, it.next().?, "def")); try testing.expect(eql(u8, it.next().?, "def"));
try testing.expect(eql(u8, it.next().?, "abc")); try testing.expect(eql(u8, it.next().?, "abc"));
@ -2261,6 +2545,33 @@ test "splitBackwards (reset)" {
try testing.expect(eql(u8, it.next().?, "abc")); try testing.expect(eql(u8, it.next().?, "abc"));
try testing.expect(it.next() == null); try testing.expect(it.next() == null);
} }
{
var it = splitBackwardsAny(u8, "abc def,ghi", " ,");
try testing.expect(eql(u8, it.first(), "ghi"));
try testing.expect(eql(u8, it.next().?, "def"));
try testing.expect(eql(u8, it.next().?, "abc"));
it.reset();
try testing.expect(eql(u8, it.first(), "ghi"));
try testing.expect(eql(u8, it.next().?, "def"));
try testing.expect(eql(u8, it.next().?, "abc"));
try testing.expect(it.next() == null);
}
{
var it = splitBackwardsScalar(u8, "abc def ghi", ' ');
try testing.expect(eql(u8, it.first(), "ghi"));
try testing.expect(eql(u8, it.next().?, "def"));
try testing.expect(eql(u8, it.next().?, "abc"));
it.reset();
try testing.expect(eql(u8, it.first(), "ghi"));
try testing.expect(eql(u8, it.next().?, "def"));
try testing.expect(eql(u8, it.next().?, "abc"));
try testing.expect(it.next() == null);
}
}
/// Returns an iterator with a sliding window of slices for `buffer`. /// Returns an iterator with a sliding window of slices for `buffer`.
/// The sliding window has length `size` and on every iteration moves /// The sliding window has length `size` and on every iteration moves
@ -2430,10 +2741,15 @@ test "endsWith" {
try testing.expect(!endsWith(u8, "Bob", "Bo")); try testing.expect(!endsWith(u8, "Bob", "Bo"));
} }
pub fn TokenIterator(comptime T: type) type { pub const DelimiterType = enum { sequence, any, scalar };
pub fn TokenIterator(comptime T: type, comptime delimiter_type: DelimiterType) type {
return struct { return struct {
buffer: []const T, buffer: []const T,
delimiter_bytes: []const T, delimiter: switch (delimiter_type) {
.sequence, .any => []const T,
.scalar => T,
},
index: usize, index: usize,
const Self = @This(); const Self = @This();
@ -2450,7 +2766,10 @@ pub fn TokenIterator(comptime T: type) type {
/// complete. Does not advance to the next token. /// complete. Does not advance to the next token.
pub fn peek(self: *Self) ?[]const T { pub fn peek(self: *Self) ?[]const T {
// move to beginning of token // move to beginning of token
while (self.index < self.buffer.len and self.isSplitByte(self.buffer[self.index])) : (self.index += 1) {} while (self.index < self.buffer.len and self.isDelimiter(self.index)) : (self.index += switch (delimiter_type) {
.sequence => self.delimiter.len,
.any, .scalar => 1,
}) {}
const start = self.index; const start = self.index;
if (start == self.buffer.len) { if (start == self.buffer.len) {
return null; return null;
@ -2458,7 +2777,7 @@ pub fn TokenIterator(comptime T: type) type {
// move to end of token // move to end of token
var end = start; var end = start;
while (end < self.buffer.len and !self.isSplitByte(self.buffer[end])) : (end += 1) {} while (end < self.buffer.len and !self.isDelimiter(end)) : (end += 1) {}
return self.buffer[start..end]; return self.buffer[start..end];
} }
@ -2467,7 +2786,10 @@ pub fn TokenIterator(comptime T: type) type {
pub fn rest(self: Self) []const T { pub fn rest(self: Self) []const T {
// move to beginning of token // move to beginning of token
var index: usize = self.index; var index: usize = self.index;
while (index < self.buffer.len and self.isSplitByte(self.buffer[index])) : (index += 1) {} while (index < self.buffer.len and self.isDelimiter(index)) : (index += switch (delimiter_type) {
.sequence => self.delimiter.len,
.any, .scalar => 1,
}) {}
return self.buffer[index..]; return self.buffer[index..];
} }
@ -2476,22 +2798,32 @@ pub fn TokenIterator(comptime T: type) type {
self.index = 0; self.index = 0;
} }
fn isSplitByte(self: Self, byte: T) bool { fn isDelimiter(self: Self, index: usize) bool {
for (self.delimiter_bytes) |delimiter_byte| { switch (delimiter_type) {
if (byte == delimiter_byte) { .sequence => return startsWith(T, self.buffer[index..], self.delimiter),
.any => {
const item = self.buffer[index];
for (self.delimiter) |delimiter_item| {
if (item == delimiter_item) {
return true; return true;
} }
} }
return false; return false;
},
.scalar => return self.buffer[index] == self.delimiter,
}
} }
}; };
} }
pub fn SplitIterator(comptime T: type) type { pub fn SplitIterator(comptime T: type, comptime delimiter_type: DelimiterType) type {
return struct { return struct {
buffer: []const T, buffer: []const T,
index: ?usize, index: ?usize,
delimiter: []const T, delimiter: switch (delimiter_type) {
.sequence, .any => []const T,
.scalar => T,
},
const Self = @This(); const Self = @This();
@ -2505,8 +2837,15 @@ pub fn SplitIterator(comptime T: type) type {
/// Returns a slice of the next field, or null if splitting is complete. /// Returns a slice of the next field, or null if splitting is complete.
pub fn next(self: *Self) ?[]const T { pub fn next(self: *Self) ?[]const T {
const start = self.index orelse return null; const start = self.index orelse return null;
const end = if (indexOfPos(T, self.buffer, start, self.delimiter)) |delim_start| blk: { const end = if (switch (delimiter_type) {
self.index = delim_start + self.delimiter.len; .sequence => indexOfPos(T, self.buffer, start, self.delimiter),
.any => indexOfAnyPos(T, self.buffer, start, self.delimiter),
.scalar => indexOfScalarPos(T, self.buffer, start, self.delimiter),
}) |delim_start| blk: {
self.index = delim_start + switch (delimiter_type) {
.sequence => self.delimiter.len,
.any, .scalar => 1,
};
break :blk delim_start; break :blk delim_start;
} else blk: { } else blk: {
self.index = null; self.index = null;
@ -2529,11 +2868,14 @@ pub fn SplitIterator(comptime T: type) type {
}; };
} }
pub fn SplitBackwardsIterator(comptime T: type) type { pub fn SplitBackwardsIterator(comptime T: type, comptime delimiter_type: DelimiterType) type {
return struct { return struct {
buffer: []const T, buffer: []const T,
index: ?usize, index: ?usize,
delimiter: []const T, delimiter: switch (delimiter_type) {
.sequence, .any => []const T,
.scalar => T,
},
const Self = @This(); const Self = @This();
@ -2547,9 +2889,16 @@ pub fn SplitBackwardsIterator(comptime T: type) type {
/// Returns a slice of the next field, or null if splitting is complete. /// Returns a slice of the next field, or null if splitting is complete.
pub fn next(self: *Self) ?[]const T { pub fn next(self: *Self) ?[]const T {
const end = self.index orelse return null; const end = self.index orelse return null;
const start = if (lastIndexOf(T, self.buffer[0..end], self.delimiter)) |delim_start| blk: { 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),
}) |delim_start| blk: {
self.index = delim_start; self.index = delim_start;
break :blk delim_start + self.delimiter.len; break :blk delim_start + switch (delimiter_type) {
.sequence => self.delimiter.len,
.any, .scalar => 1,
};
} else blk: { } else blk: {
self.index = null; self.index = null;
break :blk 0; break :blk 0;

View File

@ -1263,10 +1263,10 @@ fn linuxLookupNameFromHosts(
}, },
else => |e| return e, else => |e| return e,
}) |line| { }) |line| {
var split_it = mem.split(u8, line, "#"); var split_it = mem.splitScalar(u8, line, '#');
const no_comment_line = split_it.first(); const no_comment_line = split_it.first();
var line_it = mem.tokenize(u8, no_comment_line, " \t"); var line_it = mem.tokenizeAny(u8, no_comment_line, " \t");
const ip_text = line_it.next() orelse continue; const ip_text = line_it.next() orelse continue;
var first_name_text: ?[]const u8 = null; var first_name_text: ?[]const u8 = null;
while (line_it.next()) |name_text| { while (line_it.next()) |name_text| {
@ -1346,7 +1346,7 @@ fn linuxLookupNameFromDnsSearch(
@memcpy(canon.items, canon_name); @memcpy(canon.items, canon_name);
try canon.append('.'); try canon.append('.');
var tok_it = mem.tokenize(u8, search, " \t"); var tok_it = mem.tokenizeAny(u8, search, " \t");
while (tok_it.next()) |tok| { while (tok_it.next()) |tok| {
canon.shrinkRetainingCapacity(canon_name.len + 1); canon.shrinkRetainingCapacity(canon_name.len + 1);
try canon.appendSlice(tok); try canon.appendSlice(tok);
@ -1465,15 +1465,15 @@ fn getResolvConf(allocator: mem.Allocator, rc: *ResolvConf) !void {
else => |e| return e, else => |e| return e,
}) |line| { }) |line| {
const no_comment_line = no_comment_line: { const no_comment_line = no_comment_line: {
var split = mem.split(u8, line, "#"); var split = mem.splitScalar(u8, line, '#');
break :no_comment_line split.first(); break :no_comment_line split.first();
}; };
var line_it = mem.tokenize(u8, no_comment_line, " \t"); var line_it = mem.tokenizeAny(u8, no_comment_line, " \t");
const token = line_it.next() orelse continue; const token = line_it.next() orelse continue;
if (mem.eql(u8, token, "options")) { if (mem.eql(u8, token, "options")) {
while (line_it.next()) |sub_tok| { while (line_it.next()) |sub_tok| {
var colon_it = mem.split(u8, sub_tok, ":"); var colon_it = mem.splitScalar(u8, sub_tok, ':');
const name = colon_it.first(); const name = colon_it.first();
const value_txt = colon_it.next() orelse continue; const value_txt = colon_it.next() orelse continue;
const value = std.fmt.parseInt(u8, value_txt, 10) catch |err| switch (err) { const value = std.fmt.parseInt(u8, value_txt, 10) catch |err| switch (err) {

View File

@ -1878,7 +1878,7 @@ pub fn execvpeZ_expandArg0(
// Use of MAX_PATH_BYTES here is valid as the path_buf will be passed // Use of MAX_PATH_BYTES here is valid as the path_buf will be passed
// directly to the operating system in execveZ. // directly to the operating system in execveZ.
var path_buf: [MAX_PATH_BYTES]u8 = undefined; var path_buf: [MAX_PATH_BYTES]u8 = undefined;
var it = mem.tokenize(u8, PATH, ":"); var it = mem.tokenizeScalar(u8, PATH, ':');
var seen_eacces = false; var seen_eacces = false;
var err: ExecveError = error.FileNotFound; var err: ExecveError = error.FileNotFound;

View File

@ -310,7 +310,7 @@ pub fn getEnvMap(allocator: Allocator) !EnvMap {
for (environ) |env| { for (environ) |env| {
const pair = mem.sliceTo(env, 0); const pair = mem.sliceTo(env, 0);
var parts = mem.split(u8, pair, "="); var parts = mem.splitScalar(u8, pair, '=');
const key = parts.first(); const key = parts.first();
const value = parts.rest(); const value = parts.rest();
try result.put(key, value); try result.put(key, value);
@ -1200,7 +1200,7 @@ fn totalSystemMemoryLinux() !usize {
var buf: [50]u8 = undefined; var buf: [50]u8 = undefined;
const amt = try file.read(&buf); const amt = try file.read(&buf);
if (amt != 50) return error.Unexpected; if (amt != 50) return error.Unexpected;
var it = std.mem.tokenize(u8, buf[0..amt], " \n"); var it = std.mem.tokenizeAny(u8, buf[0..amt], " \n");
const label = it.next().?; const label = it.next().?;
if (!std.mem.eql(u8, label, "MemTotal:")) return error.Unexpected; if (!std.mem.eql(u8, label, "MemTotal:")) return error.Unexpected;
const int_text = it.next() orelse return error.Unexpected; const int_text = it.next() orelse return error.Unexpected;

View File

@ -239,7 +239,7 @@ pub fn parse(args: ParseOptions) !CrossTarget {
.dynamic_linker = DynamicLinker.init(args.dynamic_linker), .dynamic_linker = DynamicLinker.init(args.dynamic_linker),
}; };
var it = mem.split(u8, args.arch_os_abi, "-"); var it = mem.splitScalar(u8, args.arch_os_abi, '-');
const arch_name = it.first(); const arch_name = it.first();
const arch_is_native = mem.eql(u8, arch_name, "native"); const arch_is_native = mem.eql(u8, arch_name, "native");
if (!arch_is_native) { if (!arch_is_native) {
@ -257,7 +257,7 @@ pub fn parse(args: ParseOptions) !CrossTarget {
const opt_abi_text = it.next(); const opt_abi_text = it.next();
if (opt_abi_text) |abi_text| { if (opt_abi_text) |abi_text| {
var abi_it = mem.split(u8, abi_text, "."); var abi_it = mem.splitScalar(u8, abi_text, '.');
const abi = std.meta.stringToEnum(Target.Abi, abi_it.first()) orelse const abi = std.meta.stringToEnum(Target.Abi, abi_it.first()) orelse
return error.UnknownApplicationBinaryInterface; return error.UnknownApplicationBinaryInterface;
result.abi = abi; result.abi = abi;
@ -343,7 +343,7 @@ pub fn parse(args: ParseOptions) !CrossTarget {
/// This is intended to be used if the API user of CrossTarget needs to learn the /// This is intended to be used if the API user of CrossTarget needs to learn the
/// target CPU architecture in order to fully populate `ParseOptions`. /// target CPU architecture in order to fully populate `ParseOptions`.
pub fn parseCpuArch(args: ParseOptions) ?Target.Cpu.Arch { pub fn parseCpuArch(args: ParseOptions) ?Target.Cpu.Arch {
var it = mem.split(u8, args.arch_os_abi, "-"); var it = mem.splitScalar(u8, args.arch_os_abi, '-');
const arch_name = it.first(); const arch_name = it.first();
const arch_is_native = mem.eql(u8, arch_name, "native"); const arch_is_native = mem.eql(u8, arch_name, "native");
if (arch_is_native) { if (arch_is_native) {
@ -645,7 +645,7 @@ pub fn updateCpuFeatures(self: CrossTarget, set: *Target.Cpu.Feature.Set) void {
} }
fn parseOs(result: *CrossTarget, diags: *ParseOptions.Diagnostics, text: []const u8) !void { fn parseOs(result: *CrossTarget, diags: *ParseOptions.Diagnostics, text: []const u8) !void {
var it = mem.split(u8, text, "."); var it = mem.splitScalar(u8, text, '.');
const os_name = it.first(); const os_name = it.first();
diags.os_name = os_name; diags.os_name = os_name;
const os_is_native = mem.eql(u8, os_name, "native"); const os_is_native = mem.eql(u8, os_name, "native");
@ -706,7 +706,7 @@ fn parseOs(result: *CrossTarget, diags: *ParseOptions.Diagnostics, text: []const
.linux, .linux,
.dragonfly, .dragonfly,
=> { => {
var range_it = mem.split(u8, version_text, "..."); var range_it = mem.splitSequence(u8, version_text, "...");
const min_text = range_it.next().?; const min_text = range_it.next().?;
const min_ver = SemVer.parse(min_text) catch |err| switch (err) { const min_ver = SemVer.parse(min_text) catch |err| switch (err) {
@ -726,7 +726,7 @@ fn parseOs(result: *CrossTarget, diags: *ParseOptions.Diagnostics, text: []const
}, },
.windows => { .windows => {
var range_it = mem.split(u8, version_text, "..."); var range_it = mem.splitSequence(u8, version_text, "...");
const min_text = range_it.first(); const min_text = range_it.first();
const min_ver = std.meta.stringToEnum(Target.Os.WindowsVersion, min_text) orelse const min_ver = std.meta.stringToEnum(Target.Os.WindowsVersion, min_text) orelse

View File

@ -294,7 +294,7 @@ fn renderErrorMessageToWriter(
/// ///
/// This is used to split the message in `@compileError("hello\nworld")` for example. /// This is used to split the message in `@compileError("hello\nworld")` for example.
fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, stderr: anytype, indent: usize) !void { fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, stderr: anytype, indent: usize) !void {
var lines = std.mem.split(u8, eb.nullTerminatedString(err_msg.msg), "\n"); var lines = std.mem.splitScalar(u8, eb.nullTerminatedString(err_msg.msg), '\n');
while (lines.next()) |line| { while (lines.next()) |line| {
try stderr.writeAll(line); try stderr.writeAll(line);
if (lines.index == null) break; if (lines.index == null) break;

View File

@ -1995,7 +1995,7 @@ fn renderArrayInit(
if (!expr_newlines[i]) { if (!expr_newlines[i]) {
try ais.writer().writeAll(expr_text); try ais.writer().writeAll(expr_text);
} else { } else {
var by_line = std.mem.split(u8, expr_text, "\n"); var by_line = std.mem.splitScalar(u8, expr_text, '\n');
var last_line_was_empty = false; var last_line_was_empty = false;
try ais.writer().writeAll(by_line.first()); try ais.writer().writeAll(by_line.first());
while (by_line.next()) |line| { while (by_line.next()) |line| {

View File

@ -31,7 +31,7 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths
defer allocator.free(nix_cflags_compile); defer allocator.free(nix_cflags_compile);
is_nix = true; is_nix = true;
var it = mem.tokenize(u8, nix_cflags_compile, " "); var it = mem.tokenizeScalar(u8, nix_cflags_compile, ' ');
while (true) { while (true) {
const word = it.next() orelse break; const word = it.next() orelse break;
if (mem.eql(u8, word, "-isystem")) { if (mem.eql(u8, word, "-isystem")) {
@ -62,7 +62,7 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths
defer allocator.free(nix_ldflags); defer allocator.free(nix_ldflags);
is_nix = true; is_nix = true;
var it = mem.tokenize(u8, nix_ldflags, " "); var it = mem.tokenizeScalar(u8, nix_ldflags, ' ');
while (true) { while (true) {
const word = it.next() orelse break; const word = it.next() orelse break;
if (mem.eql(u8, word, "-rpath")) { if (mem.eql(u8, word, "-rpath")) {
@ -147,21 +147,21 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths
// We use os.getenv here since this part won't be executed on // We use os.getenv here since this part won't be executed on
// windows, to get rid of unnecessary error handling. // windows, to get rid of unnecessary error handling.
if (std.os.getenv("C_INCLUDE_PATH")) |c_include_path| { if (std.os.getenv("C_INCLUDE_PATH")) |c_include_path| {
var it = mem.tokenize(u8, c_include_path, ":"); var it = mem.tokenizeScalar(u8, c_include_path, ':');
while (it.next()) |dir| { while (it.next()) |dir| {
try self.addIncludeDir(dir); try self.addIncludeDir(dir);
} }
} }
if (std.os.getenv("CPLUS_INCLUDE_PATH")) |cplus_include_path| { if (std.os.getenv("CPLUS_INCLUDE_PATH")) |cplus_include_path| {
var it = mem.tokenize(u8, cplus_include_path, ":"); var it = mem.tokenizeScalar(u8, cplus_include_path, ':');
while (it.next()) |dir| { while (it.next()) |dir| {
try self.addIncludeDir(dir); try self.addIncludeDir(dir);
} }
} }
if (std.os.getenv("LIBRARY_PATH")) |library_path| { if (std.os.getenv("LIBRARY_PATH")) |library_path| {
var it = mem.tokenize(u8, library_path, ":"); var it = mem.tokenizeScalar(u8, library_path, ':');
while (it.next()) |dir| { while (it.next()) |dir| {
try self.addLibDir(dir); try self.addLibDir(dir);
} }

View File

@ -354,7 +354,7 @@ fn detectAbiAndDynamicLinker(
const newline = mem.indexOfScalar(u8, buffer[0..len], '\n') orelse break :blk file; const newline = mem.indexOfScalar(u8, buffer[0..len], '\n') orelse break :blk file;
const line = buffer[0..newline]; const line = buffer[0..newline];
if (!mem.startsWith(u8, line, "#!")) break :blk file; if (!mem.startsWith(u8, line, "#!")) break :blk file;
var it = mem.tokenize(u8, line[2..], " "); var it = mem.tokenizeScalar(u8, line[2..], ' ');
file_name = it.next() orelse return defaultAbiAndDynamicLinker(cpu, os, cross_target); file_name = it.next() orelse return defaultAbiAndDynamicLinker(cpu, os, cross_target);
file.close(); file.close();
} }
@ -556,7 +556,7 @@ fn glibcVerFromSoFile(file: fs.File) !std.builtin.Version {
const dynstr_size = @intCast(usize, dynstr.size); const dynstr_size = @intCast(usize, dynstr.size);
const dynstr_bytes = buf[0..dynstr_size]; const dynstr_bytes = buf[0..dynstr_size];
_ = try preadMin(file, dynstr_bytes, dynstr.offset, dynstr_bytes.len); _ = try preadMin(file, dynstr_bytes, dynstr.offset, dynstr_bytes.len);
var it = mem.split(u8, dynstr_bytes, &.{0}); var it = mem.splitScalar(u8, dynstr_bytes, 0);
var max_ver: std.builtin.Version = .{ .major = 2, .minor = 2, .patch = 5 }; var max_ver: std.builtin.Version = .{ .major = 2, .minor = 2, .patch = 5 };
while (it.next()) |s| { while (it.next()) |s| {
if (mem.startsWith(u8, s, "GLIBC_2.")) { if (mem.startsWith(u8, s, "GLIBC_2.")) {
@ -811,7 +811,7 @@ pub fn abiAndDynamicLinkerFromFile(
const strtab = strtab_buf[0..strtab_read_len]; const strtab = strtab_buf[0..strtab_read_len];
const rpath_list = mem.sliceTo(strtab, 0); const rpath_list = mem.sliceTo(strtab, 0);
var it = mem.tokenize(u8, rpath_list, ":"); var it = mem.tokenizeScalar(u8, rpath_list, ':');
while (it.next()) |rpath| { while (it.next()) |rpath| {
if (glibcVerFromRPath(rpath)) |ver| { if (glibcVerFromRPath(rpath)) |ver| {
result.target.os.version_range.linux.glibc = ver; result.target.os.version_range.linux.glibc = ver;

View File

@ -4950,7 +4950,7 @@ fn findGuidePaths(self: *Autodoc, file: *File, str: []const u8) ![]const u8 {
// TODO: this algo is kinda inefficient // TODO: this algo is kinda inefficient
var it = std.mem.split(u8, str, "\n"); var it = std.mem.splitScalar(u8, str, '\n');
while (it.next()) |line| { while (it.next()) |line| {
const trimmed_line = std.mem.trim(u8, line, " "); const trimmed_line = std.mem.trim(u8, line, " ");
if (std.mem.startsWith(u8, trimmed_line, guide_prefix)) { if (std.mem.startsWith(u8, trimmed_line, guide_prefix)) {

View File

@ -4671,7 +4671,7 @@ pub fn hasSharedLibraryExt(filename: []const u8) bool {
return true; return true;
} }
// Look for .so.X, .so.X.Y, .so.X.Y.Z // Look for .so.X, .so.X.Y, .so.X.Y.Z
var it = mem.split(u8, filename, "."); var it = mem.splitScalar(u8, filename, '.');
_ = it.first(); _ = it.first();
var so_txt = it.next() orelse return false; var so_txt = it.next() orelse return false;
while (!mem.eql(u8, so_txt, "so")) { while (!mem.eql(u8, so_txt, "so")) {
@ -5051,14 +5051,14 @@ fn parseLldStderr(comp: *Compilation, comptime prefix: []const u8, stderr: []con
defer context_lines.deinit(); defer context_lines.deinit();
var current_err: ?*LldError = null; var current_err: ?*LldError = null;
var lines = mem.split(u8, stderr, std.cstr.line_sep); var lines = mem.splitSequence(u8, stderr, std.cstr.line_sep);
while (lines.next()) |line| { while (lines.next()) |line| {
if (mem.startsWith(u8, line, prefix ++ ":")) { if (mem.startsWith(u8, line, prefix ++ ":")) {
if (current_err) |err| { if (current_err) |err| {
err.context_lines = try context_lines.toOwnedSlice(); err.context_lines = try context_lines.toOwnedSlice();
} }
var split = std.mem.split(u8, line, "error: "); var split = std.mem.splitSequence(u8, line, "error: ");
_ = split.first(); _ = split.first();
const duped_msg = try std.fmt.allocPrint(comp.gpa, "{s}: {s}", .{ prefix, split.rest() }); const duped_msg = try std.fmt.allocPrint(comp.gpa, "{s}: {s}", .{ prefix, split.rest() });

View File

@ -9232,9 +9232,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
} }
const asm_source = mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len]; const asm_source = mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len];
var line_it = mem.tokenize(u8, asm_source, "\n\r;"); var line_it = mem.tokenizeAny(u8, asm_source, "\n\r;");
while (line_it.next()) |line| { while (line_it.next()) |line| {
var mnem_it = mem.tokenize(u8, line, " \t"); var mnem_it = mem.tokenizeAny(u8, line, " \t");
const mnem_str = mnem_it.next() orelse continue; const mnem_str = mnem_it.next() orelse continue;
if (mem.startsWith(u8, mnem_str, "#")) continue; if (mem.startsWith(u8, mnem_str, "#")) continue;
@ -9258,7 +9258,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
return self.fail("Invalid mnemonic: '{s}'", .{mnem_str}); return self.fail("Invalid mnemonic: '{s}'", .{mnem_str});
} }; } };
var op_it = mem.tokenize(u8, mnem_it.rest(), ","); var op_it = mem.tokenizeScalar(u8, mnem_it.rest(), ',');
var ops = [1]encoder.Instruction.Operand{.none} ** 4; var ops = [1]encoder.Instruction.Operand{.none} ** 4;
for (&ops) |*op| { for (&ops) |*op| {
const op_str = mem.trim(u8, op_it.next() orelse break, " \t"); const op_str = mem.trim(u8, op_it.next() orelse break, " \t");

View File

@ -109,7 +109,7 @@ pub fn loadMetaData(gpa: Allocator, contents: []const u8) LoadMetaDataError!*ABI
const target_name = mem.sliceTo(contents[index..], 0); const target_name = mem.sliceTo(contents[index..], 0);
index += target_name.len + 1; index += target_name.len + 1;
var component_it = mem.tokenize(u8, target_name, "-"); var component_it = mem.tokenizeScalar(u8, target_name, '-');
const arch_name = component_it.next() orelse { const arch_name = component_it.next() orelse {
log.err("abilists: expected arch name", .{}); log.err("abilists: expected arch name", .{});
return error.ZigInstallationCorrupt; return error.ZigInstallationCorrupt;

View File

@ -60,10 +60,10 @@ pub const LibCInstallation = struct {
const contents = try std.fs.cwd().readFileAlloc(allocator, libc_file, std.math.maxInt(usize)); const contents = try std.fs.cwd().readFileAlloc(allocator, libc_file, std.math.maxInt(usize));
defer allocator.free(contents); defer allocator.free(contents);
var it = std.mem.tokenize(u8, contents, "\n"); var it = std.mem.tokenizeScalar(u8, contents, '\n');
while (it.next()) |line| { while (it.next()) |line| {
if (line.len == 0 or line[0] == '#') continue; if (line.len == 0 or line[0] == '#') continue;
var line_it = std.mem.split(u8, line, "="); var line_it = std.mem.splitScalar(u8, line, '=');
const name = line_it.first(); const name = line_it.first();
const value = line_it.rest(); const value = line_it.rest();
inline for (fields, 0..) |field, i| { inline for (fields, 0..) |field, i| {
@ -293,7 +293,7 @@ pub const LibCInstallation = struct {
}, },
} }
var it = std.mem.tokenize(u8, exec_res.stderr, "\n\r"); var it = std.mem.tokenizeAny(u8, exec_res.stderr, "\n\r");
var search_paths = std.ArrayList([]const u8).init(allocator); var search_paths = std.ArrayList([]const u8).init(allocator);
defer search_paths.deinit(); defer search_paths.deinit();
while (it.next()) |line| { while (it.next()) |line| {
@ -613,7 +613,7 @@ fn ccPrintFileName(args: CCPrintFileNameOptions) ![:0]u8 {
}, },
} }
var it = std.mem.tokenize(u8, exec_res.stdout, "\n\r"); var it = std.mem.tokenizeAny(u8, exec_res.stdout, "\n\r");
const line = it.next() orelse return error.LibCRuntimeNotFound; const line = it.next() orelse return error.LibCRuntimeNotFound;
// When this command fails, it returns exit code 0 and duplicates the input file name. // When this command fails, it returns exit code 0 and duplicates the input file name.
// So we detect failure by checking if the output matches exactly the input. // So we detect failure by checking if the output matches exactly the input.
@ -692,7 +692,7 @@ fn appendCcExe(args: *std.ArrayList([]const u8), skip_cc_env_var: bool) !void {
return; return;
}; };
// Respect space-separated flags to the C compiler. // Respect space-separated flags to the C compiler.
var it = std.mem.tokenize(u8, cc_env_var, " "); var it = std.mem.tokenizeScalar(u8, cc_env_var, ' ');
while (it.next()) |arg| { while (it.next()) |arg| {
try args.append(arg); try args.append(arg);
} }

View File

@ -91,7 +91,7 @@ pub const Id = struct {
var out: u32 = 0; var out: u32 = 0;
var values: [3][]const u8 = undefined; var values: [3][]const u8 = undefined;
var split = mem.split(u8, string, "."); var split = mem.splitScalar(u8, string, '.');
var count: u4 = 0; var count: u4 = 0;
while (split.next()) |value| { while (split.next()) |value| {
if (count > 2) { if (count > 2) {

View File

@ -264,7 +264,7 @@ fn putFn(self: *Plan9, decl_index: Module.Decl.Index, out: FnDeclOutput) !void {
fn addPathComponents(self: *Plan9, path: []const u8, a: *std.ArrayList(u8)) !void { fn addPathComponents(self: *Plan9, path: []const u8, a: *std.ArrayList(u8)) !void {
const sep = std.fs.path.sep; const sep = std.fs.path.sep;
var it = std.mem.tokenize(u8, path, &.{sep}); var it = std.mem.tokenizeScalar(u8, path, sep);
while (it.next()) |component| { while (it.next()) |component| {
if (self.file_segments.get(component)) |num| { if (self.file_segments.get(component)) |num| {
try a.writer().writeIntBig(u16, num); try a.writer().writeIntBig(u16, num);

View File

@ -973,7 +973,7 @@ fn buildOutputType(
} }
} else if (mem.eql(u8, arg, "--mod")) { } else if (mem.eql(u8, arg, "--mod")) {
const info = args_iter.nextOrFatal(); const info = args_iter.nextOrFatal();
var info_it = mem.split(u8, info, ":"); var info_it = mem.splitScalar(u8, info, ':');
const mod_name = info_it.next() orelse fatal("expected non-empty argument after {s}", .{arg}); const mod_name = info_it.next() orelse fatal("expected non-empty argument after {s}", .{arg});
const deps_str = info_it.next() orelse fatal("expected 'name:deps:path' after {s}", .{arg}); const deps_str = info_it.next() orelse fatal("expected 'name:deps:path' after {s}", .{arg});
const root_src_orig = info_it.rest(); const root_src_orig = info_it.rest();
@ -1173,7 +1173,7 @@ fn buildOutputType(
} else { } else {
if (build_options.only_core_functionality) unreachable; if (build_options.only_core_functionality) unreachable;
// example: --listen 127.0.0.1:9000 // example: --listen 127.0.0.1:9000
var it = std.mem.split(u8, next_arg, ":"); var it = std.mem.splitScalar(u8, next_arg, ':');
const host = it.next().?; const host = it.next().?;
const port_text = it.next() orelse "14735"; const port_text = it.next() orelse "14735";
const port = std.fmt.parseInt(u16, port_text, 10) catch |err| const port = std.fmt.parseInt(u16, port_text, 10) catch |err|
@ -1676,7 +1676,7 @@ fn buildOutputType(
}, },
.rdynamic => rdynamic = true, .rdynamic => rdynamic = true,
.wl => { .wl => {
var split_it = mem.split(u8, it.only_arg, ","); var split_it = mem.splitScalar(u8, it.only_arg, ',');
while (split_it.next()) |linker_arg| { while (split_it.next()) |linker_arg| {
// Handle nested-joined args like `-Wl,-rpath=foo`. // Handle nested-joined args like `-Wl,-rpath=foo`.
// Must be prefixed with 1 or 2 dashes. // Must be prefixed with 1 or 2 dashes.
@ -2191,17 +2191,17 @@ fn buildOutputType(
const next_arg = linker_args_it.nextOrFatal(); const next_arg = linker_args_it.nextOrFatal();
try symbol_wrap_set.put(arena, next_arg, {}); try symbol_wrap_set.put(arena, next_arg, {});
} else if (mem.startsWith(u8, arg, "/subsystem:")) { } else if (mem.startsWith(u8, arg, "/subsystem:")) {
var split_it = mem.splitBackwards(u8, arg, ":"); var split_it = mem.splitBackwardsScalar(u8, arg, ':');
subsystem = try parseSubSystem(split_it.first()); subsystem = try parseSubSystem(split_it.first());
} else if (mem.startsWith(u8, arg, "/implib:")) { } else if (mem.startsWith(u8, arg, "/implib:")) {
var split_it = mem.splitBackwards(u8, arg, ":"); var split_it = mem.splitBackwardsScalar(u8, arg, ':');
emit_implib = .{ .yes = split_it.first() }; emit_implib = .{ .yes = split_it.first() };
emit_implib_arg_provided = true; emit_implib_arg_provided = true;
} else if (mem.startsWith(u8, arg, "/pdb:")) { } else if (mem.startsWith(u8, arg, "/pdb:")) {
var split_it = mem.splitBackwards(u8, arg, ":"); var split_it = mem.splitBackwardsScalar(u8, arg, ':');
pdb_out_path = split_it.first(); pdb_out_path = split_it.first();
} else if (mem.startsWith(u8, arg, "/version:")) { } else if (mem.startsWith(u8, arg, "/version:")) {
var split_it = mem.splitBackwards(u8, arg, ":"); var split_it = mem.splitBackwardsScalar(u8, arg, ':');
const version_arg = split_it.first(); const version_arg = split_it.first();
version = std.builtin.Version.parse(version_arg) catch |err| { version = std.builtin.Version.parse(version_arg) catch |err| {
fatal("unable to parse /version '{s}': {s}", .{ arg, @errorName(err) }); fatal("unable to parse /version '{s}': {s}", .{ arg, @errorName(err) });
@ -3541,10 +3541,10 @@ fn serveUpdateResults(s: *Server, comp: *Compilation) !void {
} }
const ModuleDepIterator = struct { const ModuleDepIterator = struct {
split: mem.SplitIterator(u8), split: mem.SplitIterator(u8, .scalar),
fn init(deps_str: []const u8) ModuleDepIterator { fn init(deps_str: []const u8) ModuleDepIterator {
return .{ .split = mem.split(u8, deps_str, ",") }; return .{ .split = mem.splitScalar(u8, deps_str, ',') };
} }
const Dependency = struct { const Dependency = struct {

View File

@ -2588,7 +2588,7 @@ const Writer = struct {
fn writeDocComment(self: *Writer, stream: anytype, doc_comment_index: u32) !void { fn writeDocComment(self: *Writer, stream: anytype, doc_comment_index: u32) !void {
if (doc_comment_index != 0) { if (doc_comment_index != 0) {
const doc_comment = self.code.nullTerminatedString(doc_comment_index); const doc_comment = self.code.nullTerminatedString(doc_comment_index);
var it = std.mem.tokenize(u8, doc_comment, "\n"); var it = std.mem.tokenizeScalar(u8, doc_comment, '\n');
while (it.next()) |doc_line| { while (it.next()) |doc_line| {
try stream.writeByteNTimes(' ', self.indent); try stream.writeByteNTimes(' ', self.indent);
try stream.print("///{s}\n", .{doc_line}); try stream.print("///{s}\n", .{doc_line});

View File

@ -18,7 +18,7 @@ test "issue 6456" {
comptime { comptime {
var fields: []const StructField = &[0]StructField{}; var fields: []const StructField = &[0]StructField{};
var it = std.mem.tokenize(u8, text, "\n"); var it = std.mem.tokenizeScalar(u8, text, '\n');
while (it.next()) |name| { while (it.next()) |name| {
fields = fields ++ &[_]StructField{StructField{ fields = fields ++ &[_]StructField{StructField{
.alignment = 0, .alignment = 0,

View File

@ -804,7 +804,7 @@ const TestManifest = struct {
}; };
const TrailingIterator = struct { const TrailingIterator = struct {
inner: std.mem.TokenIterator(u8), inner: std.mem.TokenIterator(u8, .any),
fn next(self: *TrailingIterator) ?[]const u8 { fn next(self: *TrailingIterator) ?[]const u8 {
const next_inner = self.inner.next() orelse return null; const next_inner = self.inner.next() orelse return null;
@ -814,7 +814,7 @@ const TestManifest = struct {
fn ConfigValueIterator(comptime T: type) type { fn ConfigValueIterator(comptime T: type) type {
return struct { return struct {
inner: std.mem.SplitIterator(u8), inner: std.mem.SplitIterator(u8, .scalar),
fn next(self: *@This()) !?T { fn next(self: *@This()) !?T {
const next_raw = self.inner.next() orelse return null; const next_raw = self.inner.next() orelse return null;
@ -855,7 +855,7 @@ const TestManifest = struct {
const actual_start = start orelse return error.MissingTestManifest; const actual_start = start orelse return error.MissingTestManifest;
const manifest_bytes = bytes[actual_start..end]; const manifest_bytes = bytes[actual_start..end];
var it = std.mem.tokenize(u8, manifest_bytes, "\r\n"); var it = std.mem.tokenizeAny(u8, manifest_bytes, "\r\n");
// First line is the test type // First line is the test type
const tt: Type = blk: { const tt: Type = blk: {
@ -886,7 +886,7 @@ const TestManifest = struct {
if (trimmed.len == 0) break; if (trimmed.len == 0) break;
// Parse key=value(s) // Parse key=value(s)
var kv_it = std.mem.split(u8, trimmed, "="); var kv_it = std.mem.splitScalar(u8, trimmed, '=');
const key = kv_it.first(); const key = kv_it.first();
try manifest.config_map.putNoClobber(key, kv_it.next() orelse return error.MissingValuesForConfig); try manifest.config_map.putNoClobber(key, kv_it.next() orelse return error.MissingValuesForConfig);
} }
@ -904,7 +904,7 @@ const TestManifest = struct {
) ConfigValueIterator(T) { ) ConfigValueIterator(T) {
const bytes = self.config_map.get(key) orelse TestManifestConfigDefaults.get(self.type, key); const bytes = self.config_map.get(key) orelse TestManifestConfigDefaults.get(self.type, key);
return ConfigValueIterator(T){ return ConfigValueIterator(T){
.inner = std.mem.split(u8, bytes, ","), .inner = std.mem.splitScalar(u8, bytes, ','),
}; };
} }
@ -932,7 +932,7 @@ const TestManifest = struct {
fn trailing(self: TestManifest) TrailingIterator { fn trailing(self: TestManifest) TrailingIterator {
return .{ return .{
.inner = std.mem.tokenize(u8, self.trailing_bytes, "\r\n"), .inner = std.mem.tokenizeAny(u8, self.trailing_bytes, "\r\n"),
}; };
} }
@ -1408,7 +1408,7 @@ fn runOneCase(
// Render the expected lines into a string that we can compare verbatim. // Render the expected lines into a string that we can compare verbatim.
var expected_generated = std.ArrayList(u8).init(arena); var expected_generated = std.ArrayList(u8).init(arena);
var actual_line_it = std.mem.split(u8, actual_stderr.items, "\n"); var actual_line_it = std.mem.splitScalar(u8, actual_stderr.items, '\n');
for (expected_errors) |expect_line| { for (expected_errors) |expect_line| {
const actual_line = actual_line_it.next() orelse { const actual_line = actual_line_it.next() orelse {
try expected_generated.appendSlice(expect_line); try expected_generated.appendSlice(expect_line);

View File

@ -27,7 +27,7 @@ pub fn main() !void {
var buf = std.ArrayList(u8).init(arena); var buf = std.ArrayList(u8).init(arena);
defer buf.deinit(); defer buf.deinit();
if (stderr.len != 0 and stderr[stderr.len - 1] == '\n') stderr = stderr[0 .. stderr.len - 1]; if (stderr.len != 0 and stderr[stderr.len - 1] == '\n') stderr = stderr[0 .. stderr.len - 1];
var it = mem.split(u8, stderr, "\n"); var it = mem.splitScalar(u8, stderr, '\n');
process_lines: while (it.next()) |line| { process_lines: while (it.next()) |line| {
if (line.len == 0) continue; if (line.len == 0) continue;

View File

@ -88,7 +88,7 @@ fn writeFunction(
\\ asm volatile ( \\ asm volatile (
\\ \\
); );
var iter = std.mem.split(u8, body, "\n"); var iter = std.mem.splitScalar(u8, body, '\n');
while (iter.next()) |line| { while (iter.next()) |line| {
try w.writeAll(" \\\\"); try w.writeAll(" \\\\");
try w.writeAll(line); try w.writeAll(line);

View File

@ -51,11 +51,11 @@ pub fn main() !void {
try writer.writeAll("pub const X86 = enum(usize) {\n"); try writer.writeAll("pub const X86 = enum(usize) {\n");
const table = try linux_dir.readFile("arch/x86/entry/syscalls/syscall_32.tbl", buf); const table = try linux_dir.readFile("arch/x86/entry/syscalls/syscall_32.tbl", buf);
var lines = mem.tokenize(u8, table, "\n"); var lines = mem.tokenizeScalar(u8, table, '\n');
while (lines.next()) |line| { while (lines.next()) |line| {
if (line[0] == '#') continue; if (line[0] == '#') continue;
var fields = mem.tokenize(u8, line, " \t"); var fields = mem.tokenizeAny(u8, line, " \t");
const number = fields.next() orelse return error.Incomplete; const number = fields.next() orelse return error.Incomplete;
// abi is always i386 // abi is always i386
_ = fields.next() orelse return error.Incomplete; _ = fields.next() orelse return error.Incomplete;
@ -70,11 +70,11 @@ pub fn main() !void {
try writer.writeAll("pub const X64 = enum(usize) {\n"); try writer.writeAll("pub const X64 = enum(usize) {\n");
const table = try linux_dir.readFile("arch/x86/entry/syscalls/syscall_64.tbl", buf); const table = try linux_dir.readFile("arch/x86/entry/syscalls/syscall_64.tbl", buf);
var lines = mem.tokenize(u8, table, "\n"); var lines = mem.tokenizeScalar(u8, table, '\n');
while (lines.next()) |line| { while (lines.next()) |line| {
if (line[0] == '#') continue; if (line[0] == '#') continue;
var fields = mem.tokenize(u8, line, " \t"); var fields = mem.tokenizeAny(u8, line, " \t");
const number = fields.next() orelse return error.Incomplete; const number = fields.next() orelse return error.Incomplete;
const abi = fields.next() orelse return error.Incomplete; const abi = fields.next() orelse return error.Incomplete;
// The x32 abi syscalls are always at the end. // The x32 abi syscalls are always at the end.
@ -96,11 +96,11 @@ pub fn main() !void {
); );
const table = try linux_dir.readFile("arch/arm/tools/syscall.tbl", buf); const table = try linux_dir.readFile("arch/arm/tools/syscall.tbl", buf);
var lines = mem.tokenize(u8, table, "\n"); var lines = mem.tokenizeScalar(u8, table, '\n');
while (lines.next()) |line| { while (lines.next()) |line| {
if (line[0] == '#') continue; if (line[0] == '#') continue;
var fields = mem.tokenize(u8, line, " \t"); var fields = mem.tokenizeAny(u8, line, " \t");
const number = fields.next() orelse return error.Incomplete; const number = fields.next() orelse return error.Incomplete;
const abi = fields.next() orelse return error.Incomplete; const abi = fields.next() orelse return error.Incomplete;
if (mem.eql(u8, abi, "oabi")) continue; if (mem.eql(u8, abi, "oabi")) continue;
@ -127,11 +127,11 @@ pub fn main() !void {
{ {
try writer.writeAll("pub const Sparc64 = enum(usize) {\n"); try writer.writeAll("pub const Sparc64 = enum(usize) {\n");
const table = try linux_dir.readFile("arch/sparc/kernel/syscalls/syscall.tbl", buf); const table = try linux_dir.readFile("arch/sparc/kernel/syscalls/syscall.tbl", buf);
var lines = mem.tokenize(u8, table, "\n"); var lines = mem.tokenizeScalar(u8, table, '\n');
while (lines.next()) |line| { while (lines.next()) |line| {
if (line[0] == '#') continue; if (line[0] == '#') continue;
var fields = mem.tokenize(u8, line, " \t"); var fields = mem.tokenizeAny(u8, line, " \t");
const number = fields.next() orelse return error.Incomplete; const number = fields.next() orelse return error.Incomplete;
const abi = fields.next() orelse return error.Incomplete; const abi = fields.next() orelse return error.Incomplete;
if (mem.eql(u8, abi, "32")) continue; if (mem.eql(u8, abi, "32")) continue;
@ -151,11 +151,11 @@ pub fn main() !void {
); );
const table = try linux_dir.readFile("arch/mips/kernel/syscalls/syscall_o32.tbl", buf); const table = try linux_dir.readFile("arch/mips/kernel/syscalls/syscall_o32.tbl", buf);
var lines = mem.tokenize(u8, table, "\n"); var lines = mem.tokenizeScalar(u8, table, '\n');
while (lines.next()) |line| { while (lines.next()) |line| {
if (line[0] == '#') continue; if (line[0] == '#') continue;
var fields = mem.tokenize(u8, line, " \t"); var fields = mem.tokenizeAny(u8, line, " \t");
const number = fields.next() orelse return error.Incomplete; const number = fields.next() orelse return error.Incomplete;
// abi is always o32 // abi is always o32
_ = fields.next() orelse return error.Incomplete; _ = fields.next() orelse return error.Incomplete;
@ -176,11 +176,11 @@ pub fn main() !void {
); );
const table = try linux_dir.readFile("arch/mips/kernel/syscalls/syscall_n64.tbl", buf); const table = try linux_dir.readFile("arch/mips/kernel/syscalls/syscall_n64.tbl", buf);
var lines = mem.tokenize(u8, table, "\n"); var lines = mem.tokenizeScalar(u8, table, '\n');
while (lines.next()) |line| { while (lines.next()) |line| {
if (line[0] == '#') continue; if (line[0] == '#') continue;
var fields = mem.tokenize(u8, line, " \t"); var fields = mem.tokenizeAny(u8, line, " \t");
const number = fields.next() orelse return error.Incomplete; const number = fields.next() orelse return error.Incomplete;
// abi is always n64 // abi is always n64
_ = fields.next() orelse return error.Incomplete; _ = fields.next() orelse return error.Incomplete;
@ -197,11 +197,11 @@ pub fn main() !void {
const table = try linux_dir.readFile("arch/powerpc/kernel/syscalls/syscall.tbl", buf); const table = try linux_dir.readFile("arch/powerpc/kernel/syscalls/syscall.tbl", buf);
var list_64 = std.ArrayList(u8).init(allocator); var list_64 = std.ArrayList(u8).init(allocator);
var lines = mem.tokenize(u8, table, "\n"); var lines = mem.tokenizeScalar(u8, table, '\n');
while (lines.next()) |line| { while (lines.next()) |line| {
if (line[0] == '#') continue; if (line[0] == '#') continue;
var fields = mem.tokenize(u8, line, " \t"); var fields = mem.tokenizeAny(u8, line, " \t");
const number = fields.next() orelse return error.Incomplete; const number = fields.next() orelse return error.Incomplete;
const abi = fields.next() orelse return error.Incomplete; const abi = fields.next() orelse return error.Incomplete;
const name = fields.next() orelse return error.Incomplete; const name = fields.next() orelse return error.Incomplete;
@ -277,9 +277,9 @@ pub fn main() !void {
}, },
}; };
var lines = mem.tokenize(u8, defines, "\n"); var lines = mem.tokenizeScalar(u8, defines, '\n');
loop: while (lines.next()) |line| { loop: while (lines.next()) |line| {
var fields = mem.tokenize(u8, line, " \t"); var fields = mem.tokenizeAny(u8, line, " \t");
const cmd = fields.next() orelse return error.Incomplete; const cmd = fields.next() orelse return error.Incomplete;
if (!mem.eql(u8, cmd, "#define")) continue; if (!mem.eql(u8, cmd, "#define")) continue;
const define = fields.next() orelse return error.Incomplete; const define = fields.next() orelse return error.Incomplete;
@ -339,9 +339,9 @@ pub fn main() !void {
}, },
}; };
var lines = mem.tokenize(u8, defines, "\n"); var lines = mem.tokenizeScalar(u8, defines, '\n');
loop: while (lines.next()) |line| { loop: while (lines.next()) |line| {
var fields = mem.tokenize(u8, line, " \t"); var fields = mem.tokenizeAny(u8, line, " \t");
const cmd = fields.next() orelse return error.Incomplete; const cmd = fields.next() orelse return error.Incomplete;
if (!mem.eql(u8, cmd, "#define")) continue; if (!mem.eql(u8, cmd, "#define")) continue;
const define = fields.next() orelse return error.Incomplete; const define = fields.next() orelse return error.Incomplete;

View File

@ -78,7 +78,7 @@ pub fn main() anyerror!void {
var residue: []const u8 = undefined; var residue: []const u8 = undefined;
var name: []const u8 = undefined; var name: []const u8 = undefined;
var it = mem.split(u8, line, " "); var it = mem.splitSequence(u8, line, " ");
while (it.next()) |property| { while (it.next()) |property| {
const i = mem.indexOf(u8, property, "=").?; const i = mem.indexOf(u8, property, "=").?;
const key = property[0..i]; const key = property[0..i];

View File

@ -19,7 +19,7 @@ const Version = struct {
minor: u32, minor: u32,
fn parse(str: []const u8) !Version { fn parse(str: []const u8) !Version {
var it = std.mem.split(u8, str, "."); var it = std.mem.splitScalar(u8, str, '.');
const major = it.first(); const major = it.first();
const minor = it.next() orelse return error.InvalidVersion; const minor = it.next() orelse return error.InvalidVersion;