/* Simulation of Ravi Sethi's prime-number program in C */ #include #include /* 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; }