Outils pour utilisateurs

Outils du site


lang:cpp:coroutine

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
lang:cpp:coroutine [2019/11/15 13:19] – Mise à jour de "await" avec une valeur de retour à std::future rootlang:cpp:coroutine [2023/04/27 05:05] (Version actuelle) – Ajout de "Gajendra Gulgulia" root
Ligne 1: Ligne 1:
-===co_await===+====Exemples==== 
 +===co_yield=== 
 +Version Visual Studio :
 <code cpp> <code cpp>
 #include <iostream> #include <iostream>
Ligne 19: Ligne 21:
   }   }
 } }
 +</code>
 +
 +Version gcc/clang :
 +
 +<code cpp>
 +#include <coroutine>
 +#include <memory>
 +#include <iostream>
 +
 +namespace coro_exp {
 +
 +  template<typename T>
 +  class generator {
 +   public:
 +    struct promise_type;
 +    using handle_type = std::coroutine_handle<promise_type>;
 +   private:
 +    handle_type coro;
 +   public:
 +    explicit generator(handle_type h) : coro(h) {}
 +    generator(const generator &) = delete;
 +    generator(generator &&oth) noexcept : coro(oth.coro) {
 +      oth.coro = nullptr;
 +    }
 +    generator &operator=(const generator &) = delete;
 +    generator &operator=(generator &&other) noexcept {
 +      coro = other.coro;
 +      other.coro = nullptr;
 +      return *this;
 +    }
 +    ~generator() {
 +      if (coro) {
 +        coro.destroy();
 +      }
 +    }
 +
 +    bool next() {
 +      coro.resume();
 +      return not coro.done();
 +    }
 +
 +    T getValue() {
 +      return coro.promise().current_value;
 +    }
 +
 +    struct promise_type {
 +     private:
 +      T current_value{};
 +      friend class generator;
 +     public:
 +      promise_type() = default;
 +      ~promise_type() = default;
 +      promise_type(const promise_type&) = delete;
 +      promise_type(promise_type&&) = delete;
 +      promise_type &operator=(const promise_type&) = delete;
 +      promise_type &operator=(promise_type&&) = delete;
 +
 +      auto initial_suspend() {
 +        return std::suspend_always{};
 +      }
 +
 +      auto final_suspend() {
 +        return std::suspend_always{};
 +      }
 +
 +      auto get_return_object() {
 +        return generator{handle_type::from_promise(*this)};
 +      }
 +
 +      auto return_void() {
 +        return std::suspend_never{};
 +      }
 +
 +      auto yield_value(T some_value) {
 +        current_value = some_value;
 +        return std::suspend_always{};
 +      }
 +
 +      void unhandled_exception() {
 +        std::exit(1);
 +      }
 +    };
 +  };
 +
 +} // coroutn_exp
 +
 +using coro_exp::generator;
 +
 +static constexpr int demo_ceiling = 100;
 +
 +generator<int> loop(int iterations)
 +{
 +  for (int i = 0; i < iterations; i++)
 +  {
 +    co_yield i;
 +  }
 +}
 +
 +
 +int main() {
 +  auto iter = loop(demo_ceiling);
 +  while(iter.next()) {
 +    const auto value = iter.getValue();
 +    std::cout << value << '\n';
 +  }
 +}
 +
 </code> </code>
  
