1 /*
2  * Copyright 2006-2008 The FLWOR Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 #ifndef ZORBA_RCHANDLE_H
18 #define ZORBA_RCHANDLE_H
19 
20 #include <sstream>
21 #include <errno.h>
22 
23 #include <zorba/config.h>
24 
25 #include "common/common.h"
26 
27 #include "zorbautils/fatal.h"
28 
29 #include "zorbatypes/rclock.h"
30 
31 #include "zorbaserialization/class_serializer.h"
32 
33 
34 namespace zorba
35 {
36 
37 namespace serialization
38 {
39   class archiver;
40 }
41 
42 
43 /*******************************************************************************
44 
45   Base class for reference counted objects
46 
47   Any class wishing to take advantage of automatic reference counting
48   must inherit from this class.
49 
50   rcobject encapsulates the reference count, as well as functions
51   for incrementing and decrementing the count. It also contains code
52   for destroying a value when it is no longer in use, i.e., when its
53   reference count becomes 0.
54 
55 ********************************************************************************/
56 class ZORBA_DLL_PUBLIC RCObject : public serialization::SerializeBaseClass
57 {
58 protected:
59   mutable long  theRefCount;
60 
61 public:
62   SERIALIZABLE_CLASS(RCObject);
63 
RCObject(::zorba::serialization::Archiver & ar)64   RCObject(::zorba::serialization::Archiver& ar)
65     :
66     ::zorba::serialization::SerializeBaseClass(),
67     theRefCount(0)
68   {
69   }
70 
71   void serialize(::zorba::serialization::Archiver& ar);
72 
73 public:
RCObject()74   RCObject()
75     :
76     ::zorba::serialization::SerializeBaseClass(),
77     theRefCount(0)
78   {
79   }
80 
RCObject(const RCObject &)81   RCObject(const RCObject&)
82     :
83     ::zorba::serialization::SerializeBaseClass(),
84     theRefCount(0)
85   {
86   }
87 
~RCObject()88   virtual ~RCObject() { }
89 
90   RCObject& operator=(const RCObject&) { return *this; }
91 
free()92   virtual void free() { delete this; }
93 
getRefCount()94   long getRefCount() const { return theRefCount; }
95 
96   void addReference(SYNC_CODE(RCLock* lock)) const;
97 
98   void removeReference(SYNC_CODE(RCLock* lock));
99 };
100 
101 
102 /*******************************************************************************
103 
104 ********************************************************************************/
105 class ZORBA_DLL_PUBLIC SimpleRCObject : public serialization::SerializeBaseClass
106 {
107 protected:
108   mutable long  theRefCount;
109 
110 public:
111   SERIALIZABLE_CLASS(SimpleRCObject);
112 
SimpleRCObject(serialization::Archiver & ar)113   SimpleRCObject(serialization::Archiver& ar)
114     :
115     serialization::SerializeBaseClass(),
116     theRefCount(0)
117   {
118   }
119 
120   void serialize(serialization::Archiver& ar);
121 
122 public:
SimpleRCObject()123   SimpleRCObject()
124     :
125     serialization::SerializeBaseClass(),
126     theRefCount(0)
127   {
128   }
129 
SimpleRCObject(const SimpleRCObject &)130   SimpleRCObject(const SimpleRCObject&)
131     :
132     serialization::SerializeBaseClass(),
133     theRefCount(0)
134   {
135   }
136 
~SimpleRCObject()137   virtual ~SimpleRCObject() { }
138 
139   SimpleRCObject& operator=(const SimpleRCObject&) { return *this; }
140 
free()141   virtual void free() { delete this; }
142 
getRefCount()143   long getRefCount() const { return theRefCount; }
144 
addReference(SYNC_CODE (RCLock * lock))145   void addReference(SYNC_CODE(RCLock* lock)) const { ++theRefCount; }
146 
removeReference(SYNC_CODE (RCLock * lock))147   void removeReference(SYNC_CODE(RCLock* lock))
148   {
149     if (--theRefCount == 0)
150     {
151       free();
152       return;
153     }
154   }
155 
156   SYNC_CODE(RCLock* getRCLock() const { return NULL; })
157 };
158 
159 
160 /*******************************************************************************
161 
162   rchandle = r(ef)c(ount)handle
163 
164   Template class for smart pointers-to-T objects. T must support the RCObject
165   interface, typically by inheriting from RCObject
166 
167 ********************************************************************************/
168 template<class T> class rchandle
169 {
170 public:
171   typedef T value_type;
172   typedef value_type* pointer;
173   typedef value_type const* const_pointer;
174   typedef value_type& reference;
175   typedef value_type const& const_reference;
176 
177 protected:
178   T  * p;
179 
180 public:
181   union union_T
182   {
183     T** t;
184     void** v;
185   };
186 
187 public:
p(ptr)188   rchandle(T* ptr = 0) : p(ptr)
189   {
190     init();
191   }
192 
rchandle(rchandle const & rhs)193   rchandle(rchandle const& rhs) : p(rhs.getp())
194   {
195     init();
196   }
197 
~rchandle()198   ~rchandle()
199   {
200     if (p)
201       p->removeReference(SYNC_CODE(p->getRCLock()));
202     p = 0;
203   }
204 
isNull()205   bool isNull () const { return p == NULL; }
206 
setNull()207   void setNull() { p = NULL;}
208 
getp()209   T* getp() const { return p; }
210 
getp_ref()211   union_T getp_ref() { union_T u_t; u_t.t = &p; return u_t;}
212 
213   // rchandle const-ness is unclear. The implicit operators are more
214   // restrictive than the explicit cast() and getp() methods.
215   operator T* ()              { return getp(); }
216 
217   operator const T * () const { return getp(); }
218 
219   T* operator->() const       { return p; }
220 
221   T& operator*() const        { return *p; }
222 
223   bool operator!() const      { return !p; }
224 
225   bool operator==(rchandle const& h) const  { return p == h.p; }
226   bool operator!=(rchandle const& h) const  { return p != h.p; }
227   bool operator==(T const* pp) const        { return p == pp; }
228   bool operator!=(T const* pp) const        { return p != pp; }
229   bool operator<(const rchandle& h) const   { return p < h.p; }
230 
231 
cast()232   template <class otherT> rchandle<otherT> cast() const
233   {
234     return rchandle<otherT> (static_cast<otherT *> (p));
235   }
236 
dyn_cast()237   template <class otherT> rchandle<otherT> dyn_cast() const
238   {
239     return rchandle<otherT> (dynamic_cast<otherT *> (p));
240   }
241 
242   template <class otherT> operator rchandle<otherT> ()
243   {
244     return cast<otherT> ();
245   }
246 
247   template <class otherT> operator const rchandle<otherT> () const
248   {
249     return cast<otherT> ();
250   }
251 
252   rchandle& operator=(const T* rhs)
253   {
254     if (p != rhs)
255     {
256       if (p) p->removeReference(SYNC_CODE(p->getRCLock()));
257       p = const_cast<T*>(rhs);
258       init();
259     }
260     return *this;
261   }
262 
263   template <class otherT> rchandle& operator=(const otherT* rhs)
264   {
265     if (p != rhs)
266     {
267       if (p) p->removeReference(SYNC_CODE(p->getRCLock()));
268       p = static_cast<T*>(const_cast<otherT*>(rhs));
269       init();
270     }
271     return *this;
272   }
273 
274   rchandle& operator=(rchandle const& rhs)
275   {
276     return assign (rhs);
277   }
278 
279   template <class otherT> rchandle& operator=(rchandle<otherT> const& rhs)
280   {
281     return assign (rhs);
282   }
283 
transfer(rchandle<otherT> & rhs)284   template <class otherT> rchandle& transfer(rchandle<otherT>& rhs)
285   {
286     if (p != rhs.getp())
287     {
288       if (p) p->removeReference(SYNC_CODE(p->getRCLock()));
289       p = static_cast<T*>(rhs.getp());
290       rhs.setNull();
291     }
292     return *this;
293   }
294 
transfer(rchandle & rhs)295   rchandle& transfer(rchandle& rhs)
296   {
297     if (p != rhs.p)
298     {
299       if (p) p->removeReference(SYNC_CODE(p->getRCLock()));
300       p = rhs.p;
301       rhs.p = NULL;
302     }
303     return *this;
304   }
305 
release()306   T* release()
307   {
308     T* tmp = p;
309     p = NULL;
310     return tmp;
311   }
312 
313 public:
debug()314   std::string debug() const
315   {
316     std::ostringstream oss;
317     oss << "rchandle[refcount=" << p->getRefCount() << ']';
318     return oss.str();
319   }
320 
321 protected:
init()322   void init()
323   {
324     if (p == 0) return;
325     p->addReference(SYNC_CODE(p->getRCLock()));
326   }
327 
328 
assign(const rchandle<otherT> & rhs)329   template <class otherT> rchandle& assign(const rchandle<otherT>& rhs)
330   {
331     if (p != rhs.getp())
332     {
333       if (p) p->removeReference(SYNC_CODE(p->getRCLock()));
334       p = static_cast<T*>(rhs.getp());
335       init();
336     }
337     return *this;
338   }
339 
340 };
341 
342 
343 namespace ztd
344 {
345 
346 template<typename T> inline
to_string(const rchandle<T> & r)347 std::string to_string(const rchandle<T>& r)
348 {
349   return !r ? "<null>" : to_string( *r );
350 }
351 
352 
353 template<typename T,class OutputStringType> inline
to_string(const rchandle<T> & r,OutputStringType * out)354 void to_string(const rchandle<T>& r, OutputStringType* out )
355 {
356   if ( !r )
357     *out = "<null>";
358   else
359     to_string( *r, out );
360 }
361 
362 } // namespace ztd
363 
364 /*******************************************************************************
365 
366 ********************************************************************************/
367 template<class T> class const_rchandle : protected rchandle<T>
368 {
369 public:
370   const_rchandle (const T *_p = 0) : rchandle<T> (const_cast<T *> (_p)) {}
371 
const_rchandle(const const_rchandle & rhs)372   const_rchandle (const const_rchandle &rhs) : rchandle<T> (rhs) {}
373 
const_rchandle(rchandle<T> & rhs)374   const_rchandle (rchandle<T> &rhs) : rchandle<T> (rhs) {}
375 
const_rchandle(::zorba::serialization::Archiver & ar)376   const_rchandle(::zorba::serialization::Archiver &ar) {}
377 
378   const_rchandle& operator= (const const_rchandle &rhs) {
379     this->assign (rhs);
380     return *this;
381   }
382 
383 public:
isNull()384   bool isNull () const { return rchandle<T>::isNull(); }
385 
setNull()386   void setNull() { rchandle<T>::setNull();}
387 
getp()388   const T* getp () const { return rchandle<T>::getp (); }
389 
getp_ref()390   typename rchandle<T>::union_T getp_ref() { return rchandle<T>::getp_ref(); }
391 
392   operator const T * () const { return rchandle<T>::getp (); }
393 
394   const T* operator->() const { return getp(); }
395   const T& operator*() const  { return *getp(); }
396 
397   bool operator== (const_rchandle h) const  { return rchandle<T>::operator== (h); }
398   bool operator!= (const_rchandle h) const  { return rchandle<T>::operator!= (h); }
399   bool operator== (const T * pp) const      { return rchandle<T>::operator== (pp); }
400   bool operator!= (const T * pp) const      { return rchandle<T>::operator!= (pp); }
401   bool operator< (const_rchandle h) const   { return rchandle<T>::operator<  (h); }
402 };
403 
404 
405 
406 /*******************************************************************************
407 
408 ********************************************************************************/
409 namespace RCHelper
410 {
411   template<class T>
addReference(T * t)412   static void addReference(T *t)
413   {
414     t->addReference(SYNC_CODE(t->getRCLock()));
415   }
416 
417   template<class T>
removeReference(T * t)418   static void removeReference(T *t)
419   {
420     t->removeReference(SYNC_CODE(t->getRCLock()));
421   }
422 
423   template<class T>
addReference(rchandle<T> & t)424   static void addReference(rchandle<T> &t)
425   {
426     addReference(t.getp());
427   }
428 
429   template<class T>
removeReference(rchandle<T> & t)430   static void removeReference(rchandle<T> &t)
431   {
432     removeReference(t.getp());
433   }
434 };
435 
436 } // namespace zorba
437 
438 #endif
439 /*
440  * Local variables:
441  * mode: c++
442  * End:
443  */
444 /* vim:set et sw=2 ts=2: */
445