aboutsummaryrefslogtreecommitdiff
path: root/lib/std/BitStack.zig
diff options
context:
space:
mode:
authorJosh Wolfe <thejoshwolfe@gmail.com>2023-07-21 19:56:46 -0400
committerGitHub <noreply@github.com>2023-07-21 19:56:46 -0400
commit8924f81d8cd96f5a69a54d87119a748247079a09 (patch)
tree4dcb427921a41d3c75d3f3f4b79937d406c0a8a6 /lib/std/BitStack.zig
parenta2d81c547ccdb1130c4f55bb736d82f97902a3dd (diff)
downloadzig-8924f81d8cd96f5a69a54d87119a748247079a09.tar.gz
zig-8924f81d8cd96f5a69a54d87119a748247079a09.zip
std.json: Unify stringify and writeStream (#16405)
Diffstat (limited to 'lib/std/BitStack.zig')
-rw-r--r--lib/std/BitStack.zig86
1 files changed, 86 insertions, 0 deletions
diff --git a/lib/std/BitStack.zig b/lib/std/BitStack.zig
new file mode 100644
index 0000000000..592b541d49
--- /dev/null
+++ b/lib/std/BitStack.zig
@@ -0,0 +1,86 @@
+//! Effectively a stack of u1 values implemented using ArrayList(u8).
+
+const BitStack = @This();
+
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+const ArrayList = std.ArrayList;
+
+bytes: std.ArrayList(u8),
+bit_len: usize = 0,
+
+pub fn init(allocator: Allocator) @This() {
+ return .{
+ .bytes = std.ArrayList(u8).init(allocator),
+ };
+}
+
+pub fn deinit(self: *@This()) void {
+ self.bytes.deinit();
+ self.* = undefined;
+}
+
+pub fn ensureTotalCapacity(self: *@This(), bit_capcity: usize) Allocator.Error!void {
+ const byte_capacity = (bit_capcity + 7) >> 3;
+ try self.bytes.ensureTotalCapacity(byte_capacity);
+}
+
+pub fn push(self: *@This(), b: u1) Allocator.Error!void {
+ const byte_index = self.bit_len >> 3;
+ if (self.bytes.items.len <= byte_index) {
+ try self.bytes.append(0);
+ }
+
+ pushWithStateAssumeCapacity(self.bytes.items, &self.bit_len, b);
+}
+
+pub fn peek(self: *const @This()) u1 {
+ return peekWithState(self.bytes.items, self.bit_len);
+}
+
+pub fn pop(self: *@This()) u1 {
+ return popWithState(self.bytes.items, &self.bit_len);
+}
+
+/// Standalone function for working with a fixed-size buffer.
+pub fn pushWithStateAssumeCapacity(buf: []u8, bit_len: *usize, b: u1) void {
+ const byte_index = bit_len.* >> 3;
+ const bit_index = @as(u3, @intCast(bit_len.* & 7));
+
+ buf[byte_index] &= ~(@as(u8, 1) << bit_index);
+ buf[byte_index] |= @as(u8, b) << bit_index;
+
+ bit_len.* += 1;
+}
+
+/// Standalone function for working with a fixed-size buffer.
+pub fn peekWithState(buf: []const u8, bit_len: usize) u1 {
+ const byte_index = (bit_len - 1) >> 3;
+ const bit_index = @as(u3, @intCast((bit_len - 1) & 7));
+ return @as(u1, @intCast((buf[byte_index] >> bit_index) & 1));
+}
+
+/// Standalone function for working with a fixed-size buffer.
+pub fn popWithState(buf: []const u8, bit_len: *usize) u1 {
+ const b = peekWithState(buf, bit_len.*);
+ bit_len.* -= 1;
+ return b;
+}
+
+const testing = std.testing;
+test BitStack {
+ var stack = BitStack.init(testing.allocator);
+ defer stack.deinit();
+
+ try stack.push(1);
+ try stack.push(0);
+ try stack.push(0);
+ try stack.push(1);
+
+ try testing.expectEqual(@as(u1, 1), stack.peek());
+ try testing.expectEqual(@as(u1, 1), stack.pop());
+ try testing.expectEqual(@as(u1, 0), stack.peek());
+ try testing.expectEqual(@as(u1, 0), stack.pop());
+ try testing.expectEqual(@as(u1, 0), stack.pop());
+ try testing.expectEqual(@as(u1, 1), stack.pop());
+}