OpenVPN 3 Core Library
Loading...
Searching...
No Matches
test_weak.cpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2020- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
21#include "test_common.hpp"
22
23#include <vector>
24
25#include <openvpn/common/rc.hpp>
26
27using namespace openvpn;
28
32
33class StaticCounter
34{
35 public:
36 StaticCounter()
37 {
38 ++count_;
39 }
40
41 ~StaticCounter()
42 {
43 --count_;
44 }
45
46 static int count()
47 {
48 return count_;
49 }
50
51 private:
52 static int count_;
53};
54
55int StaticCounter::count_ = 0;
56
57// Strategy A -- RefType declared before Object, so use class Template
58// so that RefType can be specialized for Object
59namespace A {
60
61template <typename PARENT>
62class RefType : public RCWeak<thread_unsafe_refcount>
63{
64 public:
65 using Ptr = RCPtr<RefType>;
66 using WPtr = RCWeakPtr<RefType>;
67
68 RefType(std::string name,
69 typename PARENT::Ptr parent)
70 : name_(std::move(name)),
71 parent_(std::move(parent))
72 {
73 }
74
75 typename PARENT::Ptr parent() const
76 {
77 return parent_.lock();
78 }
79
80 std::string to_string() const
81 {
82 auto p = parent();
83 if (p)
84 return "I am " + name() + " whose parent is " + p->name();
85 return "I am " + name() + ", an orphan";
86 }
87
88 std::string name() const
89 {
90 return name_;
91 }
92
93 private:
94 std::string name_;
95 typename PARENT::WPtr parent_;
96 StaticCounter sc_;
97};
98
99class Object : public RCWeak<thread_unsafe_refcount>
100{
101 public:
102 using Ptr = RCPtr<Object>;
103 using WPtr = RCWeakPtr<Object>;
104 using Ref = RefType<Object>;
105
106 std::string name() const
107 {
108 return "Regular Joe";
109 }
110
111 std::string to_string() const
112 {
113 std::string ret;
114 for (const auto &e : vec)
115 {
116 ret += e->to_string();
117 ret += '\n';
118 }
119 return ret;
120 }
121
122 std::vector<Ref::Ptr> vec;
123
124 private:
125 StaticCounter sc_;
126};
127
128using Ref = Object::Ref;
129} // namespace A
130
131// Strategy B -- Ref declared inside Object, so Ref can make use
132// of existing Object types (such as Ptr and WPtr)
133namespace B {
134
135class Object : public RCWeak<thread_unsafe_refcount>
136{
137 public:
138 using Ptr = RCPtr<Object>;
139 using WPtr = RCWeakPtr<Object>;
140
141 class Ref : public RCWeak<thread_unsafe_refcount>
142 {
143 public:
144 using Ptr = RCPtr<Ref>;
145 using WPtr = RCWeakPtr<Ref>;
146
147 Ref(std::string name,
148 typename Object::Ptr parent)
149 : name_(std::move(name)),
150 parent_(std::move(parent))
151 {
152 }
153
154 Object::Ptr parent() const
155 {
156 return parent_.lock();
157 }
158
159 std::string to_string() const
160 {
161 auto p = parent();
162 if (p)
163 return "I am " + name() + " whose parent is " + p->name();
164 return "I am " + name() + ", an orphan";
165 }
166
167 std::string name() const
168 {
169 return name_;
170 }
171
172 private:
173 std::string name_;
174 Object::WPtr parent_;
175 StaticCounter sc_;
176 };
177
178 std::string name() const
179 {
180 return "Regular Joe";
181 }
182
183 std::string to_string() const
184 {
185 std::string ret;
186 for (const auto &e : vec)
187 {
188 ret += e->to_string();
189 ret += '\n';
190 }
191 return ret;
192 }
193
194 std::vector<Ref::Ptr> vec;
195
196 private:
197 StaticCounter sc_;
198};
199
200using Ref = Object::Ref;
201} // namespace B
202
204
205template <typename Object, typename Ref>
206void test()
207{
208 ASSERT_EQ(StaticCounter::count(), 0);
209
210 // create new Ref objects that point back to their parent (Object)
211 typename Object::Ptr obj(new Object);
212 obj->vec.emplace_back(new Ref("One", obj));
213 obj->vec.emplace_back(new Ref("Two", obj));
214 obj->vec.emplace_back(new Ref("Three", obj));
215
216 // verify obj
217 ASSERT_EQ(obj->vec.size(), 3U);
218 ASSERT_EQ(obj->vec.at(0)->to_string(), "I am One whose parent is Regular Joe");
219 ASSERT_EQ(obj->vec.at(1)->to_string(), "I am Two whose parent is Regular Joe");
220 ASSERT_EQ(obj->vec.at(2)->to_string(), "I am Three whose parent is Regular Joe");
221
222 // make One into orphan
223 typename Ref::Ptr the_one = obj->vec[0]; // get One
224 obj.reset(); // free parent
225 ASSERT_EQ(the_one->to_string(), "I am One, an orphan");
226
227 // verify no memory leaks
228 ASSERT_EQ(StaticCounter::count(), 1);
229 the_one.reset();
230 ASSERT_EQ(StaticCounter::count(), 0);
231}
232
233// strategy A
234TEST(Misc, WeakA)
235{
236 test<A::Object, A::Ref>();
237}
238
239// strategy B
240TEST(Misc, WeakB)
241{
242 test<B::Object, B::Ref>();
243}
The smart pointer class.
Definition rc.hpp:119
implements a weak pointer for reference counted objects.
Definition rc.hpp:451
Reference count base class for objects tracked by RCPtr. Like RC, but also allows weak pointers and r...
Definition rc.hpp:1086
const char * name(const KeyDerivation kd)
void to_string(const Json::Value &root, std::string &dest, const NAME &name, const TITLE &title)
std::string ret
TEST(Misc, WeakA)
void test()