Ligne 76: Ligne 185:
  Only after resumed !  Only after resumed !
 </code> </code>
 +
 +====Tutorial====
 +
 +===Gajendra Gulgulia===
 +
 +[[https://ggulgulia.medium.com/painless-c-coroutines-part-1-ba90dd101adb|Painless C++ Coroutines-Part 1]] {{ :lang:cpp:coroutine:painless_c_coroutines_-part_1._learn_how_to_cretae_a_simple_coroutine_by_gajendra_gulgulia_may_2021_medium_medium_2023-02-25_11_53_43_.html |Archive du 31/05/2021 le 25/02/2023}}
 +
 +  * Partie 4
 +
 +<code cpp>
 +#include <coroutine>
 +#include <iostream>
 +
 +//global counter
 +int num{0};
 +
 +struct ReturnObject{
 +  struct promise_type{
 +    
 +    promise_type(){std::cout <<  num++ << ". promise_type default ctor\n";}
 +
 +    ReturnObject get_return_object() { 
 +        std::cout <<  num++ << ". promise_type::get_return_object\n";
 +        return {}; 
 +    }
 +
 +    std::suspend_never initial_suspend() {
 +         std::cout <<  num++ << ". promise_type::initial_suspend\n";
 +         return {}; 
 +    }
 +    
 +    std::suspend_never final_suspend() noexcept{ 
 +        std::cout <<  num++ << ". promise_type::final_suspend\n";
 +        return {};
 +    }
 +    
 +    void unhandled_exception(){std::cout <<  num++ << ".throw\n";}
 +  };
 +};
 +
 +ReturnObject foo(){
 +    
 +    std::cout <<  num++ << " hello from coroutine1\n";
 +    co_await std::suspend_never{}; //never suspend the coroutine at this point
 +    co_await std::suspend_never{}; //never suspend the coroutine at this point
 +    co_await std::suspend_always{}; //suspend the coroutine at this point
 +    std::cout <<  num++ << " hello from coroutine2\n";   
 +
 +
 +int main(){foo();
 +        std::cout <<  num++ << ". END\n";
 +}
 +</code>
 +
 +  * Partie 5
 +
 +[[https://ggulgulia.medium.com/painless-coroutines-part2-29b36008b507|Painless C++ Coroutines-Part 2]] {{ :lang:cpp:coroutine:painless_c_coroutines-part_2._as_promised_i_continue_the_journey_of_by_gajendra_gulgulia_medium_2023-02-25_11_53_45_.html |Archive du 31/05/2021 le 25/02/2023}}
 +
 +<code cpp>
 +#include <concepts>
 +#include <coroutine>
 +#include <exception>
 +#include <iostream>
 +
 +static int ctr{0};
 +
 +struct ReturnObject {
 +    struct promise_type {
 +        ReturnObject get_return_object() {
 +            // call ctor of ReturnObject with the coroutine handle
 +            return {
 +                std::coroutine_handle<promise_type>::from_promise(*this)};  // A
 +        }
 +        std::suspend_never initial_suspend() { return {}; }
 +        std::suspend_never final_suspend() noexcept { return {}; }
 +        void unhandled_exception() {}
 +    };
 +
 +    // B.3 implicit conversion operator
 +    operator std::coroutine_handle<>() const { return h_; }
 +
 +   private:
 +    std::coroutine_handle<> h_;  // B.1: member variable
 +
 +    ReturnObject(std::coroutine_handle<> h) : h_{h} {}  // B.2: ctor
 +};
 +
 +// coroutine
 +ReturnObject foo() {
 +    std::cout << ++ctr << ". hello from coroutine 1\n";
 +    co_await std::suspend_always{};  // suspend the coroutine at this point
 +    std::cout << ++ctr << ". hello from coroutine 2\n";
 +    co_await std::suspend_always{};  // suspend the coroutine at this point
 +    std::cout << ++ctr << ". hello from coroutine 3\n";
 +}
 +
 +// main
 +int main() {
 +    std::coroutine_handle<> h = foo();
 +    std::cout << ++ctr << ". resuming coroutine from main 1\n";
 +    h();
 +    std::cout << ++ctr << ". resuming coroutine from main 2\n";
 +    h.resume();  // same as h()
 +}
 +</code>
 +
 +  * Partie 6.2
 +
 +<code cpp>
 +#include <concepts>
 +#include <coroutine>
 +#include <exception>
 +#include <iostream>
 +
 +int ctr{0};
 +
 +struct suspend_always {
 +    bool await_ready() const noexcept {
 +        std::cout << ++ctr << ". suspend_always::await_ready\n";
 +        return false;
 +    }
 +    void await_suspend(std::coroutine_handle<> h) const noexcept {
 +        std::cout << ++ctr << ". suspend_always::await_suspend\n";
 +    }
 +    void await_resume() const noexcept {
 +        std::cout << ++ctr << ". suspend_always::await_resume\n";
 +    }
 +};
 +
 +// ReturnObject same as in section 5
 +struct ReturnObject {
 +    struct promise_type {
 +        unsigned value_{0};
 +        ReturnObject get_return_object() {
 +            return {std::coroutine_handle<promise_type>::from_promise(*this)};
 +        }
 +        std::suspend_never initial_suspend() noexcept { return {}; }
 +        std::suspend_never final_suspend() noexcept { return {}; }
 +        void unhandled_exception() {}
 +    };
 +
 +    std::coroutine_handle<promise_type> h_;
 +    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
 +    operator std::coroutine_handle<>() const { return h_; }
 +};
 +
 +ReturnObject foo() {
 +    std::cout << ++ctr << ". first hello from coroutine\n";
 +
 +    co_await suspend_always{};  // evaluate custom awaiter
 +
 +    std::cout << ++ctr << ". second hello from coroutine\n";
 +}
 +
 +int main() {
 +    std::coroutine_handle<> h = foo();
 +    std::cout << ++ctr << ". main\n";
 +    h();
 +}
 +</code>
 +
 +  * Partie 6.3
 +
 +<code cpp>
 +#include <concepts>
 +#include <coroutine>
 +#include <exception>
 +#include <iostream>
 +
 +int ctr{0};
 +
 +struct suspend_always {
 +    bool await_ready() const noexcept {
 +        std::cout << ++ctr << ". suspend_always::await_ready\n";
 +        return false;
 +    }
 +
 +    bool await_suspend(std::coroutine_handle<> h) const noexcept {
 +        std::cout << ++ctr << ". suspend_always::await_suspend\n";
 +        return true;  // Change it.
 +    }
 +    void await_resume() const noexcept {
 +        std::cout << ++ctr << ". suspend_always::await_resume\n";
 +    }
 +};
 +
 +struct ReturnObject {
 +    struct promise_type {
 +        unsigned value_{0};
 +        ReturnObject get_return_object() {
 +            return {std::coroutine_handle<promise_type>::from_promise(*this)};
 +        }
 +        std::suspend_never initial_suspend() { return {}; }
 +        std::suspend_never final_suspend() noexcept { return {}; }
 +        void unhandled_exception() {}
 +    };
 +
 +    std::coroutine_handle<promise_type> h_;
 +    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
 +    operator std::coroutine_handle<>() const { return h_; }
 +};
 +
 +ReturnObject foo() {
 +    std::cout << ++ctr << ". first hello from coroutine\n";
 +    co_await suspend_always{};  // evaluate custom awaiter
 +    std::cout << ++ctr << ". second hello from coroutine\n";
 +    co_await std::suspend_always{};
 +    std::cout << ++ctr << ". third hello from coroutine\n";
 +}
 +
 +int main() { std::coroutine_handle<> h = foo(); }
 +</code>
 +
 +
 +  * Partie 6.4
 +
 +<code cpp>
 +#include <concepts>
 +#include <coroutine>
 +#include <exception>
 +#include <iostream>
 +
 +int ctr{0};
 +
 +// ReturnObject same as in section 5
 +struct ReturnObject {
 +    struct promise_type {
 +        unsigned value_{0};
 +        ReturnObject get_return_object() {
 +            return {std::coroutine_handle<promise_type>::from_promise(*this)};
 +        }
 +        std::suspend_never initial_suspend() {
 +            std::cout << ++ctr << ". promise_type::initial_suspend\n";
 +            return {};
 +        }
 +        std::suspend_never final_suspend() noexcept { return {}; }
 +        void unhandled_exception() {}
 +    };
 +
 +    std::coroutine_handle<promise_type> h_;
 +    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
 +    operator std::coroutine_handle<>() const { return h_; }
 +};
 +
 +struct suspend_always {
 +    bool await_ready() const noexcept {
 +        std::cout << ++ctr << ". suspend_always::await_ready\n";
 +        return false;
 +    }
 +    void await_suspend(
 +        std::coroutine_handle<ReturnObject::promise_type> h) const noexcept {
 +        std::cout << ++ctr << ". suspend_always::await_suspend\n";
 +    }
 +    void await_resume() const noexcept {
 +        std::cout << ++ctr << ". suspend_always::await_resume\n";
 +    }
 +};
 +
 +ReturnObject foo() {
 +    std::cout << ++ctr << ". first hello from coroutine\n";
 +
 +    co_await suspend_always{};  // evaluate custom awaiter
 +
 +    std::cout << ++ctr << ". second hello from coroutine\n";
 +}
 +
 +int main() {
 +    std::coroutine_handle<> h = foo();
 +    std::cout << ++ctr << ". resuming coroutinefrom main\n";
 +    h();
 +}
 +</code>
 +
 +  * Partie 6.5
 +
 +<code cpp>
 +#include <concepts>
 +#include <coroutine>
 +#include <exception>
 +#include <iostream>
 +
 +int ctr{0};
 +
 +template <typename PromiseType = void>  // note this
 +struct suspend_always {
 +    bool await_ready() const noexcept {
 +        std::cout << ++ctr << ". suspend_always::await_ready\n";
 +        return false;
 +    }
 +    /*********** and this **********/
 +    void await_suspend(std::coroutine_handle<PromiseType> h) const noexcept {
 +        std::cout << ++ctr << ". suspend_always::await_suspend\n";
 +    }
 +    void await_resume() const noexcept {
 +        std::cout << ++ctr << ". suspend_always::await_resume\n";
 +    }
 +};
 +
 +// same as in section 5
 +struct ReturnObject {
 +    struct promise_type {
 +        unsigned value_{0};
 +        ReturnObject get_return_object() {
 +            return {std::coroutine_handle<promise_type>::from_promise(*this)};
 +        }
 +        std::suspend_never initial_suspend() { return {}; }
 +        std::suspend_never final_suspend() noexcept { return {}; }
 +        void unhandled_exception() {}
 +    };
 +
 +    std::coroutine_handle<> h_;
 +    ReturnObject(std::coroutine_handle<> h) : h_{h} {}
 +    operator std::coroutine_handle<>() const { return h_; }
 +};
 +
 +ReturnObject foo() {
 +    std::cout << ++ctr << ". first hello from coroutine\n";
 +    co_await suspend_always<>{};  // note this
 +    co_await suspend_always<ReturnObject::promise_type>{};
 +    std::cout << ++ctr << ". second hello from coroutine\n";
 +}
 +
 +int main() {
 +    std::coroutine_handle<> h = foo();
 +    std::cout << ++ctr << ". resuming coroutine from main 1\n";
 +    h();
 +    std::cout << ++ctr << ". resuming coroutine from main 2\n";
 +    h();
 +}
 +</code>
 +
 +[[https://ggulgulia.medium.com/painless-c-coroutine-part-3-536e4bce4f4f|Painless C++ Coroutine-Part 3]] {{ :lang:cpp:coroutine:painless_c_coroutines-part_3._in_first_part_of_the_issue_painless_by_gajendra_gulgulia_medium_2023-02-25_11_53_46_.html |Archive du 31/05/2021 le 25/02/2023}}
 +
 +  * Partie 7.1
 +
 +<code cpp>
 +#include <concepts>
 +#include <coroutine>
 +#include <exception>
 +#include <iostream>
 +#include <memory>
 +
 +// custom suspend_never
 +struct suspend_never {
 +    double* val_{new double(10.234)};
 +    bool await_ready() const noexcept { return true; }
 +    void await_suspend(std::coroutine_handle<> h) const noexcept {}
 +    double* await_resume() const noexcept { return val_; }
 +};
 +
 +// ReturnObject
 +struct ReturnObject {
 +    struct promise_type {
 +        unsigned value_{0};
 +        ReturnObject get_return_object() {
 +            return {std::coroutine_handle<promise_type>::from_promise(*this)};
 +        }
 +        std::suspend_never initial_suspend() { return {}; }
 +        std::suspend_never final_suspend() noexcept { return {}; }
 +        void unhandled_exception() {}
 +    };
 +
 +    std::coroutine_handle<promise_type> h_;
 +    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
 +    operator std::coroutine_handle<>() const { return h_; }
 +};
 +
 +// coroutine
 +ReturnObject foo() {
 +    // temporary suspend_never is destroyed after evaluation
 +    auto val1 = co_await suspend_never{};
 +    std::cout << *val1 << "\n";  //(1)
 +
 +    *val1 = 20.234;
 +    delete val1;
 +
 +    auto val2 = co_await suspend_never{};
 +    std::cout << *val2 << "\n";  //(2) == (1)
 +    delete val2;
 +}
 +
 +// main
 +int main() { std::coroutine_handle<> h = foo(); }
 +</code>
 +
 +  * Partie 7.2
 +
 +<code cpp>
 +#include <concepts>
 +#include <coroutine>
 +#include <exception>
 +#include <iostream>
 +
 +int ctr{0};
 +
 +template <typename PromiseType = void>  // 1
 +struct suspend_never {
 +    PromiseType* promise_{nullptr};  // 2.a
 +    bool await_ready() const noexcept { return false; }
 +
 +    void await_suspend(std::coroutine_handle<PromiseType> h) noexcept {
 +        promise_ = &h.promise();  // 2.b
 +    }
 +
 +    PromiseType* await_resume() const noexcept { return promise_; }  // 2.c
 +};
 +
 +struct ReturnObject {
 +    struct promise_type {
 +        int val_{11}; /*<---------------------- Note this  */
 +        ReturnObject get_return_object() {
 +            return {std::coroutine_handle<promise_type>::from_promise(*this)};
 +        }
 +        std::suspend_never initial_suspend() { return {}; }
 +        std::suspend_never final_suspend() noexcept { return {}; }
 +        void unhandled_exception() {}
 +    };
 +
 +    std::coroutine_handle<promise_type> h_;
 +    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
 +    operator std::coroutine_handle<>() const { return h_; }
 +};
 +
 +ReturnObject foo() {
 +    auto promise =
 +        co_await suspend_never<ReturnObject::promise_type>{};  // 1, 2.d
 +    std::cout << promise->val_ << "\n";
 +}
 +
 +int main() {
 +    std::coroutine_handle<> h = foo();
 +    h();
 +}
 +</code>
 +
 +  * Partie 7.3
 +
 +<code cpp>
 +#include <concepts>
 +#include <coroutine>
 +#include <exception>
 +#include <iostream>
 +
 +int ctr{0};
 +
 +template <typename PromiseType = void>  // 1
 +struct suspend_never {
 +    PromiseType* promise_{nullptr};  // 2.a
 +    bool await_ready() const noexcept { return false; }
 +
 +    void await_suspend(std::coroutine_handle<PromiseType> h) noexcept {
 +        promise_ = &h.promise();  // 2.b
 +    }
 +
 +    PromiseType* await_resume() const noexcept { return promise_; }  // 2.c
 +};
 +
 +struct ReturnObject {
 +    struct promise_type {
 +        int val_{11}; /*<------------- Note this  */
 +        ReturnObject get_return_object() {
 +            return {std::coroutine_handle<promise_type>::from_promise(*this)};
 +        }
 +        std::suspend_never initial_suspend() { return {}; }
 +        std::suspend_never final_suspend() noexcept { return {}; }
 +        void unhandled_exception() {}
 +    };
 +
 +    std::coroutine_handle<promise_type> h_;
 +    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
 +    operator std::coroutine_handle<promise_type>() const { return h_; }
 +};
 +
 +ReturnObject foo() {
 +    auto promise =
 +        co_await suspend_never<ReturnObject::promise_type>{};  // 1, 2.d
 +    std::cout << "From coroutine " << promise->val_ << "\n";
 +}
 +
 +int main() {
 +    std::coroutine_handle<ReturnObject::promise_type> h = foo();
 +    ReturnObject::promise_type prom = h.promise();
 +    std::cout << "From main: " << prom.val_ << "\n";
 +    h();
 +}
 +</code>
 +
 +  * Partie 7.4
 +
 +<code cpp>
 +#include <concepts>
 +#include <coroutine>
 +#include <exception>
 +#include <iostream>
 +#include <thread>
 +
 +int ctr{0};
 +template <typename PromiseType = void>
 +struct suspend_never {
 +    PromiseType* promise_{nullptr};
 +    bool await_ready() const noexcept { return false; }  //
 +
 +    bool await_suspend(std::coroutine_handle<PromiseType> h) noexcept {
 +        promise_ = &h.promise();
 +
 +        std::cout << ctr++ << ". In suspend_always::await_suspend\n"
 +                  << "   Do further processing on promise_->_val = "
 +                  << promise_->val_ << " ... \n";
 +
 +        return false;
 +    }
 +
 +    PromiseType* await_resume() const noexcept { return promise_; }
 +};
 +
 +struct ReturnObject {
 +    struct promise_type {
 +        int val_;
 +        ReturnObject get_return_object() {
 +            return {std::coroutine_handle<promise_type>::from_promise(*this)};
 +        }
 +        std::suspend_never initial_suspend() { return {}; }
 +        std::suspend_never final_suspend() noexcept { return {}; }
 +        void unhandled_exception() {}
 +    };
 +
 +    std::coroutine_handle<promise_type> h_;
 +    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
 +    operator std::coroutine_handle<promise_type>() const { return h_; }
 +};
 +
 +using PromType = ReturnObject::promise_type;
 +
 +ReturnObject foo() {
 +    std::cout
 +        << ctr++
 +        << ". Suspending the coroutine for 1st time with trivial awaitable\n";
 +    co_await std::suspend_always{};
 +
 +    std::cout
 +        << ctr++
 +        << ". Suspending the coroutine for 2nd time with custom awaitable\n";
 +    auto promise = co_await suspend_never<PromType>{};
 +    std::cout << ctr++ << ". Coroutine finished\n";
 +}
 +
 +int main() {
 +    std::coroutine_handle<PromType> h = foo();
 +    PromType* prom = &h.promise();
 +
 +    std::cout << ctr++
 +              << ". From main: current value of promise_->val_: " << prom->val_
 +              << "\n";  // access promise.val_ in main
 +    std::cout << ctr++
 +              << ". Changing  promise_->val_ in main and resuming coroutine\n";
 +
 +    prom->val_ = 21;
 +    h();
 +
 +    std::cout << ctr++ << ". main finished\n";
 +}
 +</code>
 +
 +  * Partie 8
 +
 +KO :
 +
 +<code cpp>
 +#include <concepts>
 +#include <coroutine>
 +#include <exception>
 +#include <iostream>
 +
 +int ctr{0};
 +
 +template <typename PromiseType = void>  // 1
 +struct suspend_always {
 +    PromiseType* promise_{nullptr};  // 2.a
 +    bool await_ready() const noexcept { return false; }
 +
 +    void await_suspend(std::coroutine_handle<PromiseType> h) noexcept {
 +        promise_ = &h.promise();  // 2.b
 +    }
 +
 +    PromiseType* await_resume() const noexcept { return promise_; }  // 2.c
 +};
 +
 +struct ReturnObject {
 +    struct promise_type {
 +        int val_; /*<---------------------------------------------- Note this */
 +        ReturnObject get_return_object() {
 +            return {std::coroutine_handle<promise_type>::from_promise(*this)};
 +        }
 +        std::suspend_never initial_suspend() { return {}; }
 +        std::suspend_never final_suspend() noexcept { return {}; }
 +        void unhandled_exception() {}
 +    };
 +
 +    std::coroutine_handle<promise_type> h_;
 +    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
 +    operator std::coroutine_handle<promise_type>() const { return h_; }
 +};
 +
 +using PromType = ReturnObject::promise_type;
 +ReturnObject generator() {
 +    auto promise = co_await suspend_always<PromType>{};
 +    for (int i = 0;; i++) {
 +        promise->val_ = i;
 +        co_await std::suspend_always{};
 +    }
 +}
 +
 +int main() {
 +    std::coroutine_handle<PromType> h = generator();
 +    PromType& prom = h.promise();
 +    for (int i = 0; i < 5; ++i) {
 +        std::cout << "From main: " << prom.val_ << "\n";
 +        h();
 +    }
 +}
 +</code>
 +
 +OK :
 +
 +<code cpp>
 +#include <concepts>
 +#include <coroutine>
 +#include <exception>
 +#include <iostream>
 +
 +template <typename PromiseType = void>
 +struct suspend_never {
 +    PromiseType* promise_{nullptr};
 +    bool await_ready() const noexcept { return false; }
 +
 +    bool await_suspend(std::coroutine_handle<PromiseType> h) noexcept {
 +        promise_ = &h.promise();
 +        return false;
 +    }
 +
 +    PromiseType* await_resume() const noexcept { return promise_; }
 +};
 +
 +struct ReturnObject {
 +    struct promise_type {
 +        int val_;
 +        ReturnObject get_return_object() {
 +            return {std::coroutine_handle<promise_type>::from_promise(*this)};
 +        }
 +        std::suspend_never initial_suspend() { return {}; }
 +        std::suspend_never final_suspend() noexcept { return {}; }
 +        void unhandled_exception() {}
 +    };
 +
 +    std::coroutine_handle<promise_type> h_;
 +    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
 +    operator std::coroutine_handle<promise_type>() const { return h_; }
 +};
 +
 +using PromType = ReturnObject::promise_type;
 +
 +ReturnObject generator() {
 +    auto promise = co_await suspend_never<PromType>{};
 +    for (int i = 0;; i++) {
 +        promise->val_ = i;
 +        co_await std::suspend_always{};
 +    }
 +}
 +
 +ReturnObject evenNumberGenerator() {
 +    auto promise = co_await suspend_never<PromType>{};
 +    for (int i = 0;; i = i + 2) {
 +        promise->val_ = i;
 +        co_await std::suspend_always{};
 +    }
 +}
 +
 +ReturnObject oddNumberGenerator() {
 +    auto promise = co_await suspend_never<PromType>{};
 +    for (int i = 1;; i = i + 2) {
 +        promise->val_ = i;
 +        co_await std::suspend_always{};
 +    }
 +}
 +
 +int main() {
 +    std::coroutine_handle<PromType> h = generator();
 +    PromType& prom = h.promise();
 +    for (int i = 0; i < 5; ++i) {
 +        std::cout << "From main: " << prom.val_ << "\n";
 +        h();
 +    }
 +}
 +</code>
 +
 +[[https://ggulgulia.medium.com/painless-c-coroutines-part-4-69117214bfdc|Painless C++ Coroutines-Part 4]] {{ :lang:cpp:coroutine:painless_c_coroutines-part_4._in_part_one_two_and_three_of_the_by_gajendra_gulgulia_medium_2023-02-25_11_53_48_.html |Archive du 13/06/2021 le 25/02/2023
 +}}
 +  * Partie 9
 +
 +<code cpp>
 +#include <concepts>
 +#include <coroutine>
 +#include <exception>
 +#include <iostream>
 +
 +struct ReturnObject {
 +    struct promise_type {
 +        int val_;
 +        ReturnObject get_return_object() {
 +            return {std::coroutine_handle<promise_type>::from_promise(*this)};
 +        }
 +        std::suspend_never initial_suspend() noexcept { return {}; }
 +        std::suspend_never final_suspend() noexcept { return {}; }
 +        std::suspend_always yield_value(int value) {
 +            val_ = value;
 +            return {};
 +        }
 +        void unhandled_exception() {}
 +    };
 +
 +    std::coroutine_handle<promise_type> h_;
 +    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
 +    operator std::coroutine_handle<promise_type>() const { return h_; }
 +};
 +
 +using PromType = ReturnObject::promise_type;
 +
 +ReturnObject generator() {
 +    for (int i = 0;; i++) {
 +        co_yield i;
 +    }
 +}
 +
 +int main() {
 +    std::coroutine_handle<PromType> h = generator();
 +    PromType& prom = h.promise();
 +    for (int i = 0; i < 5; ++i) {
 +        std::cout << "From main: " << prom.val_ << "\n";
 +        h();
 +    }
 +}
 +
 +ReturnObject evenNumberGenerator() {
 +    for (int i = 0;; i = i + 2) {
 +        co_yield i;
 +    }
 +}
 +
 +ReturnObject oddNumberGenerator() {
 +    for (int i = 1;; i = i + 2) {
 +        co_yield i;
 +    }
 +}
 +</code>
 +
 +  * Partie 10
 +
 +<code cpp>
 +#include <concepts>
 +#include <coroutine>
 +#include <exception>
 +#include <iostream>
 +
 +template <typename T>
 +struct ReturnObject {
 +    struct promise_type {
 +        T val_;
 +        ReturnObject get_return_object() {
 +            return {std::coroutine_handle<promise_type>::from_promise(*this)};
 +        }
 +        std::suspend_never initial_suspend() noexcept { return {}; }
 +        std::suspend_never final_suspend() noexcept { return {}; }
 +        std::suspend_always yield_value(T value) {
 +            val_ = value;
 +            return {};
 +        }
 +        void unhandled_exception() {}
 +    };
 +
 +    std::coroutine_handle<promise_type> h_;
 +    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
 +    operator std::coroutine_handle<promise_type>() const { return h_; }
 +};
 +
 +using PromType = ReturnObject<float>::promise_type;
 +
 +template <typename T>
 +ReturnObject<T> generator() {
 +    for (int i = 0;; i++) {
 +        co_yield 1.234 + static_cast<T>(i);
 +    }
 +}
 +
 +int main() {
 +    std::coroutine_handle<PromType> h = generator<float>();
 +    PromType& prom = h.promise();
 +    for (int i = 0; i < 5; ++i) {
 +        std::cout << "From main: " << prom.val_ << "\n";
 +        h();
 +    }
 +}
 +</code>
 +
 +[[https://ggulgulia.medium.com/painless-c-coroutines-part-5-f28e74c58a2c|Painless C++ Coroutines-Part 5]] {{ :lang:cpp:coroutine:painless_c_coroutines-part_5._in_the_fifth_issue_of_the_tutorial_by_gajendra_gulgulia_medium_2023-02-25_11_53_49_.html |Archive du 13/06/2021 le 25/02/2023}}
 +
 +  * Partie 11.1
 +
 +<code cpp>
 +#include <concepts>
 +#include <coroutine>
 +#include <exception>
 +#include <iostream>
 +
 +struct ReturnObject {
 +    struct promise_type {
 +        int val_{23};
 +        ReturnObject get_return_object() {
 +            return {std::coroutine_handle<promise_type>::from_promise(*this)};
 +        }
 +        std::suspend_never initial_suspend() noexcept { return {}; }
 +        std::suspend_never final_suspend() noexcept { return {}; }
 +        void unhandled_exception() {}
 +        void return_void() {}
 +    };
 +
 +    std::coroutine_handle<promise_type> h_;
 +    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
 +    operator std::coroutine_handle<promise_type>() const { return h_; }
 +};
 +
 +using PromType = ReturnObject::promise_type;
 +
 +ReturnObject foo() { co_return; }
 +
 +int main() {
 +    std::coroutine_handle<PromType> h = foo();
 +    std::cout << h.promise().val_ << "\n";
 +}
 +</code>
 +
 +  * Partie 11.2
 +
 +<code cpp>
 +#include <concepts>
 +#include <coroutine>
 +#include <exception>
 +#include <iostream>
 +
 +struct ReturnObject {
 +    struct promise_type {
 +        int val_;
 +        ReturnObject get_return_object() {
 +            return {std::coroutine_handle<promise_type>::from_promise(*this)};
 +        }
 +        std::suspend_never initial_suspend() noexcept { return {}; }
 +        std::suspend_never final_suspend() noexcept { return {}; }
 +        void unhandled_exception() {}
 +        void return_value(int val) { val_ = val; }
 +    };
 +
 +    std::coroutine_handle<promise_type> h_;
 +    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
 +    operator std::coroutine_handle<promise_type>() const { return h_; }
 +};
 +
 +using PromType = ReturnObject::promise_type;
 +
 +ReturnObject foo() { co_return 121; }
 +
 +int main() {
 +    std::coroutine_handle<PromType> h = foo();
 +    std::cout << h.promise().val_ << "\n";
 +}
 +</code>
 +
 +  * Partie 12
 +
 +<code cpp>
 +#include <concepts>
 +#include <coroutine>
 +#include <exception>
 +#include <iostream>
 +
 +struct ReturnObject {
 +    struct promise_type {
 +        int val_;
 +        ReturnObject get_return_object() {
 +            return {std::coroutine_handle<promise_type>::from_promise(*this)};
 +        }
 +        std::suspend_never initial_suspend() noexcept { return {}; }
 +        void return_void() { std::cout << "called return_void\n"; }
 +        std::suspend_always final_suspend() noexcept { return {}; }
 +        void unhandled_exception() {}
 +    };
 +
 +    std::coroutine_handle<promise_type> h_;
 +    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
 +    operator std::coroutine_handle<promise_type>() const { return h_; }
 +};
 +
 +ReturnObject foo() { co_await std::suspend_never{}; }
 +int main() { foo(); }
 +</code>
 +
 +<code cpp>
 +#include <concepts>
 +#include <coroutine>
 +#include <exception>
 +#include <iostream>
 +
 +struct ReturnObject {
 +    struct promise_type {
 +        int val_;
 +        ReturnObject get_return_object() {
 +            return {std::coroutine_handle<promise_type>::from_promise(*this)};
 +        }
 +        std::suspend_never initial_suspend() noexcept { return {}; }
 +
 +        std::suspend_always final_suspend() noexcept {
 +            std::cout << "suspending coroutine for one last time\n";
 +            return {};
 +        }
 +        void unhandled_exception() {}
 +
 +        void return_void() { std::cout << "return_void\n"; }
 +    };
 +
 +    std::coroutine_handle<promise_type> h_;
 +    ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {}
 +    operator std::coroutine_handle<promise_type>() const { return h_; }
 +};
 +
 +using PromType = ReturnObject::promise_type;
 +
 +ReturnObject foo() { co_await std::suspend_never{}; }
 +
 +int main() {
 +    std::coroutine_handle<PromType> h = foo();
 +    PromType* prom = &h.promise();
 +    /*
 +     call h.resume() many times
 +    */
 +    if (h.done()) {
 +        /*
 +          do something with prom one last time
 +        */
 +        std::cout << "done execution of coroutine\n";
 +        h.destroy();
 +    }
 +}
 +</code>
 +
lang/cpp/coroutine.1573820387.txt.gz · Dernière modification : 2019/11/15 13:19 de root