mirror of
https://github.com/OpenVPN/openvpn3.git
synced 2024-09-20 12:12:15 +02:00
[test/misc] unittests: added test_typeindex.cpp that's a POC for using std::typeindex as a faster replacement for dynamic_cast
Signed-off-by: James Yonan <james@openvpn.net>
This commit is contained in:
parent
b1aea61463
commit
43997ef232
172
test/unittests/test_typeindex.cpp
Normal file
172
test/unittests/test_typeindex.cpp
Normal file
@ -0,0 +1,172 @@
|
||||
// This test demonstrates an alternative to dynamic_cast
|
||||
// using std::typeindex that is much faster.
|
||||
|
||||
#include "test_common.h"
|
||||
|
||||
#include <typeindex>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
#include <openvpn/common/exception.hpp>
|
||||
#include <openvpn/common/rc.hpp>
|
||||
#include <openvpn/common/stringtempl2.hpp>
|
||||
|
||||
using namespace openvpn;
|
||||
|
||||
namespace {
|
||||
struct Base : public RC<thread_unsafe_refcount>
|
||||
{
|
||||
public:
|
||||
typedef RCPtr<Base> Ptr;
|
||||
|
||||
virtual std::string to_string() const = 0;
|
||||
|
||||
std::type_index type() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
protected:
|
||||
Base(std::type_index&& type)
|
||||
: type_(std::move(type))
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
const std::type_index type_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Wrapper : public Base
|
||||
{
|
||||
public:
|
||||
Wrapper(T&& obj_arg)
|
||||
: Base(static_type()),
|
||||
obj(std::move(obj_arg))
|
||||
{
|
||||
}
|
||||
|
||||
// this is like dynamic cast on steroids! (~1 ns)
|
||||
static const Wrapper* self(const Base* maybe_my_type)
|
||||
{
|
||||
if (maybe_my_type->type() == static_type())
|
||||
return static_cast<const Wrapper*>(maybe_my_type);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual std::string to_string() const override
|
||||
{
|
||||
return "value=" + StringTempl::to_string(obj) + " obj_size=" + std::to_string(sizeof(obj));
|
||||
}
|
||||
|
||||
static std::type_index static_type()
|
||||
{
|
||||
return std::type_index(typeid(Wrapper));
|
||||
}
|
||||
|
||||
T obj;
|
||||
};
|
||||
|
||||
struct Vec : public std::vector<Base::Ptr>
|
||||
{
|
||||
std::string to_string() const
|
||||
{
|
||||
std::string ret;
|
||||
for (const auto &e : *this)
|
||||
{
|
||||
ret += e->to_string();
|
||||
ret += '\n';
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static Base::Ptr create(T&& obj)
|
||||
{
|
||||
return Base::Ptr(new Wrapper<T>(std::move(obj)));
|
||||
}
|
||||
|
||||
static Vec create_vec()
|
||||
{
|
||||
Vec vec;
|
||||
vec.emplace_back(create(1));
|
||||
vec.emplace_back(create(2));
|
||||
vec.emplace_back(create(3.14159));
|
||||
vec.emplace_back(create(std::string("Hello")));
|
||||
vec.emplace_back(create(std::string("World!")));
|
||||
vec.emplace_back(create(true));
|
||||
vec.emplace_back(create(false));
|
||||
return vec;
|
||||
}
|
||||
}
|
||||
|
||||
// simple test of self()
|
||||
TEST(typeindex, test)
|
||||
{
|
||||
typedef Wrapper<std::string> StringWrap;
|
||||
|
||||
const Vec vec = create_vec();
|
||||
|
||||
OPENVPN_LOG("CONTENTS...");
|
||||
OPENVPN_LOG_STRING(vec.to_string());
|
||||
|
||||
OPENVPN_LOG("STRINGS...");
|
||||
for (const auto &e : vec)
|
||||
{
|
||||
const StringWrap* s = StringWrap::self(e.get());
|
||||
if (s)
|
||||
OPENVPN_LOG(s->obj);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef HAVE_VALGRIND
|
||||
|
||||
// test performance of self() as alternative to dynamic_cast
|
||||
TEST(typeindex, perf_test_fast)
|
||||
{
|
||||
typedef Wrapper<std::string> StringWrap;
|
||||
|
||||
const size_t N = 100000000;
|
||||
|
||||
const Vec vec = create_vec();
|
||||
const size_t size = vec.size();
|
||||
size_t n_strings = 0;
|
||||
size_t i = 0;
|
||||
for (size_t count = 0; count < N; ++count)
|
||||
{
|
||||
const StringWrap* s = StringWrap::self(vec[i].get());
|
||||
if (s)
|
||||
++n_strings;
|
||||
if (++i >= size)
|
||||
i = 0;
|
||||
}
|
||||
OPENVPN_LOG("PERF " << n_strings << '/' << N);
|
||||
ASSERT_EQ(n_strings, 28571428);
|
||||
}
|
||||
|
||||
// as a control, test performance of dynamic_cast
|
||||
TEST(typeindex, perf_test_dynamic)
|
||||
{
|
||||
typedef Wrapper<std::string> StringWrap;
|
||||
|
||||
const size_t N = 100000000;
|
||||
|
||||
const Vec vec = create_vec();
|
||||
const size_t size = vec.size();
|
||||
size_t n_strings = 0;
|
||||
size_t i = 0;
|
||||
for (size_t count = 0; count < N; ++count)
|
||||
{
|
||||
const StringWrap* s = dynamic_cast<const StringWrap*>(vec[i].get());
|
||||
if (s)
|
||||
++n_strings;
|
||||
if (++i >= size)
|
||||
i = 0;
|
||||
}
|
||||
OPENVPN_LOG("PERF " << n_strings << '/' << N);
|
||||
ASSERT_EQ(n_strings, 28571428);
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user