/src/Fast-DDS/src/cpp/utils/RefCountedPointer.hpp
Line | Count | Source |
1 | | // Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | /** |
16 | | * @file RefCountedPointer.hpp |
17 | | */ |
18 | | |
19 | | #ifndef UTILS__REFCOUNTEDPOINTER_HPP |
20 | | #define UTILS__REFCOUNTEDPOINTER_HPP |
21 | | |
22 | | #include <atomic> |
23 | | #include <cassert> |
24 | | #include <condition_variable> |
25 | | #include <cstdint> |
26 | | #include <memory> |
27 | | #include <mutex> |
28 | | |
29 | | namespace eprosima { |
30 | | namespace fastdds { |
31 | | |
32 | | /** |
33 | | * @brief Class to manage a local pointer with reference counting. |
34 | | * |
35 | | * It is similar to std::shared_ptr, but designed for cases where |
36 | | * a shared pointer cannot be used due to API restrictions. |
37 | | * |
38 | | * USAGE: |
39 | | * - On T class: |
40 | | * - Add a shared_ptr<RefCountedPointer<T>> local_ptr_ member. |
41 | | * - Call local_ptr_->deactivate() before destroying T. |
42 | | * |
43 | | * - On classes that need to use a pointer to T: |
44 | | * - Keep a copy of the shared_ptr<RefCountedPointer<T>>. |
45 | | * - Whenever you need to access T: |
46 | | * RefCountedPointer<T>::Instance instance(local_ptr_) |
47 | | * if (instance) |
48 | | * { |
49 | | * ptr->method(); |
50 | | * } |
51 | | */ |
52 | | template<typename T> |
53 | | class RefCountedPointer |
54 | | { |
55 | | public: |
56 | | |
57 | | class Instance; |
58 | | |
59 | | /** |
60 | | * @brief Explicit constructor. |
61 | | * @param ptr Pointer to manage. |
62 | | * |
63 | | * @pre nullptr != ptr. We must ensure that the pointer we |
64 | | * are manaing is valid. |
65 | | */ |
66 | | explicit RefCountedPointer( |
67 | | T* ptr) |
68 | 0 | : ptr_(ptr) |
69 | 0 | , is_active_(true) |
70 | 0 | , instances_(0) |
71 | 0 | { |
72 | 0 | assert(nullptr != ptr); |
73 | 0 | } |
74 | | |
75 | 0 | ~RefCountedPointer() = default; |
76 | | |
77 | | // Non-copyable and non-movable |
78 | | RefCountedPointer( |
79 | | const RefCountedPointer&) = delete; |
80 | | RefCountedPointer& operator =( |
81 | | const RefCountedPointer&) = delete; |
82 | | RefCountedPointer( |
83 | | RefCountedPointer&&) = delete; |
84 | | RefCountedPointer& operator =( |
85 | | RefCountedPointer&&) = delete; |
86 | | |
87 | | /** |
88 | | * @brief Class to manage the local pointer instance. |
89 | | * It will increase the reference count on construction and decrease |
90 | | * it on destruction. Provides a facade to access the pointee. |
91 | | */ |
92 | | class Instance |
93 | | { |
94 | | public: |
95 | | |
96 | | /** |
97 | | * @brief Constructor. |
98 | | * @param parent Shared pointer reference to its RefCountedPointer. |
99 | | */ |
100 | | explicit Instance( |
101 | | const std::shared_ptr<RefCountedPointer<T>>& parent) |
102 | 0 | : parent_(parent) |
103 | 0 | , ptr_(parent && parent->is_active_ ? parent->ptr_ : nullptr) |
104 | 0 | { |
105 | 0 | if (parent_) |
106 | 0 | { |
107 | 0 | parent_->inc_instances(); |
108 | 0 | } |
109 | 0 | } |
110 | | |
111 | | /** |
112 | | * @brief Destructor. |
113 | | */ |
114 | | ~Instance() |
115 | 0 | { |
116 | 0 | if (parent_) |
117 | 0 | { |
118 | 0 | parent_->dec_instances(); |
119 | 0 | } |
120 | 0 | } |
121 | | |
122 | | // Non-copyable, default movable |
123 | | Instance( |
124 | | const Instance&) = delete; |
125 | | Instance& operator =( |
126 | | const Instance&) = delete; |
127 | | Instance( |
128 | | Instance&&) = default; |
129 | | Instance& operator =( |
130 | | Instance&&) = default; |
131 | | |
132 | | /** |
133 | | * @brief operator to check if the pointer is valid. |
134 | | */ |
135 | | operator bool() const |
136 | 0 | { |
137 | 0 | return nullptr != ptr_; |
138 | 0 | } |
139 | | |
140 | | /** |
141 | | * @brief operator to call the T methods. |
142 | | */ |
143 | | T* operator ->() const |
144 | 0 | { |
145 | 0 | assert(nullptr != ptr_); |
146 | 0 | return ptr_; |
147 | 0 | } |
148 | | |
149 | | private: |
150 | | |
151 | | std::shared_ptr<RefCountedPointer<T>> parent_; |
152 | | T* const ptr_; |
153 | | }; |
154 | | |
155 | | /** |
156 | | * @brief Ensure no more valid local pointer instances are created, and wait for current ones to die. |
157 | | */ |
158 | | void deactivate() |
159 | 0 | { |
160 | 0 | std::unique_lock<std::mutex> lock(mutex_); |
161 | 0 | is_active_ = false; |
162 | 0 | cv_.wait(lock, [this]() -> bool |
163 | 0 | { |
164 | 0 | return instances_ == 0; |
165 | 0 | }); |
166 | 0 | } |
167 | | |
168 | | private: |
169 | | |
170 | | /** |
171 | | * @brief Increase the reference count. |
172 | | */ |
173 | | void inc_instances() |
174 | 0 | { |
175 | 0 | std::unique_lock<std::mutex> lock(mutex_); |
176 | 0 | ++instances_; |
177 | 0 | } |
178 | | |
179 | | /** |
180 | | * @brief Decrease the reference count. |
181 | | */ |
182 | | void dec_instances() |
183 | 0 | { |
184 | 0 | std::unique_lock<std::mutex> lock(mutex_); |
185 | 0 | --instances_; |
186 | 0 | if (instances_ == 0) |
187 | 0 | { |
188 | 0 | cv_.notify_one(); |
189 | 0 | } |
190 | 0 | } |
191 | | |
192 | | /** |
193 | | * Pointer to the managed object. |
194 | | */ |
195 | | T* const ptr_; |
196 | | |
197 | | /** |
198 | | * Indicates whether the pointee is still alive |
199 | | * and accessing the pointer is valid. |
200 | | */ |
201 | | std::atomic<bool> is_active_; |
202 | | |
203 | | /** |
204 | | * Protections for the number of instances. |
205 | | */ |
206 | | mutable std::mutex mutex_; |
207 | | std::condition_variable cv_; |
208 | | |
209 | | /** |
210 | | * Number of active instances (currently using the pointee). |
211 | | */ |
212 | | size_t instances_; |
213 | | }; |
214 | | |
215 | | } // namespace fastdds |
216 | | } // namespace eprosima |
217 | | |
218 | | #endif // UTILS__REFCOUNTEDPOINTER_HPP |