5.3.17. C++ Integration: Coroutines
This tutorial shows how to consume a daslang generator (coroutine)
from C++. A daslang function returns a generator<int> via
return <-. The C++ host receives a Sequence iterator and steps
through it one value at a time.
Topics covered:
Sequence— the C++ type that wraps a daslang generatorevalWithCatchwith a third&Sequenceparameter to capture generatorsbuiltin_iterator_iterate— single-step the generatorbuiltin_iterator_close— clean up generator resources
5.3.17.1. Prerequisites
Tutorial 01 completed (tutorial_integration_cpp_hello_world).
Familiarity with daslang generators (
generator<T>andyield).
5.3.17.2. The daslang side
The script defines a function that returns a generator of integers.
Each yield pauses execution and passes a value to the host:
options gen2
[export]
def test {
return <- generator<int>() <| $() {
for (i in range(5)) {
print(" [das] yielding {i}\n")
yield i
}
print(" [das] generator finished\n")
return false
}
}
The function creates the generator with generator<int>() <| $(),
fills it with a loop, and transfers ownership to the caller with
return <-.
5.3.17.3. Consuming a generator from C++
After compiling and simulating the script, we find the test function
and capture its returned generator into a Sequence:
Sequence it;
ctx.evalWithCatch(fnTest, nullptr, &it);
When the third argument of evalWithCatch is a pointer to Sequence,
the runtime fills it with the generator returned by the function.
5.3.17.4. Stepping through values
builtin_iterator_iterate advances the generator to its next yield
and writes the yielded value into a caller-provided buffer:
int32_t value = 0;
int step = 0;
while (builtin_iterator_iterate(it, &value, &ctx)) {
tout << " [c++] step " << step << " => value " << value << "\n";
step++;
}
Each call resumes the daslang generator, which runs until the next
yield (or returns false to finish).
5.3.17.5. Cleanup
Always call builtin_iterator_close when done — even if the generator
has already finished:
builtin_iterator_close(it, &value, &ctx);
This releases any resources held by the Sequence. If you break out
of the iteration early (before the generator returns false), this
call is essential.
5.3.17.6. Build & run
cmake --build build --config Release --target integration_cpp_17
bin/Release/integration_cpp_17
Expected output:
[das] yielding 0
[c++] step 0 => value 0
[das] yielding 1
[c++] step 1 => value 1
[das] yielding 2
[c++] step 2 => value 2
[das] yielding 3
[c++] step 3 => value 3
[das] yielding 4
[c++] step 4 => value 4
[das] generator finished
Generator produced 5 values total
The output is interleaved: each yield in daslang produces a
[das] line, and the C++ iteration loop produces a [c++] line.
See also
Full source:
17_coroutines.cpp,
17_coroutines.das
Previous tutorial: tutorial_integration_cpp_sandbox
Next tutorial: tutorial_integration_cpp_dynamic_scripts
Related: Generator