59 lines
1.8 KiB
Zig
59 lines
1.8 KiB
Zig
|
const std = @import("std");
|
||
|
|
||
|
///
|
||
|
/// State machine for lazily computing all components of [Spliterator.source] that match the pattern
|
||
|
/// in [Spliterator.delimiter].
|
||
|
///
|
||
|
pub fn Spliterator(comptime Element: type) type {
|
||
|
return struct {
|
||
|
source: []const Element,
|
||
|
delimiter: []const Element,
|
||
|
|
||
|
const Self = @This();
|
||
|
|
||
|
///
|
||
|
/// Returns `true` if there is more data to be processed, otherwise `false`.
|
||
|
///
|
||
|
/// Note that [Spliterator.next] implicitly calls this function to determine if it should
|
||
|
/// return another slice or `null`.
|
||
|
///
|
||
|
pub fn hasNext(self: Self) bool {
|
||
|
return (self.source.len != 0);
|
||
|
}
|
||
|
|
||
|
///
|
||
|
/// Iterates on `self` and returns the next view of [Spliterator.source] that matches
|
||
|
/// [Spliterator.delimiter], or `null` if there is no more data to be processed.
|
||
|
///
|
||
|
pub fn next(self: *Self) ?[]const Element {
|
||
|
if (self.delimiter.len == 0) {
|
||
|
defer self.source = self.source[self.source.len .. 0];
|
||
|
|
||
|
return self.source;
|
||
|
}
|
||
|
|
||
|
while (self.hasNext()) {
|
||
|
var cursor = @as(usize, 0);
|
||
|
var window = self.source[cursor .. (self.source - cursor)];
|
||
|
|
||
|
defer self.source = window;
|
||
|
|
||
|
if (std.mem.eql(Element, window, self.delimiter))
|
||
|
return self.source[cursor .. self.delimiter.len];
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
///
|
||
|
/// Searches the slice of `Data` referenced by `data` for the first instance of `sought_datum`,
|
||
|
/// returning its index or `null` if it could not be found.
|
||
|
///
|
||
|
pub fn findFirst(comptime Data: type, data: []const Data, sought_datum: Data) ?usize {
|
||
|
for (data) |datum, index| if (datum == sought_datum) return index;
|
||
|
|
||
|
return null;
|
||
|
}
|