| ... | ... | @@ -4771,6 +4771,8 @@ test "parse u64" { |
| 4771 | 4771 | {#header_open|catch#} |
| 4772 | 4772 | <p>If you want to provide a default value, you can use the {#syntax#}catch{#endsyntax#} binary operator:</p> |
| 4773 | 4773 | {#code_begin|syntax#} |
| 4774 | const parseU64 = @import("error_union_parsing_u64.zig").parseU64; |
| 4775 | |
| 4774 | 4776 | fn doAThing(str: []u8) void { |
| 4775 | 4777 | const number = parseU64(str, 10) catch 13; |
| 4776 | 4778 | _ = number; // ... |
| ... | ... | @@ -4786,6 +4788,8 @@ fn doAThing(str: []u8) void { |
| 4786 | 4788 | <p>Let's say you wanted to return the error if you got one, otherwise continue with the |
| 4787 | 4789 | function logic:</p> |
| 4788 | 4790 | {#code_begin|syntax#} |
| 4791 | const parseU64 = @import("error_union_parsing_u64.zig").parseU64; |
| 4792 | |
| 4789 | 4793 | fn doAThing(str: []u8) !void { |
| 4790 | 4794 | const number = parseU64(str, 10) catch |err| return err; |
| 4791 | 4795 | _ = number; // ... |
| ... | ... | @@ -4795,6 +4799,8 @@ fn doAThing(str: []u8) !void { |
| 4795 | 4799 | There is a shortcut for this. The {#syntax#}try{#endsyntax#} expression: |
| 4796 | 4800 | </p> |
| 4797 | 4801 | {#code_begin|syntax#} |
| 4802 | const parseU64 = @import("error_union_parsing_u64.zig").parseU64; |
| 4803 | |
| 4798 | 4804 | fn doAThing(str: []u8) !void { |
| 4799 | 4805 | const number = try parseU64(str, 10); |
| 4800 | 4806 | _ = number; // ... |
| ... | ... | @@ -4810,7 +4816,7 @@ fn doAThing(str: []u8) !void { |
| 4810 | 4816 | Maybe you know with complete certainty that an expression will never be an error. |
| 4811 | 4817 | In this case you can do this: |
| 4812 | 4818 | </p> |
| 4813 | | {#code_begin|syntax#}const number = parseU64("1234", 10) catch unreachable;{#code_end#} |
| 4819 | {#syntax#}const number = parseU64("1234", 10) catch unreachable;{#endsyntax#} |
| 4814 | 4820 | <p> |
| 4815 | 4821 | Here we know for sure that "1234" will parse successfully. So we put the |
| 4816 | 4822 | {#syntax#}unreachable{#endsyntax#} value on the right hand side. {#syntax#}unreachable{#endsyntax#} generates |
| ... | ... | @@ -4822,7 +4828,7 @@ fn doAThing(str: []u8) !void { |
| 4822 | 4828 | Finally, you may want to take a different action for every situation. For that, we combine |
| 4823 | 4829 | the {#link|if#} and {#link|switch#} expression: |
| 4824 | 4830 | </p> |
| 4825 | | {#code_begin|syntax#} |
| 4831 | {#syntax_block|zig|handle_all_error_scenarios.zig#} |
| 4826 | 4832 | fn doAThing(str: []u8) void { |
| 4827 | 4833 | if (parseU64(str, 10)) |number| { |
| 4828 | 4834 | doSomethingWithNumber(number); |
| ... | ... | @@ -4834,7 +4840,7 @@ fn doAThing(str: []u8) void { |
| 4834 | 4840 | error.InvalidChar => unreachable, |
| 4835 | 4841 | } |
| 4836 | 4842 | } |
| 4837 | | {#code_end#} |
| 4843 | {#end_syntax_block#} |
| 4838 | 4844 | {#header_open|errdefer#} |
| 4839 | 4845 | <p> |
| 4840 | 4846 | The other component to error handling is defer statements. |
| ... | ... | @@ -4845,7 +4851,7 @@ fn doAThing(str: []u8) void { |
| 4845 | 4851 | <p> |
| 4846 | 4852 | Example: |
| 4847 | 4853 | </p> |
| 4848 | | {#code_begin|syntax#} |
| 4854 | {#syntax_block|zig|errdefer_example.zig#} |
| 4849 | 4855 | fn createFoo(param: i32) !Foo { |
| 4850 | 4856 | const foo = try tryToAllocateFoo(); |
| 4851 | 4857 | // now we have allocated foo. we need to free it if the function fails. |
| ... | ... | @@ -4863,7 +4869,7 @@ fn createFoo(param: i32) !Foo { |
| 4863 | 4869 | // but the defer will run! |
| 4864 | 4870 | return foo; |
| 4865 | 4871 | } |
| 4866 | | {#code_end#} |
| 4872 | {#end_syntax_block#} |
| 4867 | 4873 | <p> |
| 4868 | 4874 | The neat thing about this is that you get robust error handling without |
| 4869 | 4875 | the verbosity and cognitive overhead of trying to make sure every exit path |
| ... | ... | @@ -5132,12 +5138,12 @@ fn bang2() void { |
| 5132 | 5138 | For the case when no errors are returned, the cost is a single memory write operation, only in the first non-failable function in the call graph that calls a failable function, i.e. when a function returning {#syntax#}void{#endsyntax#} calls a function returning {#syntax#}error{#endsyntax#}. |
| 5133 | 5139 | This is to initialize this struct in the stack memory: |
| 5134 | 5140 | </p> |
| 5135 | | {#code_begin|syntax#} |
| 5141 | {#syntax_block|zig|stack_trace_struct.zig#} |
| 5136 | 5142 | pub const StackTrace = struct { |
| 5137 | 5143 | index: usize, |
| 5138 | 5144 | instruction_addresses: [N]usize, |
| 5139 | 5145 | }; |
| 5140 | | {#code_end#} |
| 5146 | {#end_syntax_block#} |
| 5141 | 5147 | <p> |
| 5142 | 5148 | Here, N is the maximum function call depth as determined by call graph analysis. Recursion is ignored and counts for 2. |
| 5143 | 5149 | </p> |
| ... | ... | @@ -5150,13 +5156,13 @@ pub const StackTrace = struct { |
| 5150 | 5156 | <p> |
| 5151 | 5157 | When generating the code for a function that returns an error, just before the {#syntax#}return{#endsyntax#} statement (only for the {#syntax#}return{#endsyntax#} statements that return errors), Zig generates a call to this function: |
| 5152 | 5158 | </p> |
| 5153 | | {#code_begin|syntax#} |
| 5159 | {#syntax_block|zig|zig_return_error_fn.zig#} |
| 5154 | 5160 | // marked as "no-inline" in LLVM IR |
| 5155 | 5161 | fn __zig_return_error(stack_trace: *StackTrace) void { |
| 5156 | 5162 | stack_trace.instruction_addresses[stack_trace.index] = @returnAddress(); |
| 5157 | 5163 | stack_trace.index = (stack_trace.index + 1) % N; |
| 5158 | 5164 | } |
| 5159 | | {#code_end#} |
| 5165 | {#end_syntax_block#} |
| 5160 | 5166 | <p> |
| 5161 | 5167 | The cost is 2 math operations plus some memory reads and writes. The memory accessed is constrained and should remain cached for the duration of the error return bubbling. |
| 5162 | 5168 | </p> |
| ... | ... | @@ -5206,16 +5212,16 @@ const optional_int: ?i32 = 5678; |
| 5206 | 5212 | Task: call malloc, if the result is null, return null. |
| 5207 | 5213 | </p> |
| 5208 | 5214 | <p>C code</p> |
| 5209 | | <pre><code class="cpp">// malloc prototype included for reference |
| 5215 | {#syntax_block|c|call_malloc_in_c.c#}// malloc prototype included for reference |
| 5210 | 5216 | void *malloc(size_t size); |
| 5211 | 5217 | |
| 5212 | 5218 | struct Foo *do_a_thing(void) { |
| 5213 | 5219 | char *ptr = malloc(1234); |
| 5214 | 5220 | if (!ptr) return NULL; |
| 5215 | 5221 | // ... |
| 5216 | | }</code></pre> |
| 5222 | }{#end_syntax_block#} |
| 5217 | 5223 | <p>Zig code</p> |
| 5218 | | {#code_begin|syntax#} |
| 5224 | {#syntax_block|zig|call_malloc_from_zig.zig#} |
| 5219 | 5225 | // malloc prototype included for reference |
| 5220 | 5226 | extern fn malloc(size: size_t) ?*u8; |
| 5221 | 5227 | |
| ... | ... | @@ -5223,7 +5229,7 @@ fn doAThing() ?*Foo { |
| 5223 | 5229 | const ptr = malloc(1234) orelse return null; |
| 5224 | 5230 | _ = ptr; // ... |
| 5225 | 5231 | } |
| 5226 | | {#code_end#} |
| 5232 | {#end_syntax_block#} |
| 5227 | 5233 | <p> |
| 5228 | 5234 | Here, Zig is at least as convenient, if not more, than C. And, the type of "ptr" |
| 5229 | 5235 | is {#syntax#}*u8{#endsyntax#} <em>not</em> {#syntax#}?*u8{#endsyntax#}. The {#syntax#}orelse{#endsyntax#} keyword |
| ... | ... | @@ -5233,7 +5239,7 @@ fn doAThing() ?*Foo { |
| 5233 | 5239 | <p> |
| 5234 | 5240 | The other form of checking against NULL you might see looks like this: |
| 5235 | 5241 | </p> |
| 5236 | | <pre><code class="cpp">void do_a_thing(struct Foo *foo) { |
| 5242 | {#syntax_block|c|checking_null_in_c.c#}void do_a_thing(struct Foo *foo) { |
| 5237 | 5243 | // do some stuff |
| 5238 | 5244 | |
| 5239 | 5245 | if (foo) { |
| ... | ... | @@ -5241,11 +5247,14 @@ fn doAThing() ?*Foo { |
| 5241 | 5247 | } |
| 5242 | 5248 | |
| 5243 | 5249 | // do some stuff |
| 5244 | | }</code></pre> |
| 5250 | }{#end_syntax_block#} |
| 5245 | 5251 | <p> |
| 5246 | 5252 | In Zig you can accomplish the same thing: |
| 5247 | 5253 | </p> |
| 5248 | | {#code_begin|syntax#} |
| 5254 | {#code_begin|syntax|checking_null_in_zig#} |
| 5255 | const Foo = struct{}; |
| 5256 | fn doSomethingWithFoo(foo: *Foo) void { _ = foo; } |
| 5257 | |
| 5249 | 5258 | fn doAThing(optional_foo: ?*Foo) void { |
| 5250 | 5259 | // do some stuff |
| 5251 | 5260 | |
| ... | ... | @@ -6111,7 +6120,7 @@ test "perform fn" { |
| 6111 | 6120 | different code. In this example, the function {#syntax#}performFn{#endsyntax#} is generated three different times, |
| 6112 | 6121 | for the different values of {#syntax#}prefix_char{#endsyntax#} provided: |
| 6113 | 6122 | </p> |
| 6114 | | {#code_begin|syntax#} |
| 6123 | {#syntax_block|zig|performFn_1#} |
| 6115 | 6124 | // From the line: |
| 6116 | 6125 | // expect(performFn('t', 1) == 6); |
| 6117 | 6126 | fn performFn(start_value: i32) i32 { |
| ... | ... | @@ -6120,8 +6129,8 @@ fn performFn(start_value: i32) i32 { |
| 6120 | 6129 | result = three(result); |
| 6121 | 6130 | return result; |
| 6122 | 6131 | } |
| 6123 | | {#code_end#} |
| 6124 | | {#code_begin|syntax#} |
| 6132 | {#end_syntax_block#} |
| 6133 | {#syntax_block|zig|performFn_2#} |
| 6125 | 6134 | // From the line: |
| 6126 | 6135 | // expect(performFn('o', 0) == 1); |
| 6127 | 6136 | fn performFn(start_value: i32) i32 { |
| ... | ... | @@ -6129,15 +6138,15 @@ fn performFn(start_value: i32) i32 { |
| 6129 | 6138 | result = one(result); |
| 6130 | 6139 | return result; |
| 6131 | 6140 | } |
| 6132 | | {#code_end#} |
| 6133 | | {#code_begin|syntax#} |
| 6141 | {#end_syntax_block#} |
| 6142 | {#syntax_block|zig|performFn_3#} |
| 6134 | 6143 | // From the line: |
| 6135 | 6144 | // expect(performFn('w', 99) == 99); |
| 6136 | 6145 | fn performFn(start_value: i32) i32 { |
| 6137 | 6146 | var result: i32 = start_value; |
| 6138 | 6147 | return result; |
| 6139 | 6148 | } |
| 6140 | | {#code_end#} |
| 6149 | {#end_syntax_block#} |
| 6141 | 6150 | <p> |
| 6142 | 6151 | Note that this happens even in a debug build; in a release build these generated functions still |
| 6143 | 6152 | pass through rigorous LLVM optimizations. The important thing to note, however, is not that this |
| ... | ... | @@ -6367,11 +6376,11 @@ const Node = struct { |
| 6367 | 6376 | it works fine. |
| 6368 | 6377 | </p> |
| 6369 | 6378 | {#header_close#} |
| 6370 | | {#header_open|Case Study: printf in Zig#} |
| 6379 | {#header_open|Case Study: print in Zig#} |
| 6371 | 6380 | <p> |
| 6372 | | Putting all of this together, let's see how {#syntax#}printf{#endsyntax#} works in Zig. |
| 6381 | Putting all of this together, let's see how {#syntax#}print{#endsyntax#} works in Zig. |
| 6373 | 6382 | </p> |
| 6374 | | {#code_begin|exe|printf#} |
| 6383 | {#code_begin|exe|print#} |
| 6375 | 6384 | const print = @import("std").debug.print; |
| 6376 | 6385 | |
| 6377 | 6386 | const a_number: i32 = 1234; |
| ... | ... | @@ -6386,67 +6395,84 @@ pub fn main() void { |
| 6386 | 6395 | Let's crack open the implementation of this and see how it works: |
| 6387 | 6396 | </p> |
| 6388 | 6397 | |
| 6389 | | {#code_begin|syntax#} |
| 6390 | | /// Calls print and then flushes the buffer. |
| 6391 | | pub fn printf(self: *Writer, comptime format: []const u8, args: anytype) anyerror!void { |
| 6392 | | const State = enum { |
| 6393 | | start, |
| 6394 | | open_brace, |
| 6395 | | close_brace, |
| 6396 | | }; |
| 6397 | | |
| 6398 | | comptime var start_index: usize = 0; |
| 6399 | | comptime var state = State.start; |
| 6400 | | comptime var next_arg: usize = 0; |
| 6398 | {#code_begin|syntax|poc_print_fn#} |
| 6399 | const Writer = struct { |
| 6400 | /// Calls print and then flushes the buffer. |
| 6401 | pub fn print(self: *Writer, comptime format: []const u8, args: anytype) anyerror!void { |
| 6402 | const State = enum { |
| 6403 | start, |
| 6404 | open_brace, |
| 6405 | close_brace, |
| 6406 | }; |
| 6401 | 6407 | |
| 6402 | | inline for (format) |c, i| { |
| 6403 | | switch (state) { |
| 6404 | | State.start => switch (c) { |
| 6405 | | '{' => { |
| 6406 | | if (start_index < i) try self.write(format[start_index..i]); |
| 6407 | | state = State.open_brace; |
| 6408 | | }, |
| 6409 | | '}' => { |
| 6410 | | if (start_index < i) try self.write(format[start_index..i]); |
| 6411 | | state = State.close_brace; |
| 6412 | | }, |
| 6413 | | else => {}, |
| 6414 | | }, |
| 6415 | | State.open_brace => switch (c) { |
| 6416 | | '{' => { |
| 6417 | | state = State.start; |
| 6418 | | start_index = i; |
| 6408 | comptime var start_index: usize = 0; |
| 6409 | comptime var state = State.start; |
| 6410 | comptime var next_arg: usize = 0; |
| 6411 | |
| 6412 | inline for (format) |c, i| { |
| 6413 | switch (state) { |
| 6414 | State.start => switch (c) { |
| 6415 | '{' => { |
| 6416 | if (start_index < i) try self.write(format[start_index..i]); |
| 6417 | state = State.open_brace; |
| 6418 | }, |
| 6419 | '}' => { |
| 6420 | if (start_index < i) try self.write(format[start_index..i]); |
| 6421 | state = State.close_brace; |
| 6422 | }, |
| 6423 | else => {}, |
| 6419 | 6424 | }, |
| 6420 | | '}' => { |
| 6421 | | try self.printValue(args[next_arg]); |
| 6422 | | next_arg += 1; |
| 6423 | | state = State.start; |
| 6424 | | start_index = i + 1; |
| 6425 | State.open_brace => switch (c) { |
| 6426 | '{' => { |
| 6427 | state = State.start; |
| 6428 | start_index = i; |
| 6429 | }, |
| 6430 | '}' => { |
| 6431 | try self.printValue(args[next_arg]); |
| 6432 | next_arg += 1; |
| 6433 | state = State.start; |
| 6434 | start_index = i + 1; |
| 6435 | }, |
| 6436 | 's' => { |
| 6437 | continue; |
| 6438 | }, |
| 6439 | else => @compileError("Unknown format character: " ++ [1]u8{c}), |
| 6425 | 6440 | }, |
| 6426 | | else => @compileError("Unknown format character: " ++ c), |
| 6427 | | }, |
| 6428 | | State.close_brace => switch (c) { |
| 6429 | | '}' => { |
| 6430 | | state = State.start; |
| 6431 | | start_index = i; |
| 6441 | State.close_brace => switch (c) { |
| 6442 | '}' => { |
| 6443 | state = State.start; |
| 6444 | start_index = i; |
| 6445 | }, |
| 6446 | else => @compileError("Single '}' encountered in format string"), |
| 6432 | 6447 | }, |
| 6433 | | else => @compileError("Single '}' encountered in format string"), |
| 6434 | | }, |
| 6448 | } |
| 6435 | 6449 | } |
| 6436 | | } |
| 6437 | | comptime { |
| 6438 | | if (args.len != next_arg) { |
| 6439 | | @compileError("Unused arguments"); |
| 6450 | comptime { |
| 6451 | if (args.len != next_arg) { |
| 6452 | @compileError("Unused arguments"); |
| 6453 | } |
| 6454 | if (state != State.start) { |
| 6455 | @compileError("Incomplete format string: " ++ format); |
| 6456 | } |
| 6440 | 6457 | } |
| 6441 | | if (state != State.Start) { |
| 6442 | | @compileError("Incomplete format string: " ++ format); |
| 6458 | if (start_index < format.len) { |
| 6459 | try self.write(format[start_index..format.len]); |
| 6443 | 6460 | } |
| 6461 | try self.flush(); |
| 6444 | 6462 | } |
| 6445 | | if (start_index < format.len) { |
| 6446 | | try self.write(format[start_index..format.len]); |
| 6463 | |
| 6464 | fn write(self: *Writer, value: []const u8) !void { |
| 6465 | _ = self; |
| 6466 | _ = value; |
| 6447 | 6467 | } |
| 6448 | | try self.flush(); |
| 6449 | | } |
| 6468 | pub fn printValue(self: *Writer, value: anytype) !void { |
| 6469 | _ = self; |
| 6470 | _ = value; |
| 6471 | } |
| 6472 | fn flush(self: *Writer) !void { |
| 6473 | _ = self; |
| 6474 | } |
| 6475 | }; |
| 6450 | 6476 | {#code_end#} |
| 6451 | 6477 | <p> |
| 6452 | 6478 | This is a proof of concept implementation; the actual function in the standard library has more |
| ... | ... | @@ -6459,8 +6485,8 @@ pub fn printf(self: *Writer, comptime format: []const u8, args: anytype) anyerro |
| 6459 | 6485 | When this function is analyzed from our example code above, Zig partially evaluates the function |
| 6460 | 6486 | and emits a function that actually looks like this: |
| 6461 | 6487 | </p> |
| 6462 | | {#code_begin|syntax#} |
| 6463 | | pub fn printf(self: *Writer, arg0: i32, arg1: []const u8) !void { |
| 6488 | {#syntax_block|zig|Emitted print Function#} |
| 6489 | pub fn print(self: *Writer, arg0: []const u8, arg1: i32) !void { |
| 6464 | 6490 | try self.write("here is a string: '"); |
| 6465 | 6491 | try self.printValue(arg0); |
| 6466 | 6492 | try self.write("' here is a number: "); |
| ... | ... | @@ -6468,28 +6494,46 @@ pub fn printf(self: *Writer, arg0: i32, arg1: []const u8) !void { |
| 6468 | 6494 | try self.write("\n"); |
| 6469 | 6495 | try self.flush(); |
| 6470 | 6496 | } |
| 6471 | | {#code_end#} |
| 6497 | {#end_syntax_block#} |
| 6472 | 6498 | <p> |
| 6473 | 6499 | {#syntax#}printValue{#endsyntax#} is a function that takes a parameter of any type, and does different things depending |
| 6474 | 6500 | on the type: |
| 6475 | 6501 | </p> |
| 6476 | | {#code_begin|syntax#} |
| 6477 | | pub fn printValue(self: *Writer, value: anytype) !void { |
| 6478 | | switch (@typeInfo(@TypeOf(value))) { |
| 6479 | | .Int => { |
| 6480 | | return self.printInt(T, value); |
| 6481 | | }, |
| 6482 | | .Float => { |
| 6483 | | return self.printFloat(T, value); |
| 6484 | | }, |
| 6485 | | else => { |
| 6486 | | @compileError("Unable to print type '" ++ @typeName(T) ++ "'"); |
| 6487 | | }, |
| 6502 | {#code_begin|syntax|poc_printValue_fn#} |
| 6503 | const Writer = struct { |
| 6504 | pub fn printValue(self: *Writer, value: anytype) !void { |
| 6505 | switch (@typeInfo(@TypeOf(value))) { |
| 6506 | .Int => { |
| 6507 | return self.writeInt(value); |
| 6508 | }, |
| 6509 | .Float => { |
| 6510 | return self.writeFloat(value); |
| 6511 | }, |
| 6512 | .Pointer => { |
| 6513 | return self.write(value); |
| 6514 | }, |
| 6515 | else => { |
| 6516 | @compileError("Unable to print type '" ++ @typeName(@TypeOf(value)) ++ "'"); |
| 6517 | }, |
| 6518 | } |
| 6488 | 6519 | } |
| 6489 | | } |
| 6520 | |
| 6521 | fn write(self: *Writer, value: []const u8) !void { |
| 6522 | _ = self; |
| 6523 | _ = value; |
| 6524 | } |
| 6525 | fn writeInt(self: *Writer, value: anytype) !void { |
| 6526 | _ = self; |
| 6527 | _ = value; |
| 6528 | } |
| 6529 | fn writeFloat(self: *Writer, value: anytype) !void { |
| 6530 | _ = self; |
| 6531 | _ = value; |
| 6532 | } |
| 6533 | }; |
| 6490 | 6534 | {#code_end#} |
| 6491 | 6535 | <p> |
| 6492 | | And now, what happens if we give too many arguments to {#syntax#}printf{#endsyntax#}? |
| 6536 | And now, what happens if we give too many arguments to {#syntax#}print{#endsyntax#}? |
| 6493 | 6537 | </p> |
| 6494 | 6538 | {#code_begin|test_err|Unused argument in 'here is a string: '{s}' here is a number: {}#} |
| 6495 | 6539 | const print = @import("std").debug.print; |
| ... | ... | @@ -6497,7 +6541,7 @@ const print = @import("std").debug.print; |
| 6497 | 6541 | const a_number: i32 = 1234; |
| 6498 | 6542 | const a_string = "foobar"; |
| 6499 | 6543 | |
| 6500 | | test "printf too many arguments" { |
| 6544 | test "print too many arguments" { |
| 6501 | 6545 | print("here is a string: '{s}' here is a number: {}\n", .{ |
| 6502 | 6546 | a_string, |
| 6503 | 6547 | a_number, |
| ... | ... | @@ -6512,7 +6556,7 @@ test "printf too many arguments" { |
| 6512 | 6556 | Zig doesn't care whether the format argument is a string literal, |
| 6513 | 6557 | only that it is a compile-time known value that can be coerced to a {#syntax#}[]const u8{#endsyntax#}: |
| 6514 | 6558 | </p> |
| 6515 | | {#code_begin|exe|printf#} |
| 6559 | {#code_begin|exe|print#} |
| 6516 | 6560 | const print = @import("std").debug.print; |
| 6517 | 6561 | |
| 6518 | 6562 | const a_number: i32 = 1234; |
| ... | ... | @@ -7401,9 +7445,11 @@ fn add(a: i32, b: i32) i32 { |
| 7401 | 7445 | {#syntax#}@call{#endsyntax#} allows more flexibility than normal function call syntax does. The |
| 7402 | 7446 | {#syntax#}CallOptions{#endsyntax#} struct is reproduced here: |
| 7403 | 7447 | </p> |
| 7404 | | {#code_begin|syntax#} |
| 7448 | {#syntax_block|zig|builtin.CallOptions struct#} |
| 7405 | 7449 | pub const CallOptions = struct { |
| 7406 | 7450 | modifier: Modifier = .auto, |
| 7451 | |
| 7452 | /// Only valid when `Modifier` is `Modifier.async_kw`. |
| 7407 | 7453 | stack: ?[]align(std.Target.stack_align) u8 = null, |
| 7408 | 7454 | |
| 7409 | 7455 | pub const Modifier = enum { |
| ... | ... | @@ -7440,7 +7486,7 @@ pub const CallOptions = struct { |
| 7440 | 7486 | compile_time, |
| 7441 | 7487 | }; |
| 7442 | 7488 | }; |
| 7443 | | {#code_end#} |
| 7489 | {#end_syntax_block#} |
| 7444 | 7490 | {#header_close#} |
| 7445 | 7491 | |
| 7446 | 7492 | {#header_open|@cDefine#} |
| ... | ... | @@ -7554,7 +7600,7 @@ fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_v |
| 7554 | 7600 | This function performs a weak atomic compare exchange operation. It's the equivalent of this code, |
| 7555 | 7601 | except atomic: |
| 7556 | 7602 | </p> |
| 7557 | | {#code_begin|syntax#} |
| 7603 | {#syntax_block|zig|cmpxchgWeakButNotAtomic#} |
| 7558 | 7604 | fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_value: T) ?T { |
| 7559 | 7605 | const old_value = ptr.*; |
| 7560 | 7606 | if (old_value == expected_value and usuallyTrueButSometimesFalse()) { |
| ... | ... | @@ -7564,7 +7610,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val |
| 7564 | 7610 | return old_value; |
| 7565 | 7611 | } |
| 7566 | 7612 | } |
| 7567 | | {#code_end#} |
| 7613 | {#end_syntax_block#} |
| 7568 | 7614 | <p> |
| 7569 | 7615 | If you are using cmpxchg in a loop, the sporadic failure will be no problem, and {#syntax#}cmpxchgWeak{#endsyntax#} |
| 7570 | 7616 | is the better choice, because it can be implemented more efficiently in machine instructions. |
| ... | ... | @@ -10159,7 +10205,7 @@ pub fn main() void { |
| 10159 | 10205 | This expression is evaluated at compile-time and is used to control |
| 10160 | 10206 | preprocessor directives and include multiple <code class="file">.h</code> files: |
| 10161 | 10207 | </p> |
| 10162 | | {#code_begin|syntax#} |
| 10208 | {#syntax_block|zig|@cImport Expression#} |
| 10163 | 10209 | const builtin = @import("builtin"); |
| 10164 | 10210 | |
| 10165 | 10211 | const c = @cImport({ |
| ... | ... | @@ -10173,7 +10219,7 @@ const c = @cImport({ |
| 10173 | 10219 | } |
| 10174 | 10220 | @cInclude("soundio.h"); |
| 10175 | 10221 | }); |
| 10176 | | {#code_end#} |
| 10222 | {#end_syntax_block#} |
| 10177 | 10223 | {#see_also|@cImport|@cInclude|@cDefine|@cUndef|@import#} |
| 10178 | 10224 | {#header_close#} |
| 10179 | 10225 | |