authorgravatar for tgschultz@gmail.comtgschultz <tgschultz@gmail.com> 2021-10-08 16:22:32+00:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-09 03:15:34-04:00
log526191bfafe722700323df30647eed0c03fc2403
tree3b9b1c31d0a2a53ba8014da076bd6b04e1df5fca
parent73403d897caec40eff16226abb54098fa6623954

Better documentation, use of `len` field instead of function, @bitSizeOf instead of meta.bitCout


1 files changed, 109 insertions(+), 116 deletions(-)

lib/std/packed_int_array.zig+109-116
...@@ -1,3 +1,7 @@...@@ -1,3 +1,7 @@
1//! An set of array and slice types that bit-pack integer elements. A normal [12]u3
2//! takes up 12 bytes of memory since u3's alignment is 1. PackedArray(u3, 12) only
3//! takes up 4 bytes of memory.
4
1const std = @import("std");5const std = @import("std");
2const builtin = @import("builtin");6const builtin = @import("builtin");
3const debug = std.debug;7const debug = std.debug;
...@@ -5,8 +9,10 @@ const testing = std.testing;...@@ -5,8 +9,10 @@ const testing = std.testing;
5const native_endian = builtin.target.cpu.arch.endian();9const native_endian = builtin.target.cpu.arch.endian();
6const Endian = std.builtin.Endian;10const Endian = std.builtin.Endian;
711
12/// Provides a set of functions for reading and writing packed integers from a
13/// slice of bytes.
8pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {14pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {
9 //The general technique employed here is to cast bytes in the array to a container15 // The general technique employed here is to cast bytes in the array to a container
10 // integer (having bits % 8 == 0) large enough to contain the number of bits we want,16 // integer (having bits % 8 == 0) large enough to contain the number of bits we want,
11 // then we can retrieve or store the new value with a relative minimum of masking17 // then we can retrieve or store the new value with a relative minimum of masking
12 // and shifting. In this worst case, this means that we'll need an integer that's18 // and shifting. In this worst case, this means that we'll need an integer that's
...@@ -18,13 +24,13 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {...@@ -18,13 +24,13 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {
18 // mean the OS fatally kills the program. Thus, we use a larger container (MaxIo)24 // mean the OS fatally kills the program. Thus, we use a larger container (MaxIo)
19 // most of the time, but a smaller container (MinIo) when touching the last byte25 // most of the time, but a smaller container (MinIo) when touching the last byte
20 // of the memory.26 // of the memory.
21 const int_bits = comptime std.meta.bitCount(Int);27 const int_bits = @bitSizeOf(Int);
2228
23 //in the best case, this is the number of bytes we need to touch29 // In the best case, this is the number of bytes we need to touch
24 // to read or write a value, as bits30 // to read or write a value, as bits.
25 const min_io_bits = ((int_bits + 7) / 8) * 8;31 const min_io_bits = ((int_bits + 7) / 8) * 8;
2632
27 //in the worst case, this is the number of bytes we need to touch33 // In the worst case, this is the number of bytes we need to touch
28 // to read or write a value, as bits. To calculate for int_bits > 1,34 // to read or write a value, as bits. To calculate for int_bits > 1,
29 // set aside 2 bits to touch the first and last bytes, then divide35 // set aside 2 bits to touch the first and last bytes, then divide
30 // by 8 to see how many bytes can be filled up inbetween.36 // by 8 to see how many bytes can be filled up inbetween.
...@@ -34,30 +40,32 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {...@@ -34,30 +40,32 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {
34 else => ((int_bits - 2) / 8 + 2) * 8,40 else => ((int_bits - 2) / 8 + 2) * 8,
35 };41 };
3642
37 //we bitcast the desired Int type to an unsigned version of itself43 // We bitcast the desired Int type to an unsigned version of itself
38 // to avoid issues with shifting signed ints.44 // to avoid issues with shifting signed ints.
39 const UnInt = std.meta.Int(.unsigned, int_bits);45 const UnInt = std.meta.Int(.unsigned, int_bits);
4046
41 //The maximum container int type47 // The maximum container int type
42 const MinIo = std.meta.Int(.unsigned, min_io_bits);48 const MinIo = std.meta.Int(.unsigned, min_io_bits);
4349
44 //The minimum container int type50 // The minimum container int type
45 const MaxIo = std.meta.Int(.unsigned, max_io_bits);51 const MaxIo = std.meta.Int(.unsigned, max_io_bits);
4652
47 return struct {53 return struct {
54 /// Retrieves the integer at `index` from the packed data beginning at `bit_offset`
55 /// within `bytes`.
48 pub fn get(bytes: []const u8, index: usize, bit_offset: u7) Int {56 pub fn get(bytes: []const u8, index: usize, bit_offset: u7) Int {
49 if (int_bits == 0) return 0;57 if (int_bits == 0) return 0;
5058
51 const bit_index = (index * int_bits) + bit_offset;59 const bit_index = (index * int_bits) + bit_offset;
52 const max_end_byte = (bit_index + max_io_bits) / 8;60 const max_end_byte = (bit_index + max_io_bits) / 8;
5361
54 //Using the larger container size will potentially read out of bounds62 //using the larger container size will potentially read out of bounds
55 if (max_end_byte > bytes.len) return getBits(bytes, MinIo, bit_index);63 if (max_end_byte > bytes.len) return getBits(bytes, MinIo, bit_index);
56 return getBits(bytes, MaxIo, bit_index);64 return getBits(bytes, MaxIo, bit_index);
57 }65 }
5866
59 fn getBits(bytes: []const u8, comptime Container: type, bit_index: usize) Int {67 fn getBits(bytes: []const u8, comptime Container: type, bit_index: usize) Int {
60 const container_bits = comptime std.meta.bitCount(Container);68 const container_bits = @bitSizeOf(Container);
61 const Shift = std.math.Log2Int(Container);69 const Shift = std.math.Log2Int(Container);
6270
63 const start_byte = bit_index / 8;71 const start_byte = bit_index / 8;
...@@ -86,19 +94,21 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {...@@ -86,19 +94,21 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {
86 return @bitCast(Int, @truncate(UnInt, value));94 return @bitCast(Int, @truncate(UnInt, value));
87 }95 }
8896
97 /// Sets the integer at `index` to `val` within the packed data beginning
98 /// at `bit_offset` into `bytes`.
89 pub fn set(bytes: []u8, index: usize, bit_offset: u3, int: Int) void {99 pub fn set(bytes: []u8, index: usize, bit_offset: u3, int: Int) void {
90 if (int_bits == 0) return;100 if (int_bits == 0) return;
91101
92 const bit_index = (index * int_bits) + bit_offset;102 const bit_index = (index * int_bits) + bit_offset;
93 const max_end_byte = (bit_index + max_io_bits) / 8;103 const max_end_byte = (bit_index + max_io_bits) / 8;
94104
95 //Using the larger container size will potentially write out of bounds105 //using the larger container size will potentially write out of bounds
96 if (max_end_byte > bytes.len) return setBits(bytes, MinIo, bit_index, int);106 if (max_end_byte > bytes.len) return setBits(bytes, MinIo, bit_index, int);
97 setBits(bytes, MaxIo, bit_index, int);107 setBits(bytes, MaxIo, bit_index, int);
98 }108 }
99109
100 fn setBits(bytes: []u8, comptime Container: type, bit_index: usize, int: Int) void {110 fn setBits(bytes: []u8, comptime Container: type, bit_index: usize, int: Int) void {
101 const container_bits = comptime std.meta.bitCount(Container);111 const container_bits = @bitSizeOf(Container);
102 const Shift = std.math.Log2Int(Container);112 const Shift = std.math.Log2Int(Container);
103113
104 const start_byte = bit_index / 8;114 const start_byte = bit_index / 8;
...@@ -132,7 +142,9 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {...@@ -132,7 +142,9 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {
132 target_ptr.* = target;142 target_ptr.* = target;
133 }143 }
134144
135 fn slice(bytes: []u8, bit_offset: u3, start: usize, end: usize) PackedIntSliceEndian(Int, endian) {145 /// Provides a PackedIntSlice of the packed integers in `bytes` (which begins at `bit_offset`)
146 /// from the element specified by `start` to the element specified by `end`.
147 pub fn slice(bytes: []u8, bit_offset: u3, start: usize, end: usize) PackedIntSliceEndian(Int, endian) {
136 debug.assert(end >= start);148 debug.assert(end >= start);
137149
138 const length = end - start;150 const length = end - start;
...@@ -148,8 +160,11 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {...@@ -148,8 +160,11 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {
148 return new_slice;160 return new_slice;
149 }161 }
150162
151 fn sliceCast(bytes: []u8, comptime NewInt: type, comptime new_endian: Endian, bit_offset: u3, old_len: usize) PackedIntSliceEndian(NewInt, new_endian) {163 /// Recasts a packed slice to a version with elements of type `NewInt` and endianness `new_endian`.
152 const new_int_bits = comptime std.meta.bitCount(NewInt);164 /// Slice will begin at `bit_offset` within `bytes` and the new length will be automatically
165 /// calculated from `old_len` using the sizes of the current integer type and `NewInt`.
166 pub fn sliceCast(bytes: []u8, comptime NewInt: type, comptime new_endian: Endian, bit_offset: u3, old_len: usize) PackedIntSliceEndian(NewInt, new_endian) {
167 const new_int_bits = @bitSizeOf(NewInt);
153 const New = PackedIntSliceEndian(NewInt, new_endian);168 const New = PackedIntSliceEndian(NewInt, new_endian);
154169
155 const total_bits = (old_len * int_bits);170 const total_bits = (old_len * int_bits);
...@@ -165,18 +180,21 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {...@@ -165,18 +180,21 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {
165 };180 };
166}181}
167182
168///Creates a bit-packed array of integers of type Int. Bits183/// Creates a bit-packed array of `Int`. Non-byte-multiple integers
169/// are packed using native endianess and without storing any meta184/// will take up less memory in PackedIntArray than in a normal array.
170/// data. PackedIntArray(i3, 8) will occupy exactly 3 bytes of memory.185/// Elements are packed using native endianess and without storing any
186/// meta data. PackedArray(i3, 8) will occupy exactly 3 bytes
187/// of memory.
171pub fn PackedIntArray(comptime Int: type, comptime int_count: usize) type {188pub fn PackedIntArray(comptime Int: type, comptime int_count: usize) type {
172 return PackedIntArrayEndian(Int, native_endian, int_count);189 return PackedIntArrayEndian(Int, native_endian, int_count);
173}190}
174191
175///Creates a bit-packed array of integers of type Int. Bits192/// Creates a bit-packed array of `Int` with bit order specified by `endian`.
176/// are packed using specified endianess and without storing any meta193/// Non-byte-multiple integers will take up less memory in PackedIntArrayEndian
177/// data.194/// than in a normal array. Elements are packed without storing any meta data.
195/// PackedIntArrayEndian(i3, 8) will occupy exactly 3 bytes of memory.
178pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: Endian, comptime int_count: usize) type {196pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: Endian, comptime int_count: usize) type {
179 const int_bits = comptime std.meta.bitCount(Int);197 const int_bits = @bitSizeOf(Int);
180 const total_bits = int_bits * int_count;198 const total_bits = int_bits * int_count;
181 const total_bytes = (total_bits + 7) / 8;199 const total_bytes = (total_bits + 7) / 8;
182200
...@@ -185,15 +203,12 @@ pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: Endian, comptim...@@ -185,15 +203,12 @@ pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: Endian, comptim
185 return struct {203 return struct {
186 const Self = @This();204 const Self = @This();
187205
206 /// The byte buffer containing the packed data.
188 bytes: [total_bytes]u8,207 bytes: [total_bytes]u8,
208 /// The number of elements in the packed array.
209 comptime len: usize = int_count,
189210
190 ///Returns the number of elements in the packed array211 /// Initialize a packed array using an unpacked array
191 pub fn len(self: Self) usize {
192 _ = self;
193 return int_count;
194 }
195
196 ///Initialize a packed array using an unpacked array
197 /// or, more likely, an array literal.212 /// or, more likely, an array literal.
198 pub fn init(ints: [int_count]Int) Self {213 pub fn init(ints: [int_count]Int) Self {
199 var self = @as(Self, undefined);214 var self = @as(Self, undefined);
...@@ -201,27 +216,27 @@ pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: Endian, comptim...@@ -201,27 +216,27 @@ pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: Endian, comptim
201 return self;216 return self;
202 }217 }
203218
204 ///Initialize all entries of a packed array to the same value219 /// Initialize all entries of a packed array to the same value.
205 pub fn initAllTo(int: Int) Self {220 pub fn initAllTo(int: Int) Self {
206 // TODO: use `var self = @as(Self, undefined);` https://github.com/ziglang/zig/issues/7635221 // TODO: use `var self = @as(Self, undefined);` https://github.com/ziglang/zig/issues/7635
207 var self = Self{ .bytes = [_]u8{0} ** total_bytes };222 var self = Self{ .bytes = [_]u8{0} ** total_bytes, .len = int_count };
208 self.setAll(int);223 self.setAll(int);
209 return self;224 return self;
210 }225 }
211226
212 ///Return the Int stored at index227 /// Return the integer stored at `index`.
213 pub fn get(self: Self, index: usize) Int {228 pub fn get(self: Self, index: usize) Int {
214 debug.assert(index < int_count);229 debug.assert(index < int_count);
215 return Io.get(&self.bytes, index, 0);230 return Io.get(&self.bytes, index, 0);
216 }231 }
217232
218 ///Copy int into the array at index233 ///Copy the value of `int` into the array at `index`.
219 pub fn set(self: *Self, index: usize, int: Int) void {234 pub fn set(self: *Self, index: usize, int: Int) void {
220 debug.assert(index < int_count);235 debug.assert(index < int_count);
221 return Io.set(&self.bytes, index, 0, int);236 return Io.set(&self.bytes, index, 0, int);
222 }237 }
223238
224 ///Set all entries of a packed array to the same value239 /// Set all entries of a packed array to the value of `int`.
225 pub fn setAll(self: *Self, int: Int) void {240 pub fn setAll(self: *Self, int: Int) void {
226 var i: usize = 0;241 var i: usize = 0;
227 while (i < int_count) : (i += 1) {242 while (i < int_count) : (i += 1) {
...@@ -229,105 +244,96 @@ pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: Endian, comptim...@@ -229,105 +244,96 @@ pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: Endian, comptim
229 }244 }
230 }245 }
231246
232 ///Create a PackedIntSlice of the array from given start to given end247 /// Create a PackedIntSlice of the array from `start` to `end`.
233 pub fn slice(self: *Self, start: usize, end: usize) PackedIntSliceEndian(Int, endian) {248 pub fn slice(self: *Self, start: usize, end: usize) PackedIntSliceEndian(Int, endian) {
234 debug.assert(start < int_count);249 debug.assert(start < int_count);
235 debug.assert(end <= int_count);250 debug.assert(end <= int_count);
236 return Io.slice(&self.bytes, 0, start, end);251 return Io.slice(&self.bytes, 0, start, end);
237 }252 }
238253
239 ///Create a PackedIntSlice of the array using NewInt as the bit width integer.254 /// Create a PackedIntSlice of the array using `NewInt` as the integer type.
240 /// NewInt's bit width must fit evenly within the array's Int's total bits.255 /// `NewInt`'s bit width must fit evenly within the array's `Int`'s total bits.
241 pub fn sliceCast(self: *Self, comptime NewInt: type) PackedIntSlice(NewInt) {256 pub fn sliceCast(self: *Self, comptime NewInt: type) PackedIntSlice(NewInt) {
242 return self.sliceCastEndian(NewInt, endian);257 return self.sliceCastEndian(NewInt, endian);
243 }258 }
244259
245 ///Create a PackedIntSlice of the array using NewInt as the bit width integer260 /// Create a PackedIntSliceEndian of the array using `NewInt` as the integer type
246 /// and new_endian as the new endianess. NewInt's bit width must fit evenly within261 /// and `new_endian` as the new endianess. `NewInt`'s bit width must fit evenly
247 /// the array's Int's total bits.262 /// within the array's `Int`'s total bits.
248 pub fn sliceCastEndian(self: *Self, comptime NewInt: type, comptime new_endian: Endian) PackedIntSliceEndian(NewInt, new_endian) {263 pub fn sliceCastEndian(self: *Self, comptime NewInt: type, comptime new_endian: Endian) PackedIntSliceEndian(NewInt, new_endian) {
249 return Io.sliceCast(&self.bytes, NewInt, new_endian, 0, int_count);264 return Io.sliceCast(&self.bytes, NewInt, new_endian, 0, int_count);
250 }265 }
251 };266 };
252}267}
253268
254///Uses a slice as a bit-packed block of int_count integers of type Int.269/// A type representing a sub range of a PackedIntArray.
255/// Bits are packed using native endianess and without storing any meta
256/// data.
257pub fn PackedIntSlice(comptime Int: type) type {270pub fn PackedIntSlice(comptime Int: type) type {
258 return PackedIntSliceEndian(Int, native_endian);271 return PackedIntSliceEndian(Int, native_endian);
259}272}
260273
261///Uses a slice as a bit-packed block of int_count integers of type Int.274/// A type representing a sub range of a PackedIntArrayEndian.
262/// Bits are packed using specified endianess and without storing any meta
263/// data.
264pub fn PackedIntSliceEndian(comptime Int: type, comptime endian: Endian) type {275pub fn PackedIntSliceEndian(comptime Int: type, comptime endian: Endian) type {
265 const int_bits = comptime std.meta.bitCount(Int);276 const int_bits = @bitSizeOf(Int);
266 const Io = PackedIntIo(Int, endian);277 const Io = PackedIntIo(Int, endian);
267278
268 return struct {279 return struct {
269 const Self = @This();280 const Self = @This();
270281
271 bytes: []u8,282 bytes: []u8,
272 int_count: usize,
273 bit_offset: u3,283 bit_offset: u3,
284 len: usize,
274285
275 ///Returns the number of elements in the packed slice286 /// Calculates the number of bytes required to store a desired count
276 pub fn len(self: Self) usize {287 /// of `Int`s.
277 return self.int_count;
278 }
279
280 ///Calculates the number of bytes required to store a desired count
281 /// of Ints
282 pub fn bytesRequired(int_count: usize) usize {288 pub fn bytesRequired(int_count: usize) usize {
283 const total_bits = int_bits * int_count;289 const total_bits = int_bits * int_count;
284 const total_bytes = (total_bits + 7) / 8;290 const total_bytes = (total_bits + 7) / 8;
285 return total_bytes;291 return total_bytes;
286 }292 }
287293
288 ///Initialize a packed slice using the memory at bytes, with int_count294 /// Initialize a packed slice using the memory at `bytes`, with `int_count`
289 /// elements. bytes must be large enough to accomodate the requested295 /// elements. `bytes` must be large enough to accomodate the requested
290 /// count.296 /// count.
291 pub fn init(bytes: []u8, int_count: usize) Self {297 pub fn init(bytes: []u8, int_count: usize) Self {
292 debug.assert(bytes.len >= bytesRequired(int_count));298 debug.assert(bytes.len >= bytesRequired(int_count));
293299
294 return Self{300 return Self{
295 .bytes = bytes,301 .bytes = bytes,
296 .int_count = int_count,302 .len = int_count,
297 .bit_offset = 0,303 .bit_offset = 0,
298 };304 };
299 }305 }
300306
301 ///Return the Int stored at index307 /// Return the integer stored at `index`.
302 pub fn get(self: Self, index: usize) Int {308 pub fn get(self: Self, index: usize) Int {
303 debug.assert(index < self.int_count);309 debug.assert(index < self.len);
304 return Io.get(self.bytes, index, self.bit_offset);310 return Io.get(self.bytes, index, self.bit_offset);
305 }311 }
306312
307 ///Copy int into the array at index313 /// Copy `int` into the slice at `index`.
308 pub fn set(self: *Self, index: usize, int: Int) void {314 pub fn set(self: *Self, index: usize, int: Int) void {
309 debug.assert(index < self.int_count);315 debug.assert(index < self.len);
310 return Io.set(self.bytes, index, self.bit_offset, int);316 return Io.set(self.bytes, index, self.bit_offset, int);
311 }317 }
312318
313 ///Create a PackedIntSlice of this slice from given start to given end319 /// Create a PackedIntSlice of this slice from `start` to `end`.
314 pub fn slice(self: Self, start: usize, end: usize) PackedIntSliceEndian(Int, endian) {320 pub fn slice(self: Self, start: usize, end: usize) PackedIntSliceEndian(Int, endian) {
315 debug.assert(start < self.int_count);321 debug.assert(start < self.len);
316 debug.assert(end <= self.int_count);322 debug.assert(end <= self.len);
317 return Io.slice(self.bytes, self.bit_offset, start, end);323 return Io.slice(self.bytes, self.bit_offset, start, end);
318 }324 }
319325
320 ///Create a PackedIntSlice of this slice using NewInt as the bit width integer.326 /// Create a PackedIntSlice of the sclice using `NewInt` as the integer type.
321 /// NewInt's bit width must fit evenly within this slice's Int's total bits.327 /// `NewInt`'s bit width must fit evenly within the slice's `Int`'s total bits.
322 pub fn sliceCast(self: Self, comptime NewInt: type) PackedIntSliceEndian(NewInt, endian) {328 pub fn sliceCast(self: Self, comptime NewInt: type) PackedIntSliceEndian(NewInt, endian) {
323 return self.sliceCastEndian(NewInt, endian);329 return self.sliceCastEndian(NewInt, endian);
324 }330 }
325331
326 ///Create a PackedIntSlice of this slice using NewInt as the bit width integer332 /// Create a PackedIntSliceEndian of the slice using `NewInt` as the integer type
327 /// and new_endian as the new endianess. NewInt's bit width must fit evenly within333 /// and `new_endian` as the new endianess. `NewInt`'s bit width must fit evenly
328 /// this slice's Int's total bits.334 /// within the slice's `Int`'s total bits.
329 pub fn sliceCastEndian(self: Self, comptime NewInt: type, comptime new_endian: Endian) PackedIntSliceEndian(NewInt, new_endian) {335 pub fn sliceCastEndian(self: Self, comptime NewInt: type, comptime new_endian: Endian) PackedIntSliceEndian(NewInt, new_endian) {
330 return Io.sliceCast(self.bytes, NewInt, new_endian, self.bit_offset, self.int_count);336 return Io.sliceCast(self.bytes, NewInt, new_endian, self.bit_offset, self.len);
331 }337 }
332 };338 };
333}339}
...@@ -358,7 +364,7 @@ test "PackedIntArray" {...@@ -358,7 +364,7 @@ test "PackedIntArray" {
358 //write values, counting up364 //write values, counting up
359 var i = @as(usize, 0);365 var i = @as(usize, 0);
360 var count = @as(I, 0);366 var count = @as(I, 0);
361 while (i < data.len()) : (i += 1) {367 while (i < data.len) : (i += 1) {
362 data.set(i, count);368 data.set(i, count);
363 if (bits > 0) count +%= 1;369 if (bits > 0) count +%= 1;
364 }370 }
...@@ -366,7 +372,7 @@ test "PackedIntArray" {...@@ -366,7 +372,7 @@ test "PackedIntArray" {
366 //read and verify values372 //read and verify values
367 i = 0;373 i = 0;
368 count = 0;374 count = 0;
369 while (i < data.len()) : (i += 1) {375 while (i < data.len) : (i += 1) {
370 const val = data.get(i);376 const val = data.get(i);
371 try testing.expect(val == count);377 try testing.expect(val == count);
372 if (bits > 0) count +%= 1;378 if (bits > 0) count +%= 1;
...@@ -383,19 +389,17 @@ test "PackedIntIo" {...@@ -383,19 +389,17 @@ test "PackedIntIo" {
383}389}
384390
385test "PackedIntArray init" {391test "PackedIntArray init" {
386 if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
387 const PackedArray = PackedIntArray(u3, 8);392 const PackedArray = PackedIntArray(u3, 8);
388 var packed_array = PackedArray.init([_]u3{ 0, 1, 2, 3, 4, 5, 6, 7 });393 var packed_array = PackedArray.init([_]u3{ 0, 1, 2, 3, 4, 5, 6, 7 });
389 var i = @as(usize, 0);394 var i = @as(usize, 0);
390 while (i < packed_array.len()) : (i += 1) try testing.expectEqual(@intCast(u3, i), packed_array.get(i));395 while (i < packed_array.len) : (i += 1) try testing.expectEqual(@intCast(u3, i), packed_array.get(i));
391}396}
392397
393test "PackedIntArray initAllTo" {398test "PackedIntArray initAllTo" {
394 if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
395 const PackedArray = PackedIntArray(u3, 8);399 const PackedArray = PackedIntArray(u3, 8);
396 var packed_array = PackedArray.initAllTo(5);400 var packed_array = PackedArray.initAllTo(5);
397 var i = @as(usize, 0);401 var i = @as(usize, 0);
398 while (i < packed_array.len()) : (i += 1) try testing.expectEqual(@as(u3, 5), packed_array.get(i));402 while (i < packed_array.len) : (i += 1) try testing.expectEqual(@as(u3, 5), packed_array.get(i));
399}403}
400404
401test "PackedIntSlice" {405test "PackedIntSlice" {
...@@ -423,7 +427,7 @@ test "PackedIntSlice" {...@@ -423,7 +427,7 @@ test "PackedIntSlice" {
423 //write values, counting up427 //write values, counting up
424 var i = @as(usize, 0);428 var i = @as(usize, 0);
425 var count = @as(I, 0);429 var count = @as(I, 0);
426 while (i < data.len()) : (i += 1) {430 while (i < data.len) : (i += 1) {
427 data.set(i, count);431 data.set(i, count);
428 if (bits > 0) count +%= 1;432 if (bits > 0) count +%= 1;
429 }433 }
...@@ -431,7 +435,7 @@ test "PackedIntSlice" {...@@ -431,7 +435,7 @@ test "PackedIntSlice" {
431 //read and verify values435 //read and verify values
432 i = 0;436 i = 0;
433 count = 0;437 count = 0;
434 while (i < data.len()) : (i += 1) {438 while (i < data.len) : (i += 1) {
435 const val = data.get(i);439 const val = data.get(i);
436 try testing.expect(val == count);440 try testing.expect(val == count);
437 if (bits > 0) count +%= 1;441 if (bits > 0) count +%= 1;
...@@ -454,14 +458,14 @@ test "PackedIntSlice of PackedInt(Array/Slice)" {...@@ -454,14 +458,14 @@ test "PackedIntSlice of PackedInt(Array/Slice)" {
454 const limit = (1 << bits);458 const limit = (1 << bits);
455459
456 var i = @as(usize, 0);460 var i = @as(usize, 0);
457 while (i < packed_array.len()) : (i += 1) {461 while (i < packed_array.len) : (i += 1) {
458 packed_array.set(i, @intCast(Int, i % limit));462 packed_array.set(i, @intCast(Int, i % limit));
459 }463 }
460464
461 //slice of array465 //slice of array
462 var packed_slice = packed_array.slice(2, 5);466 var packed_slice = packed_array.slice(2, 5);
463 try testing.expect(packed_slice.len() == 3);467 try testing.expect(packed_slice.len == 3);
464 const ps_bit_count = (bits * packed_slice.len()) + packed_slice.bit_offset;468 const ps_bit_count = (bits * packed_slice.len) + packed_slice.bit_offset;
465 const ps_expected_bytes = (ps_bit_count + 7) / 8;469 const ps_expected_bytes = (ps_bit_count + 7) / 8;
466 try testing.expect(packed_slice.bytes.len == ps_expected_bytes);470 try testing.expect(packed_slice.bytes.len == ps_expected_bytes);
467 try testing.expect(packed_slice.get(0) == 2 % limit);471 try testing.expect(packed_slice.get(0) == 2 % limit);
...@@ -475,8 +479,8 @@ test "PackedIntSlice of PackedInt(Array/Slice)" {...@@ -475,8 +479,8 @@ test "PackedIntSlice of PackedInt(Array/Slice)" {
475479
476 //slice of a slice480 //slice of a slice
477 const packed_slice_two = packed_slice.slice(0, 3);481 const packed_slice_two = packed_slice.slice(0, 3);
478 try testing.expect(packed_slice_two.len() == 3);482 try testing.expect(packed_slice_two.len == 3);
479 const ps2_bit_count = (bits * packed_slice_two.len()) + packed_slice_two.bit_offset;483 const ps2_bit_count = (bits * packed_slice_two.len) + packed_slice_two.bit_offset;
480 const ps2_expected_bytes = (ps2_bit_count + 7) / 8;484 const ps2_expected_bytes = (ps2_bit_count + 7) / 8;
481 try testing.expect(packed_slice_two.bytes.len == ps2_expected_bytes);485 try testing.expect(packed_slice_two.bytes.len == ps2_expected_bytes);
482 try testing.expect(packed_slice_two.get(1) == 7 % limit);486 try testing.expect(packed_slice_two.get(1) == 7 % limit);
...@@ -484,21 +488,21 @@ test "PackedIntSlice of PackedInt(Array/Slice)" {...@@ -484,21 +488,21 @@ test "PackedIntSlice of PackedInt(Array/Slice)" {
484488
485 //size one case489 //size one case
486 const packed_slice_three = packed_slice_two.slice(1, 2);490 const packed_slice_three = packed_slice_two.slice(1, 2);
487 try testing.expect(packed_slice_three.len() == 1);491 try testing.expect(packed_slice_three.len == 1);
488 const ps3_bit_count = (bits * packed_slice_three.len()) + packed_slice_three.bit_offset;492 const ps3_bit_count = (bits * packed_slice_three.len) + packed_slice_three.bit_offset;
489 const ps3_expected_bytes = (ps3_bit_count + 7) / 8;493 const ps3_expected_bytes = (ps3_bit_count + 7) / 8;
490 try testing.expect(packed_slice_three.bytes.len == ps3_expected_bytes);494 try testing.expect(packed_slice_three.bytes.len == ps3_expected_bytes);
491 try testing.expect(packed_slice_three.get(0) == 7 % limit);495 try testing.expect(packed_slice_three.get(0) == 7 % limit);
492496
493 //empty slice case497 //empty slice case
494 const packed_slice_empty = packed_slice.slice(0, 0);498 const packed_slice_empty = packed_slice.slice(0, 0);
495 try testing.expect(packed_slice_empty.len() == 0);499 try testing.expect(packed_slice_empty.len == 0);
496 try testing.expect(packed_slice_empty.bytes.len == 0);500 try testing.expect(packed_slice_empty.bytes.len == 0);
497501
498 //slicing at byte boundaries502 //slicing at byte boundaries
499 const packed_slice_edge = packed_array.slice(8, 16);503 const packed_slice_edge = packed_array.slice(8, 16);
500 try testing.expect(packed_slice_edge.len() == 8);504 try testing.expect(packed_slice_edge.len == 8);
501 const pse_bit_count = (bits * packed_slice_edge.len()) + packed_slice_edge.bit_offset;505 const pse_bit_count = (bits * packed_slice_edge.len) + packed_slice_edge.bit_offset;
502 const pse_expected_bytes = (pse_bit_count + 7) / 8;506 const pse_expected_bytes = (pse_bit_count + 7) / 8;
503 try testing.expect(packed_slice_edge.bytes.len == pse_expected_bytes);507 try testing.expect(packed_slice_edge.bytes.len == pse_expected_bytes);
504 try testing.expect(packed_slice_edge.bit_offset == 0);508 try testing.expect(packed_slice_edge.bit_offset == 0);
...@@ -506,45 +510,40 @@ test "PackedIntSlice of PackedInt(Array/Slice)" {...@@ -506,45 +510,40 @@ test "PackedIntSlice of PackedInt(Array/Slice)" {
506}510}
507511
508test "PackedIntSlice accumulating bit offsets" {512test "PackedIntSlice accumulating bit offsets" {
509 if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
510 //bit_offset is u3, so standard debugging asserts should catch513 //bit_offset is u3, so standard debugging asserts should catch
511 // anything514 // anything
512 {515 {
513 const PackedArray = PackedIntArray(u3, 16);516 const PackedArray = PackedIntArray(u3, 16);
514 var packed_array = @as(PackedArray, undefined);517 var packed_array = @as(PackedArray, undefined);
515518
516 var packed_slice = packed_array.slice(0, packed_array.len());519 var packed_slice = packed_array.slice(0, packed_array.len);
517 var i = @as(usize, 0);520 var i = @as(usize, 0);
518 while (i < packed_array.len() - 1) : (i += 1) {521 while (i < packed_array.len - 1) : (i += 1) {
519 packed_slice = packed_slice.slice(1, packed_slice.len());522 packed_slice = packed_slice.slice(1, packed_slice.len);
520 }523 }
521 }524 }
522 {525 {
523 const PackedArray = PackedIntArray(u11, 88);526 const PackedArray = PackedIntArray(u11, 88);
524 var packed_array = @as(PackedArray, undefined);527 var packed_array = @as(PackedArray, undefined);
525528
526 var packed_slice = packed_array.slice(0, packed_array.len());529 var packed_slice = packed_array.slice(0, packed_array.len);
527 var i = @as(usize, 0);530 var i = @as(usize, 0);
528 while (i < packed_array.len() - 1) : (i += 1) {531 while (i < packed_array.len - 1) : (i += 1) {
529 packed_slice = packed_slice.slice(1, packed_slice.len());532 packed_slice = packed_slice.slice(1, packed_slice.len);
530 }533 }
531 }534 }
532}535}
533536
534//@NOTE: As I do not have a big endian system to test this on,
535// big endian values were not tested
536test "PackedInt(Array/Slice) sliceCast" {537test "PackedInt(Array/Slice) sliceCast" {
537 if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
538
539 const PackedArray = PackedIntArray(u1, 16);538 const PackedArray = PackedIntArray(u1, 16);
540 var packed_array = PackedArray.init([_]u1{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 });539 var packed_array = PackedArray.init([_]u1{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 });
541 const packed_slice_cast_2 = packed_array.sliceCast(u2);540 const packed_slice_cast_2 = packed_array.sliceCast(u2);
542 const packed_slice_cast_4 = packed_slice_cast_2.sliceCast(u4);541 const packed_slice_cast_4 = packed_slice_cast_2.sliceCast(u4);
543 var packed_slice_cast_9 = packed_array.slice(0, (packed_array.len() / 9) * 9).sliceCast(u9);542 var packed_slice_cast_9 = packed_array.slice(0, (packed_array.len / 9) * 9).sliceCast(u9);
544 const packed_slice_cast_3 = packed_slice_cast_9.sliceCast(u3);543 const packed_slice_cast_3 = packed_slice_cast_9.sliceCast(u3);
545544
546 var i = @as(usize, 0);545 var i = @as(usize, 0);
547 while (i < packed_slice_cast_2.len()) : (i += 1) {546 while (i < packed_slice_cast_2.len) : (i += 1) {
548 const val = switch (native_endian) {547 const val = switch (native_endian) {
549 .Big => 0b01,548 .Big => 0b01,
550 .Little => 0b10,549 .Little => 0b10,
...@@ -552,7 +551,7 @@ test "PackedInt(Array/Slice) sliceCast" {...@@ -552,7 +551,7 @@ test "PackedInt(Array/Slice) sliceCast" {
552 try testing.expect(packed_slice_cast_2.get(i) == val);551 try testing.expect(packed_slice_cast_2.get(i) == val);
553 }552 }
554 i = 0;553 i = 0;
555 while (i < packed_slice_cast_4.len()) : (i += 1) {554 while (i < packed_slice_cast_4.len) : (i += 1) {
556 const val = switch (native_endian) {555 const val = switch (native_endian) {
557 .Big => 0b0101,556 .Big => 0b0101,
558 .Little => 0b1010,557 .Little => 0b1010,
...@@ -560,13 +559,13 @@ test "PackedInt(Array/Slice) sliceCast" {...@@ -560,13 +559,13 @@ test "PackedInt(Array/Slice) sliceCast" {
560 try testing.expect(packed_slice_cast_4.get(i) == val);559 try testing.expect(packed_slice_cast_4.get(i) == val);
561 }560 }
562 i = 0;561 i = 0;
563 while (i < packed_slice_cast_9.len()) : (i += 1) {562 while (i < packed_slice_cast_9.len) : (i += 1) {
564 const val = 0b010101010;563 const val = 0b010101010;
565 try testing.expect(packed_slice_cast_9.get(i) == val);564 try testing.expect(packed_slice_cast_9.get(i) == val);
566 packed_slice_cast_9.set(i, 0b111000111);565 packed_slice_cast_9.set(i, 0b111000111);
567 }566 }
568 i = 0;567 i = 0;
569 while (i < packed_slice_cast_3.len()) : (i += 1) {568 while (i < packed_slice_cast_3.len) : (i += 1) {
570 const val = switch (native_endian) {569 const val = switch (native_endian) {
571 .Big => if (i % 2 == 0) @as(u3, 0b111) else @as(u3, 0b000),570 .Big => if (i % 2 == 0) @as(u3, 0b111) else @as(u3, 0b000),
572 .Little => if (i % 2 == 0) @as(u3, 0b111) else @as(u3, 0b000),571 .Little => if (i % 2 == 0) @as(u3, 0b111) else @as(u3, 0b000),
...@@ -576,8 +575,6 @@ test "PackedInt(Array/Slice) sliceCast" {...@@ -576,8 +575,6 @@ test "PackedInt(Array/Slice) sliceCast" {
576}575}
577576
578test "PackedInt(Array/Slice)Endian" {577test "PackedInt(Array/Slice)Endian" {
579 if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
580
581 {578 {
582 const PackedArrayBe = PackedIntArrayEndian(u4, .Big, 8);579 const PackedArrayBe = PackedIntArrayEndian(u4, .Big, 8);
583 var packed_array_be = PackedArrayBe.init([_]u4{ 0, 1, 2, 3, 4, 5, 6, 7 });580 var packed_array_be = PackedArrayBe.init([_]u4{ 0, 1, 2, 3, 4, 5, 6, 7 });
...@@ -585,20 +582,20 @@ test "PackedInt(Array/Slice)Endian" {...@@ -585,20 +582,20 @@ test "PackedInt(Array/Slice)Endian" {
585 try testing.expect(packed_array_be.bytes[1] == 0b00100011);582 try testing.expect(packed_array_be.bytes[1] == 0b00100011);
586583
587 var i = @as(usize, 0);584 var i = @as(usize, 0);
588 while (i < packed_array_be.len()) : (i += 1) {585 while (i < packed_array_be.len) : (i += 1) {
589 try testing.expect(packed_array_be.get(i) == i);586 try testing.expect(packed_array_be.get(i) == i);
590 }587 }
591588
592 var packed_slice_le = packed_array_be.sliceCastEndian(u4, .Little);589 var packed_slice_le = packed_array_be.sliceCastEndian(u4, .Little);
593 i = 0;590 i = 0;
594 while (i < packed_slice_le.len()) : (i += 1) {591 while (i < packed_slice_le.len) : (i += 1) {
595 const val = if (i % 2 == 0) i + 1 else i - 1;592 const val = if (i % 2 == 0) i + 1 else i - 1;
596 try testing.expect(packed_slice_le.get(i) == val);593 try testing.expect(packed_slice_le.get(i) == val);
597 }594 }
598595
599 var packed_slice_le_shift = packed_array_be.slice(1, 5).sliceCastEndian(u4, .Little);596 var packed_slice_le_shift = packed_array_be.slice(1, 5).sliceCastEndian(u4, .Little);
600 i = 0;597 i = 0;
601 while (i < packed_slice_le_shift.len()) : (i += 1) {598 while (i < packed_slice_le_shift.len) : (i += 1) {
602 const val = if (i % 2 == 0) i else i + 2;599 const val = if (i % 2 == 0) i else i + 2;
603 try testing.expect(packed_slice_le_shift.get(i) == val);600 try testing.expect(packed_slice_le_shift.get(i) == val);
604 }601 }
...@@ -614,7 +611,7 @@ test "PackedInt(Array/Slice)Endian" {...@@ -614,7 +611,7 @@ test "PackedInt(Array/Slice)Endian" {
614 try testing.expect(packed_array_be.bytes[4] == 0b00000000);611 try testing.expect(packed_array_be.bytes[4] == 0b00000000);
615612
616 var i = @as(usize, 0);613 var i = @as(usize, 0);
617 while (i < packed_array_be.len()) : (i += 1) {614 while (i < packed_array_be.len) : (i += 1) {
618 try testing.expect(packed_array_be.get(i) == i);615 try testing.expect(packed_array_be.get(i) == i);
619 }616 }
620617
...@@ -639,14 +636,12 @@ test "PackedInt(Array/Slice)Endian" {...@@ -639,14 +636,12 @@ test "PackedInt(Array/Slice)Endian" {
639//@NOTE: Need to manually update this list as more posix os's get636//@NOTE: Need to manually update this list as more posix os's get
640// added to DirectAllocator.637// added to DirectAllocator.
641638
642//These tests prove we aren't accidentally accessing memory past639// These tests prove we aren't accidentally accessing memory past
643// the end of the array/slice by placing it at the end of a page640// the end of the array/slice by placing it at the end of a page
644// and reading the last element. The assumption is that the page641// and reading the last element. The assumption is that the page
645// after this one is not mapped and will cause a segfault if we642// after this one is not mapped and will cause a segfault if we
646// don't account for the bounds.643// don't account for the bounds.
647test "PackedIntArray at end of available memory" {644test "PackedIntArray at end of available memory" {
648 if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
649
650 switch (builtin.target.os.tag) {645 switch (builtin.target.os.tag) {
651 .linux, .macos, .ios, .freebsd, .netbsd, .openbsd, .windows => {},646 .linux, .macos, .ios, .freebsd, .netbsd, .openbsd, .windows => {},
652 else => return,647 else => return,
...@@ -666,8 +661,6 @@ test "PackedIntArray at end of available memory" {...@@ -666,8 +661,6 @@ test "PackedIntArray at end of available memory" {
666}661}
667662
668test "PackedIntSlice at end of available memory" {663test "PackedIntSlice at end of available memory" {
669 if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
670
671 switch (builtin.target.os.tag) {664 switch (builtin.target.os.tag) {
672 .linux, .macos, .ios, .freebsd, .netbsd, .openbsd, .windows => {},665 .linux, .macos, .ios, .freebsd, .netbsd, .openbsd, .windows => {},
673 else => return,666 else => return,