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 #define DUMP_PROGRESS // undefine DUMP_PROGRESS again? (when progress bug #807 is fixed)
33 
35 
36 namespace ArbProgress {
37  typedef long SINT;
38 
39  class nestable; // nestable progresses
40 
41  class counter : virtual Noncopyable {
42  protected:
44  public:
45 
46  counter(nestable *owner)
47  : ownedBy(owner)
48  {
49  arb_assert(owner); // counter w/o owner is not possible
50  }
51  virtual ~counter() {
53  }
54 
55  virtual void inc() = 0;
56  virtual void implicit_inc() = 0;
57  virtual void inc_by(SINT count) = 0;
58  virtual void inc_to(SINT x) = 0;
59  virtual void inc_to_avoid_overflow(SINT x) = 0;
60  virtual void child_updates_gauge(double gauge) = 0;
61  virtual void done() = 0;
62  virtual void force_update() = 0;
63  virtual void auto_subtitles(const char *prefix) = 0;
64  virtual bool has_auto_subtitles() = 0;
65 
66 #if defined(DUMP_PROGRESS)
67  virtual void dump() const = 0;
68 #endif
69 
70  virtual counter *clone(nestable *owner, SINT overall_count) const = 0;
71 
72  bool owned_by(const nestable *by) const { return ownedBy && ownedBy == by; }
73  bool has_correct_ownership() const;
74  };
75 
76  const int LEVEL_TITLE = 0;
77  const int LEVEL_SUBTITLE = 1;
78 
79  class nestable : virtual Noncopyable {
80  nestable *prev_recent; // old value of global 'recent'
81  bool reuse_allowed; // display may be reused by childs
82 
83  protected:
84 #if defined(DUMP_PROGRESS)
85  char *name; // dumped name
86 #define DUMP_AS(NAME) freedup(name,NAME)
87 #else
88 #define DUMP_AS(NAME)
89 #endif
90 
91  bool has_title;
92  counter *cntr; // counter used by this progress
93 
94  static nestable *recent; // last instance constructed
95  static arb_status_implementation *impl; // defines implementation to display status
96 
97  virtual SmartPtr<nestable> create_child_progress(const char *title, SINT overall_count) = 0;
98 
99  nestable(counter *counter_, bool has_title_)
100  : reuse_allowed(false),
101  has_title(has_title_),
102  cntr(counter_)
103  {
104  prev_recent = recent;
105  recent = this;
106 
107 #if defined(DUMP_PROGRESS)
108  name = NULp;
109 #endif
110 
111 #if defined(TEST_COUNTERS)
112  accept_invalid_counters = false;
113 #endif
115  }
116  public:
117 #if defined(TEST_COUNTERS)
118  bool accept_invalid_counters; // if true, do not complain about unfinished counters
119 #endif
120 
121  virtual ~nestable() {
122  delete cntr;
123  recent = prev_recent;
124 #if defined(DUMP_PROGRESS)
125  arb_assert(name); // progress was not named (dump() wont show anything useful; use DUMP_AS in ctor of derived class)
126  free(name);
127 #endif
128  }
129 
130  static SmartPtr<nestable> create(const char *title, SINT overall_count);
132 
133  bool aborted() const;
134  virtual void set_text(int level, const char *text) = 0;
135  virtual void update_gauge(double gauge) = 0;
136 
137 #if defined(DUMP_PROGRESS)
138  virtual void dump() const;
139 #endif
140 
141  void child_sets_text(int level, const char *text) {
142  set_text(level+1-reuse_allowed+cntr->has_auto_subtitles(), text);
143  }
144  void allow_title_reuse() { reuse_allowed = true; }
145 
146  void update_parent_gauge(double gauge) { cntr->child_updates_gauge(gauge); }
147  void child_terminated() { cntr->implicit_inc(); }
148 
149  void initial_update() { cntr->force_update(); }
150  void force_update() { cntr->force_update(); }
151 
152  void inc() { cntr->inc(); }
153  void inc_by(SINT count) { arb_assert(count>0); cntr->inc_by(count); }
154  void inc_to(SINT x) { cntr->inc_to(x); }
155  void inc_to_avoid_overflow(SINT x) { cntr->inc_to_avoid_overflow(x); }
156  void done() { cntr->done(); }
157  void auto_subtitles(const char *prefix) { cntr->auto_subtitles(prefix); }
158 
159  static void show_comment(const char *comment) {
160  if (recent) recent->set_text(ArbProgress::LEVEL_SUBTITLE, comment);
161  }
162 
163  bool owns(const counter *pwnd) const { return cntr && cntr == pwnd; }
164  bool is_correct_owner() const { return owns(cntr) && cntr->owned_by(this); }
165  };
166 
167  inline bool counter::has_correct_ownership() const { return owned_by(ownedBy) && ownedBy->owns(this); }
168 
169 };
170 
173 
174  typedef ArbProgress::SINT PINT;
175 
176  void setup(const char *title, PINT overall_count) {
177  bool acceptInvalid = false;
178  if (overall_count<0) { // assume overflow
179  GB_warningf("Warning: progress indicator underflow (%li, %s)\n"
180  "Please report to devel@arb-home.de\n"
181  "Estimation of time left is broken :/",
182  overall_count, title ? title : "<no title>");
183 
184 #if defined(DEVEL_RALF)
185  arb_assert(0); // overflow?
186 #endif
187 
188  overall_count = 10L*INT_MAX; // fake sth big
189  acceptInvalid = true;
190  }
191 
192  used = ArbProgress::nestable::create(title, overall_count);
193  if (acceptInvalid) accept_invalid_counters();
194  used->initial_update();
195  }
196  // cppcheck-suppress functionConst
197  void accept_invalid_counters() {
198 #if defined(TEST_COUNTERS)
199  used->accept_invalid_counters = true;
200 #endif
201  }
202 
203 public:
204  // ------------------------------
205  // recommended interface:
206 
207  arb_progress(const char *title, PINT overall_count) {
208  // open a progress indicator
209  //
210  // expects to be incremented 'overall_count' times
211  // incrementation is done either
212  // - explicitly by calling one of the inc...()-functions below or
213  // - implicitely by creating another arb_progress while this one remains
214  //
215  // if you can't ahead-determine the exact number of incrementations,
216  // specify an upper-limit and call .done() before dtor.
217  setup(title, overall_count);
218  }
219  explicit arb_progress(const char *title) {
220  // open a wrapping progress indicator
221  //
222  // expects NOT to be incremented explicitly!
223  // if arb_progresses are created while this exists, they reuse the progress window.
224  // Useful to avoid spamming the user with numerous popping-up progress windows.
225  setup(title, 0);
226  }
227  explicit arb_progress(PINT overall_count) {
228  // open counting progress (reuses text of parent progress).
229  //
230  // Useful to separate text- from gauge-display or
231  // to summarize several consecutive child-progresses into one.
232  setup(NULp, overall_count);
233  }
234 
235 
237  // plain wrapper (avoids multiple implicit increments of its parent).
238  //
239  // usage-conditions:
240  // * caller increments progress in a loop and
241  // * loop calls one or more callees and callees open multiple progress bars.
242  //
243  // in this case the parent progress would be implicitely incremented several times
244  // per loop, resulting in wrong gauge.
245  //
246  // if you know the number of opened progresses, use arb_progress(PINT),
247  // otherwise add one wrapper-progress into the loop.
248  setup(NULp, 0);
249  }
250 
251 private:
252  // forbid constructing arb_progress with integer types that could overflow in caller code:
253  template <typename NUM> arb_progress(const char *t, NUM n);
254  template <typename NUM> explicit arb_progress(NUM n);
255 public:
256  // explicitely overload wanted ctors:
257  explicit arb_progress(char *title) { setup(title, 0); }
258  arb_progress(const char *title, unsigned long overall_count) { arb_assert(overall_count<=LONG_MAX); setup(title, overall_count); }
259  explicit arb_progress(unsigned long overall_count) { arb_assert(overall_count<=LONG_MAX); setup(NULp, overall_count); }
260 
262 
263  void subtitle(const char *stitle) { used->set_text(ArbProgress::LEVEL_SUBTITLE, stitle); }
264 
266  return aborted() ? "Operation aborted on user request" : NULp;
267  }
268 
270  inc();
271  return error_if_aborted();
272  }
273 
274  void inc_and_check_user_abort(GB_ERROR& error) { if (!error) error = inc_and_error_if_aborted(); else accept_invalid_counters(); }
275  void inc_and_check_user_abort(ARB_ERROR& error) { if (!error) error = inc_and_error_if_aborted(); else accept_invalid_counters(); }
276 
277  bool aborted() {
278  // true if user pressed "Abort"
279  bool aborted_ = used->aborted();
280 #if defined(TEST_COUNTERS)
281  if (aborted_) accept_invalid_counters();
282 #endif
283  return aborted_;
284  }
285 
286  void auto_subtitles(const char *prefix) {
287  // automatically update subtitles ("prefix #/#")
288  // prefix = NULp -> switch off
289  used->auto_subtitles(prefix);
290  }
291  static void show_comment(const char *comment) {
292  // Like subtitle(), but w/o needing to know anything about a eventually open progress
293  // e.g. used to show ARB is connecting to ptserver
295  }
296 
297  // ------------------------------
298  // less recommended interface:
299 
300  void inc() { used->inc(); } // increment progress
301  const arb_progress& operator++() { inc(); return *this; } // ++progress
302 
303  void inc_by(PINT count) { arb_assert(count>0); used->inc_by(count); }
304  void inc_to(PINT x) { used->inc_to(x); }
305  void inc_to_avoid_overflow(PINT x) { used->inc_to_avoid_overflow(x); }
306 
308 
309  void done() { used->done(); } // set "done" (aka 100%). Useful when exiting some loop early
310 #if defined(DUMP_PROGRESS)
311  void dump() const;
312 #endif
313  void force_update() { used->force_update(); }
314 };
315 
318 public:
320  : suppressor(ArbProgress::nestable::create_suppressor())
321  {}
322 };
323 
324 #else
325 #error arb_progress.h included twice
326 #endif // ARB_PROGRESS_H
#define arb_assert(cond)
Definition: arb_assert.h:245
virtual void inc_by(SINT count)=0
void inc_to_avoid_overflow(PINT x)
Definition: arb_progress.h:305
void force_update()
Definition: arb_progress.h:313
arb_progress(const char *title, unsigned long overall_count)
Definition: arb_progress.h:258
virtual void inc_to_avoid_overflow(SINT x)=0
void allow_title_reuse()
Definition: arb_progress.h:261
void inc_to(PINT x)
Definition: arb_progress.h:304
bool owned_by(const nestable *by) const
Definition: arb_progress.h:72
virtual SmartPtr< nestable > create_child_progress(const char *title, SINT overall_count)=0
void child_sets_text(int level, const char *text)
Definition: arb_progress.h:141
virtual void update_gauge(double gauge)=0
const char * title
Definition: readseq.c:22
void auto_subtitles(const char *prefix)
Definition: arb_progress.h:286
virtual void force_update()=0
void inc_to_avoid_overflow(SINT x)
Definition: arb_progress.h:155
GB_ERROR error_if_aborted()
Definition: arb_progress.h:265
void sub_progress_skipped()
Definition: arb_progress.h:307
bool has_correct_ownership() const
Definition: arb_progress.h:167
virtual counter * clone(nestable *owner, SINT overall_count) const =0
void inc_by(SINT count)
Definition: arb_progress.h:153
virtual void set_text(int level, const char *text)=0
const int LEVEL_SUBTITLE
Definition: arb_progress.h:77
bool owns(const counter *pwnd) const
Definition: arb_progress.h:163
static void show_comment(const char *comment)
Definition: arb_progress.h:291
void GB_warningf(const char *templat,...)
Definition: arb_msg.cxx:490
Generic smart pointer.
Definition: smartptr.h:149
bool aborted()
Definition: arb_progress.h:277
virtual void child_updates_gauge(double gauge)=0
static nestable * recent
Definition: arb_progress.h:94
virtual bool has_auto_subtitles()=0
#define false
Definition: ureadseq.h:13
virtual void auto_subtitles(const char *prefix)=0
arb_progress(unsigned long overall_count)
Definition: arb_progress.h:259
virtual void inc()=0
static void error(const char *msg)
Definition: mkptypes.cxx:96
void update_parent_gauge(double gauge)
Definition: arb_progress.h:146
counter(nestable *owner)
Definition: arb_progress.h:46
const arb_progress & operator++()
Definition: arb_progress.h:301
void auto_subtitles(const char *prefix)
Definition: arb_progress.h:157
virtual void implicit_inc()=0
void inc_and_check_user_abort(ARB_ERROR &error)
Definition: arb_progress.h:275
GB_ERROR inc_and_error_if_aborted()
Definition: arb_progress.h:269
static arb_status_implementation * impl
Definition: arb_progress.h:95
static SmartPtr< nestable > create(const char *title, SINT overall_count)
arb_progress(PINT overall_count)
Definition: arb_progress.h:227
arb_progress(const char *title)
Definition: arb_progress.h:219
static SmartPtr< nestable > create_suppressor()
void subtitle(const char *stitle)
Definition: arb_progress.h:263
virtual void inc_to(SINT x)=0
#define NULp
Definition: cxxforward.h:97
static void show_comment(const char *comment)
Definition: arb_progress.h:159
arb_progress(const char *title, PINT overall_count)
Definition: arb_progress.h:207
virtual void dump() const
void inc_by(PINT count)
Definition: arb_progress.h:303
virtual void done()=0
arb_progress(char *title)
Definition: arb_progress.h:257
nestable(counter *counter_, bool has_title_)
Definition: arb_progress.h:99
bool is_correct_owner() const
Definition: arb_progress.h:164
virtual void dump() const =0
const int LEVEL_TITLE
Definition: arb_progress.h:76
void inc_and_check_user_abort(GB_ERROR &error)
Definition: arb_progress.h:274
void dump() const