ARB
arb_progress.h
Go to the documentation of this file.
1 // ================================================================ //
2 // //
3 // File : arb_progress.h //
4 // Purpose : //
5 // //
6 // Coded by Ralf Westram (coder@reallysoft.de) in November 2010 //
7 // Institute of Microbiology (Technical University Munich) //
8 // http://www.arb-home.de/ //
9 // //
10 // ================================================================ //
11 
12 #ifndef ARB_PROGRESS_H
13 #define ARB_PROGRESS_H
14 
15 #ifndef ARB_ASSERT_H
16 #include <arb_assert.h>
17 #endif
18 #ifndef ARB_ERROR_H
19 #include <arb_error.h>
20 #endif
21 #ifndef ARBTOOLS_H
22 #include <arbtools.h>
23 #endif
24 #ifndef ARB_MSG_H
25 #include "arb_msg.h"
26 #endif
27 
28 #if defined(DEBUG)
29 # define TEST_COUNTERS
30 #endif
31 
32 #if !defined(DEVEL_RELEASE)
33 # define FORCE_WEIGHTED_ESTIMATION // see also ../WINDOW/AW_status.cxx@FORCEWEIGHTEDESTIMATION
34 #endif
35 
36 #define DUMP_PROGRESS // undefine DUMP_PROGRESS again? (when progress bug #807 is fixed)
37 
39 
40 namespace ArbProgress {
41  typedef long SINT;
42 
43  class nestable; // nestable progresses
44 
45  class weightable { // can weight gauge
46  bool weighted;
47 
48  double phase1_weight;
49  double phase2_weight() const { return 1.0-phase1_weight; }
50 
51  public:
53  weighted(false),
54  phase1_weight(0.0)
55  {}
56 
57  explicit weightable(double phase1_weight_) :
58  weighted(true),
59  phase1_weight(phase1_weight_)
60  {}
61 
62  bool is_weighted() const { return weighted; }
63 
64  double get_adjusted_gauge(double linear_gauge) const {
65  arb_assert(linear_gauge>=0);
66  arb_assert(linear_gauge<=1);
67 
68  double adjusted_gauge = linear_gauge;
69  if (is_weighted()) {
70  if (linear_gauge<0.5) adjusted_gauge = phase1_weight * linear_gauge * 2;
71  else adjusted_gauge = phase1_weight + phase2_weight() * (linear_gauge-0.5)*2;
72  }
73 
74  arb_assert(adjusted_gauge>=0);
75  arb_assert(adjusted_gauge<=1);
76 
77  return adjusted_gauge;
78  }
79  };
80 
81  class counter : virtual Noncopyable {
82  protected:
84  public:
85 
86  counter(nestable *owner)
87  : ownedBy(owner)
88  {
89  arb_assert(owner); // counter w/o owner is not possible
90  }
91  virtual ~counter() {
93  }
94 
95  virtual void inc() = 0;
96  virtual void implicit_inc() = 0;
97  virtual void inc_by(SINT count) = 0;
98  virtual void inc_to(SINT x) = 0;
99  virtual void inc_to_avoid_overflow(SINT x) = 0;
100  virtual void child_updates_gauge(double gauge) = 0;
101  virtual void done() = 0;
102  virtual void force_update() = 0;
103  virtual void auto_subtitles(const char *prefix) = 0;
104  virtual bool has_auto_subtitles() = 0;
105 
106 #if defined(DUMP_PROGRESS)
107  virtual void dump() const = 0;
108 #endif
109 
110  virtual counter *clone(nestable *owner, SINT overall_count) const = 0;
111 
112  bool owned_by(const nestable *by) const { return ownedBy && ownedBy == by; }
113  bool has_correct_ownership() const;
114  };
115 
116  const int LEVEL_TITLE = 0;
117  const int LEVEL_SUBTITLE = 1;
118 
119  class nestable : virtual Noncopyable {
120  nestable *prev_recent; // old value of global 'recent'
121  bool reuse_allowed; // display may be reused by childs
122 
123  protected:
124 #if defined(DUMP_PROGRESS)
125  char *name; // dumped name
126 #define DUMP_AS(NAME) freedup(name,NAME)
127 #else
128 #define DUMP_AS(NAME)
129 #endif
130 
131  bool has_title;
132  counter *cntr; // counter used by this progress
134 
135  static nestable *recent; // last instance constructed
136  static arb_status_implementation *impl; // defines implementation to display status
137 
138  virtual SmartPtr<nestable> create_child_progress(const char *title, SINT overall_count, const weightable& speed_) = 0;
139 
140  nestable(counter *counter_, bool has_title_, const weightable& speed_)
141  : reuse_allowed(false),
142  has_title(has_title_),
143  cntr(counter_),
144  speed(speed_)
145  {
146  prev_recent = recent;
147  recent = this;
148 
149 #if defined(DUMP_PROGRESS)
150  name = NULp;
151 #endif
152 
153 #if defined(TEST_COUNTERS)
154  accept_invalid_counters = false;
155 #endif
157  }
158  public:
159 #if defined(TEST_COUNTERS)
160  bool accept_invalid_counters; // if true, do not complain about unfinished counters
161 #endif
162 
163  virtual ~nestable() {
164  arb_assert(this == recent); // nestable|s should be destroyed in-order!
165 
166  delete cntr;
167  recent = prev_recent;
168 #if defined(DUMP_PROGRESS)
169  arb_assert(name); // progress was not named (dump() wont show anything useful; use DUMP_AS in ctor of derived class)
170  free(name);
171 #endif
172  }
173 
174  static SmartPtr<nestable> create(const char *title, SINT overall_count, const double *phase1_fraction);
176 
177 #if defined(FORCE_WEIGHTED_ESTIMATION)
178  static bool have_weighted_progress();
180  return speed.is_weighted() || (prev_recent && prev_recent->this_or_recent_is_weighted());
181  }
182 #endif
183 
184  bool aborted() const;
185  virtual void set_text(int level, const char *text) = 0;
186  virtual void update_gauge(double gauge) = 0;
187 
188 #if defined(DUMP_PROGRESS)
189  virtual void dump() const;
190 #endif
191 
192  void child_sets_text(int level, const char *text) {
193  set_text(level+1-reuse_allowed+cntr->has_auto_subtitles(), text);
194  }
195  void allow_title_reuse() { reuse_allowed = true; }
196 
197  void update_parent_gauge(double gauge) { cntr->child_updates_gauge(gauge); }
198  void child_terminated() { cntr->implicit_inc(); }
199 
200  void initial_update() { cntr->force_update(); }
201  void force_update() { cntr->force_update(); }
202 
203  void inc() { cntr->inc(); }
204  void inc_by(SINT count) { arb_assert(count>=0); cntr->inc_by(count); }
205  void inc_to(SINT x) { cntr->inc_to(x); }
206  void inc_to_avoid_overflow(SINT x) { cntr->inc_to_avoid_overflow(x); }
207  void done() { cntr->done(); }
208  void auto_subtitles(const char *prefix) { cntr->auto_subtitles(prefix); }
209 
210  static void show_comment(const char *comment) {
211  if (recent) recent->set_text(ArbProgress::LEVEL_SUBTITLE, comment);
212  }
213 
214  bool owns(const counter *pwnd) const { return cntr && cntr == pwnd; }
215  bool is_correct_owner() const { return owns(cntr) && cntr->owned_by(this); }
216  };
217 
218  inline bool counter::has_correct_ownership() const { return owned_by(ownedBy) && ownedBy->owns(this); }
219 
220 };
221 
222 // ----------------------
223 // arb_progress
224 
225 enum WeightedProgressMarker { WEIGHTED }; // just a marker to emphasize weighted progresses
226 
227 class arb_progress : virtual Noncopyable {
229 
230  typedef ArbProgress::SINT PINT;
231 
232  void setup(const char *title, PINT overall_count, const double *phase1_fraction = NULp) {
233  bool acceptInvalid = false;
234  if (overall_count<0) { // assume overflow
235  GB_warningf("Warning: progress indicator underflow (%li, %s)\n"
236  "Please report to devel@arb-home.de\n"
237  "Estimation of time left is broken :/",
238  overall_count, title ? title : "<no title>");
239 
240 #if defined(DEVEL_RALF)
241  arb_assert(0); // overflow?
242 #endif
243 
244  overall_count = 10L*INT_MAX; // fake sth big
245  acceptInvalid = true;
246  }
247 
248  used = ArbProgress::nestable::create(title, overall_count, phase1_fraction);
249  if (acceptInvalid) accept_invalid_counters();
250  used->initial_update();
251  }
252  // cppcheck-suppress functionConst
253  void accept_invalid_counters() {
254 #if defined(TEST_COUNTERS)
255  used->accept_invalid_counters = true;
256 #endif
257  }
258 
259 public:
260  // ------------------------------
261  // recommended interface:
262 
263  arb_progress(const char *title, PINT overall_count) {
264  // open a progress indicator
265  //
266  // expects to be incremented 'overall_count' times
267  // incrementation is done either
268  // - explicitly by calling one of the inc...()-functions below or
269  // - implicitely by creating another arb_progress while this one remains
270  //
271  // if you can't ahead-determine the exact number of incrementations,
272  // specify an upper-limit and call .done() before dtor.
273  setup(title, overall_count);
274  }
275  explicit arb_progress(const char *title) {
276  // open a wrapping progress indicator
277  //
278  // expects NOT to be incremented explicitly!
279  // if arb_progresses are created while this exists, they reuse the progress window.
280  // Useful to avoid spamming the user with numerous popping-up progress windows.
281  setup(title, 0);
282  }
283  explicit arb_progress(PINT overall_count) {
284  // open counting progress (reuses text of parent progress).
285  //
286  // Useful to separate text- from gauge-display or
287  // to summarize several consecutive child-progresses into one.
288  setup(NULp, overall_count);
289  }
290 
291 
293  // plain wrapper (avoids multiple implicit increments of its parent).
294  //
295  // usage-conditions:
296  // * caller increments progress in a loop and
297  // * loop calls one or more callees and callees open multiple progress bars.
298  //
299  // in this case the parent progress would be implicitely incremented several times
300  // per loop, resulting in wrong gauge.
301  //
302  // if you know the number of opened progresses, use arb_progress(PINT),
303  // otherwise add one wrapper-progress into the loop.
304  setup(NULp, 0);
305  }
306 
307 private:
308  // forbid constructing arb_progress with integer types that could overflow in caller code:
309  template <typename NUM> arb_progress(const char *t, NUM n);
310  template <typename NUM> explicit arb_progress(NUM n);
311 public:
312  // explicitely overload wanted ctors:
313  explicit arb_progress(char *title) { setup(title, 0); }
314  explicit arb_progress(unsigned long overall_count) { arb_assert(overall_count<=LONG_MAX); setup(NULp, overall_count); }
315  arb_progress(const char *title, unsigned long overall_count) { arb_assert(overall_count<=LONG_MAX); setup(title, overall_count); }
316  arb_progress(WeightedProgressMarker, const char *title, double phase1_fraction) { setup(title, 2UL, &phase1_fraction); } // a name weighted progress (always has count of 2)
317  arb_progress(WeightedProgressMarker, double phase1_fraction) { setup(NULp, 2UL, &phase1_fraction); } // an unnamed weighted progress (always has count of 2)
318 
320 
321  void subtitle(const char *stitle) { used->set_text(ArbProgress::LEVEL_SUBTITLE, stitle); }
322 
324  return aborted() ? "Operation aborted on user request" : NULp;
325  }
326 
328  inc();
329  return error_if_aborted();
330  }
331 
332  void inc_and_check_user_abort(GB_ERROR& error) { if (!error) error = inc_and_error_if_aborted(); else accept_invalid_counters(); }
333  void inc_and_check_user_abort(ARB_ERROR& error) { if (!error) error = inc_and_error_if_aborted(); else accept_invalid_counters(); }
334 
335  bool aborted() {
336  // true if user pressed "Abort"
337  bool aborted_ = used->aborted();
338 #if defined(TEST_COUNTERS)
339  if (aborted_) accept_invalid_counters();
340 #endif
341  return aborted_;
342  }
343 
344  void auto_subtitles(const char *prefix) {
345  // automatically update subtitles ("prefix #/#")
346  // prefix = NULp -> switch off
347  used->auto_subtitles(prefix);
348  }
349  static void show_comment(const char *comment) {
350  // Like subtitle(), but w/o needing to know anything about a eventually open progress
351  // e.g. used to show ARB is connecting to ptserver
353  }
354 
355  // ------------------------------
356  // less recommended interface:
357 
358  void inc() { used->inc(); } // increment progress
359  const arb_progress& operator++() { inc(); return *this; } // ++progress
360 
361  void inc_by(PINT count) { arb_assert(count>=0); used->inc_by(count); }
362  void inc_to(PINT x) { used->inc_to(x); }
363  void inc_to_avoid_overflow(PINT x) { used->inc_to_avoid_overflow(x); }
364 
366 
367  void done() { used->done(); } // set "done" (aka 100%). Useful when exiting some loop early
368 #if defined(DUMP_PROGRESS)
369  void dump() const;
370 #endif
371  void force_update() { used->force_update(); }
372 };
373 
374 // -------------------------------
375 // arb_suppress_progress
376 
379 public:
381  : suppressor(ArbProgress::nestable::create_suppressor())
382  {}
383 };
384 
385 
386 #else
387 #error arb_progress.h included twice
388 #endif // ARB_PROGRESS_H
#define arb_assert(cond)
Definition: arb_assert.h:245
virtual void inc_by(SINT count)=0
bool is_weighted() const
Definition: arb_progress.h:62
void inc_to_avoid_overflow(PINT x)
Definition: arb_progress.h:363
void force_update()
Definition: arb_progress.h:371
arb_progress(const char *title, unsigned long overall_count)
Definition: arb_progress.h:315
virtual void inc_to_avoid_overflow(SINT x)=0
void allow_title_reuse()
Definition: arb_progress.h:319
void inc_to(PINT x)
Definition: arb_progress.h:362
bool owned_by(const nestable *by) const
Definition: arb_progress.h:112
virtual SmartPtr< nestable > create_child_progress(const char *title, SINT overall_count, const weightable &speed_)=0
static SmartPtr< nestable > create(const char *title, SINT overall_count, const double *phase1_fraction)
void child_sets_text(int level, const char *text)
Definition: arb_progress.h:192
virtual void update_gauge(double gauge)=0
const char * title
Definition: readseq.c:22
void auto_subtitles(const char *prefix)
Definition: arb_progress.h:344
bool this_or_recent_is_weighted() const
Definition: arb_progress.h:179
virtual void force_update()=0
WeightedProgressMarker
Definition: arb_progress.h:225
void inc_to_avoid_overflow(SINT x)
Definition: arb_progress.h:206
GB_ERROR error_if_aborted()
Definition: arb_progress.h:323
void sub_progress_skipped()
Definition: arb_progress.h:365
bool has_correct_ownership() const
Definition: arb_progress.h:218
virtual counter * clone(nestable *owner, SINT overall_count) const =0
void inc_by(SINT count)
Definition: arb_progress.h:204
virtual void set_text(int level, const char *text)=0
const int LEVEL_SUBTITLE
Definition: arb_progress.h:117
bool owns(const counter *pwnd) const
Definition: arb_progress.h:214
static void show_comment(const char *comment)
Definition: arb_progress.h:349
void GB_warningf(const char *templat,...)
Definition: arb_msg.cxx:536
nestable(counter *counter_, bool has_title_, const weightable &speed_)
Definition: arb_progress.h:140
Generic smart pointer.
Definition: smartptr.h:149
bool aborted()
Definition: arb_progress.h:335
virtual void child_updates_gauge(double gauge)=0
#define true
Definition: ureadseq.h:14
static nestable * recent
Definition: arb_progress.h:135
virtual bool has_auto_subtitles()=0
#define false
Definition: ureadseq.h:13
virtual void auto_subtitles(const char *prefix)=0
static bool have_weighted_progress()
arb_progress(unsigned long overall_count)
Definition: arb_progress.h:314
virtual void inc()=0
weightable(double phase1_weight_)
Definition: arb_progress.h:57
static void error(const char *msg)
Definition: mkptypes.cxx:96
void update_parent_gauge(double gauge)
Definition: arb_progress.h:197
counter(nestable *owner)
Definition: arb_progress.h:86
const arb_progress & operator++()
Definition: arb_progress.h:359
arb_progress(WeightedProgressMarker, double phase1_fraction)
Definition: arb_progress.h:317
void auto_subtitles(const char *prefix)
Definition: arb_progress.h:208
virtual void implicit_inc()=0
void inc_and_check_user_abort(ARB_ERROR &error)
Definition: arb_progress.h:333
GB_ERROR inc_and_error_if_aborted()
Definition: arb_progress.h:327
static arb_status_implementation * impl
Definition: arb_progress.h:136
arb_progress(PINT overall_count)
Definition: arb_progress.h:283
arb_progress(const char *title)
Definition: arb_progress.h:275
arb_progress(WeightedProgressMarker, const char *title, double phase1_fraction)
Definition: arb_progress.h:316
static SmartPtr< nestable > create_suppressor()
double get_adjusted_gauge(double linear_gauge) const
Definition: arb_progress.h:64
void subtitle(const char *stitle)
Definition: arb_progress.h:321
virtual void inc_to(SINT x)=0
#define NULp
Definition: cxxforward.h:116
static void show_comment(const char *comment)
Definition: arb_progress.h:210
arb_progress(const char *title, PINT overall_count)
Definition: arb_progress.h:263
virtual void dump() const
void inc_by(PINT count)
Definition: arb_progress.h:361
virtual void done()=0
arb_progress(char *title)
Definition: arb_progress.h:313
bool is_correct_owner() const
Definition: arb_progress.h:215
virtual void dump() const =0
const int LEVEL_TITLE
Definition: arb_progress.h:116
void inc_and_check_user_abort(GB_ERROR &error)
Definition: arb_progress.h:332
void dump() const