1 // Copyright (c) 2012-2014 Konstantin Isakov <ikm@zbackup.org> and ZBackup contributors, see CONTRIBUTORS
2 // Part of ZBackup. Licensed under GNU GPLv2 or later + OpenSSL, see LICENSE
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( nullptr ), count( nullptr ) {}
29 
sptr_base(T * p_)30   sptr_base( T * p_ ): p( p_ ), count( p ? new unsigned( 1 ) : nullptr )
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 = nullptr;
52 
53         if ( p )
54         {
55           T * p_ = p;
56 
57           p = nullptr;
58 
59           delete p_;
60         }
61       }
62       else
63       {
64         p = nullptr;
65         count = nullptr;
66       }
67     }
68   }
69 
use_count() const70   unsigned use_count() const
71   { return *count; }
72 
operator =(sptr_base const & other)73   sptr_base & operator = ( sptr_base const & other )
74   { if ( &other != this ) { reset(); p = other.p; count = other.count; increment(); }
75     return * this; }
76 
operator bool(void) const77   operator bool( void ) const
78   { return !!p; }
79 
operator !(void) const80   bool operator ! ( void ) const
81   { return !p; }
82 
operator ==(sptr_base const & other) const83   bool operator == ( sptr_base const & other ) const
84   { return p == other.p; }
85 
operator !=(sptr_base const & other) const86   bool operator != ( sptr_base const & other ) const
87   { return p != other.p; }
88 
~sptr_base()89   ~sptr_base()
90   { reset(); }
91 
92 protected:
93 
get_base(void) const94   T * get_base( void ) const
95   { return p; }
96 };
97 
98 template< class T >
99 class sptr: public sptr_base< T >
100 {
101 public:
102 
sptr()103   sptr() {}
104 
sptr(T * p)105   sptr( T * p ): sptr_base< T >( p ) {}
106 
107   // TT is meant to be a derivative of T
108   template< class TT >
sptr(sptr<TT> const & other)109   sptr( sptr< TT > const & other ): sptr_base< T >( other ) {}
110 
111   // Retrieval
112 
get(void) const113   T * get( void ) const
114     { return sptr_base< T > :: get_base(); }
115 
operator ->(void) const116   T * operator -> ( void ) const
117     { return get(); }
118 
operator *(void) const119   T & operator * ( void ) const
120     { return * get(); }
121 
122   // Check
123 
operator bool(void) const124   operator bool( void ) const
125     { return get();  }
126 
operator !(void) const127   bool operator ! ( void ) const
128     { return !get(); }
129 };
130 
131 template< class T >
132 class const_sptr: public sptr_base< T >
133 {
134 public:
135 
const_sptr()136   const_sptr() {}
137 
const_sptr(T * p_)138   const_sptr( T * p_ ): sptr_base< T >( p_ ) {}
139 
const_sptr(sptr<T> const & other)140   const_sptr( sptr< T > const & other ): sptr_base< T >( other ) {}
141 
142   // TT is meant to be a derivative of T
143   template< class TT >
const_sptr(sptr_base<TT> const & other)144   const_sptr( sptr_base< TT > const & other ): sptr_base< T >( other ) {}
145 
146   // Retrieval
147 
get(void) const148   T const * get( void ) const
149     { return sptr_base< T > :: get_base(); }
150 
operator ->(void) const151   T const * operator -> ( void ) const
152     { return get(); }
153 
operator *(void) const154   T const & operator * ( void ) const
155     { return * get(); }
156 };
157 
158 
159 #endif
160