-
-
Save Vezhur/a29596a8387f513aad0c5b35b14c758e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <memory> | |
#include <vector> | |
#include <random> | |
struct Stmt_RTTI { virtual ~Stmt_RTTI() = default; }; | |
struct IfStmt_RTTI : Stmt_RTTI { }; | |
struct ForStmt_RTTI : Stmt_RTTI { }; | |
struct Stmt_WithEnum | |
{ | |
enum Type { IfStmt, ForStmt, DoStmt, WhileStmt }; | |
Stmt_WithEnum(Type kind) : m_kind { kind } { } | |
virtual ~Stmt_WithEnum() = default; | |
Type Kind() const { return m_kind; } | |
private: | |
const Type m_kind; | |
}; | |
namespace Solution1 | |
{ | |
template <Stmt_WithEnum::Type K> | |
struct type_from_kind; | |
template <typename T> | |
struct kind_from_type; | |
#define MAKE_STMT_TRAITS(t, k) \ | |
template <> struct Solution1::type_from_kind<k> \ | |
{ \ | |
using type = t; \ | |
}; \ | |
template <> struct Solution1::kind_from_type<t> \ | |
{ \ | |
static constexpr auto value = k; \ | |
}; | |
template <typename T, typename Kind, typename ...Kinds> | |
bool IsA(T stmt, Kind kind, Kinds ...kinds) noexcept | |
{ | |
return stmt && | |
((stmt->Kind() == kind) || ... || (stmt->Kind() == kinds)); | |
} | |
template <typename To, typename From> | |
requires std::is_pointer_v<To> | |
&& requires { static_cast<To>(std::declval<From *>()); } | |
auto dyn_cast(From *p) noexcept | |
{ | |
using ResultType = std::remove_cvref_t< | |
std::remove_pointer_t< std::remove_cvref_t<To> > | |
>; | |
return IsA(p, kind_from_type<ResultType>::value) | |
? static_cast<To>(p) | |
: nullptr; | |
} | |
} | |
struct IfStmt_WithEnum : Stmt_WithEnum | |
{ | |
IfStmt_WithEnum() : Stmt_WithEnum { Stmt_WithEnum::IfStmt } {} | |
static bool classof(const Stmt_WithEnum *p) noexcept | |
{ | |
return p && p->Kind() == Stmt_WithEnum::IfStmt; | |
} | |
}; | |
MAKE_STMT_TRAITS(IfStmt_WithEnum, Stmt_WithEnum::IfStmt) | |
struct ForStmt_WithEnum : Stmt_WithEnum | |
{ | |
ForStmt_WithEnum() : Stmt_WithEnum { Stmt_WithEnum::ForStmt } {} | |
static bool classof(const Stmt_WithEnum *p) noexcept | |
{ | |
return p && p->Kind() == Stmt_WithEnum::ForStmt; | |
} | |
}; | |
MAKE_STMT_TRAITS(ForStmt_WithEnum, Stmt_WithEnum::ForStmt) | |
namespace Solution2 | |
{ | |
template <typename To, typename From> | |
bool IsA(From *p) noexcept | |
{ | |
using ResultType = std::remove_cvref_t< | |
std::remove_pointer_t< std::remove_cvref_t<To> > | |
>; | |
return ResultType::classof(p); | |
} | |
template <typename To, typename From> | |
requires std::is_pointer_v<To> | |
&& requires { static_cast<To>(std::declval<From *>()); } | |
auto dyn_cast(From *p) noexcept | |
{ | |
using ResultType = std::remove_cvref_t< | |
std::remove_pointer_t< std::remove_cvref_t<To> > | |
>; | |
return IsA<ResultType>(p) ? static_cast<To>(p) : nullptr; | |
} | |
} | |
std::unique_ptr<Stmt_RTTI> factory_1() | |
{ | |
static std::mt19937_64 Generator { 0 }; | |
std::uniform_int_distribution d { 0, 1 }; | |
switch (d(Generator)) | |
{ | |
case 0: | |
return std::make_unique<IfStmt_RTTI>(); | |
case 1: | |
return std::make_unique<ForStmt_RTTI>(); | |
} | |
std::terminate(); | |
} | |
std::unique_ptr<Stmt_WithEnum> factory_2() | |
{ | |
static std::mt19937_64 Generator { 0 }; | |
std::uniform_int_distribution d { 0, 1 }; | |
switch (d(Generator)) | |
{ | |
case 0: | |
return std::make_unique<IfStmt_WithEnum>(); | |
case 1: | |
return std::make_unique<ForStmt_WithEnum>(); | |
} | |
std::terminate(); | |
} | |
static void StmtRTTI_Benchmark(benchmark::State& state) { | |
std::vector<std::unique_ptr<Stmt_RTTI>> vec; | |
const auto size = 1'000'000u; | |
vec.reserve(size); | |
for (size_t i = 0; i < size; ++i) | |
{ | |
vec.push_back(factory_1()); | |
} | |
// Code inside this loop is measured repeatedly | |
for (auto _ : state) | |
{ | |
for (const auto &stmt : vec) | |
{ | |
if (auto ifStmt = dynamic_cast<const IfStmt_RTTI *>(stmt.get())) | |
{ | |
// Make sure the variable is not optimized away by compiler | |
benchmark::DoNotOptimize(ifStmt); | |
} | |
else if (auto forStmt = dynamic_cast<const ForStmt_RTTI *>(stmt.get())) | |
{ | |
// Make sure the variable is not optimized away by compiler | |
benchmark::DoNotOptimize(forStmt); | |
} | |
} | |
} | |
} | |
// Register the function as a benchmark | |
BENCHMARK(StmtRTTI_Benchmark); | |
static void StmtWithEnum_Benchmark_1(benchmark::State& state) { | |
std::vector<std::unique_ptr<Stmt_WithEnum>> vec; | |
const auto size = 1'000'000u; | |
vec.reserve(size); | |
for (size_t i = 0; i < size; ++i) | |
{ | |
vec.push_back(factory_2()); | |
} | |
// Code inside this loop is measured repeatedly | |
for (auto _ : state) | |
{ | |
for (const auto &stmt : vec) | |
{ | |
if (auto ifStmt = | |
Solution1::dyn_cast<const IfStmt_WithEnum *>(stmt.get())) | |
{ | |
// Make sure the variable is not optimized away by compiler | |
benchmark::DoNotOptimize(ifStmt); | |
} | |
else if (auto forStmt = | |
Solution1::dyn_cast<const ForStmt_WithEnum *>(stmt.get())) | |
{ | |
// Make sure the variable is not optimized away by compiler | |
benchmark::DoNotOptimize(forStmt); | |
} | |
} | |
} | |
} | |
BENCHMARK(StmtWithEnum_Benchmark_1); | |
static void StmtWithEnum_Benchmark_2(benchmark::State& state) | |
{ | |
std::vector<std::unique_ptr<Stmt_WithEnum>> vec; | |
const auto size = 1'000'000u; | |
vec.reserve(size); | |
for (size_t i = 0; i < size; ++i) | |
{ | |
vec.push_back(factory_2()); | |
} | |
// Code inside this loop is measured repeatedly | |
for (auto _ : state) | |
{ | |
for (const auto &stmt : vec) | |
{ | |
if (auto ifStmt = Solution2::dyn_cast< | |
const IfStmt_WithEnum *>(stmt.get())) | |
{ | |
// Make sure the variable is not optimized away by compiler | |
benchmark::DoNotOptimize(ifStmt); | |
} | |
else if (auto forStmt = | |
Solution2::dyn_cast<const ForStmt_WithEnum *>(stmt.get())) | |
{ | |
// Make sure the variable is not optimized away by compiler | |
benchmark::DoNotOptimize(forStmt); | |
} | |
} | |
} | |
} | |
BENCHMARK(StmtWithEnum_Benchmark_2); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment