|
@@ -0,0 +1,121 @@
|
|
|
+//
|
|
|
+// A sentinel value indicates the end of data. Let's imagine a
|
|
|
+// sequence of lowercase letters where uppercase 'S' is the
|
|
|
+// sentinel, indicating the end of the sequence:
|
|
|
+//
|
|
|
+// abcdefS
|
|
|
+//
|
|
|
+// If our sequence also allows for uppercase letters, 'S' would
|
|
|
+// make a terrible sentinel since it could no longer be a regular
|
|
|
+// value in the sequence:
|
|
|
+//
|
|
|
+// abcdQRST
|
|
|
+// ^-- Oops! The last letter in the sequence is R!
|
|
|
+//
|
|
|
+// A popular choice for indicating the end of a string is the
|
|
|
+// value 0. ASCII and Unicode call this the "Null Character".
|
|
|
+//
|
|
|
+// Zig supports sentinel-terminated arrays, slices, and pointers:
|
|
|
+//
|
|
|
+// const a: [4:0]u32 = [4:0]u32{1, 2, 3, 4};
|
|
|
+// const b: [:0]const u32 = &[4:0]u32{1, 2, 3, 4};
|
|
|
+// const c: [*:0]const u32 = &[4:0]u32{1, 2, 3, 4};
|
|
|
+//
|
|
|
+// Array 'a' stores 5 u32 values, the last of which is 0.
|
|
|
+// However the compiler takes care of this housekeeping detail
|
|
|
+// for you. You can treat 'a' as a normal array with just 4
|
|
|
+// items.
|
|
|
+//
|
|
|
+// Slice 'b' is only allowed to point to zero-terminated arrays
|
|
|
+// but otherwise works just like a normal slice.
|
|
|
+//
|
|
|
+// Pointer 'c' is exactly like the many-pointers we learned about
|
|
|
+// in exercise 054, but it is guaranteed to end in 0. Because of
|
|
|
+// this guarantee, we can safely find the end of this
|
|
|
+// many-pointer without knowing its length. (We CAN'T do that
|
|
|
+// with regular many-pointers!).
|
|
|
+//
|
|
|
+const print = @import("std").debug.print;
|
|
|
+
|
|
|
+pub fn main() void {
|
|
|
+ // Here's a zero-terminated array of u32 values:
|
|
|
+ var nums = [_:0]u32{ 1, 2, 3, 4, 5, 6 };
|
|
|
+
|
|
|
+ // And here's a zero-terminated many-pointer:
|
|
|
+ var ptr: [*:0]u32 = &nums;
|
|
|
+
|
|
|
+ // For fun, let's replace the value at position 3 with the
|
|
|
+ // sentinel value 0. This seems kind of naughty.
|
|
|
+ nums[3] = 0;
|
|
|
+
|
|
|
+ // So now we have a zero-terminated array and a many-pointer
|
|
|
+ // that reference the same data: a sequence of numbers that
|
|
|
+ // both ends in and CONTAINS the sentinal value.
|
|
|
+ //
|
|
|
+ // Attempting to loop through and print both of these should
|
|
|
+ // demonstrate how they are similar and different.
|
|
|
+ //
|
|
|
+ // (It turns out that the array prints completely, including
|
|
|
+ // the sentinel 0 in the middle. The many-pointer must stop
|
|
|
+ // at the first sentinel value. The difference is simply that
|
|
|
+ // arrays have a known length and many-pointers don't.)
|
|
|
+ printSequence(nums);
|
|
|
+ printSequence(ptr);
|
|
|
+
|
|
|
+ print("\n", .{});
|
|
|
+}
|
|
|
+
|
|
|
+// Here's our generic sequence printing function. It's nearly
|
|
|
+// complete, but there are a couple missing bits. Please fix
|
|
|
+// them!
|
|
|
+fn printSequence(my_seq: anytype) void {
|
|
|
+ const my_type = @typeInfo(@TypeOf(my_seq));
|
|
|
+
|
|
|
+ // The TypeInfo contained in my_type is a union. We use a
|
|
|
+ // switch to handle printing the Array or Pointer fields,
|
|
|
+ // depending on which type of my_seq was passed in:
|
|
|
+ switch (my_type) {
|
|
|
+ .Array => {
|
|
|
+ print("Array:", .{});
|
|
|
+
|
|
|
+ // Loop through the items in my_seq.
|
|
|
+ for (???) |s| {
|
|
|
+ print("{}", .{s});
|
|
|
+ }
|
|
|
+ },
|
|
|
+ .Pointer => {
|
|
|
+ // Check this out - it's pretty cool:
|
|
|
+ const my_sentinel = my_type.Pointer.sentinel;
|
|
|
+ print("Many-pointer:", .{});
|
|
|
+
|
|
|
+ // Loop through the items in my_seq until we hit the
|
|
|
+ // sentinel value.
|
|
|
+ var i: usize = 0;
|
|
|
+ while (??? != my_sentinel) {
|
|
|
+ print("{}", .{my_seq[i]});
|
|
|
+ i += 1;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ else => unreachable,
|
|
|
+ }
|
|
|
+ print(". ", .{});
|
|
|
+}
|
|
|
+//
|
|
|
+// ------------------------------------------------------------
|
|
|
+// TOP SECRET TOP SECRET TOP SECRET TOP SECRET TOP SECRET
|
|
|
+// ------------------------------------------------------------
|
|
|
+//
|
|
|
+// Are you ready for the THE TRUTH about Zig string literals?
|
|
|
+//
|
|
|
+// You've earned it. Here it is:
|
|
|
+//
|
|
|
+// @TypeOf("foo") == *const [3:0]u8
|
|
|
+//
|
|
|
+// Zig's string literals are constant pointers to zero-terminated
|
|
|
+// (or "null-terminated") arrays of u8.
|
|
|
+//
|
|
|
+// Now you know. Welcome to the secret club!
|
|
|
+//
|
|
|
+// ------------------------------------------------------------
|
|
|
+// TOP SECRET TOP SECRET TOP SECRET TOP SECRET TOP SECRET
|
|
|
+// ------------------------------------------------------------
|