/* Simulation of Ravi Sethi's prime-number program in C */

#include <malloc.h>
#include <stdio.h>

/*
  General strategy:
  Every class gets its base-class parts replicated
  Every member function gets an extra `this' argument as void *
*/

/* Virtual function table */
struct vtable {
    int (*next) (void *);	/* virtual int next() */
    void (*destroy) (void *);	/* virtual ~Source() */
};

/* Forward declarations of class vtables */
extern struct vtable v_counter, v_conduit, v_filter, v_sieve;

/*
  Because class Source has no members, and because Source is
  an abstract base class, we will pass every Source pointer
  as void *.  That way we can convert to and from void *
  without having to write casts.  Nevertheless, we need a
  source structure as a placeholder for the vtable.
*/
struct source {
    struct vtable *v;
};


/* Class Counter */
struct counter {
    struct vtable *v;		/* inherited from Source */
    int n;
};

/* Counter::Counter(int) */
void make_counter(struct counter *c, int n)
{
    c->v = &v_counter;		/* fill the vtable */
    c->n = n;
}

/* Counter::~Counter() */
void destroy_counter(void * c)
{
    /* nothing to do */
}

/* Counter::next() */
int counter_next(void *p)
{
    struct counter *this = p;
    return this->n++;
}

/* Counter vtable */
struct vtable v_counter = { counter_next, destroy_counter };


/* Class Conduit */
struct conduit {
    struct vtable *v;		/* inherited from Source */
    void *src;			/* Source* src */
};

/*
  Conduit::Conduit(Source*)
  Note that we don't need to fill c->v because Conduit is
  an abstract base class, which means that we never construct
  any Conduits directly -- only objects of derived classes.
*/
void make_conduit(struct conduit *c, void *s)
{
    c->src = s;
}

/* Conduit::~Conduit() */
void destroy_conduit(void *c)
{
    struct conduit *this = c;
    struct source *s = this->src;
    s->v->destroy(s);		/* delete src; */
    free(s);
}

/* Source* Conduit::source() */
void *conduit_source(struct conduit *c)
{
    return c->src;
}

/* void Conduit::splice(Source*) */
void conduit_splice(struct conduit *c, void *s)
{
    c->src = s;
}


/* Class Filter */
struct filter {
    struct vtable *v;		/* from Source */
    void *s;			/* from Conduit */
    int factor;
};

/* Filter::Filter(int, Source*) */
void make_filter(struct filter *c, int f, void *s)
{
    make_conduit((void *)c, s); /* construct the underlying Conduit */
    c->v = &v_filter;		/* initialize the vtable */
    c->factor = f;		/* store the factor */
}

/* Filter::~Filter() */
void destroy_filter(void * p)
{
    struct filter *this = p;
    destroy_conduit(this);
}

/* Filter::next() */
int filter_next(void *p)
{
    struct filter *this = p;
    int n;
    do {
	struct source *s = conduit_source((void *)this);
	n = s->v->next(s);
    } while (n % this->factor == 0);
    return n;
}

/*
  Filter vtable
  Note that we can use destroy_conduit as our destructor,
  because there's no additional work needed to destroy a filter
*/
struct vtable v_filter = { filter_next, destroy_conduit };


/* Class Sieve */
struct sieve {
    struct vtable *v;		/* inherited from Source */
    void *src;			/* Source* src */
};

void make_sieve(struct sieve *s)
{
    struct counter *cp = malloc(sizeof(struct counter));
    make_counter(cp, 2);
    make_conduit((void *)s, cp);
    s->v = &v_sieve;
}

int sieve_next(void *s)
{
    struct sieve *this = s;
    struct source *src = conduit_source((void *) this);
    int n = src->v->next(src);
    struct filter *fp = malloc(sizeof(struct filter));
    make_filter(fp, n, src);
    conduit_splice((void *) this, fp);
    return n;
}

/* sieve vtable */
struct vtable v_sieve = { sieve_next, destroy_conduit };



/* Finally, the main program */
int main()
{
    struct sieve s;
    int n;
    make_sieve(&s);		/* Construct a sieve */
    do {
	n = s.v->next(&s);
	printf("%d\n", n);
    } while (n < 100);
    s.v->destroy(&s);		/* Destroy the sieve */
    return 0;
}

