diff --git a/src/engine/sys.zig b/src/engine/sys.zig index 709c689..79167f1 100644 --- a/src/engine/sys.zig +++ b/src/engine/sys.zig @@ -600,7 +600,7 @@ pub const FileSystem = union(enum) { const last_sequence_index = sequences.len - 1; for (sequences) |sequence, index| if (sequence.len != 0) { - var components = ona.mem.Spliterator(u8){ + var components = ona.io.Spliterator(u8){ .source = sequence, .delimiter = "/", }; diff --git a/src/ona/io.zig b/src/ona/io.zig index 6ac1d87..de8627b 100644 --- a/src/ona/io.zig +++ b/src/ona/io.zig @@ -97,6 +97,78 @@ pub const FileAccess = struct { } }; +/// +/// Returns a state machine for lazily computing all `Element` components of a given source input +/// that match a delimiting pattern. +/// +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`. + /// + 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.hasNext()) return null; + + if (std.mem.indexOfPos(Element, self.source, 0, self.delimiter)) |index| { + defer self.source = self.source[(index + self.delimiter.len) .. self.source.len]; + + return self.source[0 .. index]; + } + + defer self.source = self.source[self.source.len .. self.source.len]; + + return self.source; + } + }; +} + +test { + const testing = std.testing; + + // Single-character delimiter. + { + var spliterator = Spliterator(u8){ + .source = "single.character.separated.hello.world", + .delimiter = ".", + }; + + const components = [_][]const u8{"single", "character", "separated", "hello", "world"}; + var index = @as(usize, 0); + + while (spliterator.next()) |split| : (index += 1) { + try testing.expect(std.mem.eql(u8, split, components[index])); + } + } + + // Multi-character delimiter. + { + var spliterator = Spliterator(u8){ + .source = "finding a needle in a needle stack", + .delimiter = "needle", + }; + + const components = [_][]const u8{"finding a ", " in a ", " stack"}; + var index = @as(usize, 0); + + while (spliterator.next()) |split| : (index += 1) { + try testing.expect(std.mem.eql(u8, split, components[index])); + } + } +} + /// /// Opaque interface to a "writable" resource, such as a block device, memory buffer, or network /// socket. @@ -214,6 +286,20 @@ pub const Writer = struct { } }; +/// +/// 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; +} + +test { + try std.testing.expectEqual(findFirst(u8, "1234567890", '7'), 6); +} + /// /// Writer that silently throws consumed data away and never fails. /// diff --git a/src/ona/main.zig b/src/ona/main.zig index bef57aa..0aa7691 100644 --- a/src/ona/main.zig +++ b/src/ona/main.zig @@ -4,11 +4,6 @@ /// pub const io = @import("./io.zig"); -/// -/// Memory utilities. -/// -pub const mem = @import("./mem.zig"); - /// /// Metaprogramming introspection utilities /// @@ -26,7 +21,6 @@ pub const table = @import("./table.zig"); test { _ = io; - _ = mem; _ = meta; _ = stack; _ = table; diff --git a/src/ona/mem.zig b/src/ona/mem.zig deleted file mode 100644 index 3df40b9..0000000 --- a/src/ona/mem.zig +++ /dev/null @@ -1,87 +0,0 @@ -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`. - /// - 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.hasNext()) return null; - - if (std.mem.indexOfPos(Element, self.source, 0, self.delimiter)) |index| { - defer self.source = self.source[(index + self.delimiter.len) .. self.source.len]; - - return self.source[0 .. index]; - } - - defer self.source = self.source[self.source.len .. self.source.len]; - - return self.source; - } - }; -} - -test { - const testing = std.testing; - - // Single-character delimiter. - { - var spliterator = Spliterator(u8){ - .source = "single.character.separated.hello.world", - .delimiter = ".", - }; - - const components = [_][]const u8{"single", "character", "separated", "hello", "world"}; - var index = @as(usize, 0); - - while (spliterator.next()) |split| : (index += 1) { - try testing.expect(std.mem.eql(u8, split, components[index])); - } - } - - // Multi-character delimiter. - { - var spliterator = Spliterator(u8){ - .source = "finding a needle in a needle stack", - .delimiter = "needle", - }; - - const components = [_][]const u8{"finding a ", " in a ", " stack"}; - var index = @as(usize, 0); - - while (spliterator.next()) |split| : (index += 1) { - try testing.expect(std.mem.eql(u8, split, components[index])); - } - } -} - -/// -/// 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; -} - -test { - try std.testing.expectEqual(findFirst(u8, "1234567890", '7'), 6); -}