OpenVPN 3 Core Library
Loading...
Searching...
No Matches
test_typeindex.cpp
Go to the documentation of this file.
1// This test demonstrates an alternative to dynamic_cast
2// using std::typeindex that is much faster.
3
4#include "test_common.hpp"
5
6#include <typeindex>
7#include <vector>
8#include <utility>
9
11#include <openvpn/common/rc.hpp>
13
14using namespace openvpn;
15
16namespace {
17struct Base : public RC<thread_unsafe_refcount>
18{
19 public:
20 using Ptr = RCPtr<Base>;
21
22 virtual std::string to_string() const = 0;
23
24 std::type_index type() const
25 {
26 return type_;
27 }
28
29 protected:
30 Base(std::type_index &&type)
31 : type_(std::move(type))
32 {
33 }
34
35 private:
36 const std::type_index type_;
37};
38
39template <typename T>
40class Wrapper : public Base
41{
42 public:
43 Wrapper(T &&obj_arg)
44 : Base(static_type()),
45 obj(std::move(obj_arg))
46 {
47 }
48
49 // this is like dynamic cast on steroids! (~1 ns)
50 static const Wrapper *self(const Base *maybe_my_type)
51 {
52 if (maybe_my_type->type() == static_type())
53 return static_cast<const Wrapper *>(maybe_my_type);
54 return nullptr;
55 }
56
57 std::string to_string() const override
58 {
59 return "value=" + StringTempl::to_string(obj) + " obj_size=" + std::to_string(sizeof(obj));
60 }
61
62 static std::type_index static_type()
63 {
64 return std::type_index(typeid(Wrapper));
65 }
66
67 T obj;
68};
69
70struct Vec : public std::vector<Base::Ptr>
71{
72 std::string to_string() const
73 {
74 std::string ret;
75 for (const auto &e : *this)
76 {
77 ret += e->to_string();
78 ret += '\n';
79 }
80 return ret;
81 }
82};
83
84template <typename T>
85static Base::Ptr create(T &&obj)
86{
87 return Base::Ptr(new Wrapper<T>(std::move(obj)));
88}
89
90static Vec create_vec()
91{
92 Vec vec;
93 vec.emplace_back(create(1));
94 vec.emplace_back(create(2));
95 vec.emplace_back(create(3.14159));
96 vec.emplace_back(create(std::string("Hello")));
97 vec.emplace_back(create(std::string("World!")));
98 vec.emplace_back(create(true));
99 vec.emplace_back(create(false));
100 return vec;
101}
102} // namespace
103
104// simple test of self()
105TEST(Typeindex, Test)
106{
107 using StringWrap = Wrapper<std::string>;
108
109 const Vec vec = create_vec();
110
111 OPENVPN_LOG("CONTENTS...");
112 OPENVPN_LOG_STRING(vec.to_string());
113
114 OPENVPN_LOG("STRINGS...");
115 for (const auto &e : vec)
116 {
117 const StringWrap *s = StringWrap::self(e.get());
118 if (s)
119 OPENVPN_LOG(s->obj);
120 }
121}
122
123#ifndef INSTRUMENTATION_SLOWDOWN
124
125// test performance of self() as alternative to dynamic_cast
126TEST(Typeindex, PerfTestFast)
127{
128 using StringWrap = Wrapper<std::string>;
129
130 const size_t N = 100000000;
131
132 const Vec vec = create_vec();
133 const size_t size = vec.size();
134 size_t n_strings = 0;
135 size_t i = 0;
136 for (size_t count = 0; count < N; ++count)
137 {
138 const StringWrap *s = StringWrap::self(vec[i].get());
139 if (s)
140 ++n_strings;
141 if (++i >= size)
142 i = 0;
143 }
144 OPENVPN_LOG("PERF " << n_strings << '/' << N);
145 ASSERT_EQ(n_strings, 28571428U);
146}
147
148// as a control, test performance of dynamic_cast
149TEST(Typeindex, PerfTestDynamic)
150{
151 using StringWrap = Wrapper<std::string>;
152
153 const size_t N = 100000000;
154
155 const Vec vec = create_vec();
156 const size_t size = vec.size();
157 size_t n_strings = 0;
158 size_t i = 0;
159 for (size_t count = 0; count < N; ++count)
160 {
161 const StringWrap *s = dynamic_cast<const StringWrap *>(vec[i].get());
162 if (s)
163 ++n_strings;
164 if (++i >= size)
165 i = 0;
166 }
167 OPENVPN_LOG("PERF " << n_strings << '/' << N);
168 ASSERT_EQ(n_strings, 28571428U);
169}
170
171#endif
The smart pointer class.
Definition rc.hpp:119
Reference count base class for objects tracked by RCPtr. Disallows copying and assignment.
Definition rc.hpp:908
#define OPENVPN_LOG(args)
#define OPENVPN_LOG_STRING(str)
std::string to_string(std::nullptr_t)
HTTPBase< HTTPCore, Config, Status, HTTP::ReplyType, ContentInfo, olong, RC< thread_unsafe_refcount > > Base
Definition httpcli.hpp:347
void to_string(const Json::Value &root, std::string &dest, const NAME &name, const TITLE &title)
std::string ret
TEST(Typeindex, Test)