authorgravatar for tgschultz@gmail.comtgschultz <tgschultz@gmail.com> 2019-05-04 16:17:12+00:00
committergravatar for tgschultz@gmail.comtgschultz <tgschultz@gmail.com> 2019-05-04 16:17:12+00:00
log8c28b5960559daef3ffc6b0777829ae3262ee8c7
treeef86a52aa007077a25a8789cf4f63f14f4c7a98d
parent27ed525e03879502a983bc4782625e9c081c1c4d

Added ability to specify endianess of PackedInt(Array/Slice)


2 files changed, 335 insertions(+), 161 deletions(-)

std/packed_int_array.zig+333-161
......@@ -3,128 +3,148 @@ const builtin = @import("builtin");
33const debug = std.debug;
44const testing = std.testing;
55
6pub fn PackedIntIo(comptime Int: type) type {
6pub fn PackedIntIo(comptime Int: type, comptime endian: builtin.Endian) type
7{
78 //The general technique employed here is to cast bytes in the array to a container
89 // integer (having bits % 8 == 0) large enough to contain the number of bits we want,
910 // then we can retrieve or store the new value with a relative minimum of masking
1011 // and shifting. In this worst case, this means that we'll need an integer that's
1112 // actually 1 byte larger than the minimum required to store the bits, because it
12 // is possible that the bits start at the end of the first byte, continue through
13 // is possible that the bits start at the end of the first byte, continue through
1314 // zero or more, then end in the beginning of the last. But, if we try to access
1415 // a value in the very last byte of memory with that integer size, that extra byte
1516 // will be out of bounds. Depending on the circumstances of the memory, that might
1617 // mean the OS fatally kills the program. Thus, we use a larger container (MaxIo)
1718 // most of the time, but a smaller container (MinIo) when touching the last byte
1819 // of the memory.
20
1921 const int_bits = comptime std.meta.bitCount(Int);
20
22
2123 //in the best case, this is the number of bytes we need to touch
2224 // to read or write a value, as bits
2325 const min_io_bits = ((int_bits + 7) / 8) * 8;
24
26
2527 //in the worst case, this is the number of bytes we need to touch
2628 // to read or write a value, as bits
27 const max_io_bits = switch (int_bits) {
29 const max_io_bits = switch(int_bits)
30 {
2831 0 => 0,
2932 1 => 8,
3033 2...9 => 16,
3134 10...65535 => ((int_bits / 8) + 2) * 8,
3235 else => unreachable,
3336 };
34
37
3538 //we bitcast the desired Int type to an unsigned version of itself
3639 // to avoid issues with shifting signed ints.
3740 const UnInt = @IntType(false, int_bits);
38
41
3942 //The maximum container int type
4043 const MinIo = @IntType(false, min_io_bits);
41
44
4245 //The minimum container int type
4346 const MaxIo = @IntType(false, max_io_bits);
44
45 return struct {
46 pub fn get(bytes: []const u8, index: usize, bit_offset: u7) Int {
47 if (int_bits == 0) return 0;
48
47
48 return struct
49 {
50 pub fn get(bytes: []const u8, index: usize, bit_offset: u7) Int
51 {
52 if(int_bits == 0) return 0;
53
4954 const bit_index = (index * int_bits) + bit_offset;
5055 const max_end_byte = (bit_index + max_io_bits) / 8;
51
56
5257 //Using the larger container size will potentially read out of bounds
53 if (max_end_byte > bytes.len) return getBits(bytes, MinIo, bit_index);
58 if(max_end_byte > bytes.len) return getBits(bytes, MinIo, bit_index);
5459 return getBits(bytes, MaxIo, bit_index);
5560 }
56
57 fn getBits(bytes: []const u8, comptime Container: type, bit_index: usize) Int {
61
62 fn getBits(bytes: []const u8, comptime Container: type, bit_index: usize) Int
63 {
5864 const container_bits = comptime std.meta.bitCount(Container);
5965 const Shift = std.math.Log2Int(Container);
60
66
6167 const start_byte = bit_index / 8;
6268 const head_keep_bits = bit_index - (start_byte * 8);
6369 const tail_keep_bits = container_bits - (int_bits + head_keep_bits);
64
70
6571 //read bytes as container
66 const value_ptr = @ptrCast(*align(1) const Container, &bytes[start_byte]);
72 const value_ptr = @ptrCast(*const align(1) Container, &bytes[start_byte]);
6773 var value = value_ptr.*;
68
69 switch (builtin.endian) {
70 .Big => {
74
75 if(endian != builtin.endian) value = @bswap(Container, value);
76
77 switch(endian)
78 {
79 .Big =>
80 {
7181 value <<= @intCast(Shift, head_keep_bits);
7282 value >>= @intCast(Shift, head_keep_bits);
7383 value >>= @intCast(Shift, tail_keep_bits);
7484 },
75 .Little => {
85 .Little =>
86 {
7687 value <<= @intCast(Shift, tail_keep_bits);
7788 value >>= @intCast(Shift, tail_keep_bits);
7889 value >>= @intCast(Shift, head_keep_bits);
7990 },
8091 }
81
92
8293 return @bitCast(Int, @truncate(UnInt, value));
8394 }
84
85 pub fn set(bytes: []u8, index: usize, bit_offset: u3, int: Int) void {
86 if (int_bits == 0) return;
95
96 pub fn set(bytes: []u8, index: usize, bit_offset: u3, int: Int) void
97 {
98 if(int_bits == 0) return;
8799
88100 const bit_index = (index * int_bits) + bit_offset;
89101 const max_end_byte = (bit_index + max_io_bits) / 8;
90
102
91103 //Using the larger container size will potentially write out of bounds
92 if (max_end_byte > bytes.len) return setBits(bytes, MinIo, bit_index, int);
104 if(max_end_byte > bytes.len) return setBits(bytes, MinIo, bit_index, int);
93105 setBits(bytes, MaxIo, bit_index, int);
94106 }
95
96 fn setBits(bytes: []u8, comptime Container: type, bit_index: usize, int: Int) void {
107
108 fn setBits(bytes: []u8, comptime Container: type, bit_index: usize, int: Int) void
109 {
97110 const container_bits = comptime std.meta.bitCount(Container);
98111 const Shift = std.math.Log2Int(Container);
99
112
100113 const start_byte = bit_index / 8;
101114 const head_keep_bits = bit_index - (start_byte * 8);
102115 const tail_keep_bits = container_bits - (int_bits + head_keep_bits);
103 const keep_shift = switch (builtin.endian) {
116 const keep_shift = switch(endian)
117 {
104118 .Big => @intCast(Shift, tail_keep_bits),
105119 .Little => @intCast(Shift, head_keep_bits),
106120 };
107
121
108122 //position the bits where they need to be in the container
109123 const value = @intCast(Container, @bitCast(UnInt, int)) << keep_shift;
110
124
111125 //read existing bytes
112126 const target_ptr = @ptrCast(*align(1) Container, &bytes[start_byte]);
113127 var target = target_ptr.*;
114
128
129 if(endian != builtin.endian) target = @bswap(Container, target);
130
115131 //zero the bits we want to replace in the existing bytes
116132 const inv_mask = @intCast(Container, std.math.maxInt(UnInt)) << keep_shift;
117133 const mask = ~inv_mask;
118134 target &= mask;
119
135
120136 //merge the new value
121137 target |= value;
122
138
139 if(endian != builtin.endian) target = @bswap(Container, target);
140
123141 //save it back
124142 target_ptr.* = target;
125143 }
126
127 fn slice(bytes: []u8, bit_offset: u3, start: usize, end: usize) PackedIntSlice(Int) {
144
145 fn slice(bytes: []u8, bit_offset: u3, start: usize, end: usize)
146 PackedIntSliceEndian(Int, endian)
147 {
128148 debug.assert(end >= start);
129149
130150 const length = end - start;
......@@ -132,25 +152,28 @@ pub fn PackedIntIo(comptime Int: type) type {
132152 const start_byte = bit_index / 8;
133153 const end_byte = (bit_index + (length * int_bits) + 7) / 8;
134154 const new_bytes = bytes[start_byte..end_byte];
135
136 if (length == 0) return PackedIntSlice(Int).init(new_bytes[0..0], 0);
137
138 var new_slice = PackedIntSlice(Int).init(new_bytes, length);
155
156 if(length == 0) return PackedIntSliceEndian(Int, endian).init(new_bytes[0..0], 0);
157
158 var new_slice = PackedIntSliceEndian(Int, endian).init(new_bytes, length);
139159 new_slice.bit_offset = @intCast(u3, (bit_index - (start_byte * 8)));
140160 return new_slice;
141161 }
142
143 fn sliceCast(bytes: []u8, comptime NewInt: type, bit_offset: u3, old_len: usize) PackedIntSlice(NewInt) {
162
163 fn sliceCast(bytes: []u8, comptime NewInt: type, comptime new_endian: builtin.Endian,
164 bit_offset: u3, old_len: usize) PackedIntSliceEndian(NewInt, new_endian)
165 {
144166 const new_int_bits = comptime std.meta.bitCount(NewInt);
145 const New = PackedIntSlice(NewInt);
146
167 const New = PackedIntSliceEndian(NewInt, new_endian);
168
147169 const total_bits = (old_len * int_bits);
148170 const new_int_count = total_bits / new_int_bits;
149
171
150172 debug.assert(total_bits == new_int_count * new_int_bits);
151
173
152174 var new = New.init(bytes, new_int_count);
153175 new.bit_offset = bit_offset;
176
154177 return new;
155178 }
156179 };
......@@ -159,132 +182,187 @@ pub fn PackedIntIo(comptime Int: type) type {
159182///Creates a bit-packed array of integers of type Int. Bits
160183/// are packed using native endianess and without storing any meta
161184/// data. PackedIntArray(i3, 8) will occupy exactly 3 bytes of memory.
162pub fn PackedIntArray(comptime Int: type, comptime int_count: usize) type {
185pub fn PackedIntArray(comptime Int: type, comptime int_count: usize) type
186{
187 return PackedIntArrayEndian(Int, builtin.endian, int_count);
188}
189
190///Creates a bit-packed array of integers of type Int. Bits
191/// are packed using specified endianess and without storing any meta
192/// data.
193pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: builtin.Endian,
194 comptime int_count: usize) type
195{
163196 const int_bits = comptime std.meta.bitCount(Int);
164197 const total_bits = int_bits * int_count;
165198 const total_bytes = (total_bits + 7) / 8;
166
167 const Io = PackedIntIo(Int);
168
169 return struct {
199
200 const Io = PackedIntIo(Int, endian);
201
202 return struct
203 {
170204 const Self = @This();
171
205
172206 bytes: [total_bytes]u8,
173
207
174208 ///Returns the number of elements in the packed array
175 pub fn len(self: Self) usize {
209 pub fn len(self: Self) usize
210 {
176211 return int_count;
177212 }
178
213
179214 ///Initialize a packed array using an unpacked array
180215 /// or, more likely, an array literal.
181 pub fn init(ints: [int_count]Int) Self {
216 pub fn init(ints: [int_count]Int) Self
217 {
182218 var self = Self(undefined);
183 for (ints) |int, i| self.set(i, int);
219 for(ints) |int, i| self.set(i, int);
184220 return self;
185221 }
186
222
187223 ///Return the Int stored at index
188 pub fn get(self: Self, index: usize) Int {
224 pub fn get(self: Self, index: usize) Int
225 {
189226 debug.assert(index < int_count);
190227 return Io.get(self.bytes, index, 0);
191228 }
192
229
193230 ///Copy int into the array at index
194 pub fn set(self: *Self, index: usize, int: Int) void {
231 pub fn set(self: *Self, index: usize, int: Int) void
232 {
195233 debug.assert(index < int_count);
196234 return Io.set(&self.bytes, index, 0, int);
197235 }
198
236
199237 ///Create a PackedIntSlice of the array from given start to given end
200 pub fn slice(self: *Self, start: usize, end: usize) PackedIntSlice(Int) {
238 pub fn slice(self: *Self, start: usize, end: usize) PackedIntSliceEndian(Int, endian)
239 {
201240 debug.assert(start < int_count);
202241 debug.assert(end <= int_count);
203242 return Io.slice(&self.bytes, 0, start, end);
204243 }
205
244
206245 ///Create a PackedIntSlice of the array using NewInt as the bit width integer.
207246 /// NewInt's bit width must fit evenly within the array's Int's total bits.
208 pub fn sliceCast(self: *Self, comptime NewInt: type) PackedIntSlice(NewInt) {
209 return Io.sliceCast(&self.bytes, NewInt, 0, int_count);
247 pub fn sliceCast(self: *Self, comptime NewInt: type) PackedIntSlice(NewInt)
248 {
249 return self.sliceCastEndian(NewInt, endian);
250 }
251
252 ///Create a PackedIntSlice of the array using NewInt as the bit width integer
253 /// and new_endian as the new endianess. NewInt's bit width must fit evenly within
254 /// the array's Int's total bits.
255 pub fn sliceCastEndian(self: *Self, comptime NewInt: type,
256 comptime new_endian: builtin.Endian) PackedIntSliceEndian(NewInt, new_endian)
257 {
258 return Io.sliceCast(&self.bytes, NewInt, new_endian, 0, int_count);
210259 }
211260 };
212261}
213262
214///Uses a slice as a bit-packed block of int_count integers of type Int.
263///Uses a slice as a bit-packed block of int_count integers of type Int.
215264/// Bits are packed using native endianess and without storing any meta
216265/// data.
217pub fn PackedIntSlice(comptime Int: type) type {
218 const int_bits = comptime std.meta.bitCount(Int);
219 const Io = PackedIntIo(Int);
266pub fn PackedIntSlice(comptime Int: type) type
267{
268 return PackedIntSliceEndian(Int, builtin.endian);
269}
220270
221 return struct {
271///Uses a slice as a bit-packed block of int_count integers of type Int.
272/// Bits are packed using specified endianess and without storing any meta
273/// data.
274pub fn PackedIntSliceEndian(comptime Int: type, comptime endian: builtin.Endian) type
275{
276 const int_bits = comptime std.meta.bitCount(Int);
277 const Io = PackedIntIo(Int, endian);
278
279 return struct
280 {
222281 const Self = @This();
223
282
224283 bytes: []u8,
225284 int_count: usize,
226285 bit_offset: u3,
227
286
228287 ///Returns the number of elements in the packed slice
229 pub fn len(self: Self) usize {
288 pub fn len(self: Self) usize
289 {
230290 return self.int_count;
231291 }
232
292
233293 ///Calculates the number of bytes required to store a desired count
234294 /// of Ints
235 pub fn bytesRequired(int_count: usize) usize {
295 pub fn bytesRequired(int_count: usize) usize
296 {
236297 const total_bits = int_bits * int_count;
237298 const total_bytes = (total_bits + 7) / 8;
238299 return total_bytes;
239300 }
240
301
241302 ///Initialize a packed slice using the memory at bytes, with int_count
242303 /// elements. bytes must be large enough to accomodate the requested
243304 /// count.
244 pub fn init(bytes: []u8, int_count: usize) Self {
305 pub fn init(bytes: []u8, int_count: usize) Self
306 {
245307 debug.assert(bytes.len >= bytesRequired(int_count));
246
247 return Self{
308
309 return Self
310 {
248311 .bytes = bytes,
249312 .int_count = int_count,
250313 .bit_offset = 0,
251314 };
252315 }
253
316
254317 ///Return the Int stored at index
255 pub fn get(self: Self, index: usize) Int {
318 pub fn get(self: Self, index: usize) Int
319 {
256320 debug.assert(index < self.int_count);
257321 return Io.get(self.bytes, index, self.bit_offset);
258322 }
259
323
260324 ///Copy int into the array at index
261 pub fn set(self: *Self, index: usize, int: Int) void {
325 pub fn set(self: *Self, index: usize, int: Int) void
326 {
262327 debug.assert(index < self.int_count);
263328 return Io.set(self.bytes, index, self.bit_offset, int);
264329 }
265
330
266331 ///Create a PackedIntSlice of this slice from given start to given end
267 pub fn slice(self: Self, start: usize, end: usize) PackedIntSlice(Int) {
332 pub fn slice(self: Self, start: usize, end: usize) PackedIntSliceEndian(Int, endian)
333 {
268334 debug.assert(start < self.int_count);
269335 debug.assert(end <= self.int_count);
270336 return Io.slice(self.bytes, self.bit_offset, start, end);
271337 }
272
338
273339 ///Create a PackedIntSlice of this slice using NewInt as the bit width integer.
274340 /// NewInt's bit width must fit evenly within this slice's Int's total bits.
275 pub fn sliceCast(self: Self, comptime NewInt: type) PackedIntSlice(NewInt) {
276 return Io.sliceCast(self.bytes, NewInt, self.bit_offset, self.int_count);
341 pub fn sliceCast(self: Self, comptime NewInt: type) PackedIntSliceEndian(NewInt, endian)
342 {
343 return self.sliceCastEndian(NewInt, endian);
344 }
345
346 ///Create a PackedIntSlice of this slice using NewInt as the bit width integer
347 /// and new_endian as the new endianess. NewInt's bit width must fit evenly within
348 /// this slice's Int's total bits.
349 pub fn sliceCastEndian(self: Self, comptime NewInt: type,
350 comptime new_endian: builtin.Endian) PackedIntSliceEndian(NewInt, new_endian)
351 {
352 return Io.sliceCast(self.bytes, NewInt, new_endian, self.bit_offset, self.int_count);
277353 }
278354 };
279355}
280356
281test "PackedIntArray" {
357test "PackedIntArray"
358{
282359 @setEvalBranchQuota(10000);
283360 const max_bits = 256;
284361 const int_count = 19;
285
362
286363 comptime var bits = 0;
287 inline while (bits <= 256) : (bits += 1) {
364 inline while(bits <= 256):(bits += 1)
365 {
288366 //alternate unsigned and signed
289367 const even = bits % 2 == 0;
290368 const I = @IntType(even, bits);
......@@ -292,90 +370,100 @@ test "PackedIntArray" {
292370 const PackedArray = PackedIntArray(I, int_count);
293371 const expected_bytes = ((bits * int_count) + 7) / 8;
294372 testing.expect(@sizeOf(PackedArray) == expected_bytes);
295
373
296374 var data = PackedArray(undefined);
297
375
298376 //write values, counting up
299377 var i = usize(0);
300378 var count = I(0);
301 while (i < data.len()) : (i += 1) {
379 while(i < data.len()):(i += 1)
380 {
302381 data.set(i, count);
303 if (bits > 0) count +%= 1;
382 if(bits > 0) count +%= 1;
304383 }
305
384
306385 //read and verify values
307386 i = 0;
308387 count = 0;
309 while (i < data.len()) : (i += 1) {
388 while(i < data.len()):(i += 1)
389 {
310390 const val = data.get(i);
311391 testing.expect(val == count);
312 if (bits > 0) count +%= 1;
392 if(bits > 0) count +%= 1;
313393 }
314394 }
315395}
316396
317test "PackedIntArray init" {
397test "PackedIntArray init"
398{
318399 const PackedArray = PackedIntArray(u3, 8);
319 var packed_array = PackedArray.init([]u3{ 0, 1, 2, 3, 4, 5, 6, 7 });
400 var packed_array = PackedArray.init([]u3{0,1,2,3,4,5,6,7});
320401 var i = usize(0);
321 while (i < packed_array.len()) : (i += 1) testing.expect(packed_array.get(i) == i);
402 while(i < packed_array.len()):(i += 1) testing.expect(packed_array.get(i) == i);
322403}
323404
324test "PackedIntSlice" {
405test "PackedIntSlice"
406{
325407 @setEvalBranchQuota(10000);
326408 const max_bits = 256;
327409 const int_count = 19;
328410 const total_bits = max_bits * int_count;
329411 const total_bytes = (total_bits + 7) / 8;
330
412
331413 var buffer: [total_bytes]u8 = undefined;
332
414
333415 comptime var bits = 0;
334 inline while (bits <= 256) : (bits += 1) {
416 inline while(bits <= 256):(bits += 1)
417 {
335418 //alternate unsigned and signed
336419 const even = bits % 2 == 0;
337420 const I = @IntType(even, bits);
338421 const P = PackedIntSlice(I);
339
422
340423 var data = P.init(&buffer, int_count);
341
424
342425 //write values, counting up
343426 var i = usize(0);
344427 var count = I(0);
345 while (i < data.len()) : (i += 1) {
428 while(i < data.len()):(i += 1)
429 {
346430 data.set(i, count);
347 if (bits > 0) count +%= 1;
431 if(bits > 0) count +%= 1;
348432 }
349
433
350434 //read and verify values
351435 i = 0;
352436 count = 0;
353 while (i < data.len()) : (i += 1) {
437 while(i < data.len()):(i += 1)
438 {
354439 const val = data.get(i);
355440 testing.expect(val == count);
356 if (bits > 0) count +%= 1;
441 if(bits > 0) count +%= 1;
357442 }
358443 }
359444}
360445
361test "PackedIntSlice of PackedInt(Array/Slice)" {
446test "PackedIntSlice of PackedInt(Array/Slice)"
447{
362448 const max_bits = 16;
363449 const int_count = 19;
364
450
365451 comptime var bits = 0;
366 inline while (bits <= max_bits) : (bits += 1) {
452 inline while(bits <= max_bits):(bits += 1)
453 {
367454 const Int = @IntType(false, bits);
368
455
369456 const PackedArray = PackedIntArray(Int, int_count);
370457 var packed_array = PackedArray(undefined);
371
458
372459 const limit = (1 << bits);
373
460
374461 var i = usize(0);
375 while (i < packed_array.len()) : (i += 1) {
462 while(i < packed_array.len()):(i += 1)
463 {
376464 packed_array.set(i, @intCast(Int, i % limit));
377465 }
378
466
379467 //slice of array
380468 var packed_slice = packed_array.slice(2, 5);
381469 testing.expect(packed_slice.len() == 3);
......@@ -387,10 +475,10 @@ test "PackedIntSlice of PackedInt(Array/Slice)" {
387475 testing.expect(packed_slice.get(2) == 4 % limit);
388476 packed_slice.set(1, 7 % limit);
389477 testing.expect(packed_slice.get(1) == 7 % limit);
390
478
391479 //write through slice
392480 testing.expect(packed_array.get(3) == 7 % limit);
393
481
394482 //slice of a slice
395483 const packed_slice_two = packed_slice.slice(0, 3);
396484 testing.expect(packed_slice_two.len() == 3);
......@@ -399,7 +487,7 @@ test "PackedIntSlice of PackedInt(Array/Slice)" {
399487 testing.expect(packed_slice_two.bytes.len == ps2_expected_bytes);
400488 testing.expect(packed_slice_two.get(1) == 7 % limit);
401489 testing.expect(packed_slice_two.get(2) == 4 % limit);
402
490
403491 //size one case
404492 const packed_slice_three = packed_slice_two.slice(1, 2);
405493 testing.expect(packed_slice_three.len() == 1);
......@@ -407,12 +495,12 @@ test "PackedIntSlice of PackedInt(Array/Slice)" {
407495 const ps3_expected_bytes = (ps3_bit_count + 7) / 8;
408496 testing.expect(packed_slice_three.bytes.len == ps3_expected_bytes);
409497 testing.expect(packed_slice_three.get(0) == 7 % limit);
410
498
411499 //empty slice case
412500 const packed_slice_empty = packed_slice.slice(0, 0);
413501 testing.expect(packed_slice_empty.len() == 0);
414502 testing.expect(packed_slice_empty.bytes.len == 0);
415
503
416504 //slicing at byte boundaries
417505 const packed_slice_edge = packed_array.slice(8, 16);
418506 testing.expect(packed_slice_edge.len() == 8);
......@@ -421,75 +509,154 @@ test "PackedIntSlice of PackedInt(Array/Slice)" {
421509 testing.expect(packed_slice_edge.bytes.len == pse_expected_bytes);
422510 testing.expect(packed_slice_edge.bit_offset == 0);
423511 }
512
424513}
425514
426test "PackedIntSlice accumulating bit offsets" {
515test "PackedIntSlice accumulating bit offsets"
516{
427517 //bit_offset is u3, so standard debugging asserts should catch
428518 // anything
429519 {
430520 const PackedArray = PackedIntArray(u3, 16);
431521 var packed_array = PackedArray(undefined);
432
522
433523 var packed_slice = packed_array.slice(0, packed_array.len());
434524 var i = usize(0);
435 while (i < packed_array.len() - 1) : (i += 1) {
525 while(i < packed_array.len() - 1):(i += 1)
526 {
527
436528 packed_slice = packed_slice.slice(1, packed_slice.len());
437529 }
438530 }
439531 {
440532 const PackedArray = PackedIntArray(u11, 88);
441533 var packed_array = PackedArray(undefined);
442
534
443535 var packed_slice = packed_array.slice(0, packed_array.len());
444536 var i = usize(0);
445 while (i < packed_array.len() - 1) : (i += 1) {
537 while(i < packed_array.len() - 1):(i += 1)
538 {
446539 packed_slice = packed_slice.slice(1, packed_slice.len());
447540 }
448541 }
542
449543}
450544
451545//@NOTE: As I do not have a big endian system to test this on,
452546// big endian values were not tested
453test "PackedInt(Array/Slice) sliceCast" {
547test "PackedInt(Array/Slice) sliceCast"
548{
454549 const PackedArray = PackedIntArray(u1, 16);
455 var packed_array = PackedArray.init([]u1{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 });
550 var packed_array = PackedArray.init([]u1{0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1});
456551 const packed_slice_cast_2 = packed_array.sliceCast(u2);
457552 const packed_slice_cast_4 = packed_slice_cast_2.sliceCast(u4);
458553 var packed_slice_cast_9 = packed_array.slice(0, (packed_array.len() / 9) * 9).sliceCast(u9);
459554 const packed_slice_cast_3 = packed_slice_cast_9.sliceCast(u3);
460
555
461556 var i = usize(0);
462 while (i < packed_slice_cast_2.len()) : (i += 1) {
463 const val = switch (builtin.endian) {
557 while(i < packed_slice_cast_2.len()):(i += 1)
558 {
559 const val = switch(builtin.endian)
560 {
464561 .Big => 0b01,
465562 .Little => 0b10,
466563 };
467564 testing.expect(packed_slice_cast_2.get(i) == val);
468565 }
469566 i = 0;
470 while (i < packed_slice_cast_4.len()) : (i += 1) {
471 const val = switch (builtin.endian) {
567 while(i < packed_slice_cast_4.len()):(i += 1)
568 {
569 const val = switch(builtin.endian)
570 {
472571 .Big => 0b0101,
473572 .Little => 0b1010,
474573 };
475574 testing.expect(packed_slice_cast_4.get(i) == val);
476575 }
477576 i = 0;
478 while (i < packed_slice_cast_9.len()) : (i += 1) {
577 while(i < packed_slice_cast_9.len()):(i += 1)
578 {
479579 const val = 0b010101010;
480580 testing.expect(packed_slice_cast_9.get(i) == val);
481581 packed_slice_cast_9.set(i, 0b111000111);
482582 }
483583 i = 0;
484 while (i < packed_slice_cast_3.len()) : (i += 1) {
485 const val = switch (builtin.endian) {
486 .Big => if (i % 2 == 0) u3(0b111) else u3(0b000),
487 .Little => if (i % 2 == 0) u3(0b111) else u3(0b000),
584 while(i < packed_slice_cast_3.len()):(i += 1)
585 {
586 const val = switch(builtin.endian)
587 {
588 .Big => if(i % 2 == 0) u3(0b111) else u3(0b000),
589 .Little => if(i % 2 == 0) u3(0b111) else u3(0b000),
488590 };
489591 testing.expect(packed_slice_cast_3.get(i) == val);
490592 }
491593}
492594
595test "PackedInt(Array/Slice)Endian"
596{
597 {
598 const PackedArrayBe = PackedIntArrayEndian(u4, .Big, 8);
599 var packed_array_be = PackedArrayBe.init([]u4{0,1,2,3,4,5,6,7,});
600 testing.expect(packed_array_be.bytes[0] == 0b00000001);
601 testing.expect(packed_array_be.bytes[1] == 0b00100011);
602
603 var i = usize(0);
604 while(i < packed_array_be.len()):(i += 1)
605 {
606 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 {
613 const val = if(i % 2 == 0) i + 1 else i - 1;
614 testing.expect(packed_slice_le.get(i) == val);
615 }
616
617 var packed_slice_le_shift = packed_array_be.slice(1, 5).sliceCastEndian(u4, .Little);
618 i = 0;
619 while(i < packed_slice_le_shift.len()):(i += 1)
620 {
621 const val = if(i % 2 == 0) i else i + 2;
622 testing.expect(packed_slice_le_shift.get(i) == val);
623 }
624 }
625
626 {
627 const PackedArrayBe = PackedIntArrayEndian(u11, .Big, 8);
628 var packed_array_be = PackedArrayBe.init([]u11{0,1,2,3,4,5,6,7,});
629 testing.expect(packed_array_be.bytes[0] == 0b00000000);
630 testing.expect(packed_array_be.bytes[1] == 0b00000000);
631 testing.expect(packed_array_be.bytes[2] == 0b00000100);
632 testing.expect(packed_array_be.bytes[3] == 0b00000001);
633 testing.expect(packed_array_be.bytes[4] == 0b00000000);
634
635 var i = usize(0);
636 while(i < packed_array_be.len()):(i += 1)
637 {
638 testing.expect(packed_array_be.get(i) == i);
639 }
640
641 var packed_slice_le = packed_array_be.sliceCastEndian(u11, .Little);
642 testing.expect(packed_slice_le.get(0) == 0b00000000000);
643 testing.expect(packed_slice_le.get(1) == 0b00010000000);
644 testing.expect(packed_slice_le.get(2) == 0b00000000100);
645 testing.expect(packed_slice_le.get(3) == 0b00000000000);
646 testing.expect(packed_slice_le.get(4) == 0b00010000011);
647 testing.expect(packed_slice_le.get(5) == 0b00000000010);
648 testing.expect(packed_slice_le.get(6) == 0b10000010000);
649 testing.expect(packed_slice_le.get(7) == 0b00000111001);
650
651
652 var packed_slice_le_shift = packed_array_be.slice(1, 5).sliceCastEndian(u11, .Little);
653 testing.expect(packed_slice_le_shift.get(0) == 0b00010000000);
654 testing.expect(packed_slice_le_shift.get(1) == 0b00000000100);
655 testing.expect(packed_slice_le_shift.get(2) == 0b00000000000);
656 testing.expect(packed_slice_le_shift.get(3) == 0b00010000011);
657 }
658}
659
493660//@NOTE: Need to manually update this list as more posix os's get
494661// added to DirectAllocator. Windows can be added too when DirectAllocator
495662// switches to VirtualAlloc.
......@@ -499,39 +666,44 @@ test "PackedInt(Array/Slice) sliceCast" {
499666// and reading the last element. The assumption is that the page
500667// after this one is not mapped and will cause a segfault if we
501668// don't account for the bounds.
502test "PackedIntArray at end of available memory" {
503 switch (builtin.os) {
669test "PackedIntArray at end of available memory"
670{
671 switch(builtin.os)
672 {
504673 .linux, .macosx, .ios, .freebsd, .netbsd => {},
505674 else => return,
506675 }
507676 const PackedArray = PackedIntArray(u3, 8);
508
509 const Padded = struct {
677
678 const Padded = struct
679 {
510680 _: [std.os.page_size - @sizeOf(PackedArray)]u8,
511681 p: PackedArray,
512682 };
513
683
514684 var da = std.heap.DirectAllocator.init();
515685 const allocator = &da.allocator;
516
686
517687 var pad = try allocator.create(Padded);
518688 defer allocator.destroy(pad);
519689 pad.p.set(7, std.math.maxInt(u3));
520690}
521691
522test "PackedIntSlice at end of available memory" {
523 switch (builtin.os) {
692test "PackedIntSlice at end of available memory"
693{
694 switch(builtin.os)
695 {
524696 .linux, .macosx, .ios, .freebsd, .netbsd => {},
525697 else => return,
526698 }
527699 const PackedSlice = PackedIntSlice(u11);
528
700
529701 var da = std.heap.DirectAllocator.init();
530702 const allocator = &da.allocator;
531
703
532704 var page = try allocator.alloc(u8, std.os.page_size);
533705 defer allocator.free(page);
534
535 var p = PackedSlice.init(page[std.os.page_size - 2 ..], 1);
706
707 var p = PackedSlice.init(page[std.os.page_size - 2..], 1);
536708 p.set(0, std.math.maxInt(u11));
537}
709}
\ No newline at end of file
std/std.zig+2
......@@ -9,7 +9,9 @@ pub const DynLib = @import("dynamic_library.zig").DynLib;
99pub const HashMap = @import("hash_map.zig").HashMap;
1010pub const LinkedList = @import("linked_list.zig").LinkedList;
1111pub const Mutex = @import("mutex.zig").Mutex;
12pub const PackedIntArrayEndian = @import("packed_int_array.zig").PackedIntArrayEndian;
1213pub const PackedIntArray = @import("packed_int_array.zig").PackedIntArray;
14pub const PackedIntSliceEndian = @import("packed_int_array.zig").PackedIntSliceEndian;
1315pub const PackedIntSlice = @import("packed_int_array.zig").PackedIntSlice;
1416pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;
1517pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex;