Source
pub fn SplitIterator(comptime T: type, comptime delimiter_type: DelimiterType) type {
return struct {
buffer: []const T,
index: ?usize,
delimiter: switch (delimiter_type) {
.sequence, .any => []const T,
.scalar => T,
},
const Self = @This();
/// Returns a slice of the first field.
/// Call this only to get the first field and then use `next` to get all subsequent fields.
/// Asserts that iteration has not begun.
pub fn first(self: *Self) []const T {
assert(self.index.? == 0);
return self.next().?;
}
/// Returns a slice of the next field, or null if splitting is complete.
pub fn next(self: *Self) ?[]const T {
const start = self.index orelse return null;
const end = if (switch (delimiter_type) {
.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;
} else blk: {
self.index = null;
break :blk self.buffer.len;
};
return self.buffer[start..end];
}
/// Returns a slice of the next field, or null if splitting is complete.
/// This method does not alter self.index.
pub fn peek(self: *Self) ?[]const T {
const start = self.index orelse return null;
const end = if (switch (delimiter_type) {
.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| delim_start else self.buffer.len;
return self.buffer[start..end];
}
/// Returns a slice of the remaining bytes. Does not affect iterator state.
pub fn rest(self: Self) []const T {
const end = self.buffer.len;
const start = self.index orelse end;
return self.buffer[start..end];
}
/// Resets the iterator to the initial slice.
pub fn reset(self: *Self) void {
self.index = 0;
}
};
}