| ... | ... | @@ -2523,19 +2523,28 @@ test "multidimensional arrays" { |
| 2523 | 2523 | {#header_open|Sentinel-Terminated Arrays#} |
| 2524 | 2524 | <p> |
| 2525 | 2525 | The syntax {#syntax#}[N:x]T{#endsyntax#} describes an array which has a sentinel element of value {#syntax#}x{#endsyntax#} at the |
| 2526 | | index corresponding to {#syntax#}len{#endsyntax#}. |
| 2526 | index corresponding to the length {#syntax#}N{#endsyntax#}. |
| 2527 | 2527 | </p> |
| 2528 | 2528 | {#code_begin|test|test_null_terminated_array#} |
| 2529 | 2529 | const std = @import("std"); |
| 2530 | 2530 | const expect = std.testing.expect; |
| 2531 | 2531 | |
| 2532 | | test "null terminated array" { |
| 2532 | test "0-terminated sentinel array" { |
| 2533 | 2533 | const array = [_:0]u8 {1, 2, 3, 4}; |
| 2534 | 2534 | |
| 2535 | 2535 | try expect(@TypeOf(array) == [4:0]u8); |
| 2536 | 2536 | try expect(array.len == 4); |
| 2537 | 2537 | try expect(array[4] == 0); |
| 2538 | 2538 | } |
| 2539 | |
| 2540 | test "extra 0s in 0-terminated sentinel array" { |
| 2541 | // The sentinel value may appear earlier, but does not influence the compile-time 'len'. |
| 2542 | const array = [_:0]u8 {1, 0, 0, 4}; |
| 2543 | |
| 2544 | try expect(@TypeOf(array) == [4:0]u8); |
| 2545 | try expect(array.len == 4); |
| 2546 | try expect(array[4] == 0); |
| 2547 | } |
| 2539 | 2548 | {#code_end#} |
| 2540 | 2549 | {#see_also|Sentinel-Terminated Pointers|Sentinel-Terminated Slices#} |
| 2541 | 2550 | {#header_close#} |
| ... | ... | @@ -3052,8 +3061,6 @@ test "using slices for strings" { |
| 3052 | 3061 | } |
| 3053 | 3062 | |
| 3054 | 3063 | test "slice pointer" { |
| 3055 | | var a: []u8 = undefined; |
| 3056 | | try expect(@TypeOf(a) == []u8); |
| 3057 | 3064 | var array: [10]u8 = undefined; |
| 3058 | 3065 | const ptr = &array; |
| 3059 | 3066 | try expect(@TypeOf(ptr) == *[10]u8); |
| ... | ... | @@ -3062,10 +3069,10 @@ test "slice pointer" { |
| 3062 | 3069 | var start: usize = 0; |
| 3063 | 3070 | var end: usize = 5; |
| 3064 | 3071 | const slice = ptr[start..end]; |
| 3065 | | slice[2] = 3; |
| 3066 | | try expect(slice[2] == 3); |
| 3067 | 3072 | // The slice is mutable because we sliced a mutable pointer. |
| 3068 | 3073 | try expect(@TypeOf(slice) == []u8); |
| 3074 | slice[2] = 3; |
| 3075 | try expect(array[2] == 3); |
| 3069 | 3076 | |
| 3070 | 3077 | // Again, slicing with comptime-known indexes will produce another pointer |
| 3071 | 3078 | // to an array: |
| ... | ... | @@ -3088,7 +3095,7 @@ test "slice pointer" { |
| 3088 | 3095 | const std = @import("std"); |
| 3089 | 3096 | const expect = std.testing.expect; |
| 3090 | 3097 | |
| 3091 | | test "null terminated slice" { |
| 3098 | test "0-terminated slice" { |
| 3092 | 3099 | const slice: [:0]const u8 = "hello"; |
| 3093 | 3100 | |
| 3094 | 3101 | try expect(slice.len == 5); |
| ... | ... | @@ -3104,7 +3111,7 @@ test "null terminated slice" { |
| 3104 | 3111 | const std = @import("std"); |
| 3105 | 3112 | const expect = std.testing.expect; |
| 3106 | 3113 | |
| 3107 | | test "null terminated slicing" { |
| 3114 | test "0-terminated slicing" { |
| 3108 | 3115 | var array = [_]u8{ 3, 2, 1, 0, 3, 2, 1, 0 }; |
| 3109 | 3116 | var runtime_length: usize = 3; |
| 3110 | 3117 | const slice = array[0..runtime_length :0]; |
| ... | ... | @@ -3590,7 +3597,7 @@ const std = @import("std"); |
| 3590 | 3597 | const expect = std.testing.expect; |
| 3591 | 3598 | |
| 3592 | 3599 | test "fully anonymous struct" { |
| 3593 | | try dump(.{ |
| 3600 | try check(.{ |
| 3594 | 3601 | .int = @as(u32, 1234), |
| 3595 | 3602 | .float = @as(f64, 12.34), |
| 3596 | 3603 | .b = true, |
| ... | ... | @@ -3598,7 +3605,7 @@ test "fully anonymous struct" { |
| 3598 | 3605 | }); |
| 3599 | 3606 | } |
| 3600 | 3607 | |
| 3601 | | fn dump(args: anytype) !void { |
| 3608 | fn check(args: anytype) !void { |
| 3602 | 3609 | try expect(args.int == 1234); |
| 3603 | 3610 | try expect(args.float == 12.34); |
| 3604 | 3611 | try expect(args.b); |
| ... | ... | @@ -3813,8 +3820,8 @@ test "switch using enum literals" { |
| 3813 | 3820 | |
| 3814 | 3821 | {#header_open|Non-exhaustive enum#} |
| 3815 | 3822 | <p> |
| 3816 | | A Non-exhaustive enum can be created by adding a trailing '_' field. |
| 3817 | | It must specify a tag type and cannot consume every enumeration value. |
| 3823 | A non-exhaustive enum can be created by adding a trailing {#syntax#}_{#endsyntax#} field. |
| 3824 | The enum must specify a tag type and cannot consume every enumeration value. |
| 3818 | 3825 | </p> |
| 3819 | 3826 | <p> |
| 3820 | 3827 | {#link|@enumFromInt#} on a non-exhaustive enum involves the safety semantics |
| ... | ... | @@ -3822,8 +3829,8 @@ test "switch using enum literals" { |
| 3822 | 3829 | a well-defined enum value. |
| 3823 | 3830 | </p> |
| 3824 | 3831 | <p> |
| 3825 | | A switch on a non-exhaustive enum can include a '_' prong as an alternative to an {#syntax#}else{#endsyntax#} prong |
| 3826 | | with the difference being that it makes it a compile error if all the known tag names are not handled by the switch. |
| 3832 | A switch on a non-exhaustive enum can include a {#syntax#}_{#endsyntax#} prong as an alternative to an {#syntax#}else{#endsyntax#} prong. |
| 3833 | With a {#syntax#}_{#endsyntax#} prong the compiler errors if all the known tag names are not handled by the switch. |
| 3827 | 3834 | </p> |
| 3828 | 3835 | {#code_begin|test|test_switch_non-exhaustive#} |
| 3829 | 3836 | const std = @import("std"); |
| ... | ... | @@ -5268,14 +5275,14 @@ fn shiftLeftOne(a: u32) callconv(.Inline) u32 { |
| 5268 | 5275 | pub fn sub2(a: i8, b: i8) i8 { return a - b; } |
| 5269 | 5276 | |
| 5270 | 5277 | // Function pointers are prefixed with `*const `. |
| 5271 | | const call2_op = *const fn (a: i8, b: i8) i8; |
| 5272 | | fn do_op(fn_call: call2_op, op1: i8, op2: i8) i8 { |
| 5273 | | return fn_call(op1, op2); |
| 5278 | const Call2Op = *const fn (a: i8, b: i8) i8; |
| 5279 | fn doOp(fnCall: Call2Op, op1: i8, op2: i8) i8 { |
| 5280 | return fnCall(op1, op2); |
| 5274 | 5281 | } |
| 5275 | 5282 | |
| 5276 | 5283 | test "function" { |
| 5277 | | try expect(do_op(add, 5, 6) == 11); |
| 5278 | | try expect(do_op(sub2, 5, 6) == -1); |
| 5284 | try expect(doOp(add, 5, 6) == 11); |
| 5285 | try expect(doOp(sub2, 5, 6) == -1); |
| 5279 | 5286 | } |
| 5280 | 5287 | {#code_end#} |
| 5281 | 5288 | <p>There is a difference between a function <em>body</em> and a function <em>pointer</em>. |
| ... | ... | @@ -6515,7 +6522,7 @@ test "coerce to optionals" { |
| 6515 | 6522 | try expect(y == null); |
| 6516 | 6523 | } |
| 6517 | 6524 | {#code_end#} |
| 6518 | | <p>It works nested inside the {#link|Error Union Type#}, too:</p> |
| 6525 | <p>Optionals work nested inside the {#link|Error Union Type#}, too:</p> |
| 6519 | 6526 | {#code_begin|test|test_coerce_optional_wrapped_error_union#} |
| 6520 | 6527 | const std = @import("std"); |
| 6521 | 6528 | const expect = std.testing.expect; |
| ... | ... | @@ -6841,7 +6848,8 @@ test "turn HashMap into a set with void" { |
| 6841 | 6848 | {#syntax#}void{#endsyntax#} has a known size of 0 bytes, and {#syntax#}anyopaque{#endsyntax#} has an unknown, but non-zero, size. |
| 6842 | 6849 | </p> |
| 6843 | 6850 | <p> |
| 6844 | | Expressions of type {#syntax#}void{#endsyntax#} are the only ones whose value can be ignored. For example: |
| 6851 | Expressions of type {#syntax#}void{#endsyntax#} are the only ones whose value can be ignored. For example, ignoring |
| 6852 | a non-{#syntax#}void{#endsyntax#} expression is a compile error: |
| 6845 | 6853 | </p> |
| 6846 | 6854 | {#code_begin|test_err|test_expression_ignored|ignored#} |
| 6847 | 6855 | test "ignoring expression value" { |
| ... | ... | @@ -6852,7 +6860,7 @@ fn foo() i32 { |
| 6852 | 6860 | return 1234; |
| 6853 | 6861 | } |
| 6854 | 6862 | {#code_end#} |
| 6855 | | <p>However, if the expression has type {#syntax#}void{#endsyntax#}, there will be no error. Function return values can also be explicitly ignored by assigning them to {#syntax#}_{#endsyntax#}. </p> |
| 6863 | <p>However, if the expression has type {#syntax#}void{#endsyntax#}, there will be no error. Expression results can be explicitly ignored by assigning them to {#syntax#}_{#endsyntax#}. </p> |
| 6856 | 6864 | {#code_begin|test|test_void_ignored#} |
| 6857 | 6865 | test "void is ignored" { |
| 6858 | 6866 | returnsVoid(); |
| ... | ... | @@ -7110,12 +7118,10 @@ fn performFn(start_value: i32) i32 { |
| 7110 | 7118 | } |
| 7111 | 7119 | {#end_syntax_block#} |
| 7112 | 7120 | <p> |
| 7113 | | Note that this happens even in a debug build; in a release build these generated functions still |
| 7114 | | pass through rigorous LLVM optimizations. The important thing to note, however, is not that this |
| 7115 | | is a way to write more optimized code, but that it is a way to make sure that what <em>should</em> happen |
| 7116 | | at compile-time, <em>does</em> happen at compile-time. This catches more errors and as demonstrated |
| 7117 | | later in this article, allows expressiveness that in other languages requires using macros, |
| 7118 | | generated code, or a preprocessor to accomplish. |
| 7121 | Note that this happens even in a debug build. |
| 7122 | This is not a way to write more optimized code, but it is a way to make sure that what <em>should</em> happen |
| 7123 | at compile-time, <em>does</em> happen at compile-time. This catches more errors and allows expressiveness |
| 7124 | that in other languages requires using macros, generated code, or a preprocessor to accomplish. |
| 7119 | 7125 | </p> |
| 7120 | 7126 | {#header_close#} |
| 7121 | 7127 | {#header_open|Compile-Time Expressions#} |
| ... | ... | @@ -7297,9 +7303,8 @@ test "variable values" { |
| 7297 | 7303 | {#header_close#} |
| 7298 | 7304 | {#header_open|Generic Data Structures#} |
| 7299 | 7305 | <p> |
| 7300 | | Zig uses these capabilities to implement generic data structures without introducing any |
| 7301 | | special-case syntax. If you followed along so far, you may already know how to create a |
| 7302 | | generic data structure. |
| 7306 | Zig uses comptime capabilities to implement generic data structures without introducing any |
| 7307 | special-case syntax. |
| 7303 | 7308 | </p> |
| 7304 | 7309 | <p> |
| 7305 | 7310 | 			Here is an example of a generic {#syntax#}List{#endsyntax#} data structure. |
| ... | ... | @@ -7321,7 +7326,6 @@ var list = List(i32){ |
| 7321 | 7326 | {#code_end#} |
| 7322 | 7327 | <p> |
| 7323 | 7328 | That's it. It's a function that returns an anonymous {#syntax#}struct{#endsyntax#}. |
| 7324 | | To keep the language small and uniform, all aggregate types in Zig are anonymous. |
| 7325 | 7329 | For the purposes of error messages and debugging, Zig infers the name |
| 7326 | 7330 | {#syntax#}"List(i32)"{#endsyntax#} from the function name and parameters invoked when creating |
| 7327 | 7331 | the anonymous struct. |
| ... | ... | @@ -7754,6 +7758,9 @@ test "global assembly" { |
| 7754 | 7758 | <p>TODO: @fence()</p> |
| 7755 | 7759 | <p>TODO: @atomic rmw</p> |
| 7756 | 7760 | <p>TODO: builtin atomic memory ordering enum</p> |
| 7761 | |
| 7762 | {#see_also|@atomicLoad|@atomicStore|@atomicRmw|@fence|@cmpxchgWeak|@cmpxchgStrong#} |
| 7763 | |
| 7757 | 7764 | {#header_close#} |
| 7758 | 7765 | |
| 7759 | 7766 | {#header_open|Async Functions#} |
| ... | ... | @@ -7824,7 +7831,7 @@ comptime { |
| 7824 | 7831 | {#header_open|@atomicLoad#} |
| 7825 | 7832 | <pre>{#syntax#}@atomicLoad(comptime T: type, ptr: *const T, comptime ordering: builtin.AtomicOrder) T{#endsyntax#}</pre> |
| 7826 | 7833 | <p> |
| 7827 | | This builtin function atomically dereferences a pointer and returns the value. |
| 7834 | This builtin function atomically dereferences a pointer to a {#syntax#}T{#endsyntax#} and returns the value. |
| 7828 | 7835 | </p> |
| 7829 | 7836 | <p> |
| 7830 | 7837 | {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float, |
| ... | ... | @@ -7836,14 +7843,15 @@ comptime { |
| 7836 | 7843 | {#header_open|@atomicRmw#} |
| 7837 | 7844 | <pre>{#syntax#}@atomicRmw(comptime T: type, ptr: *T, comptime op: builtin.AtomicRmwOp, operand: T, comptime ordering: builtin.AtomicOrder) T{#endsyntax#}</pre> |
| 7838 | 7845 | <p> |
| 7839 | | This builtin function atomically modifies memory and then returns the previous value. |
| 7846 | This builtin function dereferences a pointer to a {#syntax#}T{#endsyntax#} and atomically |
| 7847 | modifies the value and returns the previous value. |
| 7840 | 7848 | </p> |
| 7841 | 7849 | <p> |
| 7842 | 7850 | {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float, |
| 7843 | 7851 | an integer or an enum. |
| 7844 | 7852 | </p> |
| 7845 | 7853 | <p> |
| 7846 | | Supported operations: |
| 7854 | Supported values for the {#syntax#}op{#endsyntax#} parameter: |
| 7847 | 7855 | </p> |
| 7848 | 7856 | <ul> |
| 7849 | 7857 | <li>{#syntax#}.Xchg{#endsyntax#} - stores the operand unmodified. Supports enums, integers and floats.</li> |
| ... | ... | @@ -7864,7 +7872,7 @@ comptime { |
| 7864 | 7872 | {#header_open|@atomicStore#} |
| 7865 | 7873 | <pre>{#syntax#}@atomicStore(comptime T: type, ptr: *T, value: T, comptime ordering: builtin.AtomicOrder) void{#endsyntax#}</pre> |
| 7866 | 7874 | <p> |
| 7867 | | This builtin function atomically stores a value. |
| 7875 | This builtin function dereferences a pointer to a {#syntax#}T{#endsyntax#} and atomically stores the given value. |
| 7868 | 7876 | </p> |
| 7869 | 7877 | <p> |
| 7870 | 7878 | {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float, |
| ... | ... | @@ -8122,7 +8130,8 @@ pub const CallModifier = enum { |
| 8122 | 8130 | {#header_open|@cmpxchgStrong#} |
| 8123 | 8131 | <pre>{#syntax#}@cmpxchgStrong(comptime T: type, ptr: *T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) ?T{#endsyntax#}</pre> |
| 8124 | 8132 | <p> |
| 8125 | | This function performs a strong atomic compare exchange operation. It's the equivalent of this code, |
| 8133 | This function performs a strong atomic compare-and-exchange operation, returning {#syntax#}null{#endsyntax#} |
| 8134 | if the current value is not the given expected value. It's the equivalent of this code, |
| 8126 | 8135 | except atomic: |
| 8127 | 8136 | </p> |
| 8128 | 8137 | {#code_begin|syntax|not_atomic_cmpxchgStrong#} |
| ... | ... | @@ -8137,7 +8146,7 @@ fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_v |
| 8137 | 8146 | } |
| 8138 | 8147 | {#code_end#} |
| 8139 | 8148 | <p> |
| 8140 | | If you are using cmpxchg in a loop, {#link|@cmpxchgWeak#} is the better choice, because it can be implemented |
| 8149 | If you are using cmpxchg in a retry loop, {#link|@cmpxchgWeak#} is the better choice, because it can be implemented |
| 8141 | 8150 | more efficiently in machine instructions. |
| 8142 | 8151 | </p> |
| 8143 | 8152 | <p> |
| ... | ... | @@ -8151,7 +8160,8 @@ fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_v |
| 8151 | 8160 | {#header_open|@cmpxchgWeak#} |
| 8152 | 8161 | <pre>{#syntax#}@cmpxchgWeak(comptime T: type, ptr: *T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) ?T{#endsyntax#}</pre> |
| 8153 | 8162 | <p> |
| 8154 | | This function performs a weak atomic compare exchange operation. It's the equivalent of this code, |
| 8163 | This function performs a weak atomic compare-and-exchange operation, returning {#syntax#}null{#endsyntax#} |
| 8164 | if the current value is not the given expected value. It's the equivalent of this code, |
| 8155 | 8165 | except atomic: |
| 8156 | 8166 | </p> |
| 8157 | 8167 | {#syntax_block|zig|cmpxchgWeakButNotAtomic#} |
| ... | ... | @@ -8166,7 +8176,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val |
| 8166 | 8176 | } |
| 8167 | 8177 | {#end_syntax_block#} |
| 8168 | 8178 | <p> |
| 8169 | | If you are using cmpxchg in a loop, the sporadic failure will be no problem, and {#syntax#}cmpxchgWeak{#endsyntax#} |
| 8179 | If you are using cmpxchg in a retry loop, the sporadic failure will be no problem, and {#syntax#}cmpxchgWeak{#endsyntax#} |
| 8170 | 8180 | is the better choice, because it can be implemented more efficiently in machine instructions. |
| 8171 | 8181 | However if you need a stronger guarantee, use {#link|@cmpxchgStrong#}. |
| 8172 | 8182 | </p> |
| ... | ... | @@ -8219,24 +8229,6 @@ const num1 = blk: { |
| 8219 | 8229 | test "main" { |
| 8220 | 8230 | @compileLog("comptime in main"); |
| 8221 | 8231 | |
| 8222 | | print("Runtime in main, num1 = {}.\n", .{num1}); |
| 8223 | | } |
| 8224 | | {#code_end#} |
| 8225 | | <p> |
| 8226 | | If all {#syntax#}@compileLog{#endsyntax#} calls are removed or |
| 8227 | | not encountered by analysis, the |
| 8228 | | program compiles successfully and the generated executable prints: |
| 8229 | | </p> |
| 8230 | | {#code_begin|test|test_without_compileLog_builtin#} |
| 8231 | | const print = @import("std").debug.print; |
| 8232 | | |
| 8233 | | const num1 = blk: { |
| 8234 | | var val1: i32 = 99; |
| 8235 | | val1 = val1 + 1; |
| 8236 | | break :blk val1; |
| 8237 | | }; |
| 8238 | | |
| 8239 | | test "main" { |
| 8240 | 8232 | print("Runtime in main, num1 = {}.\n", .{num1}); |
| 8241 | 8233 | } |
| 8242 | 8234 | {#code_end#} |
| ... | ... | @@ -9020,14 +9012,16 @@ pub const PrefetchOptions = struct { |
| 9020 | 9012 | {#header_open|@setCold#} |
| 9021 | 9013 | <pre>{#syntax#}@setCold(comptime is_cold: bool) void{#endsyntax#}</pre> |
| 9022 | 9014 | <p> |
| 9023 | | Tells the optimizer that a function is rarely called. |
| 9015 | Tells the optimizer that the current function is (or is not) rarely called. |
| 9016 | |
| 9017 | This function is only valid within function scope. |
| 9024 | 9018 | </p> |
| 9025 | 9019 | {#header_close#} |
| 9026 | 9020 | |
| 9027 | 9021 | {#header_open|@setEvalBranchQuota#} |
| 9028 | 9022 | <pre>{#syntax#}@setEvalBranchQuota(comptime new_quota: u32) void{#endsyntax#}</pre> |
| 9029 | 9023 | <p> |
| 9030 | | Changes the maximum number of backwards branches that compile-time code |
| 9024 | Increase the maximum number of backwards branches that compile-time code |
| 9031 | 9025 | execution can use before giving up and making a compile error. |
| 9032 | 9026 | </p> |
| 9033 | 9027 | <p> |
| ... | ... | @@ -9232,7 +9226,7 @@ test "vector @shuffle" { |
| 9232 | 9226 | The result is a target-specific compile time constant. |
| 9233 | 9227 | </p> |
| 9234 | 9228 | <p> |
| 9235 | | This size may contain padding bytes. If there were two consecutive T in memory, this would be the offset |
| 9229 | This size may contain padding bytes. If there were two consecutive T in memory, the padding would be the offset |
| 9236 | 9230 | in bytes between element at index 0 and the element at index 1. For {#link|integer|Integers#}, |
| 9237 | 9231 | consider whether you want to use {#syntax#}@sizeOf(T){#endsyntax#} or |
| 9238 | 9232 | {#syntax#}@typeInfo(T).Int.bits{#endsyntax#}. |
| ... | ... | @@ -9247,7 +9241,7 @@ test "vector @shuffle" { |
| 9247 | 9241 | {#header_open|@splat#} |
| 9248 | 9242 | <pre>{#syntax#}@splat(scalar: anytype) anytype{#endsyntax#}</pre> |
| 9249 | 9243 | <p> |
| 9250 | | Produces a vector where each element is the value {#syntax#}scalar{#endsyntax#}. |
| 9244 | Produces a vector where each element is the value {#syntax#}scalar{#endsyntax#}. |
| 9251 | 9245 | The return type and thus the length of the vector is inferred. |
| 9252 | 9246 | </p> |
| 9253 | 9247 | {#code_begin|test|test_splat_builtin#} |