authorgravatar for tgschultz@gmail.comtgschultz <tgschultz@gmail.com> 2019-05-04 13:31:53+00:00
committergravatar for tgschultz@gmail.comtgschultz <tgschultz@gmail.com> 2019-05-04 13:31:53+00:00
log27ed525e03879502a983bc4782625e9c081c1c4d
tree7abaf49e78e4e9ff03babe62897fd3b0c81e5901
parent4dfd1f54db66cec2e02e245397b1c5df5051656c

zig fmt


1 files changed, 153 insertions(+), 217 deletions(-)

std/packed_int_array.zig+153-217
...@@ -3,141 +3,128 @@ const builtin = @import("builtin");...@@ -3,141 +3,128 @@ const builtin = @import("builtin");
3const debug = std.debug;3const debug = std.debug;
4const testing = std.testing;4const testing = std.testing;
55
6pub fn PackedIntIo(comptime Int: type) type6pub fn PackedIntIo(comptime Int: type) type {
7{
8 //The general technique employed here is to cast bytes in the array to a container7 //The general technique employed here is to cast bytes in the array to a container
9 // integer (having bits % 8 == 0) large enough to contain the number of bits we want,8 // integer (having bits % 8 == 0) large enough to contain the number of bits we want,
10 // then we can retrieve or store the new value with a relative minimum of masking9 // then we can retrieve or store the new value with a relative minimum of masking
11 // and shifting. In this worst case, this means that we'll need an integer that's10 // and shifting. In this worst case, this means that we'll need an integer that's
12 // actually 1 byte larger than the minimum required to store the bits, because it11 // actually 1 byte larger than the minimum required to store the bits, because it
13 // is possible that the bits start at the end of the first byte, continue through 12 // is possible that the bits start at the end of the first byte, continue through
14 // zero or more, then end in the beginning of the last. But, if we try to access13 // zero or more, then end in the beginning of the last. But, if we try to access
15 // a value in the very last byte of memory with that integer size, that extra byte14 // a value in the very last byte of memory with that integer size, that extra byte
16 // will be out of bounds. Depending on the circumstances of the memory, that might15 // will be out of bounds. Depending on the circumstances of the memory, that might
17 // mean the OS fatally kills the program. Thus, we use a larger container (MaxIo)16 // mean the OS fatally kills the program. Thus, we use a larger container (MaxIo)
18 // most of the time, but a smaller container (MinIo) when touching the last byte17 // most of the time, but a smaller container (MinIo) when touching the last byte
19 // of the memory.18 // of the memory.
20
21 const int_bits = comptime std.meta.bitCount(Int);19 const int_bits = comptime std.meta.bitCount(Int);
22 20
23 //in the best case, this is the number of bytes we need to touch21 //in the best case, this is the number of bytes we need to touch
24 // to read or write a value, as bits22 // to read or write a value, as bits
25 const min_io_bits = ((int_bits + 7) / 8) * 8;23 const min_io_bits = ((int_bits + 7) / 8) * 8;
26 24
27 //in the worst case, this is the number of bytes we need to touch25 //in the worst case, this is the number of bytes we need to touch
28 // to read or write a value, as bits26 // to read or write a value, as bits
29 const max_io_bits = switch(int_bits)27 const max_io_bits = switch (int_bits) {
30 {
31 0 => 0,28 0 => 0,
32 1 => 8,29 1 => 8,
33 2...9 => 16,30 2...9 => 16,
34 10...65535 => ((int_bits / 8) + 2) * 8,31 10...65535 => ((int_bits / 8) + 2) * 8,
35 else => unreachable,32 else => unreachable,
36 };33 };
37 34
38 //we bitcast the desired Int type to an unsigned version of itself35 //we bitcast the desired Int type to an unsigned version of itself
39 // to avoid issues with shifting signed ints.36 // to avoid issues with shifting signed ints.
40 const UnInt = @IntType(false, int_bits);37 const UnInt = @IntType(false, int_bits);
41 38
42 //The maximum container int type39 //The maximum container int type
43 const MinIo = @IntType(false, min_io_bits);40 const MinIo = @IntType(false, min_io_bits);
44 41
45 //The minimum container int type42 //The minimum container int type
46 const MaxIo = @IntType(false, max_io_bits);43 const MaxIo = @IntType(false, max_io_bits);
47 44
48 return struct45 return struct {
49 {46 pub fn get(bytes: []const u8, index: usize, bit_offset: u7) Int {
50 pub fn get(bytes: []const u8, index: usize, bit_offset: u7) Int47 if (int_bits == 0) return 0;
51 {48
52 if(int_bits == 0) return 0;
53
54 const bit_index = (index * int_bits) + bit_offset;49 const bit_index = (index * int_bits) + bit_offset;
55 const max_end_byte = (bit_index + max_io_bits) / 8;50 const max_end_byte = (bit_index + max_io_bits) / 8;
56 51
57 //Using the larger container size will potentially read out of bounds52 //Using the larger container size will potentially read out of bounds
58 if(max_end_byte > bytes.len) return getBits(bytes, MinIo, bit_index);53 if (max_end_byte > bytes.len) return getBits(bytes, MinIo, bit_index);
59 return getBits(bytes, MaxIo, bit_index);54 return getBits(bytes, MaxIo, bit_index);
60 }55 }
61 56
62 fn getBits(bytes: []const u8, comptime Container: type, bit_index: usize) Int57 fn getBits(bytes: []const u8, comptime Container: type, bit_index: usize) Int {
63 {
64 const container_bits = comptime std.meta.bitCount(Container);58 const container_bits = comptime std.meta.bitCount(Container);
65 const Shift = std.math.Log2Int(Container);59 const Shift = std.math.Log2Int(Container);
66 60
67 const start_byte = bit_index / 8;61 const start_byte = bit_index / 8;
68 const head_keep_bits = bit_index - (start_byte * 8);62 const head_keep_bits = bit_index - (start_byte * 8);
69 const tail_keep_bits = container_bits - (int_bits + head_keep_bits);63 const tail_keep_bits = container_bits - (int_bits + head_keep_bits);
70 64
71 //read bytes as container65 //read bytes as container
72 const value_ptr = @ptrCast(*const align(1) Container, &bytes[start_byte]);66 const value_ptr = @ptrCast(*align(1) const Container, &bytes[start_byte]);
73 var value = value_ptr.*;67 var value = value_ptr.*;
7468
75 switch(builtin.endian)69 switch (builtin.endian) {
76 {70 .Big => {
77 .Big =>
78 {
79 value <<= @intCast(Shift, head_keep_bits);71 value <<= @intCast(Shift, head_keep_bits);
80 value >>= @intCast(Shift, head_keep_bits);72 value >>= @intCast(Shift, head_keep_bits);
81 value >>= @intCast(Shift, tail_keep_bits);73 value >>= @intCast(Shift, tail_keep_bits);
82 },74 },
83 .Little =>75 .Little => {
84 {
85 value <<= @intCast(Shift, tail_keep_bits);76 value <<= @intCast(Shift, tail_keep_bits);
86 value >>= @intCast(Shift, tail_keep_bits);77 value >>= @intCast(Shift, tail_keep_bits);
87 value >>= @intCast(Shift, head_keep_bits);78 value >>= @intCast(Shift, head_keep_bits);
88 },79 },
89 }80 }
90 81
91 return @bitCast(Int, @truncate(UnInt, value));82 return @bitCast(Int, @truncate(UnInt, value));
92 }83 }
93 84
94 pub fn set(bytes: []u8, index: usize, bit_offset: u3, int: Int) void85 pub fn set(bytes: []u8, index: usize, bit_offset: u3, int: Int) void {
95 {86 if (int_bits == 0) return;
96 if(int_bits == 0) return;
9787
98 const bit_index = (index * int_bits) + bit_offset;88 const bit_index = (index * int_bits) + bit_offset;
99 const max_end_byte = (bit_index + max_io_bits) / 8;89 const max_end_byte = (bit_index + max_io_bits) / 8;
100 90
101 //Using the larger container size will potentially write out of bounds91 //Using the larger container size will potentially write out of bounds
102 if(max_end_byte > bytes.len) return setBits(bytes, MinIo, bit_index, int);92 if (max_end_byte > bytes.len) return setBits(bytes, MinIo, bit_index, int);
103 setBits(bytes, MaxIo, bit_index, int);93 setBits(bytes, MaxIo, bit_index, int);
104 }94 }
105 95
106 fn setBits(bytes: []u8, comptime Container: type, bit_index: usize, int: Int) void96 fn setBits(bytes: []u8, comptime Container: type, bit_index: usize, int: Int) void {
107 {
108 const container_bits = comptime std.meta.bitCount(Container);97 const container_bits = comptime std.meta.bitCount(Container);
109 const Shift = std.math.Log2Int(Container);98 const Shift = std.math.Log2Int(Container);
110 99
111 const start_byte = bit_index / 8;100 const start_byte = bit_index / 8;
112 const head_keep_bits = bit_index - (start_byte * 8);101 const head_keep_bits = bit_index - (start_byte * 8);
113 const tail_keep_bits = container_bits - (int_bits + head_keep_bits);102 const tail_keep_bits = container_bits - (int_bits + head_keep_bits);
114 const keep_shift = switch(builtin.endian)103 const keep_shift = switch (builtin.endian) {
115 {
116 .Big => @intCast(Shift, tail_keep_bits),104 .Big => @intCast(Shift, tail_keep_bits),
117 .Little => @intCast(Shift, head_keep_bits),105 .Little => @intCast(Shift, head_keep_bits),
118 };106 };
119 107
120 //position the bits where they need to be in the container108 //position the bits where they need to be in the container
121 const value = @intCast(Container, @bitCast(UnInt, int)) << keep_shift;109 const value = @intCast(Container, @bitCast(UnInt, int)) << keep_shift;
122 110
123 //read existing bytes111 //read existing bytes
124 const target_ptr = @ptrCast(*align(1) Container, &bytes[start_byte]);112 const target_ptr = @ptrCast(*align(1) Container, &bytes[start_byte]);
125 var target = target_ptr.*;113 var target = target_ptr.*;
126 114
127 //zero the bits we want to replace in the existing bytes115 //zero the bits we want to replace in the existing bytes
128 const inv_mask = @intCast(Container, std.math.maxInt(UnInt)) << keep_shift;116 const inv_mask = @intCast(Container, std.math.maxInt(UnInt)) << keep_shift;
129 const mask = ~inv_mask;117 const mask = ~inv_mask;
130 target &= mask;118 target &= mask;
131 119
132 //merge the new value120 //merge the new value
133 target |= value;121 target |= value;
134 122
135 //save it back123 //save it back
136 target_ptr.* = target;124 target_ptr.* = target;
137 }125 }
138 126
139 fn slice(bytes: []u8, bit_offset: u3, start: usize, end: usize) PackedIntSlice(Int)127 fn slice(bytes: []u8, bit_offset: u3, start: usize, end: usize) PackedIntSlice(Int) {
140 {
141 debug.assert(end >= start);128 debug.assert(end >= start);
142129
143 const length = end - start;130 const length = end - start;
...@@ -145,25 +132,23 @@ pub fn PackedIntIo(comptime Int: type) type...@@ -145,25 +132,23 @@ pub fn PackedIntIo(comptime Int: type) type
145 const start_byte = bit_index / 8;132 const start_byte = bit_index / 8;
146 const end_byte = (bit_index + (length * int_bits) + 7) / 8;133 const end_byte = (bit_index + (length * int_bits) + 7) / 8;
147 const new_bytes = bytes[start_byte..end_byte];134 const new_bytes = bytes[start_byte..end_byte];
148 135
149 if(length == 0) return PackedIntSlice(Int).init(new_bytes[0..0], 0);136 if (length == 0) return PackedIntSlice(Int).init(new_bytes[0..0], 0);
150 137
151 var new_slice = PackedIntSlice(Int).init(new_bytes, length);138 var new_slice = PackedIntSlice(Int).init(new_bytes, length);
152 new_slice.bit_offset = @intCast(u3, (bit_index - (start_byte * 8)));139 new_slice.bit_offset = @intCast(u3, (bit_index - (start_byte * 8)));
153 return new_slice;140 return new_slice;
154 }141 }
155 142
156 fn sliceCast(bytes: []u8, comptime NewInt: type, bit_offset: u3, old_len: usize) 143 fn sliceCast(bytes: []u8, comptime NewInt: type, bit_offset: u3, old_len: usize) PackedIntSlice(NewInt) {
157 PackedIntSlice(NewInt)
158 {
159 const new_int_bits = comptime std.meta.bitCount(NewInt);144 const new_int_bits = comptime std.meta.bitCount(NewInt);
160 const New = PackedIntSlice(NewInt);145 const New = PackedIntSlice(NewInt);
161 146
162 const total_bits = (old_len * int_bits);147 const total_bits = (old_len * int_bits);
163 const new_int_count = total_bits / new_int_bits;148 const new_int_count = total_bits / new_int_bits;
164 149
165 debug.assert(total_bits == new_int_count * new_int_bits);150 debug.assert(total_bits == new_int_count * new_int_bits);
166 151
167 var new = New.init(bytes, new_int_count);152 var new = New.init(bytes, new_int_count);
168 new.bit_offset = bit_offset;153 new.bit_offset = bit_offset;
169 return new;154 return new;
...@@ -174,152 +159,132 @@ pub fn PackedIntIo(comptime Int: type) type...@@ -174,152 +159,132 @@ pub fn PackedIntIo(comptime Int: type) type
174///Creates a bit-packed array of integers of type Int. Bits159///Creates a bit-packed array of integers of type Int. Bits
175/// are packed using native endianess and without storing any meta160/// are packed using native endianess and without storing any meta
176/// data. PackedIntArray(i3, 8) will occupy exactly 3 bytes of memory.161/// data. PackedIntArray(i3, 8) will occupy exactly 3 bytes of memory.
177pub fn PackedIntArray(comptime Int: type, comptime int_count: usize) type162pub fn PackedIntArray(comptime Int: type, comptime int_count: usize) type {
178{
179 const int_bits = comptime std.meta.bitCount(Int);163 const int_bits = comptime std.meta.bitCount(Int);
180 const total_bits = int_bits * int_count;164 const total_bits = int_bits * int_count;
181 const total_bytes = (total_bits + 7) / 8;165 const total_bytes = (total_bits + 7) / 8;
182 166
183 const Io = PackedIntIo(Int);167 const Io = PackedIntIo(Int);
184 168
185 return struct169 return struct {
186 {
187 const Self = @This();170 const Self = @This();
188 171
189 bytes: [total_bytes]u8,172 bytes: [total_bytes]u8,
190 173
191 ///Returns the number of elements in the packed array174 ///Returns the number of elements in the packed array
192 pub fn len(self: Self) usize175 pub fn len(self: Self) usize {
193 {
194 return int_count;176 return int_count;
195 }177 }
196 178
197 ///Initialize a packed array using an unpacked array179 ///Initialize a packed array using an unpacked array
198 /// or, more likely, an array literal.180 /// or, more likely, an array literal.
199 pub fn init(ints: [int_count]Int) Self181 pub fn init(ints: [int_count]Int) Self {
200 {
201 var self = Self(undefined);182 var self = Self(undefined);
202 for(ints) |int, i| self.set(i, int);183 for (ints) |int, i| self.set(i, int);
203 return self;184 return self;
204 }185 }
205 186
206 ///Return the Int stored at index187 ///Return the Int stored at index
207 pub fn get(self: Self, index: usize) Int188 pub fn get(self: Self, index: usize) Int {
208 {
209 debug.assert(index < int_count);189 debug.assert(index < int_count);
210 return Io.get(self.bytes, index, 0);190 return Io.get(self.bytes, index, 0);
211 }191 }
212 192
213 ///Copy int into the array at index193 ///Copy int into the array at index
214 pub fn set(self: *Self, index: usize, int: Int) void194 pub fn set(self: *Self, index: usize, int: Int) void {
215 {
216 debug.assert(index < int_count);195 debug.assert(index < int_count);
217 return Io.set(&self.bytes, index, 0, int);196 return Io.set(&self.bytes, index, 0, int);
218 }197 }
219 198
220 ///Create a PackedIntSlice of the array from given start to given end199 ///Create a PackedIntSlice of the array from given start to given end
221 pub fn slice(self: *Self, start: usize, end: usize) PackedIntSlice(Int)200 pub fn slice(self: *Self, start: usize, end: usize) PackedIntSlice(Int) {
222 {
223 debug.assert(start < int_count);201 debug.assert(start < int_count);
224 debug.assert(end <= int_count);202 debug.assert(end <= int_count);
225 return Io.slice(&self.bytes, 0, start, end);203 return Io.slice(&self.bytes, 0, start, end);
226 }204 }
227 205
228 ///Create a PackedIntSlice of the array using NewInt as the bit width integer.206 ///Create a PackedIntSlice of the array using NewInt as the bit width integer.
229 /// NewInt's bit width must fit evenly within the array's Int's total bits.207 /// NewInt's bit width must fit evenly within the array's Int's total bits.
230 pub fn sliceCast(self: *Self, comptime NewInt: type) PackedIntSlice(NewInt)208 pub fn sliceCast(self: *Self, comptime NewInt: type) PackedIntSlice(NewInt) {
231 {
232 return Io.sliceCast(&self.bytes, NewInt, 0, int_count);209 return Io.sliceCast(&self.bytes, NewInt, 0, int_count);
233 }210 }
234 };211 };
235}212}
236213
237///Uses a slice as a bit-packed block of int_count integers of type Int. 214///Uses a slice as a bit-packed block of int_count integers of type Int.
238/// Bits are packed using native endianess and without storing any meta215/// Bits are packed using native endianess and without storing any meta
239/// data.216/// data.
240pub fn PackedIntSlice(comptime Int: type) type217pub fn PackedIntSlice(comptime Int: type) type {
241{
242 const int_bits = comptime std.meta.bitCount(Int);218 const int_bits = comptime std.meta.bitCount(Int);
243 const Io = PackedIntIo(Int);219 const Io = PackedIntIo(Int);
244 220
245 return struct221 return struct {
246 {
247 const Self = @This();222 const Self = @This();
248 223
249 bytes: []u8,224 bytes: []u8,
250 int_count: usize,225 int_count: usize,
251 bit_offset: u3,226 bit_offset: u3,
252 227
253 ///Returns the number of elements in the packed slice228 ///Returns the number of elements in the packed slice
254 pub fn len(self: Self) usize229 pub fn len(self: Self) usize {
255 {
256 return self.int_count;230 return self.int_count;
257 }231 }
258 232
259 ///Calculates the number of bytes required to store a desired count233 ///Calculates the number of bytes required to store a desired count
260 /// of Ints234 /// of Ints
261 pub fn bytesRequired(int_count: usize) usize235 pub fn bytesRequired(int_count: usize) usize {
262 {
263 const total_bits = int_bits * int_count;236 const total_bits = int_bits * int_count;
264 const total_bytes = (total_bits + 7) / 8;237 const total_bytes = (total_bits + 7) / 8;
265 return total_bytes;238 return total_bytes;
266 }239 }
267 240
268 ///Initialize a packed slice using the memory at bytes, with int_count241 ///Initialize a packed slice using the memory at bytes, with int_count
269 /// elements. bytes must be large enough to accomodate the requested242 /// elements. bytes must be large enough to accomodate the requested
270 /// count.243 /// count.
271 pub fn init(bytes: []u8, int_count: usize) Self244 pub fn init(bytes: []u8, int_count: usize) Self {
272 {
273 debug.assert(bytes.len >= bytesRequired(int_count));245 debug.assert(bytes.len >= bytesRequired(int_count));
274 246
275 return Self247 return Self{
276 {
277 .bytes = bytes,248 .bytes = bytes,
278 .int_count = int_count,249 .int_count = int_count,
279 .bit_offset = 0,250 .bit_offset = 0,
280 };251 };
281 }252 }
282 253
283 ///Return the Int stored at index254 ///Return the Int stored at index
284 pub fn get(self: Self, index: usize) Int255 pub fn get(self: Self, index: usize) Int {
285 {
286 debug.assert(index < self.int_count);256 debug.assert(index < self.int_count);
287 return Io.get(self.bytes, index, self.bit_offset);257 return Io.get(self.bytes, index, self.bit_offset);
288 }258 }
289 259
290 ///Copy int into the array at index260 ///Copy int into the array at index
291 pub fn set(self: *Self, index: usize, int: Int) void261 pub fn set(self: *Self, index: usize, int: Int) void {
292 {
293 debug.assert(index < self.int_count);262 debug.assert(index < self.int_count);
294 return Io.set(self.bytes, index, self.bit_offset, int);263 return Io.set(self.bytes, index, self.bit_offset, int);
295 }264 }
296 265
297 ///Create a PackedIntSlice of this slice from given start to given end266 ///Create a PackedIntSlice of this slice from given start to given end
298 pub fn slice(self: Self, start: usize, end: usize) PackedIntSlice(Int)267 pub fn slice(self: Self, start: usize, end: usize) PackedIntSlice(Int) {
299 {
300 debug.assert(start < self.int_count);268 debug.assert(start < self.int_count);
301 debug.assert(end <= self.int_count);269 debug.assert(end <= self.int_count);
302 return Io.slice(self.bytes, self.bit_offset, start, end);270 return Io.slice(self.bytes, self.bit_offset, start, end);
303 }271 }
304 272
305 ///Create a PackedIntSlice of this slice using NewInt as the bit width integer.273 ///Create a PackedIntSlice of this slice using NewInt as the bit width integer.
306 /// NewInt's bit width must fit evenly within this slice's Int's total bits.274 /// NewInt's bit width must fit evenly within this slice's Int's total bits.
307 pub fn sliceCast(self: Self, comptime NewInt: type) PackedIntSlice(NewInt)275 pub fn sliceCast(self: Self, comptime NewInt: type) PackedIntSlice(NewInt) {
308 {
309 return Io.sliceCast(self.bytes, NewInt, self.bit_offset, self.int_count);276 return Io.sliceCast(self.bytes, NewInt, self.bit_offset, self.int_count);
310 }277 }
311 };278 };
312}279}
313280
314test "PackedIntArray"281test "PackedIntArray" {
315{
316 @setEvalBranchQuota(10000);282 @setEvalBranchQuota(10000);
317 const max_bits = 256;283 const max_bits = 256;
318 const int_count = 19;284 const int_count = 19;
319 285
320 comptime var bits = 0;286 comptime var bits = 0;
321 inline while(bits <= 256):(bits += 1)287 inline while (bits <= 256) : (bits += 1) {
322 {
323 //alternate unsigned and signed288 //alternate unsigned and signed
324 const even = bits % 2 == 0;289 const even = bits % 2 == 0;
325 const I = @IntType(even, bits);290 const I = @IntType(even, bits);
...@@ -327,100 +292,90 @@ test "PackedIntArray"...@@ -327,100 +292,90 @@ test "PackedIntArray"
327 const PackedArray = PackedIntArray(I, int_count);292 const PackedArray = PackedIntArray(I, int_count);
328 const expected_bytes = ((bits * int_count) + 7) / 8;293 const expected_bytes = ((bits * int_count) + 7) / 8;
329 testing.expect(@sizeOf(PackedArray) == expected_bytes);294 testing.expect(@sizeOf(PackedArray) == expected_bytes);
330 295
331 var data = PackedArray(undefined);296 var data = PackedArray(undefined);
332 297
333 //write values, counting up298 //write values, counting up
334 var i = usize(0);299 var i = usize(0);
335 var count = I(0);300 var count = I(0);
336 while(i < data.len()):(i += 1)301 while (i < data.len()) : (i += 1) {
337 {
338 data.set(i, count);302 data.set(i, count);
339 if(bits > 0) count +%= 1;303 if (bits > 0) count +%= 1;
340 }304 }
341 305
342 //read and verify values306 //read and verify values
343 i = 0;307 i = 0;
344 count = 0;308 count = 0;
345 while(i < data.len()):(i += 1)309 while (i < data.len()) : (i += 1) {
346 {
347 const val = data.get(i);310 const val = data.get(i);
348 testing.expect(val == count);311 testing.expect(val == count);
349 if(bits > 0) count +%= 1;312 if (bits > 0) count +%= 1;
350 }313 }
351 }314 }
352}315}
353316
354test "PackedIntArray init"317test "PackedIntArray init" {
355{
356 const PackedArray = PackedIntArray(u3, 8);318 const PackedArray = PackedIntArray(u3, 8);
357 var packed_array = PackedArray.init([]u3{0,1,2,3,4,5,6,7});319 var packed_array = PackedArray.init([]u3{ 0, 1, 2, 3, 4, 5, 6, 7 });
358 var i = usize(0);320 var i = usize(0);
359 while(i < packed_array.len()):(i += 1) testing.expect(packed_array.get(i) == i);321 while (i < packed_array.len()) : (i += 1) testing.expect(packed_array.get(i) == i);
360}322}
361323
362test "PackedIntSlice"324test "PackedIntSlice" {
363{
364 @setEvalBranchQuota(10000);325 @setEvalBranchQuota(10000);
365 const max_bits = 256;326 const max_bits = 256;
366 const int_count = 19;327 const int_count = 19;
367 const total_bits = max_bits * int_count;328 const total_bits = max_bits * int_count;
368 const total_bytes = (total_bits + 7) / 8;329 const total_bytes = (total_bits + 7) / 8;
369 330
370 var buffer: [total_bytes]u8 = undefined;331 var buffer: [total_bytes]u8 = undefined;
371 332
372 comptime var bits = 0;333 comptime var bits = 0;
373 inline while(bits <= 256):(bits += 1)334 inline while (bits <= 256) : (bits += 1) {
374 {
375 //alternate unsigned and signed335 //alternate unsigned and signed
376 const even = bits % 2 == 0;336 const even = bits % 2 == 0;
377 const I = @IntType(even, bits);337 const I = @IntType(even, bits);
378 const P = PackedIntSlice(I);338 const P = PackedIntSlice(I);
379 339
380 var data = P.init(&buffer, int_count);340 var data = P.init(&buffer, int_count);
381 341
382 //write values, counting up342 //write values, counting up
383 var i = usize(0);343 var i = usize(0);
384 var count = I(0);344 var count = I(0);
385 while(i < data.len()):(i += 1)345 while (i < data.len()) : (i += 1) {
386 {
387 data.set(i, count);346 data.set(i, count);
388 if(bits > 0) count +%= 1;347 if (bits > 0) count +%= 1;
389 }348 }
390 349
391 //read and verify values350 //read and verify values
392 i = 0;351 i = 0;
393 count = 0;352 count = 0;
394 while(i < data.len()):(i += 1)353 while (i < data.len()) : (i += 1) {
395 {
396 const val = data.get(i);354 const val = data.get(i);
397 testing.expect(val == count);355 testing.expect(val == count);
398 if(bits > 0) count +%= 1;356 if (bits > 0) count +%= 1;
399 }357 }
400 }358 }
401}359}
402360
403test "PackedIntSlice of PackedInt(Array/Slice)"361test "PackedIntSlice of PackedInt(Array/Slice)" {
404{
405 const max_bits = 16;362 const max_bits = 16;
406 const int_count = 19;363 const int_count = 19;
407 364
408 comptime var bits = 0;365 comptime var bits = 0;
409 inline while(bits <= max_bits):(bits += 1)366 inline while (bits <= max_bits) : (bits += 1) {
410 {
411 const Int = @IntType(false, bits);367 const Int = @IntType(false, bits);
412 368
413 const PackedArray = PackedIntArray(Int, int_count);369 const PackedArray = PackedIntArray(Int, int_count);
414 var packed_array = PackedArray(undefined);370 var packed_array = PackedArray(undefined);
415 371
416 const limit = (1 << bits);372 const limit = (1 << bits);
417 373
418 var i = usize(0);374 var i = usize(0);
419 while(i < packed_array.len()):(i += 1)375 while (i < packed_array.len()) : (i += 1) {
420 {
421 packed_array.set(i, @intCast(Int, i % limit));376 packed_array.set(i, @intCast(Int, i % limit));
422 }377 }
423 378
424 //slice of array379 //slice of array
425 var packed_slice = packed_array.slice(2, 5);380 var packed_slice = packed_array.slice(2, 5);
426 testing.expect(packed_slice.len() == 3);381 testing.expect(packed_slice.len() == 3);
...@@ -432,10 +387,10 @@ test "PackedIntSlice of PackedInt(Array/Slice)"...@@ -432,10 +387,10 @@ test "PackedIntSlice of PackedInt(Array/Slice)"
432 testing.expect(packed_slice.get(2) == 4 % limit);387 testing.expect(packed_slice.get(2) == 4 % limit);
433 packed_slice.set(1, 7 % limit);388 packed_slice.set(1, 7 % limit);
434 testing.expect(packed_slice.get(1) == 7 % limit);389 testing.expect(packed_slice.get(1) == 7 % limit);
435 390
436 //write through slice391 //write through slice
437 testing.expect(packed_array.get(3) == 7 % limit);392 testing.expect(packed_array.get(3) == 7 % limit);
438 393
439 //slice of a slice394 //slice of a slice
440 const packed_slice_two = packed_slice.slice(0, 3);395 const packed_slice_two = packed_slice.slice(0, 3);
441 testing.expect(packed_slice_two.len() == 3);396 testing.expect(packed_slice_two.len() == 3);
...@@ -444,7 +399,7 @@ test "PackedIntSlice of PackedInt(Array/Slice)"...@@ -444,7 +399,7 @@ test "PackedIntSlice of PackedInt(Array/Slice)"
444 testing.expect(packed_slice_two.bytes.len == ps2_expected_bytes);399 testing.expect(packed_slice_two.bytes.len == ps2_expected_bytes);
445 testing.expect(packed_slice_two.get(1) == 7 % limit);400 testing.expect(packed_slice_two.get(1) == 7 % limit);
446 testing.expect(packed_slice_two.get(2) == 4 % limit);401 testing.expect(packed_slice_two.get(2) == 4 % limit);
447 402
448 //size one case403 //size one case
449 const packed_slice_three = packed_slice_two.slice(1, 2);404 const packed_slice_three = packed_slice_two.slice(1, 2);
450 testing.expect(packed_slice_three.len() == 1);405 testing.expect(packed_slice_three.len() == 1);
...@@ -452,12 +407,12 @@ test "PackedIntSlice of PackedInt(Array/Slice)"...@@ -452,12 +407,12 @@ test "PackedIntSlice of PackedInt(Array/Slice)"
452 const ps3_expected_bytes = (ps3_bit_count + 7) / 8;407 const ps3_expected_bytes = (ps3_bit_count + 7) / 8;
453 testing.expect(packed_slice_three.bytes.len == ps3_expected_bytes);408 testing.expect(packed_slice_three.bytes.len == ps3_expected_bytes);
454 testing.expect(packed_slice_three.get(0) == 7 % limit);409 testing.expect(packed_slice_three.get(0) == 7 % limit);
455 410
456 //empty slice case411 //empty slice case
457 const packed_slice_empty = packed_slice.slice(0, 0);412 const packed_slice_empty = packed_slice.slice(0, 0);
458 testing.expect(packed_slice_empty.len() == 0);413 testing.expect(packed_slice_empty.len() == 0);
459 testing.expect(packed_slice_empty.bytes.len == 0);414 testing.expect(packed_slice_empty.bytes.len == 0);
460 415
461 //slicing at byte boundaries416 //slicing at byte boundaries
462 const packed_slice_edge = packed_array.slice(8, 16);417 const packed_slice_edge = packed_array.slice(8, 16);
463 testing.expect(packed_slice_edge.len() == 8);418 testing.expect(packed_slice_edge.len() == 8);
...@@ -466,84 +421,70 @@ test "PackedIntSlice of PackedInt(Array/Slice)"...@@ -466,84 +421,70 @@ test "PackedIntSlice of PackedInt(Array/Slice)"
466 testing.expect(packed_slice_edge.bytes.len == pse_expected_bytes);421 testing.expect(packed_slice_edge.bytes.len == pse_expected_bytes);
467 testing.expect(packed_slice_edge.bit_offset == 0);422 testing.expect(packed_slice_edge.bit_offset == 0);
468 }423 }
469
470}424}
471425
472test "PackedIntSlice accumulating bit offsets"426test "PackedIntSlice accumulating bit offsets" {
473{
474 //bit_offset is u3, so standard debugging asserts should catch427 //bit_offset is u3, so standard debugging asserts should catch
475 // anything428 // anything
476 {429 {
477 const PackedArray = PackedIntArray(u3, 16);430 const PackedArray = PackedIntArray(u3, 16);
478 var packed_array = PackedArray(undefined);431 var packed_array = PackedArray(undefined);
479 432
480 var packed_slice = packed_array.slice(0, packed_array.len());433 var packed_slice = packed_array.slice(0, packed_array.len());
481 var i = usize(0);434 var i = usize(0);
482 while(i < packed_array.len() - 1):(i += 1)435 while (i < packed_array.len() - 1) : (i += 1) {
483 {
484
485 packed_slice = packed_slice.slice(1, packed_slice.len());436 packed_slice = packed_slice.slice(1, packed_slice.len());
486 }437 }
487 }438 }
488 {439 {
489 const PackedArray = PackedIntArray(u11, 88);440 const PackedArray = PackedIntArray(u11, 88);
490 var packed_array = PackedArray(undefined);441 var packed_array = PackedArray(undefined);
491 442
492 var packed_slice = packed_array.slice(0, packed_array.len());443 var packed_slice = packed_array.slice(0, packed_array.len());
493 var i = usize(0);444 var i = usize(0);
494 while(i < packed_array.len() - 1):(i += 1)445 while (i < packed_array.len() - 1) : (i += 1) {
495 {
496 packed_slice = packed_slice.slice(1, packed_slice.len());446 packed_slice = packed_slice.slice(1, packed_slice.len());
497 }447 }
498 }448 }
499
500}449}
501450
502//@NOTE: As I do not have a big endian system to test this on,451//@NOTE: As I do not have a big endian system to test this on,
503// big endian values were not tested452// big endian values were not tested
504test "PackedInt(Array/Slice) sliceCast"453test "PackedInt(Array/Slice) sliceCast" {
505{
506 const PackedArray = PackedIntArray(u1, 16);454 const PackedArray = PackedIntArray(u1, 16);
507 var packed_array = PackedArray.init([]u1{0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1});455 var packed_array = PackedArray.init([]u1{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 });
508 const packed_slice_cast_2 = packed_array.sliceCast(u2);456 const packed_slice_cast_2 = packed_array.sliceCast(u2);
509 const packed_slice_cast_4 = packed_slice_cast_2.sliceCast(u4);457 const packed_slice_cast_4 = packed_slice_cast_2.sliceCast(u4);
510 var packed_slice_cast_9 = packed_array.slice(0, (packed_array.len() / 9) * 9).sliceCast(u9);458 var packed_slice_cast_9 = packed_array.slice(0, (packed_array.len() / 9) * 9).sliceCast(u9);
511 const packed_slice_cast_3 = packed_slice_cast_9.sliceCast(u3);459 const packed_slice_cast_3 = packed_slice_cast_9.sliceCast(u3);
512 460
513 var i = usize(0);461 var i = usize(0);
514 while(i < packed_slice_cast_2.len()):(i += 1)462 while (i < packed_slice_cast_2.len()) : (i += 1) {
515 {463 const val = switch (builtin.endian) {
516 const val = switch(builtin.endian)
517 {
518 .Big => 0b01,464 .Big => 0b01,
519 .Little => 0b10,465 .Little => 0b10,
520 };466 };
521 testing.expect(packed_slice_cast_2.get(i) == val);467 testing.expect(packed_slice_cast_2.get(i) == val);
522 }468 }
523 i = 0;469 i = 0;
524 while(i < packed_slice_cast_4.len()):(i += 1)470 while (i < packed_slice_cast_4.len()) : (i += 1) {
525 {471 const val = switch (builtin.endian) {
526 const val = switch(builtin.endian)
527 {
528 .Big => 0b0101,472 .Big => 0b0101,
529 .Little => 0b1010,473 .Little => 0b1010,
530 };474 };
531 testing.expect(packed_slice_cast_4.get(i) == val);475 testing.expect(packed_slice_cast_4.get(i) == val);
532 }476 }
533 i = 0;477 i = 0;
534 while(i < packed_slice_cast_9.len()):(i += 1)478 while (i < packed_slice_cast_9.len()) : (i += 1) {
535 {
536 const val = 0b010101010;479 const val = 0b010101010;
537 testing.expect(packed_slice_cast_9.get(i) == val);480 testing.expect(packed_slice_cast_9.get(i) == val);
538 packed_slice_cast_9.set(i, 0b111000111);481 packed_slice_cast_9.set(i, 0b111000111);
539 }482 }
540 i = 0;483 i = 0;
541 while(i < packed_slice_cast_3.len()):(i += 1)484 while (i < packed_slice_cast_3.len()) : (i += 1) {
542 {485 const val = switch (builtin.endian) {
543 const val = switch(builtin.endian)486 .Big => if (i % 2 == 0) u3(0b111) else u3(0b000),
544 {487 .Little => if (i % 2 == 0) u3(0b111) else u3(0b000),
545 .Big => if(i % 2 == 0) u3(0b111) else u3(0b000),
546 .Little => if(i % 2 == 0) u3(0b111) else u3(0b000),
547 };488 };
548 testing.expect(packed_slice_cast_3.get(i) == val);489 testing.expect(packed_slice_cast_3.get(i) == val);
549 }490 }
...@@ -558,44 +499,39 @@ test "PackedInt(Array/Slice) sliceCast"...@@ -558,44 +499,39 @@ test "PackedInt(Array/Slice) sliceCast"
558// and reading the last element. The assumption is that the page499// and reading the last element. The assumption is that the page
559// after this one is not mapped and will cause a segfault if we500// after this one is not mapped and will cause a segfault if we
560// don't account for the bounds.501// don't account for the bounds.
561test "PackedIntArray at end of available memory"502test "PackedIntArray at end of available memory" {
562{503 switch (builtin.os) {
563 switch(builtin.os)
564 {
565 .linux, .macosx, .ios, .freebsd, .netbsd => {},504 .linux, .macosx, .ios, .freebsd, .netbsd => {},
566 else => return,505 else => return,
567 }506 }
568 const PackedArray = PackedIntArray(u3, 8);507 const PackedArray = PackedIntArray(u3, 8);
569 508
570 const Padded = struct509 const Padded = struct {
571 {
572 _: [std.os.page_size - @sizeOf(PackedArray)]u8,510 _: [std.os.page_size - @sizeOf(PackedArray)]u8,
573 p: PackedArray,511 p: PackedArray,
574 };512 };
575 513
576 var da = std.heap.DirectAllocator.init();514 var da = std.heap.DirectAllocator.init();
577 const allocator = &da.allocator;515 const allocator = &da.allocator;
578 516
579 var pad = try allocator.create(Padded);517 var pad = try allocator.create(Padded);
580 defer allocator.destroy(pad);518 defer allocator.destroy(pad);
581 pad.p.set(7, std.math.maxInt(u3));519 pad.p.set(7, std.math.maxInt(u3));
582}520}
583521
584test "PackedIntSlice at end of available memory"522test "PackedIntSlice at end of available memory" {
585{523 switch (builtin.os) {
586 switch(builtin.os)
587 {
588 .linux, .macosx, .ios, .freebsd, .netbsd => {},524 .linux, .macosx, .ios, .freebsd, .netbsd => {},
589 else => return,525 else => return,
590 }526 }
591 const PackedSlice = PackedIntSlice(u11);527 const PackedSlice = PackedIntSlice(u11);
592 528
593 var da = std.heap.DirectAllocator.init();529 var da = std.heap.DirectAllocator.init();
594 const allocator = &da.allocator;530 const allocator = &da.allocator;
595 531
596 var page = try allocator.alloc(u8, std.os.page_size);532 var page = try allocator.alloc(u8, std.os.page_size);
597 defer allocator.free(page);533 defer allocator.free(page);
598 534
599 var p = PackedSlice.init(page[std.os.page_size - 2..], 1);535 var p = PackedSlice.init(page[std.os.page_size - 2 ..], 1);
600 p.set(0, std.math.maxInt(u11));536 p.set(0, std.math.maxInt(u11));
601}537}