#include "tile/base/casting.h"

#include "tile/base/make_unique.h"

#include "benchmark/benchmark.h"

namespace tile {

struct Base {
    virtual ~Base() = default;

    enum { kA, kB, kC [[maybe_unused]] } type;
};

struct A : Base {
    A() { type = kA; }

    static bool classof(const Base &val) { return val.type == kA || val.type == kB; }
};

struct B : A {
    B() { type = kB; }

    static bool classof(const Base &val) { return val.type == kB; }
};

auto pb   = make_unique<B>();
Base *ptr = pb.get();
volatile A *converted_ptr;

struct C1 : ExactMatchCastable {};

struct C2 : C1 {
    C2() { SetRuntimeType(this, GetRuntimeTypeId<C2>()); }
};

struct C3 : C1 {
    C3() { SetRuntimeType(this, GetRuntimeTypeId<C3>()); }
};

auto pc2 = make_unique<C2>();
C1 *pc1  = pc2.get();
volatile C3 *pc3;

void
Benchmark_BuiltinDynamicCast(benchmark::State &state)
{
    while (state.KeepRunning()) { converted_ptr = dynamic_cast<A *>(ptr); }
}

BENCHMARK(Benchmark_BuiltinDynamicCast);

void
Benchmark_DynCast(benchmark::State &state)
{
    while (state.KeepRunning()) { converted_ptr = dyn_cast<A>(ptr); }
}

BENCHMARK(Benchmark_DynCast);

void
Benchmark_ExactMatchCastableDynCast(benchmark::State &state)
{
    while (state.KeepRunning()) { pc3 = dyn_cast<C3>(pc1); }
}

BENCHMARK(Benchmark_ExactMatchCastableDynCast);

}// namespace tile
