- Use swap instead of reset in RW_pointer.
[platform/upstream/libzypp.git] / zypp / base / PtrTypes.h
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/base/PtrTypes.h
10  *  \ingroup ZYPP_SMART_PTR
11  *  \see ZYPP_SMART_PTR
12 */
13 #ifndef ZYPP_BASE_PTRTYPES_H
14 #define ZYPP_BASE_PTRTYPES_H
15
16 #include <string>
17
18 #include <boost/scoped_ptr.hpp>
19 #include <boost/shared_ptr.hpp>
20 #include <boost/weak_ptr.hpp>
21 #include <boost/intrusive_ptr.hpp>
22
23 ///////////////////////////////////////////////////////////////////
24 namespace zypp
25 { /////////////////////////////////////////////////////////////////
26
27     /** \defgroup ZYPP_SMART_PTR Smart pointer types
28      *  Smart pointer types.
29      *
30      * Namespace zypp provides 3 smart pointer types \b using the
31      * boost smart pointer library.
32      *
33      * \li \c scoped_ptr Simple sole ownership of single objects. Noncopyable.
34      *
35      * \li \c shared_ptr Object ownership shared among multiple pointers
36      *
37      * \li \c weak_ptr Non-owning observers of an object owned by shared_ptr.
38      *
39      * And \ref zypp::RW_pointer, as wrapper around a smart pointer,
40      * poviding \c const correct read/write access to the object it refers.
41     */
42     /*@{*/
43
44     /** \class scoped_ptr scoped_ptr */
45     using boost::scoped_ptr;
46
47     /** \class shared_ptr */
48     using boost::shared_ptr;
49
50     /** \class weak_ptr */
51     using boost::weak_ptr;
52
53     /** \class intrusive_ptr */
54     using boost::intrusive_ptr;
55
56     /**  */
57     using boost::static_pointer_cast;
58     /**  */
59     using boost::const_pointer_cast;
60     /**  */
61     using boost::dynamic_pointer_cast;
62
63     ///////////////////////////////////////////////////////////////////
64     //
65     //  RW_pointer traits
66     //
67     ///////////////////////////////////////////////////////////////////
68     /**
69      * Don't forgett to provide versions for _Ptr and _constPtr,
70      * esp. if creation a of temporary is not acceptable (eg. when
71      * checking the ref count value).
72     */
73     namespace rw_pointer {
74
75       template<class _D>
76         struct Shared
77         {
78           typedef shared_ptr<_D>       _Ptr;
79           typedef shared_ptr<const _D> _constPtr;
80           /** Check whether pointer is not shared. */
81           bool unique( const _constPtr & ptr_r )
82           { return ptr_r.unique(); }
83           bool unique( const _Ptr & ptr_r )
84           { return ptr_r.unique(); }
85           /** Return number of references. */
86           long use_count( const _constPtr & ptr_r ) const
87           { return ptr_r.use_count(); }
88           long use_count( const _Ptr & ptr_r ) const
89           { return ptr_r.use_count(); }
90         };
91
92       template<class _D>
93         struct Intrusive
94         {
95           typedef intrusive_ptr<_D>       _Ptr;
96           typedef intrusive_ptr<const _D> _constPtr;
97           /** Check whether pointer is not shared. */
98           bool unique( const _constPtr & ptr_r )
99           { return !ptr_r || (ptr_r->refCount() <= 1); }
100           bool unique( const _Ptr & ptr_r )
101           { return !ptr_r || (ptr_r->refCount() <= 1); }
102           /** Return number of references. */
103           long use_count( const _constPtr & ptr_r ) const
104           { return ptr_r ? ptr_r->refCount() : 0; }
105           long use_count( const _Ptr & ptr_r ) const
106           { return ptr_r ? ptr_r->refCount() : 0; }
107         };
108     }
109     ///////////////////////////////////////////////////////////////////
110
111     ///////////////////////////////////////////////////////////////////
112     //
113     //  CLASS NAME : RW_pointer
114     //
115     /** Wrapper for \c const correct access via \ref ZYPP_SMART_PTR.
116      *
117      * zypp::RW_pointer<tt>\<_D,_Traits></tt> stores a \ref ZYPP_SMART_PTR
118      * of type \c _Traits::_Ptr, which must be convertible into a <tt>_D *</tt>.
119      * Pointer style access (via \c -> and \c *) offers a <tt>const _D *</tt> in const
120      * a context, otherwise a <tt>_D *</tt>. Thus \em RW_ means \em read/write,
121      * as you get a different type, dependent on whether you're allowed to
122      * read or write.
123      *
124      * Forwarding access from an interface to an implemantation class, an
125      * RW_pointer prevents const interface methods from accidentally calling
126      * nonconst implementation methods.
127      *
128      * The second template argument defaults to
129      * <tt>_Traits = rw_pointer::Shared<_D></tt> thus wraping a
130      * <tt>shared_ptr<_D></tt>. To wrap an <tt>intrusive_ptr<_D></tt>
131      * use <tt>rw_pointer::Intrusive<_D></tt>.
132      *
133      * \see zypp::RWCOW_pointer for 'copy on write' functionality.
134      *
135      * \code
136      * #include "zypp/base/PtrTypes.h"
137      *
138      * class Foo
139      * {
140      *   ...
141      *   private:
142      *     // Implementation class
143      *     struct Impl;
144      *     // Pointer to implementation; actually a shared_ptr<Impl>
145      *     RW_pointer<Impl> _pimpl;
146      *
147      *     void baa()       { _pimpl->... } // is Impl *
148      *     void baa() const { _pimpl->... } // is Impl const *
149      * };
150      * \endcode
151     */
152     template<class _D, class _Traits = rw_pointer::Shared<_D> >
153       struct RW_pointer
154       {
155         typedef typename _Traits::_Ptr               _Ptr;
156         typedef typename _Traits::_constPtr          _constPtr;
157         typedef typename _Ptr::unspecified_bool_type unspecified_bool_type;
158
159         explicit
160         RW_pointer( typename _Ptr::element_type * dptr = 0 )
161         : _dptr( dptr )
162         {}
163
164         explicit
165         RW_pointer( _Ptr dptr )
166         : _dptr( dptr )
167         {}
168
169         void reset()
170         { _Ptr().swap( _dptr ); }
171
172         void reset( typename _Ptr::element_type * dptr )
173         { _Ptr( dptr ).swap( _dptr ); }
174
175         void swap( RW_pointer & rhs )
176         { _dptr.swap( rhs._dptr ); }
177
178         void swap( _Ptr & rhs )
179         { _dptr.swap( rhs ); }
180
181         operator unspecified_bool_type() const
182         { return _dptr; }
183
184         const _D & operator*() const
185         { return *_dptr; };
186
187         const _D * operator->() const
188         { return _dptr.get(); }
189
190         const _D * get() const
191         { return _dptr.get(); }
192
193         _D & operator*()
194         { return *_dptr; }
195
196         _D * operator->()
197         { return _dptr.get(); }
198
199         _D * get()
200         { return _dptr.get(); }
201
202       public:
203         bool unique() const
204         { return _Traits().unique( _dptr ); }
205
206         long use_count() const
207         { return _Traits().use_count( _dptr ); }
208
209         _constPtr getPtr() const
210         { return _dptr; }
211
212         _Ptr getPtr()
213         { return _dptr; }
214
215       private:
216         _Ptr _dptr;
217       };
218     ///////////////////////////////////////////////////////////////////
219
220     /** \relates RW_pointer Stream output.
221      *
222      * Print the \c _D object the RW_pointer refers, or \c "NULL"
223      * if the pointer is \c NULL.
224     */
225     template<class _D, class _Ptr>
226       inline std::ostream &
227       operator<<( std::ostream & str, const RW_pointer<_D, _Ptr> & obj )
228       {
229         if ( obj.get() )
230           return str << *obj.get();
231         return str << std::string("NULL");
232       }
233
234     ///////////////////////////////////////////////////////////////////
235
236     ///////////////////////////////////////////////////////////////////
237     //
238     //  CLASS NAME : RWCOW_pointer
239     //
240     /** \ref RW_pointer supporting 'copy on write' functionality.
241      *
242      * \em Write access to the underlying object creates a copy, iff
243      * the object is shared.
244      *
245      * See \ref RW_pointer.
246     */
247     template<class _D, class _Traits = rw_pointer::Shared<_D> >
248       struct RWCOW_pointer
249       {
250         typedef typename _Traits::_Ptr               _Ptr;
251         typedef typename _Traits::_constPtr          _constPtr;
252         typedef typename _Ptr::unspecified_bool_type unspecified_bool_type;
253
254         explicit
255         RWCOW_pointer( typename _Ptr::element_type * dptr = 0 )
256         : _dptr( dptr )
257         {}
258
259         explicit
260         RWCOW_pointer( _Ptr dptr )
261         : _dptr( dptr )
262         {}
263
264         void reset()
265         { _Ptr().swap( _dptr ); }
266
267         void reset( typename _Ptr::element_type * dptr )
268         { _Ptr( dptr ).swap( _dptr ); }
269
270         void swap( RWCOW_pointer & rhs )
271         { _dptr.swap( rhs._dptr ); }
272
273         void swap( _Ptr & rhs )
274         { _dptr.swap( rhs ); }
275
276         operator unspecified_bool_type() const
277         { return _dptr; }
278
279         const _D & operator*() const
280         { return *_dptr; };
281
282         const _D * operator->() const
283         { return _dptr.get(); }
284
285         const _D * get() const
286         { return _dptr.get(); }
287
288         _D & operator*()
289         { assertUnshared(); return *_dptr; }
290
291         _D * operator->()
292         { assertUnshared(); return _dptr.get(); }
293
294         _D * get()
295         { assertUnshared(); return _dptr.get(); }
296
297       public:
298         bool unique() const
299         { return _Traits().unique( _dptr ); }
300
301         long use_count() const
302         { return _Traits().use_count( _dptr ); }
303
304         _constPtr getPtr() const
305         { return _dptr; }
306
307         _Ptr getPtr()
308         { assertUnshared(); return _dptr; }
309
310       private:
311
312         void assertUnshared()
313         {
314           if ( !unique() )
315             _Ptr( rwcowClone( _dptr.get() ) ).swap( _dptr );
316         }
317
318       private:
319         _Ptr _dptr;
320       };
321     ///////////////////////////////////////////////////////////////////
322
323     /** \relates RWCOW_pointer Clone the underlying object.
324      * Calls \a rhs <tt>-\>clone()</tt>. Being defined as a
325      * function outside \ref RWCOW_pointer allows to overload
326      * it, in case a specific \a _D does not have <tt>clone()</tt>.
327     */
328     template<class _D>
329       inline _D * rwcowClone( const _D * rhs )
330       { return rhs->clone(); }
331
332     ///////////////////////////////////////////////////////////////////
333
334     /** \relates RWCOW_pointer Stream output.
335      *
336      * Print the \c _D object the RWCOW_pointer refers, or \c "NULL"
337      * if the pointer is \c NULL.
338     */
339     template<class _D, class _Ptr>
340       inline std::ostream &
341       operator<<( std::ostream & str, const RWCOW_pointer<_D, _Ptr> & obj )
342       {
343         if ( obj.get() )
344           return str << *obj.get();
345         return str << std::string("NULL");
346       }
347
348     ///////////////////////////////////////////////////////////////////
349
350     /*@}*/
351
352   /////////////////////////////////////////////////////////////////
353 } // namespace zypp
354 ///////////////////////////////////////////////////////////////////
355
356 /** Forward declaration of Ptr types */
357 #define DEFINE_PTR_TYPE(NAME) \
358 class NAME;                                                      \
359 extern void intrusive_ptr_add_ref( const NAME * );               \
360 extern void intrusive_ptr_release( const NAME * );               \
361 typedef zypp::intrusive_ptr<NAME>       NAME##_Ptr;        \
362 typedef zypp::intrusive_ptr<const NAME> NAME##_constPtr;
363
364 ///////////////////////////////////////////////////////////////////
365 #endif // ZYPP_BASE_PTRTYPES_H