076_sentinels.zig 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. //
  2. // A sentinel value indicates the end of data. Let's imagine a
  3. // sequence of lowercase letters where uppercase 'S' is the
  4. // sentinel, indicating the end of the sequence:
  5. //
  6. // abcdefS
  7. //
  8. // If our sequence also allows for uppercase letters, 'S' would
  9. // make a terrible sentinel since it could no longer be a regular
  10. // value in the sequence:
  11. //
  12. // abcdQRST
  13. // ^-- Oops! The last letter in the sequence is R!
  14. //
  15. // A popular choice for indicating the end of a string is the
  16. // value 0. ASCII and Unicode call this the "Null Character".
  17. //
  18. // Zig supports sentinel-terminated arrays, slices, and pointers:
  19. //
  20. // const a: [4:0]u32 = [4:0]u32{1, 2, 3, 4};
  21. // const b: [:0]const u32 = &[4:0]u32{1, 2, 3, 4};
  22. // const c: [*:0]const u32 = &[4:0]u32{1, 2, 3, 4};
  23. //
  24. // Array 'a' stores 5 u32 values, the last of which is 0.
  25. // However the compiler takes care of this housekeeping detail
  26. // for you. You can treat 'a' as a normal array with just 4
  27. // items.
  28. //
  29. // Slice 'b' is only allowed to point to zero-terminated arrays
  30. // but otherwise works just like a normal slice.
  31. //
  32. // Pointer 'c' is exactly like the many-pointers we learned about
  33. // in exercise 054, but it is guaranteed to end in 0. Because of
  34. // this guarantee, we can safely find the end of this
  35. // many-pointer without knowing its length. (We CAN'T do that
  36. // with regular many-pointers!).
  37. //
  38. const print = @import("std").debug.print;
  39. pub fn main() void {
  40. // Here's a zero-terminated array of u32 values:
  41. var nums = [_:0]u32{ 1, 2, 3, 4, 5, 6 };
  42. // And here's a zero-terminated many-pointer:
  43. var ptr: [*:0]u32 = &nums;
  44. // For fun, let's replace the value at position 3 with the
  45. // sentinel value 0. This seems kind of naughty.
  46. nums[3] = 0;
  47. // So now we have a zero-terminated array and a many-pointer
  48. // that reference the same data: a sequence of numbers that
  49. // both ends in and CONTAINS the sentinal value.
  50. //
  51. // Attempting to loop through and print both of these should
  52. // demonstrate how they are similar and different.
  53. //
  54. // (It turns out that the array prints completely, including
  55. // the sentinel 0 in the middle. The many-pointer must stop
  56. // at the first sentinel value. The difference is simply that
  57. // arrays have a known length and many-pointers don't.)
  58. printSequence(nums);
  59. printSequence(ptr);
  60. print("\n", .{});
  61. }
  62. // Here's our generic sequence printing function. It's nearly
  63. // complete, but there are a couple missing bits. Please fix
  64. // them!
  65. fn printSequence(my_seq: anytype) void {
  66. const my_type = @typeInfo(@TypeOf(my_seq));
  67. // The TypeInfo contained in my_type is a union. We use a
  68. // switch to handle printing the Array or Pointer fields,
  69. // depending on which type of my_seq was passed in:
  70. switch (my_type) {
  71. .Array => {
  72. print("Array:", .{});
  73. // Loop through the items in my_seq.
  74. for (???) |s| {
  75. print("{}", .{s});
  76. }
  77. },
  78. .Pointer => {
  79. // Check this out - it's pretty cool:
  80. const my_sentinel = my_type.Pointer.sentinel;
  81. print("Many-pointer:", .{});
  82. // Loop through the items in my_seq until we hit the
  83. // sentinel value.
  84. var i: usize = 0;
  85. while (??? != my_sentinel) {
  86. print("{}", .{my_seq[i]});
  87. i += 1;
  88. }
  89. },
  90. else => unreachable,
  91. }
  92. print(". ", .{});
  93. }
  94. //
  95. // ------------------------------------------------------------
  96. // TOP SECRET TOP SECRET TOP SECRET TOP SECRET TOP SECRET
  97. // ------------------------------------------------------------
  98. //
  99. // Are you ready for the THE TRUTH about Zig string literals?
  100. //
  101. // You've earned it. Here it is:
  102. //
  103. // @TypeOf("foo") == *const [3:0]u8
  104. //
  105. // Zig's string literals are constant pointers to zero-terminated
  106. // (or "null-terminated") arrays of u8.
  107. //
  108. // Now you know. Welcome to the secret club!
  109. //
  110. // ------------------------------------------------------------
  111. // TOP SECRET TOP SECRET TOP SECRET TOP SECRET TOP SECRET
  112. // ------------------------------------------------------------