Ocean
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 
17 namespace 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  */
56 template <typename T>
57 class ObjectRef
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 
265 template <typename T>
266 inline 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 
274 template <typename T>
276 {
277  ocean_assert(atomicReferenceCounter_ != 0u);
278  ++atomicReferenceCounter_;
279 
280  return this;
281 }
282 
283 template <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 
313 template <typename T>
314 inline unsigned int ObjectRef<T>::ObjectHolder::references() const
315 {
316  return atomicReferenceCounter_;
317 }
318 
319 template <typename T>
320 inline ObjectRef<T>::ObjectRef(const ObjectRef<T>& objectRef)
321 {
322  if (objectRef.objectHolder_ != nullptr)
323  {
324  objectHolder_ = objectRef.objectHolder_->ref();
325  }
326 }
327 
328 template <typename T>
329 inline ObjectRef<T>::ObjectRef(ObjectRef<T>&& object) noexcept :
331 {
332  object.objectHolder_ = nullptr;
333 }
334 
335 template <typename T>
336 inline ObjectRef<T>::ObjectRef(T* object)
337 {
338  if (object != nullptr)
339  {
340  objectHolder_ = new ObjectHolder(object);
341  }
342 }
343 
344 template <typename T>
345 inline ObjectRef<T>::ObjectRef(T* object, const ReleaseCallback& releaseCallback)
346 {
347  if (object != nullptr)
348  {
349  objectHolder_ = new ObjectHolder(object, releaseCallback);
350  }
351 }
352 
353 template <typename T>
355 {
356  if (objectHolder_ != nullptr)
357  {
358  objectHolder_->unref();
359  }
360 }
361 
362 template <typename T>
363 template <typename T2>
364 inline 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 
373 template <typename T>
374 inline T* ObjectRef<T>::operator->() const
375 {
376  ocean_assert(objectHolder_ != nullptr);
377  ocean_assert(objectHolder_->object_);
378  return objectHolder_->object_;
379 }
380 
381 template <typename T>
382 inline T& ObjectRef<T>::operator*() const
383 {
384  ocean_assert(objectHolder_ != nullptr);
385  ocean_assert(objectHolder_->object_);
386  return *objectHolder_->object_;
387 }
388 
389 template <typename T>
390 inline bool ObjectRef<T>::isNull() const
391 {
392  return objectHolder_ == nullptr;
393 }
394 
395 template <typename T>
396 inline bool ObjectRef<T>::isUnique() const
397 {
398  if (objectHolder_)
399  {
400  return objectHolder_->references() == 1u;
401  }
402 
403  return true;
404 }
405 
406 template <typename T>
408 {
409  if (objectHolder_)
410  {
411  objectHolder_->unref();
412  objectHolder_ = nullptr;
413  }
414 }
415 
416 template <typename T>
417 inline T* ObjectRef<T>::pointer() const
418 {
419  ocean_assert(!objectHolder_ || objectHolder_->object_);
420  return objectHolder_ ? objectHolder_->object_ : nullptr;
421 }
422 
423 template <typename T>
425 {
426  if (objectHolder_)
427  {
428  objectHolder_->unref();
429  objectHolder_ = nullptr;
430  }
431 
432  if (objectRef.objectHolder_)
433  {
434  objectHolder_ = objectRef.objectHolder_->ref();
435  }
436 
437  return *this;
438 }
439 
440 template <typename T>
442 {
443  if (this != &right)
444  {
445  if (objectHolder_)
446  {
447  objectHolder_->unref();
448  }
449 
450  objectHolder_ = right.objectHolder_;
451  right.objectHolder_ = nullptr;
452  }
453 
454  return *this;
455 }
456 
457 template <typename T>
458 inline 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 
473 template <typename T>
474 inline bool ObjectRef<T>::operator!=(const ObjectRef<T>& objectRef) const
475 {
476  return !(*this == objectRef);
477 }
478 
479 template <typename T>
480 inline ObjectRef<T>::operator bool() const
481 {
482  return objectHolder_ != nullptr;
483 }
484 
485 template <typename T>
487 {
488  delete object;
489 }
490 
491 template <typename T>
492 inline 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 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.
friend class ObjectHolder
Definition: base/ObjectRef.h:60
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