Task: Extensible prime generator

C: #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define CHUNK_BYTES (32 << 8)
#define CHUNK_SIZE (CHUNK_BYTES << 6)

int field[CHUNK_BYTES];
#define GET(x) (field[(x)>>6] &  1<<((x)>>1&31))
#define SET(x) (field[(x)>>6] |= 1<<((x)>>1&31))

typedef unsigned uint;
typedef struct {
        uint *e;
        uint cap, len;
} uarray;
uarray primes, offset;

void push(uarray *a, uint n)
{
        if (a->len >= a->cap) {
                if (!(a->cap *= 2)) a->cap = 16;
                a->e = realloc(a->e, sizeof(uint) * a->cap);
        }
        a->e[a->len++] = n;
}

uint low;
void init(void)
{
        uint p, q;

        unsigned char f[1<<16];
        memset(f, 0, sizeof(f));
        push(&primes, 2);
        push(&offset, 0);
        for (p = 3; p < 1<<16; p += 2) {
                if (f[p]) continue;
                for (q = p*p; q < 1<<16; q += 2*p) f[q] = 1;
                push(&primes, p);
                push(&offset, q);
        }
        low = 1<<16;
}

void sieve(void)
{
        uint i, p, q, hi, ptop;
        if (!low) init();

        memset(field, 0, sizeof(field));

        hi = low + CHUNK_SIZE;
        ptop = sqrt(hi) * 2 + 1;

        for (i = 1; (p = primes.e[i]*2) < ptop; i++) {
                for (q = offset.e[i] - low; q < CHUNK_SIZE; q += p)
                        SET(q);
                offset.e[i] = q + low;
        }

        for (p = 1; p < CHUNK_SIZE; p += 2)
                if (!GET(p)) push(&primes, low + p);

        low = hi;
}

int main(void)
{
        uint i, p, c;

        while (primes.len < 20) sieve();
        printf("First 20:");
        for (i = 0; i < 20; i++)
                printf(" %u", primes.e[i]);
        putchar('\n');

        while (primes.e[primes.len-1] < 150) sieve();
        printf("Between 100 and 150:");
        for (i = 0; i < primes.len; i++) {
                if ((p = primes.e[i]) >= 100 && p < 150)
                        printf(" %u", primes.e[i]);
        }
        putchar('\n');

        while (primes.e[primes.len-1] < 8000) sieve();
        for (i = c = 0; i < primes.len; i++)
                if ((p = primes.e[i]) >= 7700 && p < 8000) c++;
        printf("%u primes between 7700 and 8000\n", c);

        for (c = 10; c <= 100000000; c *= 10) {
                while (primes.len < c) sieve();
                printf("%uth prime: %u\n", c, primes.e[c-1]);
        }

        return 0;
}


C++: #include <iostream>
#include <cstdint>
#include <queue>
#include <utility>
#include <vector>
#include <limits>

template<typename integer>
class prime_generator {
public:
    integer next_prime();
    integer count() const {
        return count_;
    }
private:
    struct queue_item {
        queue_item(integer prime, integer multiple, unsigned int wheel_index) :
            prime_(prime), multiple_(multiple), wheel_index_(wheel_index) {}
        integer prime_;
        integer multiple_;
        unsigned int wheel_index_;
    };
    struct cmp {
        bool operator()(const queue_item& a, const queue_item& b) const {
            return a.multiple_ > b.multiple_;
        }
    };
    static integer wheel_next(unsigned int& index) {
        integer offset = wheel_[index];
        ++index;
        if (index == std::size(wheel_))
            index = 0;
        return offset;
    }
    typedef std::priority_queue<queue_item, std::vector<queue_item>, cmp> queue;
    integer next_ = 11;
    integer count_ = 0;
    queue queue_;
    unsigned int wheel_index_ = 0;
    static const unsigned int wheel_[];
    static const integer primes_[];
};

template<typename integer>
const unsigned int prime_generator<integer>::wheel_[] = {
    2, 4, 2, 4, 6, 2, 6, 4, 2, 4, 6, 6, 2, 6, 4, 2,
    6, 4, 6, 8, 4, 2, 4, 2, 4, 8, 6, 4, 6, 2, 4, 6,
    2, 6, 6, 4, 2, 4, 6, 2, 6, 4, 2, 4, 2, 10, 2, 10
};

template<typename integer>
const integer prime_generator<integer>::primes_[] = {
    2, 3, 5, 7
};

template<typename integer>
integer prime_generator<integer>::next_prime() {
    if (count_ < std::size(primes_))
        return primes_[count_++];
    integer n = next_;
    integer prev = 0;
    while (!queue_.empty()) {
        queue_item item = queue_.top();
        if (prev != 0 && prev != item.multiple_)
            n += wheel_next(wheel_index_);
        if (item.multiple_ > n)
            break;
        else if (item.multiple_ == n) {
            queue_.pop();
            queue_item new_item(item);
            new_item.multiple_ += new_item.prime_ * wheel_next(new_item.wheel_index_);
            queue_.push(new_item);
        }
        else
            throw std::overflow_error("prime_generator: overflow!");
        prev = item.multiple_;
    }
    if (std::numeric_limits<integer>::max()/n > n)
        queue_.emplace(n, n * n, wheel_index_);
    next_ = n + wheel_next(wheel_index_);
    ++count_;
    return n;
}

int main() {
    typedef uint32_t integer;
    prime_generator<integer> pgen;
    std::cout << "First 20 primes:\n";
    for (int i = 0; i < 20; ++i) {
        integer p = pgen.next_prime();
        if (i != 0)
            std::cout << ", ";
        std::cout << p;
    }
    std::cout << "\nPrimes between 100 and 150:\n";
    for (int n = 0; ; ) {
        integer p = pgen.next_prime();
        if (p > 150)
            break;
        if (p >= 100) {
            if (n != 0)
                std::cout << ", ";
            std::cout << p;
            ++n;
        }
    }
    int count = 0;
    for (;;) {
        integer p = pgen.next_prime();
        if (p > 8000)
            break;
        if (p >= 7700)
            ++count;
    }
    std::cout << "\nNumber of primes between 7700 and 8000: " << count << '\n';

    for (integer n = 10000; n <= 10000000; n *= 10) {
        integer prime;
        while (pgen.count() != n)
            prime = pgen.next_prime();
        std::cout << n << "th prime: " << prime << '\n';
    }
    return 0;
}