1 /* This file is (c) 2008-2012 Konstantin Isakov <ikm@goldendict.org>
2  * Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
3 
4 #ifndef __SPTR_HH_INCLUDED__
5 #define __SPTR_HH_INCLUDED__
6 
7 // A generic non-intrusive smart-pointer template. We could use boost::, tr1::
8 // or whatever, but since there's no standard solution yet, it isn't worth
9 // the dependency given the simplicity of the template.
10 
11 template< class T >
12 class sptr_base
13 {
14   template< class TT > friend class sptr_base;
15 
16   T * p;
17   unsigned * count;
18 
19 
increment()20   void increment()
21   {
22     if ( count )
23       ++*count;
24   }
25 
26 public:
27 
sptr_base()28   sptr_base(): p( 0 ), count( 0 ) {}
29 
sptr_base(T * p_)30   sptr_base( T * p_ ): p( p_ ), count( p ? new unsigned( 1 ) : 0 )
31   {
32   }
33 
sptr_base(sptr_base<T> const & other)34   sptr_base( sptr_base< T > const & other ): p( other.p ), count( other.count )
35   { increment(); }
36 
37   // TT is meant to be a derivative of T
38   template< class TT >
sptr_base(sptr_base<TT> const & other)39   sptr_base( sptr_base< TT > const & other ): p( ( T * ) other.p ),
40     count( other.count )
41   { increment(); }
42 
reset()43   void reset()
44   {
45     if ( count )
46     {
47       if ( ! -- *count )
48       {
49         delete count;
50 
51         count = 0;
52 
53         if ( p )
54         {
55           T * p_ = p;
56 
57           p = 0;
58 
59           delete p_;
60         }
61       }
62       else
63       {
64         p = 0;
65         count = 0;
66       }
67     }
68   }
69 
operator =(sptr_base const & other)70   sptr_base & operator = ( sptr_base const & other )
71   { if ( &other != this ) { reset(); p = other.p; count = other.count; increment(); }
72     return * this; }
73 
operator !(void) const74   bool operator ! ( void ) const
75   { return !p; }
76 
operator ==(sptr_base const & other) const77   bool operator == ( sptr_base const & other ) const
78   { return p == other.p; }
79 
operator !=(sptr_base const & other) const80   bool operator != ( sptr_base const & other ) const
81   { return p != other.p; }
82 
~sptr_base()83   ~sptr_base()
84   { reset(); }
85 
86 protected:
87 
get_base(void) const88   T * get_base( void ) const
89   { return p; }
90 };
91 
92 template< class T >
93 class sptr: public sptr_base< T >
94 {
95 public:
96 
sptr()97   sptr() {}
98 
sptr(T * p)99   sptr( T * p ): sptr_base< T >( p ) {}
100 
101   // TT is meant to be a derivative of T
102   template< class TT >
sptr(sptr<TT> const & other)103   sptr( sptr< TT > const & other ): sptr_base< T >( other ) {}
104 
105   // Retrieval
106 
get(void) const107   T * get( void ) const
108     { return sptr_base< T > :: get_base(); }
109 
operator ->(void) const110   T * operator -> ( void ) const
111     { return get(); }
112 
operator *(void) const113   T & operator * ( void ) const
114     { return * get(); }
115 
116   // Check
117 
operator bool(void) const118   operator bool( void ) const
119     { return get();  }
120 
operator !(void) const121   bool operator ! ( void ) const
122     { return !get(); }
123 };
124 
125 template< class T >
126 class const_sptr: public sptr_base< T >
127 {
128 public:
129 
const_sptr()130   const_sptr() {}
131 
const_sptr(T * p_)132   const_sptr( T * p_ ): sptr_base< T >( p_ ) {}
133 
const_sptr(sptr<T> const & other)134   const_sptr( sptr< T > const & other ): sptr_base< T >( other ) {}
135 
136   // TT is meant to be a derivative of T
137   template< class TT >
const_sptr(sptr_base<TT> const & other)138   const_sptr( sptr_base< TT > const & other ): sptr_base< T >( other ) {}
139 
140   // Retrieval
141 
get(void) const142   T const * get( void ) const
143     { return sptr_base< T > :: get_base(); }
144 
operator ->(void) const145   T const * operator -> ( void ) const
146     { return get(); }
147 
operator *(void) const148   T const & operator * ( void ) const
149     { return * get(); }
150 };
151 
152 
153 #endif
154 
155