ARB
arb_progress.cxx
Go to the documentation of this file.
1 // ================================================================ //
2 // //
3 // File : arb_progress.cxx //
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 #include <arb_progress.h>
13 #include <arb_handlers.h>
14 #include <algorithm>
15 
16 using namespace ArbProgress;
17 
18 // ----------------
19 // counter
20 
21 struct null_counter: public counter {
22  null_counter(nestable *owner) : counter(owner) {}
23 
24  void inc() OVERRIDE {}
26  void inc_by(SINT) OVERRIDE {}
27  void inc_to(SINT) OVERRIDE {}
29  void done() OVERRIDE {}
31  void auto_subtitles(const char *) OVERRIDE {}
32  bool has_auto_subtitles() OVERRIDE { return false; }
33  void child_updates_gauge(double ) OVERRIDE {
34  arb_assert(0); // wont
35  }
36 
37 #if defined(DUMP_PROGRESS)
38  void dump() const OVERRIDE {
39  fprintf(stderr, "null_counter\n");
40  }
41 #endif
42 
43  counter *clone(nestable *owner, SINT ) const OVERRIDE { return new null_counter(owner); }
44 };
45 
46 struct no_counter : public null_counter {
47  no_counter(nestable *owner) : null_counter(owner) {}
48  void inc() OVERRIDE {
49  arb_assert(0); // this is no_counter - so explicit inc() is prohibited!
50  }
51  void child_updates_gauge(double gauge) OVERRIDE { ownedBy->update_gauge(gauge); }
52 
53 #if defined(DUMP_PROGRESS)
54  void dump() const OVERRIDE {
55  fprintf(stderr, "no_counter (=wrapped null_counter)\n");
56  }
57 #endif
58 
60  arb_assert(0); // this method previously was not present => previously was cloned as null_counter!
61  return NULL;
62  }
63 };
64 
65 static void warn_and_dump_counter_or_calling_progress(const char *warnmsg, const counter *fallback);
66 
67 class concrete_counter FINAL_TYPE : public counter { // derived from a Noncopyable
68  SINT explicit_counter; // incremented by calls to inc() etc.
69  SINT implicit_counter; // incremented by child_done()
70  SINT maxcount; // == 0 -> does not really count (just a wrapper for child progresses)
71  double autoUpdateEvery;
72  double nextAutoUpdate;
73  char *auto_subtitle_prefix;
74  SINT last_auto_counter;
75 
76  SINT dispositive_counter() const { return std::max(implicit_counter, explicit_counter); }
77 
78  void init(SINT overallCount) {
79  arb_assert(overallCount>0);
80 
81  implicit_counter = 0;
82  explicit_counter = 0;
83  maxcount = overallCount;
84  autoUpdateEvery = overallCount/500.0; // update status approx. 500 times
85  nextAutoUpdate = 0;
86  }
87 
88  bool refresh_if_needed(double my_counter) { // (double needed when called for child_gauge)
89  arb_assert(my_counter>=0);
90  if (my_counter<nextAutoUpdate) return false;
91 
92  {
93  double gauge = my_counter/maxcount;
94  if (gauge>=1.05) { // 5% overflow detected
95  SINT new_maxcount = maxcount*1.2+0.5;
96 
97  char *warnmsg = GBS_global_string_copy("Warning: progress indicator overflow (%.1f%%/%li)\n"
98  "Estimation of time left is broken (assuming new maximum: +20%% -> %li)\n"
99  "Please report this problem to devel@arb-home.de\n"
100  "(please mention the full text shown in the progress bar window\n"
101  "AND include the newest session log (stored after quitting arb),\n"
102  "otherwise we'll not be able to fix this problem)",
103  (gauge-1)*100, maxcount, new_maxcount);
104 
106  free(warnmsg);
107 
108  arb_assert(0); // progress overflow
109 
110  maxcount = new_maxcount;
111  gauge = my_counter/maxcount;
112  }
113  ownedBy->update_gauge(gauge);
114  }
115 
116  if (auto_subtitle_prefix) {
117  SINT count = SINT(my_counter+1);
118  if (count>last_auto_counter && count <= maxcount) {
119  const char *autosub = GBS_global_string("%s #%li/%li", auto_subtitle_prefix, count, maxcount);
120  ownedBy->set_text(LEVEL_SUBTITLE, autosub);
121  last_auto_counter = count;
122  }
123  }
124  nextAutoUpdate += autoUpdateEvery;
125  return true;
126  }
127  void update_display_if_needed() {
128  refresh_if_needed(dispositive_counter());
129  }
130 
131  void force_update() OVERRIDE {
132  double oldNext = nextAutoUpdate;
133  nextAutoUpdate = 0;
134  update_display_if_needed();
135  nextAutoUpdate = oldNext;
136  }
137 
138  public:
139  concrete_counter(nestable *owner, SINT overall_count) :
140  counter(owner),
141  auto_subtitle_prefix(NULp),
142  last_auto_counter(0)
143  {
144  arb_assert(overall_count>0);
145  init(overall_count);
146  }
148  free(auto_subtitle_prefix);
149 #if defined(TEST_COUNTERS)
150  if (!ownedBy->accept_invalid_counters) {
151  arb_assert(implicit_counter || explicit_counter); // progress was never incremented
152 
153  arb_assert(implicit_counter <= maxcount); // overflow
154  arb_assert(explicit_counter <= maxcount); // overflow
155 
156  arb_assert(dispositive_counter() == maxcount); // progress did not finish
157  }
158 #endif
159  }
160 
161 #if defined(DUMP_PROGRESS)
162  void dump() const OVERRIDE {
163  fprintf(stderr,
164  "concrete_counter: explicit=%li, implicit=%li, maxcount=%li\n",
165  explicit_counter, implicit_counter, maxcount);
166  }
167 #endif
168 
169  void auto_subtitles(const char *prefix) OVERRIDE {
170  // activates use of a prefixed counter as subtitle: "prefix #some/all"
171  arb_assert(!auto_subtitle_prefix);
172  freedup(auto_subtitle_prefix, prefix);
173  force_update();
174  }
175  bool has_auto_subtitles() OVERRIDE { return auto_subtitle_prefix; }
176 
177  void inc() OVERRIDE { explicit_counter += 1; update_display_if_needed(); }
178  void implicit_inc() OVERRIDE { implicit_counter += 1; update_display_if_needed(); }
179 
180  void inc_to(SINT x) OVERRIDE {
181  explicit_counter = std::max(explicit_counter, x);
182  update_display_if_needed();
183  }
185  inc_to(std::min(maxcount, x));
186  }
187  void inc_by(SINT count) { inc_to(explicit_counter+count); }
188 
189  void done() OVERRIDE {
190  implicit_counter = explicit_counter = maxcount;
191  force_update();
192  }
193 
194  counter *clone(nestable *owner, SINT overall_count) const OVERRIDE {
195  return new concrete_counter(owner, overall_count);
196  }
197  void child_updates_gauge(double child_gauge) OVERRIDE {
198  refresh_if_needed(dispositive_counter()+child_gauge);
199  }
200 };
201 
202 // -----------------
203 // progress
204 
205 static counter *make_counter(nestable *owner, SINT overall_count) {
206  if (overall_count) return new concrete_counter(owner, overall_count);
207  return new no_counter(owner);
208 }
209 
210 class child_progress FINAL_TYPE : public nestable { // derived from a Noncopyable
211  nestable *parent;
212  static child_progress *child_triggering_update;
213 
214 public:
215  child_progress(nestable *parent_, const char *title, SINT overall_count) :
216  nestable(make_counter(this, overall_count), title),
217  parent(parent_)
218  {
219  set_text(LEVEL_TITLE, title);
220  DUMP_AS(GBS_global_string("child: %s", title ? title : "<untitled>"));
221  }
223  parent->child_terminated();
224  }
225 
227  return new child_progress(this, title, overall_count);
228  }
229 
230 #if defined(DUMP_PROGRESS)
231  void dump() const OVERRIDE {
232  nestable::dump();
233  fprintf(stderr, "is child of\n");
234  parent->dump();
235  }
236 #endif
237 
238  void set_text(int level, const char *text) OVERRIDE { parent->child_sets_text(level+has_title-1, text); }
239 
240  void update_gauge(double gauge) OVERRIDE {
241  if (!child_triggering_update) {
242  LocallyModify<child_progress*> storeUpdater(child_triggering_update, this);
243  parent->update_parent_gauge(gauge);
244  }
245  else {
246  parent->update_parent_gauge(gauge);
247  }
248  }
249 
250  static const child_progress *calling_child_progress() { return child_triggering_update; }
251 };
252 
253 child_progress *child_progress::child_triggering_update = NULp;
254 
255 static void warn_and_dump_counter_or_calling_progress(const char *warnmsg, const counter *fallback) {
256  GB_warning(warnmsg);
257  fprintf(stderr, "-------------------- warn_and_dump_counter_or_calling_progress [start]\n");
258  fputs(warnmsg, stderr);
259  fputc('\n', stderr);
260 #if defined(DUMP_PROGRESS)
261  const child_progress *updater = child_progress::calling_child_progress();
262  if (updater) {
263  updater->dump();
264  }
265  else { // assume this counter has been updated directly
266  fallback->dump();
267  }
268 #endif
269  fprintf(stderr, "-------------------- warn_and_dump_counter_or_calling_progress [end]\n");
270 }
271 
272 class initial_progress: public nestable {
273 
274 public:
275  initial_progress(const char *title, counter *counter_)
276  : nestable(counter_, title)
277  {
278  DUMP_AS(GBS_global_string("initial: %s", title ? title : "<untitled>"));
279  if (!title) title = "..."; // use fake title (nestable got no title, so it will be replaced by child title)
280  impl->openstatus(title);
281  }
283  update_gauge(1.0); // due to numeric issues it often only counts up to 99.999%
284  impl->closestatus();
285  }
286 
288  return new child_progress(this, title, overall_count);
289  }
290 
291  void set_text(int level, const char *text) OVERRIDE {
292  if (!text) return;
293  switch (level+has_title-1) {
294  case LEVEL_TITLE: impl->set_title(text); break;
295  case LEVEL_SUBTITLE: impl->set_subtitle(text); break;
296  }
297  }
298 
299  void update_gauge(double gauge) OVERRIDE {
300  arb_assert(gauge>=0);
301  arb_assert(gauge<=1);
302  impl->set_gauge(gauge);
303  }
304 };
305 
307  initial_selfRef_progress(const char *title, SINT overall_count) :
308  initial_progress(title, make_counter(this, overall_count))
309  {}
310 };
311 
312 class null_progress: public nestable {
313  null_progress(counter *counter_to_clone, SINT overall_count) : // only used by create_child_progress
314  nestable(counter_to_clone->clone(this, overall_count), false)
315  {
316  DUMP_AS("null_progress (cloned)");
317  }
318 public:
319  explicit null_progress() : // creates a suppressor
320  nestable(new null_counter(this), false)
321  {
322  DUMP_AS("null_progress (suppressor)");
323  }
324 
326  return new null_progress(cntr, overall_count);
327  }
328  void set_text(int,const char*) OVERRIDE {}
329  void update_gauge(double) OVERRIDE {}
330 };
331 
332 // -------------------------
333 // progress factory
334 
336 arb_status_implementation *nestable::impl = NULp; // defines implementation to display status
337 
338 SmartPtr<nestable> nestable::create(const char *title, SINT overall_count) {
339  if (recent) {
340  return recent->create_child_progress(title, overall_count);
341  }
343  return new initial_selfRef_progress(title, overall_count);
344 }
345 
347  return new null_progress;
348 }
349 
350 bool nestable::aborted() const {
351  if (impl) return impl->user_abort();
352  return false;
353 }
354 
355 // --------------------------
356 // progress dumpers
357 
358 #if defined(DUMP_PROGRESS)
359 
360 // not inlined in header (otherwise they are missing while debugging)
361 
362 void nestable::dump() const {
363  fprintf(stderr, "progress '%s'\n", name);
364  fprintf(stderr, "counter: ");
365  cntr->dump();
366 }
367 void arb_progress::dump() const {
368  fprintf(stderr, "--------------------\n");
369  used->dump();
370 }
371 
372 #endif
373 
#define arb_assert(cond)
Definition: arb_assert.h:245
void child_updates_gauge(double child_gauge) OVERRIDE
concrete_counter(nestable *owner, SINT overall_count)
void GB_warning(const char *message)
Definition: arb_msg.cxx:484
SmartPtr< nestable > create_child_progress(const char *title, SINT overall_count) OVERRIDE
void inc_by(SINT) OVERRIDE
void implicit_inc() OVERRIDE
void implicit_inc() OVERRIDE
~child_progress() OVERRIDE
virtual SmartPtr< nestable > create_child_progress(const char *title, SINT overall_count)=0
void set_text(int, const char *) OVERRIDE
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:204
const char * title
Definition: readseq.c:22
void update_gauge(double gauge) OVERRIDE
SmartPtr< nestable > create_child_progress(const char *, SINT overall_count) OVERRIDE
initial_progress(const char *title, counter *counter_)
bool has_auto_subtitles() OVERRIDE
null_counter(nestable *owner)
no_counter(nestable *owner)
void done() OVERRIDE
virtual counter * clone(nestable *owner, SINT overall_count) const =0
const int LEVEL_SUBTITLE
Definition: arb_progress.h:77
arb_handlers * active_arb_handlers
static counter * make_counter(nestable *owner, SINT overall_count)
Generic smart pointer.
Definition: smartptr.h:149
static nestable * recent
Definition: arb_progress.h:94
static void warn_and_dump_counter_or_calling_progress(const char *warnmsg, const counter *fallback)
void child_updates_gauge(double gauge) OVERRIDE
void force_update() OVERRIDE
#define false
Definition: ureadseq.h:13
~initial_progress() OVERRIDE
void inc_to_avoid_overflow(SINT x) OVERRIDE
initial_selfRef_progress(const char *title, SINT overall_count)
fputc('\n', stderr)
void inc_to_avoid_overflow(SINT) OVERRIDE
counter * clone(nestable *owner, SINT overall_count) const OVERRIDE
counter * clone(nestable *, SINT) const OVERRIDE
SmartPtr< nestable > create_child_progress(const char *title, SINT overall_count) OVERRIDE
void set_text(int level, const char *text) OVERRIDE
void done() OVERRIDE
void auto_subtitles(const char *) OVERRIDE
void inc() OVERRIDE
child_progress(nestable *parent_, const char *title, SINT overall_count)
static arb_status_implementation * impl
Definition: arb_progress.h:95
static SmartPtr< nestable > create(const char *title, SINT overall_count)
fputs(TRACE_PREFIX, stderr)
void update_gauge(double) OVERRIDE
static SmartPtr< nestable > create_suppressor()
xml element
void inc_to(SINT) OVERRIDE
#define OVERRIDE
Definition: cxxforward.h:93
#define DUMP_AS(NAME)
Definition: arb_progress.h:86
~concrete_counter() OVERRIDE
static ARB_init_perl_interface init
Definition: ARB_ext.c:101
void set_text(int level, const char *text) OVERRIDE
void auto_subtitles(const char *prefix) OVERRIDE
#define NULp
Definition: cxxforward.h:97
bool has_auto_subtitles() OVERRIDE
void inc() OVERRIDE
virtual void dump() const
void child_updates_gauge(double) OVERRIDE
arb_status_implementation status
Definition: arb_handlers.h:41
void inc_by(SINT count)
static const child_progress * calling_child_progress()
counter * clone(nestable *owner, SINT) const OVERRIDE
#define min(a, b)
Definition: f2c.h:153
void inc() OVERRIDE
virtual void dump() const =0
const int LEVEL_TITLE
Definition: arb_progress.h:76
void inc_to(SINT x) OVERRIDE
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:195
void update_gauge(double gauge) OVERRIDE
void dump() const
#define max(a, b)
Definition: f2c.h:154