source: tags/ms_r18q1/CORE/arb_progress.cxx

Last change on this file was 16763, checked in by westram, 6 years ago
File size: 10.4 KB
Line 
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 <arb_msg.h>
15#include <algorithm>
16
17// ----------------
18//      counter
19
20struct null_counter: public arb_progress_counter {
21    null_counter(arb_parent_progress *progress_) : arb_progress_counter(progress_) {}
22
23    void inc() OVERRIDE {}
24    void implicit_inc() OVERRIDE {}
25    void inc_to(int) OVERRIDE {}
26    void done() OVERRIDE {}
27    void restart(int) OVERRIDE {}
28    void force_update() OVERRIDE {}
29    void auto_subtitles(const char *) OVERRIDE {}
30    bool has_auto_subtitles() OVERRIDE { return false; }
31    void child_updates_gauge(double ) OVERRIDE {
32        arb_assert(0); // wont
33    }
34
35#if defined(DUMP_PROGRESS)
36    void dump() OVERRIDE {
37        fprintf(stderr, "null_counter\n");
38    }
39#endif
40
41    arb_progress_counter* clone(arb_parent_progress *parent_, int ) const OVERRIDE { return new null_counter(parent_); }
42};
43
44struct no_counter : public null_counter {
45    no_counter(arb_parent_progress *progress_) : null_counter(progress_) {}
46    void inc() OVERRIDE {
47        arb_assert(0); // this is no_counter - so explicit inc() is prohibited!
48    }
49    void child_updates_gauge(double gauge) OVERRIDE { progress->update_gauge(gauge); }
50   
51#if defined(DUMP_PROGRESS)
52    void dump() OVERRIDE {
53        fprintf(stderr, "no_counter (=wrapper)\n");
54    }
55#endif
56};
57
58class concrete_counter FINAL_TYPE : public arb_progress_counter { // derived from a Noncopyable
59    int     explicit_counter; // incremented by calls to inc() etc.
60    int     implicit_counter; // incremented by child_done()
61    int     maxcount;         // == 0 -> does not really count (just a wrapper for child progresses)
62    double  autoUpdateEvery;
63    double  nextAutoUpdate;
64    char   *auto_subtitle_prefix;
65    int     last_auto_counter;
66
67    int dispositive_counter() const { return std::max(implicit_counter, explicit_counter); }
68
69    void init(int overallCount) {
70        arb_assert(overallCount>0);
71
72        implicit_counter  = 0;
73        explicit_counter  = 0;
74        maxcount          = overallCount;
75        autoUpdateEvery   = overallCount/500.0; // update status approx. 500 times
76        nextAutoUpdate    = 0;
77    }
78
79    bool refresh_if_needed(double my_counter) {
80        if (my_counter<nextAutoUpdate) return false;
81        progress->update_gauge(my_counter/maxcount);
82        if (auto_subtitle_prefix) {
83            int count = int(my_counter+1);
84            if (count>last_auto_counter && count <= maxcount) {
85                const char *autosub = GBS_global_string("%s #%i/%i", auto_subtitle_prefix, count, maxcount);
86                progress->set_text(LEVEL_SUBTITLE, autosub);
87                last_auto_counter   = count;
88            }
89        }
90        nextAutoUpdate += autoUpdateEvery;
91        return true;
92    }
93    void update_display_if_needed() {
94        int dcount = dispositive_counter();
95        arb_assert(dcount <= maxcount);
96        refresh_if_needed(dcount);
97    }
98
99    void force_update() OVERRIDE {
100        int oldNext    = nextAutoUpdate;;
101        nextAutoUpdate = 0;
102        update_display_if_needed();
103        nextAutoUpdate = oldNext;
104    }
105
106public:
107    concrete_counter(arb_parent_progress *parent, int overall_count) :
108        arb_progress_counter(parent),
109        auto_subtitle_prefix(NULp),
110        last_auto_counter(0)
111    {
112        arb_assert(overall_count>0);
113        init(overall_count);
114    }
115    ~concrete_counter() OVERRIDE {
116        free(auto_subtitle_prefix);
117#if defined(TEST_COUNTERS)
118        if (!progress->accept_invalid_counters) {
119            arb_assert(implicit_counter || explicit_counter); // progress was never incremented
120           
121            arb_assert(implicit_counter <= maxcount); // overflow
122            arb_assert(explicit_counter <= maxcount); // overflow
123
124            arb_assert(dispositive_counter() == maxcount); // progress did not finish
125        }
126#endif
127    }
128
129#if defined(DUMP_PROGRESS)
130    void dump() OVERRIDE {
131        fprintf(stderr,
132                "concrete_counter: explicit=%i, implicit=%i, maxcount=%i\n", 
133                explicit_counter, implicit_counter, maxcount);
134    }
135#endif
136
137    void auto_subtitles(const char *prefix) OVERRIDE {
138        arb_assert(!auto_subtitle_prefix);
139        freedup(auto_subtitle_prefix, prefix);
140        force_update();
141    }
142    bool has_auto_subtitles() OVERRIDE { return auto_subtitle_prefix; }
143
144    void inc()          OVERRIDE { explicit_counter += 1; update_display_if_needed(); }
145    void implicit_inc() OVERRIDE { implicit_counter += 1; update_display_if_needed(); }
146    void inc_to(int x) {
147        explicit_counter = std::max(explicit_counter, x);
148        if (maxcount) {
149            explicit_counter = std::min(explicit_counter, maxcount);
150        }
151        update_display_if_needed();
152    }
153   
154    void done() OVERRIDE {
155        implicit_counter = explicit_counter = maxcount;
156        force_update();
157    }
158
159    void restart(int overallCount) OVERRIDE {
160        init(overallCount);
161        force_update();
162    }
163
164    arb_progress_counter* clone(arb_parent_progress *parent, int overall_count) const OVERRIDE {
165        return new concrete_counter(parent, overall_count);
166    }
167    void child_updates_gauge(double child_gauge) OVERRIDE {
168        refresh_if_needed(dispositive_counter()+child_gauge);
169    }
170};
171
172// -----------------
173//      progress
174
175
176class child_progress : public arb_parent_progress { // derived from a Noncopyable
177    arb_parent_progress *parent;
178
179public:
180    child_progress(arb_parent_progress *parent_, const char *title, int overall_count)
181        : arb_parent_progress(overall_count
182                              ? (arb_progress_counter*)new concrete_counter(this, overall_count)
183                              : (arb_progress_counter*)new no_counter(this),
184                              title),
185          parent(parent_)
186    {
187        set_text(LEVEL_TITLE, title);
188#if defined(DUMP_PROGRESS)
189        freedup(name, GBS_global_string("child: %s", title));
190#endif
191    }
192    ~child_progress() OVERRIDE {
193        parent->child_terminated();
194    }
195
196    SmartPtr<arb_parent_progress> create_child_progress(const char *title, int overall_count) OVERRIDE {
197        return new child_progress(this, title, overall_count);
198    }
199
200#if defined(DUMP_PROGRESS)
201    void dump() OVERRIDE {
202        arb_parent_progress::dump();
203        fprintf(stderr, "is child of\n");
204        parent->dump();
205    }
206#endif
207
208    bool aborted() const OVERRIDE { return parent->aborted(); }
209    void set_text(int level, const char *text) OVERRIDE { parent->child_sets_text(level+has_title-1, text); }
210   
211    void update_gauge(double gauge) OVERRIDE { parent->child_updates_gauge(gauge); }
212};
213
214class initial_progress: public arb_parent_progress {
215    bool user_abort;
216   
217public:
218    initial_progress(const char *title, arb_progress_counter *counter_)
219        : arb_parent_progress(counter_, title),
220          user_abort(false)
221    {
222        if (!title) title = "..."; // use fake title (arb_parent_progress got no title, so it will be replaced by child title)
223        impl->openstatus(title);
224#if defined(DUMP_PROGRESS)
225        freedup(name, GBS_global_string("initial: %s", title));
226#endif
227    }
228    ~initial_progress() OVERRIDE {
229        update_gauge(1.0); // due to numeric issues it often only counts up to 99.999%
230        impl->closestatus();
231    }
232
233    SmartPtr<arb_parent_progress> create_child_progress(const char *title, int overall_count) OVERRIDE {
234        return new child_progress(this, title, overall_count);
235    }
236
237    bool aborted() const OVERRIDE { return user_abort; }
238    void set_text(int level, const char *text) OVERRIDE {
239        if (!text) return;
240        switch (level+has_title-1) {
241            case LEVEL_TITLE: impl->set_title(text); break;
242            case LEVEL_SUBTITLE: impl->set_subtitle(text); break;
243        }
244    }
245
246    void update_gauge(double gauge) OVERRIDE { user_abort = impl->set_gauge(gauge); }
247};
248
249struct initial_wrapping_progress: public initial_progress {
250    initial_wrapping_progress(const char *title)
251        : initial_progress(title, new no_counter(this)) {}
252};
253struct initial_counting_progress : public initial_progress {
254    initial_counting_progress(const char *title, int overall_count)
255        : initial_progress(title, new concrete_counter(this, overall_count)) {}
256};
257
258struct null_progress: public arb_parent_progress {
259    null_progress(arb_progress_counter *counter_)
260        : arb_parent_progress(counter_, false)
261    {
262#if defined(DUMP_PROGRESS)
263        freedup(name, "null_progress");
264#endif
265    }
266
267    SmartPtr<arb_parent_progress> create_child_progress(const char*, int overall_count) OVERRIDE {
268        return new null_progress(clone_counter(overall_count));
269    }
270    bool aborted() const OVERRIDE { return false; }
271    void set_text(int,const char*) OVERRIDE {}
272    void update_gauge(double) OVERRIDE {}
273};
274
275// -------------------------
276//      progress factory
277
278arb_parent_progress       *arb_parent_progress::recent = NULp;
279arb_status_implementation *arb_parent_progress::impl   = NULp; // defines implementation to display status
280
281SmartPtr<arb_parent_progress> arb_parent_progress::create(const char *title, int overall_count) {
282    if (recent) {
283        return recent->create_child_progress(title, overall_count);
284    }
285
286    impl = &active_arb_handlers->status;
287
288    if (overall_count == 0) return new initial_wrapping_progress(title);
289    return new initial_counting_progress(title, overall_count);
290
291}
292
293SmartPtr<arb_parent_progress> arb_parent_progress::create_suppressor() {
294    return new null_progress(new null_counter(NULp));
295}
296
297// --------------------------
298//      progress dumpers
299
300#if defined(DUMP_PROGRESS)
301
302// not inlined in header (otherwise they are missing while debugging)
303
304void arb_parent_progress::dump() {
305    fprintf(stderr, "progress '%s'\n", name);
306    fprintf(stderr, "counter: ");
307    counter->dump();
308}
309void arb_progress::dump() {
310    fprintf(stderr, "--------------------\n");
311    used->dump();
312}
313
314#endif
315
Note: See TracBrowser for help on using the repository browser.