1 /*
2 This file is part of Caelum.
3 See http://www.ogre3d.org/wiki/index.php/Caelum
4 
5 Copyright (c) 2008 Caelum team. See Contributors.txt for details.
6 
7 Caelum is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Caelum is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU Lesser General Public License for more details.
16 
17 You should have received a copy of the GNU Lesser General Public License
18 along with Caelum. If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #ifndef CAELUM__PRIVATE_PTR_H
22 #define CAELUM__PRIVATE_PTR_H
23 
24 #include "CaelumPrerequisites.h"
25 
26 namespace Caelum
27 {
28     /** Default traits for Caelum::PrivatePtr.
29      *
30      *  This default traits class make PrivatePtr work like std::auto_ptr.
31      *  Other Traits classes can derive from this and only customize some of
32      *  the functions.
33      *
34      *  @see PrivatePtr
35      */
36     template<class PointedT>
37     struct DefaultPrivatePtrTraits
38     {
39         /// The type of the inner member to hold in PrivatePtr
40         typedef PointedT* InnerPointerType;
41 
42         /// Return an InnerPointerType repressenting a null value.
getNullValueDefaultPrivatePtrTraits43         static inline const InnerPointerType getNullValue() {
44             return 0;
45         }
46 
47         /// Convert InnerPointerType to a naked PointedT.
getPointerDefaultPrivatePtrTraits48         static inline PointedT* getPointer (const InnerPointerType& inner) {
49             return inner;
50         }
51 
52         /// Destroy the inner value (and set null).
destroyDefaultPrivatePtrTraits53         static void destroy (InnerPointerType& inner)
54         {
55             delete inner;
56             inner = 0;
57         }
58     };
59 
60     /** Template for smart pointers with strict unique ownership.
61      *  A lot of objects in Ogre are created and destroyed through other
62      *  "Manager" objects. Even though the memory for such objects is never
63      *  actually leaked better lifetime control is frequently useful.
64      *
65      *  PrivatePtr is very similar in behaviour to std::auto_ptr but tries
66      *  to mimic Ogre::SharedPtr method names. Only one PrivatePtr must exist to
67      *  a certain object at any one time. Assignment and copy  construction will
68      *  in fact pass away ownership and set the original PrivatePtr to null.
69      *
70      *  This very limited functionality makes PrivatePtr very efficient; it should
71      *  have no overhead compared to doing the same thing manually.
72      *
73      *  PrivatePtr supports customization through a static traits class which
74      *  can customize what happens when the PrivatePtr is destroyed. This makes
75      *  it possible to use PrivatePtr classes for fine control over the lifetime
76      *  of objects which are otherwise managed by an external class.
77      *
78      *  @see DefaultPrivatePtrTraits
79      */
80     template<class PointedT, typename TraitsT = DefaultPrivatePtrTraits<PointedT> >
81     class PrivatePtr
82     {
83     private:
84         /// Brings InnerPointerType as a type in this scope.
85         typedef typename TraitsT::InnerPointerType InnerPointerType;
86 
87         /// Inner data member.
88         InnerPointerType mInner;
89 
90 	public:
91         /** Change the inner value.
92          *  This will destroy the old value and gain ownership of the new value.
93          */
94         void reset (const InnerPointerType& newInner = TraitsT::getNullValue()) {
95             if (mInner == newInner) {
96                 return;
97             }
98             TraitsT::destroy (mInner);
99             mInner = newInner;
100         }
101 
release()102         InnerPointerType release () {
103             InnerPointerType result = mInner;
104             mInner = TraitsT::getNullValue();
105             return result;
106         }
107 
108         /** Constructor; always initialize to 0.
109          */
PrivatePtr()110         PrivatePtr () { mInner = TraitsT::getNullValue (); }
111 
112         /** Initializing constructur
113          */
PrivatePtr(const InnerPointerType & inner)114         PrivatePtr (const InnerPointerType& inner) { mInner = inner; }
115 
116         /** Non-virtual destructor (don't derive from this).
117          */
~PrivatePtr()118         ~PrivatePtr () { setNull(); }
119 
120         /** Copy constructor; clears right-hand-side.
121          */
PrivatePtr(PrivatePtr & rhs)122         PrivatePtr (PrivatePtr& rhs)
123         {
124             if (&rhs != this) {
125                 this->reset (rhs.mInner);
126                 rhs.mInner = TraitsT::getNullValue ();
127             }
128         }
129 
130         /** Assignment
131          */
132         const PrivatePtr& operator= (PrivatePtr& rhs)
133         {
134             if (&rhs != this) {
135                 this->reset (rhs.mInner);
136                 rhs.mInner = TraitsT::getNullValue ();
137             }
138             return *this;
139         }
140 
141         /// Check if this is null.
isNull()142         bool isNull () const { return mInner == TraitsT::getNullValue (); }
143 
144         /// Set to null and destroy contents (if any).
setNull()145         void setNull () {
146             TraitsT::destroy (mInner);
147             assert(this->isNull());
148         }
149 
getPointer()150         PointedT* getPointer () const { return TraitsT::getPointer (mInner); }
get()151         PointedT* get () const { return getPointer (); }
152         PointedT* operator-> () const { return getPointer (); }
153         PointedT& operator* () const{ return *getPointer (); }
154     };
155 
156     /** PrivatePtr traits for a movable object.
157      *  This kind of pointer will remove the movable from the scene and destroy it.
158      */
159     template<class MovableT>
160     struct MovableObjectPrivatePtrTraits: public DefaultPrivatePtrTraits<MovableT>
161     {
162         typedef MovableT* InnerPointerType;
163 
destroyMovableObjectPrivatePtrTraits164         static void destroy (InnerPointerType& inner)
165         {
166             if (inner != 0) {
167                 //Ogre::LogManager::getSingletonPtr ()->logMessage (
168                 //        "PrivatePtr: Destroying movable object " + inner->getName ());
169                 inner->_getManager ()->destroyMovableObject (inner);
170                 inner = 0;
171             }
172         }
173     };
174 
175     typedef PrivatePtr<Ogre::MovableObject, MovableObjectPrivatePtrTraits<Ogre::MovableObject> > PrivateMovableObjectPtr;
176     typedef PrivatePtr<Ogre::BillboardChain, MovableObjectPrivatePtrTraits<Ogre::BillboardChain> > PrivateBillboardChainPtr;
177     typedef PrivatePtr<Ogre::BillboardSet, MovableObjectPrivatePtrTraits<Ogre::BillboardSet> > PrivateBillboardSetPtr;
178     typedef PrivatePtr<Ogre::Entity, MovableObjectPrivatePtrTraits<Ogre::Entity> > PrivateEntityPtr;
179     typedef PrivatePtr<Ogre::Light, MovableObjectPrivatePtrTraits<Ogre::Light> > PrivateLightPtr;
180     typedef PrivatePtr<Ogre::ManualObject, MovableObjectPrivatePtrTraits<Ogre::ManualObject> > PrivateManualObjectPtr;
181     typedef PrivatePtr<Ogre::ParticleSystem, MovableObjectPrivatePtrTraits<Ogre::ParticleSystem> > PrivateParticleSystemPtr;
182 
183     /** PrivatePtr traits for a scene node.
184      *  Scene nodes are created and destroyed through the scene manager.
185      *  @see PrivatePrivateSceneNodePtr
186      */
187     struct SceneNodePrivatePtrTraits: public DefaultPrivatePtrTraits<Ogre::SceneNode>
188     {
destroySceneNodePrivatePtrTraits189         static void destroy (InnerPointerType& inner)
190         {
191             if (inner) {
192                 //Ogre::LogManager::getSingletonPtr ()->logMessage (
193                 //        "PrivatePtr: Destroying scene node " + inner->getName ());
194                 inner->getCreator ()->destroySceneNode (inner->getName ());
195                 inner = 0;
196             }
197         }
198     };
199 
200     typedef PrivatePtr<Ogre::SceneNode, SceneNodePrivatePtrTraits> PrivateSceneNodePtr;
201 
202     /** PrivatePtr traits for uniquely-owned resources.
203      *
204      *  All ogre resources are tracked by a resource managed by name and can
205      *  be globally referenced from multiple places. This traits class allows
206      *  you to hold a pointer to a resource which you create and completely
207      *  control.
208      *
209      *  The best example of this is a cloned material. It is frequently useful
210      *  to create a clone of an existing material and tweak settings for one
211      *  particular usage. After the clone is no longer useful the material must
212      *  be explicitly removed from the MaterialManager. Otherwise an unloaded
213      *  resource handle is leaked.
214      *
215      *  When the PrivatePtr gets out of scope the resource is removed from the
216      *  manager. In debug mode this will also check that there are no other
217      *  references to the destroyed resource.
218      */
219     template<class PointedT, class InnerT, class ManagerT>
220     struct PrivateResourcePtrTraits
221     {
222         typedef InnerT InnerPointerType;
223 
getNullValuePrivateResourcePtrTraits224         static const InnerT getNullValue () {
225             return InnerT();
226         }
227 
getPointerPrivateResourcePtrTraits228         static PointedT* getPointer (const InnerPointerType& inner) {
229             return inner.getPointer ();
230         }
231 
destroyPrivateResourcePtrTraits232         static void destroy (InnerPointerType& inner) {
233             if (!inner.isNull ()) {
234                 //Ogre::LogManager::getSingletonPtr ()->logMessage (
235                 //        "PrivateResourcePtrTraits: Destroying owned resource"
236                 //        " name=" + inner->getName () +
237                 //        " handle=" + Ogre::StringConverter::toString (inner->getHandle ()) );
238                 ManagerT::getSingletonPtr ()->remove (inner->getHandle ());
239                 assert (inner.unique () && "Resource pointer not unique after destruction");
240                 inner.setNull();
241             }
242         }
243     };
244 
245     typedef PrivatePtr <
246         Ogre::Material,
247         PrivateResourcePtrTraits <
248             Ogre::Material,
249             Ogre::MaterialPtr,
250             Ogre::MaterialManager
251         >
252     > PrivateMaterialPtr;
253 
254     typedef PrivatePtr <
255         Ogre::Mesh,
256         PrivateResourcePtrTraits <
257             Ogre::Mesh,
258             Ogre::MeshPtr,
259             Ogre::MeshManager
260         >
261     > PrivateMeshPtr;
262 }
263 
264 #endif // CAELUM__PRIVATE_PTR_H
265