测试_第29章_协程.cpp

← 测试总览 · 目录

编译运行:clang++ -std=c++26 -Wall -Wextra -pthread 测试_第29章_协程.cpp -o t && ./t(需先 cd 测试/

// 第29章测试:协程与异步(生成器实现 + 验证)
// 编译需要 -fcoroutines-ts 或 C++20 原生协程支持
#include <print>
#include <coroutine>
#include <cstdint>
#include <exception>
#include <vector>
#include <cmath>

int failures = 0;
#define CHECK(expr)                                                         \
    do {                                                                    \
        if (!(expr)) {                                                      \
            ++failures;                                                     \
            std::println("FAIL 第{}行: {}", __LINE__, #expr);              \
        }                                                                   \
    } while (0)

// 29.3 最小生成器框架(教材级)
template <typename T>
class Generator {
public:
    struct promise_type;
    using handle = std::coroutine_handle<promise_type>;

    struct promise_type {
        T current;
        struct FinalAwaiter {
            bool await_ready() const noexcept { return false; }
            void await_suspend(handle) const noexcept {}
            void await_resume() const noexcept {}
        };
        Generator get_return_object() { return Generator{handle::from_promise(*this)}; }
        std::suspend_always initial_suspend() const noexcept { return {}; }
        FinalAwaiter final_suspend() const noexcept { return {}; }
        void return_void() const noexcept {}
        void unhandled_exception() { std::terminate(); }   // 异常处理(教材简化)
        std::suspend_always yield_value(T value) {
            current = std::move(value);
            return {};
        }
    };

    struct Iterator {
        handle h;
        bool operator!=(const Iterator&) const noexcept { return !h.done(); }
        void operator++() { h.resume(); }
        T& operator*() { return h.promise().current; }
    };

    Iterator begin() { h.resume(); return {h}; }
    Iterator end() { return {handle{}}; }
    Generator(Generator&& o) noexcept : h(o.h) { o.h = nullptr; }
    ~Generator() { if (h) h.destroy(); }
private:
    explicit Generator(handle h) : h(h) {}
    handle h;
};

// 29.2 生成器:区间
Generator<int> range(int from, int to) {
    for (int i = from; i < to; ++i)
        co_yield i;
}

// 29.4 无限斐波那契生成器
Generator<unsigned long long> fibonacci() {
    unsigned long long a = 0, b = 1;
    while (true) {
        co_yield a;
        unsigned long long t = a + b;
        a = b; b = t;
    }
}

// 练习3:质数生成器(朴素判定)
Generator<int> primes() {
    co_yield 2;
    for (int n = 3; ; n += 2) {
        bool ok = true;
        for (int d = 3; d * d <= n; d += 2)
            if (n % d == 0) { ok = false; break; }
        if (ok) co_yield n;
    }
}

// 练习4:平方生成器
Generator<long long> squares(int n) {
    for (int i = 1; i <= n; ++i)
        co_yield (long long)i * i;
}

int main() {
    // 29.2 基础生成器
    std::vector<int> got;
    for (int x : range(0, 5)) got.push_back(x);
    CHECK((got == std::vector<int>{0, 1, 2, 3, 4}));

    // 29.4 无限斐波那契(惰性:只取前 10 个)
    std::vector<unsigned long long> fibs;
    for (auto v : fibonacci()) {
        if (fibs.size() >= 10) break;
        fibs.push_back(v);
    }
    CHECK(fibs.size() == 10);
    CHECK(fibs[0] == 0 && fibs[1] == 1 && fibs[2] == 1);
    CHECK(fibs[9] == 34);

    // 惰性验证:无限序列只算需要的部分(上面已证明)
    // 生成器内存 O(1):连续取 1 亿个也不占内存(概念验证,
    // 这里取 10 万说明遍历可行)
    std::size_t count = 0;
    for (auto v : fibonacci()) {
        (void)v;
        if (++count >= 100'000) break;
    }
    CHECK(count == 100'000);

    // 练习3:前 10 个质数
    std::vector<int> ps;
    for (int p : primes()) {
        ps.push_back(p);
        if (ps.size() >= 10) break;
    }
    CHECK((ps == std::vector<int>{2, 3, 5, 7, 11, 13, 17, 19, 23, 29}));

    // 练习4:平方生成器
    std::vector<long long> sq;
    for (auto v : squares(5)) sq.push_back(v);
    CHECK((sq == std::vector<long long>{1, 4, 9, 16, 25}));

    // 生成器与算法配合:求和
    long long total = 0;
    for (auto v : range(1, 101)) total += v;
    CHECK(total == 5050);

    if (failures == 0) std::println("全部通过");
    return failures;
}