Browse Source

add ex076 sentinels

Dave Gauer 4 years ago
parent
commit
e9547cf808
4 changed files with 134 additions and 1 deletions
  1. 1 1
      README.md
  2. 4 0
      build.zig
  3. 121 0
      exercises/076_sentinels.zig
  4. 8 0
      patches/patches/076_sentinels.patch

+ 1 - 1
README.md

@@ -146,8 +146,8 @@ Core Language
 * [x] Builtins
 * [x] Builtins
 * [x] Inline loops
 * [x] Inline loops
 * [x] Comptime
 * [x] Comptime
+* [x] Sentinel termination
 * [ ] Anonymous structs
 * [ ] Anonymous structs
-* [ ] Sentinel termination
 * [ ] Suspend / Resume
 * [ ] Suspend / Resume
 * [ ] Async / Await
 * [ ] Async / Await
 * [ ] Nosuspend
 * [ ] Nosuspend

+ 4 - 0
build.zig

@@ -379,6 +379,10 @@ const exercises = [_]Exercise{
         .output = "Archer's Point--2->Bridge--1->Dogwood Grove--3->Cottage--2->East Pond--1->Fox Pond",
         .output = "Archer's Point--2->Bridge--1->Dogwood Grove--3->Cottage--2->East Pond--1->Fox Pond",
         .hint = "Roll up those sleeves. You get to WRITE some code for this one.",
         .hint = "Roll up those sleeves. You get to WRITE some code for this one.",
     },
     },
+    .{
+        .main_file = "076_sentinels.zig",
+        .output = "Array:123056. Many-pointer:123.",
+    },
 };
 };
 
 
 /// Check the zig version to make sure it can compile the examples properly.
 /// Check the zig version to make sure it can compile the examples properly.

+ 121 - 0
exercises/076_sentinels.zig

@@ -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
+// ------------------------------------------------------------

+ 8 - 0
patches/patches/076_sentinels.patch

@@ -0,0 +1,8 @@
+82c82
+<             for (???) |s| {
+---
+>             for (my_seq) |s| {
+94c94
+<             while (??? != my_sentinel) {
+---
+>             while (my_seq[i] != my_sentinel) {