0.6.0-1 release
[manu/suphp.git] / src / SmartPtr.hpp
1 /*
2     suPHP - (c)2002-2005 Sebastian Marsching <sebastian@marsching.com>
3
4     This file is part of suPHP.
5
6     suPHP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     suPHP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with suPHP; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #ifndef SUPHP_SMARTPTR_H
22
23 namespace suPHP {
24     class Environment;
25 };
26
27 #define SUPHP_SMARTPTR_H
28
29 #include <map>
30 #include <cstdlib>
31 #include "PointerException.hpp"
32
33 namespace suPHP {
34     /**
35      * Class template encapsulating pointers.
36      */
37     template<class T>
38     class SmartPtr {
39     private:
40         static std::map<T*, int> counter;
41         T* ptr;
42         
43         void increment(T* key_ptr);
44         void decrement(T* key_ptr);
45         
46     public:
47         /**
48          * Constructor using NULL pointer
49          */
50         SmartPtr();
51         
52         /**
53          * Constructor taking T* as argument
54          */
55         SmartPtr(T* obj_ptr);
56
57         /**
58          * Copy constructor
59          */
60         SmartPtr(const SmartPtr<T>& ref);
61         
62         /**
63          * Destructor
64          */
65         ~SmartPtr();
66         
67         /**
68          * Copy operator
69          */
70         const SmartPtr& operator=(const SmartPtr<T>& ref);
71
72         /**
73          * Dereference operator.
74          * Returns reference to object hold by smart pointer
75          */
76         T& operator*() const throw(PointerException);
77         
78         /**
79          * Member access operator
80          */
81         T* operator->() const throw(PointerException);
82         
83         /**
84          * Returns underlying pointer
85          */
86         T* get() const;
87         
88         /**
89          * Returns underlying pointer and releases it
90          * from management by the SmartPtr.
91          * Throws an exception if underlying pointer is
92          * hold by more than one SmartPtr.
93          */
94         T* release() throw (PointerException);
95         
96         /**
97          * Resets SmartPtr to point to another object
98          */
99         void reset(T* obj_ptr);
100         
101         /**
102          * Compares to pointers.
103          * Returns true, if both point to the same object,
104          * false otherwise
105          */
106         bool operator==(const SmartPtr<T>& ref);
107         
108     };
109
110     template<class T>
111     std::map<T*, int> suPHP::SmartPtr<T>::counter;
112     
113     template<class T>
114     suPHP::SmartPtr<T>::SmartPtr() {
115         this->ptr = NULL;
116     }
117     
118     template<class T>
119     suPHP::SmartPtr<T>::SmartPtr(T* obj_ptr) {
120         this->ptr = obj_ptr;
121         this->increment(obj_ptr);
122     }
123     
124     template<class T>
125     suPHP::SmartPtr<T>::SmartPtr(const SmartPtr<T>& ref) {
126         this->ptr = ref.ptr;
127         if (ref.ptr != NULL)
128             this->increment(ref.ptr);
129     }
130     
131     template<class T>
132     suPHP::SmartPtr<T>::~SmartPtr() {
133         if (this->ptr != NULL)
134             this->decrement(this->ptr);
135     }
136     
137     template<class T>
138     const SmartPtr<T>& suPHP::SmartPtr<T>::operator=(
139         const SmartPtr<T>& ref) {
140         this.reset(ref.ptr);
141         return *this;
142     }
143     
144     template<class T>
145     T& suPHP::SmartPtr<T>::operator*() const throw (PointerException) {
146         if (this->ptr == NULL)
147             throw PointerException("Cannot dereference NULL pointer", 
148                                    __FILE__, __LINE__);
149         return *(this->ptr);
150     }
151     
152     template<class T>
153     T* suPHP::SmartPtr<T>::operator->() const throw (PointerException) {
154         if (this->ptr == NULL)
155             throw PointerException("Cannot access member of NULL pointer", 
156                                    __FILE__, __LINE__);
157         return this->ptr;
158     }
159     
160     template<class T>
161     T* suPHP::SmartPtr<T>::get() const {
162         return this->ptr;
163     }
164     
165     template<class T>
166     T* suPHP::SmartPtr<T>::release() throw (PointerException) {
167         T* obj_ptr = this->ptr;
168         if (obj_ptr == NULL)
169             return NULL;
170
171         int& c = SmartPtr<T>::counter.find(obj_ptr)->second;
172         
173         if (c > 1) {
174             throw PointerException(
175                 "Cannot release object hold by more than one SmartPointer.", 
176                 __FILE__, __LINE__);
177         } else {
178             SmartPtr<T>::counter.erase(obj_ptr);
179         }
180         this->ptr = NULL;
181         return obj_ptr;
182     }
183     
184     template<class T>
185     void suPHP::SmartPtr<T>::reset(T* obj_ptr) {
186         if (obj_ptr != this->ptr) {
187             this->decrement(this->ptr);
188             this->ptr = obj_ptr;
189             this->increment(obj_ptr);
190         }
191     }
192     
193     template<class T>
194     void suPHP::SmartPtr<T>::increment(T* key_ptr) {
195         if (key_ptr == NULL)
196             return;
197
198         if (SmartPtr<T>::counter.find(key_ptr) 
199             != SmartPtr<T>::counter.end()) {
200             (SmartPtr<T>::counter.find(key_ptr)->second)++;
201         } else {
202             std::pair<T*, int> p;
203             p.first = key_ptr;
204             p.second = 1;
205             SmartPtr<T>::counter.insert(p);
206         }
207     }
208
209     template<class T>
210     void suPHP::SmartPtr<T>::decrement(T* key_ptr) {
211         if (key_ptr == NULL)
212             return;
213
214         int& c = SmartPtr<T>::counter.find(key_ptr)->second;
215         c--;
216         if (c < 1) {
217             delete key_ptr;
218             SmartPtr<T>::counter.erase(key_ptr);
219         }
220     }
221     
222     template<class T>
223     bool suPHP::SmartPtr<T>::operator==(const SmartPtr<T>& ref) {
224         if (this->get() == ref.get())
225             return true;
226         else
227             return false;
228     }
229
230 };
231
232 #endif // SUPHP_SMARTPTR_H