You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

132 lines
3.1 KiB

/**
* Copyright (c) 2018 Niklas Rosenstein
* MIT licensed.
*/
#include <benchmark/benchmark.h>
#include <gtest/gtest.h>
#include <NiklasRosenstein/typeid.hpp>
namespace nr = niklasrosenstein;
class InterfaceA {
NR_TYPEID(InterfaceA, 1000);
public:
virtual int method_a() = 0;
};
class InterfaceB {
NR_TYPEID(InterfaceB, 1001);
public:
virtual int method_b() = 0;
};
class InterfaceC {
int member;
public:
InterfaceC(int member) : member(member) {}
virtual int method_c() { return member; }
};
// Associate a type ID with an external type that you can not add the
// #NR_TYPEID() macro to the class defition to. Note that casting FROM
// a pointer of such a type is not possible.
NR_TYPEID_EX(InterfaceC, 1003);
struct Impl : public virtual InterfaceA, virtual InterfaceB, virtual InterfaceC {
NR_TYPEID(Impl, 3000, InterfaceA, InterfaceB, InterfaceC);
Impl() : InterfaceC(10) { }
virtual ~Impl() {}
// InterfaceA Overrides
virtual int method_a() override { return 99; }
// InterfaceB Overrides
virtual int method_b() override { return 42; }
// InterfaceC Overrides
virtual int method_c() override { return InterfaceC::method_c() * 2; }
};
struct Unsupported {};
TEST(type_id, castaround) {
Impl* i = new Impl;
// Down-cast (just a static_cast)
InterfaceA* a = i;
EXPECT_EQ(a->method_a(), i->method_a());
// Side-cast (can not be performed with static_cast).
InterfaceB* b = nr::type_cast<InterfaceB>(a);
ASSERT_TRUE(b != nullptr);
EXPECT_EQ(b, static_cast<InterfaceB*>(i));
EXPECT_EQ(b->method_b(), i->method_b());
InterfaceC* c = nr::type_cast<InterfaceC>(a);
ASSERT_TRUE(c != nullptr);
EXPECT_EQ(c, static_cast<InterfaceC*>(i));
EXPECT_EQ(c->method_c(), i->method_c());
// Cast to class that does not provide a type ID always fails.
Unsupported* u = nr::type_cast<Unsupported>(a);
EXPECT_EQ(u, nullptr);
// Back to A from B (can not be performed with static_cast).
InterfaceA* a_from_b = nr::type_cast<InterfaceA>(b);
ASSERT_TRUE(a_from_b != nullptr);
EXPECT_EQ(a_from_b, a);
// Up-cast (can not be performed with static_cast).
Impl* up_i_from_b = nr::type_cast<Impl>(b);
ASSERT_TRUE(up_i_from_b != nullptr);
EXPECT_EQ(i, up_i_from_b);
delete i;
}
static void BM_TypeID_SideCast(benchmark::State& state) {
Impl* i = new Impl;
InterfaceA* a = i;
while (state.KeepRunning()) {
InterfaceB* b = nr::type_cast<InterfaceB>(a);
if (!b) {
state.SkipWithError("Sidecast from InterfaceA to InterfaceB failed");
break;
}
if (b != static_cast<InterfaceB*>(i)) {
state.SkipWithError("Sidecast from InterfaceA to InterfaceB returned an invalid value");
break;
}
}
delete i;
}
BENCHMARK(BM_TypeID_SideCast);
static void BM_TypeID_UpCast(benchmark::State& state) {
Impl* i = new Impl;
InterfaceA* a = i;
while (state.KeepRunning()) {
Impl* other_i = nr::type_cast<Impl>(a);
if (!other_i) {
state.SkipWithError("Upcast from InterfaceA to Impl failed");
break;
}
if (other_i != i) {
state.SkipWithError("Upcast from InterfaceA to Impl returned an invalid value");
break;
}
}
delete i;
}
BENCHMARK(BM_TypeID_UpCast);