AGX Dynamics 2.41.2.0
Loading...
Searching...
No Matches
Referenced.h
Go to the documentation of this file.
1/*
2Copyright 2007-2025. Algoryx Simulation AB.
3
4All AGX source code, intellectual property, documentation, sample code,
5tutorials, scene files and technical white papers, are copyrighted, proprietary
6and confidential material of Algoryx Simulation AB. You may not download, read,
7store, distribute, publish, copy or otherwise disseminate, use or expose this
8material unless having a written signed agreement with Algoryx Simulation AB, or having been
9advised so by Algoryx Simulation AB for a time limited evaluation, or having purchased a
10valid commercial license from Algoryx Simulation AB.
11
12Algoryx Simulation AB disclaims all responsibilities for loss or damage caused
13from using this software, unless otherwise stated in written agreements with
14Algoryx Simulation AB.
15*/
16
17#ifndef AGX_REFERENCED_H
18#define AGX_REFERENCED_H
19
20#ifdef _MSC_VER
21# pragma warning(push)
22# pragma warning(disable: 4251) // warning C4251: class X needs to have dll-interface to be used by clients of class Y
23#endif
24
25
28
29#include <agx/ref_ptr.h>
30#include <agx/observer_ptr.h>
31#include <agx/agxCore_export.h>
32#include <agx/AtomicValue.h>
33#include <agx/ScopeLock.h>
34
35#include <mutex>
36
37#if AGX_DEBUG_REFERENCED()
38# include <map>
39# include <agx/StackWalker.h>
40#endif
41
42
43#if AGX_DEBUG_TRACK_REFERENCED_OBJECTS()
45#endif
46
47
48#define OBSERVER_CONTAINER_TYPE 1 // 1: Vector< Observer* > pointer (new/delete)
49 // 2: HashSet< Observer* > pointer (new/delete)
50 // 3: Vector< Observer* > member on stack
51
52#if OBSERVER_CONTAINER_TYPE == 1
53#include <agx/Vector.h>
54#define ObserverContainer VectorPOD< Observer* >*
55#define INSERT_OBSERVER( obs ) \
56 if ( !m_observers->contains( obs ) ) m_observers->push_back( obs )
57#define REMOVE_OBSERVER( obs ) \
58 if ( m_observers ) m_observers->findAndErase( obs )
59#define REPORT_REFERENCED_DELETED \
60 if ( m_observers ) { \
61 for ( size_t i = 0, numObservers = m_observers->size(); i < numObservers; ++i ) \
62 (*m_observers)[ i ]->objectDeleted( this ); \
63 delete m_observers; \
64 m_observers = nullptr; \
65 }
66#elif OBSERVER_CONTAINER_TYPE == 2
67#include <agx/HashSet.h>
68#define ObserverContainer HashSet< Observer* >*
69#define INSERT_OBSERVER( obs ) \
70 if ( m_observers == nullptr ) m_observers = new HashSet< Observer* >; \
71 m_observers->insert( obs )
72#define REMOVE_OBSERVER( obs ) \
73 if ( m_observers ) m_observers->erase( obs )
74#define REPORT_REFERENCED_DELETED \
75 if ( m_observers ) { \
76 for ( HashSet< Observer* >::iterator i = m_observers->begin(), end = m_observers->end(); i != end; ++i ) \
77 (*i)->objectDeleted( this ); \
78 delete m_observers; \
79 m_observers = nullptr; \
80 }
81#elif OBSERVER_CONTAINER_TYPE == 3
82#include <agx/Vector.h>
83#define ObserverContainer Vector< Observer* >
84#define INSERT_OBSERVER( obs ) \
85 if ( !m_observers.contains( obs ) ) m_observers.push_back( obs )
86#define REMOVE_OBSERVER( obs ) \
87 m_observers.findAndErase( obs )
88#define REPORT_REFERENCED_DELETED \
89 for ( size_t i = 0, numObservers = m_observers.size(); i < numObservers; ++i ) \
90 m_observers[ i ]->objectDeleted( this );
91#endif
92
93namespace agx
94{
95 // forward declare, declared after Referenced below.
96 class DeleteHandler;
97 class Observer;
98
99 using Mutex = std::mutex;
100
101#define AGX_EXPIRED_SCOPE_ALLOCATION (-0xABC)
102
120 {
121
122 public:
123
126
127 //explicit Referenced(/*bool threadSafeRefUnref*/);
128#ifndef SWIG
130#endif
131
133 Referenced& operator = (const Referenced&);
134
140 void reference(void* ptr = nullptr) const;
141
150 void unreference(void* ptr = nullptr) const;
151
155 int getReferenceCount() const;
156
166
167 public:
168
170
171
172 void setReferenceCount(int count) const;
173
177 void addObserver( Observer* observer ) const;
178
182 void removeObserver( Observer* observer ) const;
183
185
189 template <typename T>
190 bool is() const;
191
195 template <typename T>
196 T *as();
197
198 template <typename T>
199 const T *as() const;
200
201
205 template <typename T>
206 T *asSafe();
207
208 template <typename T>
209 const T *asSafe() const;
210
211 friend class DeleteHandler;
212
213#if AGX_DEBUG_REFERENCED()
214 static bool getEnableStackTrace();
215 static void setEnableStackTrace( bool flag );
216
217 typedef std::map<void*, agx::StackTrace> StackMap;
218 const StackMap& getStackMap() const;
219#endif
220 public:
221
222 template <typename T>
223 static bool ValidateCast(const Referenced *object);
224
225 protected:
227 virtual ~Referenced();
228
233 static void setDeleteHandler(DeleteHandler* handler);
234
238 static DeleteHandler* getDeleteHandler();
239
241
243
244 protected:
245 mutable ObserverContainer m_observers;
246 mutable Mutex m_mutex;
248
249#if AGX_DEBUG_REFERENCED()
250 mutable StackMap m_stackMap;
251#endif
252 };
253
254#define AGX_DECLARE_POINTER_TYPES(type) \
255 class type; \
256 typedef agx::ref_ptr< type > type ## Ref; \
257 typedef agx::observer_ptr< type > type ## Observer; \
258 typedef agx::ref_ptr< const type > type ## ConstRef;\
259 typedef agx::observer_ptr< const type > type ## ConstObserver
260
262
263
270 class AGXCORE_EXPORT DeleteHandler
271 {
272 public:
273
274 virtual ~DeleteHandler();
275
276 void doDelete(const Referenced* object);
277
282 virtual void requestDelete(const Referenced* object);
283 };
284
285#if AGX_DEBUG_REFERENCED()
286
287 AGX_FORCE_INLINE void Referenced::reference( void* ptr ) const
288 {
289 if ( getEnableStackTrace() )
290 m_stackMap.insert( std::make_pair(ptr, agx::generateStackTrace()) );
291#else
292 AGX_FORCE_INLINE void Referenced::reference( void*) const
293 {
294#endif
295 m_refCount.inc();
296 }
297
298#if AGX_DEBUG_REFERENCED()
299
300 AGX_FORCE_INLINE void Referenced::unreference( void* ptr ) const
301#else
302 AGX_FORCE_INLINE void Referenced::unreference( void* ) const
303#endif
304 {
305 int old = m_refCount.dec();
306
307 agxAssert(old > 0 || old == AGX_EXPIRED_SCOPE_ALLOCATION);
308
309#if AGX_DEBUG_REFERENCED()
310 if ( getEnableStackTrace() )
311 m_stackMap.erase( ptr );
312#endif
313
314 if (old == 1) {
316 else delete this;
317 }
318 }
319
320 AGX_FORCE_INLINE void Referenced::addObserver( Observer* observer ) const
321 {
323
324 if (!m_observers)
326
327 INSERT_OBSERVER( observer );
328 }
329
330 AGX_FORCE_INLINE void Referenced::removeObserver( Observer* observer ) const
331 {
333
334 REMOVE_OBSERVER( observer );
335 }
336
338 {
339 return *this;
340 }
341
342 template <typename T>
343 AGX_FORCE_INLINE bool Referenced::is() const { return T::template ValidateCast<T>(this); }
344 // AGX_FORCE_INLINE bool Referenced::is() const { return dynamic_cast<const T *>(this) != nullptr; }
345
346
347 // Compiler warns on '!(void*)this' because it is illegal to call member
348 // functions on nullptr. However, if it helps us find a nullptr dereference
349 // earlier, and with an assert instead of segmentation fault, then I think
350 // it's ok to leave the check.
352 template <typename T>
353 AGX_FORCE_INLINE T *Referenced::as() { agxAssert(!(void *)this || this->is<T>()); return static_cast<T *>(this); }
354 #include <agx/PopDisableWarnings.h>
355
356
357 template <typename T>
358 AGX_FORCE_INLINE const T *Referenced::as() const { return const_cast<Referenced *>(this)->as<T>(); }
359
360
361 template <typename T>
362 AGX_FORCE_INLINE T *Referenced::asSafe() { return dynamic_cast<T *>(this); }
363
364 template <typename T>
365 AGX_FORCE_INLINE const T *Referenced::asSafe() const { return const_cast<Referenced *>(this)->asSafe<T>(); }
366
367 template <typename T>
368 AGX_FORCE_INLINE bool Referenced::ValidateCast(const Referenced *object) { return dynamic_cast<const T *>(object) != nullptr; }
369
371 {
372 return m_refCount.get();
373 }
374
375 AGX_FORCE_INLINE void DeleteHandler::doDelete(const Referenced* object)
376 {
377 delete object;
378 }
379
380 AGX_FORCE_INLINE void DeleteHandler::requestDelete(const Referenced* object)
381 {
382 doDelete(object);
383 }
384
386
387}
388
389#ifdef _MSC_VER
390# pragma warning(pop)
391#endif
392
393
394#endif
#define AGX_EXPIRED_SCOPE_ALLOCATION
Definition: Referenced.h:101
#define AGXCORE_EXPORT
T get() const
Get the current value.
Definition: AtomicValue.h:136
T inc()
Increment the value.
Definition: AtomicValue.h:168
T dec()
Decrement the value.
Definition: AtomicValue.h:174
Base class providing referencing counted objects.
Definition: Referenced.h:120
void unreference_nodelete() const
Decrement the reference count by one, indicating that a pointer to this object is referencing it.
void reference(void *ptr=nullptr) const
Explicitly increment the reference count by one, indicating that this object has another pointer whic...
static bool ValidateCast(const Referenced *object)
ObserverContainer m_observers
Definition: Referenced.h:245
T * asSafe()
Safe subclass casting, return nullptr if template type does not match.
static void setDeleteHandler(DeleteHandler *handler)
Internal: Set a DeleteHandler to which deletion of all referenced counted objects will be delegated t...
Referenced & operator=(const Referenced &)
Assignment operator. Will increment the number of references to the referenced object.
bool is() const
Subclass test.
void unreference(void *ptr=nullptr) const
Decrement the reference count by one, indicating that a pointer to this object is referencing it.
int getReferenceCount() const
void allocateObserverVector() const
AtomicValue m_refCount
Definition: Referenced.h:247
virtual ~Referenced()
Destructor.
T * as()
Subclass casting.
Referenced(const Referenced &)
void deleteUsingDeleteHandler() const
Referenced()
Default constructor.
static DeleteHandler * getDeleteHandler()
#define agxAssert(expr)
Definition: debug.h:143
#define DOXYGEN_END_INTERNAL_BLOCK()
Definition: macros.h:89
#define DOXYGEN_START_INTERNAL_BLOCK()
Definition: macros.h:88
#define AGX_FORCE_INLINE
Definition: macros.h:58
The agx namespace contains the dynamics/math part of the AGX Dynamics API.
std::mutex Mutex
Definition: Referenced.h:99
std::lock_guard< T > ScopeLock
agx::ScopeLock is an alias for std::lock_guard
Definition: ScopeLock.h:31