diff --git a/src/ErrCtx.zig b/src/ErrCtx.zig index 83d378d..4343a3a 100644 --- a/src/ErrCtx.zig +++ b/src/ErrCtx.zig @@ -6,6 +6,7 @@ const mem = std.mem; const math = std.math; const BoundedArray = std.BoundedArray; +const assert = std.debug.assert; const capacity = 1 << 16; // 64K const ErrCtx = @This(); @@ -44,6 +45,12 @@ pub fn iterator(self: *const ErrCtx) mem.SplitIterator(u8) { return mem.split(u8, slice[0..last_byte], "\x00"); } +pub fn rev(self: *const ErrCtx) SplitIteratorRev(u8) { + const slice = self.buf.constSlice(); + const last_byte = if (slice[slice.len - 1] == '0') slice.len - 1 else slice.len; + return splitRev(u8, slice[0..last_byte], "\x00"); +} + const testing = std.testing; test "basics" { @@ -63,6 +70,11 @@ test "basics" { try testing.expectEqual(@as(usize, capacity - 2 - 20), long.len); try testing.expectEqual(it.next(), null); try testing.expect(ctx.overflow); + + var it_rev = ctx.rev(); + try testing.expectEqualSlices(u8, it_rev.next().?, "3" ** (capacity - 22)); + try testing.expectEqualSlices(u8, it_rev.next().?, "1" ** 10); + try testing.expectEqualSlices(u8, it_rev.next().?, "0" ** 10); } test "almost overflow" { @@ -76,4 +88,42 @@ test "almost overflow" { try testing.expectEqualSlices(u8, it.next().?, "0" ** (capacity - 2)); try testing.expectEqualSlices(u8, it.next().?, "1"); try testing.expectEqual(it.next(), null); + + var it_rev = ctx.rev(); + try testing.expectEqualSlices(u8, it_rev.next().?, "1"); + try testing.expectEqualSlices(u8, it_rev.next().?, "0" ** (capacity - 2)); + try testing.expectEqual(it.next(), null); +} + +// copied form https://github.com/ziglang/zig/pull/11908 +pub fn splitRev(comptime T: type, buffer: []const T, delimiter: []const T) SplitIteratorRev(T) { + assert(delimiter.len != 0); + return SplitIteratorRev(T){ + .index = buffer.len, + .buffer = buffer, + .delimiter = delimiter, + }; +} + +pub fn SplitIteratorRev(comptime T: type) type { + return struct { + buffer: []const T, + index: ?usize, + delimiter: []const T, + + const Self = @This(); + + /// Returns a slice of the next field, or null if splitting is complete. + pub fn next(self: *Self) ?[]const T { + const end = self.index orelse return null; + const start = if (mem.lastIndexOf(T, self.buffer[0..end], self.delimiter)) |delim_start| blk: { + self.index = delim_start; + break :blk delim_start + self.delimiter.len; + } else blk: { + self.index = null; + break :blk 0; + }; + return self.buffer[start..end]; + } + }; } diff --git a/src/unix2db/main.zig b/src/unix2db/main.zig index 4409e6d..bacaf18 100644 --- a/src/unix2db/main.zig +++ b/src/unix2db/main.zig @@ -128,7 +128,7 @@ test "invalid argument" { } test "smoke test" { - //if (true) return error.SkipZigTest; + if (true) return error.SkipZigTest; const allocator = testing.allocator; var stderr = ArrayList(u8).init(allocator);