| 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_OBSERVER_PTR |
|---|
| 15 | #define OSG_OBSERVER_PTR |
|---|
| 16 | |
|---|
| 17 | #include <osg/Notify> |
|---|
| 18 | #include <osg/ref_ptr> |
|---|
| 19 | #include <osg/Observer> |
|---|
| 20 | |
|---|
| 21 | #include <OpenThreads/ScopedLock> |
|---|
| 22 | #include <OpenThreads/Mutex> |
|---|
| 23 | |
|---|
| 24 | namespace osg { |
|---|
| 25 | |
|---|
| 26 | /** Smart pointer for observed objects, that automatically set pointers to them to null when they are deleted. |
|---|
| 27 | * To use the observer_ptr<> robustly in multi-threaded applications it is recommend to access the pointer via |
|---|
| 28 | * the lock() method that passes back a ref_ptr<> that safely takes a reference to the object to prevent deletion |
|---|
| 29 | * during usage of the object. In certain conditions it may be safe to use the pointer directly without using lock(), |
|---|
| 30 | * which will confer a perfomance advantage, the conditions are: |
|---|
| 31 | * 1) The data structure is only accessed/deleted in single threaded/serial way. |
|---|
| 32 | * 2) The data strucutre is guarenteed by high level management of data strucutures and threads which avoid |
|---|
| 33 | * possible situations where the observer_ptr<>'s object may be deleted by one thread whilst being accessed |
|---|
| 34 | * by another. |
|---|
| 35 | * If you are in any doubt about whether it is safe to access the object safe then use the |
|---|
| 36 | * ref_ptr<> observer_ptr<>.lock() combination. */ |
|---|
| 37 | template<class T> |
|---|
| 38 | class observer_ptr |
|---|
| 39 | { |
|---|
| 40 | public: |
|---|
| 41 | typedef T element_type; |
|---|
| 42 | observer_ptr() : _reference(0), _ptr(0) {} |
|---|
| 43 | |
|---|
| 44 | /** |
|---|
| 45 | * Create a observer_ptr from a ref_ptr. |
|---|
| 46 | */ |
|---|
| 47 | observer_ptr(const ref_ptr<T>& rp) |
|---|
| 48 | { |
|---|
| 49 | _reference = rp.valid() ? rp->getOrCreateObserverSet() : 0; |
|---|
| 50 | _ptr = (_reference.valid() && _reference->getObserverdObject()!=0) ? rp.get() : 0; |
|---|
| 51 | } |
|---|
| 52 | |
|---|
| 53 | /** |
|---|
| 54 | * Create a observer_ptr from a raw pointer. For compatibility; |
|---|
| 55 | * the result might not be lockable. |
|---|
| 56 | */ |
|---|
| 57 | observer_ptr(T* rp) |
|---|
| 58 | { |
|---|
| 59 | _reference = rp ? rp->getOrCreateObserverSet() : 0; |
|---|
| 60 | _ptr = (_reference.valid() && _reference->getObserverdObject()!=0) ? rp : 0; |
|---|
| 61 | } |
|---|
| 62 | |
|---|
| 63 | observer_ptr(const observer_ptr& wp) : |
|---|
| 64 | _reference(wp._reference), |
|---|
| 65 | _ptr(wp._ptr) |
|---|
| 66 | { |
|---|
| 67 | } |
|---|
| 68 | |
|---|
| 69 | ~observer_ptr() |
|---|
| 70 | { |
|---|
| 71 | } |
|---|
| 72 | |
|---|
| 73 | observer_ptr& operator = (const observer_ptr& wp) |
|---|
| 74 | { |
|---|
| 75 | if (&wp==this) return *this; |
|---|
| 76 | |
|---|
| 77 | _reference = wp._reference; |
|---|
| 78 | _ptr = wp._ptr; |
|---|
| 79 | return *this; |
|---|
| 80 | } |
|---|
| 81 | |
|---|
| 82 | observer_ptr& operator = (const ref_ptr<T>& rp) |
|---|
| 83 | { |
|---|
| 84 | _reference = rp.valid() ? rp->getOrCreateObserverSet() : 0; |
|---|
| 85 | _ptr = (_reference.valid() && _reference->getObserverdObject()!=0) ? rp.get() : 0; |
|---|
| 86 | return *this; |
|---|
| 87 | } |
|---|
| 88 | |
|---|
| 89 | observer_ptr& operator = (T* rp) |
|---|
| 90 | { |
|---|
| 91 | _reference = rp ? rp->getOrCreateObserverSet() : 0; |
|---|
| 92 | _ptr = (_reference.valid() && _reference->getObserverdObject()!=0) ? rp : 0; |
|---|
| 93 | return *this; |
|---|
| 94 | } |
|---|
| 95 | |
|---|
| 96 | /** |
|---|
| 97 | * Assign the observer_ptr to a ref_ptr. The ref_ptr will be valid if the |
|---|
| 98 | * referenced object hasn't been deleted and has a ref count > 0. |
|---|
| 99 | */ |
|---|
| 100 | bool lock(ref_ptr<T>& rptr) const |
|---|
| 101 | { |
|---|
| 102 | if (!_reference) |
|---|
| 103 | { |
|---|
| 104 | rptr = 0; |
|---|
| 105 | return false; |
|---|
| 106 | } |
|---|
| 107 | |
|---|
| 108 | Referenced* obj = _reference->addRefLock(); |
|---|
| 109 | if (!obj) |
|---|
| 110 | { |
|---|
| 111 | rptr = 0; |
|---|
| 112 | return false; |
|---|
| 113 | } |
|---|
| 114 | |
|---|
| 115 | rptr = _ptr; |
|---|
| 116 | obj->unref_nodelete(); |
|---|
| 117 | return rptr.valid(); |
|---|
| 118 | } |
|---|
| 119 | |
|---|
| 120 | /** Comparison operators. These continue to work even after the |
|---|
| 121 | * observed object has been deleted. |
|---|
| 122 | */ |
|---|
| 123 | bool operator == (const observer_ptr& wp) const { return _reference == wp._reference; } |
|---|
| 124 | bool operator != (const observer_ptr& wp) const { return _reference != wp._reference; } |
|---|
| 125 | bool operator < (const observer_ptr& wp) const { return _reference < wp._reference; } |
|---|
| 126 | bool operator > (const observer_ptr& wp) const { return _reference > wp._reference; } |
|---|
| 127 | |
|---|
| 128 | // Non-strict interface, for compatibility |
|---|
| 129 | // comparison operator for const T*. |
|---|
| 130 | inline bool operator == (const T* ptr) const { return _ptr == ptr; } |
|---|
| 131 | inline bool operator != (const T* ptr) const { return _ptr != ptr; } |
|---|
| 132 | inline bool operator < (const T* ptr) const { return _ptr < ptr; } |
|---|
| 133 | inline bool operator > (const T* ptr) const { return _ptr > ptr; } |
|---|
| 134 | |
|---|
| 135 | // Convenience methods for operating on object, however, access is not automatically threadsafe. |
|---|
| 136 | // To make thread safe, one should either ensure at a high level |
|---|
| 137 | // that the object will not be deleted while operating on it, or |
|---|
| 138 | // by using the observer_ptr<>::lock() to get a ref_ptr<> that |
|---|
| 139 | // ensures the objects stay alive throughout all access to it. |
|---|
| 140 | |
|---|
| 141 | // Throw an error if _reference is null? |
|---|
| 142 | inline T& operator*() const { return *_ptr; } |
|---|
| 143 | inline T* operator->() const { return _ptr; } |
|---|
| 144 | |
|---|
| 145 | // get the raw C pointer |
|---|
| 146 | inline T* get() const { return (_reference.valid() && _reference->getObserverdObject()!=0) ? _ptr : 0; } |
|---|
| 147 | |
|---|
| 148 | inline bool operator!() const { return get() == 0; } |
|---|
| 149 | inline bool valid() const { return get() != 0; } |
|---|
| 150 | |
|---|
| 151 | protected: |
|---|
| 152 | |
|---|
| 153 | osg::ref_ptr<ObserverSet> _reference; |
|---|
| 154 | T* _ptr; |
|---|
| 155 | }; |
|---|
| 156 | |
|---|
| 157 | } |
|---|
| 158 | |
|---|
| 159 | #endif |
|---|