Thanks for using Compiler Explorer
Sponsors
Jakt
C++
Ada
Analysis
Android Java
Android Kotlin
Assembly
C
C3
Carbon
C++ (Circle)
CIRCT
Clean
CMake
CMakeScript
COBOL
C++ for OpenCL
MLIR
Cppx
Cppx-Blue
Cppx-Gold
Cpp2-cppfront
Crystal
C#
CUDA C++
D
Dart
Elixir
Erlang
Fortran
F#
Go
Haskell
HLSL
Hook
Hylo
ispc
Java
Julia
Kotlin
LLVM IR
LLVM MIR
Modula-2
Nim
Objective-C
Objective-C++
OCaml
OpenCL C
Pascal
Pony
Python
Racket
Ruby
Rust
Snowball
Scala
Solidity
Spice
Swift
LLVM TableGen
Toit
TypeScript Native
V
Vala
Visual Basic
WASM
Zig
Javascript
GIMPLE
zig source #1
Output
Compile to binary object
Link to binary
Execute the code
Intel asm syntax
Demangle identifiers
Verbose demangling
Filters
Unused labels
Library functions
Directives
Comments
Horizontal whitespace
Debug intrinsics
Compiler
zig 0.10.0
zig 0.11.0
zig 0.12.0
zig 0.12.1
zig 0.13.0
zig 0.2.0
zig 0.3.0
zig 0.4.0
zig 0.5.0
zig 0.6.0
zig 0.7.0
zig 0.7.1
zig 0.8.0
zig 0.9.0
zig trunk
Options
Source code
const std = @import("std"); const expect = std.testing.expect; const time = std.time; const Timer = time.Timer; // Helper class for Generator. An instance of this class is passed by pointer // to functions which intend to be used in Generator instances. It is used to // yield results. // // TODO: Find a better name for this. Thoughts: GeneratorProducer, // GeneratorHandle. fn Yielder(comptime T: type) type { return struct { const Self = @This(); next_result: ?T = null, // Place to stash the frame where the generator frame: anyframe = undefined, yield_waiter: ?anyframe = undefined, pub fn yield(self: *Self, t: T) void { self.next_result = t; std.debug.print("Yielder: about to yield\n", .{}); suspend { std.debug.print("Yielder: inside suspend\n", .{}); self.frame = @frame(); if (self.yield_waiter) |waiter| { std.debug.print("Yielder: about to resume waiter\n", .{}); resume waiter; } } self.next_result = null; } }; } // Class used to create an async generator from a function (generator_fn). fn Generator(comptime T: type, comptime generator_fn: fn (*Yielder(T)) void) type { return struct { const Self = @This(); // The object passed to generator_fn, which is used to yield results. yielder: Yielder(T) = Yielder(T){}, // The original Frame returned by the async call to generator_fn. frame: @Frame(generator_fn) = undefined, // Whether next has been called yet. have_started: bool = false, // Calls (or resumes) the generator_fn to get the next result, and then // returns it once the generator_fn calls Yielder.yield(result). pub fn next(self: *Self) ?T { if (!self.have_started) { self.have_started = true; std.debug.print("Generator: about to call generator_fn \n", .{}); self.frame = async generator_fn(&self.yielder); std.debug.print("Generator: done calling generator_fn \n", .{}); } else { resume self.yielder.frame; } if (self.yielder.next_result == null) { // If we reach this point, it means that the generator_fn has a suspend // point prior to the yield. We stash our frame inside the Yielder for it // to be resumed the next time yield is called. suspend { std.debug.print("Generator: suspending \n", .{}); self.yielder.yield_waiter = @frame(); } std.debug.print("Generator: Done suspending\n", .{}); } self.yielder.yield_waiter = null; return self.yielder.next_result; } }; } fn integers(generator: *Yielder(i64)) void { var n: i64 = 1; while (true) { generator.yield(n); n += 1; } } fn generate_integers_test() void { var generator = Generator(i64, integers){}; var i: i64 = 1; while (i < 10000000) : (i += 1) { // TODO: Without the .? the compiler crashes expect(generator.next().? == i); } } //test "generate integers" { // _ = async generate_integers_test(); //} fn squares(generator: *Yielder(i64)) void { var n: i64 = 1; while (true) { generator.yield(n * n); n += 1; } } fn generate_squares_test() void { var generator = Generator(i64, squares){}; var i: i64 = 1; while (i < 100000) : (i += 1) { expect(generator.next().? == i * i); } } //test "generate squares" { // _ = async generate_squares_test(); //} fn fibonacci(generator: *Yielder(i64)) void { var a: i64 = 0; var b: i64 = 1; while (true) { generator.yield(b); const next = a + b; a = b; b = next; } } var test_frame: anyframe = undefined; fn fibonacci_with_suspend(generator: *Yielder(i64)) void { var a: i64 = 0; var b: i64 = 1; while (true) { std.debug.print("fibonacci_with_suspend: about to suspend\n", .{}); suspend { test_frame = @frame(); } std.debug.print("fibonacci_with_suspend: about to yield\n", .{}); generator.yield(b); std.debug.print("fibonacci_with_suspend: after yield\n", .{}); const next = a + b; a = b; b = next; } } // Normal usage fn generate_fibonacci_test(generator: anytype, finished_test: *bool) void { expect(generator.next().? == @intCast(i64, 1)); expect(generator.next().? == @intCast(i64, 1)); expect(generator.next().? == @intCast(i64, 2)); expect(generator.next().? == @intCast(i64, 3)); expect(generator.next().? == @intCast(i64, 5)); expect(generator.next().? == @intCast(i64, 8)); expect(generator.next().? == @intCast(i64, 13)); finished_test.* = true; } test "generate fibonacci" { var generator = Generator(i64, fibonacci){}; var finished_test = false; _ = async generate_fibonacci_test(&generator, &finished_test); } // This simulates the case where the generator function has a suspend point // due to e.g. I/O in an event loop. We have to manually resume that suspend // point here before awaiting the result from next(). fn do_fibonacci_with_suspend_test_case(generator: anytype, n: i64) void { var frame = async generator.next(); resume test_frame; const next = await frame; expect(next.? == n); } fn generate_fibonacci_with_suspend_test(generator: anytype, finished_test: *bool) void { do_fibonacci_with_suspend_test_case(generator, 1); do_fibonacci_with_suspend_test_case(generator, 1); do_fibonacci_with_suspend_test_case(generator, 2); do_fibonacci_with_suspend_test_case(generator, 3); do_fibonacci_with_suspend_test_case(generator, 5); do_fibonacci_with_suspend_test_case(generator, 8); do_fibonacci_with_suspend_test_case(generator, 13); do_fibonacci_with_suspend_test_case(generator, 21); finished_test.* = true; } test "generate fibonacci with suspend" { var generator = Generator(i64, fibonacci_with_suspend){}; var finished_test = false; _ = async generate_fibonacci_with_suspend_test(&generator, &finished_test); expect(finished_test); } pub fn main() !void { var generator = Generator(i64, fibonacci_with_suspend){}; var finished_test = false; _ = async generate_fibonacci_with_suspend_test(&generator, &finished_test); expect(finished_test); }
Become a Patron
Sponsor on GitHub
Donate via PayPal
Source on GitHub
Mailing list
Installed libraries
Wiki
Report an issue
How it works
Contact the author
CE on Mastodon
About the author
Statistics
Changelog
Version tree