1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
//
// We've already learned about switch statements in exercises 030, 031 and 111.
// They also work with packed containers:
const S = packed struct(u2) {
a: bool,
b: i1,
};
// Try to make it compile without adding an `else` prong!
comptime {
const s: S = .{ .a = true, .b = -1 };
switch (s) {
.{ .a = true, .b = -1 } => {}, // ok!
.{ .a = true, .b = ??? },
.{ .a = ???, .b = 0 },
.{ .a = ???, .b = ??? },
=> @compileError("We don't want to end up here!"),
}
}
// As we can see, switching on packed structs is pretty straightforward.
// When switching on packed unions however, we'll realize that a packed
// union never keeps track of its active tag, not even in debug mode! This
// means that packed unions compare solely by their bit pattern (again, just
// like integers).
const U = packed union(u2) {
a: u2,
b: i2,
};
// Find and remove the duplicate case!
comptime {
const u: U = .{ .a = 3 };
switch (u) {
.{ .a = 3 } => {}, // ok!
.{ .a = 2 },
.{ .b = 1 },
.{ .b = -1 },
.{ .a = 0 },
=> @compileError("We don't want to end up here!"),
}
}
// Since packed unions don't have the concept of an active tag, it's always legal
// to access any of their fields. This can be useful to view the same data from
// different perspectives seamlessly.
//
// Try to make the float below negative:
/// IEEE 754 half precision float
const Float = packed union(u16) {
value: f16,
bits: packed struct(u16) {
mantissa: u10,
exponent: u5,
sign: u1,
},
};
pub fn main() void {
// Reminder: if the sign bit of a float is set, the number is negative!
var number: Float = .{ .value = 2.34 };
number.bits.??? = ???;
if (number.value != -2.34) {
std.debug.print("Make it negative!\n", .{});
}
}
// This concludes our introduction to packed containers. The next time you need
// control over individual bits, keep them in mind as a potent alternative!
//
const std = @import("std");
|