1 /*
2 
3   Copyright (C) 2011 Grame
4 
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9 
10   This library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14 
15   You should have received a copy of the GNU Lesser General Public
16   License along with this library; if not, write to the Free Software
17   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 
19   Grame Research Laboratory, 9 rue du Garet, 69001 Lyon - France
20   research@grame.fr
21 
22 */
23 
24 #ifndef __smartpointer__
25 #define __smartpointer__
26 
27 #include <cassert>
28 
29 /*!
30 \brief the base class for smart pointers implementation
31 
32 	Any object that want to support smart pointers should
33 	inherit from the smartable class which provides reference counting
34 	and automatic delete when the reference count drops to zero.
35 */
36 class smartable {
37 	private:
38 		unsigned 	refCount;
39 	public:
40 		//! gives the reference count of the object
refs()41 		unsigned refs() const         { return refCount; }
42 		//! addReference increments the ref count and checks for refCount overflow
addReference()43 		void addReference()           { refCount++; assert(refCount != 0); }
44 		//! removeReference delete the object when refCount is zero
removeReference()45 		void removeReference()		  { if (--refCount == 0) delete this; }
46 
47 	protected:
smartable()48 		smartable() : refCount(0) {}
smartable(const smartable &)49 		smartable(const smartable&): refCount(0) {}
50 		//! destructor checks for non-zero refCount
~smartable()51         virtual ~smartable()
52         {
53             //printf(" ~smartable() \n");
54             //assert (refCount == 0);
55         }
56 		smartable& operator=(const smartable&) { return *this; }
57 };
58 
59 /*!
60 \brief the smart pointer implementation
61 
62 	A smart pointer is in charge of maintaining the objects reference count
63 	by the way of pointers operators overloading. It supports class
64 	inheritance and conversion whenever possible.
65 \n	Instances of the SMARTP class are supposed to use \e smartable types (or at least
66 	objects that implements the \e addReference and \e removeReference
67 	methods in a consistent way).
68 */
69 template<class T> class SMARTP {
70 	private:
71 		//! the actual pointer to the class
72 		T* fSmartPtr;
73 
74 	public:
75 		//! an empty constructor - points to null
SMARTP()76 		SMARTP()	: fSmartPtr(0) {}
77 		//! build a smart pointer from a class pointer
SMARTP(T * rawptr)78 		SMARTP(T* rawptr) : fSmartPtr(rawptr)              { if (fSmartPtr) fSmartPtr->addReference(); }
79 		//! build a smart pointer from an convertible class reference
80 		template<class T2>
SMARTP(const SMARTP<T2> & ptr)81 		SMARTP(const SMARTP<T2>& ptr) : fSmartPtr((T*)ptr) { if (fSmartPtr) fSmartPtr->addReference(); }
82 		//! build a smart pointer from another smart pointer reference
SMARTP(const SMARTP & ptr)83 		SMARTP(const SMARTP& ptr) : fSmartPtr((T*)ptr)     { if (fSmartPtr) fSmartPtr->addReference(); }
84 
85 		//! the smart pointer destructor: simply removes one reference count
~SMARTP()86 		~SMARTP()  { if (fSmartPtr) fSmartPtr->removeReference(); }
87 
88 		//! cast operator to retrieve the actual class pointer
89 		operator T*() const  { return fSmartPtr;	}
90 
91 		//! '*' operator to access the actual class pointer
92 		T& operator*() const {
93 			// checks for null dereference
94 			assert (fSmartPtr != 0);
95 			return *fSmartPtr;
96 		}
97 
98 		//! operator -> overloading to access the actual class pointer
99 		T* operator->() const	{
100 			// checks for null dereference
101 			assert (fSmartPtr != 0);
102 			return fSmartPtr;
103 		}
104 
105 		//! operator = that moves the actual class pointer
106 		template <class T2>
107 		SMARTP& operator=(T2 p1_)	{ *this=(T*)p1_; return *this; }
108 
109 		//! operator = that moves the actual class pointer
110 		SMARTP& operator=(T* p_)	{
111 			// check first that pointers differ
112 			if (fSmartPtr != p_) {
113 				// increments the ref count of the new pointer if not null
114 				if (p_ != 0) p_->addReference();
115 				// decrements the ref count of the old pointer if not null
116 				if (fSmartPtr != 0) fSmartPtr->removeReference();
117 				// and finally stores the new actual pointer
118 				fSmartPtr = p_;
119 			}
120 			return *this;
121 		}
122 		//! operator < to support SMARTP map with Visual C++
123 		bool operator<(const SMARTP<T>& p_)	const			  { return fSmartPtr < ((T *) p_); }
124 		//! operator = to support inherited class reference
125 		SMARTP& operator=(const SMARTP<T>& p_)                { return operator=((T *) p_); }
126 		//! dynamic cast support
cast(T2 * p_)127 		template<class T2> SMARTP& cast(T2* p_)               { return operator=(dynamic_cast<T*>(p_)); }
128 		//! dynamic cast support
cast(const SMARTP<T2> & p_)129 		template<class T2> SMARTP& cast(const SMARTP<T2>& p_) { return operator=(dynamic_cast<T*>(p_)); }
130 };
131 
132 #endif
133