0.6.1.20060928-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         if (SmartPtr<T>::counter == NULL) {
116             SmartPtr<T>::counter = new std::map<T*, int>;
117         }
118         this->ptr = NULL;
119     }
120     
121     template<class T>
122     suPHP::SmartPtr<T>::SmartPtr(T* obj_ptr) {
123         if (SmartPtr<T>::counter == NULL) {
124             SmartPtr<T>::counter = new std::map<T*, int>;
125         }
126         this->ptr = obj_ptr;
127         this->increment(obj_ptr);
128     }
129     
130     template<class T>
131     suPHP::SmartPtr<T>::SmartPtr(const SmartPtr<T>& ref) {
132         if (SmartPtr<T>::counter == NULL) {
133             SmartPtr<T>::counter = new std::map<T*, int>;
134         }
135         this->ptr = ref.ptr;
136         if (ref.ptr != NULL)
137             this->increment(ref.ptr);
138     }
139     
140     template<class T>
141     suPHP::SmartPtr<T>::~SmartPtr() {
142         if (this->ptr != NULL)
143             this->decrement(this->ptr);
144         if (SmartPtr<T>::counter != NULL && SmartPtr<T>::counter->size() == 0) {
145             delete SmartPtr<T>::counter;
146             SmartPtr<T>::counter = NULL;
147         }
148     }
149     
150     template<class T>
151     const SmartPtr<T>& suPHP::SmartPtr<T>::operator=(
152         const SmartPtr<T>& ref) {
153         this.reset(ref.ptr);
154         return *this;
155     }
156     
157     template<class T>
158     T& suPHP::SmartPtr<T>::operator*() const throw (PointerException) {
159         if (this->ptr == NULL)
160             throw PointerException("Cannot dereference NULL pointer", 
161                                    __FILE__, __LINE__);
162         return *(this->ptr);
163     }
164     
165     template<class T>
166     T* suPHP::SmartPtr<T>::operator->() const throw (PointerException) {
167         if (this->ptr == NULL)
168             throw PointerException("Cannot access member of NULL pointer", 
169                                    __FILE__, __LINE__);
170         return this->ptr;
171     }
172     
173     template<class T>
174     T* suPHP::SmartPtr<T>::get() const {
175         return this->ptr;
176     }
177     
178     template<class T>
179     T* suPHP::SmartPtr<T>::release() throw (PointerException) {
180         T* obj_ptr = this->ptr;
181         if (obj_ptr == NULL)
182             return NULL;
183
184         int& c = SmartPtr<T>::counter->find(obj_ptr)->second;
185         
186         if (c > 1) {
187             throw PointerException(
188                 "Cannot release object hold by more than one SmartPointer.", 
189                 __FILE__, __LINE__);
190         } else {
191             SmartPtr<T>::counter->erase(obj_ptr);
192         }
193         this->ptr = NULL;
194         return obj_ptr;
195     }
196     
197     template<class T>
198     void suPHP::SmartPtr<T>::reset(T* obj_ptr) {
199         if (obj_ptr != this->ptr) {
200             this->decrement(this->ptr);
201             this->ptr = obj_ptr;
202             this->increment(obj_ptr);
203         }
204     }
205     
206     template<class T>
207     void suPHP::SmartPtr<T>::increment(T* key_ptr) {
208         if (key_ptr == NULL)
209             return;
210
211         if (SmartPtr<T>::counter->find(key_ptr) 
212             != SmartPtr<T>::counter->end()) {
213             (SmartPtr<T>::counter->find(key_ptr)->second)++;
214         } else {
215             std::pair<T*, int> p;
216             p.first = key_ptr;
217             p.second = 1;
218             SmartPtr<T>::counter->insert(p);
219         }
220     }
221
222     template<class T>
223     void suPHP::SmartPtr<T>::decrement(T* key_ptr) {
224         if (key_ptr == NULL)
225             return;
226
227         int& c = SmartPtr<T>::counter->find(key_ptr)->second;
228         c--;
229         if (c < 1) {
230             delete key_ptr;
231             SmartPtr<T>::counter->erase(key_ptr);
232         }
233     }
234     
235     template<class T>
236     bool suPHP::SmartPtr<T>::operator==(const SmartPtr<T>& ref) {
237         if (this->get() == ref.get())
238             return true;
239         else
240             return false;
241     }
242
243 };
244
245 #endif // SUPHP_SMARTPTR_H