authorgravatar for der.teufel.mail@gmail.comKrzysztof Wolicki <der.teufel.mail@gmail.com> 2024-10-12 12:00:09+02:00
committergravatar for der.teufel.mail@gmail.comKrzysztof Wolicki <der.teufel.mail@gmail.com> 2024-10-12 12:00:09+02:00
logce27ae1c68112dd5bc42356142a65a17278ac86c
tree6bda49b88c222beb23c90f4acc453a5658099118
parent0367f18cb9dc61090c27e29572a50810b9809822

Remove packed_int_array.zig from std


2 files changed, 0 insertions(+), 702 deletions(-)

lib/std/packed_int_array.zig deleted-697
...@@ -1,697 +0,0 @@
1//! A 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
5const std = @import("std");
6const builtin = @import("builtin");
7const debug = std.debug;
8const testing = std.testing;
9const native_endian = builtin.target.cpu.arch.endian();
10const Endian = std.builtin.Endian;
11
12/// Provides a set of functions for reading and writing packed integers from a
13/// slice of bytes.
14pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {
15 // The general technique employed here is to cast bytes in the array to a container
16 // integer (having bits % 8 == 0) large enough to contain the number of bits we want,
17 // then we can retrieve or store the new value with a relative minimum of masking
18 // and shifting. In this worst case, this means that we'll need an integer that's
19 // actually 1 byte larger than the minimum required to store the bits, because it
20 // is possible that the bits start at the end of the first byte, continue through
21 // zero or more, then end in the beginning of the last. But, if we try to access
22 // a value in the very last byte of memory with that integer size, that extra byte
23 // will be out of bounds. Depending on the circumstances of the memory, that might
24 // mean the OS fatally kills the program. Thus, we use a larger container (MaxIo)
25 // most of the time, but a smaller container (MinIo) when touching the last byte
26 // of the memory.
27 const int_bits = @bitSizeOf(Int);
28
29 // In the best case, this is the number of bytes we need to touch
30 // to read or write a value, as bits.
31 const min_io_bits = ((int_bits + 7) / 8) * 8;
32
33 // In the worst case, this is the number of bytes we need to touch
34 // to read or write a value, as bits. To calculate for int_bits > 1,
35 // set aside 2 bits to touch the first and last bytes, then divide
36 // by 8 to see how many bytes can be filled up in between.
37 const max_io_bits = switch (int_bits) {
38 0 => 0,
39 1 => 8,
40 else => ((int_bits - 2) / 8 + 2) * 8,
41 };
42
43 // We bitcast the desired Int type to an unsigned version of itself
44 // to avoid issues with shifting signed ints.
45 const UnInt = std.meta.Int(.unsigned, int_bits);
46
47 // The maximum container int type
48 const MinIo = std.meta.Int(.unsigned, min_io_bits);
49
50 // The minimum container int type
51 const MaxIo = std.meta.Int(.unsigned, max_io_bits);
52
53 return struct {
54 /// Retrieves the integer at `index` from the packed data beginning at `bit_offset`
55 /// within `bytes`.
56 pub fn get(bytes: []const u8, index: usize, bit_offset: u7) Int {
57 if (int_bits == 0) return 0;
58
59 const bit_index = (index * int_bits) + bit_offset;
60 const max_end_byte = (bit_index + max_io_bits) / 8;
61
62 //using the larger container size will potentially read out of bounds
63 if (max_end_byte > bytes.len) return getBits(bytes, MinIo, bit_index);
64 return getBits(bytes, MaxIo, bit_index);
65 }
66
67 fn getBits(bytes: []const u8, comptime Container: type, bit_index: usize) Int {
68 const container_bits = @bitSizeOf(Container);
69
70 const start_byte = bit_index / 8;
71 const head_keep_bits = bit_index - (start_byte * 8);
72 const tail_keep_bits = container_bits - (int_bits + head_keep_bits);
73
74 //read bytes as container
75 const value_ptr: *align(1) const Container = @ptrCast(&bytes[start_byte]);
76 var value = value_ptr.*;
77
78 if (endian != native_endian) value = @byteSwap(value);
79
80 switch (endian) {
81 .big => {
82 value <<= @intCast(head_keep_bits);
83 value >>= @intCast(head_keep_bits);
84 value >>= @intCast(tail_keep_bits);
85 },
86 .little => {
87 value <<= @intCast(tail_keep_bits);
88 value >>= @intCast(tail_keep_bits);
89 value >>= @intCast(head_keep_bits);
90 },
91 }
92
93 return @bitCast(@as(UnInt, @truncate(value)));
94 }
95
96 /// Sets the integer at `index` to `val` within the packed data beginning
97 /// at `bit_offset` into `bytes`.
98 pub fn set(bytes: []u8, index: usize, bit_offset: u3, int: Int) void {
99 if (int_bits == 0) return;
100
101 const bit_index = (index * int_bits) + bit_offset;
102 const max_end_byte = (bit_index + max_io_bits) / 8;
103
104 //using the larger container size will potentially write out of bounds
105 if (max_end_byte > bytes.len) return setBits(bytes, MinIo, bit_index, int);
106 setBits(bytes, MaxIo, bit_index, int);
107 }
108
109 fn setBits(bytes: []u8, comptime Container: type, bit_index: usize, int: Int) void {
110 const container_bits = @bitSizeOf(Container);
111 const Shift = std.math.Log2Int(Container);
112
113 const start_byte = bit_index / 8;
114 const head_keep_bits = bit_index - (start_byte * 8);
115 const tail_keep_bits = container_bits - (int_bits + head_keep_bits);
116 const keep_shift: Shift = switch (endian) {
117 .big => @intCast(tail_keep_bits),
118 .little => @intCast(head_keep_bits),
119 };
120
121 //position the bits where they need to be in the container
122 const value = @as(Container, @intCast(@as(UnInt, @bitCast(int)))) << keep_shift;
123
124 //read existing bytes
125 const target_ptr: *align(1) Container = @ptrCast(&bytes[start_byte]);
126 var target = target_ptr.*;
127
128 if (endian != native_endian) target = @byteSwap(target);
129
130 //zero the bits we want to replace in the existing bytes
131 const inv_mask = @as(Container, @intCast(std.math.maxInt(UnInt))) << keep_shift;
132 const mask = ~inv_mask;
133 target &= mask;
134
135 //merge the new value
136 target |= value;
137
138 if (endian != native_endian) target = @byteSwap(target);
139
140 //save it back
141 target_ptr.* = target;
142 }
143
144 /// Provides a PackedIntSlice of the packed integers in `bytes` (which begins at `bit_offset`)
145 /// from the element specified by `start` to the element specified by `end`.
146 pub fn slice(bytes: []u8, bit_offset: u3, start: usize, end: usize) PackedIntSliceEndian(Int, endian) {
147 debug.assert(end >= start);
148
149 const length = end - start;
150 const bit_index = (start * int_bits) + bit_offset;
151 const start_byte = bit_index / 8;
152 const end_byte = (bit_index + (length * int_bits) + 7) / 8;
153 const new_bytes = bytes[start_byte..end_byte];
154
155 if (length == 0) return PackedIntSliceEndian(Int, endian).init(new_bytes[0..0], 0);
156
157 var new_slice = PackedIntSliceEndian(Int, endian).init(new_bytes, length);
158 new_slice.bit_offset = @intCast((bit_index - (start_byte * 8)));
159 return new_slice;
160 }
161
162 /// Recasts a packed slice to a version with elements of type `NewInt` and endianness `new_endian`.
163 /// Slice will begin at `bit_offset` within `bytes` and the new length will be automatically
164 /// calculated from `old_len` using the sizes of the current integer type and `NewInt`.
165 pub fn sliceCast(bytes: []u8, comptime NewInt: type, comptime new_endian: Endian, bit_offset: u3, old_len: usize) PackedIntSliceEndian(NewInt, new_endian) {
166 const new_int_bits = @bitSizeOf(NewInt);
167 const New = PackedIntSliceEndian(NewInt, new_endian);
168
169 const total_bits = (old_len * int_bits);
170 const new_int_count = total_bits / new_int_bits;
171
172 debug.assert(total_bits == new_int_count * new_int_bits);
173
174 var new = New.init(bytes, new_int_count);
175 new.bit_offset = bit_offset;
176
177 return new;
178 }
179 };
180}
181
182/// Creates a bit-packed array of `Int`. Non-byte-multiple integers
183/// will take up less memory in PackedIntArray than in a normal array.
184/// Elements are packed using native endianness and without storing any
185/// meta data. PackedArray(i3, 8) will occupy exactly 3 bytes
186/// of memory.
187pub fn PackedIntArray(comptime Int: type, comptime int_count: usize) type {
188 return PackedIntArrayEndian(Int, native_endian, int_count);
189}
190
191/// Creates a bit-packed array of `Int` with bit order specified by `endian`.
192/// Non-byte-multiple integers will take up less memory in PackedIntArrayEndian
193/// than in a normal array. Elements are packed without storing any meta data.
194/// PackedIntArrayEndian(i3, 8) will occupy exactly 3 bytes of memory.
195pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: Endian, comptime int_count: usize) type {
196 const int_bits = @bitSizeOf(Int);
197 const total_bits = int_bits * int_count;
198 const total_bytes = (total_bits + 7) / 8;
199
200 const Io = PackedIntIo(Int, endian);
201
202 return struct {
203 const Self = @This();
204
205 /// The byte buffer containing the packed data.
206 bytes: [total_bytes]u8,
207 /// The number of elements in the packed array.
208 comptime len: usize = int_count,
209
210 /// The integer type of the packed array.
211 pub const Child = Int;
212
213 /// Initialize a packed array using an unpacked array
214 /// or, more likely, an array literal.
215 pub fn init(ints: [int_count]Int) Self {
216 var self: Self = undefined;
217 for (ints, 0..) |int, i| self.set(i, int);
218 return self;
219 }
220
221 /// Initialize all entries of a packed array to the same value.
222 pub fn initAllTo(int: Int) Self {
223 var self: Self = undefined;
224 self.setAll(int);
225 return self;
226 }
227
228 /// Return the integer stored at `index`.
229 pub fn get(self: Self, index: usize) Int {
230 debug.assert(index < int_count);
231 return Io.get(&self.bytes, index, 0);
232 }
233
234 /// Copy the value of `int` into the array at `index`.
235 pub fn set(self: *Self, index: usize, int: Int) void {
236 debug.assert(index < int_count);
237 return Io.set(&self.bytes, index, 0, int);
238 }
239
240 /// Set all entries of a packed array to the value of `int`.
241 pub fn setAll(self: *Self, int: Int) void {
242 var i: usize = 0;
243 while (i < int_count) : (i += 1) {
244 self.set(i, int);
245 }
246 }
247
248 /// Create a PackedIntSlice of the array from `start` to `end`.
249 pub fn slice(self: *Self, start: usize, end: usize) PackedIntSliceEndian(Int, endian) {
250 debug.assert(start < int_count);
251 debug.assert(end <= int_count);
252 return Io.slice(&self.bytes, 0, start, end);
253 }
254
255 /// Create a PackedIntSlice of the array using `NewInt` as the integer type.
256 /// `NewInt`'s bit width must fit evenly within the array's `Int`'s total bits.
257 pub fn sliceCast(self: *Self, comptime NewInt: type) PackedIntSlice(NewInt) {
258 return self.sliceCastEndian(NewInt, endian);
259 }
260
261 /// Create a PackedIntSliceEndian of the array using `NewInt` as the integer type
262 /// and `new_endian` as the new endianness. `NewInt`'s bit width must fit evenly
263 /// within the array's `Int`'s total bits.
264 pub fn sliceCastEndian(self: *Self, comptime NewInt: type, comptime new_endian: Endian) PackedIntSliceEndian(NewInt, new_endian) {
265 return Io.sliceCast(&self.bytes, NewInt, new_endian, 0, int_count);
266 }
267 };
268}
269
270/// A type representing a sub range of a PackedIntArray.
271pub fn PackedIntSlice(comptime Int: type) type {
272 return PackedIntSliceEndian(Int, native_endian);
273}
274
275/// A type representing a sub range of a PackedIntArrayEndian.
276pub fn PackedIntSliceEndian(comptime Int: type, comptime endian: Endian) type {
277 const int_bits = @bitSizeOf(Int);
278 const Io = PackedIntIo(Int, endian);
279
280 return struct {
281 const Self = @This();
282
283 bytes: []u8,
284 bit_offset: u3,
285 len: usize,
286
287 /// The integer type of the packed slice.
288 pub const Child = Int;
289
290 /// Calculates the number of bytes required to store a desired count
291 /// of `Int`s.
292 pub fn bytesRequired(int_count: usize) usize {
293 const total_bits = int_bits * int_count;
294 const total_bytes = (total_bits + 7) / 8;
295 return total_bytes;
296 }
297
298 /// Initialize a packed slice using the memory at `bytes`, with `int_count`
299 /// elements. `bytes` must be large enough to accommodate the requested
300 /// count.
301 pub fn init(bytes: []u8, int_count: usize) Self {
302 debug.assert(bytes.len >= bytesRequired(int_count));
303
304 return Self{
305 .bytes = bytes,
306 .len = int_count,
307 .bit_offset = 0,
308 };
309 }
310
311 /// Return the integer stored at `index`.
312 pub fn get(self: Self, index: usize) Int {
313 debug.assert(index < self.len);
314 return Io.get(self.bytes, index, self.bit_offset);
315 }
316
317 /// Copy `int` into the slice at `index`.
318 pub fn set(self: *Self, index: usize, int: Int) void {
319 debug.assert(index < self.len);
320 return Io.set(self.bytes, index, self.bit_offset, int);
321 }
322
323 /// Create a PackedIntSlice of this slice from `start` to `end`.
324 pub fn slice(self: Self, start: usize, end: usize) PackedIntSliceEndian(Int, endian) {
325 debug.assert(start < self.len);
326 debug.assert(end <= self.len);
327 return Io.slice(self.bytes, self.bit_offset, start, end);
328 }
329
330 /// Create a PackedIntSlice of the sclice using `NewInt` as the integer type.
331 /// `NewInt`'s bit width must fit evenly within the slice's `Int`'s total bits.
332 pub fn sliceCast(self: Self, comptime NewInt: type) PackedIntSliceEndian(NewInt, endian) {
333 return self.sliceCastEndian(NewInt, endian);
334 }
335
336 /// Create a PackedIntSliceEndian of the slice using `NewInt` as the integer type
337 /// and `new_endian` as the new endianness. `NewInt`'s bit width must fit evenly
338 /// within the slice's `Int`'s total bits.
339 pub fn sliceCastEndian(self: Self, comptime NewInt: type, comptime new_endian: Endian) PackedIntSliceEndian(NewInt, new_endian) {
340 return Io.sliceCast(self.bytes, NewInt, new_endian, self.bit_offset, self.len);
341 }
342 };
343}
344
345test "PackedIntArray" {
346 // TODO @setEvalBranchQuota generates panics in wasm32. Investigate.
347 if (builtin.target.cpu.arch == .wasm32) return error.SkipZigTest;
348
349 // TODO: enable this test
350 if (true) return error.SkipZigTest;
351
352 @setEvalBranchQuota(10000);
353 const max_bits = 256;
354 const int_count = 19;
355
356 comptime var bits = 0;
357 inline while (bits <= max_bits) : (bits += 1) {
358 //alternate unsigned and signed
359 const sign: std.builtin.Signedness = if (bits % 2 == 0) .signed else .unsigned;
360 const I = std.meta.Int(sign, bits);
361
362 const PackedArray = PackedIntArray(I, int_count);
363 const expected_bytes = ((bits * int_count) + 7) / 8;
364 try testing.expect(@sizeOf(PackedArray) == expected_bytes);
365
366 var data: PackedArray = undefined;
367
368 //write values, counting up
369 var i: usize = 0;
370 var count: I = 0;
371 while (i < data.len) : (i += 1) {
372 data.set(i, count);
373 if (bits > 0) count +%= 1;
374 }
375
376 //read and verify values
377 i = 0;
378 count = 0;
379 while (i < data.len) : (i += 1) {
380 const val = data.get(i);
381 try testing.expect(val == count);
382 if (bits > 0) count +%= 1;
383 }
384 }
385}
386
387test "PackedIntIo" {
388 const bytes = [_]u8{ 0b01101_000, 0b01011_110, 0b00011_101 };
389 try testing.expectEqual(@as(u15, 0x2bcd), PackedIntIo(u15, .little).get(&bytes, 0, 3));
390 try testing.expectEqual(@as(u16, 0xabcd), PackedIntIo(u16, .little).get(&bytes, 0, 3));
391 try testing.expectEqual(@as(u17, 0x1abcd), PackedIntIo(u17, .little).get(&bytes, 0, 3));
392 try testing.expectEqual(@as(u18, 0x3abcd), PackedIntIo(u18, .little).get(&bytes, 0, 3));
393}
394
395test "PackedIntArray init" {
396 const S = struct {
397 fn doTheTest() !void {
398 const PackedArray = PackedIntArray(u3, 8);
399 var packed_array = PackedArray.init([_]u3{ 0, 1, 2, 3, 4, 5, 6, 7 });
400 var i: usize = 0;
401 while (i < packed_array.len) : (i += 1) try testing.expectEqual(@as(u3, @intCast(i)), packed_array.get(i));
402 }
403 };
404 try S.doTheTest();
405 try comptime S.doTheTest();
406}
407
408test "PackedIntArray initAllTo" {
409 const S = struct {
410 fn doTheTest() !void {
411 const PackedArray = PackedIntArray(u3, 8);
412 var packed_array = PackedArray.initAllTo(5);
413 var i: usize = 0;
414 while (i < packed_array.len) : (i += 1) try testing.expectEqual(@as(u3, 5), packed_array.get(i));
415 }
416 };
417 try S.doTheTest();
418 try comptime S.doTheTest();
419}
420
421test "PackedIntSlice" {
422 // TODO @setEvalBranchQuota generates panics in wasm32. Investigate.
423 if (builtin.target.cpu.arch == .wasm32) return error.SkipZigTest;
424
425 // TODO enable this test
426 if (true) return error.SkipZigTest;
427
428 @setEvalBranchQuota(10000);
429 const max_bits = 256;
430 const int_count = 19;
431 const total_bits = max_bits * int_count;
432 const total_bytes = (total_bits + 7) / 8;
433
434 var buffer: [total_bytes]u8 = undefined;
435
436 comptime var bits = 0;
437 inline while (bits <= max_bits) : (bits += 1) {
438 //alternate unsigned and signed
439 const sign: std.builtin.Signedness = if (bits % 2 == 0) .signed else .unsigned;
440 const I = std.meta.Int(sign, bits);
441 const P = PackedIntSlice(I);
442
443 var data = P.init(&buffer, int_count);
444
445 //write values, counting up
446 var i: usize = 0;
447 var count: I = 0;
448 while (i < data.len) : (i += 1) {
449 data.set(i, count);
450 if (bits > 0) count +%= 1;
451 }
452
453 //read and verify values
454 i = 0;
455 count = 0;
456 while (i < data.len) : (i += 1) {
457 const val = data.get(i);
458 try testing.expect(val == count);
459 if (bits > 0) count +%= 1;
460 }
461 }
462}
463
464test "PackedIntSlice of PackedInt(Array/Slice)" {
465 // TODO enable this test
466 if (true) return error.SkipZigTest;
467
468 const max_bits = 16;
469 const int_count = 19;
470
471 comptime var bits = 0;
472 inline while (bits <= max_bits) : (bits += 1) {
473 const Int = std.meta.Int(.unsigned, bits);
474
475 const PackedArray = PackedIntArray(Int, int_count);
476 var packed_array: PackedArray = undefined;
477
478 const limit = (1 << bits);
479
480 var i: usize = 0;
481 while (i < packed_array.len) : (i += 1) {
482 packed_array.set(i, @intCast(i % limit));
483 }
484
485 //slice of array
486 var packed_slice = packed_array.slice(2, 5);
487 try testing.expect(packed_slice.len == 3);
488 const ps_bit_count = (bits * packed_slice.len) + packed_slice.bit_offset;
489 const ps_expected_bytes = (ps_bit_count + 7) / 8;
490 try testing.expect(packed_slice.bytes.len == ps_expected_bytes);
491 try testing.expect(packed_slice.get(0) == 2 % limit);
492 try testing.expect(packed_slice.get(1) == 3 % limit);
493 try testing.expect(packed_slice.get(2) == 4 % limit);
494 packed_slice.set(1, 7 % limit);
495 try testing.expect(packed_slice.get(1) == 7 % limit);
496
497 //write through slice
498 try testing.expect(packed_array.get(3) == 7 % limit);
499
500 //slice of a slice
501 const packed_slice_two = packed_slice.slice(0, 3);
502 try testing.expect(packed_slice_two.len == 3);
503 const ps2_bit_count = (bits * packed_slice_two.len) + packed_slice_two.bit_offset;
504 const ps2_expected_bytes = (ps2_bit_count + 7) / 8;
505 try testing.expect(packed_slice_two.bytes.len == ps2_expected_bytes);
506 try testing.expect(packed_slice_two.get(1) == 7 % limit);
507 try testing.expect(packed_slice_two.get(2) == 4 % limit);
508
509 //size one case
510 const packed_slice_three = packed_slice_two.slice(1, 2);
511 try testing.expect(packed_slice_three.len == 1);
512 const ps3_bit_count = (bits * packed_slice_three.len) + packed_slice_three.bit_offset;
513 const ps3_expected_bytes = (ps3_bit_count + 7) / 8;
514 try testing.expect(packed_slice_three.bytes.len == ps3_expected_bytes);
515 try testing.expect(packed_slice_three.get(0) == 7 % limit);
516
517 //empty slice case
518 const packed_slice_empty = packed_slice.slice(0, 0);
519 try testing.expect(packed_slice_empty.len == 0);
520 try testing.expect(packed_slice_empty.bytes.len == 0);
521
522 //slicing at byte boundaries
523 const packed_slice_edge = packed_array.slice(8, 16);
524 try testing.expect(packed_slice_edge.len == 8);
525 const pse_bit_count = (bits * packed_slice_edge.len) + packed_slice_edge.bit_offset;
526 const pse_expected_bytes = (pse_bit_count + 7) / 8;
527 try testing.expect(packed_slice_edge.bytes.len == pse_expected_bytes);
528 try testing.expect(packed_slice_edge.bit_offset == 0);
529 }
530}
531
532test "PackedIntSlice accumulating bit offsets" {
533 //bit_offset is u3, so standard debugging asserts should catch
534 // anything
535 {
536 const PackedArray = PackedIntArray(u3, 16);
537 var packed_array: PackedArray = undefined;
538
539 var packed_slice = packed_array.slice(0, packed_array.len);
540 var i: usize = 0;
541 while (i < packed_array.len - 1) : (i += 1) {
542 packed_slice = packed_slice.slice(1, packed_slice.len);
543 }
544 }
545 {
546 const PackedArray = PackedIntArray(u11, 88);
547 var packed_array: PackedArray = undefined;
548
549 var packed_slice = packed_array.slice(0, packed_array.len);
550 var i: usize = 0;
551 while (i < packed_array.len - 1) : (i += 1) {
552 packed_slice = packed_slice.slice(1, packed_slice.len);
553 }
554 }
555}
556
557test "PackedInt(Array/Slice) sliceCast" {
558 const PackedArray = PackedIntArray(u1, 16);
559 var packed_array = PackedArray.init([_]u1{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 });
560 const packed_slice_cast_2 = packed_array.sliceCast(u2);
561 const packed_slice_cast_4 = packed_slice_cast_2.sliceCast(u4);
562 var packed_slice_cast_9 = packed_array.slice(0, (packed_array.len / 9) * 9).sliceCast(u9);
563 const packed_slice_cast_3 = packed_slice_cast_9.sliceCast(u3);
564
565 var i: usize = 0;
566 while (i < packed_slice_cast_2.len) : (i += 1) {
567 const val = switch (native_endian) {
568 .big => 0b01,
569 .little => 0b10,
570 };
571 try testing.expect(packed_slice_cast_2.get(i) == val);
572 }
573 i = 0;
574 while (i < packed_slice_cast_4.len) : (i += 1) {
575 const val = switch (native_endian) {
576 .big => 0b0101,
577 .little => 0b1010,
578 };
579 try testing.expect(packed_slice_cast_4.get(i) == val);
580 }
581 i = 0;
582 while (i < packed_slice_cast_9.len) : (i += 1) {
583 const val = 0b010101010;
584 try testing.expect(packed_slice_cast_9.get(i) == val);
585 packed_slice_cast_9.set(i, 0b111000111);
586 }
587 i = 0;
588 while (i < packed_slice_cast_3.len) : (i += 1) {
589 const val: u3 = switch (native_endian) {
590 .big => if (i % 2 == 0) 0b111 else 0b000,
591 .little => if (i % 2 == 0) 0b111 else 0b000,
592 };
593 try testing.expect(packed_slice_cast_3.get(i) == val);
594 }
595}
596
597test "PackedInt(Array/Slice)Endian" {
598 {
599 const PackedArrayBe = PackedIntArrayEndian(u4, .big, 8);
600 var packed_array_be = PackedArrayBe.init([_]u4{ 0, 1, 2, 3, 4, 5, 6, 7 });
601 try testing.expect(packed_array_be.bytes[0] == 0b00000001);
602 try testing.expect(packed_array_be.bytes[1] == 0b00100011);
603
604 var i: usize = 0;
605 while (i < packed_array_be.len) : (i += 1) {
606 try testing.expect(packed_array_be.get(i) == i);
607 }
608
609 var packed_slice_le = packed_array_be.sliceCastEndian(u4, .little);
610 i = 0;
611 while (i < packed_slice_le.len) : (i += 1) {
612 const val = if (i % 2 == 0) i + 1 else i - 1;
613 try testing.expect(packed_slice_le.get(i) == val);
614 }
615
616 var packed_slice_le_shift = packed_array_be.slice(1, 5).sliceCastEndian(u4, .little);
617 i = 0;
618 while (i < packed_slice_le_shift.len) : (i += 1) {
619 const val = if (i % 2 == 0) i else i + 2;
620 try testing.expect(packed_slice_le_shift.get(i) == val);
621 }
622 }
623
624 {
625 const PackedArrayBe = PackedIntArrayEndian(u11, .big, 8);
626 var packed_array_be = PackedArrayBe.init([_]u11{ 0, 1, 2, 3, 4, 5, 6, 7 });
627 try testing.expect(packed_array_be.bytes[0] == 0b00000000);
628 try testing.expect(packed_array_be.bytes[1] == 0b00000000);
629 try testing.expect(packed_array_be.bytes[2] == 0b00000100);
630 try testing.expect(packed_array_be.bytes[3] == 0b00000001);
631 try testing.expect(packed_array_be.bytes[4] == 0b00000000);
632
633 var i: usize = 0;
634 while (i < packed_array_be.len) : (i += 1) {
635 try testing.expect(packed_array_be.get(i) == i);
636 }
637
638 var packed_slice_le = packed_array_be.sliceCastEndian(u11, .little);
639 try testing.expect(packed_slice_le.get(0) == 0b00000000000);
640 try testing.expect(packed_slice_le.get(1) == 0b00010000000);
641 try testing.expect(packed_slice_le.get(2) == 0b00000000100);
642 try testing.expect(packed_slice_le.get(3) == 0b00000000000);
643 try testing.expect(packed_slice_le.get(4) == 0b00010000011);
644 try testing.expect(packed_slice_le.get(5) == 0b00000000010);
645 try testing.expect(packed_slice_le.get(6) == 0b10000010000);
646 try testing.expect(packed_slice_le.get(7) == 0b00000111001);
647
648 var packed_slice_le_shift = packed_array_be.slice(1, 5).sliceCastEndian(u11, .little);
649 try testing.expect(packed_slice_le_shift.get(0) == 0b00010000000);
650 try testing.expect(packed_slice_le_shift.get(1) == 0b00000000100);
651 try testing.expect(packed_slice_le_shift.get(2) == 0b00000000000);
652 try testing.expect(packed_slice_le_shift.get(3) == 0b00010000011);
653 }
654}
655
656//@NOTE: Need to manually update this list as more posix os's get
657// added to DirectAllocator.
658
659// These tests prove we aren't accidentally accessing memory past
660// the end of the array/slice by placing it at the end of a page
661// and reading the last element. The assumption is that the page
662// after this one is not mapped and will cause a segfault if we
663// don't account for the bounds.
664test "PackedIntArray at end of available memory" {
665 switch (builtin.target.os.tag) {
666 .linux, .macos, .ios, .freebsd, .netbsd, .openbsd, .windows => {},
667 else => return,
668 }
669 const PackedArray = PackedIntArray(u3, 8);
670
671 const Padded = struct {
672 _: [std.mem.page_size - @sizeOf(PackedArray)]u8,
673 p: PackedArray,
674 };
675
676 const allocator = std.testing.allocator;
677
678 var pad = try allocator.create(Padded);
679 defer allocator.destroy(pad);
680 pad.p.set(7, std.math.maxInt(u3));
681}
682
683test "PackedIntSlice at end of available memory" {
684 switch (builtin.target.os.tag) {
685 .linux, .macos, .ios, .freebsd, .netbsd, .openbsd, .windows => {},
686 else => return,
687 }
688 const PackedSlice = PackedIntSlice(u11);
689
690 const allocator = std.testing.allocator;
691
692 var page = try allocator.alloc(u8, std.mem.page_size);
693 defer allocator.free(page);
694
695 var p = PackedSlice.init(page[std.mem.page_size - 2 ..], 1);
696 p.set(0, std.math.maxInt(u11));
697}
lib/std/std.zig-5
...@@ -26,10 +26,6 @@ pub const EnumSet = enums.EnumSet;...@@ -26,10 +26,6 @@ pub const EnumSet = enums.EnumSet;
26pub const HashMap = hash_map.HashMap;26pub const HashMap = hash_map.HashMap;
27pub const HashMapUnmanaged = hash_map.HashMapUnmanaged;27pub const HashMapUnmanaged = hash_map.HashMapUnmanaged;
28pub const MultiArrayList = @import("multi_array_list.zig").MultiArrayList;28pub const MultiArrayList = @import("multi_array_list.zig").MultiArrayList;
29pub const PackedIntArray = @import("packed_int_array.zig").PackedIntArray;
30pub const PackedIntArrayEndian = @import("packed_int_array.zig").PackedIntArrayEndian;
31pub const PackedIntSlice = @import("packed_int_array.zig").PackedIntSlice;
32pub const PackedIntSliceEndian = @import("packed_int_array.zig").PackedIntSliceEndian;
33pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;29pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;
34pub const PriorityDequeue = @import("priority_dequeue.zig").PriorityDequeue;30pub const PriorityDequeue = @import("priority_dequeue.zig").PriorityDequeue;
35pub const Progress = @import("Progress.zig");31pub const Progress = @import("Progress.zig");
...@@ -82,7 +78,6 @@ pub const meta = @import("meta.zig");...@@ -82,7 +78,6 @@ pub const meta = @import("meta.zig");
82pub const net = @import("net.zig");78pub const net = @import("net.zig");
83pub const os = @import("os.zig");79pub const os = @import("os.zig");
84pub const once = @import("once.zig").once;80pub const once = @import("once.zig").once;
85pub const packed_int_array = @import("packed_int_array.zig");
86pub const pdb = @import("pdb.zig");81pub const pdb = @import("pdb.zig");
87pub const posix = @import("posix.zig");82pub const posix = @import("posix.zig");
88pub const process = @import("process.zig");83pub const process = @import("process.zig");