#include <iostream>
#include <unistd.h>
#include <sys/times.h>
#define SUBCLASSES \
SUBCLASS(A) SUBCLASS(B) SUBCLASS(C) SUBCLASS(D) SUBCLASS(E) \
SUBCLASS(F) SUBCLASS(G)
#define SUBCLASS(X) struct X ;
SUBCLASSES
#undef SUBCLASS
struct Base;
// Use this as a way to hack template specialization of template method
template <typename MAYBE_DERIVED>
struct BaseIsTypeOrSubtype {
MAYBE_DERIVED * operator () (Base *) const { return 0; }
};
struct Base {
Base () { std::cout << __func__ << std::endl; }
virtual ~Base () {}
template <typename MAYBE_DERIVED> MAYBE_DERIVED * isTypeOrSubtype () {
return BaseIsTypeOrSubtype<MAYBE_DERIVED>()(this);
}
#define SUBCLASS(X) virtual X * is_##X () { return 0; }
SUBCLASSES
#undef SUBCLASS
};
#define SUBCLASS(X) \
template <> struct BaseIsTypeOrSubtype<X> { \
X * operator () (Base *b) const { return b->is_##X(); } \
};
SUBCLASSES
#undef SUBCLASS
#define FOO(X) \
X () : count_(0) {} \
X * is_##X () { return this; } \
void foo () { if (this) { count_ += 1; } } \
int count () { return this ? count_ : 0; } \
private: int count_
struct A : virtual Base { FOO(A); };
struct B : A { FOO(B); };
struct C : A { FOO(C); };
struct D : virtual Base { FOO(D); };
struct E : D { FOO(E); };
struct F : D { FOO(F); };
struct G : B, F { FOO(G); };
void foo (Base *b) {
for (int i = 0; i < 20000000; ++i) {
b->isTypeOrSubtype<E>()->foo();
}
}
void foo_dc (Base *b) {
for (int i = 0; i < 2000000; ++i) {
dynamic_cast<E *>(b)->foo();
}
}
void bar (Base *b) {
for (int i = 0; i < 20000000; ++i) {
b->isTypeOrSubtype<C>()->foo();
}
}
void bar_dc (Base *b) {
for (int i = 0; i < 2000000; ++i) {
dynamic_cast<C *>(b)->foo();
}
}
void report (struct tms &start, struct tms &finish, Base *x, int f = 1) {
double ticks_per_sec = sysconf(_SC_CLK_TCK);
unsigned long long elapsed = 0;
elapsed += finish.tms_utime;
elapsed += finish.tms_stime;
elapsed -= start.tms_utime;
elapsed -= start.tms_stime;
int countC = x->isTypeOrSubtype<C>()->count();
int countE = x->isTypeOrSubtype<E>()->count();
std::cout << countC + countE << " hits, "
<< f * elapsed/ticks_per_sec << " seconds"
<< std::endl;
}
void run_test (void (*test)(Base *), Base *x, int f = 1) {
struct tms start;
struct tms finish;
times(&start);
test(x);
times(&finish);
report(start, finish, x, f);
}
int main () {
G g;
C c;
E e;
run_test(foo_dc, &g, 10); //--> 0 g is not an E
run_test(bar_dc, &g, 10); //--> 0 g is not a C
run_test(foo_dc, &c, 10); //--> 0 c is not an E
run_test(bar_dc, &c, 10); //--> 2000000 c is a C
run_test(foo_dc, &e, 10); //--> 2000000 e is an E
run_test(bar_dc, &e, 10); //--> 2000000 e is not a C
}