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 typedef RCPtr<RefType> Ptr;
66 typedef RCWeakPtr<RefType> WPtr;
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 else
86 return "I am " + name() + ", an orphan";
87 }
88
89 std::string name() const
90 {
91 return name_;
92 }
93
94 private:
95 std::string name_;
96 typename PARENT::WPtr parent_;
97 StaticCounter sc_;
98};
99
100class Object : public RCWeak<thread_unsafe_refcount>
101{
102 public:
103 typedef RCPtr<Object> Ptr;
104 typedef RCWeakPtr<Object> WPtr;
105 typedef RefType<Object> Ref;
106
107 std::string name() const
108 {
109 return "Regular Joe";
110 }
111
112 std::string to_string() const
113 {
114 std::string ret;
115 for (const auto &e : vec)
116 {
117 ret += e->to_string();
118 ret += '\n';
119 }
120 return ret;
121 }
122
123 std::vector<Ref::Ptr> vec;
124
125 private:
126 StaticCounter sc_;
127};
128
129typedef Object::Ref Ref;
130} // namespace A
131
132// Strategy B -- Ref declared inside Object, so Ref can make use
133// of existing Object types (such as Ptr and WPtr)
134namespace B {
135
136class Object : public RCWeak<thread_unsafe_refcount>
137{
138 public:
139 typedef RCPtr<Object> Ptr;
140 typedef RCWeakPtr<Object> WPtr;
141
142 class Ref : public RCWeak<thread_unsafe_refcount>
143 {
144 public:
145 typedef RCPtr<Ref> Ptr;
146 typedef RCWeakPtr<Ref> WPtr;
147
148 Ref(std::string name,
149 typename Object::Ptr parent)
150 : name_(std::move(name)),
151 parent_(std::move(parent))
152 {
153 }
154
155 Object::Ptr parent() const
156 {
157 return parent_.lock();
158 }
159
160 std::string to_string() const
161 {
162 auto p = parent();
163 if (p)
164 return "I am " + name() + " whose parent is " + p->name();
165 else
166 return "I am " + name() + ", an orphan";
167 }
168
169 std::string name() const
170 {
171 return name_;
172 }
173
174 private:
175 std::string name_;
176 Object::WPtr parent_;
177 StaticCounter sc_;
178 };
179
180 std::string name() const
181 {
182 return "Regular Joe";
183 }
184
185 std::string to_string() const
186 {
187 std::string ret;
188 for (const auto &e : vec)
189 {
190 ret += e->to_string();
191 ret += '\n';
192 }
193 return ret;
194 }
195
196 std::vector<Ref::Ptr> vec;
197
198 private:
199 StaticCounter sc_;
200};
201
202typedef Object::Ref Ref;
203} // namespace B
204
206
207template <typename Object, typename Ref>
208void test()
209{
210 ASSERT_EQ(StaticCounter::count(), 0);
211
212 std::string result;
213
214 // create new Ref objects that point back to their parent (Object)
215 typename Object::Ptr obj(new Object);
216 obj->vec.emplace_back(new Ref("One", obj));
217 obj->vec.emplace_back(new Ref("Two", obj));
218 obj->vec.emplace_back(new Ref("Three", obj));
219
220 // verify obj
221 ASSERT_EQ(obj->vec.size(), 3u);
222 ASSERT_EQ(obj->vec.at(0)->to_string(), "I am One whose parent is Regular Joe");
223 ASSERT_EQ(obj->vec.at(1)->to_string(), "I am Two whose parent is Regular Joe");
224 ASSERT_EQ(obj->vec.at(2)->to_string(), "I am Three whose parent is Regular Joe");
225
226 // make One into orphan
227 typename Ref::Ptr the_one = obj->vec[0]; // get One
228 obj.reset(); // free parent
229 ASSERT_EQ(the_one->to_string(), "I am One, an orphan");
230
231 // verify no memory leaks
232 ASSERT_EQ(StaticCounter::count(), 1);
233 the_one.reset();
234 ASSERT_EQ(StaticCounter::count(), 0);
235}
236
237// strategy A
238TEST(misc, weak_a)
239{
240 test<A::Object, A::Ref>();
241}
242
243// strategy B
244TEST(misc, weak_b)
245{
246 test<B::Object, B::Ref>();
247}
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:1090
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, weak_a)
void test()