Ocean
Loading...
Searching...
No Matches
base/ObjectRef.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#ifndef META_OCEAN_BASE_OBJECT_REF_H
9#define META_OCEAN_BASE_OBJECT_REF_H
10
11#include "ocean/base/Base.h"
12#include "ocean/base/Callback.h"
13#include "ocean/base/Lock.h"
14
15#include <atomic>
16
17namespace Ocean
18{
19
20/**
21 * This template class implements a object reference with an internal reference counter.
22 * The reference counter is thread-safe.
23 *
24 * Further, this implementation allows to define a callback function for release events.<br>
25 * By application of the callback function, a manager can be implemented that allows to store several ObjectRef objects in a managed list.<br>
26 * The manager can used this list to provide instances of specific ObjectRef objects on demand.<br>
27 * Due to the callback function, the manager will be informed whenever an ObjectRef object can be removed from the managed list so that the real object (which is encapsulated by the ObjectRef) can be released automatically.<br>
28 * The following code snippet demonstrates the application:
29 * @code
30 * // any class, struct or data type
31 * class DataType
32 * {
33 * public:
34 *
35 * // any function
36 * int function(const double value);
37 * };
38 *
39 * // we create a new ObjectRef instance
40 * const ObjectRef<DataType> object(new DataType());
41 *
42 * if (!object.isNull())
43 * {
44 * const int result = object->function(5.0);
45 * }
46 *
47 * const ObjectRef<DataType> sameObject(object);
48 *
49 * ocean_assert(sameObject);
50 * const int result2 = sameObject->function(5.0);
51 * @endcode
52 * @tparam T Type of the object to be encapsulated by this object reference
53 * @see SmartObjectRef.
54 * @ingroup base
55 */
56template <typename T>
58{
59 template <typename T2, typename TBase> friend class SmartObjectRef;
60 friend class ObjectHolder;
61
62 public:
63
64 /**
65 * Definition of a release callback function.
66 * The first parameter determines the object for that the release event is invoked.<br>
67 */
69
70 protected:
71
72 /**
73 * This class implements a helper object for the actual object reference class.
74 * ObjectRef objects sharing the same encapsulated object share the same holder object of the encapsulated object.
75 * The holder is created only once for the very first ObjectRef object, while the pointer to this holder is shared to the subsequent ObjectRef objects (which access the same encapsulated object).
76 */
78 {
79 friend class ObjectRef<T>;
80
81 public:
82
83 /**
84 * Creates a new ObjectHolder object.
85 * @param object Pointer to the internal object
86 * @param releaseCallback Callback for release event
87 */
88 explicit inline ObjectHolder(T* object, const ReleaseCallback& releaseCallback = ReleaseCallback());
89
90 /**
91 * Increases the reference counter.
92 * @return Pointer to this object
93 */
94 inline ObjectHolder* ref();
95
96 /**
97 * Decreases the reference counter and disposes the encapsulated object and the holder itself if the reference counter reaches zero.
98 */
99 void unref();
100
101 /**
102 * Returns the number of references.
103 * @return Reference number
104 */
105 inline unsigned int references() const;
106
107 protected:
108
109 /// Pointer to the internal object.
110 T* object_ = nullptr;
111
112 /// Reference counter of the internal object.
113 std::atomic<unsigned int> atomicReferenceCounter_;
114
115 /// Release callback
117 };
118
119 public:
120
121 /**
122 * Creates an empty ObjectRef object.
123 */
124 ObjectRef() = default;
125
126 /**
127 * Copy constructor.
128 * Copies an ObjectRef object.
129 * @param objectRef ObjectRef to copy
130 */
131 inline ObjectRef(const ObjectRef<T>& objectRef);
132
133 /**
134 * Move constructor.
135 * @param object The object to be moved
136 */
137 inline ObjectRef(ObjectRef<T>&& object) noexcept;
138
139 /**
140 * Creates a new ObjectRef holding a given object.
141 * Beware: The given object will be released by this object reference!
142 * @param object The object to store
143 */
144 explicit inline ObjectRef(T* object);
145
146 /**
147 * Creates a new ObjectRef holding and managing a given object.
148 * This constructor also requests a release callback event.<br>
149 * This callback event will be invoked after the internal reference counter of this object has been decremented and is equal to 1 afterwards.<br>
150 * Thus, the release callback provides an information that in the moment of the callback only one instance of the ObjectRef exists.<br>
151 * Therefore, this callback can be used to release an ObjectRef object which is stored in e.g. a managed list so that finally the reference counter will be zero and the stored object will be released.<br>
152 * Beware: The given object will be released by this object reference!
153 * @param object The object to store
154 * @param releaseCallback Callback function which will be invoked if only one ObjectRef instance managing a specific object is left (if more than one existed before)
155 */
156 inline ObjectRef(T* object, const ReleaseCallback& releaseCallback);
157
158 /**
159 * Destructs an object reference object and releases the internal object if possible.
160 */
161 inline ~ObjectRef();
162
163 /**
164 * Returns a reference to the internal object forcing to a specified type.
165 * Beware: Check whether this reference holds a valid internal object before calling this function!<br>
166 * Beware: Make sure the forced type is matching the internal object!
167 * @return Internal object with the forced type
168 */
169 template <typename T2> inline T2& force() const;
170
171 /**
172 * Returns a point to the internal object if existing.
173 * Beware: Check whether this reference holds an internal object before calling this function!
174 * @return Pointer to the internal object
175 */
176 inline T* operator->() const;
177
178 /**
179 * Returns a reference to the internal object if existing.
180 * Beware: Check whether this reference holds an internal object before calling this function!
181 * @return Reference to the internal object
182 */
183 inline T& operator*() const;
184
185 /**
186 * Returns whether there is no other object reference but this one.
187 * @return True, if so
188 */
189 inline bool isUnique() const;
190
191 /**
192 * Returns whether this object reference holds no internal object.
193 * @return True, if so
194 */
195 inline bool isNull() const;
196
197 /**
198 * Releases the internal object, if any.
199 * Beware: After the release the object can not be accessed anymore!
200 */
201 inline void release();
202
203 /**
204 * Returns a pointer to the objects that is encapsulated by this wrapper.
205 * @return Pointer to the object or nullptr if no object is encapsulated
206 */
207 inline T* pointer() const;
208
209 /**
210 * Assign operator.
211 * @param objectRef Right object reference to assign
212 * @return Reference to this object reference
213 */
214 inline ObjectRef<T>& operator=(const ObjectRef<T>& objectRef);
215
216 /**
217 * Move operator.
218 * @param right The right object to assign
219 * @return Reference to this object
220 */
221 inline ObjectRef<T>& operator=(ObjectRef<T>&& right) noexcept;
222
223 /**
224 * Returns whether two object references are holds the same internal object.
225 * @param objectRef Right object reference
226 * @return True, if so
227 */
228 inline bool operator==(const ObjectRef<T>& objectRef) const;
229
230 /**
231 * Returns whether two object references are not equal.
232 * @param objectRef Right object reference
233 * @return True, if so
234 */
235 inline bool operator!=(const ObjectRef<T>& objectRef) const;
236
237 /**
238 * Returns whether the left object is less than the right one.
239 * @param objectRef Right operand
240 * @return True, if so
241 */
242 inline bool operator<(const ObjectRef<T>& objectRef) const;
243
244 /**
245 * Returns whether this object reference holds an internal object.
246 * @return True, if so
247 */
248 explicit inline operator bool() const;
249
250 protected:
251
252 /**
253 * Destroys the object located in the ObjectHolder object.
254 * This function is used to get access to the protected delete operator of the internal encapsulated object.
255 * @param object the object to destroy
256 */
257 static inline void destroyObject(T* object);
258
259 protected:
260
261 /// Pointer to the object holder.
263};
264
265template <typename T>
266inline ObjectRef<T>::ObjectHolder::ObjectHolder(T* newObject, const ReleaseCallback& releaseCallback) :
267 object_(newObject),
268 atomicReferenceCounter_(1u),
269 callback_(releaseCallback)
270{
271 // nothing to do here
272}
273
274template <typename T>
276{
277 ocean_assert(atomicReferenceCounter_ != 0u);
278 ++atomicReferenceCounter_;
279
280 return this;
281}
282
283template <typename T>
285{
286 ocean_assert(atomicReferenceCounter_ != 0u);
287
288 const unsigned int newReferenceCount = atomicReferenceCounter_.fetch_sub(1u) - 1u;
289
290 if (newReferenceCount == 1u && callback_)
291 {
292 // from this point on the reference counter cannot (and also must not) be decremented from any caller but from the object which receives the callback
293
294 ocean_assert(object_);
295 callback_(object_);
296 return;
297 }
298
299 if (newReferenceCount == 0u)
300 {
301 // from this point on there is the guarantee that the no party is interested in the encapsulated object anymore as all corresponding ObjectRef instances have been disposed already
302
304
305#ifdef OCEAN_DEBUG
306 object_ = nullptr;
307#endif
308
309 delete this;
310 }
311}
312
313template <typename T>
314inline unsigned int ObjectRef<T>::ObjectHolder::references() const
315{
316 return atomicReferenceCounter_;
317}
318
319template <typename T>
320inline ObjectRef<T>::ObjectRef(const ObjectRef<T>& objectRef)
321{
322 if (objectRef.objectHolder_ != nullptr)
323 {
324 objectHolder_ = objectRef.objectHolder_->ref();
325 }
326}
327
328template <typename T>
329inline ObjectRef<T>::ObjectRef(ObjectRef<T>&& object) noexcept :
331{
332 object.objectHolder_ = nullptr;
333}
334
335template <typename T>
336inline ObjectRef<T>::ObjectRef(T* object)
337{
338 if (object != nullptr)
339 {
340 objectHolder_ = new ObjectHolder(object);
341 }
342}
343
344template <typename T>
345inline ObjectRef<T>::ObjectRef(T* object, const ReleaseCallback& releaseCallback)
346{
347 if (object != nullptr)
348 {
349 objectHolder_ = new ObjectHolder(object, releaseCallback);
350 }
351}
352
353template <typename T>
355{
356 if (objectHolder_ != nullptr)
357 {
359 }
360}
361
362template <typename T>
363template <typename T2>
364inline T2& ObjectRef<T>::force() const
365{
366 ocean_assert(objectHolder_ != nullptr);
367 ocean_assert(objectHolder_->object_ != nullptr);
368 ocean_assert(dynamic_cast<T2*>(objectHolder_->object_) != nullptr);
369
370 return dynamic_cast<T2&>(*objectHolder_->object_);
371}
372
373template <typename T>
375{
376 ocean_assert(objectHolder_ != nullptr);
377 ocean_assert(objectHolder_->object_);
378 return objectHolder_->object_;
379}
380
381template <typename T>
382inline T& ObjectRef<T>::operator*() const
383{
384 ocean_assert(objectHolder_ != nullptr);
385 ocean_assert(objectHolder_->object_);
386 return *objectHolder_->object_;
387}
388
389template <typename T>
390inline bool ObjectRef<T>::isNull() const
391{
392 return objectHolder_ == nullptr;
393}
394
395template <typename T>
396inline bool ObjectRef<T>::isUnique() const
397{
398 if (objectHolder_)
399 {
400 return objectHolder_->references() == 1u;
401 }
402
403 return true;
404}
405
406template <typename T>
408{
409 if (objectHolder_)
410 {
412 objectHolder_ = nullptr;
413 }
414}
415
416template <typename T>
417inline T* ObjectRef<T>::pointer() const
418{
419 ocean_assert(!objectHolder_ || objectHolder_->object_);
420 return objectHolder_ ? objectHolder_->object_ : nullptr;
421}
422
423template <typename T>
425{
426 if (objectHolder_)
427 {
429 objectHolder_ = nullptr;
430 }
431
432 if (objectRef.objectHolder_)
433 {
434 objectHolder_ = objectRef.objectHolder_->ref();
435 }
436
437 return *this;
438}
439
440template <typename T>
442{
443 if (this != &right)
444 {
445 if (objectHolder_)
446 {
448 }
449
450 objectHolder_ = right.objectHolder_;
451 right.objectHolder_ = nullptr;
452 }
453
454 return *this;
455}
456
457template <typename T>
458inline bool ObjectRef<T>::operator==(const ObjectRef<T>& objectRef) const
459{
460 if (!objectHolder_ && !objectRef.objectHolder_)
461 {
462 return true;
463 }
464
465 if (objectHolder_ && objectRef.objectHolder_)
466 {
467 return objectHolder_->object_ == objectRef.objectHolder_->object_;
468 }
469
470 return false;
471}
472
473template <typename T>
474inline bool ObjectRef<T>::operator!=(const ObjectRef<T>& objectRef) const
475{
476 return !(*this == objectRef);
477}
478
479template <typename T>
480inline ObjectRef<T>::operator bool() const
481{
482 return objectHolder_ != nullptr;
483}
484
485template <typename T>
487{
488 delete object;
489}
490
491template <typename T>
492inline bool ObjectRef<T>::operator<(const ObjectRef& objectRef) const
493{
494 if (objectHolder_ && objectRef.objectHolder_)
495 {
496 return objectHolder_->object_ < objectRef.objectHolder_->object_;
497 }
498
499 if (objectHolder_ && !objectRef.objectHolder_)
500 {
501 return false;
502 }
503
504 return !objectHolder_ && objectRef.objectHolder_;
505}
506
507}
508
509#endif // META_OCEAN_BASE_OBJECT_REF_H
This class implements a container for callback functions.
Definition Callback.h:3456
This class implements a helper object for the actual object reference class.
Definition base/ObjectRef.h:78
ObjectHolder * ref()
Increases the reference counter.
Definition base/ObjectRef.h:275
T * object_
Pointer to the internal object.
Definition base/ObjectRef.h:110
ReleaseCallback callback_
Release callback.
Definition base/ObjectRef.h:116
unsigned int references() const
Returns the number of references.
Definition base/ObjectRef.h:314
void unref()
Decreases the reference counter and disposes the encapsulated object and the holder itself if the ref...
Definition base/ObjectRef.h:284
std::atomic< unsigned int > atomicReferenceCounter_
Reference counter of the internal object.
Definition base/ObjectRef.h:113
ObjectHolder(T *object, const ReleaseCallback &releaseCallback=ReleaseCallback())
Creates a new ObjectHolder object.
Definition base/ObjectRef.h:266
This template class implements a object reference with an internal reference counter.
Definition base/ObjectRef.h:58
~ObjectRef()
Destructs an object reference object and releases the internal object if possible.
Definition base/ObjectRef.h:354
T * pointer() const
Returns a pointer to the objects that is encapsulated by this wrapper.
Definition base/ObjectRef.h:417
T * operator->() const
Returns a point to the internal object if existing.
Definition base/ObjectRef.h:374
ObjectRef(ObjectRef< T > &&object) noexcept
Move constructor.
Definition base/ObjectRef.h:329
ObjectRef< T > & operator=(ObjectRef< T > &&right) noexcept
Move operator.
Definition base/ObjectRef.h:441
ObjectHolder * objectHolder_
Pointer to the object holder.
Definition base/ObjectRef.h:262
bool isUnique() const
Returns whether there is no other object reference but this one.
Definition base/ObjectRef.h:396
ObjectRef()=default
Creates an empty ObjectRef object.
bool isNull() const
Returns whether this object reference holds no internal object.
Definition base/ObjectRef.h:390
ObjectRef(T *object, const ReleaseCallback &releaseCallback)
Creates a new ObjectRef holding and managing a given object.
Definition base/ObjectRef.h:345
static void destroyObject(T *object)
Destroys the object located in the ObjectHolder object.
Definition base/ObjectRef.h:486
bool operator==(const ObjectRef< T > &objectRef) const
Returns whether two object references are holds the same internal object.
Definition base/ObjectRef.h:458
ObjectRef< T > & operator=(const ObjectRef< T > &objectRef)
Assign operator.
Definition base/ObjectRef.h:424
ObjectRef(const ObjectRef< T > &objectRef)
Copy constructor.
Definition base/ObjectRef.h:320
T2 & force() const
Returns a reference to the internal object forcing to a specified type.
Definition base/ObjectRef.h:364
Callback< void, const T * > ReleaseCallback
Definition of a release callback function.
Definition base/ObjectRef.h:68
ObjectRef(T *object)
Creates a new ObjectRef holding a given object.
Definition base/ObjectRef.h:336
T & operator*() const
Returns a reference to the internal object if existing.
Definition base/ObjectRef.h:382
void release()
Releases the internal object, if any.
Definition base/ObjectRef.h:407
bool operator<(const ObjectRef< T > &objectRef) const
Returns whether the left object is less than the right one.
Definition base/ObjectRef.h:492
bool operator!=(const ObjectRef< T > &objectRef) const
Returns whether two object references are not equal.
Definition base/ObjectRef.h:474
This template class implements a smart object reference which is a specialization of an ObjectRef obj...
Definition SmartObjectRef.h:90
The namespace covering the entire Ocean framework.
Definition Accessor.h:15