#include <iostream>
#include <unordered_map>
#include <map>
#include <iostream>
#include <typeinfo>
#include <unistd.h>
#include <sys/times.h>
struct Base {
typedef std::map<const char *, void *> MapType;
MapType children_;
Base () { std::cout << __func__ << std::endl; }
virtual ~Base () {}
template <typename MAYBE_DERIVED>
MAYBE_DERIVED * isTypeOrSubtype () {
auto x = children_.find(typeid(MAYBE_DERIVED).name());
return ((x != children_.end())
? static_cast<MAYBE_DERIVED *>(x->second)
: 0);
}
};
#define FOO(X) \
X () : count_(0) { children_[typeid(X).name()] = 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, &g); //--> 0 g is not an E
run_test(bar, &g); //--> 0 g is not a C
run_test(foo, &c); //--> 0 c is not an E
run_test(bar, &c); //--> 20000000 c is a C
run_test(foo, &e); //--> 20000000 e is an E
run_test(bar, &e); //--> 20000000 e is not a C
}