authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-27 16:48:17-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-31 22:10:11-07:00
logfa410cc234f4db16f9bdff3f9b0d0d66caa54c6b
tree19fb291eed8cb72a47f5f19a1384fabbfaf88644
parent1b43551190fc9aa83ae175e1db3a9db60dba5bb9

std.Io: delete BitReader


3 files changed, 4 insertions(+), 243 deletions(-)

lib/std/Io.zig-5
...@@ -467,9 +467,6 @@ pub const CountingReader = @import("Io/counting_reader.zig").CountingReader;...@@ -467,9 +467,6 @@ pub const CountingReader = @import("Io/counting_reader.zig").CountingReader;
467/// Deprecated with no replacement; inefficient pattern467/// Deprecated with no replacement; inefficient pattern
468pub const countingReader = @import("Io/counting_reader.zig").countingReader;468pub const countingReader = @import("Io/counting_reader.zig").countingReader;
469469
470pub const BitReader = @import("Io/bit_reader.zig").BitReader;
471pub const bitReader = @import("Io/bit_reader.zig").bitReader;
472
473pub const tty = @import("Io/tty.zig");470pub const tty = @import("Io/tty.zig");
474471
475/// Deprecated in favor of `Writer.Discarding`.472/// Deprecated in favor of `Writer.Discarding`.
...@@ -945,9 +942,7 @@ pub fn PollFiles(comptime StreamEnum: type) type {...@@ -945,9 +942,7 @@ pub fn PollFiles(comptime StreamEnum: type) type {
945942
946test {943test {
947 _ = Reader;944 _ = Reader;
948 _ = Reader.Limited;
949 _ = Writer;945 _ = Writer;
950 _ = BitReader;
951 _ = BufferedReader;946 _ = BufferedReader;
952 _ = BufferedWriter;947 _ = BufferedWriter;
953 _ = CountingWriter;948 _ = CountingWriter;
lib/std/Io/Reader.zig+4
...@@ -1874,3 +1874,7 @@ pub fn writableVectorWsa(...@@ -1874,3 +1874,7 @@ pub fn writableVectorWsa(
1874 }1874 }
1875 return .{ i, n };1875 return .{ i, n };
1876}1876}
1877
1878test {
1879 _ = Limited;
1880}
lib/std/Io/bit_reader.zig deleted-238
...@@ -1,238 +0,0 @@
1const std = @import("../std.zig");
2
3//General note on endianess:
4//Big endian is packed starting in the most significant part of the byte and subsequent
5// bytes contain less significant bits. Thus we always take bits from the high
6// end and place them below existing bits in our output.
7//Little endian is packed starting in the least significant part of the byte and
8// subsequent bytes contain more significant bits. Thus we always take bits from
9// the low end and place them above existing bits in our output.
10//Regardless of endianess, within any given byte the bits are always in most
11// to least significant order.
12//Also regardless of endianess, the buffer always aligns bits to the low end
13// of the byte.
14
15/// Creates a bit reader which allows for reading bits from an underlying standard reader
16pub fn BitReader(comptime endian: std.builtin.Endian, comptime Reader: type) type {
17 return struct {
18 reader: Reader,
19 bits: u8 = 0,
20 count: u4 = 0,
21
22 const low_bit_mask = [9]u8{
23 0b00000000,
24 0b00000001,
25 0b00000011,
26 0b00000111,
27 0b00001111,
28 0b00011111,
29 0b00111111,
30 0b01111111,
31 0b11111111,
32 };
33
34 fn Bits(comptime T: type) type {
35 return struct {
36 T,
37 u16,
38 };
39 }
40
41 fn initBits(comptime T: type, out: anytype, num: u16) Bits(T) {
42 const UT = std.meta.Int(.unsigned, @bitSizeOf(T));
43 return .{
44 @bitCast(@as(UT, @intCast(out))),
45 num,
46 };
47 }
48
49 /// Reads `bits` bits from the reader and returns a specified type
50 /// containing them in the least significant end, returning an error if the
51 /// specified number of bits could not be read.
52 pub fn readBitsNoEof(self: *@This(), comptime T: type, num: u16) !T {
53 const b, const c = try self.readBitsTuple(T, num);
54 if (c < num) return error.EndOfStream;
55 return b;
56 }
57
58 /// Reads `bits` bits from the reader and returns a specified type
59 /// containing them in the least significant end. The number of bits successfully
60 /// read is placed in `out_bits`, as reaching the end of the stream is not an error.
61 pub fn readBits(self: *@This(), comptime T: type, num: u16, out_bits: *u16) !T {
62 const b, const c = try self.readBitsTuple(T, num);
63 out_bits.* = c;
64 return b;
65 }
66
67 /// Reads `bits` bits from the reader and returns a tuple of the specified type
68 /// containing them in the least significant end, and the number of bits successfully
69 /// read. Reaching the end of the stream is not an error.
70 pub fn readBitsTuple(self: *@This(), comptime T: type, num: u16) !Bits(T) {
71 const UT = std.meta.Int(.unsigned, @bitSizeOf(T));
72 const U = if (@bitSizeOf(T) < 8) u8 else UT; //it is a pain to work with <u8
73
74 //dump any bits in our buffer first
75 if (num <= self.count) return initBits(T, self.removeBits(@intCast(num)), num);
76
77 var out_count: u16 = self.count;
78 var out: U = self.removeBits(self.count);
79
80 //grab all the full bytes we need and put their
81 //bits where they belong
82 const full_bytes_left = (num - out_count) / 8;
83
84 for (0..full_bytes_left) |_| {
85 const byte = self.reader.readByte() catch |err| switch (err) {
86 error.EndOfStream => return initBits(T, out, out_count),
87 else => |e| return e,
88 };
89
90 switch (endian) {
91 .big => {
92 if (U == u8) out = 0 else out <<= 8; //shifting u8 by 8 is illegal in Zig
93 out |= byte;
94 },
95 .little => {
96 const pos = @as(U, byte) << @intCast(out_count);
97 out |= pos;
98 },
99 }
100 out_count += 8;
101 }
102
103 const bits_left = num - out_count;
104 const keep = 8 - bits_left;
105
106 if (bits_left == 0) return initBits(T, out, out_count);
107
108 const final_byte = self.reader.readByte() catch |err| switch (err) {
109 error.EndOfStream => return initBits(T, out, out_count),
110 else => |e| return e,
111 };
112
113 switch (endian) {
114 .big => {
115 out <<= @intCast(bits_left);
116 out |= final_byte >> @intCast(keep);
117 self.bits = final_byte & low_bit_mask[keep];
118 },
119 .little => {
120 const pos = @as(U, final_byte & low_bit_mask[bits_left]) << @intCast(out_count);
121 out |= pos;
122 self.bits = final_byte >> @intCast(bits_left);
123 },
124 }
125
126 self.count = @intCast(keep);
127 return initBits(T, out, num);
128 }
129
130 //convenience function for removing bits from
131 //the appropriate part of the buffer based on
132 //endianess.
133 fn removeBits(self: *@This(), num: u4) u8 {
134 if (num == 8) {
135 self.count = 0;
136 return self.bits;
137 }
138
139 const keep = self.count - num;
140 const bits = switch (endian) {
141 .big => self.bits >> @intCast(keep),
142 .little => self.bits & low_bit_mask[num],
143 };
144 switch (endian) {
145 .big => self.bits &= low_bit_mask[keep],
146 .little => self.bits >>= @intCast(num),
147 }
148
149 self.count = keep;
150 return bits;
151 }
152
153 pub fn alignToByte(self: *@This()) void {
154 self.bits = 0;
155 self.count = 0;
156 }
157 };
158}
159
160pub fn bitReader(comptime endian: std.builtin.Endian, reader: anytype) BitReader(endian, @TypeOf(reader)) {
161 return .{ .reader = reader };
162}
163
164///////////////////////////////
165
166test "api coverage" {
167 const mem_be = [_]u8{ 0b11001101, 0b00001011 };
168 const mem_le = [_]u8{ 0b00011101, 0b10010101 };
169
170 var mem_in_be = std.io.fixedBufferStream(&mem_be);
171 var bit_stream_be = bitReader(.big, mem_in_be.reader());
172
173 var out_bits: u16 = undefined;
174
175 const expect = std.testing.expect;
176 const expectError = std.testing.expectError;
177
178 try expect(1 == try bit_stream_be.readBits(u2, 1, &out_bits));
179 try expect(out_bits == 1);
180 try expect(2 == try bit_stream_be.readBits(u5, 2, &out_bits));
181 try expect(out_bits == 2);
182 try expect(3 == try bit_stream_be.readBits(u128, 3, &out_bits));
183 try expect(out_bits == 3);
184 try expect(4 == try bit_stream_be.readBits(u8, 4, &out_bits));
185 try expect(out_bits == 4);
186 try expect(5 == try bit_stream_be.readBits(u9, 5, &out_bits));
187 try expect(out_bits == 5);
188 try expect(1 == try bit_stream_be.readBits(u1, 1, &out_bits));
189 try expect(out_bits == 1);
190
191 mem_in_be.pos = 0;
192 bit_stream_be.count = 0;
193 try expect(0b110011010000101 == try bit_stream_be.readBits(u15, 15, &out_bits));
194 try expect(out_bits == 15);
195
196 mem_in_be.pos = 0;
197 bit_stream_be.count = 0;
198 try expect(0b1100110100001011 == try bit_stream_be.readBits(u16, 16, &out_bits));
199 try expect(out_bits == 16);
200
201 _ = try bit_stream_be.readBits(u0, 0, &out_bits);
202
203 try expect(0 == try bit_stream_be.readBits(u1, 1, &out_bits));
204 try expect(out_bits == 0);
205 try expectError(error.EndOfStream, bit_stream_be.readBitsNoEof(u1, 1));
206
207 var mem_in_le = std.io.fixedBufferStream(&mem_le);
208 var bit_stream_le = bitReader(.little, mem_in_le.reader());
209
210 try expect(1 == try bit_stream_le.readBits(u2, 1, &out_bits));
211 try expect(out_bits == 1);
212 try expect(2 == try bit_stream_le.readBits(u5, 2, &out_bits));
213 try expect(out_bits == 2);
214 try expect(3 == try bit_stream_le.readBits(u128, 3, &out_bits));
215 try expect(out_bits == 3);
216 try expect(4 == try bit_stream_le.readBits(u8, 4, &out_bits));
217 try expect(out_bits == 4);
218 try expect(5 == try bit_stream_le.readBits(u9, 5, &out_bits));
219 try expect(out_bits == 5);
220 try expect(1 == try bit_stream_le.readBits(u1, 1, &out_bits));
221 try expect(out_bits == 1);
222
223 mem_in_le.pos = 0;
224 bit_stream_le.count = 0;
225 try expect(0b001010100011101 == try bit_stream_le.readBits(u15, 15, &out_bits));
226 try expect(out_bits == 15);
227
228 mem_in_le.pos = 0;
229 bit_stream_le.count = 0;
230 try expect(0b1001010100011101 == try bit_stream_le.readBits(u16, 16, &out_bits));
231 try expect(out_bits == 16);
232
233 _ = try bit_stream_le.readBits(u0, 0, &out_bits);
234
235 try expect(0 == try bit_stream_le.readBits(u1, 1, &out_bits));
236 try expect(out_bits == 0);
237 try expectError(error.EndOfStream, bit_stream_le.readBitsNoEof(u1, 1));
238}