Imported Upstream version 16.3.2
[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 <iosfwd>
17 #include <string>
18
19 #include <boost/scoped_ptr.hpp>
20 #include <boost/shared_ptr.hpp>
21 #include <boost/weak_ptr.hpp>
22 #include <boost/intrusive_ptr.hpp>
23
24 ///////////////////////////////////////////////////////////////////
25 namespace zypp
26 { /////////////////////////////////////////////////////////////////
27
28   namespace str
29   {
30     // printing void* (prevents us from including <ostream>)
31     std::string form( const char * format, ... ) __attribute__ ((format (printf, 1, 2)));
32   }
33
34     /** \defgroup ZYPP_SMART_PTR Smart pointer types
35      *  Smart pointer types.
36      *
37      * Namespace zypp provides 3 smart pointer types \b using the
38      * boost smart pointer library.
39      *
40      * \li \c scoped_ptr Simple sole ownership of single objects. Noncopyable.
41      *
42      * \li \c shared_ptr Object ownership shared among multiple pointers
43      *
44      * \li \c weak_ptr Non-owning observers of an object owned by shared_ptr.
45      *
46      * And \ref zypp::RW_pointer, as wrapper around a smart pointer,
47      * poviding \c const correct read/write access to the object it refers.
48     */
49     /*@{*/
50
51     /** shared_ptr custom deleter doing nothing.
52      * A custom deleter is a function being called when the
53      * last shared_ptr goes out of score. Per default the
54      * object gets deleted, but you can insall custom deleters
55      * as well. This one does nothing.
56      *
57      * \code
58      *  // Some class providing a std::istream
59      *  struct InpuStream
60      * {
61      *   // Per deafult use std::cin.
62      *   InputStream()
63      *   : _stream( &std::cin, NullDeleter() )
64      *   {}
65      *   // Or read from a file.
66      *   InputStream( const Pathname & file_r )
67      *   : _stream( new ifgzstream( _path.asString().c_str() ) )
68      *   {}
69      *   // Or use a stream priovided by the application.
70      *   InputStream( std::istream & stream_r )
71      *   : _stream( &stream_r, NullDeleter() )
72      *   {}
73      *
74      *   std::istream & stream()
75      *   { return *_stream; }
76      *
77      * private:
78      *   shared_ptr<std::istream> _stream;
79      * };
80      * \endcode
81     */
82     struct NullDeleter
83     {
84       void operator()( const void *const ) const
85       {}
86     };
87
88     /** \class scoped_ptr */
89     using boost::scoped_ptr;
90
91     /** \class shared_ptr */
92     using boost::shared_ptr;
93
94     /** \class weak_ptr */
95     using boost::weak_ptr;
96
97     /** \class intrusive_ptr */
98     using boost::intrusive_ptr;
99
100     /** */
101     using boost::static_pointer_cast;
102     /**  */
103     using boost::const_pointer_cast;
104     /**  */
105     using boost::dynamic_pointer_cast;
106
107   /////////////////////////////////////////////////////////////////
108 } // namespace zypp
109 ///////////////////////////////////////////////////////////////////
110 ///////////////////////////////////////////////////////////////////
111 namespace std
112 { /////////////////////////////////////////////////////////////////
113
114   // namespace sub {
115   //    class Foo;
116   //    typedef zypp::intrusive_ptr<Foo> Foo_Ptr; // see DEFINE_PTR_TYPE(NAME) macro below
117   // }
118
119   // Defined in namespace std g++ finds the output operator (König-Lookup),
120   // even if we typedef the pointer in a different namespace than ::zypp.
121   // Otherwise we had to define an output operator always in the same namespace
122   // as the typedef (else g++ will just print the pointer value).
123
124   /** \relates zypp::shared_ptr Stream output. */
125   template<class D>
126   inline std::ostream & operator<<( std::ostream & str, const zypp::shared_ptr<D> & obj )
127   {
128     if ( obj )
129       return str << *obj;
130     return str << std::string("NULL");
131   }
132   /** \overload specialize for void */
133   template<>
134   inline std::ostream & operator<<( std::ostream & str, const zypp::shared_ptr<void> & obj )
135   {
136     if ( obj )
137       return str << zypp::str::form( "%p", (void*)obj.get() );
138     return str << std::string("NULL");
139   }
140
141   /** \relates zypp::shared_ptr Stream output. */
142   template<class D>
143   inline std::ostream & dumpOn( std::ostream & str, const zypp::shared_ptr<D> & obj )
144   {
145     if ( obj )
146       return dumpOn( str, *obj );
147     return str << std::string("NULL");
148   }
149   /** \overload specialize for void */
150   template<>
151   inline std::ostream & dumpOn( std::ostream & str, const zypp::shared_ptr<void> & obj )
152   { return str << obj; }
153
154   /** \relates zypp::intrusive_ptr Stream output. */
155   template<class D>
156   inline std::ostream & operator<<( std::ostream & str, const zypp::intrusive_ptr<D> & obj )
157   {
158     if ( obj )
159       return str << *obj;
160     return str << std::string("NULL");
161   }
162   /** \relates zypp::intrusive_ptr Stream output. */
163   template<class D>
164   inline std::ostream & dumpOn( std::ostream & str, const zypp::intrusive_ptr<D> & obj )
165   {
166     if ( obj )
167       return dumpOn( str, *obj );
168     return str << std::string("NULL");
169   }
170   /////////////////////////////////////////////////////////////////
171 } // namespace std
172 ///////////////////////////////////////////////////////////////////
173 ///////////////////////////////////////////////////////////////////
174 namespace zypp
175 { /////////////////////////////////////////////////////////////////
176
177     ///////////////////////////////////////////////////////////////////
178     //
179     //  RW_pointer traits
180     //
181     ///////////////////////////////////////////////////////////////////
182     /**
183      * Don't forgett to provide versions for PtrType and constPtrType,
184      * esp. if creation a of temporary is not acceptable (eg. when
185      * checking the ref count value).
186     */
187     namespace rw_pointer {
188
189       template<class D>
190         struct Shared
191         {
192           typedef shared_ptr<D>       PtrType;
193           typedef shared_ptr<const D> constPtrType;
194           /** Check whether pointer is not shared. */
195           bool unique( const constPtrType & ptr_r )
196           { return !ptr_r || ptr_r.unique(); }
197           bool unique( const PtrType & ptr_r )
198           { return !ptr_r || ptr_r.unique(); }
199           /** Return number of references. */
200           long use_count( const constPtrType & ptr_r ) const
201           { return ptr_r.use_count(); }
202           long use_count( const PtrType & ptr_r ) const
203           { return ptr_r.use_count(); }
204         };
205
206       template<class D>
207         struct Intrusive
208         {
209           typedef intrusive_ptr<D>       PtrType;
210           typedef intrusive_ptr<const D> constPtrType;
211           /** Check whether pointer is not shared. */
212           bool unique( const constPtrType & ptr_r )
213           { return !ptr_r || (ptr_r->refCount() <= 1); }
214           bool unique( const PtrType & ptr_r )
215           { return !ptr_r || (ptr_r->refCount() <= 1); }
216           /** Return number of references. */
217           long use_count( const constPtrType & ptr_r ) const
218           { return ptr_r ? ptr_r->refCount() : 0; }
219           long use_count( const PtrType & ptr_r ) const
220           { return ptr_r ? ptr_r->refCount() : 0; }
221         };
222
223        template<class D>
224         struct Scoped
225         {
226           typedef scoped_ptr<D>       PtrType;
227           typedef scoped_ptr<const D> constPtrType;
228           /** Check whether pointer is not shared. */
229           bool unique( const constPtrType & ptr_r )
230           { return true; }
231           bool unique( const PtrType & ptr_r )
232           { return true; }
233           /** Return number of references. */
234           long use_count( const constPtrType & ptr_r ) const
235           { return ptr_r ? 1 : 0; }
236           long use_count( const PtrType & ptr_r ) const
237           { return ptr_r ? 1 : 0; }
238         };
239
240    }
241     ///////////////////////////////////////////////////////////////////
242
243     ///////////////////////////////////////////////////////////////////
244     //
245     //  CLASS NAME : RW_pointer
246     //
247     /** Wrapper for \c const correct access via \ref ZYPP_SMART_PTR.
248      *
249      * zypp::RW_pointer<tt>\<D,DTraits></tt> stores a \ref ZYPP_SMART_PTR
250      * of type \c DTraits::PtrType, which must be convertible into a <tt>D *</tt>.
251      * Pointer style access (via \c -> and \c *) offers a <tt>const D *</tt> in const
252      * a context, otherwise a <tt>D *</tt>. Thus \em RW_ means \em read/write,
253      * as you get a different type, dependent on whether you're allowed to
254      * read or write.
255      *
256      * Forwarding access from an interface to an implemantation class, an
257      * RW_pointer prevents const interface methods from accidentally calling
258      * nonconst implementation methods.
259      *
260      * The second template argument defaults to
261      * <tt>DTraits = rw_pointer::Shared<D></tt> thus wraping a
262      * <tt>shared_ptr<D></tt>. To wrap an <tt>intrusive_ptr<D></tt>
263      * use <tt>rw_pointer::Intrusive<D></tt>.
264      *
265      * \see zypp::RWCOW_pointer for 'copy on write' functionality.
266      *
267      * \code
268      * #include "zypp/base/PtrTypes.h"
269      *
270      * class Foo
271      * {
272      *   ...
273      *   private:
274      *     // Implementation class
275      *     struct Impl;
276      *     // Pointer to implementation; actually a shared_ptr<Impl>
277      *     RW_pointer<Impl> _pimpl;
278      *
279      *     void baa()       { _pimpl->... } // is Impl *
280      *     void baa() const { _pimpl->... } // is Impl const *
281      * };
282      * \endcode
283     */
284     template<class D, class DTraits = rw_pointer::Shared<D> >
285       struct RW_pointer
286       {
287         typedef typename DTraits::PtrType               PtrType;
288         typedef typename DTraits::constPtrType          constPtrType;
289
290         RW_pointer()
291         {}
292
293         RW_pointer( std::nullptr_t )
294         {}
295
296         explicit
297         RW_pointer( typename PtrType::element_type * dptr )
298         : _dptr( dptr )
299         {}
300
301         explicit
302         RW_pointer( PtrType dptr )
303         : _dptr( dptr )
304         {}
305
306         RW_pointer & operator=( std::nullptr_t )
307         { reset(); return *this; }
308
309         void reset()
310         { PtrType().swap( _dptr ); }
311
312         void reset( typename PtrType::element_type * dptr )
313         { PtrType( dptr ).swap( _dptr ); }
314
315         void swap( RW_pointer & rhs )
316         { _dptr.swap( rhs._dptr ); }
317
318         void swap( PtrType & rhs )
319         { _dptr.swap( rhs ); }
320
321         explicit operator bool() const
322         { return _dptr.get() != nullptr; }
323
324         const D & operator*() const
325         { return *_dptr; };
326
327         const D * operator->() const
328         { return _dptr.operator->(); }
329
330         const D * get() const
331         { return _dptr.get(); }
332
333         D & operator*()
334         { return *_dptr; }
335
336         D * operator->()
337         { return _dptr.operator->(); }
338
339         D * get()
340         { return _dptr.get(); }
341
342       public:
343         bool unique() const
344         { return DTraits().unique( _dptr ); }
345
346         long use_count() const
347         { return DTraits().use_count( _dptr ); }
348
349         constPtrType getPtr() const
350         { return _dptr; }
351
352         PtrType getPtr()
353         { return _dptr; }
354
355         constPtrType cgetPtr()
356         { return _dptr; }
357
358       private:
359         PtrType _dptr;
360       };
361     ///////////////////////////////////////////////////////////////////
362
363     /** \relates RW_pointer Stream output.
364      *
365      * Print the \c D object the RW_pointer refers, or \c "NULL"
366      * if the pointer is \c NULL.
367      */
368     template<class D, class DPtr>
369       inline std::ostream & operator<<( std::ostream & str, const RW_pointer<D, DPtr> & obj )
370       {
371         if ( obj.get() )
372           return str << *obj.get();
373         return str << std::string("NULL");
374       }
375
376     /** \relates RW_pointer */
377     template<class D, class DPtr>
378       inline bool operator==( const RW_pointer<D, DPtr> & lhs, const RW_pointer<D, DPtr> & rhs )
379       { return( lhs.get() == rhs.get() ); }
380     /** \relates RW_pointer */
381     template<class D, class DPtr>
382       inline bool operator==( const RW_pointer<D, DPtr> & lhs, const typename DPtr::PtrType & rhs )
383       { return( lhs.get() == rhs.get() ); }
384     /** \relates RW_pointer */
385     template<class D, class DPtr>
386       inline bool operator==( const typename DPtr::PtrType & lhs, const RW_pointer<D, DPtr> & rhs )
387       { return( lhs.get() == rhs.get() ); }
388     /** \relates RW_pointer */
389     template<class D, class DPtr>
390       inline bool operator==( const RW_pointer<D, DPtr> & lhs, const typename DPtr::constPtrType & rhs )
391       { return( lhs.get() == rhs.get() ); }
392     /** \relates RW_pointer */
393     template<class D, class DPtr>
394       inline bool operator==( const typename DPtr::constPtrType & lhs, const RW_pointer<D, DPtr> & rhs )
395       { return( lhs.get() == rhs.get() ); }
396     /** \relates RW_pointer */
397     template<class D, class DPtr>
398       inline bool operator==( const RW_pointer<D, DPtr> & lhs, std::nullptr_t )
399       { return( lhs.get() == nullptr ); }
400     /** \relates RW_pointer */
401     template<class D, class DPtr>
402       inline bool operator==( std::nullptr_t, const RW_pointer<D, DPtr> & rhs )
403       { return( nullptr == rhs.get() ); }
404
405
406     /** \relates RW_pointer */
407     template<class D, class DPtr>
408       inline bool operator!=( const RW_pointer<D, DPtr> & lhs, const RW_pointer<D, DPtr> & rhs )
409       { return ! ( lhs == rhs ); }
410     /** \relates RW_pointer */
411     template<class D, class DPtr>
412       inline bool operator!=( const RW_pointer<D, DPtr> & lhs, const typename DPtr::PtrType & rhs )
413       { return ! ( lhs == rhs ); }
414     /** \relates RW_pointer */
415     template<class D, class DPtr>
416       inline bool operator!=( const typename DPtr::PtrType & lhs, const RW_pointer<D, DPtr> & rhs )
417       { return ! ( lhs == rhs ); }
418     /** \relates RW_pointer */
419     template<class D, class DPtr>
420       inline bool operator!=( const RW_pointer<D, DPtr> & lhs, const typename DPtr::constPtrType & rhs )
421       { return ! ( lhs == rhs ); }
422     /** \relates RW_pointer */
423     template<class D, class DPtr>
424       inline bool operator!=( const typename DPtr::constPtrType & lhs, const RW_pointer<D, DPtr> & rhs )
425       { return ! ( lhs == rhs ); }
426     /** \relates RW_pointer */
427     template<class D, class DPtr>
428       inline bool operator!=( const RW_pointer<D, DPtr> & lhs, std::nullptr_t )
429       { return( lhs.get() != nullptr ); }
430     /** \relates RW_pointer */
431     template<class D, class DPtr>
432       inline bool operator!=( std::nullptr_t, const RW_pointer<D, DPtr> & rhs )
433       { return( nullptr != rhs.get() ); }
434
435     ///////////////////////////////////////////////////////////////////
436
437     /** \relates RWCOW_pointer Clone the underlying object.
438      * Calls \a rhs <tt>-\>clone()</tt>. Being defined as a
439      * function outside \ref RWCOW_pointer allows to overload
440      * it, in case a specific \a D does not have <tt>clone()</tt>.
441      */
442     template<class D>
443       inline D * rwcowClone( const D * rhs )
444       { return rhs->clone(); }
445
446     ///////////////////////////////////////////////////////////////////
447     //
448     //  CLASS NAME : RWCOW_pointer
449     //
450     /** \ref RW_pointer supporting 'copy on write' functionality.
451      *
452      * \em Write access to the underlying object creates a copy, iff
453      * the object is shared.
454      *
455      * See \ref RW_pointer.
456     */
457     template<class D, class DTraits = rw_pointer::Shared<D> >
458       struct RWCOW_pointer
459       {
460         typedef typename DTraits::PtrType               PtrType;
461         typedef typename DTraits::constPtrType          constPtrType;
462
463         RWCOW_pointer()
464         {}
465
466         RWCOW_pointer( std::nullptr_t )
467         {}
468
469         explicit
470         RWCOW_pointer( typename PtrType::element_type * dptr )
471         : _dptr( dptr )
472         {}
473
474         explicit
475         RWCOW_pointer( PtrType dptr )
476         : _dptr( dptr )
477         {}
478
479         RWCOW_pointer & operator=( std::nullptr_t )
480         { reset(); return *this; }
481
482         void reset()
483         { PtrType().swap( _dptr ); }
484
485         void reset( typename PtrType::element_type * dptr )
486         { PtrType( dptr ).swap( _dptr ); }
487
488         void swap( RWCOW_pointer & rhs )
489         { _dptr.swap( rhs._dptr ); }
490
491         void swap( PtrType & rhs )
492         { _dptr.swap( rhs ); }
493
494         explicit operator bool() const
495         { return _dptr.get() != nullptr; }
496
497         const D & operator*() const
498         { return *_dptr; };
499
500         const D * operator->() const
501         { return _dptr.operator->(); }
502
503         const D * get() const
504         { return _dptr.get(); }
505
506         D & operator*()
507         { assertUnshared(); return *_dptr; }
508
509         D * operator->()
510         { assertUnshared(); return _dptr.operator->(); }
511
512         D * get()
513         { assertUnshared(); return _dptr.get(); }
514
515       public:
516         bool unique() const
517         { return DTraits().unique( _dptr ); }
518
519         long use_count() const
520         { return DTraits().use_count( _dptr ); }
521
522         constPtrType getPtr() const
523         { return _dptr; }
524
525         PtrType getPtr()
526         { assertUnshared(); return _dptr; }
527
528         constPtrType cgetPtr()
529         { return _dptr; }
530
531       private:
532
533         void assertUnshared()
534         {
535           if ( !unique() )
536             PtrType( rwcowClone( _dptr.get() ) ).swap( _dptr );
537         }
538
539       private:
540         PtrType _dptr;
541       };
542     ///////////////////////////////////////////////////////////////////
543
544     /** \relates RWCOW_pointer Stream output.
545      *
546      * Print the \c D object the RWCOW_pointer refers, or \c "NULL"
547      * if the pointer is \c NULL.
548      */
549     template<class D, class DPtr>
550       inline std::ostream & operator<<( std::ostream & str, const RWCOW_pointer<D, DPtr> & obj )
551       {
552         if ( obj.get() )
553           return str << *obj.get();
554         return str << std::string("NULL");
555       }
556
557     /** \relates RWCOW_pointer */
558     template<class D, class DPtr>
559       inline bool operator==( const RWCOW_pointer<D, DPtr> & lhs, const RWCOW_pointer<D, DPtr> & rhs )
560       { return( lhs.get() == rhs.get() ); }
561     /** \relates RWCOW_pointer */
562     template<class D, class DPtr>
563       inline bool operator==( const RWCOW_pointer<D, DPtr> & lhs, const typename DPtr::PtrType & rhs )
564       { return( lhs.get() == rhs.get() ); }
565     /** \relates RWCOW_pointer */
566     template<class D, class DPtr>
567       inline bool operator==( const typename DPtr::PtrType & lhs, const RWCOW_pointer<D, DPtr> & rhs )
568       { return( lhs.get() == rhs.get() ); }
569     /** \relates RWCOW_pointer */
570     template<class D, class DPtr>
571       inline bool operator==( const RWCOW_pointer<D, DPtr> & lhs, const typename DPtr::constPtrType & rhs )
572       { return( lhs.get() == rhs.get() ); }
573     /** \relates RWCOW_pointer */
574     template<class D, class DPtr>
575       inline bool operator==( const typename DPtr::constPtrType & lhs, const RWCOW_pointer<D, DPtr> & rhs )
576       { return( lhs.get() == rhs.get() ); }
577     /** \relates RWCOW_pointer */
578     template<class D, class DPtr>
579       inline bool operator==( const RWCOW_pointer<D, DPtr> & lhs, std::nullptr_t )
580       { return( lhs.get() == nullptr ); }
581     /** \relates RWCOW_pointer */
582     template<class D, class DPtr>
583       inline bool operator==( std::nullptr_t, const RWCOW_pointer<D, DPtr> & rhs )
584       { return( nullptr == rhs.get() ); }
585
586     /** \relates RWCOW_pointer */
587     template<class D, class DPtr>
588       inline bool operator!=( const RWCOW_pointer<D, DPtr> & lhs, const RWCOW_pointer<D, DPtr> & rhs )
589       { return ! ( lhs == rhs ); }
590     /** \relates RWCOW_pointer */
591     template<class D, class DPtr>
592       inline bool operator!=( const RWCOW_pointer<D, DPtr> & lhs, const typename DPtr::PtrType & rhs )
593       { return ! ( lhs == rhs ); }
594     /** \relates RWCOW_pointer */
595     template<class D, class DPtr>
596       inline bool operator!=( const typename DPtr::PtrType & lhs, const RWCOW_pointer<D, DPtr> & rhs )
597       { return ! ( lhs == rhs ); }
598     /** \relates RWCOW_pointer */
599     template<class D, class DPtr>
600       inline bool operator!=( const RWCOW_pointer<D, DPtr> & lhs, const typename DPtr::constPtrType & rhs )
601       { return ! ( lhs == rhs ); }
602     /** \relates RWCOW_pointer */
603     template<class D, class DPtr>
604       inline bool operator!=( const typename DPtr::constPtrType & lhs, const RWCOW_pointer<D, DPtr> & rhs )
605       { return ! ( lhs == rhs ); }
606     /** \relates RWCOW_pointer */
607     template<class D, class DPtr>
608       inline bool operator!=( const RWCOW_pointer<D, DPtr> & lhs, std::nullptr_t )
609       { return( lhs.get() != nullptr ); }
610     /** \relates RWCOW_pointer */
611     template<class D, class DPtr>
612       inline bool operator!=( std::nullptr_t, const RWCOW_pointer<D, DPtr> & rhs )
613       { return( nullptr != rhs.get() ); }
614
615     ///////////////////////////////////////////////////////////////////
616
617     /*@}*/
618   /////////////////////////////////////////////////////////////////
619 } // namespace zypp
620 ///////////////////////////////////////////////////////////////////
621
622 /** Forward declaration of Ptr types */
623 #define DEFINE_PTR_TYPE(NAME) \
624 class NAME;                                                      \
625 extern void intrusive_ptr_add_ref( const NAME * );               \
626 extern void intrusive_ptr_release( const NAME * );               \
627 typedef zypp::intrusive_ptr<NAME>       NAME##_Ptr;        \
628 typedef zypp::intrusive_ptr<const NAME> NAME##_constPtr;
629
630 ///////////////////////////////////////////////////////////////////
631 #endif // ZYPP_BASE_PTRTYPES_H