root/OpenSceneGraph/trunk/include/osg/Referenced @ 13041

Revision 13041, 6.4 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14#ifndef OSG_REFERENCED
15#define OSG_REFERENCED 1
16
17#include <osg/Export>
18
19#include <OpenThreads/ScopedLock>
20#include <OpenThreads/Mutex>
21#include <OpenThreads/Atomic>
22
23#if !defined(_OPENTHREADS_ATOMIC_USE_MUTEX)
24# define _OSG_REFERENCED_USE_ATOMIC_OPERATIONS
25#endif
26
27namespace osg {
28
29// forward declare, declared after Referenced below.
30class DeleteHandler;
31class Observer;
32class ObserverSet;
33
34/** template class to help enforce static initialization order. */
35template <typename T, T M()>
36struct depends_on
37{
38    depends_on() { M(); }
39};
40
41/** Base class for providing reference counted objects.*/
42class OSG_EXPORT Referenced
43{
44
45    public:
46
47
48        Referenced();
49
50        explicit Referenced(bool threadSafeRefUnref);
51
52        Referenced(const Referenced&);
53
54        inline Referenced& operator = (const Referenced&) { return *this; }
55
56        /** Set whether to use a mutex to ensure ref() and unref() are thread safe.*/
57        virtual void setThreadSafeRefUnref(bool threadSafe);
58
59        /** Get whether a mutex is used to ensure ref() and unref() are thread safe.*/
60
61#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
62        bool getThreadSafeRefUnref() const { return true; }
63#else
64        bool getThreadSafeRefUnref() const { return _refMutex!=0; }
65#endif
66
67        /** Get the mutex used to ensure thread safety of ref()/unref(). */
68#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
69        OpenThreads::Mutex* getRefMutex() const { return getGlobalReferencedMutex(); }
70#else
71        OpenThreads::Mutex* getRefMutex() const { return _refMutex; }
72#endif
73
74        /** Get the optional global Referenced mutex, this can be shared between all osg::Referenced.*/
75        static OpenThreads::Mutex* getGlobalReferencedMutex();
76
77        /** Increment the reference count by one, indicating that
78            this object has another pointer which is referencing it.*/
79        inline int ref() const;
80
81        /** Decrement the reference count by one, indicating that
82            a pointer to this object is no longer referencing it.  If the
83            reference count goes to zero, it is assumed that this object
84            is no longer referenced and is automatically deleted.*/
85        inline int unref() const;
86
87        /** Decrement the reference count by one, indicating that
88            a pointer to this object is no longer referencing it.  However, do
89            not delete it, even if ref count goes to 0.  Warning, unref_nodelete()
90            should only be called if the user knows exactly who will
91            be responsible for, one should prefer unref() over unref_nodelete()
92            as the latter can lead to memory leaks.*/
93        int unref_nodelete() const;
94
95        /** Return the number of pointers currently referencing this object. */
96        inline int referenceCount() const { return _refCount; }
97
98
99        /** Get the ObserverSet if one is attached, otherwise return NULL.*/
100        ObserverSet* getObserverSet() const
101        {
102            #if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
103                return static_cast<ObserverSet*>(_observerSet.get());
104            #else
105                return static_cast<ObserverSet*>(_observerSet);
106            #endif
107        }
108
109        /** Get the ObserverSet if one is attached, otherwise create an ObserverSet, attach it, then return this newly created ObserverSet.*/
110        ObserverSet* getOrCreateObserverSet() const;
111
112        /** Add a Observer that is observing this object, notify the Observer when this object gets deleted.*/
113        void addObserver(Observer* observer) const;
114
115        /** Remove Observer that is observing this object.*/
116        void removeObserver(Observer* observer) const;
117
118    public:
119
120        /** Set whether reference counting should use a mutex for thread safe reference counting.*/
121        static void setThreadSafeReferenceCounting(bool enableThreadSafeReferenceCounting);
122
123        /** Get whether reference counting is active.*/
124        static bool getThreadSafeReferenceCounting();
125
126        friend class DeleteHandler;
127
128        /** Set a DeleteHandler to which deletion of all referenced counted objects
129          * will be delegated.*/
130        static void setDeleteHandler(DeleteHandler* handler);
131
132        /** Get a DeleteHandler.*/
133        static DeleteHandler* getDeleteHandler();
134
135
136    protected:
137
138        virtual ~Referenced();
139
140        void signalObserversAndDelete(bool signalDelete, bool doDelete) const;
141
142        void deleteUsingDeleteHandler() const;
143
144#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
145        mutable OpenThreads::AtomicPtr  _observerSet;
146
147        mutable OpenThreads::Atomic     _refCount;
148#else
149
150        mutable OpenThreads::Mutex*     _refMutex;
151
152        mutable int                     _refCount;
153
154        mutable void*                   _observerSet;
155#endif
156};
157
158inline int Referenced::ref() const
159{
160#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
161    return ++_refCount;
162#else
163    if (_refMutex)
164    {
165        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
166        return ++_refCount;
167    }
168    else
169    {
170        return ++_refCount;
171    }
172#endif
173}
174
175inline int Referenced::unref() const
176{
177    int newRef;
178#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
179    newRef = --_refCount;
180    bool needDelete = (newRef == 0);
181#else
182    bool needDelete = false;
183    if (_refMutex)
184    {
185        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
186        newRef = --_refCount;
187        needDelete = newRef==0;
188    }
189    else
190    {
191        newRef = --_refCount;
192        needDelete = newRef==0;
193    }
194#endif
195
196    if (needDelete)
197    {
198        signalObserversAndDelete(true,true);
199    }
200    return newRef;
201}
202
203// intrusive_ptr_add_ref and intrusive_ptr_release allow
204// use of osg Referenced classes with boost::intrusive_ptr
205inline void intrusive_ptr_add_ref(Referenced* p) { p->ref(); }
206inline void intrusive_ptr_release(Referenced* p) { p->unref(); }
207
208}
209
210#endif
Note: See TracBrowser for help on using the browser.