Imported Upstream version 14.44.0
[platform/upstream/libzypp.git] / zypp / ProgressData.h
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/ProgressData.h
10  *
11 */
12 #ifndef ZYPP_PROGRESSDATA_H
13 #define ZYPP_PROGRESSDATA_H
14
15 #include <iosfwd>
16 #include <string>
17
18 #include "zypp/base/PtrTypes.h"
19 #include "zypp/base/Function.h"
20 #include "zypp/base/ProvideNumericId.h"
21
22 #include "zypp/Date.h"
23
24 ///////////////////////////////////////////////////////////////////
25 namespace zypp
26 { /////////////////////////////////////////////////////////////////
27
28   ///////////////////////////////////////////////////////////////////
29   //
30   //    CLASS NAME : ProgressData
31   //
32   /** Maintain <tt>[min,max]</tt> and counter <tt>(value)</tt> for progress counting.
33    *
34    * This class should provide everything the producer of progress data
35    * needs. As a convention, a zero sizes range indicates that you are just
36    * able to send <em>'still alive'</em> triggers.
37    *
38    * The counter should be updated in reasonable intervals. Don't mind whether
39    * the counter value actually increased or not. ProgressData will recognize
40    * your triggers and knows when to actually send notification to a consumer.
41    *
42    * Each ProgressData object provides a unique numeric id and you may assign
43    * it a name.
44    *
45    * \code
46    *      bool exampleReceiver( ProgressData::value_type v )
47    *      {
48    *        DBG << "got ->" << v << endl;
49    *        return( v <= 100 ); // Abort if ( v > 100 )
50    *      }
51    *
52    *      class Example
53    *      {
54    *        public:
55    *
56    *          Example( const ProgressData::ReceiverFnc & fnc_r = ProgressData::ReceiverFnc() )
57    *          : _fnc( fnc_r )
58    *          {}
59    *
60    *          void SendTo( const ProgressData::ReceiverFnc & fnc_r )
61    *          { _fnc = fnc_r; }
62    *
63    *        public:
64    *
65    *          void action()
66    *          {
67    *            ProgressData tics( 10 );    // Expect range 0 -> 10
68    *            tics.name( "test ticks" );  // Some arbitrary name
69    *            tics.sendTo( _fnc );        // Send reports to _fnc
70    *            tics.toMin();               // start sending min (0)
71    *
72    *            for ( int i = 0; i < 10; ++i )
73    *            {
74    *              if ( ! tics.set( i ) )
75    *                return; // user requested abort
76    *            }
77    *
78    *            tics.toMax(); // take care 100% are reported on success
79    *          }
80    *
81    *          void action2()
82    *          {
83    *            ProgressData tics;          // Just send 'still alive' messages
84    *            tics.name( "test ticks" );  // Some arbitrary name
85    *            tics.sendTo( _fnc );        // Send reports to _fnc
86    *            tics.toMin();               // start sending min (0)
87    *
88    *            for ( int i = 0; i < 10; ++i )
89    *            {
90    *              if ( ! tics.set( i ) )
91    *                return; // user requested abort
92    *            }
93    *
94    *            tics.toMax(); //
95    *          }
96    *
97    *        private:
98    *          ProgressData::ReceiverFnc _fnc;
99    *      };
100    * \endcode
101    * \code
102    *   Example t( exampleReceiver );
103    *   DBG << "Reporting %:" << endl;
104    *   t.action();
105    *   DBG << "Reporting 'still alive':" << endl;
106    *   t.action2();
107    * \endcode
108    * \code
109    * Reporting %:
110    * got ->0
111    * got ->10
112    * got ->20
113    * got ->30
114    * got ->40
115    * got ->50
116    * got ->60
117    * got ->70
118    * got ->80
119    * got ->90
120    * got ->100
121    * got ->100
122    * Reporting 'still alive':
123    * got ->0
124    * got ->9
125    * \endcode
126    *
127    * The different ammount of triggers is due to different rules for sending
128    * percent or 'still alive' messages.
129    */
130   class ProgressData : public base::ProvideNumericId<ProgressData,unsigned>
131   {
132     public:
133       typedef long long value_type;
134       /** Most simple version of progress reporting
135        * The percentage in most cases. Sometimes just keepalive.
136        * \p sender ProgressData object who sends the progress info
137        * \p
138        */
139       typedef function<bool( const ProgressData & )> ReceiverFnc;
140
141     private:
142       enum State { INIT, RUN, END };
143
144       class Data
145       {
146         public:
147           Data( value_type min_r, value_type max_r, value_type val_r )
148           : _state( INIT ), _min( min_r ), _max( max_r ), _val( val_r )
149           , _last_val( 0 ), _last_send( 0 )
150           {}
151
152         public:
153           State       _state;
154           std::string _name;
155           value_type  _min;
156           value_type  _max;
157           value_type  _val;
158
159           ReceiverFnc _receiver;
160           value_type  _last_val;
161           Date        _last_send;
162
163         private:
164           /** clone for RWCOW_pointer */
165           friend Data * rwcowClone<Data>( const Data * rhs );
166           Data * clone() const { return new Data( *this ); }
167       };
168
169     public:
170       /** Ctor no range <tt>[0,0](0)</tt>. */
171       ProgressData()
172       : _d( new Data( 0, 0, 0 ) )
173       {}
174
175       /** Ctor <tt>[0,max](0)</tt>. */
176       ProgressData( value_type max_r )
177       : _d( new Data( 0, max_r, 0 ) )
178       {}
179
180       /** Ctor <tt>[min,max](min)</tt>. */
181       ProgressData( value_type min_r, value_type max_r )
182       : _d( new Data( min_r, max_r, min_r ) )
183       {}
184
185       /** Ctor <tt>[min,max](val)</tt>. */
186       ProgressData( value_type min_r, value_type max_r, value_type val_r )
187       : _d( new Data( min_r, max_r, val_r ) )
188       {}
189
190       ~ProgressData()
191       {
192         if ( _d->_state == RUN )
193         {
194           _d->_state = END;
195           report();
196         }
197       }
198
199     public:
200       /** Set new \c min value. */
201       void min( value_type min_r )
202       { _d->_min = min_r; }
203
204       /** Set new \c max value. */
205       void max( value_type max_r )
206       { _d->_max = max_r; }
207
208       /** Set no range <tt>[0,0]</tt>. */
209       void noRange()
210       { range( 0, 0 ); }
211
212       /** Set new <tt>[0,max]</tt>. */
213       void range( value_type max_r )
214       { range( 0, max_r ); }
215
216       /** Set new <tt>[min,max]</tt>. */
217       void range( value_type min_r, value_type max_r )
218       { min( min_r ); max( max_r ); }
219
220     public:
221       /** Set counter name. */
222       void name( const std::string & name_r )
223       { _d->_name = name_r; }
224
225       /** Set ReceiverFnc. */
226       void sendTo( const ReceiverFnc & fnc_r )
227       { _d->_receiver = fnc_r; }
228
229       /** Set no ReceiverFnc. */
230       void noSend()
231       { _d->_receiver = ReceiverFnc(); }
232
233     public:
234       /** \name Progress reporting.
235        *
236        * These methods may actually cause a progress report to be sent.
237        *
238        * All methods return \c bool, because a progress receiver may
239        * return \c false to indicate the desire to abort the pending
240        * action. The incident is logged, but it's finaly up to the caller
241        * to honor this.
242        */
243       //@{
244
245       /** Set new counter \c value. */
246       bool set( value_type val_r )
247       {
248         _d->_val = val_r;
249         return report();
250       }
251
252       /** Set range and counter from an other \ref ProgressData. */
253       bool set( const ProgressData & rhs )
254       {
255         min( rhs.min() );
256         max( rhs.max() );
257         return set( rhs.val() );
258       }
259
260       /** Increment counter \c value (default by 1). */
261       bool incr( value_type val_r = 1 )
262       { return set( val() + val_r ); }
263
264       /** Decrement counter \c value (default by 1). */
265       bool decr( value_type val_r = 1 )
266       { return set( val() - val_r ); }
267
268       /** Set counter value to current \c min value. */
269       bool toMin()
270       { return set( min() ); }
271
272       /** Set counter value to current \c max value (unless no range). */
273       bool toMax()
274       { return hasRange() ? set( max() ) : tick(); }
275
276       /** Leave counter value unchanged (still alive). */
277       bool tick()
278       { return report(); }
279
280       //@}
281
282     public:
283       /** \name Progress receiving.
284        */
285       //@{
286       /** @return Current \c min value. */
287       value_type min() const
288       { return _d->_min; }
289
290       /** @return Current \c max value. */
291       value_type max() const
292       { return _d->_max; }
293
294       /** @return Current counter \c value. */
295       value_type val() const
296       { return _d->_val; }
297
298       /** @return Whether <tt>[min,max]</tt> defines a nonempty range. */
299       bool hasRange() const
300       { return min() != max(); }
301
302       /** @return Whether \ref reportValue will return a percent value.
303        * Same as \ref hasRange.
304        *  \see \ref reportAlive
305        */
306       bool reportPercent() const
307       { return hasRange(); }
308
309       /** @return Whether \ref reportValue always returns -1, because we
310        * trigger 'still alive' messages. I.e. \ref hasrange is \c false.
311        * \see \ref reportPercent
312       */
313       bool reportAlive() const
314       { return ! hasRange(); }
315
316       /** @return Either a a percent value or -1.
317        * \see \ref reportPercent and \ref reportAlive.
318       */
319       value_type reportValue() const
320       { return hasRange() ? val() * 100 / ( max() - min() ) : -1; }
321
322       /** @return The counters name. */
323       const std::string & name() const
324       { return _d->_name; }
325
326       /** @return The ReceiverFnc. */
327       const ReceiverFnc & receiver() const
328       { return _d->_receiver; }
329
330       /** @return Return \c true if this is the final report sent by the
331        *  ProgressData dtor.
332        */
333       bool finalReport() const
334       { return( _d->_state == END ); }
335
336       //@}
337
338     private:
339       /** Send report if necessary. */
340       bool report();
341
342       /** Pointer to data. */
343       RWCOW_pointer<Data> _d;
344   };
345   ///////////////////////////////////////////////////////////////////
346
347   /** \relates ProgressData Stream output */
348   std::ostream & operator<<( std::ostream & str, const ProgressData & obj );
349
350   ///////////////////////////////////////////////////////////////////
351
352   class InputStream;
353   /** \relates ProgressData Setup from \ref InputStream. */
354   ProgressData makeProgressData( const InputStream & input_r );
355
356   ///////////////////////////////////////////////////////////////////
357
358   /**
359    * \short Progress callback from another progress
360    *
361    * This class allows you to pass a progress callback to a
362    * subtask based on a current progress data, plus a weight
363    * value. Every progress reported by the subtask via
364    * this callback will be forwarded to the main progress
365    * data, with the corresponding weight.
366    *
367    * Example:
368    *
369    * \code
370    *
371    * // receiver for main task
372    * void task_receiver( ProgressData &progress );
373    *
374    * // subtask prototypes
375    * void do_subtask_one( ProgressData::ReceiverFnc &fnc );
376    * void do_subtask_two( ProgressData::ReceiverFnc &fnc );
377    *
378    * // main task
379    * ProgressData progress;
380    * //progress for subtask 1
381    * // which is 80%
382    * CombinedProgressData sub1(pd, 80);
383    * // the second is only 20%
384    * CombinedProgressData sub2(pd, 20);
385    * do_subtask_one( sub1 );
386    * do_subtask_two( sub2 );
387    *
388    * \endcode
389    */
390   class CombinedProgressData
391   {
392   public:
393     /**
394      * \short Ctor
395      *
396      * Creates a \ref ProgressData::ReceiverFnc
397      * from a \ref ProgressData object
398      *
399      * \param pd \ref ProgressData object
400      * \param weight Weight of the subtask
401      * relative to the main task range.
402      *
403      * If weight is 0, or \param pd only reports
404      * keepalives. then only ticks are sent.
405      *
406      */
407     CombinedProgressData( ProgressData &pd,
408                           ProgressData::value_type weight = 0 );
409
410     /**
411      * Implements the \ref ProgressData::ReceiverFnc
412      * callback interface
413      */
414     bool operator()( const ProgressData &progress );
415
416   private:
417     ProgressData::value_type _weight;
418     ProgressData::value_type _last_value;
419     ProgressData &_pd;
420   };
421
422   /////////////////////////////////////////////////////////////////
423 } // namespace zypp
424 ///////////////////////////////////////////////////////////////////
425 #endif // ZYPP_PROGRESSDATA_H